@wireai/activation 0.12.2 → 0.13.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 +145 -0
- package/README.md +5 -3
- package/dist/analytics/index.d.mts +2 -2
- package/dist/analytics/index.d.ts +2 -2
- package/dist/analytics/index.js +114 -35
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +114 -36
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/{currentSession-BxEB37xt.d.ts → currentSession-D7zabMXK.d.ts} +161 -9
- package/dist/{currentSession-BlCeDP0f.d.mts → currentSession-_GynvhzT.d.mts} +161 -9
- package/dist/index.d.mts +5 -15
- package/dist/index.d.ts +5 -15
- package/dist/index.js +232 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +229 -134
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.js +8 -6
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +8 -6
- package/dist/reviews/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/OnboardingFlow.tsx +10 -3
- package/src/WireOnboarding.tsx +115 -32
- package/src/activation/wireActivation.ts +13 -7
- package/src/analytics/analyticsFacade.ts +11 -10
- package/src/analytics/currentSession.ts +6 -20
- package/src/analytics/eventQueue.ts +69 -1
- package/src/analytics/index.ts +1 -1
- package/src/analytics/reportClientEvent.ts +92 -29
- package/src/config/wireConfigFromEnv.ts +1 -10
- package/src/context/deviceId.ts +77 -16
- package/src/context/userContext.ts +4 -15
- package/src/identity/identityRecord.ts +123 -0
- package/src/identity/userIdentity.ts +45 -9
- package/src/index.ts +6 -4
- package/src/session-analytics/useLifecycleEvents.ts +10 -1
- package/src/types.ts +14 -0
- package/src/utils/deriveAnswers.ts +6 -2
- package/src/utils/readProgress.ts +4 -0
- package/src/utils/warnInDev.ts +33 -0
- package/src/components/DoneBlock.tsx +0 -37
package/dist/index.js
CHANGED
|
@@ -1012,26 +1012,26 @@ var _OnboardingScaffold = ({
|
|
|
1012
1012
|
children
|
|
1013
1013
|
}) => {
|
|
1014
1014
|
const t = useOnboardingTheme();
|
|
1015
|
-
const
|
|
1015
|
+
const styles17 = React18.useMemo(() => makeStyles(t), [t]);
|
|
1016
1016
|
const hit = { top: 12, bottom: 12, left: 12, right: 12 };
|
|
1017
1017
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1018
1018
|
reactNativeSafeAreaContext.SafeAreaView,
|
|
1019
1019
|
{
|
|
1020
1020
|
edges: ["top", "bottom"],
|
|
1021
|
-
style: [
|
|
1021
|
+
style: [styles17.flex, { backgroundColor: t.colors.background }],
|
|
1022
1022
|
children: [
|
|
1023
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
1024
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1025
|
-
onSkip ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onSkip, hitSlop: hit, style:
|
|
1023
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles17.header, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }], children: [
|
|
1024
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles17.progressWrap, children: /* @__PURE__ */ jsxRuntime.jsx(StepProgress, { step, complete, approxScreens }) }),
|
|
1025
|
+
onSkip ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onSkip, hitSlop: hit, style: styles17.skip, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: skipLabel }) }) : null
|
|
1026
1026
|
] }),
|
|
1027
1027
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
1028
|
reactNative.View,
|
|
1029
1029
|
{
|
|
1030
|
-
style: [
|
|
1030
|
+
style: [styles17.body, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }],
|
|
1031
1031
|
children
|
|
1032
1032
|
}
|
|
1033
1033
|
),
|
|
1034
|
-
onBack ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
1034
|
+
onBack ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles17.footer, { paddingHorizontal: t.spacing.md, paddingBottom: t.spacing.sm }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.TouchableOpacity, { onPress: onBack, hitSlop: hit, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: backLabel }) }) }) : null
|
|
1035
1035
|
]
|
|
1036
1036
|
}
|
|
1037
1037
|
);
|
|
@@ -1168,10 +1168,10 @@ var _CardLayout = ({
|
|
|
1168
1168
|
titleNode
|
|
1169
1169
|
}) => {
|
|
1170
1170
|
const t = useOnboardingTheme();
|
|
1171
|
-
const
|
|
1171
|
+
const styles17 = React18.useMemo(() => makeStyles2(t), [t]);
|
|
1172
1172
|
const hasHeader = !!title || !!subtitle || !!titleNode;
|
|
1173
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.KeyboardAvoidingView, { style:
|
|
1174
|
-
hasHeader ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
1173
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.KeyboardAvoidingView, { style: styles17.fill, behavior: "padding", children: [
|
|
1174
|
+
hasHeader ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles17.header, children: [
|
|
1175
1175
|
titleNode != null ? titleNode : title ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [labelStyle(t.fonts), { color: t.colors.text }], children: title }) : null,
|
|
1176
1176
|
subtitle ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1177
1177
|
reactNative.Text,
|
|
@@ -1187,10 +1187,10 @@ var _CardLayout = ({
|
|
|
1187
1187
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1188
1188
|
reactNative.ScrollView,
|
|
1189
1189
|
{
|
|
1190
|
-
style:
|
|
1190
|
+
style: styles17.fill,
|
|
1191
1191
|
contentContainerStyle: [
|
|
1192
|
-
|
|
1193
|
-
align === "center" &&
|
|
1192
|
+
styles17.scrollContent,
|
|
1193
|
+
align === "center" && styles17.center
|
|
1194
1194
|
],
|
|
1195
1195
|
keyboardShouldPersistTaps: "handled",
|
|
1196
1196
|
keyboardDismissMode: "on-drag",
|
|
@@ -1198,7 +1198,7 @@ var _CardLayout = ({
|
|
|
1198
1198
|
children
|
|
1199
1199
|
}
|
|
1200
1200
|
),
|
|
1201
|
-
footer ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
1201
|
+
footer ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles17.footer, children: footer }) : null
|
|
1202
1202
|
] });
|
|
1203
1203
|
};
|
|
1204
1204
|
var CardLayout = React18__default.default.memo(_CardLayout);
|
|
@@ -1480,7 +1480,7 @@ var deriveAnswers = (messages) => {
|
|
|
1480
1480
|
const props = (_a2 = r.props) != null ? _a2 : {};
|
|
1481
1481
|
const progress = props.progress;
|
|
1482
1482
|
const questionText = (_c = (_b = props.title) != null ? _b : props.label) != null ? _c : props.question;
|
|
1483
|
-
const key = (progress == null ? void 0 : progress.key) || questionText;
|
|
1483
|
+
const key = (progress == null ? void 0 : progress.slot_id) || (progress == null ? void 0 : progress.key) || questionText;
|
|
1484
1484
|
const reply = messages[i + 1];
|
|
1485
1485
|
if (key && (reply == null ? void 0 : reply.role) === "user") {
|
|
1486
1486
|
out[key] = tryParse(stripPrefix(reply.content));
|
|
@@ -1501,6 +1501,8 @@ var readProgress = (response) => {
|
|
|
1501
1501
|
step: typeof p.step === "number" ? p.step : void 0,
|
|
1502
1502
|
total: typeof p.total === "number" ? p.total : void 0,
|
|
1503
1503
|
key: typeof p.key === "string" ? p.key : void 0,
|
|
1504
|
+
// Whitelisted the same way as every other field: an old backend simply omits it.
|
|
1505
|
+
slot_id: typeof p.slot_id === "string" ? p.slot_id : void 0,
|
|
1504
1506
|
skippable: typeof p.skippable === "boolean" ? p.skippable : void 0
|
|
1505
1507
|
};
|
|
1506
1508
|
};
|
|
@@ -1518,28 +1520,35 @@ var buildEventsRequest = (target, events) => {
|
|
|
1518
1520
|
return null;
|
|
1519
1521
|
}
|
|
1520
1522
|
};
|
|
1521
|
-
var
|
|
1522
|
-
if (typeof __DEV__ === "undefined" || !__DEV__) return;
|
|
1523
|
-
if (typeof console === "undefined" || !console.warn) return;
|
|
1523
|
+
var readEventsAck = async (res) => {
|
|
1524
1524
|
try {
|
|
1525
1525
|
const json = res == null ? void 0 : res.json;
|
|
1526
|
-
if (typeof json !== "function") return;
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
);
|
|
1533
|
-
}).catch(() => {
|
|
1534
|
-
});
|
|
1526
|
+
if (typeof json !== "function") return void 0;
|
|
1527
|
+
const body = await Promise.resolve(json.call(res));
|
|
1528
|
+
const skipped = body == null ? void 0 : body.skipped;
|
|
1529
|
+
if (typeof skipped !== "number" || !Number.isFinite(skipped)) return void 0;
|
|
1530
|
+
const reasons = Array.isArray(body == null ? void 0 : body.errors) ? body.errors.map((e) => e == null ? void 0 : e.reason).filter((r) => typeof r === "string") : [];
|
|
1531
|
+
return { written: typeof (body == null ? void 0 : body.written) === "number" ? body.written : void 0, skipped, reasons };
|
|
1535
1532
|
} catch {
|
|
1533
|
+
return void 0;
|
|
1536
1534
|
}
|
|
1537
1535
|
};
|
|
1536
|
+
var describeDiscarded = (ack) => `[wireai] the server ACCEPTED the /v1/events POST but DISCARDED ${ack.skipped} event(s) (skipped in the response body) \u2014 they are gone, not retried. The server reported: skipped=${ack.skipped}${ack.written !== void 0 ? `, written=${ack.written}` : ""}` + (ack.reasons.length > 0 ? `, reasons: ${ack.reasons.join(", ")}.` : ". It gave no reason (the endpoint folds every rejection into one count), so check the server's ingest log for this request rather than guessing.");
|
|
1537
|
+
var warnOnSkippedEvents = (res) => {
|
|
1538
|
+
if (typeof __DEV__ === "undefined" || !__DEV__) return;
|
|
1539
|
+
if (typeof console === "undefined" || !console.warn) return;
|
|
1540
|
+
void readEventsAck(res).then((ack) => {
|
|
1541
|
+
if (!ack || ack.skipped <= 0) return;
|
|
1542
|
+
console.warn(describeDiscarded(ack));
|
|
1543
|
+
});
|
|
1544
|
+
};
|
|
1538
1545
|
var reportClientEvents = (target, events) => {
|
|
1539
1546
|
try {
|
|
1540
1547
|
const req = buildEventsRequest(target, events);
|
|
1541
1548
|
if (!req) return;
|
|
1542
|
-
void fetch(req.url, req.init).
|
|
1549
|
+
void fetch(req.url, req.init).then((res) => {
|
|
1550
|
+
warnOnSkippedEvents(res);
|
|
1551
|
+
}).catch(() => {
|
|
1543
1552
|
});
|
|
1544
1553
|
} catch {
|
|
1545
1554
|
}
|
|
@@ -1550,7 +1559,13 @@ var reportClientEventsAwait = async (target, events) => {
|
|
|
1550
1559
|
const req = buildEventsRequest(target, events);
|
|
1551
1560
|
if (!req) return false;
|
|
1552
1561
|
const res = await fetch(req.url, req.init);
|
|
1553
|
-
|
|
1562
|
+
if (!res || !res.ok) return false;
|
|
1563
|
+
const ack = await readEventsAck(res);
|
|
1564
|
+
if (!ack || ack.skipped <= 0) return true;
|
|
1565
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
1566
|
+
console.warn(describeDiscarded(ack));
|
|
1567
|
+
}
|
|
1568
|
+
return false;
|
|
1554
1569
|
} catch {
|
|
1555
1570
|
return false;
|
|
1556
1571
|
}
|
|
@@ -1770,8 +1785,8 @@ var OnboardingFlow = ({
|
|
|
1770
1785
|
(messageId) => {
|
|
1771
1786
|
var _a3;
|
|
1772
1787
|
const base = makeActions(messageId);
|
|
1773
|
-
const
|
|
1774
|
-
const validator =
|
|
1788
|
+
const validators2 = validatorsRef.current;
|
|
1789
|
+
const validator = (_a3 = progress.slot_id ? validators2 == null ? void 0 : validators2[progress.slot_id] : void 0) != null ? _a3 : progress.key ? validators2 == null ? void 0 : validators2[progress.key] : void 0;
|
|
1775
1790
|
if (!validator) return base;
|
|
1776
1791
|
const out = { ...base };
|
|
1777
1792
|
for (const name2 of ANSWER_CALLBACKS) {
|
|
@@ -1796,7 +1811,7 @@ var OnboardingFlow = ({
|
|
|
1796
1811
|
}
|
|
1797
1812
|
return out;
|
|
1798
1813
|
},
|
|
1799
|
-
[makeActions, progress.key]
|
|
1814
|
+
[makeActions, progress.key, progress.slot_id]
|
|
1800
1815
|
);
|
|
1801
1816
|
if (degraded) {
|
|
1802
1817
|
if (fallbackFlow !== void 0) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallbackFlow });
|
|
@@ -2107,7 +2122,7 @@ var _TextInputCard = ({
|
|
|
2107
2122
|
lines = 6
|
|
2108
2123
|
}) => {
|
|
2109
2124
|
const t = useOnboardingTheme();
|
|
2110
|
-
const
|
|
2125
|
+
const styles17 = React18.useMemo(() => makeStyles3(t), [t]);
|
|
2111
2126
|
const { height: screenHeight } = reactNative.useWindowDimensions();
|
|
2112
2127
|
const [value, setValue] = React18.useState("");
|
|
2113
2128
|
const [submitted, setSubmitted] = React18.useState(false);
|
|
@@ -2134,7 +2149,7 @@ var _TextInputCard = ({
|
|
|
2134
2149
|
disabled: !value.trim() || locked
|
|
2135
2150
|
}
|
|
2136
2151
|
),
|
|
2137
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2152
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles17.row, children: [
|
|
2138
2153
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2139
2154
|
reactNative.TextInput,
|
|
2140
2155
|
{
|
|
@@ -2148,7 +2163,7 @@ var _TextInputCard = ({
|
|
|
2148
2163
|
textAlignVertical: multiline ? "top" : "center",
|
|
2149
2164
|
style: [
|
|
2150
2165
|
bodyStyle(t.fonts),
|
|
2151
|
-
|
|
2166
|
+
styles17.input,
|
|
2152
2167
|
{
|
|
2153
2168
|
color: t.colors.text,
|
|
2154
2169
|
backgroundColor: t.colors.surface,
|
|
@@ -2874,7 +2889,7 @@ var _NumberStepperCard = ({
|
|
|
2874
2889
|
onSubmit
|
|
2875
2890
|
}) => {
|
|
2876
2891
|
const t = useOnboardingTheme();
|
|
2877
|
-
const
|
|
2892
|
+
const styles17 = React18.useMemo(() => makeStyles4(t), [t]);
|
|
2878
2893
|
const safeMin = safeNum(min, 1);
|
|
2879
2894
|
const safeMaxRaw = safeNum(max, 30);
|
|
2880
2895
|
const safeMax = safeMaxRaw < safeMin ? safeMin : safeMaxRaw;
|
|
@@ -2898,7 +2913,7 @@ var _NumberStepperCard = ({
|
|
|
2898
2913
|
const atMin = value <= safeMin;
|
|
2899
2914
|
const atMax = value >= safeMax;
|
|
2900
2915
|
const stepBtnStyle = (disabled) => [
|
|
2901
|
-
|
|
2916
|
+
styles17.stepBtn,
|
|
2902
2917
|
{ borderRadius: t.radius.full, backgroundColor: t.colors.background, borderColor: disabled ? t.colors.border : t.colors.primary }
|
|
2903
2918
|
];
|
|
2904
2919
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2907,10 +2922,10 @@ var _NumberStepperCard = ({
|
|
|
2907
2922
|
title: label,
|
|
2908
2923
|
align: "center",
|
|
2909
2924
|
footer: /* @__PURE__ */ jsxRuntime.jsx(Button, { title: submitLabel, onPress: handleSubmit, variant: "primary", disabled: submitted }),
|
|
2910
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2911
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [
|
|
2925
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles17.wrap, children: [
|
|
2926
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles17.stepper, { gap: t.spacing.lg }], children: [
|
|
2912
2927
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: atMin || submitted ? void 0 : handleDecrement, disabled: atMin || submitted, style: stepBtnStyle(atMin), children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: atMin ? t.colors.textMuted : t.colors.primary }], children: "\u2212" }) }),
|
|
2913
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
2928
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles17.valueBox, children: [
|
|
2914
2929
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: t.colors.primary }], children: String(value) }),
|
|
2915
2930
|
unit ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [captionStyle(t.fonts), { color: t.colors.textMuted }], children: unit }) : null
|
|
2916
2931
|
] }),
|
|
@@ -3317,6 +3332,33 @@ var collectDeviceContext = () => {
|
|
|
3317
3332
|
return ctx;
|
|
3318
3333
|
};
|
|
3319
3334
|
|
|
3335
|
+
// src/identity/identityRecord.ts
|
|
3336
|
+
var IDENTITY_PROVENANCE_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:identityProvenance");
|
|
3337
|
+
var provenanceGlobal = globalThis;
|
|
3338
|
+
var provenanceRegistry = () => {
|
|
3339
|
+
const existing = provenanceGlobal[IDENTITY_PROVENANCE_SLOT];
|
|
3340
|
+
if (existing) return existing;
|
|
3341
|
+
const created = { host: /* @__PURE__ */ new Map() };
|
|
3342
|
+
provenanceGlobal[IDENTITY_PROVENANCE_SLOT] = created;
|
|
3343
|
+
return created;
|
|
3344
|
+
};
|
|
3345
|
+
var provenanceKey = (space, scope) => `${space}:${scope != null ? scope : "default"}`;
|
|
3346
|
+
var resolveIdentity = (input) => {
|
|
3347
|
+
var _a2;
|
|
3348
|
+
if (typeof input.value !== "string") return void 0;
|
|
3349
|
+
const value = input.value.trim();
|
|
3350
|
+
if (!value) return void 0;
|
|
3351
|
+
const durable = (_a2 = input.durable) != null ? _a2 : input.source === "host";
|
|
3352
|
+
if (input.source === "host") {
|
|
3353
|
+
provenanceRegistry().host.set(provenanceKey(input.space, input.scope), value);
|
|
3354
|
+
}
|
|
3355
|
+
return { value, space: input.space, source: input.source, durable };
|
|
3356
|
+
};
|
|
3357
|
+
var hostIdentity = (space, scope) => provenanceRegistry().host.get(provenanceKey(space, scope));
|
|
3358
|
+
var resetIdentityProvenance = () => {
|
|
3359
|
+
provenanceRegistry().host.clear();
|
|
3360
|
+
};
|
|
3361
|
+
|
|
3320
3362
|
// src/context/deviceId.ts
|
|
3321
3363
|
var AUTO_DEVICE_ID_PREFIX = "wdev_";
|
|
3322
3364
|
var deviceIdStorageKey = (appId) => `wireai:analytics:deviceKey:${appId != null ? appId : "default"}`;
|
|
@@ -3339,24 +3381,37 @@ var startHydration = (registry, appId, storage, minted) => {
|
|
|
3339
3381
|
const existing = registry.pending.get(appId);
|
|
3340
3382
|
if (existing) return existing;
|
|
3341
3383
|
const slot = deviceIdStorageKey(appId);
|
|
3342
|
-
const
|
|
3384
|
+
const degraded = () => {
|
|
3343
3385
|
var _a2;
|
|
3344
|
-
return (_a2 = registry.keys.get(appId)) != null ? _a2 : minted;
|
|
3386
|
+
return { value: (_a2 = registry.keys.get(appId)) != null ? _a2 : minted, durable: false };
|
|
3345
3387
|
};
|
|
3388
|
+
const adopted = (value) => ({ value, durable: true });
|
|
3346
3389
|
let run;
|
|
3347
3390
|
try {
|
|
3348
3391
|
run = Promise.resolve(storage.getItem(slot)).then((saved) => {
|
|
3349
3392
|
const persisted = typeof saved === "string" && saved.trim() ? saved.trim() : void 0;
|
|
3350
3393
|
if (persisted) {
|
|
3351
3394
|
registry.keys.set(appId, persisted);
|
|
3352
|
-
return persisted;
|
|
3395
|
+
return adopted(persisted);
|
|
3353
3396
|
}
|
|
3354
|
-
return Promise.resolve(storage.setItem(slot, minted)).then(
|
|
3355
|
-
|
|
3397
|
+
return Promise.resolve(storage.setItem(slot, minted)).then(
|
|
3398
|
+
() => {
|
|
3399
|
+
var _a2;
|
|
3400
|
+
return adopted((_a2 = registry.keys.get(appId)) != null ? _a2 : minted);
|
|
3401
|
+
},
|
|
3402
|
+
degraded
|
|
3403
|
+
);
|
|
3404
|
+
}).catch(degraded);
|
|
3356
3405
|
} catch {
|
|
3357
|
-
run = Promise.resolve(
|
|
3406
|
+
run = Promise.resolve(degraded());
|
|
3358
3407
|
}
|
|
3359
3408
|
registry.pending.set(appId, run);
|
|
3409
|
+
void run.then((outcome) => {
|
|
3410
|
+
var _a2;
|
|
3411
|
+
if (outcome.durable) return;
|
|
3412
|
+
(_a2 = registry.pending) == null ? void 0 : _a2.delete(appId);
|
|
3413
|
+
registry.hydrating.delete(appId);
|
|
3414
|
+
});
|
|
3360
3415
|
return run;
|
|
3361
3416
|
};
|
|
3362
3417
|
var resolveAutoDeviceKey = (opts = {}) => {
|
|
@@ -3376,14 +3431,20 @@ var resolveAutoDeviceKey = (opts = {}) => {
|
|
|
3376
3431
|
return (_b = registry.keys.get(appId)) != null ? _b : id;
|
|
3377
3432
|
};
|
|
3378
3433
|
var hydrateAutoDeviceKey = async (opts = {}) => {
|
|
3434
|
+
var _a2, _b;
|
|
3435
|
+
return (_b = (_a2 = await hydrateDeviceIdentity(opts)) == null ? void 0 : _a2.value) != null ? _b : resolveAutoDeviceKey(opts);
|
|
3436
|
+
};
|
|
3437
|
+
var hydrateDeviceIdentity = async (opts = {}) => {
|
|
3379
3438
|
var _a2, _b, _c;
|
|
3380
3439
|
const id = resolveAutoDeviceKey(opts);
|
|
3381
|
-
if (!opts.storage) return id;
|
|
3382
|
-
const registry = autoDeviceKeyRegistry();
|
|
3383
3440
|
const appId = (_a2 = opts.appId) != null ? _a2 : "default";
|
|
3441
|
+
const record = (value, durable) => resolveIdentity({ value, space: "device", source: "auto", durable, scope: appId });
|
|
3442
|
+
if (!opts.storage) return record(id, false);
|
|
3443
|
+
const registry = autoDeviceKeyRegistry();
|
|
3384
3444
|
const pending = (_b = registry.pending) == null ? void 0 : _b.get(appId);
|
|
3385
|
-
if (pending)
|
|
3386
|
-
|
|
3445
|
+
if (!pending) return record((_c = registry.keys.get(appId)) != null ? _c : id, false);
|
|
3446
|
+
const outcome = await pending;
|
|
3447
|
+
return record(outcome.value, outcome.durable);
|
|
3387
3448
|
};
|
|
3388
3449
|
var resetAutoDeviceKeys = () => {
|
|
3389
3450
|
var _a2;
|
|
@@ -3393,6 +3454,15 @@ var resetAutoDeviceKeys = () => {
|
|
|
3393
3454
|
(_a2 = registry.pending) == null ? void 0 : _a2.clear();
|
|
3394
3455
|
};
|
|
3395
3456
|
|
|
3457
|
+
// src/utils/warnInDev.ts
|
|
3458
|
+
var warnInDev = (message) => {
|
|
3459
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
3460
|
+
console.warn(message);
|
|
3461
|
+
return true;
|
|
3462
|
+
}
|
|
3463
|
+
return false;
|
|
3464
|
+
};
|
|
3465
|
+
|
|
3396
3466
|
// src/analytics/currentSession.ts
|
|
3397
3467
|
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
3398
3468
|
"@wireai/activation:currentSessionId"
|
|
@@ -3407,13 +3477,6 @@ var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
|
3407
3477
|
var resetCurrentSessionId = () => {
|
|
3408
3478
|
globalSlot[CURRENT_SESSION_ID_SLOT] = void 0;
|
|
3409
3479
|
};
|
|
3410
|
-
var warnInDev = (message) => {
|
|
3411
|
-
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
3412
|
-
console.warn(message);
|
|
3413
|
-
return true;
|
|
3414
|
-
}
|
|
3415
|
-
return false;
|
|
3416
|
-
};
|
|
3417
3480
|
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.";
|
|
3418
3481
|
var MINT_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
|
|
3419
3482
|
"@wireai/activation:currentSessionIdMintWarned"
|
|
@@ -3510,27 +3573,20 @@ var identifyOnboarding = async (opts) => {
|
|
|
3510
3573
|
contextId = stored == null ? void 0 : stored.id;
|
|
3511
3574
|
}
|
|
3512
3575
|
}
|
|
3513
|
-
|
|
3576
|
+
let space = "onboarding";
|
|
3577
|
+
if (!contextId && opts.allowAppSessionFallback) {
|
|
3578
|
+
contextId = getCurrentSessionId();
|
|
3579
|
+
space = "app_session";
|
|
3580
|
+
}
|
|
3514
3581
|
if (!contextId) return false;
|
|
3515
3582
|
reportClientEvent(
|
|
3516
3583
|
{ serverUrl: opts.config.serverUrl, apiKey: opts.config.apiKey },
|
|
3517
3584
|
{ event_type: "identify", session_id: contextId, user_id: userId }
|
|
3518
3585
|
);
|
|
3519
|
-
return
|
|
3586
|
+
return space;
|
|
3520
3587
|
};
|
|
3521
3588
|
|
|
3522
3589
|
// src/context/userContext.ts
|
|
3523
|
-
var RESERVED_USER_CONTEXT_KEYS = [
|
|
3524
|
-
"device_key",
|
|
3525
|
-
"app_version",
|
|
3526
|
-
"app_build",
|
|
3527
|
-
"network_type",
|
|
3528
|
-
"session_count",
|
|
3529
|
-
"returning",
|
|
3530
|
-
"platform",
|
|
3531
|
-
"user_email",
|
|
3532
|
-
"user_email_hashed"
|
|
3533
|
-
];
|
|
3534
3590
|
var EXTRA_KEY_PREFIX = "custom.";
|
|
3535
3591
|
var isWireScalar = (value) => {
|
|
3536
3592
|
const t = typeof value;
|
|
@@ -3611,11 +3667,6 @@ var resolveUserContext = (ctx = {}, opts = {}) => {
|
|
|
3611
3667
|
if (Object.keys(bucket).length > 0) result.userContext = bucket;
|
|
3612
3668
|
return result;
|
|
3613
3669
|
};
|
|
3614
|
-
var warnInDev2 = (message) => {
|
|
3615
|
-
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
3616
|
-
console.warn(message);
|
|
3617
|
-
}
|
|
3618
|
-
};
|
|
3619
3670
|
var AUTO_JOIN_HYDRATION_TIMEOUT_MS = 1500;
|
|
3620
3671
|
var WireOnboarding = ({
|
|
3621
3672
|
config,
|
|
@@ -3642,7 +3693,7 @@ var WireOnboarding = ({
|
|
|
3642
3693
|
userId,
|
|
3643
3694
|
autoJoinKey = true
|
|
3644
3695
|
}) => {
|
|
3645
|
-
var _a2, _b, _c;
|
|
3696
|
+
var _a2, _b, _c, _d, _e;
|
|
3646
3697
|
const boundUserId = React18.useMemo(() => sanitizeUserId(userId), [userId]);
|
|
3647
3698
|
const device = React18.useMemo(() => {
|
|
3648
3699
|
const collected = collectDeviceContext();
|
|
@@ -3653,44 +3704,72 @@ var WireOnboarding = ({
|
|
|
3653
3704
|
() => userContextKey ? JSON.parse(userContextKey) : void 0,
|
|
3654
3705
|
[userContextKey]
|
|
3655
3706
|
);
|
|
3656
|
-
const
|
|
3707
|
+
const hostJoinIdentity = React18.useMemo(
|
|
3708
|
+
() => resolveIdentity({
|
|
3709
|
+
value: userContextStable == null ? void 0 : userContextStable.device_key,
|
|
3710
|
+
space: "device",
|
|
3711
|
+
source: "host",
|
|
3712
|
+
scope: config.appId
|
|
3713
|
+
}),
|
|
3714
|
+
[userContextStable, config.appId]
|
|
3715
|
+
);
|
|
3716
|
+
const missingJoinKey = !hostJoinIdentity;
|
|
3657
3717
|
const autoJoinPossible = Boolean(storage) && autoJoinKey !== false;
|
|
3658
3718
|
const wantsAutoJoin = missingJoinKey && autoJoinPossible;
|
|
3659
|
-
const [
|
|
3719
|
+
const [autoJoinOutcome, setAutoJoinOutcome] = React18.useState(void 0);
|
|
3660
3720
|
React18.useEffect(() => {
|
|
3661
|
-
if (!wantsAutoJoin ||
|
|
3721
|
+
if (!wantsAutoJoin || autoJoinOutcome !== void 0 || !storage) return;
|
|
3662
3722
|
let cancelled = false;
|
|
3663
3723
|
const timer = setTimeout(() => {
|
|
3664
|
-
if (!cancelled)
|
|
3724
|
+
if (!cancelled) setAutoJoinOutcome({ key: null, reason: "timeout" });
|
|
3665
3725
|
}, AUTO_JOIN_HYDRATION_TIMEOUT_MS);
|
|
3666
|
-
void
|
|
3726
|
+
void hydrateDeviceIdentity({ appId: config.appId, storage }).then((identity) => {
|
|
3667
3727
|
if (cancelled) return;
|
|
3668
3728
|
clearTimeout(timer);
|
|
3669
|
-
|
|
3729
|
+
setAutoJoinOutcome(
|
|
3730
|
+
(identity == null ? void 0 : identity.durable) ? { key: identity.value } : { key: null, reason: "not-durable" }
|
|
3731
|
+
);
|
|
3670
3732
|
});
|
|
3671
3733
|
return () => {
|
|
3672
3734
|
cancelled = true;
|
|
3673
3735
|
clearTimeout(timer);
|
|
3674
3736
|
};
|
|
3675
|
-
}, [wantsAutoJoin,
|
|
3676
|
-
const injectedJoinKey = wantsAutoJoin
|
|
3677
|
-
const autoJoinPending = wantsAutoJoin &&
|
|
3737
|
+
}, [wantsAutoJoin, autoJoinOutcome, config.appId, storage]);
|
|
3738
|
+
const injectedJoinKey = wantsAutoJoin ? (_a2 = autoJoinOutcome == null ? void 0 : autoJoinOutcome.key) != null ? _a2 : void 0 : void 0;
|
|
3739
|
+
const autoJoinPending = wantsAutoJoin && autoJoinOutcome === void 0;
|
|
3678
3740
|
const effectiveUserContext = React18.useMemo(
|
|
3679
3741
|
() => injectedJoinKey ? { ...userContextStable, ...activationJoinContext(injectedJoinKey) } : userContextStable,
|
|
3680
3742
|
[userContextStable, injectedJoinKey]
|
|
3681
3743
|
);
|
|
3744
|
+
const frozenWireContextRef = React18.useRef(null);
|
|
3745
|
+
if (!autoJoinPending && frozenWireContextRef.current === null) {
|
|
3746
|
+
frozenWireContextRef.current = effectiveUserContext ? JSON.stringify(effectiveUserContext) : "";
|
|
3747
|
+
}
|
|
3748
|
+
const startupUserContextKey = (_b = frozenWireContextRef.current) != null ? _b : "";
|
|
3749
|
+
const startupUserContext = React18.useMemo(
|
|
3750
|
+
() => startupUserContextKey ? JSON.parse(startupUserContextKey) : void 0,
|
|
3751
|
+
[startupUserContextKey]
|
|
3752
|
+
);
|
|
3682
3753
|
const warnMissingJoinKey = missingJoinKey && !injectedJoinKey && !autoJoinPending;
|
|
3683
|
-
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.";
|
|
3754
|
+
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." : (autoJoinOutcome == null ? void 0 : autoJoinOutcome.key) === null && autoJoinOutcome.reason === "not-durable" ? "your `storage` adapter answered but could not persist the key (the read or the write failed), so the key would be different on every launch, which corrupts min_sessions instead of merely leaving the join empty. Check the adapter you passed as `storage`." : "your `storage` adapter did not answer in time.";
|
|
3684
3755
|
React18.useEffect(() => {
|
|
3685
3756
|
if (!warnMissingJoinKey) return;
|
|
3686
|
-
|
|
3757
|
+
warnInDev(
|
|
3687
3758
|
"[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
|
|
3688
3759
|
);
|
|
3689
3760
|
}, [warnMissingJoinKey, autoJoinReason]);
|
|
3761
|
+
const hostKeyElsewhere = missingJoinKey ? hostIdentity("device", config.appId) : void 0;
|
|
3762
|
+
const warnHostKeyElsewhere = Boolean(hostKeyElsewhere) && Boolean(injectedJoinKey);
|
|
3763
|
+
React18.useEffect(() => {
|
|
3764
|
+
if (!warnHostKeyElsewhere) return;
|
|
3765
|
+
warnInDev(
|
|
3766
|
+
`[wireai] <WireOnboarding> got no user_context.device_key, so the kit injected its own \u2014 but another surface in this app was constructed WITH a host-supplied device key ("${hostKeyElsewhere}"). Your app events carry that id and this onboarding session carries the kit's, so the two land in disjoint id spaces and the \`activated\` funnel still reads zero. Pass the SAME id here: userContext={activationJoinContext(deviceKey)}.`
|
|
3767
|
+
);
|
|
3768
|
+
}, [warnHostKeyElsewhere, hostKeyElsewhere]);
|
|
3690
3769
|
const misspelledJoinKey = missingJoinKey && typeof (userContextStable == null ? void 0 : userContextStable.deviceKey) === "string" && Boolean(userContextStable.deviceKey.trim());
|
|
3691
3770
|
React18.useEffect(() => {
|
|
3692
3771
|
if (!misspelledJoinKey || !injectedJoinKey) return;
|
|
3693
|
-
|
|
3772
|
+
warnInDev(
|
|
3694
3773
|
"[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."
|
|
3695
3774
|
);
|
|
3696
3775
|
}, [misspelledJoinKey, injectedJoinKey]);
|
|
@@ -3719,7 +3798,7 @@ var WireOnboarding = ({
|
|
|
3719
3798
|
},
|
|
3720
3799
|
[storage, storageKey, retainSessionOnComplete, onComplete]
|
|
3721
3800
|
);
|
|
3722
|
-
const sessionId = (
|
|
3801
|
+
const sessionId = (_c = session == null ? void 0 : session.id) != null ? _c : "";
|
|
3723
3802
|
const startupUserIdRef = React18.useRef(boundUserId);
|
|
3724
3803
|
const metadataKey = config.metadata ? JSON.stringify(config.metadata) : "";
|
|
3725
3804
|
const metadataStable = React18.useMemo(() => metadataKey ? JSON.parse(metadataKey) : void 0, [metadataKey]);
|
|
@@ -3743,7 +3822,9 @@ var WireOnboarding = ({
|
|
|
3743
3822
|
// Device snapshot + host-injected user context ride the session-start metadata so the
|
|
3744
3823
|
// backend can segment the funnel. Old servers ignore these unknown keys (backward compat).
|
|
3745
3824
|
device,
|
|
3746
|
-
|
|
3825
|
+
// The FROZEN wire context, never the live one — see the freeze note above. A change here
|
|
3826
|
+
// recreates the A2A adapter and drops `contextId`.
|
|
3827
|
+
...startupUserContext ? { userContext: startupUserContext } : {},
|
|
3747
3828
|
// The session-start user id (from the ref) rides the session-start metadata so the
|
|
3748
3829
|
// server binds the session to a real user at creation. Reading the ref — not
|
|
3749
3830
|
// `boundUserId` — keeps this memo off the userId dependency, so a mid-session change
|
|
@@ -3752,7 +3833,7 @@ var WireOnboarding = ({
|
|
|
3752
3833
|
},
|
|
3753
3834
|
timeoutMs: 6e4
|
|
3754
3835
|
};
|
|
3755
|
-
}, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device,
|
|
3836
|
+
}, [config.serverUrl, config.appId, config.apiKey, metadataStable, sessionId, componentsStable, device, startupUserContext]);
|
|
3756
3837
|
const reportTarget = React18.useMemo(
|
|
3757
3838
|
() => ({ serverUrl: config.serverUrl, apiKey: config.apiKey }),
|
|
3758
3839
|
[config.serverUrl, config.apiKey]
|
|
@@ -3778,8 +3859,8 @@ var WireOnboarding = ({
|
|
|
3778
3859
|
return /* @__PURE__ */ jsxRuntime.jsx(OnboardingThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3779
3860
|
LoadingScreen,
|
|
3780
3861
|
{
|
|
3781
|
-
title: (
|
|
3782
|
-
hint: (
|
|
3862
|
+
title: (_d = copy == null ? void 0 : copy.restoringTitle) != null ? _d : DEFAULT_COPY.restoringTitle,
|
|
3863
|
+
hint: (_e = copy == null ? void 0 : copy.restoringHint) != null ? _e : DEFAULT_COPY.restoringHint
|
|
3783
3864
|
}
|
|
3784
3865
|
) });
|
|
3785
3866
|
}
|
|
@@ -3817,7 +3898,7 @@ function DemoOnboarding({
|
|
|
3817
3898
|
const [open, setOpen] = React18.useState(false);
|
|
3818
3899
|
const [runId, setRunId] = React18.useState(0);
|
|
3819
3900
|
const t = React18.useMemo(() => mergeTheme(theme != null ? theme : {}), [theme]);
|
|
3820
|
-
const
|
|
3901
|
+
const styles17 = React18.useMemo(() => makeStyles5(t), [t]);
|
|
3821
3902
|
const openDemo = React18.useCallback(() => {
|
|
3822
3903
|
setRunId((n) => n + 1);
|
|
3823
3904
|
setOpen(true);
|
|
@@ -3831,7 +3912,7 @@ function DemoOnboarding({
|
|
|
3831
3912
|
[onComplete]
|
|
3832
3913
|
);
|
|
3833
3914
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3834
|
-
renderTrigger ? renderTrigger(openDemo) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: openDemo, style:
|
|
3915
|
+
renderTrigger ? renderTrigger(openDemo) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: openDemo, style: styles17.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles17.triggerText, children: label }) }),
|
|
3835
3916
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3836
3917
|
reactNative.Modal,
|
|
3837
3918
|
{
|
|
@@ -3839,7 +3920,7 @@ function DemoOnboarding({
|
|
|
3839
3920
|
animationType: "slide",
|
|
3840
3921
|
presentationStyle: "fullScreen",
|
|
3841
3922
|
onRequestClose: close,
|
|
3842
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
3923
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles17.modal, children: config ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3843
3924
|
WireOnboarding,
|
|
3844
3925
|
{
|
|
3845
3926
|
config,
|
|
@@ -3852,10 +3933,10 @@ function DemoOnboarding({
|
|
|
3852
3933
|
onError: close
|
|
3853
3934
|
},
|
|
3854
3935
|
runId
|
|
3855
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
3856
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
3857
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style:
|
|
3858
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: close, style:
|
|
3936
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles17.notice, children: [
|
|
3937
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles17.noticeTitle, children: "Wire AI not configured" }),
|
|
3938
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles17.noticeBody, children: "Set the Wire AI key + server URL (e.g. via wireConfigFromEnv) to demo the AI onboarding here." }),
|
|
3939
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: close, style: styles17.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles17.triggerText, children: "Close" }) })
|
|
3859
3940
|
] }) })
|
|
3860
3941
|
}
|
|
3861
3942
|
)
|
|
@@ -3929,20 +4010,6 @@ var themeFromBrand = (input) => {
|
|
|
3929
4010
|
button: { ...base.button, ...extra.button }
|
|
3930
4011
|
};
|
|
3931
4012
|
};
|
|
3932
|
-
var _DoneBlock = ({
|
|
3933
|
-
title = "You're all set",
|
|
3934
|
-
message = "Personalizing your experience\u2026"
|
|
3935
|
-
}) => {
|
|
3936
|
-
const t = useOnboardingTheme();
|
|
3937
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles16.center, { gap: t.spacing.sm, padding: t.spacing.lg }], children: [
|
|
3938
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [headingStyle(t.fonts), { color: t.colors.success, textAlign: "center" }], children: title }),
|
|
3939
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted, textAlign: "center" }], children: message })
|
|
3940
|
-
] });
|
|
3941
|
-
};
|
|
3942
|
-
var DoneBlock = React18__default.default.memo(_DoneBlock);
|
|
3943
|
-
var styles16 = reactNative.StyleSheet.create({
|
|
3944
|
-
center: { flex: 1, alignItems: "center", justifyContent: "center" }
|
|
3945
|
-
});
|
|
3946
4013
|
|
|
3947
4014
|
// src/motion/centeredModalMotion.ts
|
|
3948
4015
|
var CENTERED_MODAL_ANIM = {
|
|
@@ -4019,25 +4086,25 @@ var _CenteredModal = React18.forwardRef(
|
|
|
4019
4086
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4020
4087
|
reactNative.Animated.View,
|
|
4021
4088
|
{
|
|
4022
|
-
style: [
|
|
4089
|
+
style: [styles16.backdrop, { opacity: backdropOpacity }],
|
|
4023
4090
|
pointerEvents: "none"
|
|
4024
4091
|
}
|
|
4025
4092
|
),
|
|
4026
4093
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4027
4094
|
reactNative.Pressable,
|
|
4028
4095
|
{
|
|
4029
|
-
style:
|
|
4096
|
+
style: styles16.fill,
|
|
4030
4097
|
onPress: onBackdrop,
|
|
4031
4098
|
accessibilityRole: "button",
|
|
4032
4099
|
accessibilityLabel: "Dismiss",
|
|
4033
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSafeAreaContext.SafeAreaView, { style:
|
|
4034
|
-
}, style:
|
|
4100
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNativeSafeAreaContext.SafeAreaView, { style: styles16.center, pointerEvents: "box-none", children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { onPress: () => {
|
|
4101
|
+
}, style: styles16.cardWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4035
4102
|
reactNative.Animated.View,
|
|
4036
4103
|
{
|
|
4037
4104
|
accessibilityViewIsModal: true,
|
|
4038
4105
|
accessibilityRole: "alert",
|
|
4039
4106
|
style: [
|
|
4040
|
-
|
|
4107
|
+
styles16.card,
|
|
4041
4108
|
{
|
|
4042
4109
|
backgroundColor: theme.colors.surface,
|
|
4043
4110
|
borderRadius: theme.radius.lg,
|
|
@@ -4059,7 +4126,7 @@ var _CenteredModal = React18.forwardRef(
|
|
|
4059
4126
|
);
|
|
4060
4127
|
_CenteredModal.displayName = "CenteredModal";
|
|
4061
4128
|
var CenteredModal = React18__default.default.memo(_CenteredModal);
|
|
4062
|
-
var
|
|
4129
|
+
var styles16 = reactNative.StyleSheet.create({
|
|
4063
4130
|
fill: { flex: 1 },
|
|
4064
4131
|
backdrop: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "#000" },
|
|
4065
4132
|
center: { flex: 1, alignItems: "center", justifyContent: "center", padding: 24 },
|
|
@@ -4245,11 +4312,6 @@ var WIRE_ENV_VARS = [
|
|
|
4245
4312
|
"EXPO_PUBLIC_WIREAI_SERVER_URL",
|
|
4246
4313
|
"EXPO_PUBLIC_WIREAI_APP_ID"
|
|
4247
4314
|
];
|
|
4248
|
-
var warnInDev3 = (message) => {
|
|
4249
|
-
if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
|
|
4250
|
-
console.warn(message);
|
|
4251
|
-
}
|
|
4252
|
-
};
|
|
4253
4315
|
var wireConfigFromEnv = (overrides) => {
|
|
4254
4316
|
var _a2, _b, _c, _d, _e;
|
|
4255
4317
|
const apiKey = (_a2 = overrides == null ? void 0 : overrides.apiKey) != null ? _a2 : process.env.EXPO_PUBLIC_WIREAI_API_KEY;
|
|
@@ -4260,7 +4322,7 @@ var wireConfigFromEnv = (overrides) => {
|
|
|
4260
4322
|
apiKey ? void 0 : "EXPO_PUBLIC_WIREAI_API_KEY",
|
|
4261
4323
|
serverUrl ? void 0 : "EXPO_PUBLIC_WIREAI_SERVER_URL"
|
|
4262
4324
|
].filter(Boolean);
|
|
4263
|
-
|
|
4325
|
+
warnInDev(
|
|
4264
4326
|
`[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.`
|
|
4265
4327
|
);
|
|
4266
4328
|
return null;
|
|
@@ -4368,15 +4430,17 @@ var resetActivationRevalidation = () => {
|
|
|
4368
4430
|
};
|
|
4369
4431
|
|
|
4370
4432
|
// src/activation/wireActivation.ts
|
|
4371
|
-
var clean =
|
|
4372
|
-
if (typeof value !== "string") return void 0;
|
|
4373
|
-
const trimmed = value.trim();
|
|
4374
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
4375
|
-
};
|
|
4433
|
+
var clean = cleanString;
|
|
4376
4434
|
var createWireActivation = (config) => {
|
|
4377
4435
|
var _a2, _b;
|
|
4378
4436
|
const target = { serverUrl: config.serverUrl, apiKey: config.apiKey };
|
|
4379
4437
|
const explicitDeviceKey = (_b = clean(config.deviceKey)) != null ? _b : clean((_a2 = config.userContext) == null ? void 0 : _a2.deviceKey);
|
|
4438
|
+
resolveIdentity({
|
|
4439
|
+
value: explicitDeviceKey,
|
|
4440
|
+
space: "device",
|
|
4441
|
+
source: "host",
|
|
4442
|
+
scope: config.appId
|
|
4443
|
+
});
|
|
4380
4444
|
const autoDeviceKeyOptions = {
|
|
4381
4445
|
appId: config.appId,
|
|
4382
4446
|
// An explicit key opts out of minting AND persisting (unchanged contract).
|
|
@@ -4810,6 +4874,30 @@ var DEFAULTS = {
|
|
|
4810
4874
|
maxRetries: 6
|
|
4811
4875
|
};
|
|
4812
4876
|
var READ_TIMEOUT_MS4 = 1500;
|
|
4877
|
+
var QUEUE_KEY_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:eventQueueKeys");
|
|
4878
|
+
var queueKeyGlobal = globalThis;
|
|
4879
|
+
var claimedQueueKeys = () => {
|
|
4880
|
+
const existing = queueKeyGlobal[QUEUE_KEY_SLOT];
|
|
4881
|
+
if (existing) return existing;
|
|
4882
|
+
const created = /* @__PURE__ */ new Set();
|
|
4883
|
+
queueKeyGlobal[QUEUE_KEY_SLOT] = created;
|
|
4884
|
+
return created;
|
|
4885
|
+
};
|
|
4886
|
+
var claimQueueKey = (preferred, explicit) => {
|
|
4887
|
+
const claimed = claimedQueueKeys();
|
|
4888
|
+
if (explicit || !claimed.has(preferred)) {
|
|
4889
|
+
claimed.add(preferred);
|
|
4890
|
+
return preferred;
|
|
4891
|
+
}
|
|
4892
|
+
let ordinal = 2;
|
|
4893
|
+
while (claimed.has(`${preferred}#${ordinal}`)) ordinal++;
|
|
4894
|
+
const key = `${preferred}#${ordinal}`;
|
|
4895
|
+
claimed.add(key);
|
|
4896
|
+
warnInDev(
|
|
4897
|
+
`[wireai] a second event queue was created for the same appId, and "${preferred}" is already claimed by a live one. Two queues sharing one storage slot overwrite each other's backlog, delete each other's pending events when one drains to empty, and double-send on relaunch, so this queue was given "${key}" instead. Prefer ONE analytics instance per app; if you really need two, pass an explicit \`storageKey\` to each so the slots are yours to reason about.`
|
|
4898
|
+
);
|
|
4899
|
+
return key;
|
|
4900
|
+
};
|
|
4813
4901
|
var withTimeout4 = (p, ms) => {
|
|
4814
4902
|
let timer;
|
|
4815
4903
|
const timeout = new Promise((resolve) => {
|
|
@@ -4841,7 +4929,8 @@ var createEventQueue = (options) => {
|
|
|
4841
4929
|
var _a2, _b, _c, _d, _e, _f, _g;
|
|
4842
4930
|
const target = options.target;
|
|
4843
4931
|
const storage = options.storage;
|
|
4844
|
-
const
|
|
4932
|
+
const defaultKey = (_b = options.storageKey) != null ? _b : `wireai:evtq:${(_a2 = options.appId) != null ? _a2 : "default"}`;
|
|
4933
|
+
const key = storage ? claimQueueKey(defaultKey, options.storageKey !== void 0) : defaultKey;
|
|
4845
4934
|
const maxSize = (_c = options.maxSize) != null ? _c : DEFAULTS.maxSize;
|
|
4846
4935
|
const batchSize = (_d = options.batchSize) != null ? _d : DEFAULTS.batchSize;
|
|
4847
4936
|
const baseBackoffMs = (_e = options.baseBackoffMs) != null ? _e : DEFAULTS.baseBackoffMs;
|
|
@@ -5031,7 +5120,13 @@ var useLifecycleEvents = (config, options = {}) => {
|
|
|
5031
5120
|
return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" } : void 0;
|
|
5032
5121
|
};
|
|
5033
5122
|
const resolveDeviceKey = (cfg, opts) => {
|
|
5034
|
-
|
|
5123
|
+
var _a2;
|
|
5124
|
+
const host = (_a2 = resolveIdentity({
|
|
5125
|
+
value: opts.deviceKey,
|
|
5126
|
+
space: "device",
|
|
5127
|
+
source: "host",
|
|
5128
|
+
scope: cfg == null ? void 0 : cfg.appId
|
|
5129
|
+
})) == null ? void 0 : _a2.value;
|
|
5035
5130
|
if (host) return host;
|
|
5036
5131
|
if (!(cfg == null ? void 0 : cfg.storage)) return void 0;
|
|
5037
5132
|
return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
|
|
@@ -5120,7 +5215,6 @@ exports.CompletionView = CompletionView;
|
|
|
5120
5215
|
exports.DEFAULT_FEATURES_TTL_MS = DEFAULT_FEATURES_TTL_MS;
|
|
5121
5216
|
exports.DEFAULT_SESSION_TTL_MS = DEFAULT_SESSION_TTL_MS;
|
|
5122
5217
|
exports.DemoOnboarding = DemoOnboarding;
|
|
5123
|
-
exports.DoneBlock = DoneBlock;
|
|
5124
5218
|
exports.EXTRA_KEY_PREFIX = EXTRA_KEY_PREFIX;
|
|
5125
5219
|
exports.ErrorBlock = ErrorBlock;
|
|
5126
5220
|
exports.FIRST_OPEN_EVENT = FIRST_OPEN_EVENT;
|
|
@@ -5135,7 +5229,6 @@ exports.OnboardingFlow = OnboardingFlow;
|
|
|
5135
5229
|
exports.OnboardingScaffold = OnboardingScaffold;
|
|
5136
5230
|
exports.OnboardingThemeProvider = OnboardingThemeProvider;
|
|
5137
5231
|
exports.PLAN_TIER_CONTEXT_KEY = PLAN_TIER_CONTEXT_KEY;
|
|
5138
|
-
exports.RESERVED_USER_CONTEXT_KEYS = RESERVED_USER_CONTEXT_KEYS;
|
|
5139
5232
|
exports.SESSION_STARTED_EVENT = SESSION_STARTED_EVENT;
|
|
5140
5233
|
exports.SelectionCard = SelectionCard;
|
|
5141
5234
|
exports.StatusCard = StatusCard;
|
|
@@ -5179,7 +5272,9 @@ exports.firstOpenStorageKey = firstOpenStorageKey;
|
|
|
5179
5272
|
exports.getActivationRevalidationVersion = getActivationRevalidationVersion;
|
|
5180
5273
|
exports.getCurrentSessionId = getCurrentSessionId;
|
|
5181
5274
|
exports.hashEmailFnv1a = hashEmailFnv1a;
|
|
5275
|
+
exports.hostIdentity = hostIdentity;
|
|
5182
5276
|
exports.hydrateAutoDeviceKey = hydrateAutoDeviceKey;
|
|
5277
|
+
exports.hydrateDeviceIdentity = hydrateDeviceIdentity;
|
|
5183
5278
|
exports.identifyOnboarding = identifyOnboarding;
|
|
5184
5279
|
exports.isFeaturesFresh = isFeaturesFresh;
|
|
5185
5280
|
exports.isOnboardingEnabled = isOnboardingEnabled;
|
|
@@ -5208,8 +5303,10 @@ exports.resetActivationRevalidation = resetActivationRevalidation;
|
|
|
5208
5303
|
exports.resetAutoDeviceKeys = resetAutoDeviceKeys;
|
|
5209
5304
|
exports.resetCurrentSessionId = resetCurrentSessionId;
|
|
5210
5305
|
exports.resetFirstOpenLatch = resetFirstOpenLatch;
|
|
5306
|
+
exports.resetIdentityProvenance = resetIdentityProvenance;
|
|
5211
5307
|
exports.resetSessionStartGuard = resetSessionStartGuard;
|
|
5212
5308
|
exports.resolveAutoDeviceKey = resolveAutoDeviceKey;
|
|
5309
|
+
exports.resolveIdentity = resolveIdentity;
|
|
5213
5310
|
exports.resolvePlanTier = resolvePlanTier;
|
|
5214
5311
|
exports.resolveUserContext = resolveUserContext;
|
|
5215
5312
|
exports.sanitizeUserId = sanitizeUserId;
|