@cross-deck/web 1.6.4 → 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/CHANGELOG.md +45 -49
- package/dist/contracts.json +12 -12
- 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 +150 -167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.mjs +150 -167
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +139 -156
- package/dist/react.cjs.map +1 -1
- package/dist/react.mjs +139 -156
- package/dist/react.mjs.map +1 -1
- package/dist/vue.cjs +139 -156
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.mjs +139 -156
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/vue.mjs
CHANGED
|
@@ -67,7 +67,7 @@ function typeMapForStatus(status) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// src/_version.ts
|
|
70
|
-
var SDK_VERSION = "1.
|
|
70
|
+
var SDK_VERSION = "1.7.0";
|
|
71
71
|
var SDK_NAME = "@cross-deck/web";
|
|
72
72
|
|
|
73
73
|
// src/http.ts
|
|
@@ -983,9 +983,13 @@ var EventQueue = class {
|
|
|
983
983
|
const env = this.cfg.envelope();
|
|
984
984
|
const result = await this.cfg.http.request("POST", "/events", {
|
|
985
985
|
body: {
|
|
986
|
-
//
|
|
987
|
-
//
|
|
988
|
-
//
|
|
986
|
+
// Event Envelope v1 batch envelope (backend/docs/
|
|
987
|
+
// event-envelope-spec-v1.md §1). `envelopeVersion` is the
|
|
988
|
+
// schema/wire version the server parses against ("can I parse
|
|
989
|
+
// this?") and is DISTINCT from `sdk.version` ("which build is in
|
|
990
|
+
// the wild?") — two questions, two fields, never conflated. The
|
|
991
|
+
// backend refuses payloads with a missing/unknown envelopeVersion.
|
|
992
|
+
envelopeVersion: 1,
|
|
989
993
|
appId: env.appId,
|
|
990
994
|
environment: env.environment,
|
|
991
995
|
sdk: env.sdk,
|
|
@@ -1440,6 +1444,15 @@ var AutoTracker = class {
|
|
|
1440
1444
|
this.cleanups = [];
|
|
1441
1445
|
/** Last time we flushed lastActivityAt to storage (throttle gate). */
|
|
1442
1446
|
this.lastPersistAt = 0;
|
|
1447
|
+
/**
|
|
1448
|
+
* Event Envelope v1 §3 — per-session monotonic sequence counter.
|
|
1449
|
+
* The single owner of the seq counter lives here, alongside all other
|
|
1450
|
+
* session state. Incremented atomically at track() time (via nextSeq()),
|
|
1451
|
+
* reset to 0 whenever a new session boundary is crossed (startNewSession
|
|
1452
|
+
* path + resetSession). Persists across background/foreground within a
|
|
1453
|
+
* session — only a real session boundary (not a tab hide/show) resets it.
|
|
1454
|
+
*/
|
|
1455
|
+
this._sessionSeq = 0;
|
|
1443
1456
|
/**
|
|
1444
1457
|
* Stable per-page-view identifier. Minted at every `page.viewed`
|
|
1445
1458
|
* emission and attached to every subsequent event until the next
|
|
@@ -1524,6 +1537,20 @@ var AutoTracker = class {
|
|
|
1524
1537
|
get currentAcquisition() {
|
|
1525
1538
|
return this.session?.acquisition ?? EMPTY_ACQUISITION;
|
|
1526
1539
|
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Event Envelope v1 §3 — return the next seq value for the current session
|
|
1542
|
+
* and advance the counter. Called SYNCHRONOUSLY at track() time, before any
|
|
1543
|
+
* async dispatch, so the seq assignment order is deterministic (call order,
|
|
1544
|
+
* not scheduler luck). The counter is reset to 0 at every session boundary;
|
|
1545
|
+
* it is NOT reset by tab hide/show (spec §3 clause 1: backgrounding does not
|
|
1546
|
+
* reset seq). When no session is active (Node, before init, after uninstall),
|
|
1547
|
+
* returns 0 and leaves the counter unchanged — fallback, not an error.
|
|
1548
|
+
*/
|
|
1549
|
+
nextSeq() {
|
|
1550
|
+
const seq = this._sessionSeq;
|
|
1551
|
+
this._sessionSeq += 1;
|
|
1552
|
+
return seq;
|
|
1553
|
+
}
|
|
1527
1554
|
// ---------- sessions ----------
|
|
1528
1555
|
installSessionTracking() {
|
|
1529
1556
|
const now = Date.now();
|
|
@@ -1575,6 +1602,7 @@ var AutoTracker = class {
|
|
|
1575
1602
|
}
|
|
1576
1603
|
startNewSession() {
|
|
1577
1604
|
const now = Date.now();
|
|
1605
|
+
this._sessionSeq = 0;
|
|
1578
1606
|
return {
|
|
1579
1607
|
sessionId: mintSessionId(),
|
|
1580
1608
|
startedAt: now,
|
|
@@ -2303,6 +2331,40 @@ function writeJson(storage, key, value) {
|
|
|
2303
2331
|
}
|
|
2304
2332
|
}
|
|
2305
2333
|
|
|
2334
|
+
// src/internal-opt-out.ts
|
|
2335
|
+
var INTERNAL_OPT_OUT_PROPERTY = "$crossdeck_internal";
|
|
2336
|
+
var STORAGE_KEY = "crossdeck.internalOptOut";
|
|
2337
|
+
function localStore() {
|
|
2338
|
+
try {
|
|
2339
|
+
return typeof localStorage !== "undefined" ? localStorage : null;
|
|
2340
|
+
} catch {
|
|
2341
|
+
return null;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
function processInternalOptOutUrl() {
|
|
2345
|
+
try {
|
|
2346
|
+
const search = typeof location !== "undefined" ? location.search : "";
|
|
2347
|
+
const params = new URLSearchParams(search || "");
|
|
2348
|
+
if (!params.has("crossdeck_internal")) return;
|
|
2349
|
+
const store = localStore();
|
|
2350
|
+
if (!store) return;
|
|
2351
|
+
const v = params.get("crossdeck_internal");
|
|
2352
|
+
if (v === "1" || v === "true") {
|
|
2353
|
+
store.setItem(STORAGE_KEY, "1");
|
|
2354
|
+
} else if (v === "0" || v === "false") {
|
|
2355
|
+
store.removeItem(STORAGE_KEY);
|
|
2356
|
+
}
|
|
2357
|
+
} catch {
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
function isInternalOptOut() {
|
|
2361
|
+
try {
|
|
2362
|
+
return localStore()?.getItem(STORAGE_KEY) === "1";
|
|
2363
|
+
} catch {
|
|
2364
|
+
return false;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2306
2368
|
// src/web-vitals.ts
|
|
2307
2369
|
var WebVitalsTracker = class {
|
|
2308
2370
|
constructor(cfg, report) {
|
|
@@ -2833,15 +2895,6 @@ var VerifierReporter = class {
|
|
|
2833
2895
|
constructor(ctx) {
|
|
2834
2896
|
this.ctx = ctx;
|
|
2835
2897
|
this.reentrancyDepth = 0;
|
|
2836
|
-
/** The live verifier set — attached by the SDK right after init so the
|
|
2837
|
-
* emit path can schema-lock its OWN outgoing telemetry against the real
|
|
2838
|
-
* payload. Null until attached (boot-time reports still work without it). */
|
|
2839
|
-
this.verifiers = null;
|
|
2840
|
-
}
|
|
2841
|
-
/** Hand the reporter the live verifier set so `reportFail` can run the
|
|
2842
|
-
* `onReportContractFailure` hook on the exact payload it's about to emit. */
|
|
2843
|
-
attachVerifiers(verifiers) {
|
|
2844
|
-
this.verifiers = verifiers;
|
|
2845
2898
|
}
|
|
2846
2899
|
/**
|
|
2847
2900
|
* Report a verifier result. Pass `operation` for hot-path results
|
|
@@ -2870,7 +2923,7 @@ var VerifierReporter = class {
|
|
|
2870
2923
|
if (this.reentrancyDepth > 0) return;
|
|
2871
2924
|
this.reentrancyDepth += 1;
|
|
2872
2925
|
try {
|
|
2873
|
-
|
|
2926
|
+
this.ctx.emitTelemetry({
|
|
2874
2927
|
contract_id: result.contractId,
|
|
2875
2928
|
sdk_version: this.ctx.sdkVersion,
|
|
2876
2929
|
sdk_platform: "web",
|
|
@@ -2878,13 +2931,7 @@ var VerifierReporter = class {
|
|
|
2878
2931
|
run_context: this.ctx.runContext,
|
|
2879
2932
|
run_id: this.ctx.runId,
|
|
2880
2933
|
verification_phase: phase
|
|
2881
|
-
};
|
|
2882
|
-
if (this.verifiers) {
|
|
2883
|
-
runOnReportContractFailure(this.verifiers, this, this.ctx, {
|
|
2884
|
-
outgoingPayload: payload
|
|
2885
|
-
});
|
|
2886
|
-
}
|
|
2887
|
-
this.ctx.emitTelemetry(payload);
|
|
2934
|
+
});
|
|
2888
2935
|
} finally {
|
|
2889
2936
|
this.reentrancyDepth -= 1;
|
|
2890
2937
|
}
|
|
@@ -3174,31 +3221,9 @@ var VERIFIER_FLUSH_INTERVAL_PARITY = {
|
|
|
3174
3221
|
"eventFlushIntervalMs default = 2000ms (Web/Node/RN/Swift/Android parity)",
|
|
3175
3222
|
nowMs() - t0
|
|
3176
3223
|
);
|
|
3177
|
-
},
|
|
3178
|
-
// Hot-path hook — on every real track() we re-affirm the LIVE configured
|
|
3179
|
-
// flush interval (carried on the observation), so the parity guarantee is
|
|
3180
|
-
// verified against the running SDK in the customer flow, not just a
|
|
3181
|
-
// canonical constant at boot. It can't change per-event, but observing it
|
|
3182
|
-
// per-event is what makes the contract genuinely runtime-verified.
|
|
3183
|
-
hooks: {
|
|
3184
|
-
onTrack(obs) {
|
|
3185
|
-
const t0 = nowMs();
|
|
3186
|
-
const CANONICAL_DEFAULT_MS = 2e3;
|
|
3187
|
-
const ms = obs.flushIntervalMs;
|
|
3188
|
-
if (typeof ms !== "number" || ms < 100 || ms > 6e4) {
|
|
3189
|
-
return fail(
|
|
3190
|
-
"flush-interval-parity",
|
|
3191
|
-
`live eventFlushIntervalMs=${ms} outside reasonable bounds [100, 60000]`,
|
|
3192
|
-
nowMs() - t0
|
|
3193
|
-
);
|
|
3194
|
-
}
|
|
3195
|
-
return pass(
|
|
3196
|
-
"flush-interval-parity",
|
|
3197
|
-
ms === CANONICAL_DEFAULT_MS ? "live eventFlushIntervalMs = 2000ms (canonical parity value)" : `live eventFlushIntervalMs = ${ms}ms (permitted override; canonical default 2000ms)`,
|
|
3198
|
-
nowMs() - t0
|
|
3199
|
-
);
|
|
3200
|
-
}
|
|
3201
3224
|
}
|
|
3225
|
+
// No hot-path hook — the flush interval is set once at start() and
|
|
3226
|
+
// never changes per-operation.
|
|
3202
3227
|
};
|
|
3203
3228
|
function buildFlushIntervalVerifier(configuredIntervalMs) {
|
|
3204
3229
|
return {
|
|
@@ -3325,26 +3350,6 @@ var CONTRACT_FAILED_FORBIDDEN_FIELDS = [
|
|
|
3325
3350
|
"referrer",
|
|
3326
3351
|
"deviceId"
|
|
3327
3352
|
];
|
|
3328
|
-
function contractFailedSchemaViolation(keys) {
|
|
3329
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
3330
|
-
...CONTRACT_FAILED_REQUIRED_FIELDS,
|
|
3331
|
-
...CONTRACT_FAILED_OPTIONAL_FIELDS
|
|
3332
|
-
]);
|
|
3333
|
-
const forbidden = new Set(CONTRACT_FAILED_FORBIDDEN_FIELDS);
|
|
3334
|
-
for (const required of CONTRACT_FAILED_REQUIRED_FIELDS) {
|
|
3335
|
-
if (!keys.includes(required)) return `missing required field: ${required}`;
|
|
3336
|
-
}
|
|
3337
|
-
for (const k of keys) {
|
|
3338
|
-
if (forbidden.has(k)) return `forbidden field on wire: ${k}`;
|
|
3339
|
-
}
|
|
3340
|
-
for (const k of keys) {
|
|
3341
|
-
if (!allowed.has(k)) {
|
|
3342
|
-
return `unrecognised field on wire: ${k} (not in required \u222A optional)`;
|
|
3343
|
-
}
|
|
3344
|
-
}
|
|
3345
|
-
return null;
|
|
3346
|
-
}
|
|
3347
|
-
var CONTRACT_FAILED_OK_EVIDENCE = `fields \u2286 required(${CONTRACT_FAILED_REQUIRED_FIELDS.length}) \u222A optional(${CONTRACT_FAILED_OPTIONAL_FIELDS.length}); ${CONTRACT_FAILED_FORBIDDEN_FIELDS.length} forbidden absent`;
|
|
3348
3353
|
var VERIFIER_CONTRACT_FAILED_PAYLOAD_SCHEMA_LOCK = {
|
|
3349
3354
|
contractId: "contract-failed-payload-schema-lock",
|
|
3350
3355
|
bootTest() {
|
|
@@ -3359,35 +3364,43 @@ var VERIFIER_CONTRACT_FAILED_PAYLOAD_SCHEMA_LOCK = {
|
|
|
3359
3364
|
verification_phase: "boot"
|
|
3360
3365
|
};
|
|
3361
3366
|
const keys = Object.keys(syntheticPayload);
|
|
3362
|
-
const
|
|
3363
|
-
|
|
3364
|
-
|
|
3367
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
3368
|
+
...CONTRACT_FAILED_REQUIRED_FIELDS,
|
|
3369
|
+
...CONTRACT_FAILED_OPTIONAL_FIELDS
|
|
3370
|
+
]);
|
|
3371
|
+
const forbidden = new Set(CONTRACT_FAILED_FORBIDDEN_FIELDS);
|
|
3372
|
+
for (const required of CONTRACT_FAILED_REQUIRED_FIELDS) {
|
|
3373
|
+
if (!keys.includes(required)) {
|
|
3374
|
+
return fail(
|
|
3375
|
+
"contract-failed-payload-schema-lock",
|
|
3376
|
+
`missing required field: ${required}`,
|
|
3377
|
+
nowMs() - t0
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
for (const k of keys) {
|
|
3382
|
+
if (forbidden.has(k)) {
|
|
3383
|
+
return fail(
|
|
3384
|
+
"contract-failed-payload-schema-lock",
|
|
3385
|
+
`forbidden field on wire: ${k}`,
|
|
3386
|
+
nowMs() - t0
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
for (const k of keys) {
|
|
3391
|
+
if (!allowed.has(k)) {
|
|
3392
|
+
return fail(
|
|
3393
|
+
"contract-failed-payload-schema-lock",
|
|
3394
|
+
`unrecognised field on wire: ${k} (not in required \u222A optional)`,
|
|
3395
|
+
nowMs() - t0
|
|
3396
|
+
);
|
|
3397
|
+
}
|
|
3365
3398
|
}
|
|
3366
3399
|
return pass(
|
|
3367
3400
|
"contract-failed-payload-schema-lock",
|
|
3368
|
-
`${keys.length} ${
|
|
3401
|
+
`${keys.length} fields \u2286 required(${CONTRACT_FAILED_REQUIRED_FIELDS.length}) \u222A optional(${CONTRACT_FAILED_OPTIONAL_FIELDS.length}); ${CONTRACT_FAILED_FORBIDDEN_FIELDS.length} forbidden absent`,
|
|
3369
3402
|
nowMs() - t0
|
|
3370
3403
|
);
|
|
3371
|
-
},
|
|
3372
|
-
// Hot-path hook — fires on the REAL reportFail emit (VerifierReporter,
|
|
3373
|
-
// inside the re-entrancy guard) against the exact payload about to go on
|
|
3374
|
-
// the wire. This is the assertion the guard at reportFail was built in
|
|
3375
|
-
// anticipation of: every reliability-channel write is schema-locked in the
|
|
3376
|
-
// field, against real data, not just the synthetic boot mirror.
|
|
3377
|
-
hooks: {
|
|
3378
|
-
onReportContractFailure(obs) {
|
|
3379
|
-
const t0 = nowMs();
|
|
3380
|
-
const keys = Object.keys(obs.outgoingPayload);
|
|
3381
|
-
const violation = contractFailedSchemaViolation(keys);
|
|
3382
|
-
if (violation) {
|
|
3383
|
-
return fail("contract-failed-payload-schema-lock", violation, nowMs() - t0);
|
|
3384
|
-
}
|
|
3385
|
-
return pass(
|
|
3386
|
-
"contract-failed-payload-schema-lock",
|
|
3387
|
-
`${keys.length} ${CONTRACT_FAILED_OK_EVIDENCE}`,
|
|
3388
|
-
nowMs() - t0
|
|
3389
|
-
);
|
|
3390
|
-
}
|
|
3391
3404
|
}
|
|
3392
3405
|
};
|
|
3393
3406
|
var BACKEND_WIRE_CODES = Object.freeze([
|
|
@@ -3438,39 +3451,6 @@ var VERIFIER_SDK_ERROR_CODES_CATALOGUE = {
|
|
|
3438
3451
|
nowMs() - t0
|
|
3439
3452
|
);
|
|
3440
3453
|
}
|
|
3441
|
-
},
|
|
3442
|
-
// Hot-path hook — when the SDK parses a real wire error, assert the code
|
|
3443
|
-
// the customer actually hit carries usable remediation in the shipped
|
|
3444
|
-
// catalogue. Scoped to BACKEND_WIRE_CODES (the contract's set); other
|
|
3445
|
-
// codes are out of scope and pass. This turns the catalogue from a
|
|
3446
|
-
// boot-only completeness claim into a per-error field assertion: a backend
|
|
3447
|
-
// code that ships without remediation is caught the first time a customer
|
|
3448
|
-
// hits it, not only if the off-by-default boot self-test ran.
|
|
3449
|
-
hooks: {
|
|
3450
|
-
onErrorParse(obs) {
|
|
3451
|
-
const t0 = nowMs();
|
|
3452
|
-
const code = obs.errorCode;
|
|
3453
|
-
if (!code || !BACKEND_WIRE_CODES.includes(code)) {
|
|
3454
|
-
return pass(
|
|
3455
|
-
"sdk-error-codes-catalogue",
|
|
3456
|
-
`wire code "${code || "(none)"}" is out of the backend-catalogue scope`,
|
|
3457
|
-
nowMs() - t0
|
|
3458
|
-
);
|
|
3459
|
-
}
|
|
3460
|
-
const entry = getErrorCode(code);
|
|
3461
|
-
if (!entry || !entry.description || entry.description.trim().length === 0 || !entry.resolution || entry.resolution.trim().length === 0) {
|
|
3462
|
-
return fail(
|
|
3463
|
-
"sdk-error-codes-catalogue",
|
|
3464
|
-
`backend wire code "${code}" hit in the field has no description+resolution in the shipped catalogue`,
|
|
3465
|
-
nowMs() - t0
|
|
3466
|
-
);
|
|
3467
|
-
}
|
|
3468
|
-
return pass(
|
|
3469
|
-
"sdk-error-codes-catalogue",
|
|
3470
|
-
`backend wire code "${code}" carries description + resolution`,
|
|
3471
|
-
nowMs() - t0
|
|
3472
|
-
);
|
|
3473
|
-
}
|
|
3474
3454
|
}
|
|
3475
3455
|
};
|
|
3476
3456
|
var STATIC_VERIFIERS = Object.freeze([
|
|
@@ -3594,24 +3574,6 @@ function runOnErrorParse(verifiers, reporter, ctx, obs) {
|
|
|
3594
3574
|
reporter.report(result, "hot_path", "errorParse");
|
|
3595
3575
|
}
|
|
3596
3576
|
}
|
|
3597
|
-
function runOnReportContractFailure(verifiers, reporter, ctx, obs) {
|
|
3598
|
-
if (ctx.disableContractAssertions) return;
|
|
3599
|
-
for (const verifier of verifiers) {
|
|
3600
|
-
const hook = verifier.hooks?.onReportContractFailure;
|
|
3601
|
-
if (!hook) continue;
|
|
3602
|
-
let result;
|
|
3603
|
-
try {
|
|
3604
|
-
result = hook(obs);
|
|
3605
|
-
} catch (err) {
|
|
3606
|
-
result = fail(
|
|
3607
|
-
verifier.contractId,
|
|
3608
|
-
`hook threw: ${err.message?.slice(0, 80) ?? "unknown"}`,
|
|
3609
|
-
0
|
|
3610
|
-
);
|
|
3611
|
-
}
|
|
3612
|
-
reporter.report(result, "hot_path", "reportContractFailure");
|
|
3613
|
-
}
|
|
3614
|
-
}
|
|
3615
3577
|
function defaultDebugModeFlag() {
|
|
3616
3578
|
try {
|
|
3617
3579
|
if (typeof process !== "undefined" && process.env) {
|
|
@@ -3763,18 +3725,18 @@ function isInAppFrame(filename) {
|
|
|
3763
3725
|
if (/\/crossdeck\.umd\.min\.js$/.test(filename)) return false;
|
|
3764
3726
|
return true;
|
|
3765
3727
|
}
|
|
3766
|
-
function fingerprintError(message, frames,
|
|
3728
|
+
function fingerprintError(message, frames, location2) {
|
|
3767
3729
|
const inAppFrames = frames.filter((f) => f.in_app).slice(0, 3);
|
|
3768
3730
|
const parts = [
|
|
3769
3731
|
(message || "").slice(0, 200),
|
|
3770
3732
|
...inAppFrames.map((f) => `${f.function}@${f.filename}:${f.lineno}`)
|
|
3771
3733
|
];
|
|
3772
|
-
if (inAppFrames.length === 0 &&
|
|
3734
|
+
if (inAppFrames.length === 0 && location2) {
|
|
3773
3735
|
const loc = [
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3736
|
+
location2.errorType ?? "",
|
|
3737
|
+
location2.filename ?? "",
|
|
3738
|
+
location2.lineno ?? "",
|
|
3739
|
+
location2.colno ?? ""
|
|
3778
3740
|
].join(":");
|
|
3779
3741
|
if (loc !== ":::") parts.push(loc);
|
|
3780
3742
|
}
|
|
@@ -4444,9 +4406,6 @@ var CrossdeckClient = class {
|
|
|
4444
4406
|
this.verifiers = null;
|
|
4445
4407
|
this.verifierReporter = null;
|
|
4446
4408
|
this.verifierCtx = null;
|
|
4447
|
-
// The live configured event-flush interval, surfaced to the track-path
|
|
4448
|
-
// verifier so flush-interval-parity validates the real cadence per event.
|
|
4449
|
-
this.flushIntervalMs = 2e3;
|
|
4450
4409
|
}
|
|
4451
4410
|
/**
|
|
4452
4411
|
* Boot the SDK. Idempotent — calling init twice with the same options
|
|
@@ -4623,6 +4582,7 @@ var CrossdeckClient = class {
|
|
|
4623
4582
|
persistIdentity ? effectiveStorage : new MemoryStorage(),
|
|
4624
4583
|
opts.storagePrefix
|
|
4625
4584
|
);
|
|
4585
|
+
processInternalOptOutUrl();
|
|
4626
4586
|
const consent = new ConsentManager({ respectDnt: options.respectDnt === true });
|
|
4627
4587
|
if (consent.isDntDenied) {
|
|
4628
4588
|
debug.emit(
|
|
@@ -4726,8 +4686,6 @@ var CrossdeckClient = class {
|
|
|
4726
4686
|
this.verifierReporter = new VerifierReporter(this.verifierCtx);
|
|
4727
4687
|
const flushVerifier = buildFlushIntervalVerifier(opts.eventFlushIntervalMs);
|
|
4728
4688
|
this.verifiers = Object.freeze([...STATIC_VERIFIERS, flushVerifier]);
|
|
4729
|
-
this.flushIntervalMs = opts.eventFlushIntervalMs;
|
|
4730
|
-
this.verifierReporter.attachVerifiers(this.verifiers);
|
|
4731
4689
|
if (localDevMode) {
|
|
4732
4690
|
const verifyAtBootLocal = options.verifyContractsAtBoot ?? debugDefault;
|
|
4733
4691
|
if (verifyAtBootLocal && this.verifierReporter) {
|
|
@@ -5278,8 +5236,27 @@ var CrossdeckClient = class {
|
|
|
5278
5236
|
);
|
|
5279
5237
|
}
|
|
5280
5238
|
}
|
|
5239
|
+
const seq = s.autoTracker?.nextSeq() ?? 0;
|
|
5240
|
+
const occurrenceTimestamp = Date.now();
|
|
5281
5241
|
s.autoTracker?.markActivity();
|
|
5282
|
-
const
|
|
5242
|
+
const wireContext = {};
|
|
5243
|
+
const di = s.deviceInfo;
|
|
5244
|
+
if (di.os) wireContext.os = di.os;
|
|
5245
|
+
if (di.osVersion) wireContext.osVersion = di.osVersion;
|
|
5246
|
+
const appVer = s.options.appVersion;
|
|
5247
|
+
if (appVer) wireContext.appVersion = appVer;
|
|
5248
|
+
wireContext.sdkName = SDK_NAME;
|
|
5249
|
+
wireContext.sdkVersion = s.options.sdkVersion;
|
|
5250
|
+
if (di.locale) wireContext.locale = di.locale;
|
|
5251
|
+
if (di.timezone) wireContext.timezone = di.timezone;
|
|
5252
|
+
if (di.browser) wireContext.browser = di.browser;
|
|
5253
|
+
if (di.browserVersion) wireContext.browserVersion = di.browserVersion;
|
|
5254
|
+
const enriched = {};
|
|
5255
|
+
if (di.screenWidth !== void 0) enriched.screenWidth = di.screenWidth;
|
|
5256
|
+
if (di.screenHeight !== void 0) enriched.screenHeight = di.screenHeight;
|
|
5257
|
+
if (di.viewportWidth !== void 0) enriched.viewportWidth = di.viewportWidth;
|
|
5258
|
+
if (di.viewportHeight !== void 0) enriched.viewportHeight = di.viewportHeight;
|
|
5259
|
+
if (di.devicePixelRatio !== void 0) enriched.devicePixelRatio = di.devicePixelRatio;
|
|
5283
5260
|
const sessionId = s.autoTracker?.currentSessionId;
|
|
5284
5261
|
if (sessionId) enriched.sessionId = sessionId;
|
|
5285
5262
|
const pageviewId = s.autoTracker?.currentPageviewId;
|
|
@@ -5302,17 +5279,24 @@ var CrossdeckClient = class {
|
|
|
5302
5279
|
}
|
|
5303
5280
|
}
|
|
5304
5281
|
const supers = s.superProps.getSuperProperties();
|
|
5305
|
-
Object.
|
|
5282
|
+
for (const k of Object.keys(supers)) {
|
|
5283
|
+
if (!(k in enriched)) enriched[k] = supers[k];
|
|
5284
|
+
}
|
|
5306
5285
|
const groupIds = s.superProps.getGroupIds();
|
|
5307
5286
|
if (Object.keys(groupIds).length > 0) {
|
|
5308
5287
|
enriched.$groups = groupIds;
|
|
5309
5288
|
}
|
|
5310
5289
|
Object.assign(enriched, validation.properties);
|
|
5290
|
+
if (isInternalOptOut()) {
|
|
5291
|
+
enriched[INTERNAL_OPT_OUT_PROPERTY] = true;
|
|
5292
|
+
}
|
|
5311
5293
|
const finalProperties = s.scrubPii ? scrubPiiFromProperties(enriched) : enriched;
|
|
5312
5294
|
const event = {
|
|
5313
5295
|
eventId: this.mintEventId(),
|
|
5314
5296
|
name,
|
|
5315
|
-
timestamp:
|
|
5297
|
+
timestamp: occurrenceTimestamp,
|
|
5298
|
+
seq,
|
|
5299
|
+
context: wireContext,
|
|
5316
5300
|
properties: finalProperties
|
|
5317
5301
|
};
|
|
5318
5302
|
Object.assign(event, this.identityHintForEvent());
|
|
@@ -5322,8 +5306,7 @@ var CrossdeckClient = class {
|
|
|
5322
5306
|
callerProperties: validation.properties,
|
|
5323
5307
|
superProperties: supers,
|
|
5324
5308
|
deviceProperties: s.deviceInfo,
|
|
5325
|
-
mergedProperties: enriched
|
|
5326
|
-
flushIntervalMs: this.flushIntervalMs
|
|
5309
|
+
mergedProperties: enriched
|
|
5327
5310
|
});
|
|
5328
5311
|
}
|
|
5329
5312
|
if (!isError && !isWebVital) {
|