Skip to content

Conversation

@7heMech
Copy link
Contributor

@7heMech 7heMech commented Aug 15, 2025

First of all awesome project, I love how it uses specific servers for each runtime, with this PR we make adding new ones even easier and improve type safety.

This PR mainly edits the server file does several things:

  • Adds deno, node and open's types as development dependencies (not in the final bundle) and uses them to have proper types in the server and gets rid of the ts ignore comments
  • Adds a base server class to get rid of redundant code.

7heMech and others added 4 commits August 15, 2025 13:39
* feat: Improve type safety and remove @ts-ignore

- Installed `@types/open` and `@types/node` to provide type definitions for dependencies.
- Updated `tsconfig.json` to include `deno` and `node` types, making globals for these runtimes available to TypeScript.
- Refactored `src/server.ts` to use specific types instead of `any`, including `Bun.Server`, `http.Server`, and `http.IncomingMessage`.
- Removed all `@ts-ignore` comments from `src/server.ts`.

* Fix the rest of the TS issues and types for deno

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: 7heMech <[email protected]>
@7heMech
Copy link
Contributor Author

7heMech commented Aug 15, 2025

I also

  • Modernized Timeout Handling

    • Before: The logic used a manual setTimeout, a boolean flag (isResolved), and clearTimeout to manage the timeout. This is verbose and has several moving parts that could potentially fail.

    • After: Replaced all of that with a single, elegant Promise.race(). This is the modern, standard way to handle this scenario in JavaScript. It's more declarative (the code says what it's doing, not how it's doing it), less error-prone, and easier to read.

  • Guaranteed Cleanup

    • Before: Cleanup logic was spread out. clearTimeout was called in the resolve/reject wrappers, and the callbackPromise was cleared in the stop() method.

    • After: Added a try...finally block inside waitForCallback. The finally block guarantees that this.callbackListeners.delete(path) is called for that specific listener, whether the callback succeeds or times out. This is a more reliable pattern for resource management and prevents memory leaks.

@koistya
Copy link
Member

koistya commented Aug 16, 2025

Hey @7heMech! 👋 I just noticed this PR after pushing #2 Let me review with a bit of help from Claude.

First off, thank you so much for taking the time to contribute to this project! I really appreciate your thoughtful improvements to the codebase. Your PR shows a deep understanding of the code structure and brings some excellent modernization ideas. Let me share my detailed review of the changes.

✅ What I Love About This PR

1. Base Class Architecture 🏗️

The introduction of BaseCallbackServer is brilliant! This dramatically reduces code duplication across the three runtime implementations (Bun, Deno, Node.js). The shared logic for request handling, timeout management, and cleanup is now centralized, making the codebase much more maintainable.

2. Modern Promise Patterns with Promise.race()

Your replacement of the manual timeout handling with Promise.race() is exactly the kind of modernization this project needed. The old approach with isResolved flags and manual clearTimeout calls was indeed verbose and error-prone. Your solution is:

  • More declarative and readable
  • Less prone to race conditions
  • Following modern JavaScript best practices

3. Improved Resource Management 🧹

The try...finally block in waitForCallback is a significant improvement! This guarantees that listeners are always cleaned up, preventing potential memory leaks. The use of a Map for tracking multiple path listeners is also more robust than the single property approach.

4. Better Error Handling for Multiple Listeners 🛡️

The check for existing listeners on the same path prevents potential conflicts and provides clear error messages. This is a thoughtful addition that improves the developer experience.

🔍 Areas That Need Attention

1. TypeScript Type Definitions Issue

While adding type packages (@types/deno, @types/node) was a good intention, there's a compilation issue. The TypeScript compiler can't find the Deno global even with the types installed. The PR still requires @ts-ignore comments for Deno globals, which somewhat defeats the purpose of adding the type packages.

Critical issue with Node.js type imports:
The PR adds import type { Server as HttpServer } from "node:http" at the top level, which is problematic for a cross-runtime library:

  • These imports will fail in Bun and Deno environments
  • Goes against the cross-runtime design principle
  • The any type for runtime-specific servers is actually the correct pattern here

Current state:

  • Build fails without @ts-ignore for Deno globals
  • The added type packages aren't fully utilized
  • Node-specific type imports break cross-runtime compatibility

2. Type Safety Could Be Stronger

While the base class reduces duplication, we're still using any for runtime-specific server types (e.g., Bun.Server). With the type packages added, we could potentially use the proper types:

private server?: Bun.Server;  // Instead of any

3. Minor Implementation Details

  • The generateCallbackHTML function refactor is cleaner but changes the logic flow slightly (early return vs. nested if)
  • The Node.js implementation now uses req.headers.host which is good, but might need validation for security

📊 Test Results

✅ All tests pass successfully (9/9 tests, 22 assertions)
✅ Examples run without issues
✅ Server functionality remains intact

🎯 Suggestions for Improvement

  1. Consider conditional type imports instead of adding all type packages:

    /// <reference types="bun-types" />

    Only in files where needed, keeping the package lighter.

  2. Type the server properties properly if keeping the type packages:

    private server?: Bun.Server;  // For BunCallbackServer
    private server?: HttpServer;  // For NodeCallbackServer
  3. Document the breaking changes if any - the refactoring might affect error messages or timing slightly.

🚀 Overall Assessment

This is a high-quality PR that brings meaningful improvements to the codebase! The architectural changes with the base class pattern and modernized Promise handling are exactly what this project needed. While there are some minor issues with the TypeScript types that need resolution, the core improvements are solid and valuable.

The code is cleaner, more maintainable, and follows modern JavaScript/TypeScript best practices. Your attention to detail in areas like resource cleanup and error handling shows careful consideration of edge cases.

@7heMech
Copy link
Contributor Author

7heMech commented Aug 19, 2025

Hey, I'm sorry, but Claude is just hallucinating. I'll address everything one by one, if you think I'm wrong on some (which I might) I'd be happy to learn.

1. TypeScript Type Definitions Issue

While adding type packages (@types/deno, @types/node) was a good intention, there's a compilation issue. The TypeScript compiler can't find the Deno global even with the types installed. The PR still requires @ts-ignore comments for Deno globals, which somewhat defeats the purpose of adding the type packages.

bun run build runs fine for me, and I added it because the typescript language server was complaining about deno global, when I added it the issue was resolved.

Critical issue with Node.js type imports:
The PR adds import type { Server as HttpServer } from "node:http" at the top level, which is problematic for a cross-runtime library:

  • These imports will fail in Bun and Deno environments

These type imports don't make it into the final compiled code.

2. Type Safety Could Be Stronger

While the base class reduces duplication, we're still using any for runtime-specific server types (e.g., Bun.Server). With the type packages added, we could potentially use the proper types:

private server?: Bun.Server;  // Instead of any

This is exactly what I did at line 213.

3. Minor Implementation Details

  • The generateCallbackHTML function refactor is cleaner but changes the logic flow slightly (early return vs. nested if)

That's the cleaner layout for the core doesn't change how the app works.

  • The Node.js implementation now uses req.headers.host which is good, but might need validation for security

I don't really think it does.

@koistya
Copy link
Member

koistya commented Aug 20, 2025

@7heMech sounds good. Let me check if there is a way to resolve the merge conflict...

@7heMech
Copy link
Contributor Author

7heMech commented Aug 20, 2025

This should do it, I'll test though

@7heMech
Copy link
Contributor Author

7heMech commented Aug 20, 2025

Yeah, now you can squash and merge, tell me if you don't want the replit ide config I'll get rid of that, that's just what I code on.

@koistya
Copy link
Member

koistya commented Aug 20, 2025

@7heMech having Replit config in place is convenient.

@koistya koistya merged commit 150f30e into kriasoft:main Aug 20, 2025
4 checks passed
@koistya
Copy link
Member

koistya commented Aug 20, 2025

@7heMech that was quick. Awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants