@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
package/src/runtime/router.ts
CHANGED
|
@@ -81,14 +81,14 @@ export class RouterError extends Error {
|
|
|
81
81
|
/**
|
|
82
82
|
* Wildcard 설정
|
|
83
83
|
*/
|
|
84
|
-
interface WildcardConfig {
|
|
85
|
-
/** 파라미터 이름 (예: "path" for :path*) */
|
|
86
|
-
name: string;
|
|
87
|
-
/** optional 여부 (예: :path*? 는 optional) */
|
|
88
|
-
optional: boolean;
|
|
89
|
-
/** 라우트 정보 */
|
|
90
|
-
route: RouteSpec;
|
|
91
|
-
}
|
|
84
|
+
interface WildcardConfig {
|
|
85
|
+
/** 파라미터 이름 (예: "path" for :path*) */
|
|
86
|
+
name: string;
|
|
87
|
+
/** optional 여부 (예: :path*? 는 optional) */
|
|
88
|
+
optional: boolean;
|
|
89
|
+
/** 라우트 정보 */
|
|
90
|
+
route: RouteSpec;
|
|
91
|
+
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
94
|
* Trie node for dynamic route matching
|
|
@@ -133,7 +133,7 @@ class TrieNode {
|
|
|
133
133
|
*
|
|
134
134
|
* @returns Decoded string or null if security violation
|
|
135
135
|
*/
|
|
136
|
-
function safeDecodeURIComponent(str: string): string | null {
|
|
136
|
+
function safeDecodeURIComponent(str: string): string | null {
|
|
137
137
|
// 1. Pre-decode %2F check
|
|
138
138
|
if (ENCODED_SLASH_PATTERN.test(str)) {
|
|
139
139
|
return null;
|
|
@@ -158,26 +158,26 @@ function safeDecodeURIComponent(str: string): string | null {
|
|
|
158
158
|
return null;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
return decoded;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Decode wildcard segments safely (per-segment)
|
|
166
|
-
*/
|
|
167
|
-
function decodeWildcardSegments(segments: string[]): string | null {
|
|
168
|
-
if (segments.length === 0) return "";
|
|
169
|
-
|
|
170
|
-
const decodedSegments: string[] = [];
|
|
171
|
-
for (const segment of segments) {
|
|
172
|
-
const decoded = safeDecodeURIComponent(segment);
|
|
173
|
-
if (decoded === null) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
decodedSegments.push(decoded);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return decodedSegments.join("/");
|
|
180
|
-
}
|
|
161
|
+
return decoded;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Decode wildcard segments safely (per-segment)
|
|
166
|
+
*/
|
|
167
|
+
function decodeWildcardSegments(segments: string[]): string | null {
|
|
168
|
+
if (segments.length === 0) return "";
|
|
169
|
+
|
|
170
|
+
const decodedSegments: string[] = [];
|
|
171
|
+
for (const segment of segments) {
|
|
172
|
+
const decoded = safeDecodeURIComponent(segment);
|
|
173
|
+
if (decoded === null) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
decodedSegments.push(decoded);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return decodedSegments.join("/");
|
|
180
|
+
}
|
|
181
181
|
|
|
182
182
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
183
183
|
// Router Class
|
|
@@ -371,47 +371,47 @@ export class Router {
|
|
|
371
371
|
private insertTrie(pattern: string, segments: string[], route: RouteSpec): void {
|
|
372
372
|
let node = this.trie;
|
|
373
373
|
|
|
374
|
-
for (let i = 0; i < segments.length; i++) {
|
|
375
|
-
const seg = segments[i];
|
|
376
|
-
|
|
377
|
-
// Legacy wildcard: *
|
|
378
|
-
if (seg === "*") {
|
|
379
|
-
if (node.wildcardConfig) {
|
|
380
|
-
throw new RouterError(
|
|
381
|
-
`Wildcard conflict in pattern "${pattern}"`,
|
|
382
|
-
"ROUTE_CONFLICT",
|
|
383
|
-
route.id,
|
|
384
|
-
node.wildcardConfig.route.id
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
node.wildcardConfig = {
|
|
388
|
-
name: WILDCARD_PARAM_KEY,
|
|
389
|
-
optional: false,
|
|
390
|
-
route,
|
|
391
|
-
};
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
374
|
+
for (let i = 0; i < segments.length; i++) {
|
|
375
|
+
const seg = segments[i];
|
|
376
|
+
|
|
377
|
+
// Legacy wildcard: *
|
|
378
|
+
if (seg === "*") {
|
|
379
|
+
if (node.wildcardConfig) {
|
|
380
|
+
throw new RouterError(
|
|
381
|
+
`Wildcard conflict in pattern "${pattern}"`,
|
|
382
|
+
"ROUTE_CONFLICT",
|
|
383
|
+
route.id,
|
|
384
|
+
node.wildcardConfig.route.id
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
node.wildcardConfig = {
|
|
388
|
+
name: WILDCARD_PARAM_KEY,
|
|
389
|
+
optional: false,
|
|
390
|
+
route,
|
|
391
|
+
};
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
394
|
|
|
395
395
|
// Parameter handling (including wildcards)
|
|
396
396
|
if (seg.startsWith(":")) {
|
|
397
397
|
// Check for wildcard pattern: :param* or :param*?
|
|
398
398
|
const wildcardMatch = seg.match(/^:([^*?]+)\*(\?)?$/);
|
|
399
|
-
if (wildcardMatch) {
|
|
400
|
-
const paramName = wildcardMatch[1];
|
|
401
|
-
const isOptional = wildcardMatch[2] === "?";
|
|
402
|
-
|
|
403
|
-
if (node.wildcardConfig) {
|
|
404
|
-
throw new RouterError(
|
|
405
|
-
`Wildcard conflict in pattern "${pattern}"`,
|
|
406
|
-
"ROUTE_CONFLICT",
|
|
407
|
-
route.id,
|
|
408
|
-
node.wildcardConfig.route.id
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
node.wildcardConfig = {
|
|
413
|
-
name: paramName,
|
|
414
|
-
optional: isOptional,
|
|
399
|
+
if (wildcardMatch) {
|
|
400
|
+
const paramName = wildcardMatch[1];
|
|
401
|
+
const isOptional = wildcardMatch[2] === "?";
|
|
402
|
+
|
|
403
|
+
if (node.wildcardConfig) {
|
|
404
|
+
throw new RouterError(
|
|
405
|
+
`Wildcard conflict in pattern "${pattern}"`,
|
|
406
|
+
"ROUTE_CONFLICT",
|
|
407
|
+
route.id,
|
|
408
|
+
node.wildcardConfig.route.id
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
node.wildcardConfig = {
|
|
413
|
+
name: paramName,
|
|
414
|
+
optional: isOptional,
|
|
415
415
|
route,
|
|
416
416
|
};
|
|
417
417
|
|
|
@@ -494,18 +494,18 @@ export class Router {
|
|
|
494
494
|
continue;
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
-
// 3. No match - try wildcard fallback
|
|
498
|
-
if (wildcardMatch) {
|
|
499
|
-
const remainingSegments = segments.slice(wildcardMatch.consumed);
|
|
500
|
-
const remaining = decodeWildcardSegments(remainingSegments);
|
|
501
|
-
if (remaining === null) {
|
|
502
|
-
return null;
|
|
503
|
-
}
|
|
504
|
-
if (this.debug) {
|
|
505
|
-
console.log(`[Router] Wildcard match: ${wildcardMatch.config.route.id} with ${remaining}`);
|
|
506
|
-
}
|
|
507
|
-
return {
|
|
508
|
-
route: wildcardMatch.config.route,
|
|
497
|
+
// 3. No match - try wildcard fallback
|
|
498
|
+
if (wildcardMatch) {
|
|
499
|
+
const remainingSegments = segments.slice(wildcardMatch.consumed);
|
|
500
|
+
const remaining = decodeWildcardSegments(remainingSegments);
|
|
501
|
+
if (remaining === null) {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
if (this.debug) {
|
|
505
|
+
console.log(`[Router] Wildcard match: ${wildcardMatch.config.route.id} with ${remaining}`);
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
route: wildcardMatch.config.route,
|
|
509
509
|
params: { ...params, [wildcardMatch.config.name]: remaining },
|
|
510
510
|
};
|
|
511
511
|
}
|
|
@@ -522,36 +522,36 @@ export class Router {
|
|
|
522
522
|
return { route: node.route, params };
|
|
523
523
|
}
|
|
524
524
|
|
|
525
|
-
// Check for wildcard at current node (but with no remaining segments)
|
|
526
|
-
if (node.wildcardConfig) {
|
|
527
|
-
// Optional wildcard: /files/:path*? matches /files (with empty path param)
|
|
528
|
-
if (node.wildcardConfig.optional) {
|
|
529
|
-
if (this.debug) {
|
|
530
|
-
console.log(`[Router] Optional wildcard match: ${node.wildcardConfig.route.id} with empty path`);
|
|
531
|
-
}
|
|
532
|
-
return {
|
|
533
|
-
route: node.wildcardConfig.route,
|
|
534
|
-
params,
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
// Non-optional wildcard: /files/:path* does NOT match /files
|
|
538
|
-
if (this.debug) {
|
|
539
|
-
console.log(`[Router] Wildcard policy: ${pathname} does not match non-optional wildcard`);
|
|
540
|
-
}
|
|
525
|
+
// Check for wildcard at current node (but with no remaining segments)
|
|
526
|
+
if (node.wildcardConfig) {
|
|
527
|
+
// Optional wildcard: /files/:path*? matches /files (with empty path param)
|
|
528
|
+
if (node.wildcardConfig.optional) {
|
|
529
|
+
if (this.debug) {
|
|
530
|
+
console.log(`[Router] Optional wildcard match: ${node.wildcardConfig.route.id} with empty path`);
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
route: node.wildcardConfig.route,
|
|
534
|
+
params,
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
// Non-optional wildcard: /files/:path* does NOT match /files
|
|
538
|
+
if (this.debug) {
|
|
539
|
+
console.log(`[Router] Wildcard policy: ${pathname} does not match non-optional wildcard`);
|
|
540
|
+
}
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
-
// Try wildcard fallback from earlier in the path
|
|
544
|
-
if (wildcardMatch) {
|
|
545
|
-
const remainingSegments = segments.slice(wildcardMatch.consumed);
|
|
546
|
-
const remaining = decodeWildcardSegments(remainingSegments);
|
|
547
|
-
if (remaining === null) {
|
|
548
|
-
return null;
|
|
549
|
-
}
|
|
550
|
-
return {
|
|
551
|
-
route: wildcardMatch.config.route,
|
|
552
|
-
params: { ...params, [wildcardMatch.config.name]: remaining },
|
|
553
|
-
};
|
|
554
|
-
}
|
|
543
|
+
// Try wildcard fallback from earlier in the path
|
|
544
|
+
if (wildcardMatch) {
|
|
545
|
+
const remainingSegments = segments.slice(wildcardMatch.consumed);
|
|
546
|
+
const remaining = decodeWildcardSegments(remainingSegments);
|
|
547
|
+
if (remaining === null) {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
return {
|
|
551
|
+
route: wildcardMatch.config.route,
|
|
552
|
+
params: { ...params, [wildcardMatch.config.name]: remaining },
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
555
|
|
|
556
556
|
return null;
|
|
557
557
|
}
|
package/src/runtime/server.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import type { BunFile, Server, ServerWebSocket } from "bun";
|
|
1
|
+
import type { BunFile, Server, ServerWebSocket } from "bun";
|
|
2
2
|
import type { RoutesManifest, RouteSpec, HydrationConfig, StaticParamSetSchema } from "../spec/schema";
|
|
3
3
|
import type { BundleManifest } from "../bundler/types";
|
|
4
4
|
import type { ManduFilling, RenderMode } from "../filling/filling";
|
|
5
5
|
import { ManduContext, CookieManager } from "../filling/context";
|
|
6
6
|
import { Router } from "./router";
|
|
7
7
|
import { renderSSR, renderStreamingResponse, resolveAsyncElement } from "./ssr";
|
|
8
|
-
import {
|
|
9
|
-
resolveMetadata,
|
|
10
|
-
renderMetadata,
|
|
11
|
-
renderTitle,
|
|
12
|
-
type Metadata,
|
|
8
|
+
import {
|
|
9
|
+
resolveMetadata,
|
|
10
|
+
renderMetadata,
|
|
11
|
+
renderTitle,
|
|
12
|
+
type Metadata,
|
|
13
13
|
type MetadataItem,
|
|
14
|
-
type GenerateMetadata,
|
|
15
|
-
} from "../seo";
|
|
16
|
-
import { type ErrorFallbackProps } from "./boundary";
|
|
17
|
-
import React from "react";
|
|
14
|
+
type GenerateMetadata,
|
|
15
|
+
} from "../seo";
|
|
16
|
+
import { type ErrorFallbackProps } from "./boundary";
|
|
17
|
+
import React from "react";
|
|
18
18
|
import path from "path";
|
|
19
19
|
import fs from "fs/promises";
|
|
20
20
|
import { PORTS } from "../constants";
|
|
21
21
|
import {
|
|
22
|
-
type CacheStore,
|
|
23
|
-
type CacheStoreStats,
|
|
24
|
-
type CacheConfig,
|
|
25
|
-
lookupCache,
|
|
22
|
+
type CacheStore,
|
|
23
|
+
type CacheStoreStats,
|
|
24
|
+
type CacheConfig,
|
|
25
|
+
lookupCache,
|
|
26
26
|
createCacheEntry,
|
|
27
27
|
createCachedResponse,
|
|
28
28
|
computeCacheControl,
|
|
@@ -51,12 +51,12 @@ import {
|
|
|
51
51
|
} from "./cors";
|
|
52
52
|
import { validateImportPath } from "./security";
|
|
53
53
|
import { KITCHEN_PREFIX, KitchenHandler, recordRequest } from "../kitchen/kitchen-handler";
|
|
54
|
-
import {
|
|
55
|
-
eventBus,
|
|
56
|
-
type EventType,
|
|
57
|
-
type ObservabilityEvent,
|
|
58
|
-
type ObservabilitySeverity,
|
|
59
|
-
} from "../observability/event-bus";
|
|
54
|
+
import {
|
|
55
|
+
eventBus,
|
|
56
|
+
type EventType,
|
|
57
|
+
type ObservabilityEvent,
|
|
58
|
+
type ObservabilitySeverity,
|
|
59
|
+
} from "../observability/event-bus";
|
|
60
60
|
import {
|
|
61
61
|
HEAP_ENDPOINT,
|
|
62
62
|
METRICS_ENDPOINT,
|
|
@@ -65,12 +65,12 @@ import {
|
|
|
65
65
|
isObservabilityExposed,
|
|
66
66
|
recordHttpRequest,
|
|
67
67
|
} from "../observability/metrics";
|
|
68
|
-
import {
|
|
69
|
-
handleOpenAPIRequest,
|
|
70
|
-
isOpenAPIEndpointEnabled,
|
|
71
|
-
resolveOpenAPIEndpointSettings,
|
|
72
|
-
type OpenAPIEndpointSettings,
|
|
73
|
-
} from "./openapi-endpoint";
|
|
68
|
+
import {
|
|
69
|
+
handleOpenAPIRequest,
|
|
70
|
+
isOpenAPIEndpointEnabled,
|
|
71
|
+
resolveOpenAPIEndpointSettings,
|
|
72
|
+
type OpenAPIEndpointSettings,
|
|
73
|
+
} from "./openapi-endpoint";
|
|
74
74
|
// Phase 18.ψ — user-facing perf marks dashboard append. We include a
|
|
75
75
|
// `perf` block on the `/_mandu/heap` payload when the feature is active
|
|
76
76
|
// so operators see a unified view (heap + caches + perf histogram).
|
|
@@ -81,7 +81,7 @@ import { collectPerfSnapshot } from "../perf/user-marks";
|
|
|
81
81
|
// `startServer()`; `runWithSpan` is used at the absolute TOP of the
|
|
82
82
|
// request handler so every downstream await (middleware, filling
|
|
83
83
|
// loader, SSR render) inherits the active span via AsyncLocalStorage.
|
|
84
|
-
import type { Tracer } from "../observability/tracing";
|
|
84
|
+
import type { Tracer } from "../observability/tracing";
|
|
85
85
|
import {
|
|
86
86
|
createTracerFromConfig,
|
|
87
87
|
runWithSpan,
|
|
@@ -102,10 +102,10 @@ import type { Middleware } from "../middleware/define";
|
|
|
102
102
|
// Phase 18.λ — scheduler wiring (statically imported so `startServer` stays
|
|
103
103
|
// synchronous; the cost of unused code is trivial — `defineCron` is a thin
|
|
104
104
|
// wrapper around `Bun.cron`).
|
|
105
|
-
import { defineCron as schedulerDefineCron, type CronDef, type CronRegistration } from "../scheduler";
|
|
105
|
+
import { defineCron as schedulerDefineCron, type CronDef, type CronRegistration } from "../scheduler";
|
|
106
106
|
import { setActiveSchedulerRegistration } from "../middleware/scheduler-cron";
|
|
107
107
|
import { createFetchHandler } from "./handler";
|
|
108
|
-
import { wrapBunWebSocket, type WSHandlers, type WSUpgradeData } from "../filling/ws";
|
|
108
|
+
import { wrapBunWebSocket, type WSHandlers, type WSUpgradeData } from "../filling/ws";
|
|
109
109
|
import { handleImageRequest } from "./image-handler";
|
|
110
110
|
import { extractShellHtml, createPPRResponse } from "./ppr";
|
|
111
111
|
import { isRedirectResponse } from "./redirect";
|
|
@@ -113,16 +113,16 @@ import { isNotFoundResponse } from "./not-found";
|
|
|
113
113
|
import { newId } from "../id";
|
|
114
114
|
// Phase 18.κ — typed RPC dispatch (tRPC-like). See
|
|
115
115
|
// `packages/core/src/contract/rpc.ts` + `docs/architect/typed-rpc.md`.
|
|
116
|
-
import {
|
|
117
|
-
matchRpcPath,
|
|
118
|
-
dispatchRpc,
|
|
119
|
-
registerRpc,
|
|
120
|
-
clearRpcRegistry,
|
|
121
|
-
type RpcDefinition,
|
|
122
|
-
type RpcProcedureRecord,
|
|
123
|
-
} from "../contract/rpc";
|
|
124
|
-
import type { GuardConfig } from "../guard/types";
|
|
125
|
-
import type { ManduHooks, ManduPlugin } from "../plugins/hooks";
|
|
116
|
+
import {
|
|
117
|
+
matchRpcPath,
|
|
118
|
+
dispatchRpc,
|
|
119
|
+
registerRpc,
|
|
120
|
+
clearRpcRegistry,
|
|
121
|
+
type RpcDefinition,
|
|
122
|
+
type RpcProcedureRecord,
|
|
123
|
+
} from "../contract/rpc";
|
|
124
|
+
import type { GuardConfig } from "../guard/types";
|
|
125
|
+
import type { ManduHooks, ManduPlugin } from "../plugins/hooks";
|
|
126
126
|
import { handleMetadataRoute as dispatchMetadataRoute } from "../routes/metadata-routes";
|
|
127
127
|
import {
|
|
128
128
|
DEFAULT_PRERENDER_DIR,
|
|
@@ -426,7 +426,7 @@ export interface ServerOptions {
|
|
|
426
426
|
/**
|
|
427
427
|
* Guard config for Kitchen dev dashboard (dev mode only)
|
|
428
428
|
*/
|
|
429
|
-
guardConfig?: GuardConfig | null;
|
|
429
|
+
guardConfig?: GuardConfig | null;
|
|
430
430
|
/**
|
|
431
431
|
* SSR 캐시 설정 (ISR/SWR 용).
|
|
432
432
|
*
|
|
@@ -582,8 +582,8 @@ export interface ServerOptions {
|
|
|
582
582
|
* `options.middleware` so they run BEFORE user-declared layers. Both
|
|
583
583
|
* fields are optional; omission is a zero-overhead passthrough.
|
|
584
584
|
*/
|
|
585
|
-
plugins?: readonly ManduPlugin[];
|
|
586
|
-
configHooks?: Partial<ManduHooks>;
|
|
585
|
+
plugins?: readonly ManduPlugin[];
|
|
586
|
+
configHooks?: Partial<ManduHooks>;
|
|
587
587
|
/**
|
|
588
588
|
* Phase 18.κ — tRPC-like typed RPC endpoints.
|
|
589
589
|
*
|
|
@@ -596,7 +596,7 @@ export interface ServerOptions {
|
|
|
596
596
|
* Typically threaded from `ManduConfig.rpc.endpoints`.
|
|
597
597
|
*/
|
|
598
598
|
rpc?: {
|
|
599
|
-
endpoints?: Record<string, RpcDefinition<RpcProcedureRecord>>;
|
|
599
|
+
endpoints?: Record<string, RpcDefinition<RpcProcedureRecord>>;
|
|
600
600
|
};
|
|
601
601
|
/**
|
|
602
602
|
* Phase 18.λ — declarative cron scheduler.
|
|
@@ -612,7 +612,7 @@ export interface ServerOptions {
|
|
|
612
612
|
* Typically threaded from `ManduConfig.scheduler`.
|
|
613
613
|
*/
|
|
614
614
|
scheduler?: {
|
|
615
|
-
jobs?: CronDef[];
|
|
615
|
+
jobs?: CronDef[];
|
|
616
616
|
disabled?: boolean;
|
|
617
617
|
};
|
|
618
618
|
/**
|
|
@@ -823,7 +823,7 @@ export interface ServerRegistrySettings {
|
|
|
823
823
|
* tracing is disabled (the hot path is branch-free). When set, every
|
|
824
824
|
* request opens a root span via `tracer.startSpanFromRequest()`.
|
|
825
825
|
*/
|
|
826
|
-
tracer?: Tracer;
|
|
826
|
+
tracer?: Tracer;
|
|
827
827
|
/**
|
|
828
828
|
* Production OpenAPI endpoint — resolved from `ServerOptions.openapi`.
|
|
829
829
|
* `undefined` means the endpoint is disabled (hot path branch-free).
|
|
@@ -831,7 +831,7 @@ export interface ServerRegistrySettings {
|
|
|
831
831
|
* `<basePath>.json` / `<basePath>.yaml` short-circuits before route
|
|
832
832
|
* dispatch to serve the cached spec body.
|
|
833
833
|
*/
|
|
834
|
-
openapi?: OpenAPIEndpointSettings;
|
|
834
|
+
openapi?: OpenAPIEndpointSettings;
|
|
835
835
|
/**
|
|
836
836
|
* Phase 18 — resolved prerender pass-through state. `undefined`
|
|
837
837
|
* means the feature is disabled for this server instance.
|
|
@@ -917,7 +917,7 @@ export class ServerRegistry {
|
|
|
917
917
|
/** Layout slot 파일 경로 캐시 (모듈 경로 → slot 경로 | null) */
|
|
918
918
|
readonly layoutSlotPaths: Map<string, string | null> = new Map();
|
|
919
919
|
/** WebSocket 핸들러 (라우트 ID → WSHandlers) */
|
|
920
|
-
readonly wsHandlers: Map<string, WSHandlers> = new Map();
|
|
920
|
+
readonly wsHandlers: Map<string, WSHandlers> = new Map();
|
|
921
921
|
/**
|
|
922
922
|
* Metadata API 캐시 (#186)
|
|
923
923
|
* - pageMetadata: routeId → page 모듈의 static `metadata` export
|
|
@@ -925,10 +925,10 @@ export class ServerRegistry {
|
|
|
925
925
|
* - layoutMetadata: layout 모듈 경로 → static `metadata` export (null = 시도했지만 없음)
|
|
926
926
|
* - layoutGenerateMetadata: layout 모듈 경로 → `generateMetadata` 함수
|
|
927
927
|
*/
|
|
928
|
-
readonly pageMetadata: Map<string, Metadata> = new Map();
|
|
929
|
-
readonly pageGenerateMetadata: Map<string, GenerateMetadata> = new Map();
|
|
930
|
-
readonly layoutMetadata: Map<string, Metadata | null> = new Map();
|
|
931
|
-
readonly layoutGenerateMetadata: Map<string, GenerateMetadata> = new Map();
|
|
928
|
+
readonly pageMetadata: Map<string, Metadata> = new Map();
|
|
929
|
+
readonly pageGenerateMetadata: Map<string, GenerateMetadata> = new Map();
|
|
930
|
+
readonly layoutMetadata: Map<string, Metadata | null> = new Map();
|
|
931
|
+
readonly layoutGenerateMetadata: Map<string, GenerateMetadata> = new Map();
|
|
932
932
|
settings: ServerRegistrySettings = {
|
|
933
933
|
isDev: false,
|
|
934
934
|
rootDir: process.cwd(),
|
|
@@ -1277,7 +1277,7 @@ export function registerNotFoundHandler(handler: PageHandler): void {
|
|
|
1277
1277
|
defaultRegistry.registerNotFoundHandler(handler);
|
|
1278
1278
|
}
|
|
1279
1279
|
|
|
1280
|
-
export function registerWSHandler(routeId: string, handlers: WSHandlers): void {
|
|
1280
|
+
export function registerWSHandler(routeId: string, handlers: WSHandlers): void {
|
|
1281
1281
|
defaultRegistry.wsHandlers.set(routeId, handlers);
|
|
1282
1282
|
}
|
|
1283
1283
|
|
|
@@ -1363,7 +1363,7 @@ function handleEventsStreamRequest(req: Request): Response {
|
|
|
1363
1363
|
const filterSource = url.searchParams.get("source") || undefined;
|
|
1364
1364
|
const filterTrace = url.searchParams.get("trace") || undefined;
|
|
1365
1365
|
|
|
1366
|
-
const matches = (e: ObservabilityEvent): boolean => {
|
|
1366
|
+
const matches = (e: ObservabilityEvent): boolean => {
|
|
1367
1367
|
if (filterType && e.type !== filterType) return false;
|
|
1368
1368
|
if (filterSeverity && e.severity !== filterSeverity) return false;
|
|
1369
1369
|
if (filterSource && e.source !== filterSource) return false;
|
|
@@ -1444,8 +1444,8 @@ function handleEventsRecentRequest(req: Request): Response {
|
|
|
1444
1444
|
const events = eventBus.getRecent(
|
|
1445
1445
|
count ? Number(count) : undefined,
|
|
1446
1446
|
{
|
|
1447
|
-
type: type as EventType | undefined,
|
|
1448
|
-
severity: severity as ObservabilitySeverity | undefined,
|
|
1447
|
+
type: type as EventType | undefined,
|
|
1448
|
+
severity: severity as ObservabilitySeverity | undefined,
|
|
1449
1449
|
},
|
|
1450
1450
|
);
|
|
1451
1451
|
const stats = eventBus.getStats(windowMs);
|
|
@@ -1551,7 +1551,7 @@ function evictEtagCacheIfNeeded(): void {
|
|
|
1551
1551
|
*/
|
|
1552
1552
|
async function computeStrongEtag(
|
|
1553
1553
|
filePath: string,
|
|
1554
|
-
file: BunFile,
|
|
1554
|
+
file: BunFile,
|
|
1555
1555
|
): Promise<string> {
|
|
1556
1556
|
const size = file.size;
|
|
1557
1557
|
const mtime = file.lastModified;
|
|
@@ -4682,12 +4682,12 @@ export function startServer(manifest: RoutesManifest, options: ServerOptions = {
|
|
|
4682
4682
|
}
|
|
4683
4683
|
// ─── End Phase 18.ζ ────────────────────────────────────────────────────
|
|
4684
4684
|
|
|
4685
|
-
// Kitchen dev dashboard (dev mode only)
|
|
4686
|
-
if (isDev) {
|
|
4687
|
-
const kitchen = new KitchenHandler({ rootDir, manifest, guardConfig });
|
|
4688
|
-
void kitchen.start();
|
|
4689
|
-
registry.kitchen = kitchen;
|
|
4690
|
-
}
|
|
4685
|
+
// Kitchen dev dashboard (dev mode only)
|
|
4686
|
+
if (isDev) {
|
|
4687
|
+
const kitchen = new KitchenHandler({ rootDir, manifest, guardConfig });
|
|
4688
|
+
void kitchen.start();
|
|
4689
|
+
registry.kitchen = kitchen;
|
|
4690
|
+
}
|
|
4691
4691
|
|
|
4692
4692
|
const router = new Router(manifest.routes);
|
|
4693
4693
|
|
|
@@ -4869,7 +4869,7 @@ export function startServer(manifest: RoutesManifest, options: ServerOptions = {
|
|
|
4869
4869
|
// other boot errors rather than aborting the server. `startServer` is
|
|
4870
4870
|
// synchronous by contract, so we use the already-imported scheduler
|
|
4871
4871
|
// module rather than `await import`.
|
|
4872
|
-
let schedulerRegistration: CronRegistration | null = null;
|
|
4872
|
+
let schedulerRegistration: CronRegistration | null = null;
|
|
4873
4873
|
const jobDefs = schedulerOption?.jobs ?? [];
|
|
4874
4874
|
const schedulerDisabled = schedulerOption?.disabled === true;
|
|
4875
4875
|
if (jobDefs.length > 0 && !schedulerDisabled) {
|
|
@@ -4921,10 +4921,10 @@ export function startServer(manifest: RoutesManifest, options: ServerOptions = {
|
|
|
4921
4921
|
console.error("[scheduler] shutdown error:", err);
|
|
4922
4922
|
});
|
|
4923
4923
|
}
|
|
4924
|
-
void server.stop();
|
|
4925
|
-
},
|
|
4926
|
-
};
|
|
4927
|
-
}
|
|
4924
|
+
void server.stop();
|
|
4925
|
+
},
|
|
4926
|
+
};
|
|
4927
|
+
}
|
|
4928
4928
|
|
|
4929
4929
|
// Clear registries (useful for testing) - deprecated, use clearDefaultRegistry()
|
|
4930
4930
|
export function clearRegistry(): void {
|
package/src/runtime/shims.ts
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime Shims for React Compatibility
|
|
3
|
-
*
|
|
4
|
-
* React 19+ 호환성을 위한 런타임 shim 스크립트들을 제공합니다.
|
|
5
|
-
*
|
|
6
|
-
* @module runtime/shims
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* React 19 Client Internals Shim Script
|
|
11
|
-
*
|
|
12
|
-
* React 19에서 react-dom/client가 실행되기 전에 ReactSharedInternals.S가
|
|
13
|
-
* 존재하는지 확인하고 필요시 초기화하는 inline 스크립트입니다.
|
|
14
|
-
*
|
|
15
|
-
* **사용 목적**:
|
|
16
|
-
* - Playwright headless 환경에서 hydration 실패 방지
|
|
17
|
-
* - React 19의 __CLIENT_INTERNALS.S가 null일 수 있는 문제 해결
|
|
18
|
-
* - SSR HTML에 삽입하여 번들 로드 전에 실행
|
|
19
|
-
*
|
|
20
|
-
* **안전성**:
|
|
21
|
-
* - try-catch로 감싸져 있어 오류 발생 시에도 안전
|
|
22
|
-
* - 기존 값이 있으면 덮어쓰지 않음
|
|
23
|
-
* - React가 없거나 internals가 없어도 실패하지 않음
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```typescript
|
|
27
|
-
* // SSR HTML에 삽입
|
|
28
|
-
* const html = `
|
|
29
|
-
* ${hydrationScripts}
|
|
30
|
-
* ${REACT_INTERNALS_SHIM_SCRIPT}
|
|
31
|
-
* ${routerScript}
|
|
32
|
-
* `;
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export const REACT_INTERNALS_SHIM_SCRIPT = `<script>
|
|
36
|
-
// React 19 internals shim: ensure ReactSharedInternals.S exists before react-dom/client runs.
|
|
37
|
-
// Some builds expect React.__CLIENT_INTERNALS... .S to be a function, but it may be null.
|
|
38
|
-
// This shim is safe: it only fills the slot if missing.
|
|
39
|
-
(function(){
|
|
40
|
-
try {
|
|
41
|
-
var React = window.React;
|
|
42
|
-
var i = React && React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
43
|
-
if (i && i.S == null) {
|
|
44
|
-
i.S = function(){};
|
|
45
|
-
}
|
|
46
|
-
} catch(e) {}
|
|
47
|
-
})();
|
|
48
|
-
</script>`;
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Shims for React Compatibility
|
|
3
|
+
*
|
|
4
|
+
* React 19+ 호환성을 위한 런타임 shim 스크립트들을 제공합니다.
|
|
5
|
+
*
|
|
6
|
+
* @module runtime/shims
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* React 19 Client Internals Shim Script
|
|
11
|
+
*
|
|
12
|
+
* React 19에서 react-dom/client가 실행되기 전에 ReactSharedInternals.S가
|
|
13
|
+
* 존재하는지 확인하고 필요시 초기화하는 inline 스크립트입니다.
|
|
14
|
+
*
|
|
15
|
+
* **사용 목적**:
|
|
16
|
+
* - Playwright headless 환경에서 hydration 실패 방지
|
|
17
|
+
* - React 19의 __CLIENT_INTERNALS.S가 null일 수 있는 문제 해결
|
|
18
|
+
* - SSR HTML에 삽입하여 번들 로드 전에 실행
|
|
19
|
+
*
|
|
20
|
+
* **안전성**:
|
|
21
|
+
* - try-catch로 감싸져 있어 오류 발생 시에도 안전
|
|
22
|
+
* - 기존 값이 있으면 덮어쓰지 않음
|
|
23
|
+
* - React가 없거나 internals가 없어도 실패하지 않음
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // SSR HTML에 삽입
|
|
28
|
+
* const html = `
|
|
29
|
+
* ${hydrationScripts}
|
|
30
|
+
* ${REACT_INTERNALS_SHIM_SCRIPT}
|
|
31
|
+
* ${routerScript}
|
|
32
|
+
* `;
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const REACT_INTERNALS_SHIM_SCRIPT = `<script>
|
|
36
|
+
// React 19 internals shim: ensure ReactSharedInternals.S exists before react-dom/client runs.
|
|
37
|
+
// Some builds expect React.__CLIENT_INTERNALS... .S to be a function, but it may be null.
|
|
38
|
+
// This shim is safe: it only fills the slot if missing.
|
|
39
|
+
(function(){
|
|
40
|
+
try {
|
|
41
|
+
var React = window.React;
|
|
42
|
+
var i = React && React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
|
|
43
|
+
if (i && i.S == null) {
|
|
44
|
+
i.S = function(){};
|
|
45
|
+
}
|
|
46
|
+
} catch(e) {}
|
|
47
|
+
})();
|
|
48
|
+
</script>`;
|