@decocms/start 4.5.0 → 5.0.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/.cursor/skills/deco-edge-caching/SKILL.md +14 -10
- package/.github/workflows/release.yml +26 -2
- package/CHANGELOG.md +113 -0
- package/bun.lock +0 -67
- package/package.json +5 -10
- package/scripts/migrate-to-cf-observability.test.ts +63 -17
- package/scripts/migrate-to-cf-observability.ts +175 -87
- package/src/sdk/observability.ts +26 -18
- package/src/sdk/otel.test.ts +50 -71
- package/src/sdk/otel.ts +70 -295
- package/src/sdk/otelAdapters/clickhouseCollector.ts +65 -0
- package/src/sdk/otelAdapters.test.ts +11 -194
- package/src/sdk/otelAdapters.ts +18 -353
- package/src/sdk/workerEntry.ts +39 -21
- package/src/vite/plugin.js +55 -0
- package/src/vite/plugin.test.js +60 -1
- package/vitest.config.ts +1 -1
- package/src/sdk/sampler.test.ts +0 -165
- package/src/sdk/sampler.ts +0 -213
|
@@ -183,17 +183,21 @@ This is per-isolate in-memory cache (V8 Map). Resets on cold start. Includes req
|
|
|
183
183
|
|
|
184
184
|
## Cache Versioning with BUILD_HASH
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
186
|
+
Every cached entry's key is suffixed with `__v=<hash>` so a new deploy starts a fresh cache namespace and previously-cached HTML (which references now-deleted asset filenames like `/assets/main-XYZ.js`) stops being served the moment the new worker is live. Old entries become orphaned and expire naturally — no purge endpoint call required.
|
|
187
|
+
|
|
188
|
+
The hash is resolved automatically by `decoVitePlugin()` at build time and injected into the worker bundle as `__DECO_BUILD_HASH__`. Resolution order:
|
|
189
|
+
|
|
190
|
+
1. `WORKERS_CI_COMMIT_SHA` — Cloudflare Workers Builds default env var ([CF docs](https://developers.cloudflare.com/changelog/2025-06-10-default-env-vars/)). This is the production deploy path-of-record per `MIGRATION_TOOLING_PLAN.md` D6.3.
|
|
191
|
+
2. `git rev-parse --short=12 HEAD` — for someone running `wrangler deploy` from a developer laptop.
|
|
192
|
+
3. `Date.now().toString(36)` — last-resort fallback so the cache-bust invariant never silently regresses.
|
|
193
|
+
|
|
194
|
+
`createDecoWorkerEntry` reads `env.BUILD_HASH` first (explicit override path, e.g. `wrangler deploy --var BUILD_HASH:foo`) and falls back to the `__DECO_BUILD_HASH__` constant. Sites running `decoVitePlugin()` get the behaviour for free — **no per-site dashboard, `wrangler.jsonc`, or `--var` configuration required**.
|
|
195
195
|
|
|
196
|
-
The
|
|
196
|
+
The active version is exposed on every cached response via the `X-Cache-Version` header for observability. Confirm a new deploy is shipping the right hash with:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
curl -sI https://www.example.com/ | grep -i x-cache-version
|
|
200
|
+
```
|
|
197
201
|
|
|
198
202
|
## Site-Level Cache Pattern Registration
|
|
199
203
|
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
name: Release
|
|
2
2
|
|
|
3
|
+
# GOTCHA: GitHub Actions silently skips this workflow when the head
|
|
4
|
+
# commit message contains the canonical CI-skip token (the bracketed
|
|
5
|
+
# phrase "skip" + "ci") ANYWHERE in the message — title or body,
|
|
6
|
+
# inside backticks, inside code blocks, doesn't matter. The
|
|
7
|
+
# semantic-release release commit emits that token by design (so its
|
|
8
|
+
# own commit doesn't loop a release back through CI). Side effect:
|
|
9
|
+
# any PR that DESCRIBES that release commit verbatim in its body
|
|
10
|
+
# inherits the token through the squash-merge and silently skips
|
|
11
|
+
# the next release.
|
|
12
|
+
#
|
|
13
|
+
# When writing a commit message or PR body that needs to reference
|
|
14
|
+
# the suppression behaviour, refer to it descriptively (e.g. "the
|
|
15
|
+
# semantic-release skip token") instead of pasting the literal.
|
|
16
|
+
#
|
|
17
|
+
# Recover with a no-op commit whose entire message — title and body
|
|
18
|
+
# — does NOT contain the literal token.
|
|
19
|
+
#
|
|
20
|
+
# References:
|
|
21
|
+
# - https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs
|
|
22
|
+
|
|
3
23
|
on:
|
|
4
24
|
push:
|
|
5
25
|
branches: [main]
|
|
@@ -23,10 +43,14 @@ jobs:
|
|
|
23
43
|
node-version: 22
|
|
24
44
|
registry-url: https://registry.npmjs.org
|
|
25
45
|
|
|
26
|
-
-
|
|
46
|
+
- uses: oven-sh/setup-bun@v2
|
|
47
|
+
with:
|
|
48
|
+
bun-version: 1.3.5
|
|
49
|
+
|
|
50
|
+
- run: bun install --frozen-lockfile
|
|
27
51
|
|
|
28
52
|
- name: Release
|
|
29
|
-
run:
|
|
53
|
+
run: bunx semantic-release
|
|
30
54
|
env:
|
|
31
55
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
32
56
|
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@decocms/start` are documented here.
|
|
4
|
+
|
|
5
|
+
The project follows [Conventional Commits](https://www.conventionalcommits.org/)
|
|
6
|
+
and [semver](https://semver.org/). Releases are cut by semantic-release on
|
|
7
|
+
merges to `main`; this file is the human-curated breaking-change ledger.
|
|
8
|
+
For per-release auto-generated notes (every commit, every fix), see
|
|
9
|
+
[GitHub Releases](https://github.com/decocms/deco-start/releases).
|
|
10
|
+
|
|
11
|
+
## 5.0.0 — Drop in-Worker OTLP, converge on Cloudflare-native observability
|
|
12
|
+
|
|
13
|
+
### Breaking — Observability transport rewritten
|
|
14
|
+
|
|
15
|
+
- **In-Worker OTLP exporter for logs and metrics is gone.**
|
|
16
|
+
- Removed `createOtelLoggerAdapter()`, `createOtelMeterAdapter()`,
|
|
17
|
+
`OtelLoggerAdapterOptions`, `OtelMeterAdapterOptions`.
|
|
18
|
+
- Removed the per-request flush registry: `flushOtelProviders()`,
|
|
19
|
+
`registerOtelFlushHandler()`, `_resetFlushHandlersForTests()`,
|
|
20
|
+
`_getFlushHandlerCountForTests()`.
|
|
21
|
+
- **`URLBasedSampler` and the OTel sampler module are gone.**
|
|
22
|
+
- Removed `URLBasedSampler`, `decodeSamplingConfig`,
|
|
23
|
+
`createUrlBasedHeadSampler`, `SamplingConfig`, `SamplingRule`,
|
|
24
|
+
`DEFAULT_SAMPLE_RATIO`, and the entire `@decocms/start/sdk/sampler`
|
|
25
|
+
export. Use Cloudflare's `observability.traces.head_sampling_rate`
|
|
26
|
+
in `wrangler.jsonc` instead.
|
|
27
|
+
- **OTLP-related options on `instrumentWorker(handler, options)` are gone.**
|
|
28
|
+
- Removed: `enableAppSideOtlpLogs`, `otlpEndpoint`, `otlpHeaders`,
|
|
29
|
+
`otlpMinSeverity`, `samplingConfig`, `exportIntervalMillis`.
|
|
30
|
+
- Kept: `serviceName`, `analyticsEngineBindingName`,
|
|
31
|
+
`analyticsEngineEnabled`, `decoRuntimeVersion`, `decoAppsVersion`.
|
|
32
|
+
- Sites that previously read `OTEL_EXPORTER_OTLP_ENDPOINT`,
|
|
33
|
+
`OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_LOG_MIN_SEVERITY`, or
|
|
34
|
+
`OTEL_SAMPLING_CONFIG` should delete those secrets after deploying
|
|
35
|
+
against `5.0.0`:
|
|
36
|
+
```bash
|
|
37
|
+
wrangler secret delete OTEL_EXPORTER_OTLP_ENDPOINT \
|
|
38
|
+
OTEL_EXPORTER_OTLP_HEADERS \
|
|
39
|
+
OTEL_LOG_MIN_SEVERITY \
|
|
40
|
+
OTEL_SAMPLING_CONFIG
|
|
41
|
+
```
|
|
42
|
+
- **OpenTelemetry SDK dependencies dropped from `package.json`:**
|
|
43
|
+
`@opentelemetry/api-logs`, `@opentelemetry/exporter-logs-otlp-http`,
|
|
44
|
+
`@opentelemetry/exporter-metrics-otlp-http`, `@opentelemetry/resources`,
|
|
45
|
+
`@opentelemetry/sdk-logs`, `@opentelemetry/sdk-metrics`,
|
|
46
|
+
`@opentelemetry/sdk-trace-base`. Only `@opentelemetry/api` remains —
|
|
47
|
+
it is the bridge between `withTracing()` and the global tracer
|
|
48
|
+
Cloudflare's runtime exposes.
|
|
49
|
+
|
|
50
|
+
### Required `wrangler.jsonc` change
|
|
51
|
+
|
|
52
|
+
Sites must set `observability.enabled: true` at the top level of the
|
|
53
|
+
`observability` block — the master switch. Without it Cloudflare captures
|
|
54
|
+
nothing, regardless of the sub-block flags. Run the codemod to inject
|
|
55
|
+
the canonical block:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx -p @decocms/start deco-cf-observability --write
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The canonical block written by `5.0.0`:
|
|
62
|
+
|
|
63
|
+
```jsonc
|
|
64
|
+
"observability": {
|
|
65
|
+
"enabled": true,
|
|
66
|
+
"logs": { "enabled": true, "invocation_logs": true,
|
|
67
|
+
"head_sampling_rate": 1, "persist": true },
|
|
68
|
+
"traces": { "enabled": true,
|
|
69
|
+
"head_sampling_rate": 0.1, "persist": true }
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
External destinations (HyperDX, Datadog, etc.) are no longer wired by
|
|
74
|
+
default. Opt back in via `--destination-logs <slug>` /
|
|
75
|
+
`--destination-traces <slug>` if your site forwards to a destination
|
|
76
|
+
provisioned in the Cloudflare dashboard.
|
|
77
|
+
|
|
78
|
+
### Unchanged surface
|
|
79
|
+
|
|
80
|
+
The instrumentation API site code calls is unchanged:
|
|
81
|
+
|
|
82
|
+
- `instrumentWorker(handler, options)`
|
|
83
|
+
- `withTracing(name, fn, attrs)`, `getActiveSpan`, `setSpanAttribute`
|
|
84
|
+
- `recordRequestMetric`, `recordCacheMetric`, `MetricNames`
|
|
85
|
+
- `logger.{debug,info,warn,error}`, `serializeError`, `LoggerAdapter`,
|
|
86
|
+
`setLoggerAttributeFloor`
|
|
87
|
+
- `createCompositeLogger`, `createCompositeMeter`
|
|
88
|
+
- `createAnalyticsEngineMeterAdapter`, `setRuntimeEnv`, `getRuntimeEnv`
|
|
89
|
+
|
|
90
|
+
The `deco.runtime.version`, `deco.apps.version`, and
|
|
91
|
+
`deployment.environment` attribute floor that landed in 4.5.x stays —
|
|
92
|
+
stamped on every span and every log record so dashboards keep working
|
|
93
|
+
under Cloudflare's platform-managed export.
|
|
94
|
+
|
|
95
|
+
### Future (not in 5.0.0)
|
|
96
|
+
|
|
97
|
+
`@decocms/start/sdk/otelAdapters/clickhouseCollector` ships as a
|
|
98
|
+
**documented stub that throws**. When the platform-side OTel collector
|
|
99
|
+
gateway lands (forwarding to ClickHouse), the real OTLP/HTTP exporter
|
|
100
|
+
implementation goes here — composed alongside the AE meter for
|
|
101
|
+
dual-emit. The `OtelOptions` shape will gain a single
|
|
102
|
+
`clickhouseCollector?: ClickhouseCollectorOptions` field at that point.
|
|
103
|
+
|
|
104
|
+
### Migration checklist for site maintainers
|
|
105
|
+
|
|
106
|
+
1. Bump `@decocms/start` to `^5.0.0`.
|
|
107
|
+
2. `npx -p @decocms/start deco-cf-observability --write`
|
|
108
|
+
3. `wrangler deploy`
|
|
109
|
+
4. Verify CF dashboard captures logs + traces (~5 min):
|
|
110
|
+
Workers & Pages → `<site>` → Observability
|
|
111
|
+
5. `wrangler secret delete OTEL_EXPORTER_OTLP_ENDPOINT
|
|
112
|
+
OTEL_EXPORTER_OTLP_HEADERS OTEL_LOG_MIN_SEVERITY
|
|
113
|
+
OTEL_SAMPLING_CONFIG`
|
package/bun.lock
CHANGED
|
@@ -7,13 +7,6 @@
|
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@deco-cx/warp-node": "^0.3.16",
|
|
9
9
|
"@opentelemetry/api": "^1.9.1",
|
|
10
|
-
"@opentelemetry/api-logs": "^0.200.0",
|
|
11
|
-
"@opentelemetry/exporter-logs-otlp-http": "^0.200.0",
|
|
12
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.200.0",
|
|
13
|
-
"@opentelemetry/resources": "^2.6.1",
|
|
14
|
-
"@opentelemetry/sdk-logs": "^0.200.0",
|
|
15
|
-
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
16
|
-
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
|
17
10
|
"clsx": "^2.1.1",
|
|
18
11
|
"fast-json-patch": "^3.1.0",
|
|
19
12
|
"tailwind-merge": "^3.3.1",
|
|
@@ -245,28 +238,6 @@
|
|
|
245
238
|
|
|
246
239
|
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
|
247
240
|
|
|
248
|
-
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q=="],
|
|
249
|
-
|
|
250
|
-
"@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
|
|
251
|
-
|
|
252
|
-
"@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-KfWw49htbGGp9s8N4KI8EQ9XuqKJ0VG+yVYVYFiCYSjEV32qpQ5qZ9UZBzOZ6xRb+E16SXOSCT3RkqBVSABZ+g=="],
|
|
253
|
-
|
|
254
|
-
"@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw=="],
|
|
255
|
-
|
|
256
|
-
"@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
|
|
257
|
-
|
|
258
|
-
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
|
|
259
|
-
|
|
260
|
-
"@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="],
|
|
261
|
-
|
|
262
|
-
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-VZG870063NLfObmQQNtCVcdXXLzI3vOjjrRENmU37HYiPFa0ZXpXVDsTD02Nh3AT3xYJzQaWKl2X2lQ2l7TWJA=="],
|
|
263
|
-
|
|
264
|
-
"@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
|
|
265
|
-
|
|
266
|
-
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw=="],
|
|
267
|
-
|
|
268
|
-
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.40.0", "", {}, "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw=="],
|
|
269
|
-
|
|
270
241
|
"@oxc-project/types": ["@oxc-project/types@0.120.0", "", {}, "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg=="],
|
|
271
242
|
|
|
272
243
|
"@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="],
|
|
@@ -315,26 +286,6 @@
|
|
|
315
286
|
|
|
316
287
|
"@pnpm/npm-conf": ["@pnpm/npm-conf@3.0.2", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA=="],
|
|
317
288
|
|
|
318
|
-
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
|
|
319
|
-
|
|
320
|
-
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
|
|
321
|
-
|
|
322
|
-
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
|
|
323
|
-
|
|
324
|
-
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
|
|
325
|
-
|
|
326
|
-
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
|
|
327
|
-
|
|
328
|
-
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
|
|
329
|
-
|
|
330
|
-
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
|
|
331
|
-
|
|
332
|
-
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
|
|
333
|
-
|
|
334
|
-
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
|
|
335
|
-
|
|
336
|
-
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
|
|
337
|
-
|
|
338
289
|
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.10", "", { "os": "android", "cpu": "arm64" }, "sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg=="],
|
|
339
290
|
|
|
340
291
|
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w=="],
|
|
@@ -827,8 +778,6 @@
|
|
|
827
778
|
|
|
828
779
|
"lodash.uniqby": ["lodash.uniqby@4.7.0", "", {}, "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww=="],
|
|
829
780
|
|
|
830
|
-
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
|
|
831
|
-
|
|
832
781
|
"lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="],
|
|
833
782
|
|
|
834
783
|
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
|
@@ -951,8 +900,6 @@
|
|
|
951
900
|
|
|
952
901
|
"proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="],
|
|
953
902
|
|
|
954
|
-
"protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
|
|
955
|
-
|
|
956
903
|
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
|
957
904
|
|
|
958
905
|
"queue-microtask": ["queue-microtask@1.2.3", "", {}, ""],
|
|
@@ -1215,20 +1162,6 @@
|
|
|
1215
1162
|
|
|
1216
1163
|
"@deco-cx/warp-node/undici": ["undici@6.23.0", "", {}, "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g=="],
|
|
1217
1164
|
|
|
1218
|
-
"@opentelemetry/exporter-metrics-otlp-http/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
|
|
1219
|
-
|
|
1220
|
-
"@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
|
|
1221
|
-
|
|
1222
|
-
"@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw=="],
|
|
1223
|
-
|
|
1224
|
-
"@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.6.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="],
|
|
1225
|
-
|
|
1226
|
-
"@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
|
|
1227
|
-
|
|
1228
|
-
"@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
|
|
1229
|
-
|
|
1230
|
-
"@opentelemetry/sdk-trace-base/@opentelemetry/core": ["@opentelemetry/core@2.6.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="],
|
|
1231
|
-
|
|
1232
1165
|
"@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="],
|
|
1233
1166
|
|
|
1234
1167
|
"@semantic-release/git/@semantic-release/error": ["@semantic-release/error@3.0.0", "", {}, "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw=="],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/start",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"./sdk/logger": "./src/sdk/logger.ts",
|
|
40
40
|
"./sdk/composite": "./src/sdk/composite.ts",
|
|
41
41
|
"./sdk/otelAdapters": "./src/sdk/otelAdapters.ts",
|
|
42
|
-
"./sdk/
|
|
42
|
+
"./sdk/otelAdapters/clickhouseCollector": "./src/sdk/otelAdapters/clickhouseCollector.ts",
|
|
43
43
|
"./sdk/observability": "./src/sdk/observability.ts",
|
|
44
44
|
"./sdk/workerEntry": "./src/sdk/workerEntry.ts",
|
|
45
45
|
"./sdk/abTesting": "./src/sdk/abTesting.ts",
|
|
@@ -86,7 +86,8 @@
|
|
|
86
86
|
"lint:unused": "knip",
|
|
87
87
|
"format": "biome format src/ scripts/",
|
|
88
88
|
"format:fix": "biome format --write src/ scripts/",
|
|
89
|
-
"check": "
|
|
89
|
+
"check": "bun run typecheck && bun run lint && bun run lint:unused",
|
|
90
|
+
"clean": "rm -rf node_modules .cache dist .wrangler/state node_modules/.vite && bun install"
|
|
90
91
|
},
|
|
91
92
|
"keywords": [
|
|
92
93
|
"deco",
|
|
@@ -96,6 +97,7 @@
|
|
|
96
97
|
],
|
|
97
98
|
"author": "deco.cx",
|
|
98
99
|
"license": "MIT",
|
|
100
|
+
"packageManager": "bun@1.3.5",
|
|
99
101
|
"repository": {
|
|
100
102
|
"type": "git",
|
|
101
103
|
"url": "https://github.com/decocms/deco-start.git"
|
|
@@ -107,13 +109,6 @@
|
|
|
107
109
|
"dependencies": {
|
|
108
110
|
"@deco-cx/warp-node": "^0.3.16",
|
|
109
111
|
"@opentelemetry/api": "^1.9.1",
|
|
110
|
-
"@opentelemetry/api-logs": "^0.200.0",
|
|
111
|
-
"@opentelemetry/exporter-logs-otlp-http": "^0.200.0",
|
|
112
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.200.0",
|
|
113
|
-
"@opentelemetry/resources": "^2.6.1",
|
|
114
|
-
"@opentelemetry/sdk-logs": "^0.200.0",
|
|
115
|
-
"@opentelemetry/sdk-metrics": "^2.0.0",
|
|
116
|
-
"@opentelemetry/sdk-trace-base": "^2.6.1",
|
|
117
112
|
"clsx": "^2.1.1",
|
|
118
113
|
"fast-json-patch": "^3.1.0",
|
|
119
114
|
"tailwind-merge": "^3.3.1",
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
* Smoke tests for the `migrate-to-cf-observability.ts` codemod.
|
|
3
3
|
*
|
|
4
4
|
* Drives the script as a child process against tmp wrangler.jsonc fixtures.
|
|
5
|
-
* Verifies the
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
5
|
+
* Verifies the operationally important behaviors:
|
|
6
|
+
* - rewriting an existing observability block to the canonical CF-native
|
|
7
|
+
* shape (no destinations, master enabled flag set)
|
|
8
|
+
* - appending a new canonical block when none exists
|
|
8
9
|
* - second run is a no-op (idempotency / CI guard)
|
|
10
|
+
* - HyperDX-style destinations are stripped on the next run
|
|
11
|
+
* - opt-in destination forwarding via `--destination-logs` /
|
|
12
|
+
* `--destination-traces`
|
|
9
13
|
* - result is valid JSONC (parses after stripping comments)
|
|
10
14
|
*/
|
|
11
15
|
import * as cp from "node:child_process";
|
|
@@ -38,7 +42,7 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
38
42
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
39
43
|
});
|
|
40
44
|
|
|
41
|
-
it("
|
|
45
|
+
it("rewrites a partial observability block to the canonical CF-native shape", () => {
|
|
42
46
|
fs.writeFileSync(
|
|
43
47
|
wranglerPath,
|
|
44
48
|
`{
|
|
@@ -64,19 +68,58 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
64
68
|
expect(r.code).toBe(0);
|
|
65
69
|
|
|
66
70
|
const result = fs.readFileSync(wranglerPath, "utf8");
|
|
67
|
-
|
|
68
|
-
expect(result).toContain('"
|
|
71
|
+
// Master switch present.
|
|
72
|
+
expect(result).toContain('"enabled": true');
|
|
73
|
+
// Both leaves present with rates and persist.
|
|
74
|
+
expect(result).toContain('"head_sampling_rate": 1');
|
|
69
75
|
expect(result).toContain('"head_sampling_rate": 0.1');
|
|
70
|
-
|
|
76
|
+
expect(result.match(/"persist": true/g)?.length).toBe(2);
|
|
77
|
+
// No destinations by default.
|
|
78
|
+
expect(result).not.toContain('"destinations"');
|
|
79
|
+
// Original keys preserved.
|
|
80
|
+
expect(result).toContain('"name": "lebiscuit-tanstack"');
|
|
81
|
+
expect(result).toContain('"binding": "DECO_METRICS"');
|
|
71
82
|
// Result must be valid JSONC.
|
|
72
83
|
expect(() => JSON.parse(stripJsoncComments(result))).not.toThrow();
|
|
84
|
+
});
|
|
73
85
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
it("strips stale HyperDX-style destinations from a config that already has them", () => {
|
|
87
|
+
fs.writeFileSync(
|
|
88
|
+
wranglerPath,
|
|
89
|
+
`{
|
|
90
|
+
"name": "lebiscuit-tanstack",
|
|
91
|
+
"main": "./src/worker-entry.ts",
|
|
92
|
+
"observability": {
|
|
93
|
+
"enabled": true,
|
|
94
|
+
"logs": {
|
|
95
|
+
"enabled": true,
|
|
96
|
+
"invocation_logs": true,
|
|
97
|
+
"head_sampling_rate": 1,
|
|
98
|
+
"persist": true,
|
|
99
|
+
"destinations": ["hyperdx-logs"]
|
|
100
|
+
},
|
|
101
|
+
"traces": {
|
|
102
|
+
"enabled": true,
|
|
103
|
+
"head_sampling_rate": 0.1,
|
|
104
|
+
"persist": true,
|
|
105
|
+
"destinations": ["hyperdx-traces"]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
`,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const r = runCodemod(["--source", tmpDir, "--write"]);
|
|
113
|
+
expect(r.code).toBe(0);
|
|
114
|
+
|
|
115
|
+
const result = fs.readFileSync(wranglerPath, "utf8");
|
|
116
|
+
expect(result).not.toContain("hyperdx-logs");
|
|
117
|
+
expect(result).not.toContain("hyperdx-traces");
|
|
118
|
+
expect(result).not.toContain('"destinations"');
|
|
119
|
+
expect(() => JSON.parse(stripJsoncComments(result))).not.toThrow();
|
|
77
120
|
});
|
|
78
121
|
|
|
79
|
-
it("appends a
|
|
122
|
+
it("appends a canonical observability block when none exists", () => {
|
|
80
123
|
fs.writeFileSync(
|
|
81
124
|
wranglerPath,
|
|
82
125
|
`{
|
|
@@ -92,7 +135,10 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
92
135
|
|
|
93
136
|
const result = fs.readFileSync(wranglerPath, "utf8");
|
|
94
137
|
expect(result).toContain('"observability"');
|
|
95
|
-
expect(result).toContain('"
|
|
138
|
+
expect(result).toContain('"enabled": true');
|
|
139
|
+
expect(result).toContain('"head_sampling_rate": 1');
|
|
140
|
+
expect(result).toContain('"head_sampling_rate": 0.1');
|
|
141
|
+
expect(result).not.toContain('"destinations"');
|
|
96
142
|
expect(() => JSON.parse(stripJsoncComments(result))).not.toThrow();
|
|
97
143
|
});
|
|
98
144
|
|
|
@@ -114,7 +160,7 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
114
160
|
|
|
115
161
|
const r = runCodemod(["--source", tmpDir, "--write"]);
|
|
116
162
|
expect(r.code).toBe(0);
|
|
117
|
-
expect(r.stdout).toContain("already on CF
|
|
163
|
+
expect(r.stdout).toContain("already on the canonical CF observability block");
|
|
118
164
|
|
|
119
165
|
const after2 = fs.readFileSync(wranglerPath, "utf8");
|
|
120
166
|
expect(after2).toBe(after1);
|
|
@@ -135,7 +181,7 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
135
181
|
expect(fs.readFileSync(wranglerPath, "utf8")).toBe(before);
|
|
136
182
|
});
|
|
137
183
|
|
|
138
|
-
it("respects --logs / --traces / --traces-rate / --persist flags", () => {
|
|
184
|
+
it("respects --destination-logs / --destination-traces / --traces-rate / --persist flags", () => {
|
|
139
185
|
fs.writeFileSync(
|
|
140
186
|
wranglerPath,
|
|
141
187
|
`{
|
|
@@ -148,9 +194,9 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
148
194
|
runCodemod([
|
|
149
195
|
"--source",
|
|
150
196
|
tmpDir,
|
|
151
|
-
"--logs",
|
|
197
|
+
"--destination-logs",
|
|
152
198
|
"my-logs",
|
|
153
|
-
"--traces",
|
|
199
|
+
"--destination-traces",
|
|
154
200
|
"my-traces",
|
|
155
201
|
"--traces-rate",
|
|
156
202
|
"0.05",
|
|
@@ -162,7 +208,7 @@ describe("migrate-to-cf-observability codemod", () => {
|
|
|
162
208
|
expect(result).toContain('"destinations": ["my-logs"]');
|
|
163
209
|
expect(result).toContain('"destinations": ["my-traces"]');
|
|
164
210
|
expect(result).toContain('"head_sampling_rate": 0.05');
|
|
165
|
-
// Both blocks set persist:true
|
|
211
|
+
// Both blocks set persist:true.
|
|
166
212
|
const persistTrueCount = (result.match(/"persist": true/g) ?? []).length;
|
|
167
213
|
expect(persistTrueCount).toBe(2);
|
|
168
214
|
});
|