@mandujs/core 0.53.3 → 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 -451
- package/src/diagnose/checks.ts +832 -832
- package/src/diagnose/index.ts +17 -17
- package/src/diagnose/run.ts +93 -93
- 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/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,223 +1,223 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 7.2 R1 Agent B — HDR client-side runtime tests.
|
|
3
|
-
*
|
|
4
|
-
* Coverage (pure unit — no DOM, no real WebSocket):
|
|
5
|
-
* 1. dispatchSlotRefetch returns false when no transport is
|
|
6
|
-
* installed (the default "no-router" fallback).
|
|
7
|
-
* 2. setHDRTransport + dispatchSlotRefetch returns the transport's
|
|
8
|
-
* `ok` flag so the caller can decide fallback vs. done.
|
|
9
|
-
* 3. A throwing transport never propagates; dispatchSlotRefetch
|
|
10
|
-
* swallows + returns false so the HMR client stays alive.
|
|
11
|
-
* 4. Transport is isolated per test via _resetRegistryForTests().
|
|
12
|
-
* 5. HDRPayload shape round-trips through the transport (routeId,
|
|
13
|
-
* slotPath, rebuildId, timestamp all preserved — no field is
|
|
14
|
-
* silently dropped).
|
|
15
|
-
*
|
|
16
|
-
* References:
|
|
17
|
-
* docs/bun/phase-7-2-team-plan.md §3 Agent B
|
|
18
|
-
* packages/core/src/runtime/hmr-client.ts — setHDRTransport,
|
|
19
|
-
* dispatchSlotRefetch, _resetRegistryForTests
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { beforeEach, describe, expect, test } from "bun:test";
|
|
23
|
-
import {
|
|
24
|
-
setHDRTransport,
|
|
25
|
-
dispatchSlotRefetch,
|
|
26
|
-
_resetRegistryForTests,
|
|
27
|
-
} from "../hmr-client";
|
|
28
|
-
import type { HDRPayload } from "../../bundler/hmr-types";
|
|
29
|
-
|
|
30
|
-
describe("Phase 7.2 Agent B — dispatchSlotRefetch", () => {
|
|
31
|
-
beforeEach(() => {
|
|
32
|
-
_resetRegistryForTests();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("[1] returns false when no transport is installed (default fallback)", async () => {
|
|
36
|
-
const payload: HDRPayload = {
|
|
37
|
-
type: "slot-refetch",
|
|
38
|
-
routeId: "home",
|
|
39
|
-
slotPath: "app/page.slot.ts",
|
|
40
|
-
rebuildId: 1,
|
|
41
|
-
timestamp: Date.now(),
|
|
42
|
-
};
|
|
43
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
44
|
-
expect(ok).toBe(false);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("[2] returns true when the installed transport resolves ok:true", async () => {
|
|
48
|
-
const received: HDRPayload[] = [];
|
|
49
|
-
setHDRTransport(async (p) => {
|
|
50
|
-
received.push(p);
|
|
51
|
-
return { ok: true };
|
|
52
|
-
});
|
|
53
|
-
const payload: HDRPayload = {
|
|
54
|
-
type: "slot-refetch",
|
|
55
|
-
routeId: "dashboard",
|
|
56
|
-
slotPath: "app/dashboard/page.slot.ts",
|
|
57
|
-
rebuildId: 7,
|
|
58
|
-
timestamp: 1234567890,
|
|
59
|
-
};
|
|
60
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
61
|
-
expect(ok).toBe(true);
|
|
62
|
-
// Full payload passed through unchanged.
|
|
63
|
-
expect(received.length).toBe(1);
|
|
64
|
-
expect(received[0]).toEqual(payload);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test("[3] transport that throws does NOT propagate — dispatchSlotRefetch returns false", async () => {
|
|
68
|
-
setHDRTransport(async () => {
|
|
69
|
-
throw new Error("transport kaboom");
|
|
70
|
-
});
|
|
71
|
-
const payload: HDRPayload = {
|
|
72
|
-
type: "slot-refetch",
|
|
73
|
-
routeId: "home",
|
|
74
|
-
slotPath: "app/page.slot.ts",
|
|
75
|
-
rebuildId: 1,
|
|
76
|
-
timestamp: Date.now(),
|
|
77
|
-
};
|
|
78
|
-
// Must NOT reject. A thrown error in the transport is logged and
|
|
79
|
-
// the caller sees `false` so it can fall back to a full reload.
|
|
80
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
81
|
-
expect(ok).toBe(false);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("[4] transport resolves ok:false with reason — dispatch returns false", async () => {
|
|
85
|
-
setHDRTransport(async () => ({ ok: false, reason: "no-route" as const }));
|
|
86
|
-
const payload: HDRPayload = {
|
|
87
|
-
type: "slot-refetch",
|
|
88
|
-
routeId: "home",
|
|
89
|
-
slotPath: "app/page.slot.ts",
|
|
90
|
-
rebuildId: 1,
|
|
91
|
-
timestamp: Date.now(),
|
|
92
|
-
};
|
|
93
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
94
|
-
expect(ok).toBe(false);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("[5] _resetRegistryForTests restores default (no-transport) behavior", async () => {
|
|
98
|
-
setHDRTransport(async () => ({ ok: true }));
|
|
99
|
-
_resetRegistryForTests();
|
|
100
|
-
const payload: HDRPayload = {
|
|
101
|
-
type: "slot-refetch",
|
|
102
|
-
routeId: "home",
|
|
103
|
-
slotPath: "app/page.slot.ts",
|
|
104
|
-
rebuildId: 1,
|
|
105
|
-
timestamp: Date.now(),
|
|
106
|
-
};
|
|
107
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
108
|
-
// After reset the default "no-router" transport is back.
|
|
109
|
-
expect(ok).toBe(false);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test("[6] two sequential dispatches with different payloads deliver each to transport", async () => {
|
|
113
|
-
const received: HDRPayload[] = [];
|
|
114
|
-
setHDRTransport(async (p) => {
|
|
115
|
-
received.push(p);
|
|
116
|
-
return { ok: true };
|
|
117
|
-
});
|
|
118
|
-
const a: HDRPayload = {
|
|
119
|
-
type: "slot-refetch",
|
|
120
|
-
routeId: "home",
|
|
121
|
-
slotPath: "app/page.slot.ts",
|
|
122
|
-
rebuildId: 1,
|
|
123
|
-
timestamp: 100,
|
|
124
|
-
};
|
|
125
|
-
const b: HDRPayload = {
|
|
126
|
-
type: "slot-refetch",
|
|
127
|
-
routeId: "dashboard",
|
|
128
|
-
slotPath: "app/dashboard/page.slot.ts",
|
|
129
|
-
rebuildId: 2,
|
|
130
|
-
timestamp: 200,
|
|
131
|
-
};
|
|
132
|
-
await dispatchSlotRefetch(a);
|
|
133
|
-
await dispatchSlotRefetch(b);
|
|
134
|
-
expect(received.length).toBe(2);
|
|
135
|
-
expect(received[0]!.routeId).toBe("home");
|
|
136
|
-
expect(received[1]!.routeId).toBe("dashboard");
|
|
137
|
-
expect(received[1]!.rebuildId).toBe(2);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test("[7] transport may observe the full HDRPayload — no fields lost", async () => {
|
|
141
|
-
const captured: HDRPayload[] = [];
|
|
142
|
-
setHDRTransport(async (p) => {
|
|
143
|
-
captured.push(p);
|
|
144
|
-
return { ok: true };
|
|
145
|
-
});
|
|
146
|
-
const payload: HDRPayload = {
|
|
147
|
-
type: "slot-refetch",
|
|
148
|
-
routeId: "nested-route-abc123",
|
|
149
|
-
slotPath: "app/deeply/nested/page.slot.ts",
|
|
150
|
-
rebuildId: 9999,
|
|
151
|
-
timestamp: 1_700_000_000_000,
|
|
152
|
-
};
|
|
153
|
-
await dispatchSlotRefetch(payload);
|
|
154
|
-
expect(captured.length).toBe(1);
|
|
155
|
-
const first = captured[0]!;
|
|
156
|
-
expect(first.type).toBe("slot-refetch");
|
|
157
|
-
expect(first.routeId).toBe(payload.routeId);
|
|
158
|
-
expect(first.slotPath).toBe(payload.slotPath);
|
|
159
|
-
expect(first.rebuildId).toBe(payload.rebuildId);
|
|
160
|
-
expect(first.timestamp).toBe(payload.timestamp);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
test("[8] latest setHDRTransport wins (idempotent setter semantics)", async () => {
|
|
164
|
-
let firstCalled = 0;
|
|
165
|
-
let secondCalled = 0;
|
|
166
|
-
setHDRTransport(async () => {
|
|
167
|
-
firstCalled++;
|
|
168
|
-
return { ok: false, reason: "disabled" as const };
|
|
169
|
-
});
|
|
170
|
-
setHDRTransport(async () => {
|
|
171
|
-
secondCalled++;
|
|
172
|
-
return { ok: true };
|
|
173
|
-
});
|
|
174
|
-
const payload: HDRPayload = {
|
|
175
|
-
type: "slot-refetch",
|
|
176
|
-
routeId: "home",
|
|
177
|
-
slotPath: "app/page.slot.ts",
|
|
178
|
-
rebuildId: 1,
|
|
179
|
-
timestamp: Date.now(),
|
|
180
|
-
};
|
|
181
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
182
|
-
expect(firstCalled).toBe(0);
|
|
183
|
-
expect(secondCalled).toBe(1);
|
|
184
|
-
expect(ok).toBe(true);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test("[9] transport that resolves with 'fetch-failed' reason — dispatch returns false", async () => {
|
|
188
|
-
setHDRTransport(async () => ({
|
|
189
|
-
ok: false,
|
|
190
|
-
reason: "fetch-failed" as const,
|
|
191
|
-
}));
|
|
192
|
-
const payload: HDRPayload = {
|
|
193
|
-
type: "slot-refetch",
|
|
194
|
-
routeId: "home",
|
|
195
|
-
slotPath: "app/page.slot.ts",
|
|
196
|
-
rebuildId: 1,
|
|
197
|
-
timestamp: Date.now(),
|
|
198
|
-
};
|
|
199
|
-
const ok = await dispatchSlotRefetch(payload);
|
|
200
|
-
expect(ok).toBe(false);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
test("[10] HDRPayload slotPath with Windows backslashes is preserved verbatim", async () => {
|
|
204
|
-
// The helper does no normalization on the browser side — the
|
|
205
|
-
// server ships whatever string it put in the payload. Lock that
|
|
206
|
-
// contract so future changes don't introduce silent mutation.
|
|
207
|
-
const captured: HDRPayload[] = [];
|
|
208
|
-
setHDRTransport(async (p) => {
|
|
209
|
-
captured.push(p);
|
|
210
|
-
return { ok: true };
|
|
211
|
-
});
|
|
212
|
-
const payload: HDRPayload = {
|
|
213
|
-
type: "slot-refetch",
|
|
214
|
-
routeId: "home",
|
|
215
|
-
slotPath: "C:\\proj\\app\\page.slot.ts",
|
|
216
|
-
rebuildId: 1,
|
|
217
|
-
timestamp: Date.now(),
|
|
218
|
-
};
|
|
219
|
-
await dispatchSlotRefetch(payload);
|
|
220
|
-
expect(captured.length).toBe(1);
|
|
221
|
-
expect(captured[0]!.slotPath).toBe("C:\\proj\\app\\page.slot.ts");
|
|
222
|
-
});
|
|
223
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Phase 7.2 R1 Agent B — HDR client-side runtime tests.
|
|
3
|
+
*
|
|
4
|
+
* Coverage (pure unit — no DOM, no real WebSocket):
|
|
5
|
+
* 1. dispatchSlotRefetch returns false when no transport is
|
|
6
|
+
* installed (the default "no-router" fallback).
|
|
7
|
+
* 2. setHDRTransport + dispatchSlotRefetch returns the transport's
|
|
8
|
+
* `ok` flag so the caller can decide fallback vs. done.
|
|
9
|
+
* 3. A throwing transport never propagates; dispatchSlotRefetch
|
|
10
|
+
* swallows + returns false so the HMR client stays alive.
|
|
11
|
+
* 4. Transport is isolated per test via _resetRegistryForTests().
|
|
12
|
+
* 5. HDRPayload shape round-trips through the transport (routeId,
|
|
13
|
+
* slotPath, rebuildId, timestamp all preserved — no field is
|
|
14
|
+
* silently dropped).
|
|
15
|
+
*
|
|
16
|
+
* References:
|
|
17
|
+
* docs/bun/phase-7-2-team-plan.md §3 Agent B
|
|
18
|
+
* packages/core/src/runtime/hmr-client.ts — setHDRTransport,
|
|
19
|
+
* dispatchSlotRefetch, _resetRegistryForTests
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
23
|
+
import {
|
|
24
|
+
setHDRTransport,
|
|
25
|
+
dispatchSlotRefetch,
|
|
26
|
+
_resetRegistryForTests,
|
|
27
|
+
} from "../hmr-client";
|
|
28
|
+
import type { HDRPayload } from "../../bundler/hmr-types";
|
|
29
|
+
|
|
30
|
+
describe("Phase 7.2 Agent B — dispatchSlotRefetch", () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
_resetRegistryForTests();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("[1] returns false when no transport is installed (default fallback)", async () => {
|
|
36
|
+
const payload: HDRPayload = {
|
|
37
|
+
type: "slot-refetch",
|
|
38
|
+
routeId: "home",
|
|
39
|
+
slotPath: "app/page.slot.ts",
|
|
40
|
+
rebuildId: 1,
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
};
|
|
43
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
44
|
+
expect(ok).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("[2] returns true when the installed transport resolves ok:true", async () => {
|
|
48
|
+
const received: HDRPayload[] = [];
|
|
49
|
+
setHDRTransport(async (p) => {
|
|
50
|
+
received.push(p);
|
|
51
|
+
return { ok: true };
|
|
52
|
+
});
|
|
53
|
+
const payload: HDRPayload = {
|
|
54
|
+
type: "slot-refetch",
|
|
55
|
+
routeId: "dashboard",
|
|
56
|
+
slotPath: "app/dashboard/page.slot.ts",
|
|
57
|
+
rebuildId: 7,
|
|
58
|
+
timestamp: 1234567890,
|
|
59
|
+
};
|
|
60
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
61
|
+
expect(ok).toBe(true);
|
|
62
|
+
// Full payload passed through unchanged.
|
|
63
|
+
expect(received.length).toBe(1);
|
|
64
|
+
expect(received[0]).toEqual(payload);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("[3] transport that throws does NOT propagate — dispatchSlotRefetch returns false", async () => {
|
|
68
|
+
setHDRTransport(async () => {
|
|
69
|
+
throw new Error("transport kaboom");
|
|
70
|
+
});
|
|
71
|
+
const payload: HDRPayload = {
|
|
72
|
+
type: "slot-refetch",
|
|
73
|
+
routeId: "home",
|
|
74
|
+
slotPath: "app/page.slot.ts",
|
|
75
|
+
rebuildId: 1,
|
|
76
|
+
timestamp: Date.now(),
|
|
77
|
+
};
|
|
78
|
+
// Must NOT reject. A thrown error in the transport is logged and
|
|
79
|
+
// the caller sees `false` so it can fall back to a full reload.
|
|
80
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
81
|
+
expect(ok).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("[4] transport resolves ok:false with reason — dispatch returns false", async () => {
|
|
85
|
+
setHDRTransport(async () => ({ ok: false, reason: "no-route" as const }));
|
|
86
|
+
const payload: HDRPayload = {
|
|
87
|
+
type: "slot-refetch",
|
|
88
|
+
routeId: "home",
|
|
89
|
+
slotPath: "app/page.slot.ts",
|
|
90
|
+
rebuildId: 1,
|
|
91
|
+
timestamp: Date.now(),
|
|
92
|
+
};
|
|
93
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
94
|
+
expect(ok).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("[5] _resetRegistryForTests restores default (no-transport) behavior", async () => {
|
|
98
|
+
setHDRTransport(async () => ({ ok: true }));
|
|
99
|
+
_resetRegistryForTests();
|
|
100
|
+
const payload: HDRPayload = {
|
|
101
|
+
type: "slot-refetch",
|
|
102
|
+
routeId: "home",
|
|
103
|
+
slotPath: "app/page.slot.ts",
|
|
104
|
+
rebuildId: 1,
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
};
|
|
107
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
108
|
+
// After reset the default "no-router" transport is back.
|
|
109
|
+
expect(ok).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("[6] two sequential dispatches with different payloads deliver each to transport", async () => {
|
|
113
|
+
const received: HDRPayload[] = [];
|
|
114
|
+
setHDRTransport(async (p) => {
|
|
115
|
+
received.push(p);
|
|
116
|
+
return { ok: true };
|
|
117
|
+
});
|
|
118
|
+
const a: HDRPayload = {
|
|
119
|
+
type: "slot-refetch",
|
|
120
|
+
routeId: "home",
|
|
121
|
+
slotPath: "app/page.slot.ts",
|
|
122
|
+
rebuildId: 1,
|
|
123
|
+
timestamp: 100,
|
|
124
|
+
};
|
|
125
|
+
const b: HDRPayload = {
|
|
126
|
+
type: "slot-refetch",
|
|
127
|
+
routeId: "dashboard",
|
|
128
|
+
slotPath: "app/dashboard/page.slot.ts",
|
|
129
|
+
rebuildId: 2,
|
|
130
|
+
timestamp: 200,
|
|
131
|
+
};
|
|
132
|
+
await dispatchSlotRefetch(a);
|
|
133
|
+
await dispatchSlotRefetch(b);
|
|
134
|
+
expect(received.length).toBe(2);
|
|
135
|
+
expect(received[0]!.routeId).toBe("home");
|
|
136
|
+
expect(received[1]!.routeId).toBe("dashboard");
|
|
137
|
+
expect(received[1]!.rebuildId).toBe(2);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("[7] transport may observe the full HDRPayload — no fields lost", async () => {
|
|
141
|
+
const captured: HDRPayload[] = [];
|
|
142
|
+
setHDRTransport(async (p) => {
|
|
143
|
+
captured.push(p);
|
|
144
|
+
return { ok: true };
|
|
145
|
+
});
|
|
146
|
+
const payload: HDRPayload = {
|
|
147
|
+
type: "slot-refetch",
|
|
148
|
+
routeId: "nested-route-abc123",
|
|
149
|
+
slotPath: "app/deeply/nested/page.slot.ts",
|
|
150
|
+
rebuildId: 9999,
|
|
151
|
+
timestamp: 1_700_000_000_000,
|
|
152
|
+
};
|
|
153
|
+
await dispatchSlotRefetch(payload);
|
|
154
|
+
expect(captured.length).toBe(1);
|
|
155
|
+
const first = captured[0]!;
|
|
156
|
+
expect(first.type).toBe("slot-refetch");
|
|
157
|
+
expect(first.routeId).toBe(payload.routeId);
|
|
158
|
+
expect(first.slotPath).toBe(payload.slotPath);
|
|
159
|
+
expect(first.rebuildId).toBe(payload.rebuildId);
|
|
160
|
+
expect(first.timestamp).toBe(payload.timestamp);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("[8] latest setHDRTransport wins (idempotent setter semantics)", async () => {
|
|
164
|
+
let firstCalled = 0;
|
|
165
|
+
let secondCalled = 0;
|
|
166
|
+
setHDRTransport(async () => {
|
|
167
|
+
firstCalled++;
|
|
168
|
+
return { ok: false, reason: "disabled" as const };
|
|
169
|
+
});
|
|
170
|
+
setHDRTransport(async () => {
|
|
171
|
+
secondCalled++;
|
|
172
|
+
return { ok: true };
|
|
173
|
+
});
|
|
174
|
+
const payload: HDRPayload = {
|
|
175
|
+
type: "slot-refetch",
|
|
176
|
+
routeId: "home",
|
|
177
|
+
slotPath: "app/page.slot.ts",
|
|
178
|
+
rebuildId: 1,
|
|
179
|
+
timestamp: Date.now(),
|
|
180
|
+
};
|
|
181
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
182
|
+
expect(firstCalled).toBe(0);
|
|
183
|
+
expect(secondCalled).toBe(1);
|
|
184
|
+
expect(ok).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("[9] transport that resolves with 'fetch-failed' reason — dispatch returns false", async () => {
|
|
188
|
+
setHDRTransport(async () => ({
|
|
189
|
+
ok: false,
|
|
190
|
+
reason: "fetch-failed" as const,
|
|
191
|
+
}));
|
|
192
|
+
const payload: HDRPayload = {
|
|
193
|
+
type: "slot-refetch",
|
|
194
|
+
routeId: "home",
|
|
195
|
+
slotPath: "app/page.slot.ts",
|
|
196
|
+
rebuildId: 1,
|
|
197
|
+
timestamp: Date.now(),
|
|
198
|
+
};
|
|
199
|
+
const ok = await dispatchSlotRefetch(payload);
|
|
200
|
+
expect(ok).toBe(false);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("[10] HDRPayload slotPath with Windows backslashes is preserved verbatim", async () => {
|
|
204
|
+
// The helper does no normalization on the browser side — the
|
|
205
|
+
// server ships whatever string it put in the payload. Lock that
|
|
206
|
+
// contract so future changes don't introduce silent mutation.
|
|
207
|
+
const captured: HDRPayload[] = [];
|
|
208
|
+
setHDRTransport(async (p) => {
|
|
209
|
+
captured.push(p);
|
|
210
|
+
return { ok: true };
|
|
211
|
+
});
|
|
212
|
+
const payload: HDRPayload = {
|
|
213
|
+
type: "slot-refetch",
|
|
214
|
+
routeId: "home",
|
|
215
|
+
slotPath: "C:\\proj\\app\\page.slot.ts",
|
|
216
|
+
rebuildId: 1,
|
|
217
|
+
timestamp: Date.now(),
|
|
218
|
+
};
|
|
219
|
+
await dispatchSlotRefetch(payload);
|
|
220
|
+
expect(captured.length).toBe(1);
|
|
221
|
+
expect(captured[0]!.slotPath).toBe("C:\\proj\\app\\page.slot.ts");
|
|
222
|
+
});
|
|
223
|
+
});
|