@cross-deck/web 1.8.0 → 1.9.1
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 +18 -0
- package/README.md +12 -6
- package/dist/crossdeck.umd.min.js +2 -2
- package/dist/crossdeck.umd.min.js.map +1 -1
- package/dist/error-codes.json +1 -1
- package/dist/index.cjs +30 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.mjs +30 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +30 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +30 -1
- package/dist/react.mjs.map +1 -1
- package/dist/vue.cjs +30 -1
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.mjs +30 -1
- package/dist/vue.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@cross-deck/web` will be documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [1.9.1] — 2026-06-30
|
|
6
|
+
|
|
7
|
+
**Docs — knowledge-backbone governance release.** No runtime API change. This
|
|
8
|
+
patch republishes the SDK with the Markdoc-backed README/version-control surface
|
|
9
|
+
so npm, the public GitHub mirror, and the Crossdeck knowledge backbone all carry
|
|
10
|
+
the same governed installation and contract documentation.
|
|
11
|
+
|
|
12
|
+
## [1.9.0] — 2026-06-24
|
|
13
|
+
|
|
14
|
+
**Added — read-cost cross-match (the Buckets bridge).** When
|
|
15
|
+
[`@cross-deck/buckets/web`](https://www.npmjs.com/package/@cross-deck/buckets) is
|
|
16
|
+
installed, `identify(userId)` now tells the browser collector who the session is,
|
|
17
|
+
so every browser database read attributes to that user; `reset()` clears it on
|
|
18
|
+
logout. A browser session is single-user, so the actor is session-level. Decoupled
|
|
19
|
+
and zero-dependency — the SDK drives a global bridge (`__crossdeckBucketsBridge__`)
|
|
20
|
+
and never imports Buckets; a missing collector is a silent no-op. The cross-match is
|
|
21
|
+
operational (like the entitlement cache), not an analytics event.
|
|
22
|
+
|
|
5
23
|
## [1.8.0] — 2026-06-11
|
|
6
24
|
|
|
7
25
|
**PARK on version-rejection — events are held, never dropped.** A third
|
package/README.md
CHANGED
|
@@ -79,6 +79,7 @@ That's the full happy path.
|
|
|
79
79
|
- **One identity for every device + user.** Pre-login events get an `anonymousId`. After login, `identify()` links them to your user ID through Crossdeck's identity graph. The SDK persists both so subsequent app launches resume where you left off.
|
|
80
80
|
- **Synchronous entitlement reads.** `getEntitlements()` populates a local cache. `isEntitled("pro")` is a Set lookup — no network call, no waiting.
|
|
81
81
|
- **Batched telemetry.** `track()` queues events in memory; the SDK flushes every 5 seconds (configurable) or when the buffer hits 20 events. Network failures re-queue the batch — events aren't lost on a flaky connection.
|
|
82
|
+
- **Outdated-version PARK (v1.8.0).** If the server ever stops accepting this SDK version's event format (HTTP `426` / `sdk_version_unsupported`), events are **parked, not lost**: held in the durable on-device queue (up to 1,000 events across page loads via `localStorage`), flushing hushes, one console warning names the exact version to update to, and everything delivers automatically after you upgrade. See [the durability contract](https://cross-deck.com/docs/sdk-event-durability/).
|
|
82
83
|
- **Boot heartbeat.** On `init()` the SDK pings `/v1/sdk/heartbeat` so the dashboard's Apps page can show you "last seen" per install. Disable with `autoHeartbeat: false`.
|
|
83
84
|
- **Stripe-style errors.** Every async method throws `CrossdeckError` with `type`, `code`, `requestId`, and `status` — same shape as Stripe's SDKs, so generic error handlers transfer.
|
|
84
85
|
|
|
@@ -167,6 +168,8 @@ If `mergePending: true`, both identifiers already pointed at different customers
|
|
|
167
168
|
|
|
168
169
|
**Entitlement-cache isolation (v1.4.0).** Every `identify(userId)` switches the local entitlement cache to a per-user storage slot — `localStorage["crossdeck:entitlements:<sha256(userId)>"]` — and unconditionally wipes the in-memory snapshot. A user-switch on a shared device CANNOT cross-read a prior user's cached entitlements, even if the in-memory clear is somehow skipped, because the storage keys are physically separate. `reset()` then wipes every per-user slot on the device (logout-grade).
|
|
169
170
|
|
|
171
|
+
**Read-cost cross-match (v1.9.0).** If [`@cross-deck/buckets/web`](https://www.npmjs.com/package/@cross-deck/buckets) is installed, `identify(userId)` also tells the browser read-cost collector who the session is — so every database read this session makes attributes to that user, and you can see *which user's which feature* is driving your read bill (`npx @cross-deck/buckets`, or the dashboard). `reset()` clears it on logout. Decoupled and zero-dependency — the SDK never imports Buckets; with no collector installed it's a silent no-op. This is operational, not an analytics event.
|
|
172
|
+
|
|
170
173
|
**Idempotency-Key (v1.4.0).** Every `syncPurchases()` derives a
|
|
171
174
|
deterministic `Idempotency-Key` from the request body — same
|
|
172
175
|
signed transaction in produces the same key out. The backend
|
|
@@ -204,6 +207,8 @@ window.addEventListener("beforeunload", () => {
|
|
|
204
207
|
|
|
205
208
|
Event names match `[A-Za-z0-9_.\-:]+`, max 128 chars. Properties are JSON-serialisable, max 8 KB per event after JSON encoding.
|
|
206
209
|
|
|
210
|
+
An empty event name **throws synchronously** with `CrossdeckError({ code: "missing_event_name" })` — the JS SDKs reject invalid input at the call site with a typed, catchable error (the Swift SDK's fire-and-forget surface drops + debug-logs instead; same invariant — invalid input never crashes your app and never reaches the wire — platform-native signalling). Codified as the `invalid-input-rejected-natively` contract.
|
|
211
|
+
|
|
207
212
|
In `debug: true` mode the SDK warns (one signal per call) when property keys look like PII — `email`, `password`, `token`, `secret`, `card`, `phone`. Crossdeck never strips fields automatically; the warning is so accidental leaks surface during development, not in prod logs.
|
|
208
213
|
|
|
209
214
|
### `await Crossdeck.syncPurchases(input)`
|
|
@@ -237,7 +242,7 @@ Force-flush the in-memory event queue. Useful before page unload or when shuttin
|
|
|
237
242
|
|
|
238
243
|
### `Crossdeck.setDebugMode(enabled)`
|
|
239
244
|
|
|
240
|
-
Toggle the verbose debug-signal vocabulary at runtime (NorthStar §16). When enabled, the SDK emits a fixed set of `console.info` lines tagged `[crossdeck:sdk.<signal>]` for `sdk.configured`, `sdk.first_event_sent`, `sdk.no_identity`, `sdk.purchase_evidence_sent`, `sdk.environment_mismatch`, and `sdk.
|
|
245
|
+
Toggle the verbose debug-signal vocabulary at runtime (NorthStar §16). When enabled, the SDK emits a fixed set of `console.info` lines tagged `[crossdeck:sdk.<signal>]` for `sdk.configured`, `sdk.first_event_sent`, `sdk.no_identity`, `sdk.purchase_evidence_sent`, `sdk.environment_mismatch`, `sdk.sensitive_property_warning`, and `sdk.parked` (fired once when the queue parks on an outdated-version rejection).
|
|
241
246
|
|
|
242
247
|
### `Crossdeck.diagnostics()`
|
|
243
248
|
|
|
@@ -249,7 +254,7 @@ Diagnostic snapshot — useful for development consoles and bug reports:
|
|
|
249
254
|
anonymousId: "anon_…",
|
|
250
255
|
crossdeckCustomerId: "cdcust_…" | null,
|
|
251
256
|
developerUserId: "user_…" | null,
|
|
252
|
-
sdkVersion: "
|
|
257
|
+
sdkVersion: "1.9.0",
|
|
253
258
|
baseUrl: "https://api.cross-deck.com/v1",
|
|
254
259
|
entitlements: { count: 2, lastUpdated: 1717891200000 },
|
|
255
260
|
events: { buffered: 0, dropped: 0, inFlight: 0, lastFlushAt: 1717891200000, lastError: null },
|
|
@@ -271,8 +276,8 @@ CrossdeckContracts.byId("per-user-cache-isolation");
|
|
|
271
276
|
CrossdeckContracts.byPillar("entitlements");
|
|
272
277
|
CrossdeckContracts.withStatus("proposed");
|
|
273
278
|
CrossdeckContracts.findByTestName("identify(B) makes A's entitlements unreachable from in-memory");
|
|
274
|
-
CrossdeckContracts.sdkVersion; // "1.
|
|
275
|
-
CrossdeckContracts.bundledIn; // "@cross-deck/web@1.
|
|
279
|
+
CrossdeckContracts.sdkVersion; // "1.9.0"
|
|
280
|
+
CrossdeckContracts.bundledIn; // "@cross-deck/web@1.9.0"
|
|
276
281
|
```
|
|
277
282
|
|
|
278
283
|
The `Contract` type is exported alongside; the binary-stability promise (which fields are guaranteed across patch/minor releases) is documented inline on `src/contracts.ts` and in [`contracts/README.md`](https://github.com/VistaApps-za/crossdeck/blob/main/contracts/README.md).
|
|
@@ -373,8 +378,9 @@ Error fields:
|
|
|
373
378
|
|
|
374
379
|
| Field | What it is |
|
|
375
380
|
|---|---|
|
|
376
|
-
| `type` | One of `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `internal_error`, `network_error`, `configuration_error`. Same vocabulary the backend uses. |
|
|
377
|
-
| `code` | Specific machine-readable code, e.g. `invalid_api_key`, `origin_not_allowed`, `rate_limited`, `network_error`. |
|
|
381
|
+
| `type` | One of `authentication_error`, `permission_error`, `invalid_request_error`, `rate_limit_error`, `internal_error`, `network_error`, `configuration_error`, `version_error`. Same vocabulary the backend uses. |
|
|
382
|
+
| `code` | Specific machine-readable code, e.g. `invalid_api_key`, `origin_not_allowed`, `rate_limited`, `network_error`, `sdk_version_unsupported`. |
|
|
383
|
+
| `minVersion`, `surface` | Set on `version_error` (HTTP 426) responses — the exact SDK version to update to. The queue PARKs on this error instead of dropping (see "Outdated-version PARK" above). |
|
|
378
384
|
| `message` | Human-readable description. |
|
|
379
385
|
| `requestId` | Server-issued ID. Echo it in support tickets — we'll have a one-line log entry that explains the decision. |
|
|
380
386
|
| `status` | HTTP status code if the error came from an API response. |
|