@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa
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/AGENTS.md +8 -4
- package/README.md +296 -887
- package/dist/bin/rango.js +459 -91
- package/dist/testing/vitest.js +36 -2
- package/dist/vite/index.js +1708 -414
- package/package.json +35 -10
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +82 -5
- package/skills/bundle-analysis/SKILL.md +2 -2
- package/skills/cache-guide/SKILL.md +14 -9
- package/skills/caching/SKILL.md +221 -12
- package/skills/catalog.json +271 -0
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +83 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +11 -3
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +9 -9
- package/skills/hooks/SKILL.md +73 -900
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +84 -7
- package/skills/i18n/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +51 -17
- package/skills/layout/SKILL.md +38 -16
- package/skills/links/SKILL.md +1 -1
- package/skills/loader/SKILL.md +48 -20
- package/skills/middleware/SKILL.md +11 -5
- package/skills/migrate-nextjs/SKILL.md +203 -20
- package/skills/migrate-react-router/SKILL.md +59 -675
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +3 -3
- package/skills/observability/SKILL.md +70 -5
- package/skills/parallel/SKILL.md +32 -8
- package/skills/ppr/SKILL.md +622 -0
- package/skills/prerender/SKILL.md +59 -28
- package/skills/rango/SKILL.md +124 -50
- package/skills/response-routes/SKILL.md +78 -46
- package/skills/route/SKILL.md +85 -6
- package/skills/router-setup/SKILL.md +41 -6
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +28 -3
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +1 -1
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +68 -654
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +1 -1
- package/skills/typesafety/SKILL.md +45 -918
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +47 -17
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +44 -1
- package/src/__augment-tests__/augmented.check.ts +2 -3
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +178 -100
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +81 -68
- package/src/browser/navigation-client.ts +115 -70
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +153 -88
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +157 -144
- package/src/browser/prefetch/cache.ts +148 -81
- package/src/browser/prefetch/fetch.ts +231 -51
- package/src/browser/prefetch/queue.ts +25 -7
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +40 -7
- package/src/browser/react/NavigationProvider.tsx +140 -99
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +17 -2
- package/src/browser/react/index.ts +0 -51
- package/src/browser/react/location-state-shared.ts +14 -15
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +10 -5
- package/src/browser/react/use-params.ts +0 -2
- package/src/browser/react/use-router.ts +6 -4
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +74 -8
- package/src/browser/rsc-router.tsx +97 -22
- package/src/browser/scroll-restoration.ts +15 -8
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/server-action-bridge.ts +216 -38
- package/src/browser/types.ts +94 -22
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/generate-manifest.ts +155 -131
- package/src/build/generate-route-types.ts +1 -1
- package/src/build/index.ts +11 -5
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -22
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +12 -1
- package/src/build/route-types/include-resolution.ts +455 -61
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +15 -2
- package/src/build/route-types/router-processing.ts +77 -41
- package/src/build/route-types/source-scan.ts +105 -7
- package/src/build/runtime-discovery.ts +4 -1
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +454 -101
- package/src/cache/cache-scope.ts +159 -54
- package/src/cache/cache-tag.ts +149 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2170 -377
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +126 -41
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +39 -22
- package/src/client.tsx +28 -58
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +13 -1
- package/src/decode-loader-results.ts +18 -2
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +0 -3
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +57 -40
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +7 -0
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +7 -12
- package/src/index.rsc.ts +88 -8
- package/src/index.ts +90 -16
- package/src/internal-debug.ts +11 -10
- package/src/loader.rsc.ts +19 -9
- package/src/loader.ts +12 -4
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +75 -7
- package/src/redirect-origin.ts +114 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +25 -0
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +13 -49
- package/src/route-definition/dsl-helpers.ts +60 -53
- package/src/route-definition/helper-factories.ts +0 -2
- package/src/route-definition/helpers-types.ts +46 -46
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +6 -1
- package/src/route-definition/use-item-types.ts +3 -6
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +0 -5
- package/src/router/content-negotiation.ts +58 -23
- package/src/router/error-handling.ts +44 -17
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +6 -1
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +35 -2
- package/src/router/lazy-includes.ts +79 -56
- package/src/router/loader-resolution.ts +151 -73
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +76 -52
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +181 -178
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +115 -194
- package/src/router/match-middleware/cache-store.ts +61 -50
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +36 -67
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +231 -120
- package/src/router/navigation-snapshot.ts +7 -56
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +99 -152
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +111 -66
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +47 -42
- package/src/router/revalidation.ts +75 -81
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +70 -8
- package/src/router/router-options.ts +126 -4
- package/src/router/segment-resolution/fresh.ts +104 -80
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +155 -39
- package/src/router/segment-resolution/loader-mask.ts +60 -0
- package/src/router/segment-resolution/loader-snapshot.ts +259 -0
- package/src/router/segment-resolution/mask-nested.ts +83 -0
- package/src/router/segment-resolution/revalidation.ts +215 -304
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +35 -15
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +54 -35
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +9 -23
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -64
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +13 -5
- package/src/router.ts +119 -48
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +1 -0
- package/src/rsc/handler.ts +267 -152
- package/src/rsc/helpers.ts +78 -4
- package/src/rsc/index.ts +1 -4
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +11 -15
- package/src/rsc/progressive-enhancement.ts +120 -13
- package/src/rsc/redirect-guard.ts +100 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +58 -141
- package/src/rsc/rsc-rendering.ts +492 -49
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +268 -82
- package/src/rsc/shell-capture.ts +1190 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +45 -3
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +31 -26
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +260 -95
- package/src/server/context.ts +99 -9
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +125 -2
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +379 -138
- package/src/ssr/index.tsx +491 -182
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +44 -48
- package/src/testing/collect-handle.ts +14 -31
- package/src/testing/dispatch.ts +533 -160
- package/src/testing/e2e/fixture.ts +45 -11
- package/src/testing/e2e/index.ts +1 -22
- package/src/testing/e2e/matchers.ts +0 -16
- package/src/testing/e2e/parity.ts +85 -4
- package/src/testing/e2e/server.ts +12 -0
- package/src/testing/flight-matchers.ts +7 -14
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +36 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +30 -0
- package/src/testing/flight.ts +145 -70
- package/src/testing/generated-routes.ts +26 -50
- package/src/testing/index.ts +18 -19
- package/src/testing/internal/context.ts +184 -68
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +134 -115
- package/src/testing/run-loader.ts +140 -51
- package/src/testing/run-middleware.ts +59 -33
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
- package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
- package/src/testing/vitest.ts +138 -16
- package/src/theme/ThemeProvider.tsx +56 -84
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +15 -15
- package/src/types/handler-context.ts +45 -15
- package/src/types/index.ts +2 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +8 -22
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +100 -13
- package/src/urls/include-helper.ts +10 -12
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -8
- package/src/urls/path-helper-types.ts +52 -14
- package/src/urls/path-helper.ts +5 -54
- package/src/urls/pattern-types.ts +36 -0
- package/src/urls/type-extraction.ts +76 -42
- package/src/urls/urls-function.ts +0 -14
- package/src/use-loader.tsx +0 -186
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +34 -43
- package/src/vite/discovery/discovery-errors.ts +61 -0
- package/src/vite/discovery/prerender-collection.ts +33 -46
- package/src/vite/discovery/state.ts +12 -1
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/index.ts +9 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +143 -10
- package/src/vite/plugins/cjs-to-esm.ts +8 -12
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +85 -56
- package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
- package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
- package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
- package/src/vite/plugins/expose-internal-ids.ts +10 -1
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +21 -46
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +22 -27
- package/src/vite/plugins/version-plugin.ts +6 -66
- package/src/vite/plugins/virtual-entries.ts +137 -26
- package/src/vite/rango.ts +146 -135
- package/src/vite/router-discovery.ts +189 -48
- package/src/vite/utils/ast-handler-extract.ts +11 -20
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +4 -75
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +71 -44
- package/src/vite/utils/shared-utils.ts +55 -37
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -1,20 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OpenTelemetry
|
|
2
|
+
* OpenTelemetry adapters for the router.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Two adapters, two surfaces — matching the split in instrument.ts:
|
|
5
|
+
*
|
|
6
|
+
* - createOTelTracing(tracer): the OTel adapter for the `tracing` SLOT — the
|
|
7
|
+
* canonical phase-span layer. It bridges observePhase's callback boundary
|
|
8
|
+
* onto OTel's callback-bound `startActiveSpan`, so the router's phase spans
|
|
9
|
+
* (rango.request/middleware/loader/render/ssr) nest by async context and the
|
|
10
|
+
* loader's own OTel spans (db/fetch) land under rango.loader. This is the
|
|
11
|
+
* OTel equivalent of createCloudflareTracing — pass it to
|
|
12
|
+
* `createRouter({ tracing })`.
|
|
13
|
+
*
|
|
14
|
+
* - createOTelSink(tracer): the OTel adapter for the `telemetry` SLOT — a
|
|
15
|
+
* TelemetrySink for the EVENT-shaped facts (handler errors, cache decisions,
|
|
16
|
+
* revalidation decisions, timeouts, origin rejections). It emits one instant
|
|
17
|
+
* OTel span per fact. It deliberately does NOT emit request/loader phase
|
|
18
|
+
* spans: those are owned by the tracing slot (createOTelTracing) so the two
|
|
19
|
+
* layers don't produce duplicate rango.request / rango.loader spans.
|
|
20
|
+
*
|
|
21
|
+
* The core router stays OTel-agnostic — these adapters accept a standard OTel
|
|
22
|
+
* Tracer (structurally typed, no import needed) and bridge the gap.
|
|
7
23
|
*
|
|
8
24
|
* Usage:
|
|
9
25
|
* import { trace } from "@opentelemetry/api";
|
|
10
|
-
* import { createOTelSink } from "@rangojs/router";
|
|
26
|
+
* import { createRouter, createOTelTracing, createOTelSink } from "@rangojs/router";
|
|
11
27
|
*
|
|
28
|
+
* const tracer = trace.getTracer("my-app");
|
|
12
29
|
* const router = createRouter({
|
|
13
|
-
*
|
|
30
|
+
* tracing: createOTelTracing(tracer), // phase spans (callback-bound)
|
|
31
|
+
* telemetry: createOTelSink(tracer), // discrete-fact instant spans
|
|
14
32
|
* });
|
|
33
|
+
*
|
|
34
|
+
* Faithful nesting requires an OTel async context manager
|
|
35
|
+
* (AsyncLocalStorageContextManager) configured in your OTel setup — standard for
|
|
36
|
+
* any startActiveSpan-based instrumentation.
|
|
15
37
|
*/
|
|
16
38
|
|
|
17
39
|
import type { TelemetrySink, TelemetryEvent } from "./telemetry.js";
|
|
40
|
+
import { runThenSettle } from "./tracing.js";
|
|
41
|
+
import type {
|
|
42
|
+
RouterTracingConfig,
|
|
43
|
+
SpanRunner,
|
|
44
|
+
TracingToggleOptions,
|
|
45
|
+
} from "./tracing.js";
|
|
18
46
|
|
|
19
47
|
// ---------------------------------------------------------------------------
|
|
20
48
|
// Minimal OTel-compatible types (structurally typed, no import needed)
|
|
@@ -22,21 +50,21 @@ import type { TelemetrySink, TelemetryEvent } from "./telemetry.js";
|
|
|
22
50
|
|
|
23
51
|
/**
|
|
24
52
|
* Minimal Span interface compatible with @opentelemetry/api Span.
|
|
25
|
-
* Only the methods used by the
|
|
53
|
+
* Only the methods used by the adapters are declared.
|
|
26
54
|
*/
|
|
27
55
|
export interface OTelSpan {
|
|
28
56
|
setAttribute(key: string, value: string | number | boolean): OTelSpan | void;
|
|
29
|
-
addEvent(
|
|
30
|
-
name: string,
|
|
31
|
-
attributes?: Record<string, string | number | boolean>,
|
|
32
|
-
): OTelSpan | void;
|
|
33
57
|
setStatus(status: { code: number; message?: string }): OTelSpan | void;
|
|
34
58
|
recordException(exception: Error): void;
|
|
35
59
|
end(): void;
|
|
36
60
|
}
|
|
37
61
|
|
|
38
62
|
/**
|
|
39
|
-
* Minimal Tracer interface
|
|
63
|
+
* Minimal Tracer interface for the EVENT sink (createOTelSink): only `startSpan`
|
|
64
|
+
* is used (one instant span per discrete fact). Kept narrow so a custom,
|
|
65
|
+
* event-only tracer that does not implement `startActiveSpan` still satisfies it.
|
|
66
|
+
* The real `@opentelemetry/api` Tracer has both methods, so it satisfies this and
|
|
67
|
+
* `OTelActiveSpanTracer` below.
|
|
40
68
|
*/
|
|
41
69
|
export interface OTelTracer {
|
|
42
70
|
startSpan(
|
|
@@ -47,194 +75,108 @@ export interface OTelTracer {
|
|
|
47
75
|
): OTelSpan;
|
|
48
76
|
}
|
|
49
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Minimal Tracer interface for the PHASE-SPAN adapter (createOTelTracing): only
|
|
80
|
+
* `startActiveSpan` is used (callback-bound, so the span is active for the work
|
|
81
|
+
* and child spans nest). Declared separately from `OTelTracer` so each factory
|
|
82
|
+
* requires exactly the method it calls.
|
|
83
|
+
*/
|
|
84
|
+
export interface OTelActiveSpanTracer {
|
|
85
|
+
startActiveSpan<T>(name: string, fn: (span: OTelSpan) => T): T;
|
|
86
|
+
}
|
|
87
|
+
|
|
50
88
|
// OTel SpanStatusCode constants (mirrors @opentelemetry/api values)
|
|
51
|
-
const STATUS_OK = 1;
|
|
52
89
|
const STATUS_ERROR = 2;
|
|
53
90
|
|
|
54
91
|
// ---------------------------------------------------------------------------
|
|
55
|
-
//
|
|
92
|
+
// Tracing adapter: phase spans via startActiveSpan (the `tracing` slot)
|
|
56
93
|
// ---------------------------------------------------------------------------
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
function requestKey(event: {
|
|
64
|
-
requestId?: string;
|
|
65
|
-
pathname: string;
|
|
66
|
-
transaction: string;
|
|
67
|
-
}): string {
|
|
68
|
-
return `${event.requestId ?? ""}:${event.pathname}:${event.transaction}`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function loaderKey(event: {
|
|
72
|
-
requestId?: string;
|
|
73
|
-
segmentId: string;
|
|
74
|
-
loaderName: string;
|
|
75
|
-
pathname: string;
|
|
76
|
-
}): string {
|
|
77
|
-
return `${event.requestId ?? ""}:${event.segmentId}:${event.loaderName}:${event.pathname}`;
|
|
78
|
-
}
|
|
95
|
+
/**
|
|
96
|
+
* Options for createOTelTracing. Alias of the shared {@link TracingToggleOptions}
|
|
97
|
+
* (`enabled` master switch + per-phase `spans` toggles); the name is public API.
|
|
98
|
+
*/
|
|
99
|
+
export type OTelTracingOptions = TracingToggleOptions;
|
|
79
100
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Create the tracing config that maps the router's phases onto OTel spans via
|
|
103
|
+
* `tracer.startActiveSpan`, which runs the work inside the span's active context
|
|
104
|
+
* (so child spans nest) and returns the work's value unchanged. The span ends
|
|
105
|
+
* when that value — or, for async work, the returned promise — settles, matching
|
|
106
|
+
* observePhase's contract. When the work throws or rejects, the exception is
|
|
107
|
+
* recorded and the span status is set to ERROR before it ends, so a failed phase
|
|
108
|
+
* stays visible in the trace (the old createOTelSink error path is preserved here
|
|
109
|
+
* now that phase spans live in this adapter). Pass the result to
|
|
110
|
+
* `createRouter({ tracing })`.
|
|
111
|
+
*
|
|
112
|
+
* @see createCloudflareTracing (`@rangojs/router/cloudflare`) for the same slot
|
|
113
|
+
* using Cloudflare Workers native custom spans.
|
|
114
|
+
*/
|
|
115
|
+
export function createOTelTracing(
|
|
116
|
+
tracer: OTelActiveSpanTracer,
|
|
117
|
+
options: OTelTracingOptions = {},
|
|
118
|
+
): RouterTracingConfig {
|
|
119
|
+
const runner: SpanRunner = <T>(name: string, fn: (span: OTelSpan) => T): T =>
|
|
120
|
+
tracer.startActiveSpan(
|
|
121
|
+
name,
|
|
122
|
+
(span): T =>
|
|
123
|
+
runThenSettle(
|
|
124
|
+
() => fn(span),
|
|
125
|
+
(error) => {
|
|
126
|
+
// On failure record the exception + ERROR status before ending, so a
|
|
127
|
+
// failed phase stays visible in the trace.
|
|
128
|
+
if (error !== undefined) {
|
|
129
|
+
if (error instanceof Error) {
|
|
130
|
+
span.recordException(error);
|
|
131
|
+
span.setStatus({ code: STATUS_ERROR, message: error.message });
|
|
132
|
+
} else {
|
|
133
|
+
span.setStatus({ code: STATUS_ERROR });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
span.end();
|
|
137
|
+
},
|
|
138
|
+
),
|
|
139
|
+
);
|
|
92
140
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (!stack || stack.length === 0) return undefined;
|
|
99
|
-
const span = stack.pop()!;
|
|
100
|
-
if (stack.length === 0) map.delete(key);
|
|
101
|
-
return span;
|
|
141
|
+
return {
|
|
142
|
+
runner,
|
|
143
|
+
enabled: options.enabled ?? true,
|
|
144
|
+
spans: options.spans,
|
|
145
|
+
};
|
|
102
146
|
}
|
|
103
147
|
|
|
104
148
|
// ---------------------------------------------------------------------------
|
|
105
|
-
//
|
|
149
|
+
// Telemetry sink: discrete-fact instant spans (the `telemetry` slot)
|
|
106
150
|
// ---------------------------------------------------------------------------
|
|
107
151
|
|
|
108
152
|
/**
|
|
109
|
-
* Create a TelemetrySink that maps router
|
|
153
|
+
* Create a TelemetrySink that maps the router's discrete-fact events to instant
|
|
154
|
+
* OTel spans. One span per fact; no duration spans.
|
|
155
|
+
*
|
|
156
|
+
* Fact mapping:
|
|
157
|
+
* - handler.error -> "rango.handler.error" (error)
|
|
158
|
+
* - cache.decision -> "rango.cache.decision"
|
|
159
|
+
* - revalidation.decision -> "rango.revalidation.decision"
|
|
160
|
+
* - request.timeout -> "rango.request.timeout" (error)
|
|
161
|
+
* - request.origin-rejected -> "rango.request.origin-rejected" (error)
|
|
110
162
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* - cache.decision → "rango.cache.decision" instant span
|
|
116
|
-
* - revalidation.decision → "rango.revalidation.decision" instant span
|
|
163
|
+
* Request and loader PHASE spans are intentionally NOT emitted here — they are
|
|
164
|
+
* owned by the tracing slot (createOTelTracing) so the two layers cannot produce
|
|
165
|
+
* duplicate rango.request / rango.loader spans. request.start/end and
|
|
166
|
+
* loader.start/end events are no-ops for this sink.
|
|
117
167
|
*
|
|
118
168
|
* Attributes use the `rango.*` namespace for router-specific data and
|
|
119
169
|
* `http.method` / `http.route` for HTTP semantics.
|
|
120
170
|
*/
|
|
121
171
|
export function createOTelSink(tracer: OTelTracer): TelemetrySink {
|
|
122
|
-
const
|
|
123
|
-
|
|
172
|
+
const instant = (
|
|
173
|
+
name: string,
|
|
174
|
+
attributes: Record<string, string | number | boolean>,
|
|
175
|
+
): OTelSpan => tracer.startSpan(name, { attributes });
|
|
124
176
|
|
|
125
177
|
return {
|
|
126
178
|
emit(event: TelemetryEvent): void {
|
|
127
179
|
switch (event.type) {
|
|
128
|
-
// -----------------------------------------------------------------
|
|
129
|
-
// Request lifecycle
|
|
130
|
-
// -----------------------------------------------------------------
|
|
131
|
-
|
|
132
|
-
case "request.start": {
|
|
133
|
-
const span = tracer.startSpan("rango.request", {
|
|
134
|
-
attributes: {
|
|
135
|
-
"http.method": event.method,
|
|
136
|
-
"http.route": event.pathname,
|
|
137
|
-
"rango.transaction": event.transaction,
|
|
138
|
-
"rango.is_partial": event.isPartial,
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
pushSpan(requestSpans, requestKey(event), span);
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
case "request.end": {
|
|
146
|
-
const span = popSpan(requestSpans, requestKey(event));
|
|
147
|
-
if (span) {
|
|
148
|
-
span.setAttribute("rango.duration_ms", event.durationMs);
|
|
149
|
-
span.setAttribute("rango.segment_count", event.segmentCount);
|
|
150
|
-
span.setAttribute("rango.cache.hit", event.cacheHit);
|
|
151
|
-
span.setStatus({ code: STATUS_OK });
|
|
152
|
-
span.end();
|
|
153
|
-
}
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
case "request.error": {
|
|
158
|
-
const span = popSpan(requestSpans, requestKey(event));
|
|
159
|
-
if (span) {
|
|
160
|
-
span.setAttribute("rango.duration_ms", event.durationMs);
|
|
161
|
-
span.setAttribute("rango.phase", event.phase);
|
|
162
|
-
span.recordException(event.error);
|
|
163
|
-
span.setStatus({
|
|
164
|
-
code: STATUS_ERROR,
|
|
165
|
-
message: event.error.message,
|
|
166
|
-
});
|
|
167
|
-
span.end();
|
|
168
|
-
}
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// -----------------------------------------------------------------
|
|
173
|
-
// Loader lifecycle
|
|
174
|
-
// -----------------------------------------------------------------
|
|
175
|
-
|
|
176
|
-
case "loader.start": {
|
|
177
|
-
const span = tracer.startSpan("rango.loader", {
|
|
178
|
-
attributes: {
|
|
179
|
-
"rango.segment_id": event.segmentId,
|
|
180
|
-
"rango.loader_name": event.loaderName,
|
|
181
|
-
"http.route": event.pathname,
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
pushSpan(loaderSpans, loaderKey(event), span);
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
case "loader.end": {
|
|
189
|
-
const key = loaderKey(event);
|
|
190
|
-
const span = popSpan(loaderSpans, key);
|
|
191
|
-
if (span) {
|
|
192
|
-
span.setAttribute("rango.duration_ms", event.durationMs);
|
|
193
|
-
span.setAttribute("rango.loader.ok", event.ok);
|
|
194
|
-
span.setStatus({ code: event.ok ? STATUS_OK : STATUS_ERROR });
|
|
195
|
-
span.end();
|
|
196
|
-
}
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
case "loader.error": {
|
|
201
|
-
const key = loaderKey(event);
|
|
202
|
-
const span = popSpan(loaderSpans, key);
|
|
203
|
-
if (span) {
|
|
204
|
-
span.setAttribute(
|
|
205
|
-
"rango.handled_by_boundary",
|
|
206
|
-
event.handledByBoundary,
|
|
207
|
-
);
|
|
208
|
-
span.recordException(event.error);
|
|
209
|
-
span.setStatus({
|
|
210
|
-
code: STATUS_ERROR,
|
|
211
|
-
message: event.error.message,
|
|
212
|
-
});
|
|
213
|
-
span.end();
|
|
214
|
-
} else {
|
|
215
|
-
// No matching start — create a standalone error span
|
|
216
|
-
const errorSpan = tracer.startSpan("rango.loader", {
|
|
217
|
-
attributes: {
|
|
218
|
-
"rango.segment_id": event.segmentId,
|
|
219
|
-
"rango.loader_name": event.loaderName,
|
|
220
|
-
"http.route": event.pathname,
|
|
221
|
-
"rango.handled_by_boundary": event.handledByBoundary,
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
errorSpan.recordException(event.error);
|
|
225
|
-
errorSpan.setStatus({
|
|
226
|
-
code: STATUS_ERROR,
|
|
227
|
-
message: event.error.message,
|
|
228
|
-
});
|
|
229
|
-
errorSpan.end();
|
|
230
|
-
}
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// -----------------------------------------------------------------
|
|
235
|
-
// Handler errors (instant span)
|
|
236
|
-
// -----------------------------------------------------------------
|
|
237
|
-
|
|
238
180
|
case "handler.error": {
|
|
239
181
|
const attrs: Record<string, string | number | boolean> = {
|
|
240
182
|
"rango.handled_by_boundary": event.handledByBoundary,
|
|
@@ -244,23 +186,16 @@ export function createOTelSink(tracer: OTelTracer): TelemetrySink {
|
|
|
244
186
|
attrs["rango.segment_type"] = event.segmentType;
|
|
245
187
|
if (event.pathname) attrs["http.route"] = event.pathname;
|
|
246
188
|
if (event.routeKey) attrs["rango.route_key"] = event.routeKey;
|
|
247
|
-
if (event.params)
|
|
189
|
+
if (event.params)
|
|
248
190
|
attrs["rango.params"] = JSON.stringify(event.params);
|
|
249
|
-
}
|
|
250
191
|
|
|
251
|
-
const span =
|
|
252
|
-
attributes: attrs,
|
|
253
|
-
});
|
|
192
|
+
const span = instant("rango.handler.error", attrs);
|
|
254
193
|
span.recordException(event.error);
|
|
255
194
|
span.setStatus({ code: STATUS_ERROR, message: event.error.message });
|
|
256
195
|
span.end();
|
|
257
196
|
break;
|
|
258
197
|
}
|
|
259
198
|
|
|
260
|
-
// -----------------------------------------------------------------
|
|
261
|
-
// Cache decision (instant span)
|
|
262
|
-
// -----------------------------------------------------------------
|
|
263
|
-
|
|
264
199
|
case "cache.decision": {
|
|
265
200
|
const attrs: Record<string, string | number | boolean> = {
|
|
266
201
|
"http.route": event.pathname,
|
|
@@ -269,30 +204,55 @@ export function createOTelSink(tracer: OTelTracer): TelemetrySink {
|
|
|
269
204
|
"rango.cache.should_revalidate": event.shouldRevalidate,
|
|
270
205
|
};
|
|
271
206
|
if (event.source) attrs["rango.cache.source"] = event.source;
|
|
207
|
+
instant("rango.cache.decision", attrs).end();
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
272
210
|
|
|
273
|
-
|
|
274
|
-
|
|
211
|
+
case "revalidation.decision": {
|
|
212
|
+
instant("rango.revalidation.decision", {
|
|
213
|
+
"rango.segment_id": event.segmentId,
|
|
214
|
+
"http.route": event.pathname,
|
|
215
|
+
"rango.route_key": event.routeKey,
|
|
216
|
+
"rango.revalidate": event.shouldRevalidate,
|
|
217
|
+
}).end();
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
case "request.timeout": {
|
|
222
|
+
const attrs: Record<string, string | number | boolean> = {
|
|
223
|
+
"rango.phase": event.phase,
|
|
224
|
+
"http.route": event.pathname,
|
|
225
|
+
"rango.duration_ms": event.durationMs,
|
|
226
|
+
"rango.timeout.custom_handler": event.customHandler,
|
|
227
|
+
};
|
|
228
|
+
if (event.routeKey) attrs["rango.route_key"] = event.routeKey;
|
|
229
|
+
if (event.actionId) attrs["rango.action_id"] = event.actionId;
|
|
230
|
+
const span = instant("rango.request.timeout", attrs);
|
|
231
|
+
span.setStatus({
|
|
232
|
+
code: STATUS_ERROR,
|
|
233
|
+
message: `timeout: ${event.phase}`,
|
|
275
234
|
});
|
|
276
235
|
span.end();
|
|
277
236
|
break;
|
|
278
237
|
}
|
|
279
238
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
"rango.revalidate": event.shouldRevalidate,
|
|
291
|
-
},
|
|
292
|
-
});
|
|
239
|
+
case "request.origin-rejected": {
|
|
240
|
+
const attrs: Record<string, string | number | boolean> = {
|
|
241
|
+
"http.method": event.method,
|
|
242
|
+
"http.route": event.pathname,
|
|
243
|
+
"rango.phase": event.phase,
|
|
244
|
+
};
|
|
245
|
+
if (event.origin) attrs["rango.origin"] = event.origin;
|
|
246
|
+
if (event.host) attrs["http.host"] = event.host;
|
|
247
|
+
const span = instant("rango.request.origin-rejected", attrs);
|
|
248
|
+
span.setStatus({ code: STATUS_ERROR, message: "origin rejected" });
|
|
293
249
|
span.end();
|
|
294
250
|
break;
|
|
295
251
|
}
|
|
252
|
+
|
|
253
|
+
// request.start/end/error and loader.start/end/error are phase events;
|
|
254
|
+
// their spans are owned by the tracing slot (createOTelTracing), so this
|
|
255
|
+
// sink ignores them to avoid duplicate rango.request / rango.loader spans.
|
|
296
256
|
}
|
|
297
257
|
},
|
|
298
258
|
};
|
package/src/router/telemetry.ts
CHANGED
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
* - revalidation.decision (revalidation evaluation)
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
// Event types
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
|
|
21
17
|
interface BaseEvent {
|
|
22
18
|
/** Monotonic timestamp from performance.now() */
|
|
23
19
|
timestamp: number;
|
|
@@ -42,6 +38,14 @@ export interface RequestEndEvent extends BaseEvent {
|
|
|
42
38
|
durationMs: number;
|
|
43
39
|
segmentCount: number;
|
|
44
40
|
cacheHit: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* HTTP status when a Response ended the transaction — a thrown-Response
|
|
43
|
+
* short-circuit (redirect / auth gate carries the Response's status, e.g. 302),
|
|
44
|
+
* or dispatch()'s final response status. Absent for a normal render completion:
|
|
45
|
+
* the Response is built after match(), so match()/matchPartial() have no status
|
|
46
|
+
* to stamp there. Lets a sink split 3xx short-circuits from 2xx completions.
|
|
47
|
+
*/
|
|
48
|
+
status?: number;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
export interface RequestErrorEvent extends BaseEvent {
|
|
@@ -239,10 +243,6 @@ export function formatCacheSignalHeader(
|
|
|
239
243
|
return segments.map((s) => `${s.id}=${s.cacheStatus}`).join(", ");
|
|
240
244
|
}
|
|
241
245
|
|
|
242
|
-
// ---------------------------------------------------------------------------
|
|
243
|
-
// Sink interface
|
|
244
|
-
// ---------------------------------------------------------------------------
|
|
245
|
-
|
|
246
246
|
/**
|
|
247
247
|
* Telemetry sink receives structured lifecycle events from the router.
|
|
248
248
|
* Implement this interface to integrate with any observability backend.
|
|
@@ -253,10 +253,6 @@ export interface TelemetrySink {
|
|
|
253
253
|
emit(event: TelemetryEvent): void;
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
// ---------------------------------------------------------------------------
|
|
257
|
-
// No-op singleton (zero-cost disabled state)
|
|
258
|
-
// ---------------------------------------------------------------------------
|
|
259
|
-
|
|
260
256
|
const noopSink: TelemetrySink = {
|
|
261
257
|
emit() {},
|
|
262
258
|
};
|
|
@@ -284,12 +280,6 @@ export function safeEmit(sink: TelemetrySink, event: TelemetryEvent): void {
|
|
|
284
280
|
}
|
|
285
281
|
}
|
|
286
282
|
|
|
287
|
-
// ---------------------------------------------------------------------------
|
|
288
|
-
// Request ID extraction (for span correlation)
|
|
289
|
-
// ---------------------------------------------------------------------------
|
|
290
|
-
|
|
291
|
-
// Per-request memoization so the same Request object always maps to the
|
|
292
|
-
// same ID. WeakMap allows GC when the Request is no longer referenced.
|
|
293
283
|
const requestIds = new WeakMap<Request, string>();
|
|
294
284
|
let telemetryRequestCounter = 0;
|
|
295
285
|
|
|
@@ -323,10 +313,6 @@ export function getRequestId(request: Request): string {
|
|
|
323
313
|
return id;
|
|
324
314
|
}
|
|
325
315
|
|
|
326
|
-
// ---------------------------------------------------------------------------
|
|
327
|
-
// Console sink (built-in, replaces ad-hoc console.log debug traces)
|
|
328
|
-
// ---------------------------------------------------------------------------
|
|
329
|
-
|
|
330
316
|
/**
|
|
331
317
|
* Built-in console sink that logs events in a structured format.
|
|
332
318
|
* Designed as the default sink for development / debugging.
|
|
@@ -342,7 +328,7 @@ export function createConsoleSink(): TelemetrySink {
|
|
|
342
328
|
break;
|
|
343
329
|
case "request.end":
|
|
344
330
|
console.log(
|
|
345
|
-
`[telemetry] ${event.type} ${event.method} ${event.pathname} ${event.durationMs.toFixed(1)}ms segments=${event.segmentCount} cache=${event.cacheHit}`,
|
|
331
|
+
`[telemetry] ${event.type} ${event.method} ${event.pathname} ${event.durationMs.toFixed(1)}ms segments=${event.segmentCount} cache=${event.cacheHit}${event.status !== undefined ? ` status=${event.status}` : ""}`,
|
|
346
332
|
);
|
|
347
333
|
break;
|
|
348
334
|
case "request.error":
|
package/src/router/timeout.ts
CHANGED
|
@@ -6,10 +6,6 @@
|
|
|
6
6
|
* a Promise.race mechanism, returning 504 on expiry.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
// Public types
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
|
|
13
9
|
export interface RouterTimeouts {
|
|
14
10
|
/** Timeout for server action execution (ms). */
|
|
15
11
|
actionMs?: number;
|
|
@@ -35,10 +31,6 @@ export type OnTimeoutCallback<TEnv = any> = (
|
|
|
35
31
|
ctx: TimeoutContext<TEnv>,
|
|
36
32
|
) => Response | Promise<Response>;
|
|
37
33
|
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
// Internal resolved form
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
|
|
42
34
|
export interface ResolvedTimeouts {
|
|
43
35
|
actionMs: number | undefined;
|
|
44
36
|
renderStartMs: number | undefined;
|
|
@@ -63,10 +55,6 @@ export function resolveTimeouts(
|
|
|
63
55
|
};
|
|
64
56
|
}
|
|
65
57
|
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
// Error class
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
|
|
70
58
|
export class RouterTimeoutError extends Error {
|
|
71
59
|
override name = "RouterTimeoutError" as const;
|
|
72
60
|
phase: TimeoutPhase;
|
|
@@ -81,10 +69,6 @@ export class RouterTimeoutError extends Error {
|
|
|
81
69
|
}
|
|
82
70
|
}
|
|
83
71
|
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
// Race helper
|
|
86
|
-
// ---------------------------------------------------------------------------
|
|
87
|
-
|
|
88
72
|
type TimeoutResult<T> =
|
|
89
73
|
| { result: T; timedOut: false }
|
|
90
74
|
| { timedOut: true; durationMs: number };
|
|
@@ -129,10 +113,6 @@ export async function withTimeout<T>(
|
|
|
129
113
|
}
|
|
130
114
|
}
|
|
131
115
|
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
// Default response
|
|
134
|
-
// ---------------------------------------------------------------------------
|
|
135
|
-
|
|
136
116
|
/**
|
|
137
117
|
* Create the default 504 response for a timed-out request.
|
|
138
118
|
* Includes `X-Rango-Timeout-Phase` header for observability.
|