@cross-deck/web 1.10.2 → 1.11.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.
@@ -106,6 +106,20 @@ interface CrossdeckOptions {
106
106
  storage?: KeyValueStorage;
107
107
  /** Storage key prefix for the SDK's persisted state. Default "crossdeck:". */
108
108
  storagePrefix?: string;
109
+ /**
110
+ * Cross-subdomain identity. The anonymous-ID cookie is scoped to this domain so
111
+ * a visitor is ONE person across every subdomain — your marketing site
112
+ * (`example.com`) and your app (`app.example.com`) share one identity, so
113
+ * first-touch source, journey, and conversion stitch into one timeline.
114
+ *
115
+ * - `"auto"` (default) — the registrable domain (eTLD+1), detected safely.
116
+ * - a domain string (`".example.com"` / `"example.com"`) — set it explicitly.
117
+ * - `"none"` — host-only (each subdomain is its own identity; pre-1.11 behaviour).
118
+ *
119
+ * No effect in Node/native — cookies + subdomains are browser-only. Cross-*device*
120
+ * / cross-platform identity is resolved server-side by email/userId, not here.
121
+ */
122
+ cookieDomain?: string;
109
123
  /**
110
124
  * Send a heartbeat to /v1/sdk/heartbeat on start(). Default true.
111
125
  * Disable for high-frequency boot scenarios where the heartbeat is
@@ -106,6 +106,20 @@ interface CrossdeckOptions {
106
106
  storage?: KeyValueStorage;
107
107
  /** Storage key prefix for the SDK's persisted state. Default "crossdeck:". */
108
108
  storagePrefix?: string;
109
+ /**
110
+ * Cross-subdomain identity. The anonymous-ID cookie is scoped to this domain so
111
+ * a visitor is ONE person across every subdomain — your marketing site
112
+ * (`example.com`) and your app (`app.example.com`) share one identity, so
113
+ * first-touch source, journey, and conversion stitch into one timeline.
114
+ *
115
+ * - `"auto"` (default) — the registrable domain (eTLD+1), detected safely.
116
+ * - a domain string (`".example.com"` / `"example.com"`) — set it explicitly.
117
+ * - `"none"` — host-only (each subdomain is its own identity; pre-1.11 behaviour).
118
+ *
119
+ * No effect in Node/native — cookies + subdomains are browser-only. Cross-*device*
120
+ * / cross-platform identity is resolved server-side by email/userId, not here.
121
+ */
122
+ cookieDomain?: string;
109
123
  /**
110
124
  * Send a heartbeat to /v1/sdk/heartbeat on start(). Default true.
111
125
  * Disable for high-frequency boot scenarios where the heartbeat is
package/dist/vue.cjs CHANGED
@@ -97,7 +97,7 @@ function typeMapForStatus(status) {
97
97
  }
98
98
 
99
99
  // src/_version.ts
100
- var SDK_VERSION = "1.10.2";
100
+ var SDK_VERSION = "1.11.1";
101
101
  var SDK_NAME = "@cross-deck/web";
102
102
 
103
103
  // src/http.ts
@@ -1325,6 +1325,7 @@ var CookieStorage = class {
1325
1325
  this.maxAgeSec = options?.maxAgeSec ?? 63072e3;
1326
1326
  this.secure = options?.secure ?? defaultSecure();
1327
1327
  this.sameSite = options?.sameSite ?? "Lax";
1328
+ this.domain = options?.domain || void 0;
1328
1329
  }
1329
1330
  getItem(key) {
1330
1331
  if (!hasDocument()) return null;
@@ -1351,6 +1352,7 @@ var CookieStorage = class {
1351
1352
  `Max-Age=${this.maxAgeSec}`,
1352
1353
  `SameSite=${this.sameSite}`
1353
1354
  ];
1355
+ if (this.domain) parts.push(`Domain=${this.domain}`);
1354
1356
  if (this.secure) parts.push("Secure");
1355
1357
  try {
1356
1358
  doc.cookie = parts.join("; ");
@@ -1366,6 +1368,7 @@ var CookieStorage = class {
1366
1368
  "Max-Age=0",
1367
1369
  `SameSite=${this.sameSite}`
1368
1370
  ];
1371
+ if (this.domain) parts.push(`Domain=${this.domain}`);
1369
1372
  if (this.secure) parts.push("Secure");
1370
1373
  try {
1371
1374
  doc.cookie = parts.join("; ");
@@ -1373,6 +1376,34 @@ var CookieStorage = class {
1373
1376
  }
1374
1377
  }
1375
1378
  };
1379
+ function resolveCookieDomain(config) {
1380
+ if (config === void 0 || config === "none" || config === "") return void 0;
1381
+ if (config !== "auto") {
1382
+ const d = config.trim().toLowerCase();
1383
+ return d.startsWith(".") ? d : `.${d}`;
1384
+ }
1385
+ if (!hasDocument()) return void 0;
1386
+ const doc = globalThis.document;
1387
+ const loc = globalThis.location;
1388
+ const host = (loc?.hostname ?? "").toLowerCase();
1389
+ if (!host || host === "localhost" || /^\d{1,3}(\.\d{1,3}){3}$/.test(host) || host.indexOf(".") === -1) {
1390
+ return void 0;
1391
+ }
1392
+ const labels = host.split(".");
1393
+ for (let i = labels.length - 2; i >= 0; i--) {
1394
+ const candidate = "." + labels.slice(i).join(".");
1395
+ const testKey = "__cd_domain_probe";
1396
+ try {
1397
+ doc.cookie = `${testKey}=1; Domain=${candidate}; Path=/; SameSite=Lax`;
1398
+ const accepted = doc.cookie.indexOf(`${testKey}=1`) !== -1;
1399
+ doc.cookie = `${testKey}=; Domain=${candidate}; Path=/; Max-Age=0; SameSite=Lax`;
1400
+ if (accepted) return candidate;
1401
+ } catch {
1402
+ return void 0;
1403
+ }
1404
+ }
1405
+ return void 0;
1406
+ }
1376
1407
  function detectDefaultStorage() {
1377
1408
  try {
1378
1409
  const ls = globalThis.localStorage;
@@ -3836,7 +3867,18 @@ function isInAppFrame(filename) {
3836
3867
  if (/\/crossdeck\.umd\.min\.js$/.test(filename)) return false;
3837
3868
  return true;
3838
3869
  }
3870
+ var BROWSER_INJECTED_GLOBAL = /(__firefox__|__gCrWeb|zaloJSV2)/;
3871
+ function injectedGlobalName(message) {
3872
+ const m = BROWSER_INJECTED_GLOBAL.exec(message ?? "");
3873
+ return m ? m[1] : null;
3874
+ }
3875
+ function demoteVendorInjectedFrames(frames, message) {
3876
+ if (!injectedGlobalName(message)) return frames;
3877
+ return frames.map((f) => f.in_app ? { ...f, in_app: false } : f);
3878
+ }
3839
3879
  function fingerprintError(message, frames, location2) {
3880
+ const injected = injectedGlobalName(message);
3881
+ if (injected) return djb2Hex(`injected-global:${injected}`);
3840
3882
  const inAppFrames = frames.filter((f) => f.in_app).slice(0, 3);
3841
3883
  const parts = [
3842
3884
  (message || "").slice(0, 200),
@@ -4193,7 +4235,7 @@ var ErrorTracker = class {
4193
4235
  const payload = coerceErrorPayload(err);
4194
4236
  const message = (payload.message || event.message || "Unknown error").slice(0, 1024);
4195
4237
  const stack = err instanceof Error ? err.stack ?? null : null;
4196
- const frames = parseStack(stack);
4238
+ const frames = demoteVendorInjectedFrames(parseStack(stack), message);
4197
4239
  const errorType = payload.errorType ?? null;
4198
4240
  const context = payload.extras ? { ...this.opts.getContext(), __error_extras: payload.extras } : this.opts.getContext();
4199
4241
  return {
@@ -4225,7 +4267,7 @@ var ErrorTracker = class {
4225
4267
  const payload = coerceErrorPayload(err);
4226
4268
  const message = (payload.message || "Unknown error").slice(0, 1024);
4227
4269
  const stack = err instanceof Error ? err.stack ?? null : null;
4228
- const frames = parseStack(stack);
4270
+ const frames = demoteVendorInjectedFrames(parseStack(stack), message);
4229
4271
  const errorType = payload.errorType ?? null;
4230
4272
  const context = payload.extras ? { ...this.opts.getContext(), __error_extras: payload.extras } : this.opts.getContext();
4231
4273
  return {
@@ -4641,7 +4683,7 @@ var CrossdeckClient = class {
4641
4683
  const effectiveStorage = persistIdentity ? storage : new MemoryStorage();
4642
4684
  const useCookieRedundancy = persistIdentity && !options.storage && // honour caller's adapter choice
4643
4685
  typeof globalThis.document !== "undefined";
4644
- const cookieStore = useCookieRedundancy ? new CookieStorage() : void 0;
4686
+ const cookieStore = useCookieRedundancy ? new CookieStorage({ domain: resolveCookieDomain(options.cookieDomain ?? "auto") }) : void 0;
4645
4687
  const identity = new IdentityStore(effectiveStorage, opts.storagePrefix, cookieStore);
4646
4688
  const entitlements = new EntitlementCache(
4647
4689
  effectiveStorage,