@decocms/start 0.42.3 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/start",
3
- "version": "0.42.3",
3
+ "version": "0.43.0",
4
4
  "type": "module",
5
5
  "description": "Deco framework for TanStack Start - CMS bridge, admin protocol, hooks, schema generation",
6
6
  "main": "./src/index.ts",
@@ -27,6 +27,7 @@
27
27
  "./sdk/crypto": "./src/sdk/crypto.ts",
28
28
  "./sdk/invoke": "./src/sdk/invoke.ts",
29
29
  "./sdk/instrumentedFetch": "./src/sdk/instrumentedFetch.ts",
30
+ "./sdk/otel": "./src/sdk/otel.ts",
30
31
  "./sdk/workerEntry": "./src/sdk/workerEntry.ts",
31
32
  "./sdk/redirects": "./src/sdk/redirects.ts",
32
33
  "./sdk/sitemap": "./src/sdk/sitemap.ts",
@@ -87,14 +88,26 @@
87
88
  "tsx": "^4.19.0"
88
89
  },
89
90
  "peerDependencies": {
91
+ "@microlabs/otel-cf-workers": ">=1.0.0-rc.0",
92
+ "@opentelemetry/api": ">=1.9.0",
90
93
  "@tanstack/react-start": ">=1.0.0",
91
94
  "@tanstack/store": ">=0.7.0",
92
95
  "react": "^19.0.0",
93
96
  "react-dom": "^19.0.0",
94
97
  "vite": ">=6.0.0 || >=7.0.0 || >=8.0.0"
95
98
  },
99
+ "peerDependenciesMeta": {
100
+ "@microlabs/otel-cf-workers": {
101
+ "optional": true
102
+ },
103
+ "@opentelemetry/api": {
104
+ "optional": true
105
+ }
106
+ },
96
107
  "devDependencies": {
97
108
  "@biomejs/biome": "^2.4.6",
109
+ "@microlabs/otel-cf-workers": "^1.0.0-rc.52",
110
+ "@opentelemetry/api": "^1.9.1",
98
111
  "@semantic-release/exec": "^7.1.0",
99
112
  "@semantic-release/git": "^10.0.1",
100
113
  "@tanstack/store": "^0.9.1",
@@ -0,0 +1,104 @@
1
+ /**
2
+ * OpenTelemetry integration for Cloudflare Workers via @microlabs/otel-cf-workers.
3
+ *
4
+ * Opt-in module that wraps a Worker handler with auto-instrumentation and
5
+ * wires traces into @decocms/start's pluggable TracerAdapter.
6
+ *
7
+ * Requires peer dependencies:
8
+ * - `@microlabs/otel-cf-workers`
9
+ * - `@opentelemetry/api`
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createDecoWorkerEntry } from "@decocms/start/sdk/workerEntry";
14
+ * import { instrumentWorker } from "@decocms/start/sdk/otel";
15
+ *
16
+ * const handler = createDecoWorkerEntry(serverEntry, options);
17
+ *
18
+ * export default instrumentWorker(handler, { serviceName: "my-store" });
19
+ * ```
20
+ *
21
+ * Environment variables (read from `env` at request time):
22
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT` — OTLP endpoint (e.g. `https://in-otel.hyperdx.io`)
23
+ * - `OTEL_EXPORTER_OTLP_HEADERS` — comma-separated `key=value` auth headers
24
+ */
25
+
26
+ import { instrument, type ResolveConfigFn } from "@microlabs/otel-cf-workers";
27
+ import { trace } from "@opentelemetry/api";
28
+ import { configureTracer } from "../middleware/observability";
29
+
30
+ export interface OtelOptions {
31
+ serviceName: string;
32
+ /** OTLP endpoint. Defaults to env.OTEL_EXPORTER_OTLP_ENDPOINT. */
33
+ endpoint?: string;
34
+ /** OTLP auth headers. Defaults to env.OTEL_EXPORTER_OTLP_HEADERS parsed. */
35
+ headers?: Record<string, string>;
36
+ }
37
+
38
+ /** Minimal Cloudflare Worker execution context. */
39
+ interface WorkerExecutionContext {
40
+ waitUntil(promise: Promise<unknown>): void;
41
+ passThroughOnException(): void;
42
+ }
43
+
44
+ /** Handler shape returned by createDecoWorkerEntry. */
45
+ interface WorkerHandler {
46
+ fetch(
47
+ request: Request,
48
+ env: Record<string, unknown>,
49
+ ctx: WorkerExecutionContext,
50
+ ): Promise<Response>;
51
+ }
52
+
53
+ /**
54
+ * Wraps a Cloudflare Worker handler with OpenTelemetry auto-instrumentation
55
+ * (fetch, KV, D1, waitUntil) and connects to @decocms/start's TracerAdapter
56
+ * so that `withTracing()` / `createInstrumentedFetch()` emit real OTel spans.
57
+ */
58
+ export function instrumentWorker(
59
+ handler: WorkerHandler,
60
+ options: OtelOptions | ((env: Record<string, unknown>) => OtelOptions),
61
+ ) {
62
+ // Bridge @decocms/start TracerAdapter → @opentelemetry/api
63
+ configureTracer({
64
+ startSpan: (name, attrs) => {
65
+ const span = trace.getTracer("deco").startSpan(name, { attributes: attrs });
66
+ return {
67
+ end: () => span.end(),
68
+ setError: (error) => {
69
+ if (error instanceof Error) span.recordException(error);
70
+ },
71
+ setAttribute: (k, v) => span.setAttribute(k, v),
72
+ };
73
+ },
74
+ });
75
+
76
+ const resolveConfig: ResolveConfigFn = (env, _trigger) => {
77
+ const opts = typeof options === "function" ? options(env as Record<string, unknown>) : options;
78
+ const endpoint = opts.endpoint || (env.OTEL_EXPORTER_OTLP_ENDPOINT as string);
79
+ const headers = opts.headers || parseHeaders(env.OTEL_EXPORTER_OTLP_HEADERS as string | undefined);
80
+
81
+ return {
82
+ exporter: { url: endpoint, headers },
83
+ service: { name: opts.serviceName },
84
+ };
85
+ };
86
+
87
+ // Cast through `any` — @microlabs/otel-cf-workers expects Cloudflare's
88
+ // ExportedHandler type, but we avoid depending on @cloudflare/workers-types.
89
+ // deno-lint-ignore no-explicit-any
90
+ return instrument(handler as any, resolveConfig);
91
+ }
92
+
93
+ function parseHeaders(str?: string): Record<string, string> {
94
+ if (!str) return {};
95
+ return Object.fromEntries(
96
+ str
97
+ .split(",")
98
+ .map((kv) => {
99
+ const [k, ...v] = kv.split("=");
100
+ return [k.trim(), v.join("=").trim()] as const;
101
+ })
102
+ .filter(([k]) => k.length > 0),
103
+ );
104
+ }
@@ -256,6 +256,7 @@ export interface DecoWorkerEntryOptions {
256
256
  * ```
257
257
  */
258
258
  cacheVersionEnv?: string | false;
259
+
259
260
  }
260
261
 
261
262
  // ---------------------------------------------------------------------------
@@ -652,7 +653,7 @@ export function createDecoWorkerEntry(
652
653
 
653
654
  // -- Main fetch handler -----------------------------------------------------
654
655
 
655
- return {
656
+ const handler = {
656
657
  async fetch(
657
658
  request: Request,
658
659
  env: Record<string, unknown>,
@@ -673,6 +674,8 @@ export function createDecoWorkerEntry(
673
674
  },
674
675
  };
675
676
 
677
+ return handler;
678
+
676
679
  async function handleRequest(
677
680
  request: Request,
678
681
  env: Record<string, unknown>,