@cross-deck/node 0.1.0 → 1.1.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/CHANGELOG.md +139 -0
- package/README.md +406 -124
- package/dist/auto-events/index.cjs +354 -0
- package/dist/auto-events/index.cjs.map +1 -0
- package/dist/auto-events/index.d.mts +316 -0
- package/dist/auto-events/index.d.ts +316 -0
- package/dist/auto-events/index.mjs +322 -0
- package/dist/auto-events/index.mjs.map +1 -0
- package/dist/crossdeck-server-BXQaFjVx.d.mts +1414 -0
- package/dist/crossdeck-server-BXQaFjVx.d.ts +1414 -0
- package/dist/index.cjs +3069 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +339 -178
- package/dist/index.d.ts +339 -178
- package/dist/index.mjs +3054 -180
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,145 @@ All notable changes to `@cross-deck/node` will be documented here. The
|
|
|
4
4
|
format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.1.0] — 2026-05-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Auto-heartbeat on construction.** `new CrossdeckServer({...})` now
|
|
12
|
+
fires a heartbeat in the background the moment the SDK is
|
|
13
|
+
constructed, fire-and-forget. The dashboard's row flips LIVE within
|
|
14
|
+
~200 ms of the customer's process boot — no explicit `.heartbeat()`
|
|
15
|
+
call required in the bootstrap. Solves the cold-start serverless
|
|
16
|
+
verification problem at its root (function boot triggers SDK
|
|
17
|
+
construction triggers heartbeat; the install-verifier's URL probe
|
|
18
|
+
doubles as a cold-start waker).
|
|
19
|
+
- New option `bootHeartbeat?: boolean` (default `true`). Set `false`
|
|
20
|
+
for latency-sensitive cold paths that want the prior v1.0.0
|
|
21
|
+
caller-controlled behaviour. Implicitly disabled in `testMode`.
|
|
22
|
+
|
|
23
|
+
### Why this is non-breaking
|
|
24
|
+
|
|
25
|
+
The boot heartbeat is fire-and-forget and swallows its own errors —
|
|
26
|
+
the caller's code never blocks on it, never throws, and a failure
|
|
27
|
+
(bad key, network blip, firewall) has zero effect on subsequent
|
|
28
|
+
event flushes. Equivalent to Sentry's `Sentry.init()` boot session.
|
|
29
|
+
|
|
30
|
+
## [1.0.0] — 2026-05-13
|
|
31
|
+
|
|
32
|
+
Full three-USP server SDK release. Version-aligned with `@cross-deck/web@1.0.0`. Bank-grade quality bar — Stripe + Apple + Google VP-level QA review across two passes. 6,796 LOC of source / 6,230 LOC of tests / 398 unit tests + 19 e2e todos passing / Gate 3 fixture verifying the snippet against the built bundle. Web-SDK parity at the capability level: every Web SDK guarantee that has a server-side analogue ships here.
|
|
33
|
+
|
|
34
|
+
### Added — USP 1 (errors)
|
|
35
|
+
|
|
36
|
+
- `server.captureError(err, options?)` — manual try/catch capture.
|
|
37
|
+
- `server.captureMessage(msg, level?)` — non-error signals (Sentry pattern).
|
|
38
|
+
- `server.setTag(key, value)` / `setTags(tags)` / `setContext(name, data)` / `addBreadcrumb(crumb)` / `setErrorBeforeSend(hook)`.
|
|
39
|
+
- Auto-wired `process.on('uncaughtException')` + `process.on('unhandledRejection')` + `globalThis.fetch` wrap (5xx + network failures).
|
|
40
|
+
- Stack-frame parsing (V8 + Firefox/Safari) with Node `in_app` heuristics for `node_modules/`, `node:`, `internal/`, `@cross-deck/node`.
|
|
41
|
+
- Breadcrumb ring buffer (default 50 entries) attached to every error report.
|
|
42
|
+
- djb2-fingerprinted grouping + per-fingerprint rate limit (default 5/min) + per-session cap (default 100). Fingerprint Map bounded at 4,096 with dead-entry prune + FIFO eviction.
|
|
43
|
+
|
|
44
|
+
### Added — USP 2 (analytics)
|
|
45
|
+
|
|
46
|
+
- Durable event queue: exponential backoff with full jitter, `Retry-After` honoured, **`Idempotency-Key` reused on retry of the same batch** (Stripe pattern).
|
|
47
|
+
- `flush-on-exit` — `process.on('beforeExit')` + SIGTERM + SIGINT drain bounded by `flushOnExitTimeoutMs`. Critical for Lambda / Cloud Functions where the runtime freezes between invocations.
|
|
48
|
+
- `server.register(properties)` / `server.unregister(key)` / `server.group(type, id, traits?)` — Mixpanel-style super-properties + group analytics.
|
|
49
|
+
- `@cross-deck/node/auto-events` subpath:
|
|
50
|
+
- `crossdeckExpress(server, opts?)` + `crossdeckExpressErrorHandler(server, opts?)` (Express 4 + 5) — emits `request.handled` with route + method + statusCode + durationMs + userAgent + responseBytes. Captures uncaught route errors with request context.
|
|
51
|
+
- `wrapLambdaHandler(server, handler, opts?)` — emits `function.invoked` / `function.completed` / `function.failed` with cold-start detection, awaits `flush()` before return. Extracts `statusCode` + `responseBytes` for HTTP-style returns.
|
|
52
|
+
- `wrapFunction(server, handler, opts?)` — generic Firebase v1/v2 / Cloud Run wrap, shape-preserving.
|
|
53
|
+
|
|
54
|
+
### Added — USP 3 (entitlements)
|
|
55
|
+
|
|
56
|
+
- Per-customer TTL cache (default 60s) with **LRU eviction bounded at `maxCustomers` (default 10,000)** for long-running multi-tenant servers.
|
|
57
|
+
- `server.isEntitled(hint, key)` — synchronous lookup after first warm. Accepts canonical `customerId` OR `IdentityHints` ({customerId, userId, anonymousId}).
|
|
58
|
+
- `server.listEntitlements(hint)` — full snapshot.
|
|
59
|
+
- `server.onEntitlementsChange(listener)` — subscribe to cache mutations.
|
|
60
|
+
- `userId` / `anonymousId` → `crossdeckCustomerId` alias map (bounded at 10,000 with FIFO eviction).
|
|
61
|
+
- `verifyWebhookSignature(payload, header, secret, options?)` — HMAC-SHA256 + constant-time compare + 5-min replay window + multi-secret rotation.
|
|
62
|
+
- `signWebhookPayload(payload, secret, timestampSec)` — pure helper for fixture authors.
|
|
63
|
+
|
|
64
|
+
### Added — cross-cutting
|
|
65
|
+
|
|
66
|
+
- `runtime-info` detection for 13 platforms: AWS Lambda, Azure Functions, Google App Engine, Firebase Functions v1/v2, Cloud Run, Vercel, Netlify, Heroku, Render, Railway, Fly.io, generic Kubernetes, plain Node fallback. Auto-attached as `runtime.*` on every event + error.
|
|
67
|
+
- `server.heartbeat()` — boot validation: `GET /sdk/heartbeat` returns project + app metadata, throws on auth failure.
|
|
68
|
+
- `server.flush(): Promise<void>` — explicit drain.
|
|
69
|
+
- `server.diagnostics()` — stable shape with `runtime` + `events` + `errors` + `entitlements` blocks.
|
|
70
|
+
- `server.shutdown()` — teardown for tests + custom lifecycles. Clears super-properties, groups, cache, aliases, breadcrumbs, error state.
|
|
71
|
+
- `scrubPii(value)` + `scrubPiiFromProperties(obj)` — opt-in PII regex utilities (email + card-number shapes).
|
|
72
|
+
- `ConsoleDebugLogger` + `NullDebugLogger` — NorthStar §16 debug signal vocabulary.
|
|
73
|
+
- `CrossdeckErrorCode` literal union derived from `CROSSDECK_ERROR_CODES` + `isCrossdeckErrorCode()` type guard for type-safe code comparisons.
|
|
74
|
+
- `HeartbeatResponse` + `Diagnostics` + 30+ exported types.
|
|
75
|
+
- `/auto-events` subpath in `package.json` exports.
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- **Breaking**: `track(event)` is now synchronous (returns `void`), enqueues for batched delivery, and auto-fills `anonymousId` with a process-stable `anon_node_…` when no identity hint is supplied. The old `await track(...)` shape is replaced by enqueue-and-flush.
|
|
80
|
+
- `ingest(events[])` retains immediate-POST behaviour for bulk-import callers (no auto-fill, returns `IngestResponse`).
|
|
81
|
+
- Secret key prefix in `diagnostics()` is now masked as `cd_sk_(test|live)_****<last4>` (Stripe pattern).
|
|
82
|
+
|
|
83
|
+
### Added — QA review v2 (bank-grade SDK extras)
|
|
84
|
+
|
|
85
|
+
- **Error subclass hierarchy** (Stripe pattern):
|
|
86
|
+
`CrossdeckAuthenticationError`, `CrossdeckPermissionError`,
|
|
87
|
+
`CrossdeckValidationError`, `CrossdeckRateLimitError`,
|
|
88
|
+
`CrossdeckNetworkError`, `CrossdeckInternalError`,
|
|
89
|
+
`CrossdeckConfigurationError`. All extend `CrossdeckError`. Pick the
|
|
90
|
+
right subclass via `makeCrossdeckError(payload)`. Constructed
|
|
91
|
+
automatically by `crossdeckErrorFromResponse()`.
|
|
92
|
+
- `CrossdeckError.toJSON()` — structured-logger compatible
|
|
93
|
+
serialisation. Includes `type`, `code`, `requestId`, `status`,
|
|
94
|
+
`retryAfterMs`, `stack`. Critical for production observability with
|
|
95
|
+
Pino / Winston / DataDog.
|
|
96
|
+
- `Crossdeck-Api-Version` header on every request, pinned to
|
|
97
|
+
`CROSSDECK_API_VERSION` constant. Forward-compat with backend
|
|
98
|
+
evolution (Stripe `Stripe-Version` pattern).
|
|
99
|
+
- `User-Agent` header: `@cross-deck/node/<sdk> node/<node-version> <platform>`.
|
|
100
|
+
HTTP best practice. Override the runtime token via
|
|
101
|
+
`runtimeToken: "bun/1.0"` in options.
|
|
102
|
+
- **Idempotent retry on GET methods** — default 3 attempts with
|
|
103
|
+
exponential backoff + full jitter, retrying on 408 + 5xx (except
|
|
104
|
+
501) and on network failures. Honours server `Retry-After`. POST
|
|
105
|
+
retries stay queue-driven (with batch-level `Idempotency-Key` reuse).
|
|
106
|
+
Configurable via `httpRetries: { maxAttempts, retryableStatuses }`.
|
|
107
|
+
- `testMode: true` option — every HTTP call short-circuits to a
|
|
108
|
+
synthetic success response, no network goes out. Path-aware (returns
|
|
109
|
+
the right shape per endpoint). For caller test suites that don't
|
|
110
|
+
want to mock `globalThis.fetch`.
|
|
111
|
+
- `onRequest` / `onResponse` hooks on `CrossdeckServerOptions`. Fire
|
|
112
|
+
on every request (including retries), carrying method, URL, status,
|
|
113
|
+
durationMs, attempt number. Synchronous, errors swallowed — telemetry
|
|
114
|
+
must never break the request pipeline.
|
|
115
|
+
- **AbortSignal pass-through** on every async method. Final
|
|
116
|
+
`RequestOptions` argument with `{ signal, timeoutMs }`. Caller-aborted
|
|
117
|
+
requests throw `CrossdeckNetworkError({ code: "request_aborted" })`.
|
|
118
|
+
Composes with the per-request timeout — whichever fires first wins.
|
|
119
|
+
- **CrossdeckServer extends EventEmitter** — typed `on` / `once` /
|
|
120
|
+
`off` / `emit` overloads via `CrossdeckServerEvents`. Events:
|
|
121
|
+
`queue.flush_succeeded`, `queue.flush_failed`, `queue.dropped`,
|
|
122
|
+
`queue.buffer_changed`, `error.captured`, `entitlements.warmed`,
|
|
123
|
+
`sdk.shutdown`.
|
|
124
|
+
- **`Symbol.dispose` + `Symbol.asyncDispose`** — TC39 explicit
|
|
125
|
+
resource management. `using server = new CrossdeckServer(...)`
|
|
126
|
+
shuts down on scope exit; `await using` flushes first.
|
|
127
|
+
- `server.isReady(): boolean` — synchronous readiness check.
|
|
128
|
+
`false` on sustained retry storm (≥ 5 consecutive failures) or
|
|
129
|
+
buffer pressure (≥ 80% of HARD_BUFFER_CAP).
|
|
130
|
+
- `server.awaitReady(timeoutMs?, pollIntervalMs?): Promise<boolean>` —
|
|
131
|
+
backpressure-aware wait for ready state.
|
|
132
|
+
- `server.getHealth()` — k8s-friendly snapshot: `ready`, `healthy`,
|
|
133
|
+
`bufferedEvents`, `inFlight`, `consecutiveFailures`, `lastFlushAt`,
|
|
134
|
+
`lastError`, `errorHandlersInstalled`.
|
|
135
|
+
- `server.bulkGrantEntitlement(grants[])` + `bulkRevokeEntitlement(revokes[])` —
|
|
136
|
+
bounded-concurrency fan-out (default 5). Returns settled array;
|
|
137
|
+
partial failures preserved as `{ ok: false, error }` entries.
|
|
138
|
+
|
|
139
|
+
### Notes
|
|
140
|
+
|
|
141
|
+
- Bundle size: `dist/index.cjs` ~98 KB, `dist/auto-events/index.cjs` ~11 KB.
|
|
142
|
+
- Zero runtime dependencies (`fetch` + `node:crypto` + `node:events` only).
|
|
143
|
+
- 398 unit tests + 19 e2e todos passing. Source-to-test ratio ~100%.
|
|
144
|
+
- Deferred to later releases: Fastify adapter (v0.3.0), Cloudflare Workers / Vercel Edge / Bun / Deno (v0.4+), OpenTelemetry / Pino / Winston log-capture integration (roadmap), HTTP keep-alive agent, request compression, SDK-level sampling.
|
|
145
|
+
|
|
7
146
|
## [0.1.0] — 2026-05-12
|
|
8
147
|
|
|
9
148
|
Initial server SDK release.
|