@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 +14 -1
- package/src/sdk/otel.ts +104 -0
- package/src/sdk/workerEntry.ts +4 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/start",
|
|
3
|
-
"version": "0.
|
|
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",
|
package/src/sdk/otel.ts
ADDED
|
@@ -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
|
+
}
|
package/src/sdk/workerEntry.ts
CHANGED
|
@@ -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
|
-
|
|
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>,
|