@mandujs/core 0.41.2 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +21 -4
- package/src/auth/__tests__/login.test.ts +420 -419
- package/src/auth/__tests__/reset.test.ts +296 -296
- package/src/brain/adapters/anthropic-oauth.ts +421 -420
- package/src/brain/adapters/index.ts +2 -1
- package/src/brain/adapters/ollama.ts +1 -1
- package/src/brain/adapters/openai-oauth.ts +534 -533
- package/src/brain/brain.ts +2 -1
- package/src/brain/redactor.ts +196 -196
- package/src/bundler/__tests__/cli-bench-utils.test.ts +149 -149
- package/src/bundler/__tests__/cold-start.test.ts +504 -504
- package/src/bundler/__tests__/fast-refresh.test.ts +607 -606
- package/src/bundler/__tests__/hdr.test.ts +1 -1
- package/src/bundler/analyzer.ts +958 -958
- package/src/bundler/build.ts +104 -14
- package/src/bundler/dev.ts +125 -0
- package/src/bundler/hmr-types.ts +1 -0
- package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -0
- package/src/bundler/plugins/index.ts +14 -0
- package/src/bundler/plugins/react-compiler-lint.ts +253 -0
- package/src/bundler/plugins/react-compiler.ts +162 -0
- package/src/bundler/types.ts +12 -0
- package/src/change/integrity.ts +2 -1
- package/src/client/index.ts +10 -0
- package/src/client/island.ts +38 -11
- package/src/client/router.ts +6 -1
- package/src/config/mandu.ts +57 -0
- package/src/config/validate.ts +42 -0
- package/src/content/collection.ts +844 -809
- package/src/content/content-layer.ts +316 -314
- package/src/content/content.test.ts +433 -433
- package/src/content/digest.ts +133 -133
- package/src/content/generate-types.ts +168 -168
- package/src/content/index.ts +6 -1
- package/src/content/llms-txt.ts +277 -277
- package/src/contract/define.ts +474 -474
- package/src/contract/route-helpers.ts +2 -1
- package/src/contract/zod-utils.ts +158 -155
- package/src/db/index.ts +513 -513
- package/src/desktop/__tests__/smoke.test.ts +100 -100
- package/src/desktop/webview-fallback.ts +583 -583
- package/src/desktop/window.ts +3 -1
- package/src/dev-error-overlay/overlay-client.ts +300 -300
- package/src/devtools/ai/mcp-connector.ts +499 -498
- package/src/devtools/client/components/kitchen-root.tsx +7 -2
- package/src/email/resend.ts +163 -163
- package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -0
- package/src/guard/ast-analyzer.ts +806 -806
- package/src/guard/graph.ts +898 -898
- package/src/guard/index.ts +16 -0
- package/src/guard/statistics.ts +578 -578
- package/src/guard/tsgolint-bridge.ts +512 -0
- package/src/i18n/locale-resolver.ts +214 -214
- package/src/id/__tests__/id.test.ts +120 -120
- package/src/intent/index.ts +321 -321
- package/src/island/index.ts +39 -23
- package/src/kitchen/api/contract-api.ts +15 -8
- package/src/kitchen/kitchen-ui.ts +2137 -2137
- package/src/lockfile/index.ts +3 -2
- package/src/middleware/oauth/__tests__/oauth.test.ts +575 -574
- package/src/middleware/rate-limit/__tests__/rate-limit.test.ts +642 -642
- package/src/middleware/secure/index.ts +417 -417
- package/src/observability/event-bus.ts +2 -2
- package/src/observability/metrics.ts +334 -334
- package/src/observability/tracing.ts +694 -694
- package/src/openapi/generator.ts +1 -1
- package/src/perf/user-marks.ts +553 -553
- package/src/plugins/registry.ts +387 -387
- package/src/resource/ddl/diff.ts +392 -392
- package/src/resource/ddl/snapshot.ts +448 -447
- package/src/resource/generator-schema.ts +477 -476
- package/src/resource/parser.ts +4 -2
- package/src/resource/schema.ts +1 -1
- package/src/router/fs-patterns.ts +422 -422
- package/src/runtime/fast-refresh-types.ts +126 -128
- package/src/runtime/image-handler.ts +206 -195
- package/src/runtime/router.test.ts +476 -476
- package/src/runtime/security.ts +155 -155
- package/src/runtime/server.ts +36 -19
- package/src/runtime/session-key.ts +328 -328
- package/src/scheduler/__tests__/scheduler.test.ts +514 -514
- package/src/seo/resolve/index.ts +353 -353
- package/src/spec/load.ts +1 -1
- package/src/testing/reporter.ts +676 -676
- package/src/testing/server.ts +196 -196
- package/src/testing/snapshot.ts +444 -444
- package/src/utils/__tests__/lru-cache.test.ts +186 -186
- package/src/utils/bun.ts +8 -8
package/src/testing/server.ts
CHANGED
|
@@ -1,196 +1,196 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @mandujs/core/testing/server
|
|
3
|
-
*
|
|
4
|
-
* In-process server fixture for integration tests.
|
|
5
|
-
*
|
|
6
|
-
* Wraps `startServer()` with an ephemeral port (`0`), a per-test
|
|
7
|
-
* `ServerRegistry` (so parallel tests cannot stomp each other's handlers),
|
|
8
|
-
* and a scoped `fetch` helper so callers can write:
|
|
9
|
-
*
|
|
10
|
-
* ```ts
|
|
11
|
-
* import { createTestServer } from "@mandujs/core/testing";
|
|
12
|
-
*
|
|
13
|
-
* const server = await createTestServer(manifest, {
|
|
14
|
-
* registerHandlers(reg) {
|
|
15
|
-
* reg.registerApiHandler("api/health", async () => Response.json({ ok: true }));
|
|
16
|
-
* },
|
|
17
|
-
* });
|
|
18
|
-
* afterAll(() => server.close());
|
|
19
|
-
*
|
|
20
|
-
* const res = await server.fetch("/api/health");
|
|
21
|
-
* expect(res.status).toBe(200);
|
|
22
|
-
* ```
|
|
23
|
-
*
|
|
24
|
-
* ## Design
|
|
25
|
-
*
|
|
26
|
-
* - **Registry isolation** — the fixture always creates its own
|
|
27
|
-
* `ServerRegistry` (via `createServerRegistry()`), never touches the default
|
|
28
|
-
* global. That lets several fixtures run concurrently in the same test
|
|
29
|
-
* process without handler collisions.
|
|
30
|
-
* - **Port zero** — Bun picks an OS-assigned ephemeral port; the fixture
|
|
31
|
-
* exposes the resolved port and a pre-computed `baseUrl` so tests never
|
|
32
|
-
* hard-code `:3000`.
|
|
33
|
-
* - **Scoped `fetch`** — accepts either an absolute URL or a root-relative
|
|
34
|
-
* path; the latter is joined to `baseUrl`. This matches the ergonomics
|
|
35
|
-
* of `supertest` / Remix `createRoutesStub` without taking a dep on them.
|
|
36
|
-
* - **Cleanup contract** — `close()` is idempotent; the returned handle is
|
|
37
|
-
* also `asyncDispose`-compatible so `using server = await createTestServer(...)`
|
|
38
|
-
* works under Bun's Explicit Resource Management.
|
|
39
|
-
*
|
|
40
|
-
* @module testing/server
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
import type { RoutesManifest } from "../spec/schema";
|
|
44
|
-
import {
|
|
45
|
-
startServer,
|
|
46
|
-
createServerRegistry,
|
|
47
|
-
type ManduServer,
|
|
48
|
-
type ServerOptions,
|
|
49
|
-
type ServerRegistry,
|
|
50
|
-
} from "../runtime/server";
|
|
51
|
-
|
|
52
|
-
/** Options accepted by {@link createTestServer}. */
|
|
53
|
-
export interface CreateTestServerOptions {
|
|
54
|
-
/**
|
|
55
|
-
* Optional registration callback. The fixture creates a fresh
|
|
56
|
-
* `ServerRegistry` and passes it here so tests can attach API handlers,
|
|
57
|
-
* page loaders, layouts, and so on synchronously before the server starts
|
|
58
|
-
* listening. Skip when the manifest's handlers are resolved elsewhere.
|
|
59
|
-
*/
|
|
60
|
-
registerHandlers?: (registry: ServerRegistry) => void | Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* Host to bind. Default: `"127.0.0.1"` (explicit IPv4 so Windows CI boxes
|
|
63
|
-
* do not fall through to `::1` and break `fetch` default resolution).
|
|
64
|
-
*/
|
|
65
|
-
hostname?: string;
|
|
66
|
-
/**
|
|
67
|
-
* Extra options forwarded to `startServer()`. The fixture overrides
|
|
68
|
-
* `port`, `registry`, and `isDev` — those keys are ignored if present.
|
|
69
|
-
*/
|
|
70
|
-
serverOptions?: Omit<ServerOptions, "port" | "registry" | "isDev" | "hostname">;
|
|
71
|
-
/** Set to `true` to boot the server in dev mode (HMR, kitchen, etc.). Default: `false`. */
|
|
72
|
-
isDev?: boolean;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** The fixture handle returned by {@link createTestServer}. */
|
|
76
|
-
export interface TestServer {
|
|
77
|
-
/** The underlying `ManduServer` (access `server.server.port` if you need Bun handles). */
|
|
78
|
-
readonly server: ManduServer;
|
|
79
|
-
/** The registry the fixture created. Use this to register handlers *after* startup. */
|
|
80
|
-
readonly registry: ServerRegistry;
|
|
81
|
-
/** Resolved port (non-zero once `await`ed). */
|
|
82
|
-
readonly port: number;
|
|
83
|
-
/** `http://<host>:<port>` with no trailing slash. */
|
|
84
|
-
readonly baseUrl: string;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Scoped fetch — accepts a path (`"/api/foo"`) or absolute URL
|
|
88
|
-
* (`"http://other/..."`). Path-style inputs are joined to `baseUrl`.
|
|
89
|
-
*
|
|
90
|
-
* ```ts
|
|
91
|
-
* await server.fetch("/api/health")
|
|
92
|
-
* await server.fetch("/api/login", { method: "POST", body: JSON.stringify({...}) })
|
|
93
|
-
* await server.fetch(new Request("http://localhost/anything"))
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Idempotent teardown. Stops the underlying `Bun.serve` instance and
|
|
100
|
-
* clears the registry so no handler leaks into the next fixture.
|
|
101
|
-
*/
|
|
102
|
-
close(): void;
|
|
103
|
-
|
|
104
|
-
/** Explicit Resource Management support: `using server = await createTestServer(...)`. */
|
|
105
|
-
[Symbol.asyncDispose](): Promise<void>;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Boot an in-process test server on an ephemeral port.
|
|
110
|
-
*
|
|
111
|
-
* Returns once `Bun.serve` is listening — no polling required; Bun binds
|
|
112
|
-
* synchronously before `fetch` becomes ready.
|
|
113
|
-
*
|
|
114
|
-
* @throws if `manifest` is missing required fields (handler resolution errors
|
|
115
|
-
* surface on the first `fetch`, not here).
|
|
116
|
-
*/
|
|
117
|
-
export async function createTestServer(
|
|
118
|
-
manifest: RoutesManifest,
|
|
119
|
-
options: CreateTestServerOptions = {},
|
|
120
|
-
): Promise<TestServer> {
|
|
121
|
-
const registry = createServerRegistry();
|
|
122
|
-
|
|
123
|
-
if (options.registerHandlers) {
|
|
124
|
-
await options.registerHandlers(registry);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const hostname = options.hostname ?? "127.0.0.1";
|
|
128
|
-
const server = startServer(manifest, {
|
|
129
|
-
...(options.serverOptions ?? {}),
|
|
130
|
-
port: 0,
|
|
131
|
-
hostname,
|
|
132
|
-
isDev: options.isDev ?? false,
|
|
133
|
-
registry,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Bun.serve always resolves the port synchronously before returning the
|
|
137
|
-
// handle — `undefined` would only happen on a fully-closed server, which
|
|
138
|
-
// is impossible here because we just created it. Assert + narrow so
|
|
139
|
-
// consumers see a plain `number`.
|
|
140
|
-
if (typeof server.server.port !== "number") {
|
|
141
|
-
throw new Error(
|
|
142
|
-
"[testing/server] startServer() returned without a bound port. This is a framework-level bug — please report.",
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
const port: number = server.server.port;
|
|
146
|
-
const baseUrl = `http://${hostname}:${port}`;
|
|
147
|
-
|
|
148
|
-
let closed = false;
|
|
149
|
-
const close = (): void => {
|
|
150
|
-
if (closed) return;
|
|
151
|
-
closed = true;
|
|
152
|
-
try {
|
|
153
|
-
server.stop();
|
|
154
|
-
} catch {
|
|
155
|
-
// stop() is best-effort — swallow so afterEach doesn't mask real test failures.
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const fetchImpl = async (
|
|
160
|
-
input: string | URL | Request,
|
|
161
|
-
init?: RequestInit,
|
|
162
|
-
): Promise<Response> => {
|
|
163
|
-
if (closed) {
|
|
164
|
-
throw new Error(
|
|
165
|
-
"[testing/server] fetch() called after close() — did an afterAll run before this test?",
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Resolve path-style inputs against baseUrl. Absolute URLs and Request
|
|
170
|
-
// objects pass through untouched so callers keep full control.
|
|
171
|
-
if (typeof input === "string") {
|
|
172
|
-
const resolved = input.startsWith("http://") || input.startsWith("https://")
|
|
173
|
-
? input
|
|
174
|
-
: `${baseUrl}${input.startsWith("/") ? "" : "/"}${input}`;
|
|
175
|
-
return fetch(resolved, init);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (input instanceof URL) {
|
|
179
|
-
return fetch(input, init);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return fetch(input, init);
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
server,
|
|
187
|
-
registry,
|
|
188
|
-
port,
|
|
189
|
-
baseUrl,
|
|
190
|
-
fetch: fetchImpl,
|
|
191
|
-
close,
|
|
192
|
-
async [Symbol.asyncDispose]() {
|
|
193
|
-
close();
|
|
194
|
-
},
|
|
195
|
-
};
|
|
196
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @mandujs/core/testing/server
|
|
3
|
+
*
|
|
4
|
+
* In-process server fixture for integration tests.
|
|
5
|
+
*
|
|
6
|
+
* Wraps `startServer()` with an ephemeral port (`0`), a per-test
|
|
7
|
+
* `ServerRegistry` (so parallel tests cannot stomp each other's handlers),
|
|
8
|
+
* and a scoped `fetch` helper so callers can write:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { createTestServer } from "@mandujs/core/testing";
|
|
12
|
+
*
|
|
13
|
+
* const server = await createTestServer(manifest, {
|
|
14
|
+
* registerHandlers(reg) {
|
|
15
|
+
* reg.registerApiHandler("api/health", async () => Response.json({ ok: true }));
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
* afterAll(() => server.close());
|
|
19
|
+
*
|
|
20
|
+
* const res = await server.fetch("/api/health");
|
|
21
|
+
* expect(res.status).toBe(200);
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* ## Design
|
|
25
|
+
*
|
|
26
|
+
* - **Registry isolation** — the fixture always creates its own
|
|
27
|
+
* `ServerRegistry` (via `createServerRegistry()`), never touches the default
|
|
28
|
+
* global. That lets several fixtures run concurrently in the same test
|
|
29
|
+
* process without handler collisions.
|
|
30
|
+
* - **Port zero** — Bun picks an OS-assigned ephemeral port; the fixture
|
|
31
|
+
* exposes the resolved port and a pre-computed `baseUrl` so tests never
|
|
32
|
+
* hard-code `:3000`.
|
|
33
|
+
* - **Scoped `fetch`** — accepts either an absolute URL or a root-relative
|
|
34
|
+
* path; the latter is joined to `baseUrl`. This matches the ergonomics
|
|
35
|
+
* of `supertest` / Remix `createRoutesStub` without taking a dep on them.
|
|
36
|
+
* - **Cleanup contract** — `close()` is idempotent; the returned handle is
|
|
37
|
+
* also `asyncDispose`-compatible so `using server = await createTestServer(...)`
|
|
38
|
+
* works under Bun's Explicit Resource Management.
|
|
39
|
+
*
|
|
40
|
+
* @module testing/server
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import type { RoutesManifest } from "../spec/schema";
|
|
44
|
+
import {
|
|
45
|
+
startServer,
|
|
46
|
+
createServerRegistry,
|
|
47
|
+
type ManduServer,
|
|
48
|
+
type ServerOptions,
|
|
49
|
+
type ServerRegistry,
|
|
50
|
+
} from "../runtime/server";
|
|
51
|
+
|
|
52
|
+
/** Options accepted by {@link createTestServer}. */
|
|
53
|
+
export interface CreateTestServerOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Optional registration callback. The fixture creates a fresh
|
|
56
|
+
* `ServerRegistry` and passes it here so tests can attach API handlers,
|
|
57
|
+
* page loaders, layouts, and so on synchronously before the server starts
|
|
58
|
+
* listening. Skip when the manifest's handlers are resolved elsewhere.
|
|
59
|
+
*/
|
|
60
|
+
registerHandlers?: (registry: ServerRegistry) => void | Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Host to bind. Default: `"127.0.0.1"` (explicit IPv4 so Windows CI boxes
|
|
63
|
+
* do not fall through to `::1` and break `fetch` default resolution).
|
|
64
|
+
*/
|
|
65
|
+
hostname?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Extra options forwarded to `startServer()`. The fixture overrides
|
|
68
|
+
* `port`, `registry`, and `isDev` — those keys are ignored if present.
|
|
69
|
+
*/
|
|
70
|
+
serverOptions?: Omit<ServerOptions, "port" | "registry" | "isDev" | "hostname">;
|
|
71
|
+
/** Set to `true` to boot the server in dev mode (HMR, kitchen, etc.). Default: `false`. */
|
|
72
|
+
isDev?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The fixture handle returned by {@link createTestServer}. */
|
|
76
|
+
export interface TestServer {
|
|
77
|
+
/** The underlying `ManduServer` (access `server.server.port` if you need Bun handles). */
|
|
78
|
+
readonly server: ManduServer;
|
|
79
|
+
/** The registry the fixture created. Use this to register handlers *after* startup. */
|
|
80
|
+
readonly registry: ServerRegistry;
|
|
81
|
+
/** Resolved port (non-zero once `await`ed). */
|
|
82
|
+
readonly port: number;
|
|
83
|
+
/** `http://<host>:<port>` with no trailing slash. */
|
|
84
|
+
readonly baseUrl: string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Scoped fetch — accepts a path (`"/api/foo"`) or absolute URL
|
|
88
|
+
* (`"http://other/..."`). Path-style inputs are joined to `baseUrl`.
|
|
89
|
+
*
|
|
90
|
+
* ```ts
|
|
91
|
+
* await server.fetch("/api/health")
|
|
92
|
+
* await server.fetch("/api/login", { method: "POST", body: JSON.stringify({...}) })
|
|
93
|
+
* await server.fetch(new Request("http://localhost/anything"))
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Idempotent teardown. Stops the underlying `Bun.serve` instance and
|
|
100
|
+
* clears the registry so no handler leaks into the next fixture.
|
|
101
|
+
*/
|
|
102
|
+
close(): void;
|
|
103
|
+
|
|
104
|
+
/** Explicit Resource Management support: `using server = await createTestServer(...)`. */
|
|
105
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Boot an in-process test server on an ephemeral port.
|
|
110
|
+
*
|
|
111
|
+
* Returns once `Bun.serve` is listening — no polling required; Bun binds
|
|
112
|
+
* synchronously before `fetch` becomes ready.
|
|
113
|
+
*
|
|
114
|
+
* @throws if `manifest` is missing required fields (handler resolution errors
|
|
115
|
+
* surface on the first `fetch`, not here).
|
|
116
|
+
*/
|
|
117
|
+
export async function createTestServer(
|
|
118
|
+
manifest: RoutesManifest,
|
|
119
|
+
options: CreateTestServerOptions = {},
|
|
120
|
+
): Promise<TestServer> {
|
|
121
|
+
const registry = createServerRegistry();
|
|
122
|
+
|
|
123
|
+
if (options.registerHandlers) {
|
|
124
|
+
await options.registerHandlers(registry);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const hostname = options.hostname ?? "127.0.0.1";
|
|
128
|
+
const server = startServer(manifest, {
|
|
129
|
+
...(options.serverOptions ?? {}),
|
|
130
|
+
port: 0,
|
|
131
|
+
hostname,
|
|
132
|
+
isDev: options.isDev ?? false,
|
|
133
|
+
registry,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Bun.serve always resolves the port synchronously before returning the
|
|
137
|
+
// handle — `undefined` would only happen on a fully-closed server, which
|
|
138
|
+
// is impossible here because we just created it. Assert + narrow so
|
|
139
|
+
// consumers see a plain `number`.
|
|
140
|
+
if (typeof server.server.port !== "number") {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"[testing/server] startServer() returned without a bound port. This is a framework-level bug — please report.",
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
const port: number = server.server.port;
|
|
146
|
+
const baseUrl = `http://${hostname}:${port}`;
|
|
147
|
+
|
|
148
|
+
let closed = false;
|
|
149
|
+
const close = (): void => {
|
|
150
|
+
if (closed) return;
|
|
151
|
+
closed = true;
|
|
152
|
+
try {
|
|
153
|
+
server.stop();
|
|
154
|
+
} catch {
|
|
155
|
+
// stop() is best-effort — swallow so afterEach doesn't mask real test failures.
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const fetchImpl = async (
|
|
160
|
+
input: string | URL | Request,
|
|
161
|
+
init?: RequestInit,
|
|
162
|
+
): Promise<Response> => {
|
|
163
|
+
if (closed) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
"[testing/server] fetch() called after close() — did an afterAll run before this test?",
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Resolve path-style inputs against baseUrl. Absolute URLs and Request
|
|
170
|
+
// objects pass through untouched so callers keep full control.
|
|
171
|
+
if (typeof input === "string") {
|
|
172
|
+
const resolved = input.startsWith("http://") || input.startsWith("https://")
|
|
173
|
+
? input
|
|
174
|
+
: `${baseUrl}${input.startsWith("/") ? "" : "/"}${input}`;
|
|
175
|
+
return fetch(resolved, init);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (input instanceof URL) {
|
|
179
|
+
return fetch(input, init);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return fetch(input, init);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
server,
|
|
187
|
+
registry,
|
|
188
|
+
port,
|
|
189
|
+
baseUrl,
|
|
190
|
+
fetch: fetchImpl,
|
|
191
|
+
close,
|
|
192
|
+
async [Symbol.asyncDispose]() {
|
|
193
|
+
close();
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|