@cross-deck/web 1.6.3 → 1.7.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/dist/vue.cjs CHANGED
@@ -92,7 +92,7 @@ function typeMapForStatus(status) {
92
92
  }
93
93
 
94
94
  // src/_version.ts
95
- var SDK_VERSION = "1.6.3";
95
+ var SDK_VERSION = "1.7.0";
96
96
  var SDK_NAME = "@cross-deck/web";
97
97
 
98
98
  // src/http.ts
@@ -1008,9 +1008,13 @@ var EventQueue = class {
1008
1008
  const env = this.cfg.envelope();
1009
1009
  const result = await this.cfg.http.request("POST", "/events", {
1010
1010
  body: {
1011
- // NorthStar §13.1 batch envelope. The backend validates these
1012
- // against the API-key-resolved app and rejects mismatches
1013
- // loudly (env_mismatch).
1011
+ // Event Envelope v1 batch envelope (backend/docs/
1012
+ // event-envelope-spec-v1.md §1). `envelopeVersion` is the
1013
+ // schema/wire version the server parses against ("can I parse
1014
+ // this?") and is DISTINCT from `sdk.version` ("which build is in
1015
+ // the wild?") — two questions, two fields, never conflated. The
1016
+ // backend refuses payloads with a missing/unknown envelopeVersion.
1017
+ envelopeVersion: 1,
1014
1018
  appId: env.appId,
1015
1019
  environment: env.environment,
1016
1020
  sdk: env.sdk,
@@ -1465,6 +1469,15 @@ var AutoTracker = class {
1465
1469
  this.cleanups = [];
1466
1470
  /** Last time we flushed lastActivityAt to storage (throttle gate). */
1467
1471
  this.lastPersistAt = 0;
1472
+ /**
1473
+ * Event Envelope v1 §3 — per-session monotonic sequence counter.
1474
+ * The single owner of the seq counter lives here, alongside all other
1475
+ * session state. Incremented atomically at track() time (via nextSeq()),
1476
+ * reset to 0 whenever a new session boundary is crossed (startNewSession
1477
+ * path + resetSession). Persists across background/foreground within a
1478
+ * session — only a real session boundary (not a tab hide/show) resets it.
1479
+ */
1480
+ this._sessionSeq = 0;
1468
1481
  /**
1469
1482
  * Stable per-page-view identifier. Minted at every `page.viewed`
1470
1483
  * emission and attached to every subsequent event until the next
@@ -1549,6 +1562,20 @@ var AutoTracker = class {
1549
1562
  get currentAcquisition() {
1550
1563
  return this.session?.acquisition ?? EMPTY_ACQUISITION;
1551
1564
  }
1565
+ /**
1566
+ * Event Envelope v1 §3 — return the next seq value for the current session
1567
+ * and advance the counter. Called SYNCHRONOUSLY at track() time, before any
1568
+ * async dispatch, so the seq assignment order is deterministic (call order,
1569
+ * not scheduler luck). The counter is reset to 0 at every session boundary;
1570
+ * it is NOT reset by tab hide/show (spec §3 clause 1: backgrounding does not
1571
+ * reset seq). When no session is active (Node, before init, after uninstall),
1572
+ * returns 0 and leaves the counter unchanged — fallback, not an error.
1573
+ */
1574
+ nextSeq() {
1575
+ const seq = this._sessionSeq;
1576
+ this._sessionSeq += 1;
1577
+ return seq;
1578
+ }
1552
1579
  // ---------- sessions ----------
1553
1580
  installSessionTracking() {
1554
1581
  const now = Date.now();
@@ -1600,6 +1627,7 @@ var AutoTracker = class {
1600
1627
  }
1601
1628
  startNewSession() {
1602
1629
  const now = Date.now();
1630
+ this._sessionSeq = 0;
1603
1631
  return {
1604
1632
  sessionId: mintSessionId(),
1605
1633
  startedAt: now,
@@ -2328,6 +2356,40 @@ function writeJson(storage, key, value) {
2328
2356
  }
2329
2357
  }
2330
2358
 
2359
+ // src/internal-opt-out.ts
2360
+ var INTERNAL_OPT_OUT_PROPERTY = "$crossdeck_internal";
2361
+ var STORAGE_KEY = "crossdeck.internalOptOut";
2362
+ function localStore() {
2363
+ try {
2364
+ return typeof localStorage !== "undefined" ? localStorage : null;
2365
+ } catch {
2366
+ return null;
2367
+ }
2368
+ }
2369
+ function processInternalOptOutUrl() {
2370
+ try {
2371
+ const search = typeof location !== "undefined" ? location.search : "";
2372
+ const params = new URLSearchParams(search || "");
2373
+ if (!params.has("crossdeck_internal")) return;
2374
+ const store = localStore();
2375
+ if (!store) return;
2376
+ const v = params.get("crossdeck_internal");
2377
+ if (v === "1" || v === "true") {
2378
+ store.setItem(STORAGE_KEY, "1");
2379
+ } else if (v === "0" || v === "false") {
2380
+ store.removeItem(STORAGE_KEY);
2381
+ }
2382
+ } catch {
2383
+ }
2384
+ }
2385
+ function isInternalOptOut() {
2386
+ try {
2387
+ return localStore()?.getItem(STORAGE_KEY) === "1";
2388
+ } catch {
2389
+ return false;
2390
+ }
2391
+ }
2392
+
2331
2393
  // src/web-vitals.ts
2332
2394
  var WebVitalsTracker = class {
2333
2395
  constructor(cfg, report) {
@@ -3688,18 +3750,18 @@ function isInAppFrame(filename) {
3688
3750
  if (/\/crossdeck\.umd\.min\.js$/.test(filename)) return false;
3689
3751
  return true;
3690
3752
  }
3691
- function fingerprintError(message, frames, location) {
3753
+ function fingerprintError(message, frames, location2) {
3692
3754
  const inAppFrames = frames.filter((f) => f.in_app).slice(0, 3);
3693
3755
  const parts = [
3694
3756
  (message || "").slice(0, 200),
3695
3757
  ...inAppFrames.map((f) => `${f.function}@${f.filename}:${f.lineno}`)
3696
3758
  ];
3697
- if (inAppFrames.length === 0 && location) {
3759
+ if (inAppFrames.length === 0 && location2) {
3698
3760
  const loc = [
3699
- location.errorType ?? "",
3700
- location.filename ?? "",
3701
- location.lineno ?? "",
3702
- location.colno ?? ""
3761
+ location2.errorType ?? "",
3762
+ location2.filename ?? "",
3763
+ location2.lineno ?? "",
3764
+ location2.colno ?? ""
3703
3765
  ].join(":");
3704
3766
  if (loc !== ":::") parts.push(loc);
3705
3767
  }
@@ -4545,6 +4607,7 @@ var CrossdeckClient = class {
4545
4607
  persistIdentity ? effectiveStorage : new MemoryStorage(),
4546
4608
  opts.storagePrefix
4547
4609
  );
4610
+ processInternalOptOutUrl();
4548
4611
  const consent = new ConsentManager({ respectDnt: options.respectDnt === true });
4549
4612
  if (consent.isDntDenied) {
4550
4613
  debug.emit(
@@ -5198,8 +5261,27 @@ var CrossdeckClient = class {
5198
5261
  );
5199
5262
  }
5200
5263
  }
5264
+ const seq = s.autoTracker?.nextSeq() ?? 0;
5265
+ const occurrenceTimestamp = Date.now();
5201
5266
  s.autoTracker?.markActivity();
5202
- const enriched = { ...s.deviceInfo };
5267
+ const wireContext = {};
5268
+ const di = s.deviceInfo;
5269
+ if (di.os) wireContext.os = di.os;
5270
+ if (di.osVersion) wireContext.osVersion = di.osVersion;
5271
+ const appVer = s.options.appVersion;
5272
+ if (appVer) wireContext.appVersion = appVer;
5273
+ wireContext.sdkName = SDK_NAME;
5274
+ wireContext.sdkVersion = s.options.sdkVersion;
5275
+ if (di.locale) wireContext.locale = di.locale;
5276
+ if (di.timezone) wireContext.timezone = di.timezone;
5277
+ if (di.browser) wireContext.browser = di.browser;
5278
+ if (di.browserVersion) wireContext.browserVersion = di.browserVersion;
5279
+ const enriched = {};
5280
+ if (di.screenWidth !== void 0) enriched.screenWidth = di.screenWidth;
5281
+ if (di.screenHeight !== void 0) enriched.screenHeight = di.screenHeight;
5282
+ if (di.viewportWidth !== void 0) enriched.viewportWidth = di.viewportWidth;
5283
+ if (di.viewportHeight !== void 0) enriched.viewportHeight = di.viewportHeight;
5284
+ if (di.devicePixelRatio !== void 0) enriched.devicePixelRatio = di.devicePixelRatio;
5203
5285
  const sessionId = s.autoTracker?.currentSessionId;
5204
5286
  if (sessionId) enriched.sessionId = sessionId;
5205
5287
  const pageviewId = s.autoTracker?.currentPageviewId;
@@ -5230,11 +5312,16 @@ var CrossdeckClient = class {
5230
5312
  enriched.$groups = groupIds;
5231
5313
  }
5232
5314
  Object.assign(enriched, validation.properties);
5315
+ if (isInternalOptOut()) {
5316
+ enriched[INTERNAL_OPT_OUT_PROPERTY] = true;
5317
+ }
5233
5318
  const finalProperties = s.scrubPii ? scrubPiiFromProperties(enriched) : enriched;
5234
5319
  const event = {
5235
5320
  eventId: this.mintEventId(),
5236
5321
  name,
5237
- timestamp: Date.now(),
5322
+ timestamp: occurrenceTimestamp,
5323
+ seq,
5324
+ context: wireContext,
5238
5325
  properties: finalProperties
5239
5326
  };
5240
5327
  Object.assign(event, this.identityHintForEvent());