@wireai/activation 0.11.0 → 0.12.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/AGENTS.md +62 -8
- package/CHANGELOG.md +188 -3
- package/INTEGRATION_PROMPT.md +25 -2
- package/README.md +112 -1
- package/dist/analytics/index.d.mts +18 -6
- package/dist/analytics/index.d.ts +18 -6
- package/dist/analytics/index.js +151 -41
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +147 -42
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/coachmarks/index.d.mts +16 -0
- package/dist/coachmarks/index.d.ts +16 -0
- package/dist/coachmarks/index.js +19 -13
- package/dist/coachmarks/index.js.map +1 -1
- package/dist/coachmarks/index.mjs +19 -13
- package/dist/coachmarks/index.mjs.map +1 -1
- package/dist/{currentSession-C0_odnIW.d.mts → currentSession-BlCeDP0f.d.mts} +145 -33
- package/dist/{currentSession-DdnUq2HQ.d.ts → currentSession-BxEB37xt.d.ts} +145 -33
- package/dist/index.d.mts +243 -53
- package/dist/index.d.ts +243 -53
- package/dist/index.js +531 -156
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +517 -157
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +1 -1
- package/dist/questionnaire/index.d.ts +1 -1
- package/dist/questionnaire/index.js +79 -14
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +79 -14
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.d.mts +2 -2
- package/dist/reviews/index.d.ts +2 -2
- package/dist/reviews/index.js +103 -16
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +103 -16
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/showcase/index.js +15 -6
- package/dist/showcase/index.js.map +1 -1
- package/dist/showcase/index.mjs +15 -6
- package/dist/showcase/index.mjs.map +1 -1
- package/dist/{transport-BGW9uXZJ.d.mts → transport-CF_eHwzC.d.mts} +15 -1
- package/dist/{transport-jUJd5kxu.d.ts → transport-DsRe4epC.d.ts} +15 -1
- package/llms.txt +3 -0
- package/package.json +1 -1
- package/src/WireOnboarding.tsx +140 -5
- package/src/activation/useWireActivation.ts +12 -1
- package/src/activation/wireActivation.ts +44 -25
- package/src/analytics/analyticsFacade.ts +54 -29
- package/src/analytics/currentSession.ts +83 -0
- package/src/analytics/eventQueue.ts +9 -1
- package/src/analytics/index.ts +20 -1
- package/src/analytics/reportClientEvent.ts +42 -0
- package/src/analytics/screenTracking.ts +6 -1
- package/src/analytics/useAnalytics.ts +22 -1
- package/src/coachmarks/runtime.ts +53 -17
- package/src/config/wireConfigFromEnv.ts +46 -2
- package/src/context/deviceId.ts +173 -0
- package/src/context/userContext.ts +18 -0
- package/src/index.ts +54 -2
- package/src/questionnaire/runtime.ts +13 -2
- package/src/questionnaire/useQuestionnaireGate.ts +11 -4
- package/src/revenuecat/index.ts +55 -0
- package/src/revenuecat/purchaseEvents.ts +167 -0
- package/src/revenuecat/revenueCatBridge.ts +221 -0
- package/src/revenuecat/types.ts +95 -0
- package/src/reviews/runtime.ts +153 -1
- package/src/reviews/transport.ts +21 -2
- package/src/reviews/useReviewGate.ts +14 -4
- package/src/session-analytics/lifecycle.ts +9 -2
- package/src/session-analytics/reportSessionStart.ts +15 -4
- package/src/session-analytics/useLifecycleEvents.ts +83 -27
- package/src/session-analytics/useSessionStart.ts +37 -1
- package/src/types.ts +41 -4
package/dist/index.mjs
CHANGED
|
@@ -1512,6 +1512,23 @@ var buildEventsRequest = (target, events) => {
|
|
|
1512
1512
|
return null;
|
|
1513
1513
|
}
|
|
1514
1514
|
};
|
|
1515
|
+
var warnOnSkippedEvents = (res) => {
|
|
1516
|
+
if (typeof __DEV__ === "undefined" || !__DEV__) return;
|
|
1517
|
+
if (typeof console === "undefined" || !console.warn) return;
|
|
1518
|
+
try {
|
|
1519
|
+
const json = res == null ? void 0 : res.json;
|
|
1520
|
+
if (typeof json !== "function") return;
|
|
1521
|
+
void Promise.resolve(json.call(res)).then((body) => {
|
|
1522
|
+
const skipped = body == null ? void 0 : body.skipped;
|
|
1523
|
+
if (typeof skipped !== "number" || skipped <= 0) return;
|
|
1524
|
+
console.warn(
|
|
1525
|
+
`[wireai] the server ACCEPTED the /v1/events POST but DISCARDED ${skipped} event(s) (skipped in the response body) \u2014 they are gone, not retried. The usual cause is an event with a missing or empty session_id.`
|
|
1526
|
+
);
|
|
1527
|
+
}).catch(() => {
|
|
1528
|
+
});
|
|
1529
|
+
} catch {
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1515
1532
|
var reportClientEvents = (target, events) => {
|
|
1516
1533
|
try {
|
|
1517
1534
|
const req = buildEventsRequest(target, events);
|
|
@@ -3294,6 +3311,82 @@ var collectDeviceContext = () => {
|
|
|
3294
3311
|
return ctx;
|
|
3295
3312
|
};
|
|
3296
3313
|
|
|
3314
|
+
// src/context/deviceId.ts
|
|
3315
|
+
var AUTO_DEVICE_ID_PREFIX = "wdev_";
|
|
3316
|
+
var deviceIdStorageKey = (appId) => `wireai:analytics:deviceKey:${appId != null ? appId : "default"}`;
|
|
3317
|
+
var randomChunk = () => Math.floor(Math.random() * 4294967296).toString(36).padStart(6, "0");
|
|
3318
|
+
var mintDeviceId = () => {
|
|
3319
|
+
const time = Date.now().toString(36);
|
|
3320
|
+
return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
|
|
3321
|
+
};
|
|
3322
|
+
var AUTO_DEVICE_KEY_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:autoDeviceKeys");
|
|
3323
|
+
var deviceKeyGlobal = globalThis;
|
|
3324
|
+
var autoDeviceKeyRegistry = () => {
|
|
3325
|
+
const existing = deviceKeyGlobal[AUTO_DEVICE_KEY_SLOT];
|
|
3326
|
+
if (existing) return existing;
|
|
3327
|
+
const created = { keys: /* @__PURE__ */ new Map(), hydrating: /* @__PURE__ */ new Set() };
|
|
3328
|
+
deviceKeyGlobal[AUTO_DEVICE_KEY_SLOT] = created;
|
|
3329
|
+
return created;
|
|
3330
|
+
};
|
|
3331
|
+
var startHydration = (registry, appId, storage, minted) => {
|
|
3332
|
+
if (!registry.pending) registry.pending = /* @__PURE__ */ new Map();
|
|
3333
|
+
const existing = registry.pending.get(appId);
|
|
3334
|
+
if (existing) return existing;
|
|
3335
|
+
const slot = deviceIdStorageKey(appId);
|
|
3336
|
+
const settled = () => {
|
|
3337
|
+
var _a2;
|
|
3338
|
+
return (_a2 = registry.keys.get(appId)) != null ? _a2 : minted;
|
|
3339
|
+
};
|
|
3340
|
+
let run;
|
|
3341
|
+
try {
|
|
3342
|
+
run = Promise.resolve(storage.getItem(slot)).then((saved) => {
|
|
3343
|
+
const persisted = typeof saved === "string" && saved.trim() ? saved.trim() : void 0;
|
|
3344
|
+
if (persisted) {
|
|
3345
|
+
registry.keys.set(appId, persisted);
|
|
3346
|
+
return persisted;
|
|
3347
|
+
}
|
|
3348
|
+
return Promise.resolve(storage.setItem(slot, minted)).then(settled, settled);
|
|
3349
|
+
}).catch(settled);
|
|
3350
|
+
} catch {
|
|
3351
|
+
run = Promise.resolve(settled());
|
|
3352
|
+
}
|
|
3353
|
+
registry.pending.set(appId, run);
|
|
3354
|
+
return run;
|
|
3355
|
+
};
|
|
3356
|
+
var resolveAutoDeviceKey = (opts = {}) => {
|
|
3357
|
+
var _a2, _b;
|
|
3358
|
+
const registry = autoDeviceKeyRegistry();
|
|
3359
|
+
const appId = (_a2 = opts.appId) != null ? _a2 : "default";
|
|
3360
|
+
let id = registry.keys.get(appId);
|
|
3361
|
+
if (!id) {
|
|
3362
|
+
id = mintDeviceId();
|
|
3363
|
+
registry.keys.set(appId, id);
|
|
3364
|
+
}
|
|
3365
|
+
const storage = opts.storage;
|
|
3366
|
+
if (storage && !registry.hydrating.has(appId)) {
|
|
3367
|
+
registry.hydrating.add(appId);
|
|
3368
|
+
void startHydration(registry, appId, storage, id);
|
|
3369
|
+
}
|
|
3370
|
+
return (_b = registry.keys.get(appId)) != null ? _b : id;
|
|
3371
|
+
};
|
|
3372
|
+
var hydrateAutoDeviceKey = async (opts = {}) => {
|
|
3373
|
+
var _a2, _b, _c;
|
|
3374
|
+
const id = resolveAutoDeviceKey(opts);
|
|
3375
|
+
if (!opts.storage) return id;
|
|
3376
|
+
const registry = autoDeviceKeyRegistry();
|
|
3377
|
+
const appId = (_a2 = opts.appId) != null ? _a2 : "default";
|
|
3378
|
+
const pending = (_b = registry.pending) == null ? void 0 : _b.get(appId);
|
|
3379
|
+
if (pending) await pending;
|
|
3380
|
+
return (_c = registry.keys.get(appId)) != null ? _c : id;
|
|
3381
|
+
};
|
|
3382
|
+
var resetAutoDeviceKeys = () => {
|
|
3383
|
+
var _a2;
|
|
3384
|
+
const registry = autoDeviceKeyRegistry();
|
|
3385
|
+
registry.keys.clear();
|
|
3386
|
+
registry.hydrating.clear();
|
|
3387
|
+
(_a2 = registry.pending) == null ? void 0 : _a2.clear();
|
|
3388
|
+
};
|
|
3389
|
+
|
|
3297
3390
|
// src/analytics/currentSession.ts
|
|
3298
3391
|
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
3299
3392
|
"@wireai/activation:currentSessionId"
|
|
@@ -3308,6 +3401,28 @@ var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
|
3308
3401
|
var resetCurrentSessionId = () => {
|
|
3309
3402
|
globalSlot[CURRENT_SESSION_ID_SLOT] = void 0;
|
|
3310
3403
|
};
|
|
3404
|
+
var warnInDev = (message) => {
|
|
3405
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
3406
|
+
console.warn(message);
|
|
3407
|
+
return true;
|
|
3408
|
+
}
|
|
3409
|
+
return false;
|
|
3410
|
+
};
|
|
3411
|
+
var MINT_WARNING = "[wireai] No app-open session was registered, so a session id was minted for this event (the server drops an event that has no session_id, and still answers 200). Mount useLifecycleEvents at your app root so events correlate to a real app-open.";
|
|
3412
|
+
var MINT_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
|
|
3413
|
+
"@wireai/activation:currentSessionIdMintWarned"
|
|
3414
|
+
);
|
|
3415
|
+
var warnSlot = globalThis;
|
|
3416
|
+
var ensureCurrentSessionId = () => {
|
|
3417
|
+
const existing = globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
3418
|
+
if (typeof existing === "string" && existing.length > 0) return existing;
|
|
3419
|
+
const minted = makeSessionId();
|
|
3420
|
+
globalSlot[CURRENT_SESSION_ID_SLOT] = minted;
|
|
3421
|
+
if (!warnSlot[MINT_WARNED_SLOT] && warnInDev(MINT_WARNING)) {
|
|
3422
|
+
warnSlot[MINT_WARNED_SLOT] = true;
|
|
3423
|
+
}
|
|
3424
|
+
return minted;
|
|
3425
|
+
};
|
|
3311
3426
|
|
|
3312
3427
|
// src/session/persistedSession.ts
|
|
3313
3428
|
var DEFAULT_SESSION_TTL_MS = 36e5;
|
|
@@ -3397,6 +3512,105 @@ var identifyOnboarding = async (opts) => {
|
|
|
3397
3512
|
);
|
|
3398
3513
|
return true;
|
|
3399
3514
|
};
|
|
3515
|
+
|
|
3516
|
+
// src/context/userContext.ts
|
|
3517
|
+
var RESERVED_USER_CONTEXT_KEYS = [
|
|
3518
|
+
"device_key",
|
|
3519
|
+
"app_version",
|
|
3520
|
+
"app_build",
|
|
3521
|
+
"network_type",
|
|
3522
|
+
"session_count",
|
|
3523
|
+
"returning",
|
|
3524
|
+
"platform",
|
|
3525
|
+
"user_email",
|
|
3526
|
+
"user_email_hashed"
|
|
3527
|
+
];
|
|
3528
|
+
var EXTRA_KEY_PREFIX = "custom.";
|
|
3529
|
+
var isWireScalar = (value) => {
|
|
3530
|
+
const t = typeof value;
|
|
3531
|
+
if (t === "string" || t === "boolean") return true;
|
|
3532
|
+
if (t === "number") return Number.isFinite(value);
|
|
3533
|
+
return false;
|
|
3534
|
+
};
|
|
3535
|
+
var hashEmailFnv1a = (email) => {
|
|
3536
|
+
const normalized = email.trim().toLowerCase();
|
|
3537
|
+
let hash = 2166136261;
|
|
3538
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
3539
|
+
hash ^= normalized.charCodeAt(i);
|
|
3540
|
+
hash = Math.imul(hash, 16777619);
|
|
3541
|
+
}
|
|
3542
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
3543
|
+
};
|
|
3544
|
+
var cleanString = (value) => {
|
|
3545
|
+
if (typeof value !== "string") return void 0;
|
|
3546
|
+
const trimmed = value.trim();
|
|
3547
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
3548
|
+
};
|
|
3549
|
+
var namespaceExtra = (extra) => {
|
|
3550
|
+
const out = {};
|
|
3551
|
+
if (!extra || typeof extra !== "object") return out;
|
|
3552
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
3553
|
+
const cleanKey = cleanString(key);
|
|
3554
|
+
if (!cleanKey) continue;
|
|
3555
|
+
if (!isWireScalar(value)) continue;
|
|
3556
|
+
out[`${EXTRA_KEY_PREFIX}${cleanKey}`] = value;
|
|
3557
|
+
}
|
|
3558
|
+
return out;
|
|
3559
|
+
};
|
|
3560
|
+
var analyticsUserIdStorageKey = (appId) => `wireai:analytics:userId:${appId != null ? appId : "default"}`;
|
|
3561
|
+
var clearPiiFromContext = (ctx = {}) => {
|
|
3562
|
+
const rest = {};
|
|
3563
|
+
if (typeof ctx.appVersion === "string") rest.appVersion = ctx.appVersion;
|
|
3564
|
+
if (typeof ctx.deviceKey === "string") rest.deviceKey = ctx.deviceKey;
|
|
3565
|
+
return rest;
|
|
3566
|
+
};
|
|
3567
|
+
var clearUserContext = async (opts = {}) => {
|
|
3568
|
+
const storage = opts.storage;
|
|
3569
|
+
if (!storage) return;
|
|
3570
|
+
try {
|
|
3571
|
+
await storage.removeItem(analyticsUserIdStorageKey(opts.appId));
|
|
3572
|
+
} catch {
|
|
3573
|
+
}
|
|
3574
|
+
};
|
|
3575
|
+
var activationJoinContext = (deviceKey) => {
|
|
3576
|
+
var _a2;
|
|
3577
|
+
return (_a2 = resolveUserContext({ deviceKey }).userContext) != null ? _a2 : {};
|
|
3578
|
+
};
|
|
3579
|
+
var resolveUserContext = (ctx = {}, opts = {}) => {
|
|
3580
|
+
var _a2;
|
|
3581
|
+
const result = {};
|
|
3582
|
+
const bucket = {};
|
|
3583
|
+
const userId = sanitizeUserId(ctx.userId);
|
|
3584
|
+
if (userId) result.userId = userId;
|
|
3585
|
+
const deviceKey = cleanString(ctx.deviceKey);
|
|
3586
|
+
if (deviceKey) {
|
|
3587
|
+
result.deviceKey = deviceKey;
|
|
3588
|
+
bucket.device_key = deviceKey;
|
|
3589
|
+
}
|
|
3590
|
+
const appVersion = (_a2 = cleanString(ctx.appVersion)) != null ? _a2 : cleanString(opts.autoAppVersion);
|
|
3591
|
+
if (appVersion) {
|
|
3592
|
+
result.appVersion = appVersion;
|
|
3593
|
+
bucket.app_version = appVersion;
|
|
3594
|
+
}
|
|
3595
|
+
const email = cleanString(ctx.userEmail);
|
|
3596
|
+
if (email) {
|
|
3597
|
+
if (ctx.hashEmail) {
|
|
3598
|
+
bucket.user_email = hashEmailFnv1a(email);
|
|
3599
|
+
bucket.user_email_hashed = true;
|
|
3600
|
+
} else {
|
|
3601
|
+
bucket.user_email = email;
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
Object.assign(bucket, namespaceExtra(ctx.extra));
|
|
3605
|
+
if (Object.keys(bucket).length > 0) result.userContext = bucket;
|
|
3606
|
+
return result;
|
|
3607
|
+
};
|
|
3608
|
+
var warnInDev2 = (message) => {
|
|
3609
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
3610
|
+
console.warn(message);
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
var AUTO_JOIN_HYDRATION_TIMEOUT_MS = 1500;
|
|
3400
3614
|
var WireOnboarding = ({
|
|
3401
3615
|
config,
|
|
3402
3616
|
theme,
|
|
@@ -3419,7 +3633,8 @@ var WireOnboarding = ({
|
|
|
3419
3633
|
persistKey,
|
|
3420
3634
|
retainSessionOnComplete,
|
|
3421
3635
|
userContext,
|
|
3422
|
-
userId
|
|
3636
|
+
userId,
|
|
3637
|
+
autoJoinKey = true
|
|
3423
3638
|
}) => {
|
|
3424
3639
|
var _a2, _b, _c;
|
|
3425
3640
|
const boundUserId = useMemo(() => sanitizeUserId(userId), [userId]);
|
|
@@ -3432,9 +3647,50 @@ var WireOnboarding = ({
|
|
|
3432
3647
|
() => userContextKey ? JSON.parse(userContextKey) : void 0,
|
|
3433
3648
|
[userContextKey]
|
|
3434
3649
|
);
|
|
3650
|
+
const missingJoinKey = typeof (userContextStable == null ? void 0 : userContextStable.device_key) !== "string" || !userContextStable.device_key.trim();
|
|
3651
|
+
const autoJoinPossible = Boolean(storage) && autoJoinKey !== false;
|
|
3652
|
+
const wantsAutoJoin = missingJoinKey && autoJoinPossible;
|
|
3653
|
+
const [autoJoinValue, setAutoJoinValue] = useState(void 0);
|
|
3654
|
+
useEffect(() => {
|
|
3655
|
+
if (!wantsAutoJoin || autoJoinValue !== void 0 || !storage) return;
|
|
3656
|
+
let cancelled = false;
|
|
3657
|
+
const timer = setTimeout(() => {
|
|
3658
|
+
if (!cancelled) setAutoJoinValue(null);
|
|
3659
|
+
}, AUTO_JOIN_HYDRATION_TIMEOUT_MS);
|
|
3660
|
+
void hydrateAutoDeviceKey({ appId: config.appId, storage }).then((key) => {
|
|
3661
|
+
if (cancelled) return;
|
|
3662
|
+
clearTimeout(timer);
|
|
3663
|
+
setAutoJoinValue(key || null);
|
|
3664
|
+
});
|
|
3665
|
+
return () => {
|
|
3666
|
+
cancelled = true;
|
|
3667
|
+
clearTimeout(timer);
|
|
3668
|
+
};
|
|
3669
|
+
}, [wantsAutoJoin, autoJoinValue, config.appId, storage]);
|
|
3670
|
+
const injectedJoinKey = wantsAutoJoin && typeof autoJoinValue === "string" ? autoJoinValue : void 0;
|
|
3671
|
+
const autoJoinPending = wantsAutoJoin && autoJoinValue === void 0;
|
|
3672
|
+
const effectiveUserContext = useMemo(
|
|
3673
|
+
() => injectedJoinKey ? { ...userContextStable, ...activationJoinContext(injectedJoinKey) } : userContextStable,
|
|
3674
|
+
[userContextStable, injectedJoinKey]
|
|
3675
|
+
);
|
|
3676
|
+
const warnMissingJoinKey = missingJoinKey && !injectedJoinKey && !autoJoinPending;
|
|
3677
|
+
const autoJoinReason = autoJoinKey === false ? "you passed autoJoinKey={false}." : !storage ? "it got no `storage` prop, and without persistence its key would be different on every launch, which corrupts min_sessions instead of merely leaving the join empty." : "your `storage` adapter did not answer in time.";
|
|
3678
|
+
useEffect(() => {
|
|
3679
|
+
if (!warnMissingJoinKey) return;
|
|
3680
|
+
warnInDev2(
|
|
3681
|
+
"[wireai] <WireOnboarding> got no user_context.device_key, so this onboarding session can never be joined to the app's later events and the `activated` funnel will read zero. Pass userContext={activationJoinContext(deviceKey)} \u2014 and if your app owns no device id, userContext={activationJoinContext(resolveAutoDeviceKey({ appId, storage }))} returns the SAME id the analytics side stamps. Never hand-write userContext={{ deviceKey }}. The kit did NOT auto-inject its own key here because " + autoJoinReason
|
|
3682
|
+
);
|
|
3683
|
+
}, [warnMissingJoinKey, autoJoinReason]);
|
|
3684
|
+
const misspelledJoinKey = missingJoinKey && typeof (userContextStable == null ? void 0 : userContextStable.deviceKey) === "string" && Boolean(userContextStable.deviceKey.trim());
|
|
3685
|
+
useEffect(() => {
|
|
3686
|
+
if (!misspelledJoinKey || !injectedJoinKey) return;
|
|
3687
|
+
warnInDev2(
|
|
3688
|
+
"[wireai] <WireOnboarding> got userContext={{ deviceKey }}, which is NOT the wire key \u2014 the server's device lookup reads `device_key`. The kit auto-injected its own device_key so this session is at least self-consistent, but your app's own events carry YOUR id, so the two still will not join and the `activated` funnel stays zero. Pass userContext={activationJoinContext(deviceKey)} instead."
|
|
3689
|
+
);
|
|
3690
|
+
}, [misspelledJoinKey, injectedJoinKey]);
|
|
3435
3691
|
const clientContext = useMemo(
|
|
3436
|
-
() => ({ device, userContext:
|
|
3437
|
-
[device,
|
|
3692
|
+
() => ({ device, userContext: effectiveUserContext, userId: boundUserId }),
|
|
3693
|
+
[device, effectiveUserContext, boundUserId]
|
|
3438
3694
|
);
|
|
3439
3695
|
const [session, setSession] = useState(
|
|
3440
3696
|
() => storage ? null : { id: makeSessionId(), resumed: false }
|
|
@@ -3481,7 +3737,7 @@ var WireOnboarding = ({
|
|
|
3481
3737
|
// Device snapshot + host-injected user context ride the session-start metadata so the
|
|
3482
3738
|
// backend can segment the funnel. Old servers ignore these unknown keys (backward compat).
|
|
3483
3739
|
device,
|
|
3484
|
-
...
|
|
3740
|
+
...effectiveUserContext ? { userContext: effectiveUserContext } : {},
|
|
3485
3741
|
// The session-start user id (from the ref) rides the session-start metadata so the
|
|
3486
3742
|
// server binds the session to a real user at creation. Reading the ref — not
|
|
3487
3743
|
// `boundUserId` — keeps this memo off the userId dependency, so a mid-session change
|
|
@@ -3490,7 +3746,7 @@ var WireOnboarding = ({
|
|
|
3490
3746
|
},
|
|
3491
3747
|
timeoutMs: 6e4
|
|
3492
3748
|
};
|
|
3493
|
-
}, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device,
|
|
3749
|
+
}, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device, effectiveUserContext]);
|
|
3494
3750
|
const reportTarget = useMemo(
|
|
3495
3751
|
() => ({ serverUrl: config.serverUrl, apiKey: config.apiKey }),
|
|
3496
3752
|
[config.serverUrl, config.apiKey]
|
|
@@ -3512,7 +3768,7 @@ var WireOnboarding = ({
|
|
|
3512
3768
|
});
|
|
3513
3769
|
}, [session, sessionId, boundUserId, reportTarget]);
|
|
3514
3770
|
const cards = components != null ? components : onboardingComponents;
|
|
3515
|
-
if (!session) {
|
|
3771
|
+
if (!session || autoJoinPending) {
|
|
3516
3772
|
return /* @__PURE__ */ jsx(OnboardingThemeProvider, { theme, children: /* @__PURE__ */ jsx(
|
|
3517
3773
|
LoadingScreen,
|
|
3518
3774
|
{
|
|
@@ -3978,16 +4234,37 @@ var useResolvedFeatures = (options) => {
|
|
|
3978
4234
|
};
|
|
3979
4235
|
|
|
3980
4236
|
// src/config/wireConfigFromEnv.ts
|
|
4237
|
+
var WIRE_ENV_VARS = [
|
|
4238
|
+
"EXPO_PUBLIC_WIREAI_API_KEY",
|
|
4239
|
+
"EXPO_PUBLIC_WIREAI_SERVER_URL",
|
|
4240
|
+
"EXPO_PUBLIC_WIREAI_APP_ID"
|
|
4241
|
+
];
|
|
4242
|
+
var warnInDev3 = (message) => {
|
|
4243
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
4244
|
+
console.warn(message);
|
|
4245
|
+
}
|
|
4246
|
+
};
|
|
3981
4247
|
var wireConfigFromEnv = (overrides) => {
|
|
3982
|
-
var _a2, _b, _c, _d;
|
|
4248
|
+
var _a2, _b, _c, _d, _e;
|
|
3983
4249
|
const apiKey = (_a2 = overrides == null ? void 0 : overrides.apiKey) != null ? _a2 : process.env.EXPO_PUBLIC_WIREAI_API_KEY;
|
|
3984
4250
|
const serverUrl = (_b = overrides == null ? void 0 : overrides.serverUrl) != null ? _b : process.env.EXPO_PUBLIC_WIREAI_SERVER_URL;
|
|
3985
4251
|
const appId = (_d = (_c = overrides == null ? void 0 : overrides.appId) != null ? _c : process.env.EXPO_PUBLIC_WIREAI_APP_ID) != null ? _d : "default";
|
|
3986
|
-
if (!apiKey || !serverUrl)
|
|
4252
|
+
if (!apiKey || !serverUrl) {
|
|
4253
|
+
const missing = [
|
|
4254
|
+
apiKey ? void 0 : "EXPO_PUBLIC_WIREAI_API_KEY",
|
|
4255
|
+
serverUrl ? void 0 : "EXPO_PUBLIC_WIREAI_SERVER_URL"
|
|
4256
|
+
].filter(Boolean);
|
|
4257
|
+
warnInDev3(
|
|
4258
|
+
`[wireai] wireConfigFromEnv() returned null: ${missing.join(" and ")} ${missing.length > 1 ? "are" : "is"} missing. The kit is now FULLY DISABLED (no onboarding, no analytics, no gates) and nothing else will report an error. Set the var(s) in your env / EAS secrets.`
|
|
4259
|
+
);
|
|
4260
|
+
return null;
|
|
4261
|
+
}
|
|
4262
|
+
const appVersion = (_e = overrides == null ? void 0 : overrides.appVersion) != null ? _e : detectAppVersion();
|
|
3987
4263
|
return {
|
|
3988
4264
|
apiKey,
|
|
3989
4265
|
serverUrl,
|
|
3990
4266
|
appId,
|
|
4267
|
+
...appVersion ? { appVersion } : {},
|
|
3991
4268
|
...(overrides == null ? void 0 : overrides.metadata) ? { metadata: overrides.metadata } : {}
|
|
3992
4269
|
};
|
|
3993
4270
|
};
|
|
@@ -4048,104 +4325,6 @@ var attributionMetadata = (a) => {
|
|
|
4048
4325
|
return { attribution };
|
|
4049
4326
|
};
|
|
4050
4327
|
|
|
4051
|
-
// src/context/userContext.ts
|
|
4052
|
-
var RESERVED_USER_CONTEXT_KEYS = [
|
|
4053
|
-
"device_key",
|
|
4054
|
-
"app_version",
|
|
4055
|
-
"app_build",
|
|
4056
|
-
"network_type",
|
|
4057
|
-
"session_count",
|
|
4058
|
-
"returning",
|
|
4059
|
-
"platform",
|
|
4060
|
-
"user_email",
|
|
4061
|
-
"user_email_hashed"
|
|
4062
|
-
];
|
|
4063
|
-
var EXTRA_KEY_PREFIX = "custom.";
|
|
4064
|
-
var isWireScalar = (value) => {
|
|
4065
|
-
const t = typeof value;
|
|
4066
|
-
if (t === "string" || t === "boolean") return true;
|
|
4067
|
-
if (t === "number") return Number.isFinite(value);
|
|
4068
|
-
return false;
|
|
4069
|
-
};
|
|
4070
|
-
var hashEmailFnv1a = (email) => {
|
|
4071
|
-
const normalized = email.trim().toLowerCase();
|
|
4072
|
-
let hash = 2166136261;
|
|
4073
|
-
for (let i = 0; i < normalized.length; i++) {
|
|
4074
|
-
hash ^= normalized.charCodeAt(i);
|
|
4075
|
-
hash = Math.imul(hash, 16777619);
|
|
4076
|
-
}
|
|
4077
|
-
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
4078
|
-
};
|
|
4079
|
-
var cleanString = (value) => {
|
|
4080
|
-
if (typeof value !== "string") return void 0;
|
|
4081
|
-
const trimmed = value.trim();
|
|
4082
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
4083
|
-
};
|
|
4084
|
-
var namespaceExtra = (extra) => {
|
|
4085
|
-
const out = {};
|
|
4086
|
-
if (!extra || typeof extra !== "object") return out;
|
|
4087
|
-
for (const [key, value] of Object.entries(extra)) {
|
|
4088
|
-
const cleanKey = cleanString(key);
|
|
4089
|
-
if (!cleanKey) continue;
|
|
4090
|
-
if (!isWireScalar(value)) continue;
|
|
4091
|
-
out[`${EXTRA_KEY_PREFIX}${cleanKey}`] = value;
|
|
4092
|
-
}
|
|
4093
|
-
return out;
|
|
4094
|
-
};
|
|
4095
|
-
var analyticsUserIdStorageKey = (appId) => `wireai:analytics:userId:${appId != null ? appId : "default"}`;
|
|
4096
|
-
var clearPiiFromContext = (ctx = {}) => {
|
|
4097
|
-
const rest = {};
|
|
4098
|
-
if (typeof ctx.appVersion === "string") rest.appVersion = ctx.appVersion;
|
|
4099
|
-
if (typeof ctx.deviceKey === "string") rest.deviceKey = ctx.deviceKey;
|
|
4100
|
-
return rest;
|
|
4101
|
-
};
|
|
4102
|
-
var clearUserContext = async (opts = {}) => {
|
|
4103
|
-
const storage = opts.storage;
|
|
4104
|
-
if (!storage) return;
|
|
4105
|
-
try {
|
|
4106
|
-
await storage.removeItem(analyticsUserIdStorageKey(opts.appId));
|
|
4107
|
-
} catch {
|
|
4108
|
-
}
|
|
4109
|
-
};
|
|
4110
|
-
var resolveUserContext = (ctx = {}, opts = {}) => {
|
|
4111
|
-
var _a2;
|
|
4112
|
-
const result = {};
|
|
4113
|
-
const bucket = {};
|
|
4114
|
-
const userId = sanitizeUserId(ctx.userId);
|
|
4115
|
-
if (userId) result.userId = userId;
|
|
4116
|
-
const deviceKey = cleanString(ctx.deviceKey);
|
|
4117
|
-
if (deviceKey) {
|
|
4118
|
-
result.deviceKey = deviceKey;
|
|
4119
|
-
bucket.device_key = deviceKey;
|
|
4120
|
-
}
|
|
4121
|
-
const appVersion = (_a2 = cleanString(ctx.appVersion)) != null ? _a2 : cleanString(opts.autoAppVersion);
|
|
4122
|
-
if (appVersion) {
|
|
4123
|
-
result.appVersion = appVersion;
|
|
4124
|
-
bucket.app_version = appVersion;
|
|
4125
|
-
}
|
|
4126
|
-
const email = cleanString(ctx.userEmail);
|
|
4127
|
-
if (email) {
|
|
4128
|
-
if (ctx.hashEmail) {
|
|
4129
|
-
bucket.user_email = hashEmailFnv1a(email);
|
|
4130
|
-
bucket.user_email_hashed = true;
|
|
4131
|
-
} else {
|
|
4132
|
-
bucket.user_email = email;
|
|
4133
|
-
}
|
|
4134
|
-
}
|
|
4135
|
-
Object.assign(bucket, namespaceExtra(ctx.extra));
|
|
4136
|
-
if (Object.keys(bucket).length > 0) result.userContext = bucket;
|
|
4137
|
-
return result;
|
|
4138
|
-
};
|
|
4139
|
-
|
|
4140
|
-
// src/context/deviceId.ts
|
|
4141
|
-
var AUTO_DEVICE_ID_PREFIX = "wdev_";
|
|
4142
|
-
var deviceIdStorageKey = (appId) => `wireai:analytics:deviceKey:${appId != null ? appId : "default"}`;
|
|
4143
|
-
var randomChunk = () => Math.floor(Math.random() * 4294967296).toString(36).padStart(6, "0");
|
|
4144
|
-
var mintDeviceId = () => {
|
|
4145
|
-
const time = Date.now().toString(36);
|
|
4146
|
-
return `${AUTO_DEVICE_ID_PREFIX}${time}_${randomChunk()}${randomChunk()}`;
|
|
4147
|
-
};
|
|
4148
|
-
|
|
4149
4328
|
// src/activation/revalidation.ts
|
|
4150
4329
|
var REVALIDATION_SLOT = /* @__PURE__ */ Symbol.for(
|
|
4151
4330
|
"@wireai/activation:activationRevalidation"
|
|
@@ -4192,32 +4371,31 @@ var createWireActivation = (config) => {
|
|
|
4192
4371
|
var _a2, _b;
|
|
4193
4372
|
const target = { serverUrl: config.serverUrl, apiKey: config.apiKey };
|
|
4194
4373
|
const explicitDeviceKey = (_b = clean(config.deviceKey)) != null ? _b : clean((_a2 = config.userContext) == null ? void 0 : _a2.deviceKey);
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
else void storage.setItem(key, autoDeviceKey).catch(() => {
|
|
4203
|
-
});
|
|
4204
|
-
}).catch(() => {
|
|
4205
|
-
});
|
|
4206
|
-
}
|
|
4374
|
+
const autoDeviceKeyOptions = {
|
|
4375
|
+
appId: config.appId,
|
|
4376
|
+
// An explicit key opts out of minting AND persisting (unchanged contract).
|
|
4377
|
+
storage: explicitDeviceKey ? void 0 : config.storage
|
|
4378
|
+
};
|
|
4379
|
+
if (!explicitDeviceKey) resolveAutoDeviceKey(autoDeviceKeyOptions);
|
|
4380
|
+
const detectedAppVersion = detectAppVersion();
|
|
4207
4381
|
const applyContext = (event) => {
|
|
4208
|
-
var _a3, _b2;
|
|
4382
|
+
var _a3, _b2, _c;
|
|
4209
4383
|
const resolved = resolveUserContext(
|
|
4210
|
-
|
|
4211
|
-
{
|
|
4384
|
+
// `??` is lazy on purpose: an explicit key must never even touch the auto registry.
|
|
4385
|
+
{
|
|
4386
|
+
...(_a3 = config.userContext) != null ? _a3 : {},
|
|
4387
|
+
deviceKey: explicitDeviceKey != null ? explicitDeviceKey : resolveAutoDeviceKey(autoDeviceKeyOptions)
|
|
4388
|
+
},
|
|
4389
|
+
{ autoAppVersion: (_b2 = config.appVersion) != null ? _b2 : detectedAppVersion }
|
|
4212
4390
|
);
|
|
4213
4391
|
if (resolved.userContext) {
|
|
4214
|
-
event.user_context = { ...resolved.userContext, ...(
|
|
4392
|
+
event.user_context = { ...resolved.userContext, ...(_c = event.user_context) != null ? _c : {} };
|
|
4215
4393
|
}
|
|
4216
4394
|
if (resolved.userId && !event.user_id) event.user_id = resolved.userId;
|
|
4217
4395
|
};
|
|
4218
4396
|
const track = async (name2, meta) => {
|
|
4219
|
-
|
|
4220
|
-
|
|
4397
|
+
if (!clean(name2)) return false;
|
|
4398
|
+
const sessionId = ensureCurrentSessionId();
|
|
4221
4399
|
const event = {
|
|
4222
4400
|
event_type: "app_event",
|
|
4223
4401
|
session_id: sessionId,
|
|
@@ -4244,9 +4422,16 @@ var useActivationRevalidation = () => useSyncExternalStore(
|
|
|
4244
4422
|
getActivationRevalidationVersion
|
|
4245
4423
|
);
|
|
4246
4424
|
var useWireActivation = (config) => {
|
|
4425
|
+
var _a2;
|
|
4247
4426
|
const ref = useRef(void 0);
|
|
4248
4427
|
const prevKeys = useRef("");
|
|
4249
|
-
const currentKeys =
|
|
4428
|
+
const currentKeys = [
|
|
4429
|
+
config.serverUrl,
|
|
4430
|
+
config.apiKey,
|
|
4431
|
+
config.appId,
|
|
4432
|
+
config.deviceKey,
|
|
4433
|
+
(_a2 = config.userContext) == null ? void 0 : _a2.deviceKey
|
|
4434
|
+
].join("|");
|
|
4250
4435
|
if (!ref.current || prevKeys.current !== currentKeys) {
|
|
4251
4436
|
prevKeys.current = currentKeys;
|
|
4252
4437
|
ref.current = createWireActivation(config);
|
|
@@ -4255,6 +4440,154 @@ var useWireActivation = (config) => {
|
|
|
4255
4440
|
return { track: ref.current.track, sessionId: ref.current.sessionId, revalidation };
|
|
4256
4441
|
};
|
|
4257
4442
|
|
|
4443
|
+
// src/revenuecat/purchaseEvents.ts
|
|
4444
|
+
var WIRE_PURCHASE_EVENTS = {
|
|
4445
|
+
/** The paywall became visible (offerings loaded). */
|
|
4446
|
+
paywallShown: "wire_paywall_shown",
|
|
4447
|
+
/** The user tapped buy; the store sheet is about to open. */
|
|
4448
|
+
checkoutStarted: "wire_checkout_started",
|
|
4449
|
+
/** The store confirmed the purchase AND the entitlement is now active. */
|
|
4450
|
+
purchased: "wire_purchase_completed",
|
|
4451
|
+
/** The purchase did not land: a user cancel or a real store/network error (see `reason`). */
|
|
4452
|
+
purchaseFailed: "wire_purchase_failed",
|
|
4453
|
+
/** A restore ran (whether or not it produced an entitlement; see `plan_tier`). */
|
|
4454
|
+
restored: "wire_purchase_restored"
|
|
4455
|
+
};
|
|
4456
|
+
var PLAN_TIER_CONTEXT_KEY = "plan_tier";
|
|
4457
|
+
var asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
|
|
4458
|
+
var activeEntitlement = (info, entitlementId) => {
|
|
4459
|
+
var _a2, _b;
|
|
4460
|
+
const active = asRecord((_b = asRecord((_a2 = asRecord(info)) == null ? void 0 : _a2.entitlements)) == null ? void 0 : _b.active);
|
|
4461
|
+
const found = active == null ? void 0 : active[entitlementId];
|
|
4462
|
+
const entitlement = asRecord(found);
|
|
4463
|
+
if (!entitlement) return void 0;
|
|
4464
|
+
return entitlement.isActive === false ? void 0 : entitlement;
|
|
4465
|
+
};
|
|
4466
|
+
var isTrial = (entitlement) => typeof entitlement.periodType === "string" && entitlement.periodType.toUpperCase() === "TRIAL";
|
|
4467
|
+
var resolvePlanTier = (info, entitlementId) => {
|
|
4468
|
+
const entitlement = activeEntitlement(info, entitlementId);
|
|
4469
|
+
if (!entitlement) return "free";
|
|
4470
|
+
return isTrial(entitlement) ? "trial" : "paid";
|
|
4471
|
+
};
|
|
4472
|
+
var describePackage = (pkg) => {
|
|
4473
|
+
const props = {};
|
|
4474
|
+
if (!pkg) return props;
|
|
4475
|
+
if (typeof pkg.identifier === "string") props.package_id = pkg.identifier;
|
|
4476
|
+
if (typeof pkg.packageType === "string") props.package_type = pkg.packageType;
|
|
4477
|
+
if (typeof pkg.offeringIdentifier === "string") props.offering_id = pkg.offeringIdentifier;
|
|
4478
|
+
const product = asRecord(pkg.product);
|
|
4479
|
+
if (product) {
|
|
4480
|
+
if (typeof product.identifier === "string") props.product_id = product.identifier;
|
|
4481
|
+
if (typeof product.price === "number" && Number.isFinite(product.price)) {
|
|
4482
|
+
props.price = product.price;
|
|
4483
|
+
}
|
|
4484
|
+
if (typeof product.currencyCode === "string") props.currency = product.currencyCode;
|
|
4485
|
+
}
|
|
4486
|
+
return props;
|
|
4487
|
+
};
|
|
4488
|
+
var describeEntitlement = (info, entitlementId) => {
|
|
4489
|
+
const entitlement = activeEntitlement(info, entitlementId);
|
|
4490
|
+
const props = {
|
|
4491
|
+
entitlement: entitlementId,
|
|
4492
|
+
plan_tier: entitlement ? isTrial(entitlement) ? "trial" : "paid" : "free"
|
|
4493
|
+
};
|
|
4494
|
+
if (!entitlement) return props;
|
|
4495
|
+
if (typeof entitlement.periodType === "string") props.period_type = entitlement.periodType;
|
|
4496
|
+
props.is_trial = isTrial(entitlement);
|
|
4497
|
+
if (typeof entitlement.willRenew === "boolean") props.will_renew = entitlement.willRenew;
|
|
4498
|
+
if (typeof entitlement.store === "string") props.store = entitlement.store;
|
|
4499
|
+
if (typeof entitlement.productIdentifier === "string") {
|
|
4500
|
+
props.product_id = entitlement.productIdentifier;
|
|
4501
|
+
}
|
|
4502
|
+
if (typeof entitlement.isSandbox === "boolean") props.is_sandbox = entitlement.isSandbox;
|
|
4503
|
+
return props;
|
|
4504
|
+
};
|
|
4505
|
+
var PURCHASE_CANCELLED_CODE = "1";
|
|
4506
|
+
var isUserCancelled = (error) => {
|
|
4507
|
+
const record = asRecord(error);
|
|
4508
|
+
if (!record) return false;
|
|
4509
|
+
if (record.userCancelled === true) return true;
|
|
4510
|
+
return record.code === PURCHASE_CANCELLED_CODE;
|
|
4511
|
+
};
|
|
4512
|
+
var describeFailure = (error) => {
|
|
4513
|
+
const record = asRecord(error);
|
|
4514
|
+
const code = typeof (record == null ? void 0 : record.code) === "string" ? record.code : "unknown";
|
|
4515
|
+
return { reason: isUserCancelled(error) ? "cancelled" : "error", code };
|
|
4516
|
+
};
|
|
4517
|
+
|
|
4518
|
+
// src/revenuecat/revenueCatBridge.ts
|
|
4519
|
+
var createRevenueCatBridge = (config) => {
|
|
4520
|
+
const { analytics, entitlementId } = config;
|
|
4521
|
+
const writeTier = config.writePlanTier !== false;
|
|
4522
|
+
const emit = (event, props) => {
|
|
4523
|
+
try {
|
|
4524
|
+
const result = analytics.track(event, { ...config.commonProps, ...props });
|
|
4525
|
+
if (result && typeof result.catch === "function") {
|
|
4526
|
+
void result.catch(() => {
|
|
4527
|
+
});
|
|
4528
|
+
}
|
|
4529
|
+
} catch {
|
|
4530
|
+
}
|
|
4531
|
+
};
|
|
4532
|
+
const syncPlanTier = (customerInfo) => {
|
|
4533
|
+
var _a2;
|
|
4534
|
+
const tier = resolvePlanTier(customerInfo, entitlementId);
|
|
4535
|
+
if (!writeTier) return tier;
|
|
4536
|
+
try {
|
|
4537
|
+
(_a2 = analytics.setUserContext) == null ? void 0 : _a2.call(analytics, { extra: { [PLAN_TIER_CONTEXT_KEY]: tier } });
|
|
4538
|
+
} catch {
|
|
4539
|
+
}
|
|
4540
|
+
return tier;
|
|
4541
|
+
};
|
|
4542
|
+
const paywallShown = (offering, props) => {
|
|
4543
|
+
var _a2, _b;
|
|
4544
|
+
const shown = {
|
|
4545
|
+
packages_count: (_b = (_a2 = offering == null ? void 0 : offering.availablePackages) == null ? void 0 : _a2.length) != null ? _b : 0
|
|
4546
|
+
};
|
|
4547
|
+
if (typeof (offering == null ? void 0 : offering.identifier) === "string") shown.offering_id = offering.identifier;
|
|
4548
|
+
emit(WIRE_PURCHASE_EVENTS.paywallShown, { ...shown, ...props });
|
|
4549
|
+
};
|
|
4550
|
+
const checkoutStarted = (pkg, props) => {
|
|
4551
|
+
emit(WIRE_PURCHASE_EVENTS.checkoutStarted, { ...describePackage(pkg), ...props });
|
|
4552
|
+
};
|
|
4553
|
+
const purchaseCompleted = (customerInfo, pkg, props) => {
|
|
4554
|
+
const tier = syncPlanTier(customerInfo);
|
|
4555
|
+
const entitled = tier !== "free";
|
|
4556
|
+
if (entitled) {
|
|
4557
|
+
emit(WIRE_PURCHASE_EVENTS.purchased, {
|
|
4558
|
+
...describePackage(pkg),
|
|
4559
|
+
...describeEntitlement(customerInfo, entitlementId),
|
|
4560
|
+
...props
|
|
4561
|
+
});
|
|
4562
|
+
return true;
|
|
4563
|
+
}
|
|
4564
|
+
emit(WIRE_PURCHASE_EVENTS.purchaseFailed, {
|
|
4565
|
+
...describePackage(pkg),
|
|
4566
|
+
reason: "not_entitled",
|
|
4567
|
+
code: "unknown",
|
|
4568
|
+
entitlement: entitlementId,
|
|
4569
|
+
...props
|
|
4570
|
+
});
|
|
4571
|
+
return false;
|
|
4572
|
+
};
|
|
4573
|
+
const purchaseFailed = (error, pkg, props) => {
|
|
4574
|
+
emit(WIRE_PURCHASE_EVENTS.purchaseFailed, {
|
|
4575
|
+
...describePackage(pkg),
|
|
4576
|
+
...describeFailure(error),
|
|
4577
|
+
...props
|
|
4578
|
+
});
|
|
4579
|
+
};
|
|
4580
|
+
const purchasesRestored = (customerInfo, props) => {
|
|
4581
|
+
const tier = syncPlanTier(customerInfo);
|
|
4582
|
+
emit(WIRE_PURCHASE_EVENTS.restored, {
|
|
4583
|
+
...describeEntitlement(customerInfo, entitlementId),
|
|
4584
|
+
...props
|
|
4585
|
+
});
|
|
4586
|
+
return tier !== "free";
|
|
4587
|
+
};
|
|
4588
|
+
return { paywallShown, checkoutStarted, purchaseCompleted, purchaseFailed, purchasesRestored, syncPlanTier };
|
|
4589
|
+
};
|
|
4590
|
+
|
|
4258
4591
|
// src/session-analytics/reportSessionStart.ts
|
|
4259
4592
|
var SESSION_STARTED_EVENT = "app.session_started";
|
|
4260
4593
|
var _emitted = /* @__PURE__ */ new Set();
|
|
@@ -4307,6 +4640,8 @@ var reportSessionStart = (opts) => {
|
|
|
4307
4640
|
method: "POST",
|
|
4308
4641
|
headers,
|
|
4309
4642
|
body: JSON.stringify({ events: [event] })
|
|
4643
|
+
}).then((res) => {
|
|
4644
|
+
warnOnSkippedEvents(res);
|
|
4310
4645
|
}).catch(() => {
|
|
4311
4646
|
});
|
|
4312
4647
|
} catch {
|
|
@@ -4317,6 +4652,12 @@ var useSessionStart = (config, options = {}) => {
|
|
|
4317
4652
|
const latest = useRef({ config, options });
|
|
4318
4653
|
latest.current = { config, options };
|
|
4319
4654
|
useEffect(() => {
|
|
4655
|
+
const resolveDeviceKey = (cfg, opts) => {
|
|
4656
|
+
const host = typeof opts.deviceKey === "string" && opts.deviceKey.trim() ? opts.deviceKey : void 0;
|
|
4657
|
+
if (host) return host;
|
|
4658
|
+
if (!(cfg == null ? void 0 : cfg.storage)) return void 0;
|
|
4659
|
+
return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
|
|
4660
|
+
};
|
|
4320
4661
|
const fire = () => {
|
|
4321
4662
|
var _a2, _b;
|
|
4322
4663
|
const { config: cfg, options: opts } = latest.current;
|
|
@@ -4329,7 +4670,7 @@ var useSessionStart = (config, options = {}) => {
|
|
|
4329
4670
|
target,
|
|
4330
4671
|
// A fresh per-open id each fire; the emitter's once-guard dedupes within the open.
|
|
4331
4672
|
userId: opts.userId,
|
|
4332
|
-
deviceKey: opts
|
|
4673
|
+
deviceKey: resolveDeviceKey(cfg, opts),
|
|
4333
4674
|
sessionCount: opts.sessionCount,
|
|
4334
4675
|
appVersion: (_b = cfg.appVersion) != null ? _b : device.appVersion,
|
|
4335
4676
|
platform: Platform.OS,
|
|
@@ -4437,11 +4778,13 @@ var reportFirstOpen = (opts) => {
|
|
|
4437
4778
|
})();
|
|
4438
4779
|
};
|
|
4439
4780
|
var wireLifecycleEvents = (opts) => {
|
|
4440
|
-
|
|
4781
|
+
var _a2;
|
|
4782
|
+
const sessionId = (_a2 = opts.sessionId) != null ? _a2 : makeSessionId();
|
|
4783
|
+
reportFirstOpen({ ...opts, sessionId });
|
|
4441
4784
|
reportSessionStart({
|
|
4442
4785
|
target: opts.target,
|
|
4443
4786
|
sink: opts.sink,
|
|
4444
|
-
sessionId
|
|
4787
|
+
sessionId,
|
|
4445
4788
|
userId: opts.userId,
|
|
4446
4789
|
deviceKey: opts.deviceKey,
|
|
4447
4790
|
sessionCount: opts.sessionCount,
|
|
@@ -4576,6 +4919,7 @@ var createEventQueue = (options) => {
|
|
|
4576
4919
|
const timer = setTimeout(() => controller == null ? void 0 : controller.abort(), 15e3);
|
|
4577
4920
|
try {
|
|
4578
4921
|
const res = await fetch(req.url, { ...req.init, signal: controller == null ? void 0 : controller.signal });
|
|
4922
|
+
warnOnSkippedEvents(res);
|
|
4579
4923
|
return !!(res && res.ok);
|
|
4580
4924
|
} catch {
|
|
4581
4925
|
return false;
|
|
@@ -4660,15 +5004,14 @@ var useLifecycleEvents = (config, options = {}) => {
|
|
|
4660
5004
|
latest.current = { config, options };
|
|
4661
5005
|
const queueRef = useRef(void 0);
|
|
4662
5006
|
useEffect(() => {
|
|
4663
|
-
var _a2;
|
|
4664
5007
|
const resolveSink = () => {
|
|
4665
|
-
var
|
|
5008
|
+
var _a2, _b;
|
|
4666
5009
|
const { config: cfg, options: opts } = latest.current;
|
|
4667
5010
|
if (opts.sink) return opts.sink;
|
|
4668
5011
|
if (!(cfg == null ? void 0 : cfg.serverUrl)) return void 0;
|
|
4669
5012
|
if (!queueRef.current) {
|
|
4670
5013
|
queueRef.current = createEventQueue({
|
|
4671
|
-
target: { serverUrl: cfg.serverUrl, apiKey: (
|
|
5014
|
+
target: { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" },
|
|
4672
5015
|
storage: cfg.storage,
|
|
4673
5016
|
// Dedicated key so the hook's internal queue never collides with a host's main queue.
|
|
4674
5017
|
storageKey: `wireai:evtq:lifecycle:${(_b = cfg.appId) != null ? _b : "default"}`,
|
|
@@ -4678,12 +5021,18 @@ var useLifecycleEvents = (config, options = {}) => {
|
|
|
4678
5021
|
return queueRef.current.enqueue;
|
|
4679
5022
|
};
|
|
4680
5023
|
const targetOf = (cfg) => {
|
|
4681
|
-
var
|
|
4682
|
-
return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (
|
|
5024
|
+
var _a2;
|
|
5025
|
+
return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" } : void 0;
|
|
5026
|
+
};
|
|
5027
|
+
const resolveDeviceKey = (cfg, opts) => {
|
|
5028
|
+
const host = typeof opts.deviceKey === "string" && opts.deviceKey.trim() ? opts.deviceKey : void 0;
|
|
5029
|
+
if (host) return host;
|
|
5030
|
+
if (!(cfg == null ? void 0 : cfg.storage)) return void 0;
|
|
5031
|
+
return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
|
|
4683
5032
|
};
|
|
4684
5033
|
const mountOpenSessionId = makeSessionId();
|
|
4685
5034
|
const fireSession = (sessionId) => {
|
|
4686
|
-
var
|
|
5035
|
+
var _a2;
|
|
4687
5036
|
const { config: cfg, options: opts } = latest.current;
|
|
4688
5037
|
if (opts.enabled === false) return;
|
|
4689
5038
|
if (!(cfg == null ? void 0 : cfg.serverUrl) && !opts.sink) return;
|
|
@@ -4694,35 +5043,45 @@ var useLifecycleEvents = (config, options = {}) => {
|
|
|
4694
5043
|
sink: resolveSink(),
|
|
4695
5044
|
sessionId,
|
|
4696
5045
|
userId: opts.userId,
|
|
4697
|
-
deviceKey: opts
|
|
5046
|
+
deviceKey: resolveDeviceKey(cfg, opts),
|
|
4698
5047
|
sessionCount: opts.sessionCount,
|
|
4699
|
-
appVersion: (
|
|
5048
|
+
appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
|
|
4700
5049
|
platform: Platform.OS,
|
|
4701
5050
|
device,
|
|
4702
5051
|
meta: opts.meta
|
|
4703
5052
|
});
|
|
4704
5053
|
};
|
|
4705
|
-
|
|
4706
|
-
|
|
5054
|
+
const fireMountOpen = () => {
|
|
5055
|
+
var _a2;
|
|
5056
|
+
fireSession(mountOpenSessionId);
|
|
4707
5057
|
const { config: cfg, options: opts } = latest.current;
|
|
4708
|
-
if (opts.enabled
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
5058
|
+
if (opts.enabled === false) return;
|
|
5059
|
+
const device = collectDeviceContext();
|
|
5060
|
+
if (cfg == null ? void 0 : cfg.appVersion) device.appVersion = cfg.appVersion;
|
|
5061
|
+
reportFirstOpen({
|
|
5062
|
+
target: targetOf(cfg),
|
|
5063
|
+
sink: resolveSink(),
|
|
5064
|
+
sessionId: mountOpenSessionId,
|
|
5065
|
+
storage: cfg == null ? void 0 : cfg.storage,
|
|
5066
|
+
appId: cfg == null ? void 0 : cfg.appId,
|
|
5067
|
+
userId: opts.userId,
|
|
5068
|
+
deviceKey: resolveDeviceKey(cfg, opts),
|
|
5069
|
+
sessionCount: opts.sessionCount,
|
|
5070
|
+
appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
|
|
5071
|
+
platform: Platform.OS,
|
|
5072
|
+
device,
|
|
5073
|
+
meta: opts.meta
|
|
5074
|
+
});
|
|
5075
|
+
};
|
|
5076
|
+
let cancelled = false;
|
|
5077
|
+
const { config: mountCfg, options: mountOpts } = latest.current;
|
|
5078
|
+
const hostKey = typeof mountOpts.deviceKey === "string" && mountOpts.deviceKey.trim() ? mountOpts.deviceKey : void 0;
|
|
5079
|
+
if (!hostKey && (mountCfg == null ? void 0 : mountCfg.storage)) {
|
|
5080
|
+
void hydrateAutoDeviceKey({ appId: mountCfg.appId, storage: mountCfg.storage }).then(() => {
|
|
5081
|
+
if (!cancelled) fireMountOpen();
|
|
5082
|
+
});
|
|
5083
|
+
} else {
|
|
5084
|
+
fireMountOpen();
|
|
4726
5085
|
}
|
|
4727
5086
|
let backgroundedAt = null;
|
|
4728
5087
|
const onChange = (state) => {
|
|
@@ -4738,11 +5097,12 @@ var useLifecycleEvents = (config, options = {}) => {
|
|
|
4738
5097
|
};
|
|
4739
5098
|
const sub = AppState.addEventListener("change", onChange);
|
|
4740
5099
|
return () => {
|
|
5100
|
+
cancelled = true;
|
|
4741
5101
|
if (sub && typeof sub.remove === "function") sub.remove();
|
|
4742
5102
|
};
|
|
4743
5103
|
}, []);
|
|
4744
5104
|
};
|
|
4745
5105
|
|
|
4746
|
-
export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, CardGridSelectCard, CardHandoff, CenteredModal, ChipSelectCard, CompletionView, DEFAULT_FEATURES_TTL_MS, DEFAULT_SESSION_TTL_MS, DemoOnboarding, DoneBlock, EXTRA_KEY_PREFIX, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, IllustrationProvider, InterstitialCard, LoadingBlock, LoadingScreen, NumberStepperCard, Button as OnboardingButton, OnboardingFlow, OnboardingScaffold, OnboardingThemeProvider, RESERVED_USER_CONTEXT_KEYS, SESSION_STARTED_EVENT, SelectionCard, StatusCard, StepProgress, TextInputCard, USER_ID_MAX_LENGTH, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, WIRE_ONBOARDING_EVENTS, WireFeaturesProvider, WireIcon, WireOnboarding, analyticsUserIdStorageKey, attributionMetadata, bumpActivationRevalidation, clearPersistedSession, clearPiiFromContext, clearUserContext, collectDeviceContext, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, detectAppVersion, detectNativeModel, deviceIdStorageKey, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, getCurrentSessionId, hashEmailFnv1a, identifyOnboarding, isFeaturesFresh, isOnboardingEnabled, isWireScalar, loadPersistedSession, looksLikeEmail, lookupIconGlyph, makeSessionId, mergeTheme, mintDeviceId, motionSpec_exports as motionSpec, namespaceExtra, onboardingComponents, parseWireFeatures, peekPersistedSession, readCachedFeatures, readProgress, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetCurrentSessionId, resetFirstOpenLatch, resetSessionStartGuard, resolveUserContext, sanitizeUserId, savePersistedSession, sessionStorageKey, setCurrentSessionId, subscribeActivationRevalidation, themeFromBrand, toAnalyticsEvent, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
|
|
5106
|
+
export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, CardGridSelectCard, CardHandoff, CenteredModal, ChipSelectCard, CompletionView, DEFAULT_FEATURES_TTL_MS, DEFAULT_SESSION_TTL_MS, DemoOnboarding, DoneBlock, EXTRA_KEY_PREFIX, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, IllustrationProvider, InterstitialCard, LoadingBlock, LoadingScreen, NumberStepperCard, Button as OnboardingButton, OnboardingFlow, OnboardingScaffold, OnboardingThemeProvider, PLAN_TIER_CONTEXT_KEY, RESERVED_USER_CONTEXT_KEYS, SESSION_STARTED_EVENT, SelectionCard, StatusCard, StepProgress, TextInputCard, USER_ID_MAX_LENGTH, WIRE_ENV_VARS, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, WIRE_ONBOARDING_EVENTS, WIRE_PURCHASE_EVENTS, WireFeaturesProvider, WireIcon, WireOnboarding, activationJoinContext, activeEntitlement, analyticsUserIdStorageKey, attributionMetadata, bumpActivationRevalidation, clearPersistedSession, clearPiiFromContext, clearUserContext, collectDeviceContext, createRevenueCatBridge, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, describeEntitlement, describeFailure, describePackage, detectAppVersion, detectNativeModel, deviceIdStorageKey, ensureCurrentSessionId, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, getCurrentSessionId, hashEmailFnv1a, hydrateAutoDeviceKey, identifyOnboarding, isFeaturesFresh, isOnboardingEnabled, isUserCancelled, isWireScalar, loadPersistedSession, looksLikeEmail, lookupIconGlyph, makeSessionId, mergeTheme, mintDeviceId, motionSpec_exports as motionSpec, namespaceExtra, onboardingComponents, parseWireFeatures, peekPersistedSession, readCachedFeatures, readProgress, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetAutoDeviceKeys, resetCurrentSessionId, resetFirstOpenLatch, resetSessionStartGuard, resolveAutoDeviceKey, resolvePlanTier, resolveUserContext, sanitizeUserId, savePersistedSession, sessionStorageKey, setCurrentSessionId, subscribeActivationRevalidation, themeFromBrand, toAnalyticsEvent, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
|
|
4747
5107
|
//# sourceMappingURL=index.mjs.map
|
|
4748
5108
|
//# sourceMappingURL=index.mjs.map
|