Skip to content

Feature/native server#281

Open
MiaInturi wants to merge 4 commits into
mainfrom
feature/native-server
Open

Feature/native server#281
MiaInturi wants to merge 4 commits into
mainfrom
feature/native-server

Conversation

@MiaInturi

Copy link
Copy Markdown
Collaborator

No description provided.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 615008e8-22d6-4d15-9dd1-93d03f6bdc4d

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/native-server

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.

Comment on lines +59 to +78
const overrides: Record<PropertyKey, unknown> = {
body,
cookies,
headers,
params,
queries,
rawBody,
rawHeaders
};
return new Proxy(request, {
get(target, key) {
if (key in overrides) return overrides[key];
const value = Reflect.get(target, key, target);
return typeof value === 'function' ? value.bind(target) : value;
},
has(target, key) {
return key in overrides || Reflect.has(target, key);
}
}) as unknown as MockServerRequest;
};

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

чтобы не перезаписывать изначальный request (у него немутируемые свойства), а просто перехватывать обращения ко свойствам и отдавать нужное поле

@MiaInturi

Copy link
Copy Markdown
Collaborator Author

@greptile can you do review now?

@greptile-apps

greptile-apps Bot commented May 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces createNativeMockServer, a new Node.js http-based mock server that replaces the Express-based createMockServer as the backend for startMockServer. It adds full request/response lifecycle support including body parsing, cookie handling, path params extraction, and a four-level interceptor chain.

  • P1 – Multiple cookies silently dropped (createRestRoute.ts): The final header merge loop calls finalHeaders.set(name, value) for every entry in responseState.headers. Since Headers.entries() yields one entry per set-cookie value, each iteration overwrites the previous one, leaving only the last cookie. Fix: use append for set-cookie keys.
  • P1 – set-cookie corruption in sendFetchResponse.ts: serverResponse.setHeaders(fetchResponse.headers) relies on the Fetch Headers API, which comma-joins multiple set-cookie values. Cookie values may themselves contain commas, producing a malformed header. The file's own TODO flags this; explicit set-cookie extraction is needed before the bulk setHeaders call.

Confidence Score: 3/5

Not safe to merge as-is — two P1 bugs will silently corrupt or drop Set-Cookie headers in any multi-cookie response.

Two independent P1 bugs both affect cookie handling in different layers of the stack; either one alone would break responses that set multiple cookies, and they are on the hot path of every matched route response.

createRestRoute.ts (final header merge loop) and sendFetchResponse.ts (set-cookie via Fetch Headers) need fixes before merging.

Important Files Changed

Filename Overview
packages/server/src/server/createNativeMockServer/createNativeMockServer.ts Core native HTTP server entrypoint; handler loop with NextError-based routing is well-structured and error-safe.
packages/server/src/server/createNativeMockServer/helpers/http/sendFetchResponse/sendFetchResponse.ts Bridges Fetch Response to Node ServerResponse; setHeaders will corrupt multiple Set-Cookie headers (values comma-joined by Fetch Headers API). Known TODO in file.
packages/server/src/server/createNativeMockServer/helpers/http/toFetchRequest/toFetchRequest.ts Converts IncomingMessage to Fetch Request; method/body gating and duplex handling are correct.
packages/server/src/server/createNativeMockServer/helpers/http/toMockServerRequest/toMockServerRequest.ts Body parsing and Proxy-based MockServerRequest construction look correct; minor inconsistency with missing await on some async branches.
packages/server/src/server/createNativeMockServer/helpers/routes/createRestRoute.ts Core REST route logic; P1 bug: using Headers.set() in the final header merge loop silently drops all but the last set-cookie when multiple cookies are set.
packages/server/src/server/createNativeMockServer/helpers/interceptors/callResponseInterceptors.ts Chains response interceptors correctly; cookie serialization uses the new cookie package.
packages/server/src/server/createNativeMockServer/types/interceptors.ts Defines native interceptor types but imports CookieOptions from express, creating an Express coupling in the native server module.
packages/server/src/server/createNativeMockServer/types/rest.ts REST type definitions; same Express CookieOptions coupling as interceptors.ts.
packages/server/src/server/startMockServer/startMockServer.ts Swapped from Express createMockServer to native createNativeMockServer; destroyerMiddleware is compatible with node:http.Server so no breakage there.
packages/server/tsconfig.production.json Removed lib: [dom, esnext]; intentional shift to rely on @types/node for Fetch/URL globals rather than the DOM lib typings.
packages/server/src/server/createNativeMockServer/helpers/routes/prepareRestRoute.ts Builds REST request artifacts from server components and wires interceptors at all four levels; logic mirrors existing Express-based implementation.

Comments Outside Diff (3)

  1. packages/server/src/server/createNativeMockServer/helpers/routes/createRestRoute.ts, line 591-594 (link)

    P1 set-cookie headers silently dropped when multiple cookies are set

    Headers.entries() yields each set-cookie entry as a separate item. Calling finalHeaders.set(name, value) inside the loop overwrites the header on every iteration, so only the last cookie survives. This means any response that sets more than one cookie (e.g. auth token + session) will silently discard all but the final one.

  2. packages/server/src/server/createNativeMockServer/helpers/http/sendFetchResponse/sendFetchResponse.ts, line 92-101 (link)

    P1 set-cookie headers flattened/lost via setHeaders

    serverResponse.setHeaders(fetchResponse.headers) relies on the Fetch Headers API, which comma-joins multiple set-cookie values into a single string. Cookie values may themselves contain commas, producing a malformed header. The file's own TODO flags this — it needs explicit set-cookie handling (via fetchResponse.headers.getSetCookie()) before the bulk setHeaders call.

  3. packages/server/src/server/createNativeMockServer/helpers/http/toMockServerRequest/toMockServerRequest.ts, line 163-202 (link)

    P2 Inconsistent await in parseRawBody

    response.json() is awaited (return await response.json()), but response.arrayBuffer() (lines 169, 202) and response.formData() (line 186) are returned without await. All branches return Promises and the caller awaits the result, so this works, but the inconsistency is confusing and may mask future bugs if the return type changes.

Reviews (1): Last reviewed commit: "feature/native-server 💎 fix bugs" | Re-trigger Greptile

@@ -0,0 +1,38 @@
import type { CookieOptions } from 'express';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Express type dependency in native server

CookieOptions is imported from express, coupling this "native" (Express-free) server to the Express package for a type-only reason. The same import appears in types/rest.ts. Consider defining a local CookieOptions interface or importing from the standalone cookie package (already added as a dependency in this PR) to avoid the Express coupling.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +12 to +16
const isOptionSettings = !('configs' in option);
const mockServerSettings = isOptionSettings ? option : {};
const mockServerComponents = (
isOptionSettings ? mockServerConfig.slice(1) : mockServerConfig
) as MockServerComponent[];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

почему переделали тут кодец с оригинального сервера

) as MockServerComponent[];

const restRoute = prepareRestRoute(mockServerSettings, mockServerComponents);
const handle404 = () => new Response(null, { status: 404 });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

not found mb

Comment on lines +49 to +51
const restRoute = createRestRoute({ restRequestArtifacts });

return restRoute;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

return createRestRoute({ restRequestArtifacts });

Comment on lines +183 to +192
const dataResponse =
resolvedData instanceof Response
? copyResponseWith(resolvedData, {
headers: responseState.headers,
status: responseState.statusCode ?? matchedRouteConfig.config.settings?.status
})
: Response.json(resolvedData, {
headers: responseState.headers,
status: responseState.statusCode ?? matchedRouteConfig.config.settings?.status
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

возможно стоит оставить все таки 1 формат

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