@cross-deck/web 0.1.1 → 0.3.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 ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
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
+
5
+ ## [0.3.0] — 2026-05-08
6
+
7
+ This release reconciles the web SDK with the Crossdeck SDK NorthStar Addendum (§4 Shared Contract, §11.1 Web SDK pattern, §13.1 wire envelope, §15 sensitive properties, §16 debug signal vocabulary). The public surface now matches what the iOS, Android, and Node SDKs will expose — `init`, `flush`, `syncPurchases`, `setDebugMode`.
8
+
9
+ ### Added
10
+
11
+ - **`Crossdeck.init({ appId, publicKey, environment })`** — canonical lifecycle method per NorthStar §4. The trio is required and validated up-front: a publishable-key prefix that disagrees with the declared `environment` throws `CrossdeckError({ code: "environment_mismatch" })` at boot, so a typo can't silently route prod data into sandbox dashboards.
12
+ - **`Crossdeck.flush()`** — alias of the old `flushEvents()`, matching the standardised name.
13
+ - **`Crossdeck.syncPurchases(input)`** — replaces `purchaseApple`. Posts to `/v1/purchases/sync` and accepts an optional `rail` field for future Stripe/Google support.
14
+ - **`Crossdeck.setDebugMode(enabled)`** + `debug` init option — toggle the §16 debug signal vocabulary (`sdk.configured`, `sdk.first_event_sent`, `sdk.no_identity`, `sdk.purchase_evidence_sent`, `sdk.environment_mismatch`, `sdk.sensitive_property_warning`).
15
+ - **Sensitive-property warnings** — when debug mode is on, `track()` warns once per call if any property key matches `email|password|token|secret|card|phone` (NorthStar §15). The event is still sent unmodified; the warning surfaces accidental PII in the dashboard onboarding feed.
16
+ - **NorthStar §13.1 wire envelope** — every `/v1/events` POST now includes `appId`, `environment`, and `sdk: { name, version }` at the batch level. The backend validates these against the API-key-resolved app and rejects mismatches with `permission_error / env_mismatch`.
17
+
18
+ ### Changed
19
+
20
+ - `Crossdeck.start()` is now a deprecated alias of `init()` and emits a `console.warn` once per call. The signature is unchanged, but the new `appId` and `environment` options are still required even when calling `start`.
21
+ - `Crossdeck.purchaseApple()` is now a deprecated alias of `syncPurchases({ rail: "apple", ... })`. The new method posts to `/v1/purchases/sync`; the legacy `/v1/purchases` route is kept on the backend for v0.2.x callers.
22
+ - The `not_started` configuration error code is now `not_initialized` to match the rename.
23
+
24
+ ### Removed
25
+
26
+ Nothing. v0.3.0 is fully source-compatible with v0.2.x callers — the legacy method names log a deprecation but continue to work. Plan to drop them in v0.5.0.
27
+
28
+ ## [0.2.0] — 2026-05-06
29
+
30
+ - Added auto-tracking: sessions, page views, and device-info enrichment are on by default in browsers. See `autoTrack` config to disable individually or wholesale.
31
+ - Stable `Diagnostics` shape regardless of whether `start()` has been called — pre-start values are sensible empties.
32
+
33
+ ## [0.1.0] — 2026-05-05
34
+
35
+ Initial public release.
package/README.md CHANGED
@@ -12,7 +12,11 @@ npm install @cross-deck/web
12
12
  import { Crossdeck } from "@cross-deck/web";
13
13
 
14
14
  // 1. Boot once at app start
15
- Crossdeck.start({ publicKey: "cd_pub_live_…" });
15
+ Crossdeck.init({
16
+ appId: "app_web_xxx", // from the Crossdeck dashboard
17
+ publicKey: "cd_pub_live_…", // publishable key, safe in client code
18
+ environment: "production", // "production" or "sandbox"
19
+ });
16
20
 
17
21
  // 2. After the user logs in, link the device to your user ID
18
22
  await Crossdeck.identify("user_847");
@@ -33,29 +37,71 @@ That's the full happy path.
33
37
 
34
38
  ## What it does
35
39
 
40
+ - **Auto-tracking, on by default.** Sessions, page views, and device info (OS, browser, locale, timezone, screen size, app version) ship from boot. No instrumentation needed for the basics. Disable any of them via `autoTrack: { sessions: false }` etc.
36
41
  - **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.
37
42
  - **Synchronous entitlement reads.** `getEntitlements()` populates a local cache. `isEntitled("pro")` is a Set lookup — no network call, no waiting.
38
43
  - **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.
39
- - **Boot heartbeat.** On `start()` the SDK pings `/v1/sdk/heartbeat` so the dashboard's Apps page can show you "last seen" per install. Disable with `autoHeartbeat: false`.
44
+ - **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`.
40
45
  - **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.
41
46
 
47
+ ## Auto-tracked events
48
+
49
+ | Event | When |
50
+ |---|---|
51
+ | `session.started` | On boot. Carries `sessionId`. |
52
+ | `session.ended` | On `pagehide` / `beforeunload`, OR when returning to a tab after >30 min idle. Carries `sessionId` and `durationMs`. |
53
+ | `page.viewed` | On initial load + every SPA navigation (`history.pushState`, `replaceState`, `popstate`). Carries `path`, `url`, `search`, `hash`, `title`, `referrer`. |
54
+
55
+ Every event — auto-tracked and developer-emitted — is enriched with the device-info payload below. Quick tab switches (Cmd-Tab, switching browser tabs) don't end the session — only real closes do, matching GA4's session-window convention.
56
+
57
+ ## Auto-attached device info
58
+
59
+ Every event's `properties` is enriched with whatever the SDK can detect:
60
+
61
+ ```ts
62
+ {
63
+ os: "macOS" | "iOS" | "Android" | "Windows" | "Linux",
64
+ osVersion: "14.4",
65
+ browser: "Safari" | "Chrome" | "Firefox" | "Edge" | "Opera",
66
+ browserVersion: "17.5",
67
+ locale: "en-US",
68
+ timezone: "Africa/Johannesburg",
69
+ screenWidth: 2560,
70
+ screenHeight: 1440,
71
+ viewportWidth: 1440,
72
+ viewportHeight: 900,
73
+ devicePixelRatio: 2,
74
+ appVersion: "1.2.3", // only when you set Crossdeck.start({ appVersion })
75
+ }
76
+ ```
77
+
78
+ No fingerprinting, no IP collection on the event document, no canvas hashing. Privacy by default. Caller-supplied properties always override auto-detected ones, so you can override `appVersion` per event if you A/B builds.
79
+
42
80
  ## API
43
81
 
44
- ### `Crossdeck.start(options)`
82
+ ### `Crossdeck.init(options)`
45
83
 
46
- Boot the client. Idempotent — calling twice with the same options is fine.
84
+ Boot the client. Idempotent — calling twice with the same options is fine. (`Crossdeck.start()` is kept as a deprecated alias for v0.2.x callers.)
47
85
 
48
86
  ```ts
49
- Crossdeck.start({
87
+ Crossdeck.init({
88
+ appId: "app_web_xxx", // required — from the dashboard
50
89
  publicKey: "cd_pub_live_…", // required
90
+ environment: "production", // required — "production" | "sandbox"
51
91
  baseUrl: "https://api.cross-deck.com/v1", // override for self-host or emulator
92
+ appVersion: "1.2.3", // attached to every event as properties.appVersion
93
+ autoTrack: true, // default — sessions, page views, device info
94
+ // …or granular: autoTrack: { sessions: false } keeps page views + device info
52
95
  autoHeartbeat: true, // default; set false for high-frequency boots
53
96
  eventFlushBatchSize: 20, // default
54
97
  eventFlushIntervalMs: 5_000, // default
55
98
  storage: customStorage, // override the persistence adapter
99
+ debug: false, // verbose §16 debug signals when true
56
100
  });
57
101
  ```
58
102
 
103
+ Crossdeck checks the key prefix matches `environment`: `cd_pub_test_…` must declare `"sandbox"`, `cd_pub_live_…` must declare `"production"`. Mismatches throw `CrossdeckError({ code: "environment_mismatch" })` at init time so a typo can't silently route prod telemetry into sandbox dashboards.
104
+
59
105
  The publishable key is safe to ship in client code. Crossdeck enforces origin allowlists (web), bundle-ID binding (mobile), and rate limits at the edge — see [docs/api-keys](https://cross-deck.com/docs/api-keys/) for the full security model.
60
106
 
61
107
  ### `await Crossdeck.identify(userId, options?)`
@@ -92,24 +138,26 @@ Synchronous read from the local cache. Returns `false` until you've called `getE
92
138
 
93
139
  ### `Crossdeck.track(name, properties?)`
94
140
 
95
- Queue a telemetry event. Returns immediately. Events flush in batches; force a flush with `flushEvents()`:
141
+ Queue a telemetry event. Returns immediately. Events flush in batches; force a flush with `flush()`:
96
142
 
97
143
  ```ts
98
144
  Crossdeck.track("checkout_started", { product: "annual_pro" });
99
145
  // …later, e.g. before page unload:
100
146
  window.addEventListener("beforeunload", () => {
101
- void Crossdeck.flushEvents();
147
+ void Crossdeck.flush();
102
148
  });
103
149
  ```
104
150
 
105
151
  Event names match `[A-Za-z0-9_.\-:]+`, max 128 chars. Properties are JSON-serialisable, max 8 KB per event after JSON encoding.
106
152
 
107
- ### `await Crossdeck.purchaseApple(input)`
153
+ 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.
154
+
155
+ ### `await Crossdeck.syncPurchases(input)`
108
156
 
109
- Forward a StoreKit 2 transaction directly to Crossdeck for verification — closes the purchase-to-entitled latency from seconds to milliseconds (faster than waiting for the App Store webhook).
157
+ Forward purchase evidence (Apple StoreKit 2) directly to Crossdeck for verification — closes the purchase-to-entitled latency from seconds to milliseconds (faster than waiting for the App Store webhook). (`purchaseApple()` is kept as a deprecated alias.)
110
158
 
111
159
  ```ts
112
- await Crossdeck.purchaseApple({
160
+ await Crossdeck.syncPurchases({
113
161
  signedTransactionInfo: transaction.jsonRepresentation, // from StoreKit 2
114
162
  signedRenewalInfo: subscription.signedRenewalInfo, // optional
115
163
  appAccountToken: "uuid-…", // optional
@@ -120,15 +168,19 @@ Stripe and Google purchases are verified via webhooks (Stripe Connect platform e
120
168
 
121
169
  ### `await Crossdeck.heartbeat()`
122
170
 
123
- Manually send a heartbeat. Called automatically by `start()` unless `autoHeartbeat: false`. Returns the readiness summary the dashboard uses to display SDK installation status.
171
+ Manually send a heartbeat. Called automatically by `init()` unless `autoHeartbeat: false`. Returns the readiness summary the dashboard uses to display SDK installation status.
124
172
 
125
173
  ### `Crossdeck.reset()`
126
174
 
127
175
  Wipe persisted identity + entitlement cache + queued events. Call on logout. The next session generates a fresh `anonymousId` and starts a clean identity-graph entry.
128
176
 
129
- ### `Crossdeck.flushEvents()`
177
+ ### `Crossdeck.flush()`
178
+
179
+ Force-flush the in-memory event queue. Useful before page unload or when shutting down a script. (`flushEvents()` is kept as a deprecated alias.)
180
+
181
+ ### `Crossdeck.setDebugMode(enabled)`
130
182
 
131
- Force-flush the in-memory event queue. Useful before page unload or when shutting down a script.
183
+ 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.sensitive_property_warning`.
132
184
 
133
185
  ### `Crossdeck.diagnostics()`
134
186
 
@@ -149,7 +201,7 @@ Diagnostic snapshot — useful for development consoles and bug reports:
149
201
 
150
202
  ## Errors
151
203
 
152
- Every async method can throw `CrossdeckError`. Synchronous methods throw on configuration mistakes (calling before `start()`, invalid key prefix).
204
+ Every async method can throw `CrossdeckError`. Synchronous methods throw on configuration mistakes (calling before `init()`, invalid key prefix, env mismatch).
153
205
 
154
206
  ```ts
155
207
  import { CrossdeckError } from "@cross-deck/web";
@@ -183,9 +235,11 @@ The SDK works the same way in Node 18+:
183
235
  ```ts
184
236
  import { Crossdeck, MemoryStorage } from "@cross-deck/web";
185
237
 
186
- Crossdeck.start({
238
+ Crossdeck.init({
239
+ appId: process.env.CROSSDECK_APP_ID!,
187
240
  publicKey: process.env.CROSSDECK_PUBLIC_KEY!,
188
- storage: new MemoryStorage(), // session-only, no localStorage
241
+ environment: "sandbox", // or "production"
242
+ storage: new MemoryStorage(), // session-only, no localStorage
189
243
  autoHeartbeat: false, // skip the boot ping in scripts
190
244
  });
191
245
  ```
package/dist/index.d.mts CHANGED
@@ -53,12 +53,36 @@ interface HeartbeatResponse {
53
53
  serverTime: number;
54
54
  }
55
55
  /**
56
- * Configuration for Crossdeck.start. Most fields have sensible defaults
57
- * only `publicKey` is mandatory.
56
+ * Configuration for Crossdeck.init. Three fields are mandatory
57
+ * `appId`, `publicKey`, and `environment` per NorthStar §11.1.
58
+ *
59
+ * The pair of (appId, environment) is what we put on the wire envelope
60
+ * (NorthStar §13.1) so the backend can correlate events against the
61
+ * specific app surface and refuse mismatched env declarations loudly.
58
62
  */
59
63
  interface CrossdeckOptions {
64
+ /**
65
+ * Your Crossdeck App ID (e.g. "app_web_xxx"). Required.
66
+ *
67
+ * Issued in the dashboard when you create an app. Goes on the wire
68
+ * envelope so the backend correlates events with the specific app
69
+ * surface — useful when one project has multiple apps (web + iOS +
70
+ * Android) sharing the same publishable key family.
71
+ */
72
+ appId: string;
60
73
  /** Your Crossdeck publishable key (cd_pub_…). Required. */
61
74
  publicKey: string;
75
+ /**
76
+ * Explicit environment declaration. Required.
77
+ *
78
+ * Must match the publishable key's prefix:
79
+ * cd_pub_test_… → "sandbox"
80
+ * cd_pub_live_… → "production"
81
+ *
82
+ * Mismatch is rejected at init time so a typo'd key can't silently
83
+ * route prod telemetry into sandbox dashboards.
84
+ */
85
+ environment: Environment;
62
86
  /**
63
87
  * Override the API base URL. Default is https://api.cross-deck.com/v1.
64
88
  * Useful for self-hosted setups or pointing at the local emulator
@@ -90,6 +114,40 @@ interface CrossdeckOptions {
90
114
  eventFlushIntervalMs?: number;
91
115
  /** Override the SDK version reported on heartbeats. Default: package version. */
92
116
  sdkVersion?: string;
117
+ /**
118
+ * Auto-tracking. Default: every flag is `true` in browsers, all
119
+ * silently no-op in Node.
120
+ *
121
+ * Pass `false` to disable everything, or a partial object to override
122
+ * individual flags:
123
+ *
124
+ * Crossdeck.start({
125
+ * publicKey: "...",
126
+ * autoTrack: { pageViews: false }, // sessions + deviceInfo still on
127
+ * });
128
+ */
129
+ autoTrack?: boolean | Partial<AutoTrackOptions>;
130
+ /**
131
+ * Your app's version (e.g. "1.2.3"). Auto-attached to every event as
132
+ * `properties.appVersion` when `autoTrack.deviceInfo` is enabled.
133
+ * Useful for slicing dashboards by build.
134
+ */
135
+ appVersion?: string;
136
+ /**
137
+ * Enable verbose diagnostic logging via the NorthStar §16 debug-signal
138
+ * vocabulary. Default: false. Equivalent to calling
139
+ * `Crossdeck.setDebugMode(true)` after init.
140
+ */
141
+ debug?: boolean;
142
+ }
143
+ /** Auto-tracking flags. See CrossdeckOptions.autoTrack. */
144
+ interface AutoTrackOptions {
145
+ /** Emit `session.started` / `session.ended` automatically. Default true (browser only). */
146
+ sessions: boolean;
147
+ /** Emit `page.viewed` on initial load + SPA navigation. Default true (browser only). */
148
+ pageViews: boolean;
149
+ /** Auto-attach os/browser/locale/screen/etc to every event's `properties`. Default true (browser only). */
150
+ deviceInfo: boolean;
93
151
  }
94
152
  /** Minimal interface for any pluggable key-value persistence. */
95
153
  interface KeyValueStorage {
@@ -137,7 +195,11 @@ interface Diagnostics {
137
195
  *
138
196
  * import { Crossdeck } from "@cross-deck/web";
139
197
  *
140
- * Crossdeck.start({ publicKey: "cd_pub_live_…" });
198
+ * Crossdeck.init({
199
+ * appId: "app_web_xxx",
200
+ * publicKey: "cd_pub_live_…",
201
+ * environment: "production",
202
+ * });
141
203
  *
142
204
  * await Crossdeck.identify("user_847");
143
205
  * const ents = await Crossdeck.getEntitlements();
@@ -149,11 +211,12 @@ interface Diagnostics {
149
211
  *
150
212
  * Usage (Node):
151
213
  *
152
- * import { Crossdeck } from "@cross-deck/web";
153
- * import { MemoryStorage } from "@cross-deck/web";
214
+ * import { Crossdeck, MemoryStorage } from "@cross-deck/web";
154
215
  *
155
- * Crossdeck.start({
216
+ * Crossdeck.init({
217
+ * appId: "app_node_xxx",
156
218
  * publicKey: "cd_pub_test_…",
219
+ * environment: "sandbox",
157
220
  * storage: new MemoryStorage(), // session-only persistence
158
221
  * autoHeartbeat: false, // skip the boot ping in scripts
159
222
  * });
@@ -162,9 +225,19 @@ interface Diagnostics {
162
225
  declare class CrossdeckClient {
163
226
  private state;
164
227
  /**
165
- * Boot the SDK. Idempotent — calling start twice with the same options
228
+ * Boot the SDK. Idempotent — calling init twice with the same options
166
229
  * is a no-op; calling with different options replaces the previous
167
230
  * configuration.
231
+ *
232
+ * NorthStar §11.1: signature is `Crossdeck.init({ appId, publicKey,
233
+ * environment })`. The trio is validated up-front so a typo'd key or a
234
+ * mismatched env fails fast at boot rather than at first event-flush.
235
+ */
236
+ init(options: CrossdeckOptions): void;
237
+ /**
238
+ * @deprecated Use `init()` instead. NorthStar §4 standardised the
239
+ * lifecycle method name across SDKs as `init` (formerly `start` /
240
+ * `configure`). `start` will be removed in a future major version.
168
241
  */
169
242
  start(options: CrossdeckOptions): void;
170
243
  /**
@@ -188,17 +261,43 @@ declare class CrossdeckClient {
188
261
  /**
189
262
  * Queue a telemetry event. Returns immediately — the network round-
190
263
  * trip happens in the background. To flush before the page unloads,
191
- * call flushEvents().
264
+ * call flush().
192
265
  */
193
266
  track(name: string, properties?: EventProperties): void;
194
- /** Force-flush queued events. Useful to call from page-unload handlers. */
267
+ /**
268
+ * Force-flush queued events. Useful to call from page-unload handlers.
269
+ *
270
+ * NorthStar §4: standard method name across all Crossdeck SDKs.
271
+ */
272
+ flush(): Promise<void>;
273
+ /** @deprecated Use `flush()` instead. NorthStar §4 standardised the name. */
195
274
  flushEvents(): Promise<void>;
196
- /** Forward an Apple StoreKit 2 transaction for verification + projection. */
275
+ /**
276
+ * Forward purchase evidence to the backend for verification + entitlement
277
+ * projection. NorthStar §4 + §13 canonical name.
278
+ *
279
+ * Today the web SDK only supports Apple StoreKit 2 forwarding (web apps
280
+ * that sit alongside an iOS app). Stripe doesn't need this method —
281
+ * Stripe webhooks deliver evidence server-side without a client round-trip.
282
+ */
283
+ syncPurchases(input: {
284
+ rail?: "apple";
285
+ signedTransactionInfo: string;
286
+ signedRenewalInfo?: string;
287
+ appAccountToken?: string;
288
+ }): Promise<PurchaseResult>;
289
+ /** @deprecated Use `syncPurchases()` instead. NorthStar §4 standardised the name. */
197
290
  purchaseApple(input: {
198
291
  signedTransactionInfo: string;
199
292
  signedRenewalInfo?: string;
200
293
  appAccountToken?: string;
201
294
  }): Promise<PurchaseResult>;
295
+ /**
296
+ * Toggle verbose diagnostic logging — NorthStar §16. When enabled, the
297
+ * SDK emits a fixed vocabulary of debug signals to console.info that the
298
+ * dashboard's onboarding checklist can also surface as live events.
299
+ */
300
+ setDebugMode(enabled: boolean): void;
202
301
  /**
203
302
  * Send the boot heartbeat. Called automatically by start() unless
204
303
  * autoHeartbeat:false. Safe to call manually as a "we're still here" ping.
@@ -300,7 +399,41 @@ declare class MemoryStorage implements KeyValueStorage {
300
399
  * fetch shim, no transitive deps.
301
400
  */
302
401
  declare const SDK_NAME = "@cross-deck/web";
303
- declare const SDK_VERSION = "0.1.1";
402
+ declare const SDK_VERSION = "0.3.0";
304
403
  declare const DEFAULT_BASE_URL = "https://api.cross-deck.com/v1";
305
404
 
306
- export { type AliasResult, type AuditRail, Crossdeck, CrossdeckClient, CrossdeckError, type CrossdeckErrorPayload, type CrossdeckErrorType, type CrossdeckOptions, DEFAULT_BASE_URL, type Diagnostics, type EntitlementsListResponse, type Environment, type EventProperties, type HeartbeatResponse, type IdentifyOptions, type KeyValueStorage, MemoryStorage, type Platform, type PublicEntitlement, type PurchaseResult, SDK_NAME, SDK_VERSION };
405
+ /**
406
+ * Device + environment enrichment.
407
+ *
408
+ * Auto-attached to every event the SDK emits when `autoTrack.deviceInfo` is
409
+ * enabled (default). Caller-supplied event properties always override
410
+ * auto-detected ones (so a developer can manually set `app.version` per
411
+ * event if they want to A/B between builds).
412
+ *
413
+ * Privacy posture:
414
+ * - No fingerprinting (no canvas hashes, no font enumeration).
415
+ * - No precise geolocation (only timezone + locale, both of which the
416
+ * browser exposes to every page anyway).
417
+ * - No IP collection — the backend logs the request IP for rate-limit
418
+ * purposes; it isn't stored on the event document.
419
+ * - All fields are typed enums or short strings; we never echo back
420
+ * full User-Agent strings to avoid surfacing fingerprintable detail
421
+ * in dashboards.
422
+ */
423
+ interface DeviceInfo {
424
+ os?: string;
425
+ osVersion?: string;
426
+ browser?: string;
427
+ browserVersion?: string;
428
+ locale?: string;
429
+ timezone?: string;
430
+ screenWidth?: number;
431
+ screenHeight?: number;
432
+ viewportWidth?: number;
433
+ viewportHeight?: number;
434
+ devicePixelRatio?: number;
435
+ /** Caller-supplied. Set via Crossdeck.start({ appVersion: "1.2.3" }). */
436
+ appVersion?: string;
437
+ }
438
+
439
+ export { type AliasResult, type AuditRail, type AutoTrackOptions, Crossdeck, CrossdeckClient, CrossdeckError, type CrossdeckErrorPayload, type CrossdeckErrorType, type CrossdeckOptions, DEFAULT_BASE_URL, type DeviceInfo, type Diagnostics, type EntitlementsListResponse, type Environment, type EventProperties, type HeartbeatResponse, type IdentifyOptions, type KeyValueStorage, MemoryStorage, type Platform, type PublicEntitlement, type PurchaseResult, SDK_NAME, SDK_VERSION };
package/dist/index.d.ts CHANGED
@@ -53,12 +53,36 @@ interface HeartbeatResponse {
53
53
  serverTime: number;
54
54
  }
55
55
  /**
56
- * Configuration for Crossdeck.start. Most fields have sensible defaults
57
- * only `publicKey` is mandatory.
56
+ * Configuration for Crossdeck.init. Three fields are mandatory
57
+ * `appId`, `publicKey`, and `environment` per NorthStar §11.1.
58
+ *
59
+ * The pair of (appId, environment) is what we put on the wire envelope
60
+ * (NorthStar §13.1) so the backend can correlate events against the
61
+ * specific app surface and refuse mismatched env declarations loudly.
58
62
  */
59
63
  interface CrossdeckOptions {
64
+ /**
65
+ * Your Crossdeck App ID (e.g. "app_web_xxx"). Required.
66
+ *
67
+ * Issued in the dashboard when you create an app. Goes on the wire
68
+ * envelope so the backend correlates events with the specific app
69
+ * surface — useful when one project has multiple apps (web + iOS +
70
+ * Android) sharing the same publishable key family.
71
+ */
72
+ appId: string;
60
73
  /** Your Crossdeck publishable key (cd_pub_…). Required. */
61
74
  publicKey: string;
75
+ /**
76
+ * Explicit environment declaration. Required.
77
+ *
78
+ * Must match the publishable key's prefix:
79
+ * cd_pub_test_… → "sandbox"
80
+ * cd_pub_live_… → "production"
81
+ *
82
+ * Mismatch is rejected at init time so a typo'd key can't silently
83
+ * route prod telemetry into sandbox dashboards.
84
+ */
85
+ environment: Environment;
62
86
  /**
63
87
  * Override the API base URL. Default is https://api.cross-deck.com/v1.
64
88
  * Useful for self-hosted setups or pointing at the local emulator
@@ -90,6 +114,40 @@ interface CrossdeckOptions {
90
114
  eventFlushIntervalMs?: number;
91
115
  /** Override the SDK version reported on heartbeats. Default: package version. */
92
116
  sdkVersion?: string;
117
+ /**
118
+ * Auto-tracking. Default: every flag is `true` in browsers, all
119
+ * silently no-op in Node.
120
+ *
121
+ * Pass `false` to disable everything, or a partial object to override
122
+ * individual flags:
123
+ *
124
+ * Crossdeck.start({
125
+ * publicKey: "...",
126
+ * autoTrack: { pageViews: false }, // sessions + deviceInfo still on
127
+ * });
128
+ */
129
+ autoTrack?: boolean | Partial<AutoTrackOptions>;
130
+ /**
131
+ * Your app's version (e.g. "1.2.3"). Auto-attached to every event as
132
+ * `properties.appVersion` when `autoTrack.deviceInfo` is enabled.
133
+ * Useful for slicing dashboards by build.
134
+ */
135
+ appVersion?: string;
136
+ /**
137
+ * Enable verbose diagnostic logging via the NorthStar §16 debug-signal
138
+ * vocabulary. Default: false. Equivalent to calling
139
+ * `Crossdeck.setDebugMode(true)` after init.
140
+ */
141
+ debug?: boolean;
142
+ }
143
+ /** Auto-tracking flags. See CrossdeckOptions.autoTrack. */
144
+ interface AutoTrackOptions {
145
+ /** Emit `session.started` / `session.ended` automatically. Default true (browser only). */
146
+ sessions: boolean;
147
+ /** Emit `page.viewed` on initial load + SPA navigation. Default true (browser only). */
148
+ pageViews: boolean;
149
+ /** Auto-attach os/browser/locale/screen/etc to every event's `properties`. Default true (browser only). */
150
+ deviceInfo: boolean;
93
151
  }
94
152
  /** Minimal interface for any pluggable key-value persistence. */
95
153
  interface KeyValueStorage {
@@ -137,7 +195,11 @@ interface Diagnostics {
137
195
  *
138
196
  * import { Crossdeck } from "@cross-deck/web";
139
197
  *
140
- * Crossdeck.start({ publicKey: "cd_pub_live_…" });
198
+ * Crossdeck.init({
199
+ * appId: "app_web_xxx",
200
+ * publicKey: "cd_pub_live_…",
201
+ * environment: "production",
202
+ * });
141
203
  *
142
204
  * await Crossdeck.identify("user_847");
143
205
  * const ents = await Crossdeck.getEntitlements();
@@ -149,11 +211,12 @@ interface Diagnostics {
149
211
  *
150
212
  * Usage (Node):
151
213
  *
152
- * import { Crossdeck } from "@cross-deck/web";
153
- * import { MemoryStorage } from "@cross-deck/web";
214
+ * import { Crossdeck, MemoryStorage } from "@cross-deck/web";
154
215
  *
155
- * Crossdeck.start({
216
+ * Crossdeck.init({
217
+ * appId: "app_node_xxx",
156
218
  * publicKey: "cd_pub_test_…",
219
+ * environment: "sandbox",
157
220
  * storage: new MemoryStorage(), // session-only persistence
158
221
  * autoHeartbeat: false, // skip the boot ping in scripts
159
222
  * });
@@ -162,9 +225,19 @@ interface Diagnostics {
162
225
  declare class CrossdeckClient {
163
226
  private state;
164
227
  /**
165
- * Boot the SDK. Idempotent — calling start twice with the same options
228
+ * Boot the SDK. Idempotent — calling init twice with the same options
166
229
  * is a no-op; calling with different options replaces the previous
167
230
  * configuration.
231
+ *
232
+ * NorthStar §11.1: signature is `Crossdeck.init({ appId, publicKey,
233
+ * environment })`. The trio is validated up-front so a typo'd key or a
234
+ * mismatched env fails fast at boot rather than at first event-flush.
235
+ */
236
+ init(options: CrossdeckOptions): void;
237
+ /**
238
+ * @deprecated Use `init()` instead. NorthStar §4 standardised the
239
+ * lifecycle method name across SDKs as `init` (formerly `start` /
240
+ * `configure`). `start` will be removed in a future major version.
168
241
  */
169
242
  start(options: CrossdeckOptions): void;
170
243
  /**
@@ -188,17 +261,43 @@ declare class CrossdeckClient {
188
261
  /**
189
262
  * Queue a telemetry event. Returns immediately — the network round-
190
263
  * trip happens in the background. To flush before the page unloads,
191
- * call flushEvents().
264
+ * call flush().
192
265
  */
193
266
  track(name: string, properties?: EventProperties): void;
194
- /** Force-flush queued events. Useful to call from page-unload handlers. */
267
+ /**
268
+ * Force-flush queued events. Useful to call from page-unload handlers.
269
+ *
270
+ * NorthStar §4: standard method name across all Crossdeck SDKs.
271
+ */
272
+ flush(): Promise<void>;
273
+ /** @deprecated Use `flush()` instead. NorthStar §4 standardised the name. */
195
274
  flushEvents(): Promise<void>;
196
- /** Forward an Apple StoreKit 2 transaction for verification + projection. */
275
+ /**
276
+ * Forward purchase evidence to the backend for verification + entitlement
277
+ * projection. NorthStar §4 + §13 canonical name.
278
+ *
279
+ * Today the web SDK only supports Apple StoreKit 2 forwarding (web apps
280
+ * that sit alongside an iOS app). Stripe doesn't need this method —
281
+ * Stripe webhooks deliver evidence server-side without a client round-trip.
282
+ */
283
+ syncPurchases(input: {
284
+ rail?: "apple";
285
+ signedTransactionInfo: string;
286
+ signedRenewalInfo?: string;
287
+ appAccountToken?: string;
288
+ }): Promise<PurchaseResult>;
289
+ /** @deprecated Use `syncPurchases()` instead. NorthStar §4 standardised the name. */
197
290
  purchaseApple(input: {
198
291
  signedTransactionInfo: string;
199
292
  signedRenewalInfo?: string;
200
293
  appAccountToken?: string;
201
294
  }): Promise<PurchaseResult>;
295
+ /**
296
+ * Toggle verbose diagnostic logging — NorthStar §16. When enabled, the
297
+ * SDK emits a fixed vocabulary of debug signals to console.info that the
298
+ * dashboard's onboarding checklist can also surface as live events.
299
+ */
300
+ setDebugMode(enabled: boolean): void;
202
301
  /**
203
302
  * Send the boot heartbeat. Called automatically by start() unless
204
303
  * autoHeartbeat:false. Safe to call manually as a "we're still here" ping.
@@ -300,7 +399,41 @@ declare class MemoryStorage implements KeyValueStorage {
300
399
  * fetch shim, no transitive deps.
301
400
  */
302
401
  declare const SDK_NAME = "@cross-deck/web";
303
- declare const SDK_VERSION = "0.1.1";
402
+ declare const SDK_VERSION = "0.3.0";
304
403
  declare const DEFAULT_BASE_URL = "https://api.cross-deck.com/v1";
305
404
 
306
- export { type AliasResult, type AuditRail, Crossdeck, CrossdeckClient, CrossdeckError, type CrossdeckErrorPayload, type CrossdeckErrorType, type CrossdeckOptions, DEFAULT_BASE_URL, type Diagnostics, type EntitlementsListResponse, type Environment, type EventProperties, type HeartbeatResponse, type IdentifyOptions, type KeyValueStorage, MemoryStorage, type Platform, type PublicEntitlement, type PurchaseResult, SDK_NAME, SDK_VERSION };
405
+ /**
406
+ * Device + environment enrichment.
407
+ *
408
+ * Auto-attached to every event the SDK emits when `autoTrack.deviceInfo` is
409
+ * enabled (default). Caller-supplied event properties always override
410
+ * auto-detected ones (so a developer can manually set `app.version` per
411
+ * event if they want to A/B between builds).
412
+ *
413
+ * Privacy posture:
414
+ * - No fingerprinting (no canvas hashes, no font enumeration).
415
+ * - No precise geolocation (only timezone + locale, both of which the
416
+ * browser exposes to every page anyway).
417
+ * - No IP collection — the backend logs the request IP for rate-limit
418
+ * purposes; it isn't stored on the event document.
419
+ * - All fields are typed enums or short strings; we never echo back
420
+ * full User-Agent strings to avoid surfacing fingerprintable detail
421
+ * in dashboards.
422
+ */
423
+ interface DeviceInfo {
424
+ os?: string;
425
+ osVersion?: string;
426
+ browser?: string;
427
+ browserVersion?: string;
428
+ locale?: string;
429
+ timezone?: string;
430
+ screenWidth?: number;
431
+ screenHeight?: number;
432
+ viewportWidth?: number;
433
+ viewportHeight?: number;
434
+ devicePixelRatio?: number;
435
+ /** Caller-supplied. Set via Crossdeck.start({ appVersion: "1.2.3" }). */
436
+ appVersion?: string;
437
+ }
438
+
439
+ export { type AliasResult, type AuditRail, type AutoTrackOptions, Crossdeck, CrossdeckClient, CrossdeckError, type CrossdeckErrorPayload, type CrossdeckErrorType, type CrossdeckOptions, DEFAULT_BASE_URL, type DeviceInfo, type Diagnostics, type EntitlementsListResponse, type Environment, type EventProperties, type HeartbeatResponse, type IdentifyOptions, type KeyValueStorage, MemoryStorage, type Platform, type PublicEntitlement, type PurchaseResult, SDK_NAME, SDK_VERSION };