@wireai/activation 0.15.0 → 0.16.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/AGENTS.md +95 -20
- package/CHANGELOG.md +707 -0
- package/INTEGRATION_PROMPT.md +61 -23
- package/README.md +100 -25
- package/dist/analytics/index.d.mts +32 -10
- package/dist/analytics/index.d.ts +32 -10
- package/dist/analytics/index.js +288 -127
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +288 -127
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/coachmarks/index.d.mts +14 -0
- package/dist/coachmarks/index.d.ts +14 -0
- package/dist/coachmarks/index.js +73 -20
- package/dist/coachmarks/index.js.map +1 -1
- package/dist/coachmarks/index.mjs +73 -20
- package/dist/coachmarks/index.mjs.map +1 -1
- package/dist/{currentSession-orZy5p1e.d.mts → currentSession-Bz7G6lno.d.mts} +25 -35
- package/dist/{currentSession-CFSRZ2wg.d.ts → currentSession-z-CZ55ad.d.ts} +25 -35
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +125 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +125 -36
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +0 -13
- package/dist/questionnaire/index.d.ts +0 -13
- package/dist/questionnaire/index.js +154 -43
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +155 -44
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.js +159 -91
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +160 -92
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/showcase/index.js +59 -18
- package/dist/showcase/index.js.map +1 -1
- package/dist/showcase/index.mjs +60 -19
- package/dist/showcase/index.mjs.map +1 -1
- package/llms.txt +9 -9
- package/package.json +6 -9
- package/src/analytics/currentSession.ts +141 -4
- package/src/analytics/index.ts +6 -1
- package/src/analytics/reportClientEvent.ts +19 -10
- package/src/analytics/useAnalytics.ts +74 -15
- package/src/analytics/wireDoctor.ts +152 -7
- package/src/coachmarks/CoachmarkProvider.tsx +26 -5
- package/src/coachmarks/runtime.ts +53 -0
- package/src/coachmarks/useCoachmarkTour.ts +51 -1
- package/src/context/deviceId.ts +49 -15
- package/src/features/WireFeaturesProvider.tsx +72 -12
- package/src/features/fetchWireFeatures.ts +49 -11
- package/src/features/useWireFeatures.ts +39 -3
- package/src/identity/identityRecord.ts +15 -2
- package/src/questionnaire/QuestionnaireGate.tsx +40 -1
- package/src/questionnaire/transport.ts +22 -8
- package/src/questionnaire/useQuestionnaireGate.ts +58 -7
- package/src/reviews/ReviewGate.tsx +39 -0
- package/src/reviews/idempotency.ts +38 -0
- package/src/reviews/runtime.ts +39 -10
- package/src/reviews/transport.ts +22 -8
- package/src/reviews/useReviewGate.ts +57 -7
- package/src/session-analytics/lifecycle.ts +16 -0
- package/src/session-analytics/useLifecycleEvents.ts +30 -2
- package/src/session-analytics/useSessionStart.ts +22 -2
- package/src/showcase/FeatureShowcase.tsx +50 -3
- package/src/types.ts +5 -4
- package/src/utils/withDeadline.ts +70 -0
|
@@ -246,19 +246,6 @@ declare const buildQuestionnaireSubmission: (input: {
|
|
|
246
246
|
meta?: QuestionnaireMeta;
|
|
247
247
|
}) => QuestionnaireSubmission;
|
|
248
248
|
|
|
249
|
-
/**
|
|
250
|
-
* transport.ts - kit → Wire server requests for the questionnaire module, never throwing
|
|
251
|
-
* (a pre-onboarding questionnaire must NEVER break the app). Mirrors `submitReview`: a thin
|
|
252
|
-
* fetch wrapper, Bearer tenant key, and — since 0.13.3 — the SAME three-outcome delivery ack.
|
|
253
|
-
*
|
|
254
|
-
* • submitQuestionnaireResponse → POST {serverUrl}/v1/questionnaires/{id}/responses
|
|
255
|
-
* • fetchQuestionnaireDecision → GET {serverUrl}/v1/questionnaires/decision (best-effort)
|
|
256
|
-
*
|
|
257
|
-
* The decision fetch is HARD fail-open on the "never show" side: an unreachable endpoint, a
|
|
258
|
-
* non-2xx (incl. 404), a missing `fetch`, or bad JSON all resolve to null, so a host wiring
|
|
259
|
-
* pure server-directed firing simply shows nothing - exactly the reviews decision seam.
|
|
260
|
-
*/
|
|
261
|
-
|
|
262
249
|
/**
|
|
263
250
|
* What became of a questionnaire POST. The SHARED verdict — identical values, identical meaning,
|
|
264
251
|
* identical retry rule as `ReviewSubmitResult`. The reasoning lives once, in `utils/submitResult.ts`.
|
|
@@ -246,19 +246,6 @@ declare const buildQuestionnaireSubmission: (input: {
|
|
|
246
246
|
meta?: QuestionnaireMeta;
|
|
247
247
|
}) => QuestionnaireSubmission;
|
|
248
248
|
|
|
249
|
-
/**
|
|
250
|
-
* transport.ts - kit → Wire server requests for the questionnaire module, never throwing
|
|
251
|
-
* (a pre-onboarding questionnaire must NEVER break the app). Mirrors `submitReview`: a thin
|
|
252
|
-
* fetch wrapper, Bearer tenant key, and — since 0.13.3 — the SAME three-outcome delivery ack.
|
|
253
|
-
*
|
|
254
|
-
* • submitQuestionnaireResponse → POST {serverUrl}/v1/questionnaires/{id}/responses
|
|
255
|
-
* • fetchQuestionnaireDecision → GET {serverUrl}/v1/questionnaires/decision (best-effort)
|
|
256
|
-
*
|
|
257
|
-
* The decision fetch is HARD fail-open on the "never show" side: an unreachable endpoint, a
|
|
258
|
-
* non-2xx (incl. 404), a missing `fetch`, or bad JSON all resolve to null, so a host wiring
|
|
259
|
-
* pure server-directed firing simply shows nothing - exactly the reviews decision seam.
|
|
260
|
-
*/
|
|
261
|
-
|
|
262
249
|
/**
|
|
263
250
|
* What became of a questionnaire POST. The SHARED verdict — identical values, identical meaning,
|
|
264
251
|
* identical retry rule as `ReviewSubmitResult`. The reasoning lives once, in `utils/submitResult.ts`.
|
|
@@ -843,6 +843,28 @@ var toAnswers = (drafts) => {
|
|
|
843
843
|
};
|
|
844
844
|
};
|
|
845
845
|
|
|
846
|
+
// src/utils/withDeadline.ts
|
|
847
|
+
var DEADLINE_EXPIRED = /* @__PURE__ */ Symbol("wire-deadline-expired");
|
|
848
|
+
var DEFAULT_DEADLINE_MS = 15e3;
|
|
849
|
+
var withDeadline = async (exchange, timeoutMs = DEFAULT_DEADLINE_MS) => {
|
|
850
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
|
|
851
|
+
let timer;
|
|
852
|
+
const expired = new Promise((resolve) => {
|
|
853
|
+
timer = setTimeout(() => {
|
|
854
|
+
controller == null ? void 0 : controller.abort();
|
|
855
|
+
resolve(DEADLINE_EXPIRED);
|
|
856
|
+
}, timeoutMs);
|
|
857
|
+
});
|
|
858
|
+
const running = exchange(controller == null ? void 0 : controller.signal);
|
|
859
|
+
try {
|
|
860
|
+
return await Promise.race([running, expired]);
|
|
861
|
+
} finally {
|
|
862
|
+
clearTimeout(timer);
|
|
863
|
+
void running.catch(() => {
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
|
|
846
868
|
// src/questionnaire/transport.ts
|
|
847
869
|
var submitQuestionnaireResponse = async (target, id, submission) => {
|
|
848
870
|
if (!(target == null ? void 0 : target.serverUrl) || !id) return "unsent";
|
|
@@ -851,11 +873,15 @@ var submitQuestionnaireResponse = async (target, id, submission) => {
|
|
|
851
873
|
const url = `${base}/v1/questionnaires/${encodeURIComponent(id)}/responses`;
|
|
852
874
|
const headers = { "Content-Type": "application/json" };
|
|
853
875
|
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
854
|
-
const res = await
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
876
|
+
const res = await withDeadline(
|
|
877
|
+
(signal) => fetch(url, {
|
|
878
|
+
method: "POST",
|
|
879
|
+
headers,
|
|
880
|
+
body: JSON.stringify(submission),
|
|
881
|
+
signal
|
|
882
|
+
})
|
|
883
|
+
);
|
|
884
|
+
if (res === DEADLINE_EXPIRED) return "unsent";
|
|
859
885
|
if (!res) return "unsent";
|
|
860
886
|
return res.ok ? "accepted" : "rejected";
|
|
861
887
|
} catch {
|
|
@@ -873,9 +899,12 @@ var fetchQuestionnaireDecision = async (target, options = {}) => {
|
|
|
873
899
|
const url = `${base}/v1/questionnaires/decision${qs ? `?${qs}` : ""}`;
|
|
874
900
|
const headers = {};
|
|
875
901
|
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
902
|
+
const json = await withDeadline(async (signal) => {
|
|
903
|
+
const res = await fetch(url, { headers, signal });
|
|
904
|
+
if (!res || !res.ok) return null;
|
|
905
|
+
return await res.json();
|
|
906
|
+
});
|
|
907
|
+
if (json === DEADLINE_EXPIRED) return null;
|
|
879
908
|
if (!json || typeof json.fire !== "boolean") return null;
|
|
880
909
|
return json;
|
|
881
910
|
} catch {
|
|
@@ -954,6 +983,10 @@ var _QuestionnaireGate = ({
|
|
|
954
983
|
}, [id, onResolved]);
|
|
955
984
|
const postedRef = React8.useRef(false);
|
|
956
985
|
const unackedRef = React8.useRef(null);
|
|
986
|
+
const recoverOnSettleRef = React8.useRef(false);
|
|
987
|
+
const recoveredRef = React8.useRef(false);
|
|
988
|
+
const postOnceRef = React8.useRef(() => {
|
|
989
|
+
});
|
|
957
990
|
const postOnce = React8.useCallback(
|
|
958
991
|
(body) => {
|
|
959
992
|
if (postedRef.current) return;
|
|
@@ -962,6 +995,10 @@ var _QuestionnaireGate = ({
|
|
|
962
995
|
void submitQuestionnaireResponse(target, id, body).then((result) => {
|
|
963
996
|
if (result === "unsent") {
|
|
964
997
|
postedRef.current = false;
|
|
998
|
+
if (recoverOnSettleRef.current && !recoveredRef.current) {
|
|
999
|
+
recoveredRef.current = true;
|
|
1000
|
+
postOnceRef.current(body);
|
|
1001
|
+
}
|
|
965
1002
|
return;
|
|
966
1003
|
}
|
|
967
1004
|
unackedRef.current = null;
|
|
@@ -969,11 +1006,16 @@ var _QuestionnaireGate = ({
|
|
|
969
1006
|
},
|
|
970
1007
|
[target, id]
|
|
971
1008
|
);
|
|
1009
|
+
postOnceRef.current = postOnce;
|
|
972
1010
|
const recoverRef = React8.useRef(() => {
|
|
973
1011
|
});
|
|
974
1012
|
recoverRef.current = () => {
|
|
975
1013
|
const undelivered = unackedRef.current;
|
|
976
|
-
if (undelivered && !postedRef.current)
|
|
1014
|
+
if (undelivered && !postedRef.current) {
|
|
1015
|
+
postOnce(undelivered);
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
if (postedRef.current && undelivered) recoverOnSettleRef.current = true;
|
|
977
1019
|
};
|
|
978
1020
|
React8__default.default.useEffect(() => () => recoverRef.current(), []);
|
|
979
1021
|
const finish = React8.useCallback(
|
|
@@ -1122,6 +1164,39 @@ var styles7 = reactNative.StyleSheet.create({
|
|
|
1122
1164
|
backGlyph: { includeFontPadding: false }
|
|
1123
1165
|
});
|
|
1124
1166
|
|
|
1167
|
+
// src/analytics/reportClientEvent.ts
|
|
1168
|
+
var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1169
|
+
|
|
1170
|
+
// src/analytics/currentSession.ts
|
|
1171
|
+
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
1172
|
+
"@wireai/activation:currentSessionId"
|
|
1173
|
+
);
|
|
1174
|
+
var globalSlot = globalThis;
|
|
1175
|
+
var SESSION_ID_LISTENERS_SLOT = /* @__PURE__ */ Symbol.for(
|
|
1176
|
+
"@wireai/activation:currentSessionIdListeners"
|
|
1177
|
+
);
|
|
1178
|
+
var listenerSlot = globalThis;
|
|
1179
|
+
var listeners = () => {
|
|
1180
|
+
const existing = listenerSlot[SESSION_ID_LISTENERS_SLOT];
|
|
1181
|
+
if (existing) return existing;
|
|
1182
|
+
const created = /* @__PURE__ */ new Set();
|
|
1183
|
+
listenerSlot[SESSION_ID_LISTENERS_SLOT] = created;
|
|
1184
|
+
return created;
|
|
1185
|
+
};
|
|
1186
|
+
var subscribeCurrentSessionId = (listener) => {
|
|
1187
|
+
const set = listeners();
|
|
1188
|
+
set.add(listener);
|
|
1189
|
+
return () => {
|
|
1190
|
+
set.delete(listener);
|
|
1191
|
+
};
|
|
1192
|
+
};
|
|
1193
|
+
var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
1194
|
+
var MINTED_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
1195
|
+
"@wireai/activation:mintedSessionId"
|
|
1196
|
+
);
|
|
1197
|
+
var mintedSlot = globalThis;
|
|
1198
|
+
var isMintedSessionId = (id) => id !== void 0 && id === mintedSlot[MINTED_SESSION_ID_SLOT];
|
|
1199
|
+
|
|
1125
1200
|
// src/coachmarks/runtime.ts
|
|
1126
1201
|
var COACHMARK_RUNTIME_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:coachmarkRuntime");
|
|
1127
1202
|
var runtimeGlobal = globalThis;
|
|
@@ -1280,17 +1355,31 @@ var failOpen = async (storage, key) => {
|
|
|
1280
1355
|
const cached = await readCachedFeatures(storage, key);
|
|
1281
1356
|
return (_a = cached == null ? void 0 : cached.features) != null ? _a : defaultWireFeatures;
|
|
1282
1357
|
};
|
|
1283
|
-
var
|
|
1358
|
+
var NO_ANSWER = /* @__PURE__ */ Symbol("wire-features-no-answer");
|
|
1359
|
+
var fetchFeaturesJson = async (url, apiKey, timeoutMs) => {
|
|
1284
1360
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1361
|
+
let timer;
|
|
1362
|
+
const expired = new Promise((resolve) => {
|
|
1363
|
+
timer = setTimeout(() => {
|
|
1364
|
+
controller == null ? void 0 : controller.abort();
|
|
1365
|
+
resolve(NO_ANSWER);
|
|
1366
|
+
}, timeoutMs);
|
|
1367
|
+
});
|
|
1368
|
+
const exchange = (async () => {
|
|
1369
|
+
const res = await fetch(url, {
|
|
1288
1370
|
method: "GET",
|
|
1289
1371
|
headers: { Accept: "application/json", Authorization: `Bearer ${apiKey}` },
|
|
1290
1372
|
signal: controller == null ? void 0 : controller.signal
|
|
1291
1373
|
});
|
|
1374
|
+
if (!res || !res.ok) return NO_ANSWER;
|
|
1375
|
+
return await res.json();
|
|
1376
|
+
})();
|
|
1377
|
+
try {
|
|
1378
|
+
return await Promise.race([exchange, expired]);
|
|
1292
1379
|
} finally {
|
|
1293
1380
|
clearTimeout(timer);
|
|
1381
|
+
void exchange.catch(() => {
|
|
1382
|
+
});
|
|
1294
1383
|
}
|
|
1295
1384
|
};
|
|
1296
1385
|
var fetchWireFeatures = async (config) => {
|
|
@@ -1300,9 +1389,8 @@ var fetchWireFeatures = async (config) => {
|
|
|
1300
1389
|
const url = `${config.serverUrl.replace(/\/$/, "")}/v1/features`;
|
|
1301
1390
|
const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
1302
1391
|
try {
|
|
1303
|
-
const
|
|
1304
|
-
if (
|
|
1305
|
-
const json = await res.json();
|
|
1392
|
+
const json = await fetchFeaturesJson(url, config.apiKey, timeoutMs);
|
|
1393
|
+
if (json === NO_ANSWER) return failOpen(storage, key);
|
|
1306
1394
|
const features = parseWireFeatures(json);
|
|
1307
1395
|
if (storage) writeCachedFeatures(storage, key, features);
|
|
1308
1396
|
return features;
|
|
@@ -1318,39 +1406,51 @@ var useStableValue = (value, isEqual) => {
|
|
|
1318
1406
|
return ref.current;
|
|
1319
1407
|
};
|
|
1320
1408
|
var sameFetchKey = (a, b) => (a == null ? void 0 : a.serverUrl) === (b == null ? void 0 : b.serverUrl) && (a == null ? void 0 : a.apiKey) === (b == null ? void 0 : b.apiKey) && (a == null ? void 0 : a.appId) === (b == null ? void 0 : b.appId);
|
|
1321
|
-
var
|
|
1409
|
+
var useWireFeaturesState = (config) => {
|
|
1322
1410
|
const stableConfig = useStableValue(config, sameFetchKey);
|
|
1323
1411
|
const [flags, setFlags] = React8.useState(defaultWireFeatures);
|
|
1324
1412
|
const canFetch = !!(stableConfig == null ? void 0 : stableConfig.serverUrl) && !!(stableConfig == null ? void 0 : stableConfig.apiKey);
|
|
1413
|
+
const [settled, setSettled] = React8.useState(!canFetch);
|
|
1325
1414
|
React8.useEffect(() => {
|
|
1326
1415
|
if (!canFetch) {
|
|
1327
1416
|
setFlags((prev) => featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures);
|
|
1417
|
+
setSettled(true);
|
|
1328
1418
|
return;
|
|
1329
1419
|
}
|
|
1330
1420
|
let alive = true;
|
|
1331
1421
|
void fetchWireFeatures(stableConfig).then((next) => {
|
|
1332
1422
|
if (!alive) return;
|
|
1333
1423
|
setFlags((prev) => featuresEqual(prev, next) ? prev : next);
|
|
1424
|
+
setSettled(true);
|
|
1334
1425
|
});
|
|
1335
1426
|
return () => {
|
|
1336
1427
|
alive = false;
|
|
1337
1428
|
};
|
|
1338
1429
|
}, [canFetch, stableConfig]);
|
|
1339
|
-
return flags;
|
|
1430
|
+
return React8.useMemo(() => ({ flags, settled }), [flags, settled]);
|
|
1340
1431
|
};
|
|
1341
1432
|
var CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.context");
|
|
1342
|
-
var
|
|
1343
|
-
if (!
|
|
1344
|
-
|
|
1433
|
+
var featuresContextGlobal = globalThis;
|
|
1434
|
+
if (!featuresContextGlobal[CONTEXT_SYMBOL]) {
|
|
1435
|
+
featuresContextGlobal[CONTEXT_SYMBOL] = React8.createContext(null);
|
|
1436
|
+
}
|
|
1437
|
+
var WireFeaturesContext = featuresContextGlobal[CONTEXT_SYMBOL];
|
|
1438
|
+
var SETTLED_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.settled.context");
|
|
1439
|
+
var settledContextGlobal = globalThis;
|
|
1440
|
+
if (!settledContextGlobal[SETTLED_SYMBOL]) {
|
|
1441
|
+
settledContextGlobal[SETTLED_SYMBOL] = React8.createContext(true);
|
|
1345
1442
|
}
|
|
1346
|
-
var
|
|
1443
|
+
var WireFeaturesSettledContext = settledContextGlobal[SETTLED_SYMBOL];
|
|
1347
1444
|
var useWireFeaturesContext = () => React8.useContext(WireFeaturesContext);
|
|
1348
|
-
var
|
|
1445
|
+
var useResolvedFeaturesState = (options) => {
|
|
1349
1446
|
var _a, _b, _c;
|
|
1350
1447
|
const ctx = useWireFeaturesContext();
|
|
1448
|
+
const ctxSettled = React8.useContext(WireFeaturesSettledContext);
|
|
1351
1449
|
const shouldFetch = !(options == null ? void 0 : options.flags) && ctx == null;
|
|
1352
|
-
const fetched =
|
|
1353
|
-
|
|
1450
|
+
const fetched = useWireFeaturesState(shouldFetch ? options == null ? void 0 : options.config : void 0);
|
|
1451
|
+
const flags = (_c = (_b = (_a = options == null ? void 0 : options.flags) != null ? _a : ctx) != null ? _b : fetched.flags) != null ? _c : defaultWireFeatures;
|
|
1452
|
+
const settled = (options == null ? void 0 : options.flags) ? true : ctx != null ? ctxSettled : fetched.settled;
|
|
1453
|
+
return React8.useMemo(() => ({ flags, settled }), [flags, settled]);
|
|
1354
1454
|
};
|
|
1355
1455
|
|
|
1356
1456
|
// src/reviews/equality.ts
|
|
@@ -1374,16 +1474,6 @@ var sameDecision = (a, b) => {
|
|
|
1374
1474
|
return a.fire === b.fire && a.reason === b.reason;
|
|
1375
1475
|
};
|
|
1376
1476
|
|
|
1377
|
-
// src/analytics/reportClientEvent.ts
|
|
1378
|
-
var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1379
|
-
|
|
1380
|
-
// src/analytics/currentSession.ts
|
|
1381
|
-
var CURRENT_SESSION_ID_SLOT = /* @__PURE__ */ Symbol.for(
|
|
1382
|
-
"@wireai/activation:currentSessionId"
|
|
1383
|
-
);
|
|
1384
|
-
var globalSlot = globalThis;
|
|
1385
|
-
var getCurrentSessionId = () => globalSlot[CURRENT_SESSION_ID_SLOT];
|
|
1386
|
-
|
|
1387
1477
|
// src/reviews/runtime.ts
|
|
1388
1478
|
var resolveStorage = (override) => validateGateStorage(override != null ? override : getCoachmarkStorage());
|
|
1389
1479
|
var NO_STORAGE_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
|
|
@@ -1430,18 +1520,23 @@ var PROCESS_OPEN_ID_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:proces
|
|
|
1430
1520
|
var openIdGlobal = globalThis;
|
|
1431
1521
|
var currentOpenId = () => {
|
|
1432
1522
|
const live = getCurrentSessionId();
|
|
1523
|
+
const liveMinted = isMintedSessionId(live);
|
|
1433
1524
|
const pin = openIdGlobal[PROCESS_OPEN_ID_SLOT];
|
|
1434
1525
|
if (!pin) {
|
|
1435
1526
|
const openId = live != null ? live : makeSessionId();
|
|
1436
|
-
openIdGlobal[PROCESS_OPEN_ID_SLOT] = { openId, observed: live };
|
|
1527
|
+
openIdGlobal[PROCESS_OPEN_ID_SLOT] = { openId, observed: live, observedMinted: liveMinted };
|
|
1437
1528
|
return openId;
|
|
1438
1529
|
}
|
|
1439
1530
|
if (!live || live === pin.observed) return pin.openId;
|
|
1440
|
-
if (pin.observed === void 0) {
|
|
1441
|
-
openIdGlobal[PROCESS_OPEN_ID_SLOT] = {
|
|
1531
|
+
if (pin.observed === void 0 || pin.observedMinted) {
|
|
1532
|
+
openIdGlobal[PROCESS_OPEN_ID_SLOT] = {
|
|
1533
|
+
openId: pin.openId,
|
|
1534
|
+
observed: live,
|
|
1535
|
+
observedMinted: liveMinted
|
|
1536
|
+
};
|
|
1442
1537
|
return pin.openId;
|
|
1443
1538
|
}
|
|
1444
|
-
openIdGlobal[PROCESS_OPEN_ID_SLOT] = { openId: live, observed: live };
|
|
1539
|
+
openIdGlobal[PROCESS_OPEN_ID_SLOT] = { openId: live, observed: live, observedMinted: liveMinted };
|
|
1445
1540
|
return live;
|
|
1446
1541
|
};
|
|
1447
1542
|
var bumpSessionCount = (storage, sessionsKey, openKey, openId = currentOpenId()) => {
|
|
@@ -1482,7 +1577,11 @@ var useQuestionnaireGate = ({
|
|
|
1482
1577
|
}) => {
|
|
1483
1578
|
const config = useStableValue2(configProp, shallowEqual);
|
|
1484
1579
|
const decision = useStableValue2(decisionProp, (a, b) => sameDecision(a, b));
|
|
1485
|
-
const
|
|
1580
|
+
const { flags: resolvedFeatures, settled: featuresSettled } = useResolvedFeaturesState({
|
|
1581
|
+
flags: features,
|
|
1582
|
+
config: featuresConfig
|
|
1583
|
+
});
|
|
1584
|
+
const featureEnabled = resolvedFeatures.questionnaire.enabled;
|
|
1486
1585
|
const testing = isTesting != null ? isTesting : isCoachmarkTesting();
|
|
1487
1586
|
const seenKey = questionnaireSeenKey(
|
|
1488
1587
|
config.id,
|
|
@@ -1491,11 +1590,22 @@ var useQuestionnaireGate = ({
|
|
|
1491
1590
|
const lastKey = questionnaireLastShownKey(config.id);
|
|
1492
1591
|
const sessionsKey = questionnaireSessionsKey(config.id);
|
|
1493
1592
|
const sessionOpenKey = questionnaireSessionOpenKey(config.id);
|
|
1494
|
-
const
|
|
1593
|
+
const openSessionId = React8.useSyncExternalStore(
|
|
1594
|
+
subscribeCurrentSessionId,
|
|
1595
|
+
getCurrentSessionId,
|
|
1596
|
+
getCurrentSessionId
|
|
1597
|
+
);
|
|
1598
|
+
const storageRef = React8.useRef(storage);
|
|
1599
|
+
storageRef.current = storage;
|
|
1600
|
+
const [sessions, setSessions] = React8.useState(() => {
|
|
1495
1601
|
const store = resolveStorage(storage);
|
|
1496
1602
|
warnMissingGateStorage(store, "questionnaire");
|
|
1497
1603
|
return bumpSessionCount(store, sessionsKey, sessionOpenKey);
|
|
1498
|
-
})
|
|
1604
|
+
});
|
|
1605
|
+
React8.useEffect(() => {
|
|
1606
|
+
const next = bumpSessionCount(resolveStorage(storageRef.current), sessionsKey, sessionOpenKey);
|
|
1607
|
+
setSessions((prev) => prev === next ? prev : next);
|
|
1608
|
+
}, [openSessionId, sessionsKey, sessionOpenKey]);
|
|
1499
1609
|
const hasServerDecision = decision != null;
|
|
1500
1610
|
const timeoutMs = config.timeoutFallbackMs;
|
|
1501
1611
|
const waits = !hasServerDecision && timeoutMs != null && timeoutMs > 0;
|
|
@@ -1529,10 +1639,11 @@ var useQuestionnaireGate = ({
|
|
|
1529
1639
|
});
|
|
1530
1640
|
const resolved = decideQuestionnaire(local, decision);
|
|
1531
1641
|
const alreadySeen = hasSeenGate(seenKey, storage, isTesting);
|
|
1532
|
-
const ready = hasServerDecision || elapsed;
|
|
1642
|
+
const ready = (hasServerDecision || elapsed) && featuresSettled;
|
|
1533
1643
|
return { visible: ready && resolved.fire && !alreadySeen, verdict: resolved };
|
|
1534
1644
|
}, [
|
|
1535
1645
|
featureEnabled,
|
|
1646
|
+
featuresSettled,
|
|
1536
1647
|
testing,
|
|
1537
1648
|
config,
|
|
1538
1649
|
decision,
|