@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.
Files changed (88) hide show
  1. package/package.json +21 -4
  2. package/src/auth/__tests__/login.test.ts +420 -419
  3. package/src/auth/__tests__/reset.test.ts +296 -296
  4. package/src/brain/adapters/anthropic-oauth.ts +421 -420
  5. package/src/brain/adapters/index.ts +2 -1
  6. package/src/brain/adapters/ollama.ts +1 -1
  7. package/src/brain/adapters/openai-oauth.ts +534 -533
  8. package/src/brain/brain.ts +2 -1
  9. package/src/brain/redactor.ts +196 -196
  10. package/src/bundler/__tests__/cli-bench-utils.test.ts +149 -149
  11. package/src/bundler/__tests__/cold-start.test.ts +504 -504
  12. package/src/bundler/__tests__/fast-refresh.test.ts +607 -606
  13. package/src/bundler/__tests__/hdr.test.ts +1 -1
  14. package/src/bundler/analyzer.ts +958 -958
  15. package/src/bundler/build.ts +104 -14
  16. package/src/bundler/dev.ts +125 -0
  17. package/src/bundler/hmr-types.ts +1 -0
  18. package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -0
  19. package/src/bundler/plugins/index.ts +14 -0
  20. package/src/bundler/plugins/react-compiler-lint.ts +253 -0
  21. package/src/bundler/plugins/react-compiler.ts +162 -0
  22. package/src/bundler/types.ts +12 -0
  23. package/src/change/integrity.ts +2 -1
  24. package/src/client/index.ts +10 -0
  25. package/src/client/island.ts +38 -11
  26. package/src/client/router.ts +6 -1
  27. package/src/config/mandu.ts +57 -0
  28. package/src/config/validate.ts +42 -0
  29. package/src/content/collection.ts +844 -809
  30. package/src/content/content-layer.ts +316 -314
  31. package/src/content/content.test.ts +433 -433
  32. package/src/content/digest.ts +133 -133
  33. package/src/content/generate-types.ts +168 -168
  34. package/src/content/index.ts +6 -1
  35. package/src/content/llms-txt.ts +277 -277
  36. package/src/contract/define.ts +474 -474
  37. package/src/contract/route-helpers.ts +2 -1
  38. package/src/contract/zod-utils.ts +158 -155
  39. package/src/db/index.ts +513 -513
  40. package/src/desktop/__tests__/smoke.test.ts +100 -100
  41. package/src/desktop/webview-fallback.ts +583 -583
  42. package/src/desktop/window.ts +3 -1
  43. package/src/dev-error-overlay/overlay-client.ts +300 -300
  44. package/src/devtools/ai/mcp-connector.ts +499 -498
  45. package/src/devtools/client/components/kitchen-root.tsx +7 -2
  46. package/src/email/resend.ts +163 -163
  47. package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -0
  48. package/src/guard/ast-analyzer.ts +806 -806
  49. package/src/guard/graph.ts +898 -898
  50. package/src/guard/index.ts +16 -0
  51. package/src/guard/statistics.ts +578 -578
  52. package/src/guard/tsgolint-bridge.ts +512 -0
  53. package/src/i18n/locale-resolver.ts +214 -214
  54. package/src/id/__tests__/id.test.ts +120 -120
  55. package/src/intent/index.ts +321 -321
  56. package/src/island/index.ts +39 -23
  57. package/src/kitchen/api/contract-api.ts +15 -8
  58. package/src/kitchen/kitchen-ui.ts +2137 -2137
  59. package/src/lockfile/index.ts +3 -2
  60. package/src/middleware/oauth/__tests__/oauth.test.ts +575 -574
  61. package/src/middleware/rate-limit/__tests__/rate-limit.test.ts +642 -642
  62. package/src/middleware/secure/index.ts +417 -417
  63. package/src/observability/event-bus.ts +2 -2
  64. package/src/observability/metrics.ts +334 -334
  65. package/src/observability/tracing.ts +694 -694
  66. package/src/openapi/generator.ts +1 -1
  67. package/src/perf/user-marks.ts +553 -553
  68. package/src/plugins/registry.ts +387 -387
  69. package/src/resource/ddl/diff.ts +392 -392
  70. package/src/resource/ddl/snapshot.ts +448 -447
  71. package/src/resource/generator-schema.ts +477 -476
  72. package/src/resource/parser.ts +4 -2
  73. package/src/resource/schema.ts +1 -1
  74. package/src/router/fs-patterns.ts +422 -422
  75. package/src/runtime/fast-refresh-types.ts +126 -128
  76. package/src/runtime/image-handler.ts +206 -195
  77. package/src/runtime/router.test.ts +476 -476
  78. package/src/runtime/security.ts +155 -155
  79. package/src/runtime/server.ts +36 -19
  80. package/src/runtime/session-key.ts +328 -328
  81. package/src/scheduler/__tests__/scheduler.test.ts +514 -514
  82. package/src/seo/resolve/index.ts +353 -353
  83. package/src/spec/load.ts +1 -1
  84. package/src/testing/reporter.ts +676 -676
  85. package/src/testing/server.ts +196 -196
  86. package/src/testing/snapshot.ts +444 -444
  87. package/src/utils/__tests__/lru-cache.test.ts +186 -186
  88. package/src/utils/bun.ts +8 -8
@@ -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
+ }