@timber-js/app 0.2.0-alpha.98 → 0.2.0-alpha.99
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/LICENSE +8 -0
- package/dist/_chunks/actions-CQ8Z8VGL.js +1061 -0
- package/dist/_chunks/actions-CQ8Z8VGL.js.map +1 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js +61 -0
- package/dist/_chunks/build-output-helper-DXnW0qjz.js.map +1 -0
- package/dist/_chunks/{define-Itxvcd7F.js → define-B-Q_UMOD.js} +19 -23
- package/dist/_chunks/define-B-Q_UMOD.js.map +1 -0
- package/dist/_chunks/{define-C77ScO0m.js → define-CfBPoJb0.js} +24 -7
- package/dist/_chunks/define-CfBPoJb0.js.map +1 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js +194 -0
- package/dist/_chunks/define-cookie-BjpIt4UC.js.map +1 -0
- package/dist/_chunks/{format-CYBGxKtc.js → format-Bcn-Iv1x.js} +1 -1
- package/dist/_chunks/{format-CYBGxKtc.js.map → format-Bcn-Iv1x.js.map} +1 -1
- package/dist/_chunks/handler-store-B-lqaGyh.js +54 -0
- package/dist/_chunks/handler-store-B-lqaGyh.js.map +1 -0
- package/dist/_chunks/logger-0m8MsKdc.js +291 -0
- package/dist/_chunks/logger-0m8MsKdc.js.map +1 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js +122 -0
- package/dist/_chunks/merge-search-params-BphMdht_.js.map +1 -0
- package/dist/_chunks/navigation-root-BCYczjml.js +96 -0
- package/dist/_chunks/navigation-root-BCYczjml.js.map +1 -0
- package/dist/_chunks/registry-I2ss-lvy.js +20 -0
- package/dist/_chunks/registry-I2ss-lvy.js.map +1 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js +28 -0
- package/dist/_chunks/router-ref-h3-UaCQv.js.map +1 -0
- package/dist/_chunks/{schema-bridge-C3xl_vfb.js → schema-bridge-Cxu4l-7p.js} +1 -1
- package/dist/_chunks/{schema-bridge-C3xl_vfb.js.map → schema-bridge-Cxu4l-7p.js.map} +1 -1
- package/dist/_chunks/{segment-context-fHFLF1PE.js → segment-context-Dx_OizxD.js} +1 -1
- package/dist/_chunks/{segment-context-fHFLF1PE.js.map → segment-context-Dx_OizxD.js.map} +1 -1
- package/dist/_chunks/{router-ref-C8OCm7g7.js → ssr-data-B4CdH7rE.js} +2 -26
- package/dist/_chunks/ssr-data-B4CdH7rE.js.map +1 -0
- package/dist/_chunks/{stale-reload-BX5gL1r-.js → stale-reload-Bab885FO.js} +1 -1
- package/dist/_chunks/{stale-reload-BX5gL1r-.js.map → stale-reload-Bab885FO.js.map} +1 -1
- package/dist/_chunks/tracing-C8V-YGsP.js +329 -0
- package/dist/_chunks/tracing-C8V-YGsP.js.map +1 -0
- package/dist/_chunks/{use-query-states-BiV5GJgm.js → use-query-states-B2XTqxDR.js} +3 -19
- package/dist/_chunks/use-query-states-B2XTqxDR.js.map +1 -0
- package/dist/_chunks/{use-params-IOPu7E8t.js → use-segment-params-BkpKAQ7D.js} +9 -95
- package/dist/_chunks/use-segment-params-BkpKAQ7D.js.map +1 -0
- package/dist/_chunks/{walkers-VOXgavMF.js → walkers-Tg0Alwcg.js} +6 -3
- package/dist/_chunks/walkers-Tg0Alwcg.js.map +1 -0
- package/dist/_chunks/{dev-warnings-DpGRGoDi.js → warnings-Cg47l5sk.js} +3 -3
- package/dist/_chunks/warnings-Cg47l5sk.js.map +1 -0
- package/dist/adapters/build-output-helper.d.ts +28 -0
- package/dist/adapters/build-output-helper.d.ts.map +1 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +8 -28
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +8 -26
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +16 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/cache/index.js +9 -2
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/client/error-boundary.js +2 -1
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/form.d.ts +10 -24
- package/dist/client/form.d.ts.map +1 -1
- package/dist/client/index.d.ts +1 -5
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +40 -90
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.d.ts +2 -1
- package/dist/client/internal.d.ts.map +1 -1
- package/dist/client/internal.js +81 -7
- package/dist/client/internal.js.map +1 -1
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/state.d.ts +1 -1
- package/dist/client/use-cookie.d.ts +8 -0
- package/dist/client/use-cookie.d.ts.map +1 -1
- package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +1 -1
- package/dist/client/use-segment-params.d.ts.map +1 -0
- package/dist/codec.d.ts +1 -1
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +2 -2
- package/dist/config-types.d.ts +28 -0
- package/dist/config-types.d.ts.map +1 -1
- package/dist/cookies/define-cookie.d.ts +87 -35
- package/dist/cookies/define-cookie.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +2 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/index.js +48 -2
- package/dist/cookies/index.js.map +1 -0
- package/dist/cookies/json-cookie.d.ts +64 -0
- package/dist/cookies/json-cookie.d.ts.map +1 -0
- package/dist/cookies/validation.d.ts +46 -0
- package/dist/cookies/validation.d.ts.map +1 -0
- package/dist/{plugins/dev-404-page.d.ts → dev-tools/404-page.d.ts} +1 -1
- package/dist/dev-tools/404-page.d.ts.map +1 -0
- package/dist/{plugins/dev-browser-logs.d.ts → dev-tools/browser-logs.d.ts} +1 -1
- package/dist/dev-tools/browser-logs.d.ts.map +1 -0
- package/dist/{plugins/dev-error-page.d.ts → dev-tools/error-page.d.ts} +2 -2
- package/dist/dev-tools/error-page.d.ts.map +1 -0
- package/dist/{server/dev-holding-server.d.ts → dev-tools/holding-server.d.ts} +1 -1
- package/dist/dev-tools/holding-server.d.ts.map +1 -0
- package/dist/dev-tools/index.d.ts +31 -0
- package/dist/dev-tools/index.d.ts.map +1 -0
- package/dist/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
- package/dist/dev-tools/instrumentation.d.ts.map +1 -0
- package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
- package/dist/dev-tools/logger.d.ts.map +1 -0
- package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +1 -1
- package/dist/dev-tools/logs.d.ts.map +1 -0
- package/dist/{plugins/dev-error-overlay.d.ts → dev-tools/overlay.d.ts} +3 -12
- package/dist/dev-tools/overlay.d.ts.map +1 -0
- package/dist/dev-tools/stack-classifier.d.ts +34 -0
- package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
- package/dist/{plugins/dev-terminal-error.d.ts → dev-tools/terminal.d.ts} +2 -2
- package/dist/dev-tools/terminal.d.ts.map +1 -0
- package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +1 -1
- package/dist/dev-tools/warnings.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -72
- package/dist/index.js.map +1 -1
- package/dist/plugin-context.d.ts +1 -1
- package/dist/plugin-context.d.ts.map +1 -1
- package/dist/plugins/adapter-build.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/search-params/define.d.ts +25 -7
- package/dist/search-params/define.d.ts.map +1 -1
- package/dist/search-params/index.js +5 -3
- package/dist/search-params/index.js.map +1 -1
- package/dist/search-params/wrappers.d.ts +2 -2
- package/dist/search-params/wrappers.d.ts.map +1 -1
- package/dist/segment-params/define.d.ts +23 -6
- package/dist/segment-params/define.d.ts.map +1 -1
- package/dist/segment-params/index.js +1 -1
- package/dist/server/access-gate.d.ts +4 -3
- package/dist/server/access-gate.d.ts.map +1 -1
- package/dist/server/action-handler.d.ts +15 -6
- package/dist/server/action-handler.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +5 -5
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/asset-headers.d.ts +1 -15
- package/dist/server/asset-headers.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +170 -0
- package/dist/server/cookie-context.d.ts.map +1 -0
- package/dist/server/cookie-parsing.d.ts +51 -0
- package/dist/server/cookie-parsing.d.ts.map +1 -0
- package/dist/server/deny-boundary.d.ts +90 -0
- package/dist/server/deny-boundary.d.ts.map +1 -0
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/early-hints-sender.d.ts.map +1 -1
- package/dist/server/index.d.ts +5 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -149
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.d.ts +6 -4
- package/dist/server/internal.d.ts.map +1 -1
- package/dist/server/internal.js +261 -408
- package/dist/server/internal.js.map +1 -1
- package/dist/server/logger.d.ts +14 -0
- package/dist/server/logger.d.ts.map +1 -1
- package/dist/server/middleware-runner.d.ts +17 -0
- package/dist/server/middleware-runner.d.ts.map +1 -1
- package/dist/server/param-coercion.d.ts +26 -0
- package/dist/server/param-coercion.d.ts.map +1 -0
- package/dist/server/pipeline-helpers.d.ts +14 -7
- package/dist/server/pipeline-helpers.d.ts.map +1 -1
- package/dist/server/pipeline-outcome.d.ts +49 -0
- package/dist/server/pipeline-outcome.d.ts.map +1 -0
- package/dist/server/pipeline-phases.d.ts +4 -49
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +0 -2
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +22 -159
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
- package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
- package/dist/server/rsc-entry/helpers.d.ts +1 -1
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +50 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +59 -14
- package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -1
- package/dist/server/state-tree-diff.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +1 -1
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +45 -16
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/server/types.d.ts +48 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/escape-html.d.ts +14 -0
- package/dist/server/utils/escape-html.d.ts.map +1 -0
- package/dist/shims/headers.d.ts +2 -2
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/navigation-client.d.ts +3 -1
- package/dist/shims/navigation-client.d.ts.map +1 -1
- package/dist/shims/navigation.d.ts +9 -4
- package/dist/shims/navigation.d.ts.map +1 -1
- package/package.json +6 -7
- package/src/adapters/build-output-helper.ts +77 -0
- package/src/adapters/cloudflare.ts +10 -50
- package/src/adapters/nitro.ts +11 -45
- package/src/adapters/shared.ts +40 -0
- package/src/cache/timber-cache.ts +3 -2
- package/src/cli.ts +0 -0
- package/src/client/form.tsx +17 -25
- package/src/client/index.ts +16 -9
- package/src/client/internal.ts +3 -2
- package/src/client/router.ts +1 -1
- package/src/client/rsc-fetch.ts +15 -0
- package/src/client/state.ts +2 -2
- package/src/client/use-cookie.ts +29 -0
- package/src/codec.ts +3 -7
- package/src/config-types.ts +28 -0
- package/src/cookies/define-cookie.ts +271 -78
- package/src/cookies/index.ts +11 -8
- package/src/cookies/json-cookie.ts +105 -0
- package/src/cookies/validation.ts +134 -0
- package/src/{plugins/dev-404-page.ts → dev-tools/404-page.ts} +2 -7
- package/src/{plugins/dev-error-page.ts → dev-tools/error-page.ts} +5 -32
- package/src/dev-tools/index.ts +90 -0
- package/src/dev-tools/instrumentation.ts +176 -0
- package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +2 -2
- package/src/{plugins/dev-error-overlay.ts → dev-tools/overlay.ts} +5 -23
- package/src/dev-tools/stack-classifier.ts +75 -0
- package/src/{plugins/dev-terminal-error.ts → dev-tools/terminal.ts} +4 -38
- package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +1 -1
- package/src/index.ts +11 -3
- package/src/plugin-context.ts +1 -1
- package/src/plugins/adapter-build.ts +3 -1
- package/src/plugins/dev-server.ts +3 -3
- package/src/plugins/shims.ts +1 -1
- package/src/plugins/static-build.ts +1 -1
- package/src/routing/convention-lint.ts +5 -4
- package/src/routing/scanner.ts +5 -2
- package/src/routing/status-file-lint.ts +4 -2
- package/src/search-params/define.ts +71 -15
- package/src/search-params/wrappers.ts +9 -2
- package/src/segment-params/define.ts +66 -13
- package/src/server/access-gate.tsx +9 -8
- package/src/server/action-handler.ts +28 -38
- package/src/server/als-registry.ts +5 -5
- package/src/server/asset-headers.ts +8 -34
- package/src/server/cookie-context.ts +468 -0
- package/src/server/cookie-parsing.ts +135 -0
- package/src/server/{deny-page-resolver.ts → deny-boundary.ts} +78 -14
- package/src/server/deny-renderer.ts +2 -7
- package/src/server/early-hints-sender.ts +3 -2
- package/src/server/fallback-error.ts +1 -1
- package/src/server/index.ts +13 -14
- package/src/server/internal.ts +10 -3
- package/src/server/logger.ts +23 -0
- package/src/server/middleware-runner.ts +44 -0
- package/src/server/param-coercion.ts +76 -0
- package/src/server/pipeline-helpers.ts +37 -13
- package/src/server/pipeline-outcome.ts +167 -0
- package/src/server/pipeline-phases.ts +27 -209
- package/src/server/pipeline.ts +2 -9
- package/src/server/request-context.ts +46 -451
- package/src/server/route-element-builder.ts +7 -3
- package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
- package/src/server/rsc-entry/error-renderer.ts +1 -1
- package/src/server/rsc-entry/helpers.ts +2 -7
- package/src/server/rsc-entry/index.ts +34 -273
- package/src/server/rsc-entry/render-route.ts +304 -0
- package/src/server/rsc-entry/rsc-payload.ts +1 -1
- package/src/server/rsc-entry/ssr-renderer.ts +2 -2
- package/src/server/rsc-entry/wrap-action-dispatch.ts +316 -23
- package/src/server/ssr-entry.ts +1 -1
- package/src/server/state-tree-diff.ts +4 -1
- package/src/server/tracing.ts +3 -3
- package/src/server/tree-builder.ts +128 -52
- package/src/server/types.ts +52 -0
- package/src/server/utils/escape-html.ts +20 -0
- package/src/shims/headers.ts +3 -3
- package/src/shims/navigation-client.ts +4 -3
- package/src/shims/navigation.ts +9 -7
- package/dist/_chunks/actions-DLnUaR65.js +0 -421
- package/dist/_chunks/actions-DLnUaR65.js.map +0 -1
- package/dist/_chunks/als-registry-HS0LGUl2.js +0 -41
- package/dist/_chunks/als-registry-HS0LGUl2.js.map +0 -1
- package/dist/_chunks/debug-ECi_61pb.js +0 -108
- package/dist/_chunks/debug-ECi_61pb.js.map +0 -1
- package/dist/_chunks/define-C77ScO0m.js.map +0 -1
- package/dist/_chunks/define-Itxvcd7F.js.map +0 -1
- package/dist/_chunks/define-cookie-BowvzoP0.js +0 -94
- package/dist/_chunks/define-cookie-BowvzoP0.js.map +0 -1
- package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +0 -1
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js +0 -41
- package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +0 -1
- package/dist/_chunks/request-context-CK5tZqIP.js +0 -478
- package/dist/_chunks/request-context-CK5tZqIP.js.map +0 -1
- package/dist/_chunks/router-ref-C8OCm7g7.js.map +0 -1
- package/dist/_chunks/tracing-CCYbKn5n.js +0 -238
- package/dist/_chunks/tracing-CCYbKn5n.js.map +0 -1
- package/dist/_chunks/use-params-IOPu7E8t.js.map +0 -1
- package/dist/_chunks/use-query-states-BiV5GJgm.js.map +0 -1
- package/dist/_chunks/walkers-VOXgavMF.js.map +0 -1
- package/dist/client/use-params.d.ts.map +0 -1
- package/dist/plugins/dev-404-page.d.ts.map +0 -1
- package/dist/plugins/dev-browser-logs.d.ts.map +0 -1
- package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
- package/dist/plugins/dev-error-page.d.ts.map +0 -1
- package/dist/plugins/dev-logs.d.ts.map +0 -1
- package/dist/plugins/dev-terminal-error.d.ts.map +0 -1
- package/dist/server/deny-page-resolver.d.ts +0 -52
- package/dist/server/deny-page-resolver.d.ts.map +0 -1
- package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
- package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
- package/dist/server/dev-holding-server.d.ts.map +0 -1
- package/dist/server/dev-logger.d.ts.map +0 -1
- package/dist/server/dev-span-processor.d.ts.map +0 -1
- package/dist/server/dev-warnings.d.ts.map +0 -1
- package/dist/server/page-deny-boundary.d.ts +0 -31
- package/dist/server/page-deny-boundary.d.ts.map +0 -1
- package/src/server/dev-fetch-instrumentation.ts +0 -96
- package/src/server/dev-span-processor.ts +0 -78
- package/src/server/page-deny-boundary.tsx +0 -56
- /package/src/client/{use-params.ts → use-segment-params.ts} +0 -0
- /package/src/{plugins/dev-browser-logs.ts → dev-tools/browser-logs.ts} +0 -0
- /package/src/{server/dev-holding-server.ts → dev-tools/holding-server.ts} +0 -0
- /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
//#region src/cookies/define-cookie.ts
|
|
2
|
+
var _serverImpl;
|
|
3
|
+
var _clientImpl;
|
|
4
|
+
var _fromSchemaFn;
|
|
5
|
+
/**
|
|
6
|
+
* Register the server-side cookie implementation.
|
|
7
|
+
* Called by server entry at module load time.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
function _registerServerCookieImpl(impl) {
|
|
11
|
+
_serverImpl = impl;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Register the fromSchema bridge function.
|
|
15
|
+
* Called by server/client entry at module load time.
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
function _registerFromSchema(fn) {
|
|
19
|
+
_fromSchemaFn = fn;
|
|
20
|
+
}
|
|
21
|
+
var _useCookieModule;
|
|
22
|
+
function getUseCookieModule() {
|
|
23
|
+
if (!_useCookieModule) throw new Error("[timber] defineCookie().useCookie() requires @timber-js/app/client to be loaded. This hook can only be used in client components.");
|
|
24
|
+
return _useCookieModule;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register the client cookie module. Called by the client entry to wire
|
|
28
|
+
* up the lazy reference without a top-level import.
|
|
29
|
+
*
|
|
30
|
+
* @internal — framework use only
|
|
31
|
+
*/
|
|
32
|
+
function _registerUseCookieModule(mod) {
|
|
33
|
+
_useCookieModule = mod;
|
|
34
|
+
_clientImpl = {
|
|
35
|
+
useCookie: mod.useCookie,
|
|
36
|
+
getCookieValue: (name) => {
|
|
37
|
+
if (typeof document === "undefined") return void 0;
|
|
38
|
+
const match = document.cookie.match(new RegExp("(?:^|;\\s*)" + name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\s*=\\s*([^;]*)"));
|
|
39
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
40
|
+
},
|
|
41
|
+
setCookieValue: (name, value, options) => {
|
|
42
|
+
const parts = [`${name}=${encodeURIComponent(value)}`];
|
|
43
|
+
const path = options?.path ?? "/";
|
|
44
|
+
parts.push(`Path=${path}`);
|
|
45
|
+
if (options?.domain) parts.push(`Domain=${options.domain}`);
|
|
46
|
+
if (options?.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
47
|
+
if (options?.expires) parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
48
|
+
const sameSite = options?.sameSite ?? "lax";
|
|
49
|
+
parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
|
|
50
|
+
if (options?.secure) parts.push("Secure");
|
|
51
|
+
document.cookie = parts.join("; ");
|
|
52
|
+
mod.notifyCookieChange(name);
|
|
53
|
+
},
|
|
54
|
+
deleteCookieValue: (name, options) => {
|
|
55
|
+
const path = options?.path ?? "/";
|
|
56
|
+
const domain = options?.domain;
|
|
57
|
+
let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;
|
|
58
|
+
if (domain) cookieStr += `; Domain=${domain}`;
|
|
59
|
+
document.cookie = cookieStr;
|
|
60
|
+
mod.notifyCookieChange(name);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function resolveCodec(codecOrSchema) {
|
|
65
|
+
if (typeof codecOrSchema.parse === "function" && typeof codecOrSchema.serialize === "function") return codecOrSchema;
|
|
66
|
+
if (typeof codecOrSchema === "object" && codecOrSchema !== null && "~standard" in codecOrSchema) {
|
|
67
|
+
if (!_fromSchemaFn) throw new Error("[timber] defineCookie: Standard Schema auto-detection requires @timber-js/app/server or @timber-js/app/client to be loaded. Pass an explicit Codec<T> with parse/serialize methods, or ensure the framework entry module is imported.");
|
|
68
|
+
return _fromSchemaFn(codecOrSchema);
|
|
69
|
+
}
|
|
70
|
+
throw new Error("[timber] defineCookie: codec must be a Codec<T> (with parse/serialize methods) or a Standard Schema object (Zod, Valibot, ArkType).");
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Define a typed cookie.
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* import { defineCookie } from '@timber-js/app/cookies';
|
|
77
|
+
* import { z } from 'zod/v4';
|
|
78
|
+
*
|
|
79
|
+
* // httpOnly: false — client methods available
|
|
80
|
+
* export const themeCookie = defineCookie('theme', {
|
|
81
|
+
* codec: z.enum(['light', 'dark', 'system']).default('system'),
|
|
82
|
+
* httpOnly: false,
|
|
83
|
+
* maxAge: 60 * 60 * 24 * 365,
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // Server or client
|
|
87
|
+
* const theme = themeCookie.get();
|
|
88
|
+
* themeCookie.set('dark');
|
|
89
|
+
*
|
|
90
|
+
* // Client hook
|
|
91
|
+
* const [theme, setTheme] = themeCookie.useCookie();
|
|
92
|
+
*
|
|
93
|
+
* // httpOnly: true (default) — server-only, no client methods
|
|
94
|
+
* export const sessionCookie = defineCookie('session', {
|
|
95
|
+
* codec: z.string(),
|
|
96
|
+
* });
|
|
97
|
+
* sessionCookie.get(); // works on server
|
|
98
|
+
* sessionCookie.useCookie(); // TS error — httpOnly cookie
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
function defineCookie(name, options) {
|
|
102
|
+
const { codec: codecOrSchema, ...cookieOpts } = options;
|
|
103
|
+
const codec = resolveCodec(codecOrSchema);
|
|
104
|
+
const resolvedOptions = { ...cookieOpts };
|
|
105
|
+
const isHttpOnly = options.httpOnly !== false;
|
|
106
|
+
function getClientOpts() {
|
|
107
|
+
return {
|
|
108
|
+
path: resolvedOptions.path,
|
|
109
|
+
domain: resolvedOptions.domain,
|
|
110
|
+
maxAge: resolvedOptions.maxAge,
|
|
111
|
+
expires: resolvedOptions.expires,
|
|
112
|
+
sameSite: resolvedOptions.sameSite,
|
|
113
|
+
secure: resolvedOptions.secure
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function assertNotHttpOnlyClient(method) {
|
|
117
|
+
if (isHttpOnly && !_serverImpl) throw new Error(`[timber] defineCookie('${name}').${method}() cannot be used with httpOnly cookies — the browser cannot access them. Set httpOnly: false to enable client access.`);
|
|
118
|
+
}
|
|
119
|
+
const base = {
|
|
120
|
+
name,
|
|
121
|
+
options: resolvedOptions,
|
|
122
|
+
codec,
|
|
123
|
+
get() {
|
|
124
|
+
if (_serverImpl) {
|
|
125
|
+
const raw = _serverImpl.getCookieJar().get(name);
|
|
126
|
+
return codec.parse(raw);
|
|
127
|
+
}
|
|
128
|
+
assertNotHttpOnlyClient("get");
|
|
129
|
+
if (_clientImpl) {
|
|
130
|
+
const raw = _clientImpl.getCookieValue(name);
|
|
131
|
+
return codec.parse(raw);
|
|
132
|
+
}
|
|
133
|
+
throw new Error(`[timber] defineCookie('${name}').get() — no environment registered. Ensure @timber-js/app/server or @timber-js/app/client is imported.`);
|
|
134
|
+
},
|
|
135
|
+
set(value) {
|
|
136
|
+
if (_serverImpl) {
|
|
137
|
+
const jar = _serverImpl.getCookieJar();
|
|
138
|
+
const serialized = codec.serialize(value);
|
|
139
|
+
if (serialized === null) jar.delete(name, {
|
|
140
|
+
path: resolvedOptions.path,
|
|
141
|
+
domain: resolvedOptions.domain
|
|
142
|
+
});
|
|
143
|
+
else jar.set(name, serialized, resolvedOptions);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
assertNotHttpOnlyClient("set");
|
|
147
|
+
if (_clientImpl) {
|
|
148
|
+
const serialized = codec.serialize(value);
|
|
149
|
+
if (serialized === null) _clientImpl.deleteCookieValue(name, getClientOpts());
|
|
150
|
+
else _clientImpl.setCookieValue(name, serialized, getClientOpts());
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`[timber] defineCookie('${name}').set() — no environment registered. Ensure @timber-js/app/server or @timber-js/app/client is imported.`);
|
|
154
|
+
},
|
|
155
|
+
delete() {
|
|
156
|
+
if (_serverImpl) {
|
|
157
|
+
_serverImpl.getCookieJar().delete(name, {
|
|
158
|
+
path: resolvedOptions.path,
|
|
159
|
+
domain: resolvedOptions.domain
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
assertNotHttpOnlyClient("delete");
|
|
164
|
+
if (_clientImpl) {
|
|
165
|
+
_clientImpl.deleteCookieValue(name, getClientOpts());
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
throw new Error(`[timber] defineCookie('${name}').delete() — no environment registered. Ensure @timber-js/app/server or @timber-js/app/client is imported.`);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
if (isHttpOnly) return base;
|
|
172
|
+
return {
|
|
173
|
+
...base,
|
|
174
|
+
useCookie() {
|
|
175
|
+
const { useCookie: useRawCookie } = getUseCookieModule();
|
|
176
|
+
const [raw, setRaw, deleteRaw] = useRawCookie(name, getClientOpts());
|
|
177
|
+
const parsed = codec.parse(raw);
|
|
178
|
+
const setTyped = (value) => {
|
|
179
|
+
const serialized = codec.serialize(value);
|
|
180
|
+
if (serialized === null) deleteRaw();
|
|
181
|
+
else setRaw(serialized);
|
|
182
|
+
};
|
|
183
|
+
return [
|
|
184
|
+
parsed,
|
|
185
|
+
setTyped,
|
|
186
|
+
deleteRaw
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
export { defineCookie as i, _registerServerCookieImpl as n, _registerUseCookieModule as r, _registerFromSchema as t };
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=define-cookie-BjpIt4UC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-cookie-BjpIt4UC.js","names":[],"sources":["../../src/cookies/define-cookie.ts"],"sourcesContent":["/**\n * defineCookie — typed cookie definitions.\n *\n * Bundles name + codec + options into a reusable CookieDefinition<T>\n * with sync .get(), .set(), .delete() isomorphic methods (server + client)\n * and a .useCookie() client hook.\n *\n * Uses the registration pattern: server entry registers serverCookieImpl,\n * client entry registers clientCookieImpl. This avoids top-level value\n * imports from either environment and makes defineCookie isomorphic\n * without `typeof window` checks.\n *\n * Standard Schema objects (Zod, Valibot, ArkType) are auto-detected in\n * the codec option — no explicit fromSchema() wrapper needed.\n *\n * See design/29-cookies.md §\"Typed Cookies with Schema Validation\"\n */\n\nimport type { CookieOptions } from '../server/cookie-context.js';\nimport type { ClientCookieOptions } from '../client/use-cookie.js';\n\n// ─── Types ────────────────────────────────────────────────────────────────\n\nimport type { Codec } from '../codec.js';\nimport type { StandardSchemaV1 } from '../schema-bridge.js';\n\n/**\n * A codec that converts between string cookie values and typed values.\n * Type alias for the shared Codec<T> protocol.\n */\nexport type CookieCodec<T> = Codec<T>;\n\n/** Options for defineCookie: codec + CookieOptions merged. */\nexport interface DefineCookieOptions<T, HttpOnly extends boolean = boolean> extends CookieOptions {\n /**\n * Codec for parsing/serializing the cookie value.\n * Accepts a Codec<T> or a Standard Schema object (Zod, Valibot, ArkType)\n * which is auto-wrapped via fromSchema.\n */\n codec: CookieCodec<T> | StandardSchemaV1<T>;\n /**\n * Prevent client-side JS access. Default: true.\n * When true (or omitted), client methods (useCookie, get/set/delete on\n * client) are omitted from the return type and throw at runtime.\n */\n httpOnly?: HttpOnly;\n}\n\n/**\n * Server-only cookie definition. Returned when httpOnly is true or omitted.\n * Client methods are absent from the type — accessing them is a TS error.\n */\nexport interface ServerOnlyCookieDefinition<T> {\n readonly name: string;\n readonly options: CookieOptions;\n readonly codec: CookieCodec<T>;\n\n /** Read the typed value. Sync, isomorphic (server + client). */\n get(): T;\n /** Set the typed value. Sync, isomorphic (server + client). */\n set(value: T): void;\n /** Delete the cookie. Sync, isomorphic (server + client). */\n delete(): void;\n}\n\n/**\n * Full cookie definition with client methods. Returned when httpOnly: false.\n */\nexport interface CookieDefinition<T> extends ServerOnlyCookieDefinition<T> {\n /** Client: React hook for reading/writing this cookie. Returns [value, setter, deleter]. */\n useCookie(): [T, (value: T) => void, () => void];\n}\n\n// ─── Registration Pattern ─────────────────────────────────────────────────\n//\n// Server and client entries register their implementations at module load\n// time. This avoids dynamic imports (which lose ALS context) and typeof\n// window checks (which are fragile).\n\n/** Server-side cookie impl: reads from ALS-backed cookie jar. */\nexport interface ServerCookieImpl {\n getCookieJar(): {\n get(name: string): string | undefined;\n set(name: string, value: string, options?: CookieOptions): void;\n delete(name: string, options?: Pick<CookieOptions, 'path' | 'domain'>): void;\n };\n}\n\n/** Client-side cookie impl: reads/writes document.cookie via useCookie hook. */\nexport interface ClientCookieImpl {\n useCookie(\n name: string,\n options?: ClientCookieOptions\n ): [string | undefined, (value: string, options?: ClientCookieOptions) => void, () => void];\n getCookieValue(name: string): string | undefined;\n setCookieValue(name: string, value: string, options?: ClientCookieOptions): void;\n deleteCookieValue(name: string, options?: ClientCookieOptions): void;\n}\n\nlet _serverImpl: ServerCookieImpl | undefined;\nlet _clientImpl: ClientCookieImpl | undefined;\nlet _fromSchemaFn: ((schema: StandardSchemaV1<unknown>) => CookieCodec<unknown>) | undefined;\n\n/**\n * Register the server-side cookie implementation.\n * Called by server entry at module load time.\n * @internal\n */\nexport function _registerServerCookieImpl(impl: ServerCookieImpl): void {\n _serverImpl = impl;\n}\n\n/**\n * Register the client-side cookie implementation.\n * Called by client entry at module load time.\n * @internal\n */\nexport function _registerClientCookieImpl(impl: ClientCookieImpl): void {\n _clientImpl = impl;\n}\n\n/**\n * Register the fromSchema bridge function.\n * Called by server/client entry at module load time.\n * @internal\n */\nexport function _registerFromSchema(\n fn: (schema: StandardSchemaV1<unknown>) => CookieCodec<unknown>\n): void {\n _fromSchemaFn = fn;\n}\n\n// Legacy registration for useCookie module — still used by client/index.ts\nlet _useCookieModule: typeof import('../client/use-cookie.js') | undefined;\n\nfunction getUseCookieModule(): typeof import('../client/use-cookie.js') {\n if (!_useCookieModule) {\n throw new Error(\n '[timber] defineCookie().useCookie() requires @timber-js/app/client to be loaded. ' +\n 'This hook can only be used in client components.'\n );\n }\n return _useCookieModule;\n}\n\n/**\n * Register the client cookie module. Called by the client entry to wire\n * up the lazy reference without a top-level import.\n *\n * @internal — framework use only\n */\nexport function _registerUseCookieModule(mod: typeof import('../client/use-cookie.js')): void {\n _useCookieModule = mod;\n // Also register the client impl from the module\n _clientImpl = {\n useCookie: mod.useCookie,\n getCookieValue: (name: string) => {\n if (typeof document === 'undefined') return undefined;\n const match = document.cookie.match(\n new RegExp('(?:^|;\\\\s*)' + name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') + '\\\\s*=\\\\s*([^;]*)')\n );\n return match ? decodeURIComponent(match[1]) : undefined;\n },\n setCookieValue: (name: string, value: string, options?: ClientCookieOptions) => {\n const parts: string[] = [`${name}=${encodeURIComponent(value)}`];\n const path = options?.path ?? '/';\n parts.push(`Path=${path}`);\n if (options?.domain) parts.push(`Domain=${options.domain}`);\n if (options?.maxAge !== undefined) parts.push(`Max-Age=${options.maxAge}`);\n if (options?.expires) parts.push(`Expires=${options.expires.toUTCString()}`);\n const sameSite = options?.sameSite ?? 'lax';\n parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);\n if (options?.secure) parts.push('Secure');\n document.cookie = parts.join('; ');\n // Notify useCookie subscribers so mounted hooks re-render\n mod.notifyCookieChange(name);\n },\n deleteCookieValue: (name: string, options?: ClientCookieOptions) => {\n const path = options?.path ?? '/';\n const domain = options?.domain;\n let cookieStr = `${name}=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=${path}`;\n if (domain) cookieStr += `; Domain=${domain}`;\n document.cookie = cookieStr;\n mod.notifyCookieChange(name);\n },\n };\n}\n\n// ─── Standard Schema Auto-Detection ───────────────────────────────────────\n\nfunction resolveCodec<T>(codecOrSchema: CookieCodec<T> | StandardSchemaV1<T>): CookieCodec<T> {\n // If it has parse + serialize, it's already a Codec\n if (\n typeof (codecOrSchema as Codec<T>).parse === 'function' &&\n typeof (codecOrSchema as Codec<T>).serialize === 'function'\n ) {\n return codecOrSchema as CookieCodec<T>;\n }\n\n // Auto-detect Standard Schema\n if (typeof codecOrSchema === 'object' && codecOrSchema !== null && '~standard' in codecOrSchema) {\n if (!_fromSchemaFn) {\n throw new Error(\n '[timber] defineCookie: Standard Schema auto-detection requires @timber-js/app/server or ' +\n '@timber-js/app/client to be loaded. Pass an explicit Codec<T> with parse/serialize methods, ' +\n 'or ensure the framework entry module is imported.'\n );\n }\n return _fromSchemaFn(codecOrSchema as StandardSchemaV1<unknown>) as CookieCodec<T>;\n }\n\n throw new Error(\n '[timber] defineCookie: codec must be a Codec<T> (with parse/serialize methods) ' +\n 'or a Standard Schema object (Zod, Valibot, ArkType).'\n );\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────\n\n/**\n * Define a typed cookie.\n *\n * ```ts\n * import { defineCookie } from '@timber-js/app/cookies';\n * import { z } from 'zod/v4';\n *\n * // httpOnly: false — client methods available\n * export const themeCookie = defineCookie('theme', {\n * codec: z.enum(['light', 'dark', 'system']).default('system'),\n * httpOnly: false,\n * maxAge: 60 * 60 * 24 * 365,\n * });\n *\n * // Server or client\n * const theme = themeCookie.get();\n * themeCookie.set('dark');\n *\n * // Client hook\n * const [theme, setTheme] = themeCookie.useCookie();\n *\n * // httpOnly: true (default) — server-only, no client methods\n * export const sessionCookie = defineCookie('session', {\n * codec: z.string(),\n * });\n * sessionCookie.get(); // works on server\n * sessionCookie.useCookie(); // TS error — httpOnly cookie\n * ```\n */\nexport function defineCookie<T, HttpOnly extends boolean = true>(\n name: string,\n options: DefineCookieOptions<T, HttpOnly>\n): HttpOnly extends false ? CookieDefinition<T> : ServerOnlyCookieDefinition<T> {\n const { codec: codecOrSchema, ...cookieOpts } = options;\n const codec = resolveCodec(codecOrSchema);\n const resolvedOptions: CookieOptions = { ...cookieOpts };\n const isHttpOnly = options.httpOnly !== false; // default true\n\n function getClientOpts(): ClientCookieOptions {\n return {\n path: resolvedOptions.path,\n domain: resolvedOptions.domain,\n maxAge: resolvedOptions.maxAge,\n expires: resolvedOptions.expires,\n sameSite: resolvedOptions.sameSite,\n secure: resolvedOptions.secure,\n };\n }\n\n function assertNotHttpOnlyClient(method: string): void {\n if (isHttpOnly && !_serverImpl) {\n throw new Error(\n `[timber] defineCookie('${name}').${method}() cannot be used with httpOnly cookies — ` +\n `the browser cannot access them. Set httpOnly: false to enable client access.`\n );\n }\n }\n\n const base: ServerOnlyCookieDefinition<T> = {\n name,\n options: resolvedOptions,\n codec,\n\n get(): T {\n if (_serverImpl) {\n const jar = _serverImpl.getCookieJar();\n const raw = jar.get(name);\n return codec.parse(raw);\n }\n // Client path\n assertNotHttpOnlyClient('get');\n if (_clientImpl) {\n const raw = _clientImpl.getCookieValue(name);\n return codec.parse(raw);\n }\n throw new Error(\n `[timber] defineCookie('${name}').get() — no environment registered. ` +\n 'Ensure @timber-js/app/server or @timber-js/app/client is imported.'\n );\n },\n\n set(value: T): void {\n if (_serverImpl) {\n const jar = _serverImpl.getCookieJar();\n const serialized = codec.serialize(value);\n if (serialized === null) {\n jar.delete(name, {\n path: resolvedOptions.path,\n domain: resolvedOptions.domain,\n });\n } else {\n jar.set(name, serialized, resolvedOptions);\n }\n return;\n }\n // Client path\n assertNotHttpOnlyClient('set');\n if (_clientImpl) {\n const serialized = codec.serialize(value);\n if (serialized === null) {\n _clientImpl.deleteCookieValue(name, getClientOpts());\n } else {\n _clientImpl.setCookieValue(name, serialized, getClientOpts());\n }\n return;\n }\n throw new Error(\n `[timber] defineCookie('${name}').set() — no environment registered. ` +\n 'Ensure @timber-js/app/server or @timber-js/app/client is imported.'\n );\n },\n\n delete(): void {\n if (_serverImpl) {\n const jar = _serverImpl.getCookieJar();\n jar.delete(name, {\n path: resolvedOptions.path,\n domain: resolvedOptions.domain,\n });\n return;\n }\n // Client path\n assertNotHttpOnlyClient('delete');\n if (_clientImpl) {\n _clientImpl.deleteCookieValue(name, getClientOpts());\n return;\n }\n throw new Error(\n `[timber] defineCookie('${name}').delete() — no environment registered. ` +\n 'Ensure @timber-js/app/server or @timber-js/app/client is imported.'\n );\n },\n };\n\n if (isHttpOnly) {\n return base as HttpOnly extends false ? CookieDefinition<T> : ServerOnlyCookieDefinition<T>;\n }\n\n // httpOnly: false — add useCookie client hook\n const full: CookieDefinition<T> = {\n ...base,\n\n useCookie(): [T, (value: T) => void, () => void] {\n const { useCookie: useRawCookie } = getUseCookieModule();\n\n const clientOpts = getClientOpts();\n const [raw, setRaw, deleteRaw] = useRawCookie(name, clientOpts);\n const parsed = codec.parse(raw);\n\n const setTyped = (value: T): void => {\n const serialized = codec.serialize(value);\n if (serialized === null) {\n deleteRaw();\n } else {\n setRaw(serialized);\n }\n };\n\n return [parsed, setTyped, deleteRaw];\n },\n };\n\n return full as HttpOnly extends false ? CookieDefinition<T> : ServerOnlyCookieDefinition<T>;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-
|
|
1
|
+
{"version":3,"file":"format-Bcn-Iv1x.js","names":[],"sources":["../../src/utils/format.ts"],"sourcesContent":["/**\n * Shared formatting utilities.\n */\n\n/** Format a byte count as a human-readable string (e.g. \"1.50 kB\"). */\nexport function formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;\n return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;\n}\n"],"mappings":";;;;;AAKA,SAAgB,WAAW,OAAuB;AAChD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAC7D,QAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//#region src/cache/handler-store.ts
|
|
2
|
+
var handler = null;
|
|
3
|
+
/** Replace the active cache handler. Called by the framework at boot. */
|
|
4
|
+
function setCacheHandler(h) {
|
|
5
|
+
handler = h;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Get the active cache handler. Creates a default MemoryCacheHandler on
|
|
9
|
+
* first access if none has been set via setCacheHandler().
|
|
10
|
+
*/
|
|
11
|
+
function getCacheHandler() {
|
|
12
|
+
if (!handler) handler = createDefaultHandler();
|
|
13
|
+
return handler;
|
|
14
|
+
}
|
|
15
|
+
function createDefaultHandler() {
|
|
16
|
+
const store = /* @__PURE__ */ new Map();
|
|
17
|
+
const maxEntries = 1e3;
|
|
18
|
+
return {
|
|
19
|
+
async get(key) {
|
|
20
|
+
const entry = store.get(key);
|
|
21
|
+
if (!entry) return null;
|
|
22
|
+
store.delete(key);
|
|
23
|
+
store.set(key, entry);
|
|
24
|
+
const stale = Date.now() > entry.expiresAt;
|
|
25
|
+
return {
|
|
26
|
+
value: entry.value,
|
|
27
|
+
stale
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
async set(key, value, opts) {
|
|
31
|
+
if (store.has(key)) store.delete(key);
|
|
32
|
+
while (store.size >= maxEntries) {
|
|
33
|
+
const oldest = store.keys().next().value;
|
|
34
|
+
if (oldest !== void 0) store.delete(oldest);
|
|
35
|
+
else break;
|
|
36
|
+
}
|
|
37
|
+
store.set(key, {
|
|
38
|
+
value,
|
|
39
|
+
expiresAt: Date.now() + opts.ttl * 1e3,
|
|
40
|
+
tags: opts.tags
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
async invalidate(opts) {
|
|
44
|
+
if (opts.key) store.delete(opts.key);
|
|
45
|
+
if (opts.tag) {
|
|
46
|
+
for (const [key, entry] of store) if (entry.tags.includes(opts.tag)) store.delete(key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { setCacheHandler as n, getCacheHandler as t };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=handler-store-B-lqaGyh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-store-B-lqaGyh.js","names":[],"sources":["../../src/cache/handler-store.ts"],"sourcesContent":["/**\n * Module-level cache handler singleton.\n *\n * Lazily initialized to MemoryCacheHandler on first access. The framework\n * replaces this at boot from timber.config.ts via setCacheHandler().\n *\n * This module avoids importing from ./index to prevent circular dependencies.\n */\n\n// Inline the interface to avoid circular import with index.ts\ninterface CacheHandlerLike {\n get(key: string): Promise<{ value: unknown; stale: boolean } | null>;\n set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void>;\n invalidate(opts: { key?: string; tag?: string }): Promise<void>;\n}\n\nlet handler: CacheHandlerLike | null = null;\n\n/** Replace the active cache handler. Called by the framework at boot. */\nexport function setCacheHandler(h: CacheHandlerLike): void {\n handler = h;\n}\n\n/**\n * Get the active cache handler. Creates a default MemoryCacheHandler on\n * first access if none has been set via setCacheHandler().\n */\nexport function getCacheHandler(): CacheHandlerLike {\n if (!handler) {\n // Inline a minimal LRU cache to avoid circular dep with index.ts.\n // In production, the framework always calls setCacheHandler() at boot.\n handler = createDefaultHandler();\n }\n return handler;\n}\n\nfunction createDefaultHandler(): CacheHandlerLike {\n const store = new Map<string, { value: unknown; expiresAt: number; tags: string[] }>();\n const maxEntries = 1000;\n\n return {\n async get(key) {\n const entry = store.get(key);\n if (!entry) return null;\n store.delete(key);\n store.set(key, entry);\n const stale = Date.now() > entry.expiresAt;\n return { value: entry.value, stale };\n },\n async set(key, value, opts) {\n if (store.has(key)) store.delete(key);\n while (store.size >= maxEntries) {\n const oldest = store.keys().next().value;\n if (oldest !== undefined) store.delete(oldest);\n else break;\n }\n store.set(key, { value, expiresAt: Date.now() + opts.ttl * 1000, tags: opts.tags });\n },\n async invalidate(opts) {\n if (opts.key) store.delete(opts.key);\n if (opts.tag) {\n for (const [key, entry] of store) {\n if (entry.tags.includes(opts.tag)) store.delete(key);\n }\n }\n },\n };\n}\n"],"mappings":";AAgBA,IAAI,UAAmC;;AAGvC,SAAgB,gBAAgB,GAA2B;AACzD,WAAU;;;;;;AAOZ,SAAgB,kBAAoC;AAClD,KAAI,CAAC,QAGH,WAAU,sBAAsB;AAElC,QAAO;;AAGT,SAAS,uBAAyC;CAChD,MAAM,wBAAQ,IAAI,KAAoE;CACtF,MAAM,aAAa;AAEnB,QAAO;EACL,MAAM,IAAI,KAAK;GACb,MAAM,QAAQ,MAAM,IAAI,IAAI;AAC5B,OAAI,CAAC,MAAO,QAAO;AACnB,SAAM,OAAO,IAAI;AACjB,SAAM,IAAI,KAAK,MAAM;GACrB,MAAM,QAAQ,KAAK,KAAK,GAAG,MAAM;AACjC,UAAO;IAAE,OAAO,MAAM;IAAO;IAAO;;EAEtC,MAAM,IAAI,KAAK,OAAO,MAAM;AAC1B,OAAI,MAAM,IAAI,IAAI,CAAE,OAAM,OAAO,IAAI;AACrC,UAAO,MAAM,QAAQ,YAAY;IAC/B,MAAM,SAAS,MAAM,MAAM,CAAC,MAAM,CAAC;AACnC,QAAI,WAAW,KAAA,EAAW,OAAM,OAAO,OAAO;QACzC;;AAEP,SAAM,IAAI,KAAK;IAAE;IAAO,WAAW,KAAK,KAAK,GAAG,KAAK,MAAM;IAAM,MAAM,KAAK;IAAM,CAAC;;EAErF,MAAM,WAAW,MAAM;AACrB,OAAI,KAAK,IAAK,OAAM,OAAO,KAAK,IAAI;AACpC,OAAI,KAAK;SACF,MAAM,CAAC,KAAK,UAAU,MACzB,KAAI,MAAM,KAAK,SAAS,KAAK,IAAI,CAAE,OAAM,OAAO,IAAI;;;EAI3D"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { s as getTraceStore, v as isDebug, y as isDevMode } from "./tracing-C8V-YGsP.js";
|
|
2
|
+
//#region src/server/error-formatter.ts
|
|
3
|
+
/**
|
|
4
|
+
* Error Formatter — rewrites SSR/RSC error messages to surface user code.
|
|
5
|
+
*
|
|
6
|
+
* When React or Vite throw errors during SSR, stack traces reference
|
|
7
|
+
* vendored dependency paths (e.g. `.vite/deps_ssr/@vitejs_plugin-rsc_vendor_...`)
|
|
8
|
+
* and mangled export names (`__vite_ssr_export_default__`). This module
|
|
9
|
+
* rewrites error messages and stack traces to point at user code instead.
|
|
10
|
+
*
|
|
11
|
+
* Dev-only — in production, errors go through the structured logger
|
|
12
|
+
* without formatting.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Patterns that identify internal Vite/RSC vendor paths in stack traces.
|
|
16
|
+
* These are replaced with human-readable labels.
|
|
17
|
+
*/
|
|
18
|
+
var VENDOR_PATH_PATTERNS = [
|
|
19
|
+
{
|
|
20
|
+
pattern: /node_modules\/\.vite\/deps_ssr\/@vitejs_plugin-rsc_vendor_react-server-dom[^\s)]+/g,
|
|
21
|
+
replacement: "<react-server-dom>"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
pattern: /node_modules\/\.vite\/deps_ssr\/@vitejs_plugin-rsc_vendor[^\s)]+/g,
|
|
25
|
+
replacement: "<rsc-vendor>"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pattern: /node_modules\/\.vite\/deps_ssr\/[^\s)]+/g,
|
|
29
|
+
replacement: "<vite-dep>"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
pattern: /node_modules\/\.vite\/deps\/[^\s)]+/g,
|
|
33
|
+
replacement: "<vite-dep>"
|
|
34
|
+
}
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Patterns that identify Vite-mangled export names in error messages.
|
|
38
|
+
*/
|
|
39
|
+
var MANGLED_NAME_PATTERNS = [{
|
|
40
|
+
pattern: /__vite_ssr_export_default__/g,
|
|
41
|
+
replacement: "<default export>"
|
|
42
|
+
}, {
|
|
43
|
+
pattern: /__vite_ssr_export_(\w+)__/g,
|
|
44
|
+
replacement: "<export $1>"
|
|
45
|
+
}];
|
|
46
|
+
/**
|
|
47
|
+
* Rewrite an error's message and stack to replace internal Vite paths
|
|
48
|
+
* and mangled names with human-readable labels.
|
|
49
|
+
*/
|
|
50
|
+
function formatSsrError(error) {
|
|
51
|
+
if (!(error instanceof Error)) return String(error);
|
|
52
|
+
let message = error.message;
|
|
53
|
+
let stack = error.stack ?? "";
|
|
54
|
+
for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) message = message.replace(pattern, replacement);
|
|
55
|
+
for (const { pattern, replacement } of VENDOR_PATH_PATTERNS) stack = stack.replace(pattern, replacement);
|
|
56
|
+
for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) stack = stack.replace(pattern, replacement);
|
|
57
|
+
const hint = extractErrorHint(error.message);
|
|
58
|
+
const parts = [];
|
|
59
|
+
parts.push(message);
|
|
60
|
+
if (hint) parts.push(` → ${hint}`);
|
|
61
|
+
const userFrames = extractUserFrames(stack);
|
|
62
|
+
if (userFrames.length > 0) {
|
|
63
|
+
parts.push("");
|
|
64
|
+
parts.push(" User code in stack:");
|
|
65
|
+
for (const frame of userFrames) parts.push(` ${frame}`);
|
|
66
|
+
}
|
|
67
|
+
return parts.join("\n");
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extract a human-readable hint from common React/RSC error messages.
|
|
71
|
+
*
|
|
72
|
+
* React error messages contain useful information but the surrounding
|
|
73
|
+
* context (vendor paths, mangled names) obscures it. This extracts the
|
|
74
|
+
* actionable part as a one-line hint.
|
|
75
|
+
*/
|
|
76
|
+
function extractErrorHint(message) {
|
|
77
|
+
if (message.match(/Functions cannot be passed directly to Client Components/)) {
|
|
78
|
+
const propMatch = message.match(/<[^>]*?\s(\w+)=\{function/);
|
|
79
|
+
if (propMatch) return `Prop "${propMatch[1]}" is a function — mark it "use server" or call it before passing`;
|
|
80
|
+
return "A function prop was passed to a Client Component — mark it \"use server\" or call it before passing";
|
|
81
|
+
}
|
|
82
|
+
if (message.includes("Objects are not valid as a React child")) return "An object was rendered as JSX children — convert to string or extract the value";
|
|
83
|
+
const nullRefMatch = message.match(/Cannot read propert(?:y|ies) of (undefined|null) \(reading '(\w+)'\)/);
|
|
84
|
+
if (nullRefMatch) return `Accessed .${nullRefMatch[2]} on ${nullRefMatch[1]} — check that the value exists`;
|
|
85
|
+
const notFnMatch = message.match(/(\w+) is not a function/);
|
|
86
|
+
if (notFnMatch) return `"${notFnMatch[1]}" is not a function — check imports and exports`;
|
|
87
|
+
if (message.includes("Element type is invalid")) return "A component resolved to undefined/null — check default exports and import paths";
|
|
88
|
+
if (message.includes("Invalid hook call")) return "A hook was called outside of a React component render. If this is a 'use client' component, ensure the directive is at the very top of the file (before any imports) and that @vitejs/plugin-rsc is loaded correctly. Barrel re-exports from non-'use client' files do not propagate the directive.";
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Extract stack frames that reference user code (not node_modules,
|
|
93
|
+
* not framework internals).
|
|
94
|
+
*
|
|
95
|
+
* Returns at most 5 frames to keep output concise.
|
|
96
|
+
*/
|
|
97
|
+
function extractUserFrames(stack) {
|
|
98
|
+
const lines = stack.split("\n");
|
|
99
|
+
const userFrames = [];
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const trimmed = line.trim();
|
|
102
|
+
if (!trimmed.startsWith("at ")) continue;
|
|
103
|
+
if (trimmed.includes("node_modules") || trimmed.includes("<react-server-dom>") || trimmed.includes("<rsc-vendor>") || trimmed.includes("<vite-dep>") || trimmed.includes("node:internal")) continue;
|
|
104
|
+
userFrames.push(trimmed);
|
|
105
|
+
if (userFrames.length >= 5) break;
|
|
106
|
+
}
|
|
107
|
+
return userFrames;
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/server/default-logger.ts
|
|
111
|
+
/**
|
|
112
|
+
* DefaultLogger — human-readable stderr logging when no custom logger is configured.
|
|
113
|
+
*
|
|
114
|
+
* Ships as the fallback so production deployments always have error visibility,
|
|
115
|
+
* even without an `instrumentation.ts` logger export. Output is one line per
|
|
116
|
+
* event, designed for `fly logs`, `kubectl logs`, Cloudflare dashboard tails, etc.
|
|
117
|
+
*
|
|
118
|
+
* Format:
|
|
119
|
+
* [timber] ERROR message key=value key=value trace_id=4bf92f35
|
|
120
|
+
* [timber] WARN message key=value key=value trace_id=4bf92f35
|
|
121
|
+
* [timber] INFO message method=GET path=/dashboard status=200 durationMs=43 trace_id=4bf92f35
|
|
122
|
+
*
|
|
123
|
+
* Behavior:
|
|
124
|
+
* - Suppressed entirely in dev mode (dev logging handles all output)
|
|
125
|
+
* - `debug` suppressed unless TIMBER_DEBUG is set
|
|
126
|
+
* - Replaced entirely when a custom logger is set via `setLogger()`
|
|
127
|
+
*
|
|
128
|
+
* See design/17-logging.md §"DefaultLogger"
|
|
129
|
+
*/
|
|
130
|
+
/**
|
|
131
|
+
* Format data fields as `key=value` pairs for human-readable output.
|
|
132
|
+
* - `error` key is serialized via formatSsrError for stack trace cleanup
|
|
133
|
+
* - `trace_id` is truncated to 8 chars for readability (full ID in OTEL)
|
|
134
|
+
* - Other values are stringified inline
|
|
135
|
+
*/
|
|
136
|
+
function formatDataFields(data) {
|
|
137
|
+
if (!data) return "";
|
|
138
|
+
const parts = [];
|
|
139
|
+
let traceId;
|
|
140
|
+
for (const [key, value] of Object.entries(data)) {
|
|
141
|
+
if (key === "trace_id") {
|
|
142
|
+
traceId = typeof value === "string" ? value : String(value);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (key === "error") {
|
|
146
|
+
parts.push(`error=${formatSsrError(value)}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (value === void 0 || value === null) continue;
|
|
150
|
+
parts.push(`${key}=${value}`);
|
|
151
|
+
}
|
|
152
|
+
if (traceId) parts.push(`trace_id=${traceId.slice(0, 8)}`);
|
|
153
|
+
return parts.length > 0 ? " " + parts.join(" ") : "";
|
|
154
|
+
}
|
|
155
|
+
/** Pad level string to fixed width for alignment. */
|
|
156
|
+
function padLevel(level) {
|
|
157
|
+
return level.padEnd(5);
|
|
158
|
+
}
|
|
159
|
+
function createDefaultLogger() {
|
|
160
|
+
return {
|
|
161
|
+
error(msg, data) {
|
|
162
|
+
const fields = formatDataFields(data);
|
|
163
|
+
process.stderr.write(`[timber] ${padLevel("ERROR")} ${msg}${fields}\n`);
|
|
164
|
+
},
|
|
165
|
+
warn(msg, data) {
|
|
166
|
+
const fields = formatDataFields(data);
|
|
167
|
+
process.stderr.write(`[timber] ${padLevel("WARN")} ${msg}${fields}\n`);
|
|
168
|
+
},
|
|
169
|
+
info(msg, data) {
|
|
170
|
+
if (isDevMode()) return;
|
|
171
|
+
if (!isDebug()) return;
|
|
172
|
+
const fields = formatDataFields(data);
|
|
173
|
+
process.stderr.write(`[timber] ${padLevel("INFO")} ${msg}${fields}\n`);
|
|
174
|
+
},
|
|
175
|
+
debug(msg, data) {
|
|
176
|
+
if (isDevMode()) return;
|
|
177
|
+
if (!isDebug()) return;
|
|
178
|
+
const fields = formatDataFields(data);
|
|
179
|
+
process.stderr.write(`[timber] ${padLevel("DEBUG")} ${msg}${fields}\n`);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/server/logger.ts
|
|
185
|
+
/**
|
|
186
|
+
* Logger — structured logging with environment-aware formatting.
|
|
187
|
+
*
|
|
188
|
+
* timber.js ships a DefaultLogger that writes human-readable lines to stderr
|
|
189
|
+
* in production. Users can export a custom logger from instrumentation.ts to
|
|
190
|
+
* replace it with pino, winston, or any TimberLogger-compatible object.
|
|
191
|
+
*
|
|
192
|
+
* See design/17-logging.md §"Production Logging"
|
|
193
|
+
*/
|
|
194
|
+
var _logger = createDefaultLogger();
|
|
195
|
+
/**
|
|
196
|
+
* Set the user-provided logger. Called by the instrumentation loader
|
|
197
|
+
* when it finds a `logger` export in instrumentation.ts. Replaces
|
|
198
|
+
* the DefaultLogger entirely.
|
|
199
|
+
*/
|
|
200
|
+
function setLogger(logger) {
|
|
201
|
+
_logger = logger;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get the current logger. Always non-null — returns DefaultLogger when
|
|
205
|
+
* no custom logger is configured.
|
|
206
|
+
*/
|
|
207
|
+
function getLogger() {
|
|
208
|
+
return _logger;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Inject trace_id and span_id into log data for log–trace correlation.
|
|
212
|
+
* Always injects trace_id (never undefined). Injects span_id only when OTEL is active.
|
|
213
|
+
*/
|
|
214
|
+
function withTraceContext(data) {
|
|
215
|
+
const store = getTraceStore();
|
|
216
|
+
const enriched = { ...data };
|
|
217
|
+
if (store) {
|
|
218
|
+
enriched.trace_id = store.traceId;
|
|
219
|
+
if (store.spanId) enriched.span_id = store.spanId;
|
|
220
|
+
}
|
|
221
|
+
return enriched;
|
|
222
|
+
}
|
|
223
|
+
/** Log a completed request. Level: info. */
|
|
224
|
+
function logRequestCompleted(data) {
|
|
225
|
+
_logger.info("request completed", withTraceContext(data));
|
|
226
|
+
}
|
|
227
|
+
/** Log request received. Level: debug. */
|
|
228
|
+
function logRequestReceived(data) {
|
|
229
|
+
_logger.debug("request received", withTraceContext(data));
|
|
230
|
+
}
|
|
231
|
+
/** Log a slow request warning. Level: warn. */
|
|
232
|
+
function logSlowRequest(data) {
|
|
233
|
+
_logger.warn("slow request exceeded threshold", withTraceContext(data));
|
|
234
|
+
}
|
|
235
|
+
/** Log middleware short-circuit. Level: debug. */
|
|
236
|
+
function logMiddlewareShortCircuit(data) {
|
|
237
|
+
_logger.debug("middleware short-circuited", withTraceContext(data));
|
|
238
|
+
}
|
|
239
|
+
/** Log unhandled error in middleware phase. Level: error. */
|
|
240
|
+
function logMiddlewareError(data) {
|
|
241
|
+
_logger.error("unhandled error in middleware phase", withTraceContext(data));
|
|
242
|
+
}
|
|
243
|
+
/** Log unhandled render-phase error. Level: error. */
|
|
244
|
+
function logRenderError(data) {
|
|
245
|
+
_logger.error("unhandled render-phase error", withTraceContext(data));
|
|
246
|
+
}
|
|
247
|
+
/** Log proxy.ts uncaught error. Level: error. */
|
|
248
|
+
function logProxyError(data) {
|
|
249
|
+
_logger.error("proxy.ts threw uncaught error", withTraceContext(data));
|
|
250
|
+
}
|
|
251
|
+
/** Log unhandled error in route handler. Level: error. */
|
|
252
|
+
function logRouteError(data) {
|
|
253
|
+
_logger.error("unhandled route handler error", withTraceContext(data));
|
|
254
|
+
}
|
|
255
|
+
/** Log waitUntil() adapter missing (once at startup). Level: warn. */
|
|
256
|
+
function logWaitUntilUnsupported() {
|
|
257
|
+
_logger.warn("adapter does not support waitUntil()");
|
|
258
|
+
}
|
|
259
|
+
/** Log waitUntil() promise rejection. Level: warn. */
|
|
260
|
+
function logWaitUntilRejected(data) {
|
|
261
|
+
_logger.warn("waitUntil() promise rejected", withTraceContext(data));
|
|
262
|
+
}
|
|
263
|
+
/** Log staleWhileRevalidate refetch failure. Level: warn. */
|
|
264
|
+
function logSwrRefetchFailed(data) {
|
|
265
|
+
_logger.warn("staleWhileRevalidate refetch failed", withTraceContext(data));
|
|
266
|
+
}
|
|
267
|
+
/** Log cache miss. Level: debug. */
|
|
268
|
+
function logCacheMiss(data) {
|
|
269
|
+
_logger.debug("timber.cache MISS", withTraceContext(data));
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Log an intentionally swallowed error. Provides observability into catch
|
|
273
|
+
* blocks that are deliberately empty — the error is consumed, never rethrown.
|
|
274
|
+
*
|
|
275
|
+
* Default level: `warn` in dev (so the overlay surfaces patterns), `debug`
|
|
276
|
+
* in production (low noise unless TIMBER_DEBUG is set). Pass `opts.level`
|
|
277
|
+
* to override.
|
|
278
|
+
*
|
|
279
|
+
* **Infallible** — swallow() itself never throws, even if the logger is
|
|
280
|
+
* broken. A thrown swallow would turn a benign catch into a crash.
|
|
281
|
+
*/
|
|
282
|
+
function swallow(err, reason, opts) {
|
|
283
|
+
try {
|
|
284
|
+
const level = opts?.level ?? (isDevMode() ? "warn" : "debug");
|
|
285
|
+
_logger[level](`swallowed: ${reason}`, withTraceContext({ error: err }));
|
|
286
|
+
} catch {}
|
|
287
|
+
}
|
|
288
|
+
//#endregion
|
|
289
|
+
export { logProxyError as a, logRequestReceived as c, logSwrRefetchFailed as d, logWaitUntilRejected as f, swallow as h, logMiddlewareShortCircuit as i, logRouteError as l, setLogger as m, logCacheMiss as n, logRenderError as o, logWaitUntilUnsupported as p, logMiddlewareError as r, logRequestCompleted as s, getLogger as t, logSlowRequest as u };
|
|
290
|
+
|
|
291
|
+
//# sourceMappingURL=logger-0m8MsKdc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-0m8MsKdc.js","names":[],"sources":["../../src/server/error-formatter.ts","../../src/server/default-logger.ts","../../src/server/logger.ts"],"sourcesContent":["/**\n * Error Formatter — rewrites SSR/RSC error messages to surface user code.\n *\n * When React or Vite throw errors during SSR, stack traces reference\n * vendored dependency paths (e.g. `.vite/deps_ssr/@vitejs_plugin-rsc_vendor_...`)\n * and mangled export names (`__vite_ssr_export_default__`). This module\n * rewrites error messages and stack traces to point at user code instead.\n *\n * Dev-only — in production, errors go through the structured logger\n * without formatting.\n */\n\n// ─── Stack Trace Rewriting ──────────────────────────────────────────────────\n\n/**\n * Patterns that identify internal Vite/RSC vendor paths in stack traces.\n * These are replaced with human-readable labels.\n */\nconst VENDOR_PATH_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n {\n pattern: /node_modules\\/\\.vite\\/deps_ssr\\/@vitejs_plugin-rsc_vendor_react-server-dom[^\\s)]+/g,\n replacement: '<react-server-dom>',\n },\n {\n pattern: /node_modules\\/\\.vite\\/deps_ssr\\/@vitejs_plugin-rsc_vendor[^\\s)]+/g,\n replacement: '<rsc-vendor>',\n },\n {\n pattern: /node_modules\\/\\.vite\\/deps_ssr\\/[^\\s)]+/g,\n replacement: '<vite-dep>',\n },\n {\n pattern: /node_modules\\/\\.vite\\/deps\\/[^\\s)]+/g,\n replacement: '<vite-dep>',\n },\n];\n\n/**\n * Patterns that identify Vite-mangled export names in error messages.\n */\nconst MANGLED_NAME_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n {\n pattern: /__vite_ssr_export_default__/g,\n replacement: '<default export>',\n },\n {\n pattern: /__vite_ssr_export_(\\w+)__/g,\n replacement: '<export $1>',\n },\n];\n\n/**\n * Rewrite an error's message and stack to replace internal Vite paths\n * and mangled names with human-readable labels.\n */\nexport function formatSsrError(error: unknown): string {\n if (!(error instanceof Error)) {\n return String(error);\n }\n\n let message = error.message;\n let stack = error.stack ?? '';\n\n // Rewrite mangled names in the message\n for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) {\n message = message.replace(pattern, replacement);\n }\n\n // Rewrite vendor paths in the stack\n for (const { pattern, replacement } of VENDOR_PATH_PATTERNS) {\n stack = stack.replace(pattern, replacement);\n }\n\n // Rewrite mangled names in the stack too\n for (const { pattern, replacement } of MANGLED_NAME_PATTERNS) {\n stack = stack.replace(pattern, replacement);\n }\n\n // Extract hints from React-specific error patterns\n const hint = extractErrorHint(error.message);\n\n // Build formatted output: cleaned message, hint (if any), then cleaned stack\n const parts: string[] = [];\n parts.push(message);\n if (hint) {\n parts.push(` → ${hint}`);\n }\n\n // Include only the user-code frames from the stack (skip the first line\n // which is the message itself, and filter out vendor-only frames)\n const userFrames = extractUserFrames(stack);\n if (userFrames.length > 0) {\n parts.push('');\n parts.push(' User code in stack:');\n for (const frame of userFrames) {\n parts.push(` ${frame}`);\n }\n }\n\n return parts.join('\\n');\n}\n\n// ─── Error Hint Extraction ──────────────────────────────────────────────────\n\n/**\n * Extract a human-readable hint from common React/RSC error messages.\n *\n * React error messages contain useful information but the surrounding\n * context (vendor paths, mangled names) obscures it. This extracts the\n * actionable part as a one-line hint.\n */\nfunction extractErrorHint(message: string): string | null {\n // \"Functions cannot be passed directly to Client Components\"\n // Extract the component and prop name from the JSX-like syntax in the message\n const fnPassedMatch = message.match(/Functions cannot be passed directly to Client Components/);\n if (fnPassedMatch) {\n // Try to extract the prop name from the message\n // React formats: <... propName={function ...} ...>\n const propMatch = message.match(/<[^>]*?\\s(\\w+)=\\{function/);\n if (propMatch) {\n return `Prop \"${propMatch[1]}\" is a function — mark it \"use server\" or call it before passing`;\n }\n return 'A function prop was passed to a Client Component — mark it \"use server\" or call it before passing';\n }\n\n // \"Objects are not valid as a React child\"\n if (message.includes('Objects are not valid as a React child')) {\n return 'An object was rendered as JSX children — convert to string or extract the value';\n }\n\n // \"Cannot read properties of undefined/null\"\n const nullRefMatch = message.match(\n /Cannot read propert(?:y|ies) of (undefined|null) \\(reading '(\\w+)'\\)/\n );\n if (nullRefMatch) {\n return `Accessed .${nullRefMatch[2]} on ${nullRefMatch[1]} — check that the value exists`;\n }\n\n // \"X is not a function\"\n const notFnMatch = message.match(/(\\w+) is not a function/);\n if (notFnMatch) {\n return `\"${notFnMatch[1]}\" is not a function — check imports and exports`;\n }\n\n // \"Element type is invalid\"\n if (message.includes('Element type is invalid')) {\n return 'A component resolved to undefined/null — check default exports and import paths';\n }\n\n // \"Invalid hook call\" — hooks called outside React's render context.\n // In RSC, this typically means a 'use client' component was executed as a\n // server component instead of being serialized as a client reference.\n if (message.includes('Invalid hook call')) {\n return (\n 'A hook was called outside of a React component render. ' +\n \"If this is a 'use client' component, ensure the directive is at the very top of the file \" +\n '(before any imports) and that @vitejs/plugin-rsc is loaded correctly. ' +\n \"Barrel re-exports from non-'use client' files do not propagate the directive.\"\n );\n }\n\n return null;\n}\n\n// ─── Stack Frame Filtering ──────────────────────────────────────────────────\n\n/**\n * Extract stack frames that reference user code (not node_modules,\n * not framework internals).\n *\n * Returns at most 5 frames to keep output concise.\n */\nfunction extractUserFrames(stack: string): string[] {\n const lines = stack.split('\\n');\n const userFrames: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Skip non-frame lines\n if (!trimmed.startsWith('at ')) continue;\n // Skip node_modules, vendor, and internal frames\n if (\n trimmed.includes('node_modules') ||\n trimmed.includes('<react-server-dom>') ||\n trimmed.includes('<rsc-vendor>') ||\n trimmed.includes('<vite-dep>') ||\n trimmed.includes('node:internal')\n ) {\n continue;\n }\n userFrames.push(trimmed);\n if (userFrames.length >= 5) break;\n }\n\n return userFrames;\n}\n","/**\n * DefaultLogger — human-readable stderr logging when no custom logger is configured.\n *\n * Ships as the fallback so production deployments always have error visibility,\n * even without an `instrumentation.ts` logger export. Output is one line per\n * event, designed for `fly logs`, `kubectl logs`, Cloudflare dashboard tails, etc.\n *\n * Format:\n * [timber] ERROR message key=value key=value trace_id=4bf92f35\n * [timber] WARN message key=value key=value trace_id=4bf92f35\n * [timber] INFO message method=GET path=/dashboard status=200 durationMs=43 trace_id=4bf92f35\n *\n * Behavior:\n * - Suppressed entirely in dev mode (dev logging handles all output)\n * - `debug` suppressed unless TIMBER_DEBUG is set\n * - Replaced entirely when a custom logger is set via `setLogger()`\n *\n * See design/17-logging.md §\"DefaultLogger\"\n */\n\nimport { isDevMode, isDebug } from './debug.js';\nimport { formatSsrError } from './error-formatter.js';\nimport type { TimberLogger } from './logger.js';\n\n/**\n * Format data fields as `key=value` pairs for human-readable output.\n * - `error` key is serialized via formatSsrError for stack trace cleanup\n * - `trace_id` is truncated to 8 chars for readability (full ID in OTEL)\n * - Other values are stringified inline\n */\nfunction formatDataFields(data?: Record<string, unknown>): string {\n if (!data) return '';\n\n const parts: string[] = [];\n let traceId: string | undefined;\n\n for (const [key, value] of Object.entries(data)) {\n if (key === 'trace_id') {\n // Defer trace_id to the end\n traceId = typeof value === 'string' ? value : String(value);\n continue;\n }\n if (key === 'error') {\n // Serialize errors with formatSsrError for clean output\n parts.push(`error=${formatSsrError(value)}`);\n continue;\n }\n if (value === undefined || value === null) continue;\n parts.push(`${key}=${value}`);\n }\n\n // trace_id always last, truncated to 8 chars for readability\n if (traceId) {\n parts.push(`trace_id=${traceId.slice(0, 8)}`);\n }\n\n return parts.length > 0 ? ' ' + parts.join(' ') : '';\n}\n\n/** Pad level string to fixed width for alignment. */\nfunction padLevel(level: string): string {\n return level.padEnd(5);\n}\n\nexport function createDefaultLogger(): TimberLogger {\n return {\n error(msg: string, data?: Record<string, unknown>): void {\n // Errors are ALWAYS logged, including dev mode. Suppressing errors\n // in dev causes silent 500s with no stack trace, making route.ts\n // and render errors impossible to debug. See TIM-555.\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('ERROR')} ${msg}${fields}\\n`);\n },\n\n warn(msg: string, data?: Record<string, unknown>): void {\n // Warnings are always logged — same rationale as errors.\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('WARN')} ${msg}${fields}\\n`);\n },\n\n info(msg: string, data?: Record<string, unknown>): void {\n // info is suppressed by default — per-request lines are too noisy\n // without a custom logger. Enable with TIMBER_DEBUG.\n if (isDevMode()) return;\n if (!isDebug()) return;\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('INFO')} ${msg}${fields}\\n`);\n },\n\n debug(msg: string, data?: Record<string, unknown>): void {\n // debug is suppressed in dev (dev logger handles it) and in\n // production unless TIMBER_DEBUG is explicitly set.\n if (isDevMode()) return;\n if (!isDebug()) return;\n const fields = formatDataFields(data);\n process.stderr.write(`[timber] ${padLevel('DEBUG')} ${msg}${fields}\\n`);\n },\n };\n}\n","/**\n * Logger — structured logging with environment-aware formatting.\n *\n * timber.js ships a DefaultLogger that writes human-readable lines to stderr\n * in production. Users can export a custom logger from instrumentation.ts to\n * replace it with pino, winston, or any TimberLogger-compatible object.\n *\n * See design/17-logging.md §\"Production Logging\"\n */\n\nimport { getTraceStore } from './tracing.js';\nimport { createDefaultLogger } from './default-logger.js';\nimport { isDevMode } from './debug.js';\n\n// ─── Logger Interface ─────────────────────────────────────────────────────\n\n/** Any object with standard log methods satisfies this — pino, winston, consola, console. */\nexport interface TimberLogger {\n info(msg: string, data?: Record<string, unknown>): void;\n warn(msg: string, data?: Record<string, unknown>): void;\n error(msg: string, data?: Record<string, unknown>): void;\n debug(msg: string, data?: Record<string, unknown>): void;\n}\n\n// ─── Logger Registry ──────────────────────────────────────────────────────\n\n// Initialize with DefaultLogger so production errors are never silent.\n// Replaced when setLogger() is called from instrumentation.ts.\nlet _logger: TimberLogger = createDefaultLogger();\n\n/**\n * Set the user-provided logger. Called by the instrumentation loader\n * when it finds a `logger` export in instrumentation.ts. Replaces\n * the DefaultLogger entirely.\n */\nexport function setLogger(logger: TimberLogger): void {\n _logger = logger;\n}\n\n/**\n * Get the current logger. Always non-null — returns DefaultLogger when\n * no custom logger is configured.\n */\nexport function getLogger(): TimberLogger {\n return _logger;\n}\n\n// ─── Framework Log Helpers ────────────────────────────────────────────────\n\n/**\n * Inject trace_id and span_id into log data for log–trace correlation.\n * Always injects trace_id (never undefined). Injects span_id only when OTEL is active.\n */\nfunction withTraceContext(data?: Record<string, unknown>): Record<string, unknown> {\n const store = getTraceStore();\n const enriched: Record<string, unknown> = { ...data };\n if (store) {\n enriched.trace_id = store.traceId;\n if (store.spanId) {\n enriched.span_id = store.spanId;\n }\n }\n return enriched;\n}\n\n// ─── Framework Event Emitters ─────────────────────────────────────────────\n\n/** Log a completed request. Level: info. */\nexport function logRequestCompleted(data: {\n method: string;\n path: string;\n status: number;\n durationMs: number;\n /** Number of concurrent in-flight requests (including this one) at completion time. */\n concurrency?: number;\n}): void {\n _logger.info('request completed', withTraceContext(data));\n}\n\n/** Log request received. Level: debug. */\nexport function logRequestReceived(data: { method: string; path: string }): void {\n _logger.debug('request received', withTraceContext(data));\n}\n\n/** Log a slow request warning. Level: warn. */\nexport function logSlowRequest(data: {\n method: string;\n path: string;\n durationMs: number;\n threshold: number;\n /** Number of concurrent in-flight requests at the time the slow request completed. */\n concurrency?: number;\n}): void {\n _logger.warn('slow request exceeded threshold', withTraceContext(data));\n}\n\n/** Log middleware short-circuit. Level: debug. */\nexport function logMiddlewareShortCircuit(data: {\n method: string;\n path: string;\n status: number;\n}): void {\n _logger.debug('middleware short-circuited', withTraceContext(data));\n}\n\n/** Log unhandled error in middleware phase. Level: error. */\nexport function logMiddlewareError(data: { method: string; path: string; error: unknown }): void {\n _logger.error('unhandled error in middleware phase', withTraceContext(data));\n}\n\n/** Log unhandled render-phase error. Level: error. */\nexport function logRenderError(data: {\n method: string;\n path: string;\n error: unknown;\n errorId?: string;\n}): void {\n _logger.error('unhandled render-phase error', withTraceContext(data));\n}\n\n/** Log proxy.ts uncaught error. Level: error. */\nexport function logProxyError(data: { error: unknown }): void {\n _logger.error('proxy.ts threw uncaught error', withTraceContext(data));\n}\n\n/** Log unhandled error in server action. Level: error. */\nexport function logActionError(data: { method: string; path: string; error: unknown }): void {\n _logger.error('unhandled server action error', withTraceContext(data));\n}\n\n/** Log unhandled error in route handler. Level: error. */\nexport function logRouteError(data: { method: string; path: string; error: unknown }): void {\n _logger.error('unhandled route handler error', withTraceContext(data));\n}\n\n/** Log SSR streaming error (post-shell). Level: error. */\nexport function logStreamingError(data: { error: unknown }): void {\n _logger.error('SSR streaming error (post-shell)', withTraceContext(data));\n}\n\n/** Log waitUntil() adapter missing (once at startup). Level: warn. */\nexport function logWaitUntilUnsupported(): void {\n _logger.warn('adapter does not support waitUntil()');\n}\n\n/** Log waitUntil() promise rejection. Level: warn. */\nexport function logWaitUntilRejected(data: { error: unknown }): void {\n _logger.warn('waitUntil() promise rejected', withTraceContext(data));\n}\n\n/** Log staleWhileRevalidate refetch failure. Level: warn. */\nexport function logSwrRefetchFailed(data: { cacheKey: string; error: unknown }): void {\n _logger.warn('staleWhileRevalidate refetch failed', withTraceContext(data));\n}\n\n/** Log cache miss. Level: debug. */\nexport function logCacheMiss(data: { cacheKey: string }): void {\n _logger.debug('timber.cache MISS', withTraceContext(data));\n}\n\n// ─── Swallow Helper ───────────────────────────────────────────────────────\n\n/**\n * Log an intentionally swallowed error. Provides observability into catch\n * blocks that are deliberately empty — the error is consumed, never rethrown.\n *\n * Default level: `warn` in dev (so the overlay surfaces patterns), `debug`\n * in production (low noise unless TIMBER_DEBUG is set). Pass `opts.level`\n * to override.\n *\n * **Infallible** — swallow() itself never throws, even if the logger is\n * broken. A thrown swallow would turn a benign catch into a crash.\n */\nexport function swallow(err: unknown, reason: string, opts?: { level?: 'debug' | 'warn' }): void {\n try {\n const level = opts?.level ?? (isDevMode() ? 'warn' : 'debug');\n _logger[level](`swallowed: ${reason}`, withTraceContext({ error: err }));\n } catch {\n // swallow() must never throw.\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,IAAM,uBAAwE;CAC5E;EACE,SAAS;EACT,aAAa;EACd;CACD;EACE,SAAS;EACT,aAAa;EACd;CACD;EACE,SAAS;EACT,aAAa;EACd;CACD;EACE,SAAS;EACT,aAAa;EACd;CACF;;;;AAKD,IAAM,wBAAyE,CAC7E;CACE,SAAS;CACT,aAAa;CACd,EACD;CACE,SAAS;CACT,aAAa;CACd,CACF;;;;;AAMD,SAAgB,eAAe,OAAwB;AACrD,KAAI,EAAE,iBAAiB,OACrB,QAAO,OAAO,MAAM;CAGtB,IAAI,UAAU,MAAM;CACpB,IAAI,QAAQ,MAAM,SAAS;AAG3B,MAAK,MAAM,EAAE,SAAS,iBAAiB,sBACrC,WAAU,QAAQ,QAAQ,SAAS,YAAY;AAIjD,MAAK,MAAM,EAAE,SAAS,iBAAiB,qBACrC,SAAQ,MAAM,QAAQ,SAAS,YAAY;AAI7C,MAAK,MAAM,EAAE,SAAS,iBAAiB,sBACrC,SAAQ,MAAM,QAAQ,SAAS,YAAY;CAI7C,MAAM,OAAO,iBAAiB,MAAM,QAAQ;CAG5C,MAAM,QAAkB,EAAE;AAC1B,OAAM,KAAK,QAAQ;AACnB,KAAI,KACF,OAAM,KAAK,OAAO,OAAO;CAK3B,MAAM,aAAa,kBAAkB,MAAM;AAC3C,KAAI,WAAW,SAAS,GAAG;AACzB,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,wBAAwB;AACnC,OAAK,MAAM,SAAS,WAClB,OAAM,KAAK,OAAO,QAAQ;;AAI9B,QAAO,MAAM,KAAK,KAAK;;;;;;;;;AAYzB,SAAS,iBAAiB,SAAgC;AAIxD,KADsB,QAAQ,MAAM,2DAA2D,EAC5E;EAGjB,MAAM,YAAY,QAAQ,MAAM,4BAA4B;AAC5D,MAAI,UACF,QAAO,SAAS,UAAU,GAAG;AAE/B,SAAO;;AAIT,KAAI,QAAQ,SAAS,yCAAyC,CAC5D,QAAO;CAIT,MAAM,eAAe,QAAQ,MAC3B,uEACD;AACD,KAAI,aACF,QAAO,aAAa,aAAa,GAAG,MAAM,aAAa,GAAG;CAI5D,MAAM,aAAa,QAAQ,MAAM,0BAA0B;AAC3D,KAAI,WACF,QAAO,IAAI,WAAW,GAAG;AAI3B,KAAI,QAAQ,SAAS,0BAA0B,CAC7C,QAAO;AAMT,KAAI,QAAQ,SAAS,oBAAoB,CACvC,QACE;AAOJ,QAAO;;;;;;;;AAWT,SAAS,kBAAkB,OAAyB;CAClD,MAAM,QAAQ,MAAM,MAAM,KAAK;CAC/B,MAAM,aAAuB,EAAE;AAE/B,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,KAAK,MAAM;AAE3B,MAAI,CAAC,QAAQ,WAAW,MAAM,CAAE;AAEhC,MACE,QAAQ,SAAS,eAAe,IAChC,QAAQ,SAAS,qBAAqB,IACtC,QAAQ,SAAS,eAAe,IAChC,QAAQ,SAAS,aAAa,IAC9B,QAAQ,SAAS,gBAAgB,CAEjC;AAEF,aAAW,KAAK,QAAQ;AACxB,MAAI,WAAW,UAAU,EAAG;;AAG9B,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpKT,SAAS,iBAAiB,MAAwC;AAChE,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,QAAkB,EAAE;CAC1B,IAAI;AAEJ,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,EAAE;AAC/C,MAAI,QAAQ,YAAY;AAEtB,aAAU,OAAO,UAAU,WAAW,QAAQ,OAAO,MAAM;AAC3D;;AAEF,MAAI,QAAQ,SAAS;AAEnB,SAAM,KAAK,SAAS,eAAe,MAAM,GAAG;AAC5C;;AAEF,MAAI,UAAU,KAAA,KAAa,UAAU,KAAM;AAC3C,QAAM,KAAK,GAAG,IAAI,GAAG,QAAQ;;AAI/B,KAAI,QACF,OAAM,KAAK,YAAY,QAAQ,MAAM,GAAG,EAAE,GAAG;AAG/C,QAAO,MAAM,SAAS,IAAI,OAAO,MAAM,KAAK,KAAK,GAAG;;;AAItD,SAAS,SAAS,OAAuB;AACvC,QAAO,MAAM,OAAO,EAAE;;AAGxB,SAAgB,sBAAoC;AAClD,QAAO;EACL,MAAM,KAAa,MAAsC;GAIvD,MAAM,SAAS,iBAAiB,KAAK;AACrC,WAAQ,OAAO,MAAM,YAAY,SAAS,QAAQ,CAAC,IAAI,MAAM,OAAO,IAAI;;EAG1E,KAAK,KAAa,MAAsC;GAEtD,MAAM,SAAS,iBAAiB,KAAK;AACrC,WAAQ,OAAO,MAAM,YAAY,SAAS,OAAO,CAAC,IAAI,MAAM,OAAO,IAAI;;EAGzE,KAAK,KAAa,MAAsC;AAGtD,OAAI,WAAW,CAAE;AACjB,OAAI,CAAC,SAAS,CAAE;GAChB,MAAM,SAAS,iBAAiB,KAAK;AACrC,WAAQ,OAAO,MAAM,YAAY,SAAS,OAAO,CAAC,IAAI,MAAM,OAAO,IAAI;;EAGzE,MAAM,KAAa,MAAsC;AAGvD,OAAI,WAAW,CAAE;AACjB,OAAI,CAAC,SAAS,CAAE;GAChB,MAAM,SAAS,iBAAiB,KAAK;AACrC,WAAQ,OAAO,MAAM,YAAY,SAAS,QAAQ,CAAC,IAAI,MAAM,OAAO,IAAI;;EAE3E;;;;;;;;;;;;;ACrEH,IAAI,UAAwB,qBAAqB;;;;;;AAOjD,SAAgB,UAAU,QAA4B;AACpD,WAAU;;;;;;AAOZ,SAAgB,YAA0B;AACxC,QAAO;;;;;;AAST,SAAS,iBAAiB,MAAyD;CACjF,MAAM,QAAQ,eAAe;CAC7B,MAAM,WAAoC,EAAE,GAAG,MAAM;AACrD,KAAI,OAAO;AACT,WAAS,WAAW,MAAM;AAC1B,MAAI,MAAM,OACR,UAAS,UAAU,MAAM;;AAG7B,QAAO;;;AAMT,SAAgB,oBAAoB,MAO3B;AACP,SAAQ,KAAK,qBAAqB,iBAAiB,KAAK,CAAC;;;AAI3D,SAAgB,mBAAmB,MAA8C;AAC/E,SAAQ,MAAM,oBAAoB,iBAAiB,KAAK,CAAC;;;AAI3D,SAAgB,eAAe,MAOtB;AACP,SAAQ,KAAK,mCAAmC,iBAAiB,KAAK,CAAC;;;AAIzE,SAAgB,0BAA0B,MAIjC;AACP,SAAQ,MAAM,8BAA8B,iBAAiB,KAAK,CAAC;;;AAIrE,SAAgB,mBAAmB,MAA8D;AAC/F,SAAQ,MAAM,uCAAuC,iBAAiB,KAAK,CAAC;;;AAI9E,SAAgB,eAAe,MAKtB;AACP,SAAQ,MAAM,gCAAgC,iBAAiB,KAAK,CAAC;;;AAIvE,SAAgB,cAAc,MAAgC;AAC5D,SAAQ,MAAM,iCAAiC,iBAAiB,KAAK,CAAC;;;AASxE,SAAgB,cAAc,MAA8D;AAC1F,SAAQ,MAAM,iCAAiC,iBAAiB,KAAK,CAAC;;;AASxE,SAAgB,0BAAgC;AAC9C,SAAQ,KAAK,uCAAuC;;;AAItD,SAAgB,qBAAqB,MAAgC;AACnE,SAAQ,KAAK,gCAAgC,iBAAiB,KAAK,CAAC;;;AAItE,SAAgB,oBAAoB,MAAkD;AACpF,SAAQ,KAAK,uCAAuC,iBAAiB,KAAK,CAAC;;;AAI7E,SAAgB,aAAa,MAAkC;AAC7D,SAAQ,MAAM,qBAAqB,iBAAiB,KAAK,CAAC;;;;;;;;;;;;;AAgB5D,SAAgB,QAAQ,KAAc,QAAgB,MAA2C;AAC/F,KAAI;EACF,MAAM,QAAQ,MAAM,UAAU,WAAW,GAAG,SAAS;AACrD,UAAQ,OAAO,cAAc,UAAU,iBAAiB,EAAE,OAAO,KAAK,CAAC,CAAC;SAClE"}
|