@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,182 +1,182 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Heuristic deploy intent inferer.
|
|
3
|
-
*
|
|
4
|
-
* Issue #250 — Phase 1.
|
|
5
|
-
*
|
|
6
|
-
* The rule tree below is the offline, brain-free inferer. It produces
|
|
7
|
-
* an intent for every route the manifest contains using nothing but
|
|
8
|
-
* the source code and manifest metadata gathered by `context.ts`.
|
|
9
|
-
*
|
|
10
|
-
* Design constraints:
|
|
11
|
-
*
|
|
12
|
-
* 1. **Conservative on doubt.** When a signal is ambiguous, prefer
|
|
13
|
-
* `node`/`bun` over `edge` and `no-store` over caching. A
|
|
14
|
-
* slightly-too-pessimistic intent is fixable with one explicit
|
|
15
|
-
* `.deploy()` call; a too-aggressive one breaks production.
|
|
16
|
-
*
|
|
17
|
-
* 2. **Deterministic.** Same context → same intent, byte-for-byte.
|
|
18
|
-
* The cache hashes the source so unchanged routes never re-
|
|
19
|
-
* infer; we don't want flapping intents across runs.
|
|
20
|
-
*
|
|
21
|
-
* 3. **Reasoned.** Every result carries a `rationale` string. Plan
|
|
22
|
-
* diff surfaces it so reviewers can audit "why edge here?".
|
|
23
|
-
*
|
|
24
|
-
* 4. **Replaceable.** The brain inferer (M4) calls into the same
|
|
25
|
-
* shape (`InferenceResult`) so adapters never need to know which
|
|
26
|
-
* engine produced the intent.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
import type { DeployIntent } from "../intent";
|
|
30
|
-
import type { DependencyClass, DeployInferenceContext } from "./context";
|
|
31
|
-
|
|
32
|
-
export interface InferenceResult {
|
|
33
|
-
intent: DeployIntent;
|
|
34
|
-
rationale: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Run the rule tree on a single route context.
|
|
39
|
-
*
|
|
40
|
-
* The rules below are checked top-to-bottom; the first match wins.
|
|
41
|
-
* Adding a new rule? Put it in priority order — the most specific /
|
|
42
|
-
* highest-confidence rule first.
|
|
43
|
-
*/
|
|
44
|
-
export function inferDeployIntentHeuristic(
|
|
45
|
-
ctx: DeployInferenceContext,
|
|
46
|
-
): InferenceResult {
|
|
47
|
-
// ─── Metadata routes (sitemap.xml, robots.txt, llms.txt, manifest.json)
|
|
48
|
-
if (ctx.kind === "metadata") {
|
|
49
|
-
return {
|
|
50
|
-
intent: {
|
|
51
|
-
runtime: "static",
|
|
52
|
-
cache: { sMaxAge: 3600, swr: 86_400 },
|
|
53
|
-
visibility: "public",
|
|
54
|
-
},
|
|
55
|
-
rationale:
|
|
56
|
-
"metadata route — sitemap/robots/llms.txt are stable across requests; prerender + 1h s-maxage with 1d SWR.",
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ─── Page routes
|
|
61
|
-
if (ctx.kind === "page") {
|
|
62
|
-
// Static-prerenderable: no dynamic segments, OR has generateStaticParams.
|
|
63
|
-
if (!ctx.isDynamic) {
|
|
64
|
-
return {
|
|
65
|
-
intent: {
|
|
66
|
-
runtime: "static",
|
|
67
|
-
cache: { sMaxAge: 31_536_000, swr: 86_400 },
|
|
68
|
-
visibility: "public",
|
|
69
|
-
},
|
|
70
|
-
rationale: "page with no dynamic segments — prerender at build time.",
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
if (ctx.hasGenerateStaticParams) {
|
|
74
|
-
return {
|
|
75
|
-
intent: {
|
|
76
|
-
runtime: "static",
|
|
77
|
-
cache: { sMaxAge: 31_536_000, swr: 86_400 },
|
|
78
|
-
visibility: "public",
|
|
79
|
-
},
|
|
80
|
-
rationale:
|
|
81
|
-
"dynamic page exports generateStaticParams — every parameter combination prerenders at build time.",
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
// Dynamic page without static params: needs SSR. Pick edge unless
|
|
85
|
-
// the handler imports something edge can't run.
|
|
86
|
-
if (canRunOnEdge(ctx.dependencyClasses)) {
|
|
87
|
-
return {
|
|
88
|
-
intent: {
|
|
89
|
-
runtime: "edge",
|
|
90
|
-
cache: "no-store",
|
|
91
|
-
visibility: "public",
|
|
92
|
-
},
|
|
93
|
-
rationale:
|
|
94
|
-
"dynamic page (SSR) with no Node/Bun-only dependencies — edge runtime keeps latency low.",
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
return {
|
|
98
|
-
intent: {
|
|
99
|
-
runtime: pickServerRuntime(ctx.dependencyClasses),
|
|
100
|
-
cache: "no-store",
|
|
101
|
-
visibility: "public",
|
|
102
|
-
},
|
|
103
|
-
rationale: explainServerRuntime(ctx.dependencyClasses, "page"),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// ─── API routes
|
|
108
|
-
// APIs are never `static`. Pick edge when stateless, server runtime
|
|
109
|
-
// otherwise. Cache always defaults to `no-store` — caching API
|
|
110
|
-
// responses is a deliberate decision, not something we infer.
|
|
111
|
-
if (canRunOnEdge(ctx.dependencyClasses)) {
|
|
112
|
-
return {
|
|
113
|
-
intent: {
|
|
114
|
-
runtime: "edge",
|
|
115
|
-
cache: "no-store",
|
|
116
|
-
visibility: "public",
|
|
117
|
-
},
|
|
118
|
-
rationale:
|
|
119
|
-
"API route with only fetch-class dependencies — edge runtime; opt into caching with .deploy({ cache }).",
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
return {
|
|
123
|
-
intent: {
|
|
124
|
-
runtime: pickServerRuntime(ctx.dependencyClasses),
|
|
125
|
-
cache: "no-store",
|
|
126
|
-
visibility: "public",
|
|
127
|
-
},
|
|
128
|
-
rationale: explainServerRuntime(ctx.dependencyClasses, "API"),
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ─── Rule-tree primitives ────────────────────────────────────────────
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* The classes that disqualify edge — DB drivers (open TCP sockets and
|
|
136
|
-
* ship native modules), Node-only filesystem/networking modules, Bun
|
|
137
|
-
* native primitives (sqlite/ffi/s3), AI SDKs (long-running, large
|
|
138
|
-
* payloads), and explicitly heavy native libraries (sharp/playwright).
|
|
139
|
-
*/
|
|
140
|
-
const NON_EDGE_CLASSES: ReadonlySet<DependencyClass> = new Set([
|
|
141
|
-
"db",
|
|
142
|
-
"node-fs",
|
|
143
|
-
"node-net",
|
|
144
|
-
"node-child",
|
|
145
|
-
"bun-native",
|
|
146
|
-
"ai-sdk",
|
|
147
|
-
"heavy",
|
|
148
|
-
]);
|
|
149
|
-
|
|
150
|
-
function canRunOnEdge(classes: ReadonlySet<DependencyClass>): boolean {
|
|
151
|
-
for (const cls of classes) {
|
|
152
|
-
if (NON_EDGE_CLASSES.has(cls)) return false;
|
|
153
|
-
}
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Choose between `bun` and `node` for routes that must run on a
|
|
159
|
-
* server runtime. `bun-native` imports force `bun`; everything else
|
|
160
|
-
* defaults to `node` for maximum portability (every adapter supports
|
|
161
|
-
* Node; not every adapter supports Bun yet).
|
|
162
|
-
*/
|
|
163
|
-
function pickServerRuntime(classes: ReadonlySet<DependencyClass>): "node" | "bun" {
|
|
164
|
-
return classes.has("bun-native") ? "bun" : "node";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function explainServerRuntime(
|
|
168
|
-
classes: ReadonlySet<DependencyClass>,
|
|
169
|
-
routeLabel: string,
|
|
170
|
-
): string {
|
|
171
|
-
const reasons: string[] = [];
|
|
172
|
-
if (classes.has("db")) reasons.push("imports a database driver");
|
|
173
|
-
if (classes.has("node-fs")) reasons.push("uses node:fs");
|
|
174
|
-
if (classes.has("node-net")) reasons.push("uses node:net/tls/dgram");
|
|
175
|
-
if (classes.has("node-child")) reasons.push("uses node:child_process or worker_threads");
|
|
176
|
-
if (classes.has("bun-native")) reasons.push("imports bun:* primitives");
|
|
177
|
-
if (classes.has("ai-sdk")) reasons.push("imports an AI SDK (long latency)");
|
|
178
|
-
if (classes.has("heavy")) reasons.push("imports a heavy native dependency");
|
|
179
|
-
const why = reasons.length > 0 ? reasons.join(", ") : "non-edge dependencies";
|
|
180
|
-
const runtime = pickServerRuntime(classes);
|
|
181
|
-
return `${routeLabel} ${why} — ${runtime} runtime required.`;
|
|
182
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic deploy intent inferer.
|
|
3
|
+
*
|
|
4
|
+
* Issue #250 — Phase 1.
|
|
5
|
+
*
|
|
6
|
+
* The rule tree below is the offline, brain-free inferer. It produces
|
|
7
|
+
* an intent for every route the manifest contains using nothing but
|
|
8
|
+
* the source code and manifest metadata gathered by `context.ts`.
|
|
9
|
+
*
|
|
10
|
+
* Design constraints:
|
|
11
|
+
*
|
|
12
|
+
* 1. **Conservative on doubt.** When a signal is ambiguous, prefer
|
|
13
|
+
* `node`/`bun` over `edge` and `no-store` over caching. A
|
|
14
|
+
* slightly-too-pessimistic intent is fixable with one explicit
|
|
15
|
+
* `.deploy()` call; a too-aggressive one breaks production.
|
|
16
|
+
*
|
|
17
|
+
* 2. **Deterministic.** Same context → same intent, byte-for-byte.
|
|
18
|
+
* The cache hashes the source so unchanged routes never re-
|
|
19
|
+
* infer; we don't want flapping intents across runs.
|
|
20
|
+
*
|
|
21
|
+
* 3. **Reasoned.** Every result carries a `rationale` string. Plan
|
|
22
|
+
* diff surfaces it so reviewers can audit "why edge here?".
|
|
23
|
+
*
|
|
24
|
+
* 4. **Replaceable.** The brain inferer (M4) calls into the same
|
|
25
|
+
* shape (`InferenceResult`) so adapters never need to know which
|
|
26
|
+
* engine produced the intent.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import type { DeployIntent } from "../intent";
|
|
30
|
+
import type { DependencyClass, DeployInferenceContext } from "./context";
|
|
31
|
+
|
|
32
|
+
export interface InferenceResult {
|
|
33
|
+
intent: DeployIntent;
|
|
34
|
+
rationale: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Run the rule tree on a single route context.
|
|
39
|
+
*
|
|
40
|
+
* The rules below are checked top-to-bottom; the first match wins.
|
|
41
|
+
* Adding a new rule? Put it in priority order — the most specific /
|
|
42
|
+
* highest-confidence rule first.
|
|
43
|
+
*/
|
|
44
|
+
export function inferDeployIntentHeuristic(
|
|
45
|
+
ctx: DeployInferenceContext,
|
|
46
|
+
): InferenceResult {
|
|
47
|
+
// ─── Metadata routes (sitemap.xml, robots.txt, llms.txt, manifest.json)
|
|
48
|
+
if (ctx.kind === "metadata") {
|
|
49
|
+
return {
|
|
50
|
+
intent: {
|
|
51
|
+
runtime: "static",
|
|
52
|
+
cache: { sMaxAge: 3600, swr: 86_400 },
|
|
53
|
+
visibility: "public",
|
|
54
|
+
},
|
|
55
|
+
rationale:
|
|
56
|
+
"metadata route — sitemap/robots/llms.txt are stable across requests; prerender + 1h s-maxage with 1d SWR.",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── Page routes
|
|
61
|
+
if (ctx.kind === "page") {
|
|
62
|
+
// Static-prerenderable: no dynamic segments, OR has generateStaticParams.
|
|
63
|
+
if (!ctx.isDynamic) {
|
|
64
|
+
return {
|
|
65
|
+
intent: {
|
|
66
|
+
runtime: "static",
|
|
67
|
+
cache: { sMaxAge: 31_536_000, swr: 86_400 },
|
|
68
|
+
visibility: "public",
|
|
69
|
+
},
|
|
70
|
+
rationale: "page with no dynamic segments — prerender at build time.",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (ctx.hasGenerateStaticParams) {
|
|
74
|
+
return {
|
|
75
|
+
intent: {
|
|
76
|
+
runtime: "static",
|
|
77
|
+
cache: { sMaxAge: 31_536_000, swr: 86_400 },
|
|
78
|
+
visibility: "public",
|
|
79
|
+
},
|
|
80
|
+
rationale:
|
|
81
|
+
"dynamic page exports generateStaticParams — every parameter combination prerenders at build time.",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Dynamic page without static params: needs SSR. Pick edge unless
|
|
85
|
+
// the handler imports something edge can't run.
|
|
86
|
+
if (canRunOnEdge(ctx.dependencyClasses)) {
|
|
87
|
+
return {
|
|
88
|
+
intent: {
|
|
89
|
+
runtime: "edge",
|
|
90
|
+
cache: "no-store",
|
|
91
|
+
visibility: "public",
|
|
92
|
+
},
|
|
93
|
+
rationale:
|
|
94
|
+
"dynamic page (SSR) with no Node/Bun-only dependencies — edge runtime keeps latency low.",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
intent: {
|
|
99
|
+
runtime: pickServerRuntime(ctx.dependencyClasses),
|
|
100
|
+
cache: "no-store",
|
|
101
|
+
visibility: "public",
|
|
102
|
+
},
|
|
103
|
+
rationale: explainServerRuntime(ctx.dependencyClasses, "page"),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ─── API routes
|
|
108
|
+
// APIs are never `static`. Pick edge when stateless, server runtime
|
|
109
|
+
// otherwise. Cache always defaults to `no-store` — caching API
|
|
110
|
+
// responses is a deliberate decision, not something we infer.
|
|
111
|
+
if (canRunOnEdge(ctx.dependencyClasses)) {
|
|
112
|
+
return {
|
|
113
|
+
intent: {
|
|
114
|
+
runtime: "edge",
|
|
115
|
+
cache: "no-store",
|
|
116
|
+
visibility: "public",
|
|
117
|
+
},
|
|
118
|
+
rationale:
|
|
119
|
+
"API route with only fetch-class dependencies — edge runtime; opt into caching with .deploy({ cache }).",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
intent: {
|
|
124
|
+
runtime: pickServerRuntime(ctx.dependencyClasses),
|
|
125
|
+
cache: "no-store",
|
|
126
|
+
visibility: "public",
|
|
127
|
+
},
|
|
128
|
+
rationale: explainServerRuntime(ctx.dependencyClasses, "API"),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ─── Rule-tree primitives ────────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The classes that disqualify edge — DB drivers (open TCP sockets and
|
|
136
|
+
* ship native modules), Node-only filesystem/networking modules, Bun
|
|
137
|
+
* native primitives (sqlite/ffi/s3), AI SDKs (long-running, large
|
|
138
|
+
* payloads), and explicitly heavy native libraries (sharp/playwright).
|
|
139
|
+
*/
|
|
140
|
+
const NON_EDGE_CLASSES: ReadonlySet<DependencyClass> = new Set([
|
|
141
|
+
"db",
|
|
142
|
+
"node-fs",
|
|
143
|
+
"node-net",
|
|
144
|
+
"node-child",
|
|
145
|
+
"bun-native",
|
|
146
|
+
"ai-sdk",
|
|
147
|
+
"heavy",
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
function canRunOnEdge(classes: ReadonlySet<DependencyClass>): boolean {
|
|
151
|
+
for (const cls of classes) {
|
|
152
|
+
if (NON_EDGE_CLASSES.has(cls)) return false;
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Choose between `bun` and `node` for routes that must run on a
|
|
159
|
+
* server runtime. `bun-native` imports force `bun`; everything else
|
|
160
|
+
* defaults to `node` for maximum portability (every adapter supports
|
|
161
|
+
* Node; not every adapter supports Bun yet).
|
|
162
|
+
*/
|
|
163
|
+
function pickServerRuntime(classes: ReadonlySet<DependencyClass>): "node" | "bun" {
|
|
164
|
+
return classes.has("bun-native") ? "bun" : "node";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function explainServerRuntime(
|
|
168
|
+
classes: ReadonlySet<DependencyClass>,
|
|
169
|
+
routeLabel: string,
|
|
170
|
+
): string {
|
|
171
|
+
const reasons: string[] = [];
|
|
172
|
+
if (classes.has("db")) reasons.push("imports a database driver");
|
|
173
|
+
if (classes.has("node-fs")) reasons.push("uses node:fs");
|
|
174
|
+
if (classes.has("node-net")) reasons.push("uses node:net/tls/dgram");
|
|
175
|
+
if (classes.has("node-child")) reasons.push("uses node:child_process or worker_threads");
|
|
176
|
+
if (classes.has("bun-native")) reasons.push("imports bun:* primitives");
|
|
177
|
+
if (classes.has("ai-sdk")) reasons.push("imports an AI SDK (long latency)");
|
|
178
|
+
if (classes.has("heavy")) reasons.push("imports a heavy native dependency");
|
|
179
|
+
const why = reasons.length > 0 ? reasons.join(", ") : "non-edge dependencies";
|
|
180
|
+
const runtime = pickServerRuntime(classes);
|
|
181
|
+
return `${routeLabel} ${why} — ${runtime} runtime required.`;
|
|
182
|
+
}
|