@mandujs/core 0.53.2 → 0.54.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/README.md +654 -654
- package/package.json +2 -2
- package/src/a11y/__tests__/run-audit.test.ts +333 -333
- package/src/a11y/fix-hints.ts +76 -76
- package/src/a11y/index.ts +18 -18
- package/src/a11y/run-audit.ts +394 -394
- package/src/a11y/types.ts +125 -125
- package/src/auth/__tests__/login.test.ts +1 -1
- package/src/auth/__tests__/password.test.ts +122 -122
- package/src/auth/__tests__/tokens.test.ts +274 -274
- package/src/auth/__tests__/verification.test.ts +274 -274
- package/src/auth/index.ts +76 -76
- package/src/auth/login.ts +225 -225
- package/src/auth/password.ts +120 -120
- package/src/auth/reset.ts +243 -243
- package/src/auth/tokens.ts +612 -612
- package/src/auth/verification.ts +253 -253
- package/src/brain/__tests__/redactor.test.ts +94 -94
- package/src/brain/adapters/__tests__/_helpers.ts +83 -83
- package/src/brain/adapters/__tests__/anthropic-oauth.test.ts +196 -196
- package/src/brain/adapters/__tests__/chatgpt-auth.test.ts +193 -193
- package/src/brain/adapters/__tests__/openai-oauth.test.ts +209 -209
- package/src/brain/adapters/__tests__/resolver.test.ts +143 -143
- package/src/brain/adapters/anthropic-oauth.ts +1 -1
- package/src/brain/adapters/chatgpt-auth.ts +300 -300
- package/src/brain/adapters/index.ts +319 -319
- package/src/brain/adapters/oauth-flow.ts +439 -439
- package/src/brain/consent.ts +240 -240
- package/src/brain/credentials.ts +396 -396
- package/src/bundler/__tests__/build-runner.ts +113 -113
- package/src/bundler/__tests__/dev-reliability.test.ts +619 -619
- package/src/bundler/__tests__/extended-watch.test.ts +711 -711
- package/src/bundler/__tests__/fast-refresh.test.ts +10 -10
- package/src/bundler/__tests__/hdr.test.ts +353 -353
- package/src/bundler/__tests__/hmr-client.test.ts +532 -532
- package/src/bundler/__tests__/manifest-schema.test.ts +266 -266
- package/src/bundler/__tests__/prod-smoke.test.ts +138 -138
- package/src/bundler/__tests__/reverse-import-graph.test.ts +519 -519
- package/src/bundler/__tests__/slot-dispatch.test.ts +573 -573
- package/src/bundler/__tests__/url-cap-and-slot-regex.test.ts +286 -286
- package/src/bundler/__tests__/vendor-cache.test.ts +455 -455
- package/src/bundler/budget.ts +404 -404
- package/src/bundler/build.test.ts +179 -179
- package/src/bundler/build.ts +55 -55
- package/src/bundler/dev.ts +42 -42
- package/src/bundler/manifest-schema.ts +301 -301
- package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +263 -263
- package/src/bundler/plugins/__tests__/react-compiler-config.test.ts +83 -83
- package/src/bundler/plugins/__tests__/react-compiler-lint.test.ts +110 -110
- package/src/bundler/plugins/block-generated-imports.ts +155 -155
- package/src/bundler/plugins/index.ts +83 -83
- package/src/bundler/plugins/react-compiler-config.ts +108 -108
- package/src/bundler/plugins/react-compiler-lint.ts +253 -253
- package/src/bundler/plugins/react-compiler.ts +162 -162
- package/src/bundler/reverse-import-graph.ts +339 -339
- package/src/bundler/safe-build.test.ts +201 -201
- package/src/bundler/safe-build.ts +103 -103
- package/src/bundler/scenario-matrix.ts +229 -229
- package/src/bundler/types.ts +10 -10
- package/src/bundler/vendor-cache-types.ts +130 -130
- package/src/bundler/vendor-cache.ts +526 -526
- package/src/change/snapshot.ts +18 -18
- package/src/client/Form.tsx +105 -105
- package/src/client/Link.tsx +9 -9
- package/src/client/__tests__/use-sse.test.ts +153 -153
- package/src/client/globals.ts +1 -1
- package/src/client/hooks.ts +362 -362
- package/src/client/hydrate.ts +340 -340
- package/src/client/prefetch-helper.ts +55 -55
- package/src/client/router.ts +11 -11
- package/src/client/runtime.ts +47 -47
- package/src/client/serialize.ts +404 -404
- package/src/client/use-fetch.ts +6 -6
- package/src/client/use-head.ts +197 -197
- package/src/client/use-sse.ts +378 -378
- package/src/client/window-state.ts +101 -101
- package/src/components/Image.tsx +162 -162
- package/src/config/validate.ts +3 -3
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/collection.ts +8 -8
- package/src/content/content-layer.ts +7 -7
- package/src/content/data-store.ts +245 -245
- package/src/content/frontmatter.ts +189 -189
- package/src/content/loader-context.ts +171 -171
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +172 -172
- package/src/content/loaders/glob.ts +253 -253
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/prebuild.test.ts +571 -571
- package/src/content/prebuild.ts +636 -636
- package/src/content/schema.ts +20 -20
- package/src/content/sidebar.ts +630 -630
- package/src/content/slug.ts +110 -110
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/define.ts +11 -11
- package/src/contract/index.ts +1 -1
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +410 -410
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/route-helpers.ts +1 -1
- package/src/contract/rpc.ts +443 -443
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/db/__tests__/db.test.ts +482 -482
- package/src/db/index.ts +138 -138
- package/src/db/migrations/history-table.ts +345 -345
- package/src/db/migrations/index.ts +3 -3
- package/src/db/migrations/lock.ts +324 -324
- package/src/db/migrations/runner.ts +650 -650
- package/src/deploy/cache.ts +140 -140
- package/src/deploy/compile/vercel.ts +344 -344
- package/src/deploy/index.ts +87 -87
- package/src/deploy/inference/brain.ts +268 -268
- package/src/deploy/inference/context.ts +182 -182
- package/src/deploy/inference/filling-extract.ts +245 -245
- package/src/deploy/inference/heuristic.ts +182 -182
- package/src/deploy/intent.ts +173 -173
- package/src/deploy/plan.ts +178 -178
- package/src/design/__tests__/agents-link.test.ts +109 -109
- package/src/design/__tests__/extract-patch-diff.test.ts +265 -265
- package/src/design/__tests__/lint.test.ts +110 -110
- package/src/design/__tests__/parser.test.ts +195 -195
- package/src/design/__tests__/tailwind-theme.test.ts +229 -229
- package/src/design/agents-link.ts +165 -165
- package/src/design/diff.ts +138 -138
- package/src/design/extract.ts +285 -285
- package/src/design/index.ts +102 -102
- package/src/design/lint.ts +209 -209
- package/src/design/parser.ts +555 -555
- package/src/design/patch.ts +241 -241
- package/src/design/scaffold.ts +147 -147
- package/src/design/tailwind-theme.ts +441 -441
- package/src/design/types.ts +210 -210
- package/src/desktop/__tests__/webview-fallback.test.ts +254 -254
- package/src/desktop/__tests__/window.test.ts +248 -248
- package/src/desktop/__tests__/worker.test.ts +266 -266
- package/src/desktop/index.ts +43 -43
- package/src/desktop/types.ts +158 -158
- package/src/desktop/worker.ts +180 -180
- package/src/dev-error-overlay/__tests__/overlay-injector.test.ts +241 -241
- package/src/dev-error-overlay/index.ts +30 -30
- package/src/dev-error-overlay/overlay-injector.ts +243 -243
- package/src/dev-error-overlay/overlay-styles.ts +52 -52
- package/src/dev-error-overlay/types.ts +66 -66
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +25 -25
- package/src/devtools/client/catchers/error-catcher.ts +344 -344
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/mandu-character.tsx +331 -331
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +30 -30
- package/src/devtools/client/components/panel/islands-panel.tsx +320 -320
- package/src/devtools/client/components/panel/network-panel.tsx +291 -291
- package/src/devtools/client/components/panel/panel-container.tsx +500 -500
- package/src/devtools/client/components/panel/preview-panel.tsx +46 -46
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +265 -265
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +450 -450
- package/src/devtools/types.ts +35 -35
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +233 -233
- package/src/devtools/worker/worker-manager.ts +410 -410
- package/src/diagnose/__tests__/checks.test.ts +451 -380
- package/src/diagnose/checks.ts +832 -720
- package/src/diagnose/index.ts +17 -16
- package/src/diagnose/run.ts +93 -91
- package/src/diagnose/types.ts +53 -53
- package/src/email/__tests__/email.test.ts +355 -355
- package/src/email/index.ts +282 -282
- package/src/email/smtp.ts +64 -64
- package/src/error/domains.ts +265 -265
- package/src/error/result.ts +60 -60
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/__tests__/session-sqlite.test.ts +454 -454
- package/src/filling/auth.ts +308 -308
- package/src/filling/cookie-codec.ts +299 -299
- package/src/filling/deps.ts +265 -265
- package/src/filling/session-sqlite.ts +617 -617
- package/src/filling/sse.ts +5 -5
- package/src/filling/ws.ts +78 -78
- package/src/generator/index.ts +3 -3
- package/src/guard/__tests__/design-inline-class.test.ts +219 -219
- package/src/guard/__tests__/tsgolint-bridge.test.ts +347 -347
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/auto-correct.ts +1 -1
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/define-rule.ts +243 -243
- package/src/guard/design-inline-class.ts +393 -393
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/graph.ts +1 -1
- package/src/guard/healing.ts +36 -36
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/reporter.ts +442 -442
- package/src/guard/rule-presets.ts +379 -379
- package/src/guard/semantic-slots.ts +1 -1
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/tsgolint-bridge.ts +512 -512
- package/src/guard/types.ts +348 -348
- package/src/guard/watcher.ts +405 -405
- package/src/i18n/define.ts +126 -126
- package/src/i18n/index.ts +52 -52
- package/src/i18n/message-registry.ts +173 -173
- package/src/i18n/types.ts +112 -112
- package/src/id/index.ts +105 -105
- package/src/index.ts +2 -2
- package/src/kitchen/api/agent-devtools-api.ts +779 -544
- package/src/kitchen/api/errors-grouping.ts +126 -0
- package/src/kitchen/kitchen-handler.ts +192 -63
- package/src/kitchen/kitchen-ui.ts +842 -464
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/middleware/bridge.ts +147 -147
- package/src/middleware/compose.ts +134 -134
- package/src/middleware/compress.ts +62 -62
- package/src/middleware/cors.ts +47 -47
- package/src/middleware/csrf.ts +328 -328
- package/src/middleware/define.ts +132 -132
- package/src/middleware/jwt.ts +134 -134
- package/src/middleware/logger.ts +58 -58
- package/src/middleware/oauth/__tests__/oauth.test.ts +1 -1
- package/src/middleware/oauth/index.ts +505 -505
- package/src/middleware/oauth/providers.ts +115 -115
- package/src/middleware/rate-limit/index.ts +522 -522
- package/src/middleware/rate-limit/sqlite-store.ts +382 -382
- package/src/middleware/scheduler-cron.ts +96 -96
- package/src/middleware/secure/__tests__/secure.test.ts +360 -360
- package/src/middleware/secure/csp.ts +193 -193
- package/src/middleware/session.ts +174 -174
- package/src/middleware/timeout.ts +55 -55
- package/src/observability/logger-adapter.ts +36 -36
- package/src/observability/sqlite-store.ts +254 -254
- package/src/openapi/generator.ts +1 -1
- package/src/openapi/openapi.test.ts +43 -43
- package/src/perf/__tests__/user-marks.test.ts +354 -354
- package/src/perf/index.ts +133 -133
- package/src/plugins/__tests__/lifecycle-integration.test.ts +272 -272
- package/src/plugins/__tests__/runner.test.ts +409 -409
- package/src/plugins/define.ts +124 -124
- package/src/plugins/examples/dep-check-plugin.ts +80 -80
- package/src/plugins/examples/prerender-cache-plugin.ts +111 -111
- package/src/plugins/examples/sitemap-plugin.ts +65 -65
- package/src/plugins/runner.ts +361 -361
- package/src/plugins/types.ts +368 -368
- package/src/report/index.ts +1 -1
- package/src/resource/__tests__/generator.test.ts +32 -32
- package/src/resource/ddl/__tests__/diff.test.ts +639 -639
- package/src/resource/ddl/__tests__/emit.test.ts +823 -823
- package/src/resource/ddl/__tests__/snapshot.test.ts +499 -499
- package/src/resource/ddl/emit.ts +559 -559
- package/src/resource/ddl/persistence-types.ts +218 -218
- package/src/resource/ddl/type-map.ts +223 -223
- package/src/resource/ddl/types.ts +232 -232
- package/src/resource/generator-repo.ts +630 -630
- package/src/resource/schema.ts +1 -1
- package/src/router/fs-patterns.test.ts +96 -96
- package/src/router/fs-routes.ts +6 -6
- package/src/routes/index.ts +74 -74
- package/src/routes/metadata-routes.ts +427 -427
- package/src/routes/types.ts +341 -341
- package/src/runtime/__tests__/error-boundary-redaction.test.ts +141 -141
- package/src/runtime/__tests__/hdr-client.test.ts +223 -223
- package/src/runtime/__tests__/http-errors.test.ts +117 -117
- package/src/runtime/__tests__/not-found.test.ts +152 -152
- package/src/runtime/adapter.ts +47 -47
- package/src/runtime/boundary.tsx +252 -252
- package/src/runtime/cache.ts +494 -494
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/fast-refresh-runtime.ts +322 -322
- package/src/runtime/handler.ts +65 -65
- package/src/runtime/handlers.ts +300 -300
- package/src/runtime/http-errors.ts +113 -113
- package/src/runtime/image-handler.ts +1 -1
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/middleware.ts +264 -264
- package/src/runtime/not-found.ts +93 -93
- package/src/runtime/openapi-endpoint.ts +236 -236
- package/src/runtime/ppr.ts +74 -74
- package/src/runtime/registry.ts +171 -171
- package/src/runtime/router.ts +105 -105
- package/src/runtime/server.ts +67 -67
- package/src/runtime/shims.ts +48 -48
- package/src/runtime/ssr.ts +24 -31
- package/src/runtime/streaming-ssr.ts +32 -37
- package/src/runtime/trace.ts +144 -144
- package/src/scheduler/validate.ts +169 -169
- package/src/seo/index.ts +219 -219
- package/src/seo/integration/ssr.ts +306 -306
- package/src/seo/render/basic.ts +435 -435
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +197 -197
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +127 -127
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +104 -104
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +588 -588
- package/src/slot/validator.ts +39 -39
- package/src/storage/s3/__tests__/s3.test.ts +479 -479
- package/src/storage/s3/index.ts +412 -412
- package/src/testing/__tests__/assertions.test.ts +632 -632
- package/src/testing/__tests__/reporter.test.ts +454 -454
- package/src/testing/assertions.ts +986 -986
- package/src/testing/db.ts +157 -157
- package/src/testing/mocks.ts +203 -203
- package/src/testing/session.ts +190 -190
- package/src/types/branded.ts +56 -56
- package/src/types/index.ts +1 -1
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
- package/src/watcher/watcher.ts +18 -18
|
@@ -1,138 +1,138 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 7.2 R1 Agent C (H4) — production bundle smoke tests.
|
|
3
|
-
*
|
|
4
|
-
* Confirms the Phase 7.1 audit finding L-02 regression is closed: a
|
|
5
|
-
* production build (`minify: true`, no Fast Refresh plugin) must NEVER
|
|
6
|
-
* leak the dev-only symbols that would otherwise install Fast Refresh
|
|
7
|
-
* stubs on `window` (`$RefreshReg$` / `$RefreshSig$` / `__MANDU_HMR__`)
|
|
8
|
-
* or pull in the vendor runtime (`_vendor-react-refresh`).
|
|
9
|
-
*
|
|
10
|
-
* We assert at two layers:
|
|
11
|
-
* (A) the generated output JS bundle is free of the dev symbols
|
|
12
|
-
* (B) the returned manifest has `shared.fastRefresh === undefined`
|
|
13
|
-
*
|
|
14
|
-
* Both layers matter because (A) can drift independently of (B) if a
|
|
15
|
-
* future refactor inlines a symbol name into a comment or data literal.
|
|
16
|
-
*
|
|
17
|
-
* References:
|
|
18
|
-
* docs/security/phase-7-1-audit.md §3 L-02
|
|
19
|
-
* docs/bun/phase-7-2-team-plan.md §3 Agent C H4
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
|
|
23
|
-
import { mkdtemp, mkdir, rm, writeFile } from "fs/promises";
|
|
24
|
-
import fs from "fs/promises";
|
|
25
|
-
import { tmpdir } from "os";
|
|
26
|
-
import path from "path";
|
|
27
|
-
import { fastRefreshPlugin } from "../fast-refresh-plugin";
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Strings we treat as dev-only Fast Refresh fingerprints. Any of them
|
|
31
|
-
* appearing in a prod bundle is a leak. We keep the list small and
|
|
32
|
-
* precise so we don't false-flag legitimate unrelated code.
|
|
33
|
-
*/
|
|
34
|
-
const DEV_LEAK_FINGERPRINTS = [
|
|
35
|
-
"$RefreshReg$",
|
|
36
|
-
"$RefreshSig$",
|
|
37
|
-
"__MANDU_HMR__",
|
|
38
|
-
"_vendor-react-refresh",
|
|
39
|
-
"_fast-refresh-runtime",
|
|
40
|
-
] as const;
|
|
41
|
-
|
|
42
|
-
// Integration tests that spin up Bun.build are gated on CI flaky-matrix
|
|
43
|
-
// environments. See `fast-refresh.test.ts` for the same pattern.
|
|
44
|
-
describe.skipIf(process.env.MANDU_SKIP_BUNDLER_TESTS === "1")(
|
|
45
|
-
"prod-smoke — no Fast Refresh leak in production bundles",
|
|
46
|
-
() => {
|
|
47
|
-
let rootDir = "";
|
|
48
|
-
|
|
49
|
-
beforeAll(async () => {
|
|
50
|
-
rootDir = await mkdtemp(path.join(tmpdir(), "mandu-prod-smoke-"));
|
|
51
|
-
// Minimal island source — no JSX runtime, no imports, small AST
|
|
52
|
-
await writeFile(
|
|
53
|
-
path.join(rootDir, "counter.client.tsx"),
|
|
54
|
-
`import { useState } from 'react';
|
|
55
|
-
export default function Counter() {
|
|
56
|
-
const [count, setCount] = useState(0);
|
|
57
|
-
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
|
|
58
|
-
}
|
|
59
|
-
`,
|
|
60
|
-
"utf-8",
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
afterAll(async () => {
|
|
65
|
-
if (rootDir) await rm(rootDir, { recursive: true, force: true });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("[S1] production build output contains no dev-only Fast Refresh symbols", async () => {
|
|
69
|
-
// Prod path: `reactFastRefresh` off, plugin `disabled: true`,
|
|
70
|
-
// minify on. Matches the config `buildClientBundles` uses when
|
|
71
|
-
// `options.minify === true`.
|
|
72
|
-
const result = await Bun.build({
|
|
73
|
-
entrypoints: [path.join(rootDir, "counter.client.tsx")],
|
|
74
|
-
target: "browser",
|
|
75
|
-
minify: true,
|
|
76
|
-
plugins: [fastRefreshPlugin({ disabled: true })],
|
|
77
|
-
external: ["react", "react-dom", "react/jsx-dev-runtime", "react/jsx-runtime"],
|
|
78
|
-
});
|
|
79
|
-
expect(result.success).toBe(true);
|
|
80
|
-
|
|
81
|
-
const src = await result.outputs[0]!.text();
|
|
82
|
-
for (const fingerprint of DEV_LEAK_FINGERPRINTS) {
|
|
83
|
-
expect(src.includes(fingerprint)).toBe(false);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("[S2] prod build with reactFastRefresh=true explicitly disabled does not emit stubs", async () => {
|
|
88
|
-
// Defense-in-depth: even if a future config accident leaves
|
|
89
|
-
// `reactFastRefresh: false` off-by-default, the disabled plugin
|
|
90
|
-
// MUST still prevent injection. We pass reactFastRefresh: false
|
|
91
|
-
// here to represent the guaranteed-prod config.
|
|
92
|
-
const result = await Bun.build({
|
|
93
|
-
entrypoints: [path.join(rootDir, "counter.client.tsx")],
|
|
94
|
-
target: "browser",
|
|
95
|
-
minify: true,
|
|
96
|
-
reactFastRefresh: false,
|
|
97
|
-
plugins: [fastRefreshPlugin({ disabled: true })],
|
|
98
|
-
external: ["react", "react-dom", "react/jsx-dev-runtime", "react/jsx-runtime"],
|
|
99
|
-
});
|
|
100
|
-
expect(result.success).toBe(true);
|
|
101
|
-
|
|
102
|
-
const src = await result.outputs[0]!.text();
|
|
103
|
-
expect(src).not.toContain("$RefreshReg$");
|
|
104
|
-
expect(src).not.toContain("$RefreshSig$");
|
|
105
|
-
expect(src).not.toContain("__MANDU_HMR__");
|
|
106
|
-
});
|
|
107
|
-
},
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
// Pure manifest-shape tests run regardless of the bundler skip flag —
|
|
111
|
-
// they don't invoke Bun.build and are safe everywhere.
|
|
112
|
-
describe("prod-smoke — manifest shape invariants (no Bun.build)", () => {
|
|
113
|
-
test("[M1] buildClientBundles prod path would omit shared.fastRefresh", async () => {
|
|
114
|
-
// We cannot easily invoke `buildClientBundles` here without a
|
|
115
|
-
// full Mandu project scaffold, so we assert the contract
|
|
116
|
-
// semantically via the static build.ts source: the `fastRefresh`
|
|
117
|
-
// field is populated only when the vendor shim result has both
|
|
118
|
-
// `reactRefreshRuntime` and `fastRefreshRuntime`. In prod mode
|
|
119
|
-
// `buildVendorShims` is called with `isDev: false` which returns
|
|
120
|
-
// empty strings for those — unwinding to `undefined` in the
|
|
121
|
-
// ternary at `build.ts:1548-1554`.
|
|
122
|
-
//
|
|
123
|
-
// This test documents the invariant textually; the bundler-level
|
|
124
|
-
// integration tests (S1/S2 above) prove the output side.
|
|
125
|
-
const buildSource = await fs.readFile(
|
|
126
|
-
path.join(
|
|
127
|
-
import.meta.dir,
|
|
128
|
-
"..",
|
|
129
|
-
"build.ts",
|
|
130
|
-
),
|
|
131
|
-
"utf-8",
|
|
132
|
-
);
|
|
133
|
-
// The precise construction MUST be guarded by runtime presence.
|
|
134
|
-
expect(buildSource).toContain("vendorResult.reactRefreshRuntime && vendorResult.fastRefreshRuntime");
|
|
135
|
-
// And MUST spread-conditionally include the field.
|
|
136
|
-
expect(buildSource).toContain("...(fastRefresh ? { fastRefresh } : {})");
|
|
137
|
-
});
|
|
138
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Phase 7.2 R1 Agent C (H4) — production bundle smoke tests.
|
|
3
|
+
*
|
|
4
|
+
* Confirms the Phase 7.1 audit finding L-02 regression is closed: a
|
|
5
|
+
* production build (`minify: true`, no Fast Refresh plugin) must NEVER
|
|
6
|
+
* leak the dev-only symbols that would otherwise install Fast Refresh
|
|
7
|
+
* stubs on `window` (`$RefreshReg$` / `$RefreshSig$` / `__MANDU_HMR__`)
|
|
8
|
+
* or pull in the vendor runtime (`_vendor-react-refresh`).
|
|
9
|
+
*
|
|
10
|
+
* We assert at two layers:
|
|
11
|
+
* (A) the generated output JS bundle is free of the dev symbols
|
|
12
|
+
* (B) the returned manifest has `shared.fastRefresh === undefined`
|
|
13
|
+
*
|
|
14
|
+
* Both layers matter because (A) can drift independently of (B) if a
|
|
15
|
+
* future refactor inlines a symbol name into a comment or data literal.
|
|
16
|
+
*
|
|
17
|
+
* References:
|
|
18
|
+
* docs/security/phase-7-1-audit.md §3 L-02
|
|
19
|
+
* docs/bun/phase-7-2-team-plan.md §3 Agent C H4
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { describe, expect, test, beforeAll, afterAll } from "bun:test";
|
|
23
|
+
import { mkdtemp, mkdir, rm, writeFile } from "fs/promises";
|
|
24
|
+
import fs from "fs/promises";
|
|
25
|
+
import { tmpdir } from "os";
|
|
26
|
+
import path from "path";
|
|
27
|
+
import { fastRefreshPlugin } from "../fast-refresh-plugin";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Strings we treat as dev-only Fast Refresh fingerprints. Any of them
|
|
31
|
+
* appearing in a prod bundle is a leak. We keep the list small and
|
|
32
|
+
* precise so we don't false-flag legitimate unrelated code.
|
|
33
|
+
*/
|
|
34
|
+
const DEV_LEAK_FINGERPRINTS = [
|
|
35
|
+
"$RefreshReg$",
|
|
36
|
+
"$RefreshSig$",
|
|
37
|
+
"__MANDU_HMR__",
|
|
38
|
+
"_vendor-react-refresh",
|
|
39
|
+
"_fast-refresh-runtime",
|
|
40
|
+
] as const;
|
|
41
|
+
|
|
42
|
+
// Integration tests that spin up Bun.build are gated on CI flaky-matrix
|
|
43
|
+
// environments. See `fast-refresh.test.ts` for the same pattern.
|
|
44
|
+
describe.skipIf(process.env.MANDU_SKIP_BUNDLER_TESTS === "1")(
|
|
45
|
+
"prod-smoke — no Fast Refresh leak in production bundles",
|
|
46
|
+
() => {
|
|
47
|
+
let rootDir = "";
|
|
48
|
+
|
|
49
|
+
beforeAll(async () => {
|
|
50
|
+
rootDir = await mkdtemp(path.join(tmpdir(), "mandu-prod-smoke-"));
|
|
51
|
+
// Minimal island source — no JSX runtime, no imports, small AST
|
|
52
|
+
await writeFile(
|
|
53
|
+
path.join(rootDir, "counter.client.tsx"),
|
|
54
|
+
`import { useState } from 'react';
|
|
55
|
+
export default function Counter() {
|
|
56
|
+
const [count, setCount] = useState(0);
|
|
57
|
+
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
|
|
58
|
+
}
|
|
59
|
+
`,
|
|
60
|
+
"utf-8",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
afterAll(async () => {
|
|
65
|
+
if (rootDir) await rm(rootDir, { recursive: true, force: true });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("[S1] production build output contains no dev-only Fast Refresh symbols", async () => {
|
|
69
|
+
// Prod path: `reactFastRefresh` off, plugin `disabled: true`,
|
|
70
|
+
// minify on. Matches the config `buildClientBundles` uses when
|
|
71
|
+
// `options.minify === true`.
|
|
72
|
+
const result = await Bun.build({
|
|
73
|
+
entrypoints: [path.join(rootDir, "counter.client.tsx")],
|
|
74
|
+
target: "browser",
|
|
75
|
+
minify: true,
|
|
76
|
+
plugins: [fastRefreshPlugin({ disabled: true })],
|
|
77
|
+
external: ["react", "react-dom", "react/jsx-dev-runtime", "react/jsx-runtime"],
|
|
78
|
+
});
|
|
79
|
+
expect(result.success).toBe(true);
|
|
80
|
+
|
|
81
|
+
const src = await result.outputs[0]!.text();
|
|
82
|
+
for (const fingerprint of DEV_LEAK_FINGERPRINTS) {
|
|
83
|
+
expect(src.includes(fingerprint)).toBe(false);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("[S2] prod build with reactFastRefresh=true explicitly disabled does not emit stubs", async () => {
|
|
88
|
+
// Defense-in-depth: even if a future config accident leaves
|
|
89
|
+
// `reactFastRefresh: false` off-by-default, the disabled plugin
|
|
90
|
+
// MUST still prevent injection. We pass reactFastRefresh: false
|
|
91
|
+
// here to represent the guaranteed-prod config.
|
|
92
|
+
const result = await Bun.build({
|
|
93
|
+
entrypoints: [path.join(rootDir, "counter.client.tsx")],
|
|
94
|
+
target: "browser",
|
|
95
|
+
minify: true,
|
|
96
|
+
reactFastRefresh: false,
|
|
97
|
+
plugins: [fastRefreshPlugin({ disabled: true })],
|
|
98
|
+
external: ["react", "react-dom", "react/jsx-dev-runtime", "react/jsx-runtime"],
|
|
99
|
+
});
|
|
100
|
+
expect(result.success).toBe(true);
|
|
101
|
+
|
|
102
|
+
const src = await result.outputs[0]!.text();
|
|
103
|
+
expect(src).not.toContain("$RefreshReg$");
|
|
104
|
+
expect(src).not.toContain("$RefreshSig$");
|
|
105
|
+
expect(src).not.toContain("__MANDU_HMR__");
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Pure manifest-shape tests run regardless of the bundler skip flag —
|
|
111
|
+
// they don't invoke Bun.build and are safe everywhere.
|
|
112
|
+
describe("prod-smoke — manifest shape invariants (no Bun.build)", () => {
|
|
113
|
+
test("[M1] buildClientBundles prod path would omit shared.fastRefresh", async () => {
|
|
114
|
+
// We cannot easily invoke `buildClientBundles` here without a
|
|
115
|
+
// full Mandu project scaffold, so we assert the contract
|
|
116
|
+
// semantically via the static build.ts source: the `fastRefresh`
|
|
117
|
+
// field is populated only when the vendor shim result has both
|
|
118
|
+
// `reactRefreshRuntime` and `fastRefreshRuntime`. In prod mode
|
|
119
|
+
// `buildVendorShims` is called with `isDev: false` which returns
|
|
120
|
+
// empty strings for those — unwinding to `undefined` in the
|
|
121
|
+
// ternary at `build.ts:1548-1554`.
|
|
122
|
+
//
|
|
123
|
+
// This test documents the invariant textually; the bundler-level
|
|
124
|
+
// integration tests (S1/S2 above) prove the output side.
|
|
125
|
+
const buildSource = await fs.readFile(
|
|
126
|
+
path.join(
|
|
127
|
+
import.meta.dir,
|
|
128
|
+
"..",
|
|
129
|
+
"build.ts",
|
|
130
|
+
),
|
|
131
|
+
"utf-8",
|
|
132
|
+
);
|
|
133
|
+
// The precise construction MUST be guarded by runtime presence.
|
|
134
|
+
expect(buildSource).toContain("vendorResult.reactRefreshRuntime && vendorResult.fastRefreshRuntime");
|
|
135
|
+
// And MUST spread-conditionally include the field.
|
|
136
|
+
expect(buildSource).toContain("...(fastRefresh ? { fastRefresh } : {})");
|
|
137
|
+
});
|
|
138
|
+
});
|