Skip to content

br(v29): Making createServer() sync again#3472

Merged
RobinTail merged 4 commits into
make-v29from
sync-server-again
Jun 16, 2026
Merged

br(v29): Making createServer() sync again#3472
RobinTail merged 4 commits into
make-v29from
sync-server-again

Conversation

@RobinTail

@RobinTail RobinTail commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Thanks to #3465
This should simplify daily routines for beginners.

Tradeoffs

  • Removed Promise from ServerHook type => beforeRouting and afterRouting become sync
  • No further async features to createServer

Summary by CodeRabbit

  • Documentation

    • Updated code examples to show synchronous server initialization without await
  • Refactor

    • Server creation function is now fully synchronous; remove await when invoking it
    • Server lifecycle hooks execute synchronously during initialization

@RobinTail RobinTail added this to the v29 milestone Jun 16, 2026
@RobinTail RobinTail added documentation Improvements or additions to documentation enhancement New feature or request breaking Backward incompatible changes labels Jun 16, 2026
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 842b0971-2667-4b69-81a9-97a940351dd4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: making createServer() synchronous. It directly summarizes the core modification across the codebase.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync-server-again

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@RobinTail

Copy link
Copy Markdown
Owner Author

@pullfrog please review

@coveralls-official

coveralls-official Bot commented Jun 16, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 100.0%. remained the same — sync-server-again into make-v29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
express-zod-api/src/server.ts (1)

83-83: ⚡ Quick win

Fail fast if a lifecycle hook returns a Promise.

Line 83 and Line 93 now execute hooks synchronously, but JS callers (or any-typed configs) can still return a
Promise, which is silently ignored. Add a runtime thenable guard so the new sync-only contract is enforced explicitly.

Suggested patch
 export const createServer = (config: ServerConfig, routing: Routing) => {
+  const ensureSyncHook = (
+    name: "beforeRouting" | "afterRouting",
+    result: unknown,
+  ) => {
+    if (
+      result &&
+      typeof result === "object" &&
+      "then" in result &&
+      typeof (result as PromiseLike<unknown>).then === "function"
+    ) {
+      throw new Error(`${name} hook must be synchronous and return void.`);
+    }
+  };
+
   const { logger, getLogger, notFoundHandler, catcher, loggingMiddleware } =
     makeCommonEntities(config);
@@
-  config.beforeRouting?.({ app, getLogger });
+  const beforeRoutingResult = config.beforeRouting?.({ app, getLogger });
+  ensureSyncHook("beforeRouting", beforeRoutingResult);
@@
-  config.afterRouting?.({ app, getLogger });
+  const afterRoutingResult = config.afterRouting?.({ app, getLogger });
+  ensureSyncHook("afterRouting", afterRoutingResult);

Based on learnings: PR objectives explicitly state createServer() and beforeRouting/afterRouting are now synchronous.

Also applies to: 93-93

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@express-zod-api/src/server.ts` at line 83, The beforeRouting hook call at
line 83 and the afterRouting hook call at line 93 currently execute
synchronously but do not validate that callers don't return Promises, which
would be silently ignored. Add a runtime thenable guard after each hook
invocation to check if the return value is a Promise (by detecting if it has a
.then method). If either hook returns a thenable, throw an error immediately to
fail fast and enforce the explicit synchronous contract that the PR now requires
for these lifecycle hooks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@express-zod-api/src/server.ts`:
- Line 83: The beforeRouting hook call at line 83 and the afterRouting hook call
at line 93 currently execute synchronously but do not validate that callers
don't return Promises, which would be silently ignored. Add a runtime thenable
guard after each hook invocation to check if the return value is a Promise (by
detecting if it has a .then method). If either hook returns a thenable, throw an
error immediately to fail fast and enforce the explicit synchronous contract
that the PR now requires for these lifecycle hooks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0444f5f6-e1ea-4e81-8962-fdec1d78652c

📥 Commits

Reviewing files that changed from the base of the PR and between 81cd7e3 and a47fcc1.

📒 Files selected for processing (6)
  • README.md
  • example/index.ts
  • express-zod-api/src/config-type.ts
  • express-zod-api/src/server.ts
  • express-zod-api/tests/server.spec.ts
  • express-zod-api/tests/system.spec.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — minor suggestions inline.

Reviewed changes — makes createServer() synchronous and removes Promise<void> from the ServerHook type, preventing async functions in beforeRouting/afterRouting hooks. This simplifies the API surface for beginners by eliminating the need for top-level await.

  • Make createServer() sync — removes async keyword from createServer in src/server.ts and drops await on beforeRouting/afterRouting calls
  • Remove Promise<void> from ServerHook — the ServerHook type in src/config-type.ts is now () => void only, preventing async callbacks in hooks at compile-time
  • Update tests — all async/await removed from createServer call sites in tests/server.spec.ts; tests/system.spec.ts moves the server-listening assertion into a beforeAll hook
  • Update example and docsexample/index.ts and README.md drop await and explanatory comments

ℹ️ Migration rule and CHANGELOG not yet updated

This is a breaking change (removing async support from createServer and ServerHook). Per the project conventions in AGENTS.md, breaking changes to the public API require an update to the migration ESLint rule in migration/index.ts, its tests in migration/index.spec.ts, and CHANGELOG.md. Currently none of these have been updated.

Technical details
# Missing migration rule and CHANGELOG for sync createServer

## Affected sites
- `migration/index.ts` — no rule for this breaking change
- `migration/index.spec.ts` — no test coverage for the migration
- `CHANGELOG.md` — no entry for this change

## Required outcome
- A migration rule that removes `await` before `createServer(...)` calls
- A migration rule that removes `async` from functions passed to `beforeRouting`/`afterRouting` (and the `await` on their internal calls, if applicable)
- Valid/invalid test cases in `migration/index.spec.ts`
- A CHANGELOG entry for v9 documenting this change

## Open questions for the human
- Is this PR one of several incremental v9 changes, with migration/CHANGELOG to be done in a separate consolidation PR?

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread express-zod-api/tests/system.spec.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — makes createServer() synchronous by removing Promise from ServerHook, simplifying the server bootstrap path now that async hooks are no longer required.

  • Remove Promise<void> from ServerHookbeforeRouting and afterRouting hooks are now sync-only, matching the new sync createServer().
  • Make createServer() synchronous — drops async/await from the function and its hook invocations in server.ts.
  • Update tests for sync createServer — removes async/await from test callbacks in server.spec.ts; moves server-startup assertions into beforeAll in system.spec.ts.
  • Update examplesREADME.md and example/index.ts drop await from createServer() calls.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes — one new commit removes a redundant import { beforeAll } from "vitest" in the test file, since beforeAll is a Vitest global.

  • Remove redundant beforeAll importexpress-zod-api/tests/system.spec.ts had an explicit import for a Vitest global; cleaned up.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@RobinTail RobinTail merged commit 66d585d into make-v29 Jun 16, 2026
14 checks passed
@RobinTail RobinTail deleted the sync-server-again branch June 16, 2026 17:02
@RobinTail RobinTail changed the title br(v9): Making createServer() sync again br(v29): Making createServer() sync again Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Backward incompatible changes documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant