@wireai/activation 0.13.0 → 0.13.3

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.
Files changed (82) hide show
  1. package/AGENTS.md +7 -4
  2. package/CHANGELOG.md +341 -4
  3. package/README.md +98 -2
  4. package/dist/analytics/index.d.mts +4 -4
  5. package/dist/analytics/index.d.ts +4 -4
  6. package/dist/analytics/index.js +164 -471
  7. package/dist/analytics/index.js.map +1 -1
  8. package/dist/analytics/index.mjs +162 -469
  9. package/dist/analytics/index.mjs.map +1 -1
  10. package/dist/coachmarks/index.d.mts +14 -1
  11. package/dist/coachmarks/index.d.ts +14 -1
  12. package/dist/coachmarks/index.js +58 -14
  13. package/dist/coachmarks/index.js.map +1 -1
  14. package/dist/coachmarks/index.mjs +58 -14
  15. package/dist/coachmarks/index.mjs.map +1 -1
  16. package/dist/{currentSession-_GynvhzT.d.mts → currentSession-BoWtr3Jp.d.mts} +299 -14
  17. package/dist/{currentSession-D7zabMXK.d.ts → currentSession-CCOMlaQ2.d.ts} +299 -14
  18. package/dist/{decision-Bl_M2y3r.d.mts → decision-Cjw0jbEj.d.mts} +1 -1
  19. package/dist/{decision-Cau5KmP6.d.ts → decision-GfpXAsk_.d.ts} +1 -1
  20. package/dist/index.d.mts +218 -4
  21. package/dist/index.d.ts +218 -4
  22. package/dist/index.js +1104 -888
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +887 -692
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/questionnaire/index.d.mts +42 -10
  27. package/dist/questionnaire/index.d.ts +42 -10
  28. package/dist/questionnaire/index.js +45 -13
  29. package/dist/questionnaire/index.js.map +1 -1
  30. package/dist/questionnaire/index.mjs +45 -13
  31. package/dist/questionnaire/index.mjs.map +1 -1
  32. package/dist/reviews/index.d.mts +4 -4
  33. package/dist/reviews/index.d.ts +4 -4
  34. package/dist/reviews/index.js +39 -8
  35. package/dist/reviews/index.js.map +1 -1
  36. package/dist/reviews/index.mjs +39 -8
  37. package/dist/reviews/index.mjs.map +1 -1
  38. package/dist/showcase/index.js +7 -2
  39. package/dist/showcase/index.js.map +1 -1
  40. package/dist/showcase/index.mjs +7 -2
  41. package/dist/showcase/index.mjs.map +1 -1
  42. package/dist/{transport-DsRe4epC.d.ts → transport-CefdERPs.d.mts} +44 -5
  43. package/dist/{transport-CF_eHwzC.d.mts → transport-DFuPyCoJ.d.ts} +44 -5
  44. package/dist/{types-Buj9Lw9t.d.ts → types-UVYt9BJe.d.ts} +41 -1
  45. package/dist/{types-CNUqMK0D.d.mts → types-l2tfg23P.d.mts} +41 -1
  46. package/package.json +4 -1
  47. package/src/OnboardingFlow.tsx +175 -15
  48. package/src/WireOnboarding.tsx +70 -8
  49. package/src/activation/wireActivation.ts +3 -3
  50. package/src/analytics/analyticsEvent.ts +16 -1
  51. package/src/analytics/analyticsFacade.ts +2 -2
  52. package/src/analytics/eventQueue.ts +85 -20
  53. package/src/analytics/reportClientEvent.ts +68 -12
  54. package/src/cards/CardGridSelectCard.tsx +1 -1
  55. package/src/cards/ChipSelectCard.tsx +2 -2
  56. package/src/cards/PermissionCard.tsx +438 -0
  57. package/src/cards/SelectionCard.tsx +1 -1
  58. package/src/cards/index.ts +7 -0
  59. package/src/coachmarks/runtime.ts +62 -2
  60. package/src/coachmarks/useCoachmarkTour.ts +62 -14
  61. package/src/context/deviceId.ts +4 -4
  62. package/src/features/WireFeaturesProvider.tsx +4 -1
  63. package/src/identity/userIdentity.ts +1 -1
  64. package/src/illustrations/defaultIllustrations.tsx +44 -3
  65. package/src/index.ts +38 -0
  66. package/src/permissions/index.ts +64 -0
  67. package/src/permissions/permissionCopy.ts +87 -0
  68. package/src/permissions/permissionEvents.ts +76 -0
  69. package/src/permissions/permissionMemory.ts +88 -0
  70. package/src/permissions/placement.ts +88 -0
  71. package/src/permissions/types.ts +131 -0
  72. package/src/questionnaire/QuestionnaireGate.tsx +90 -10
  73. package/src/questionnaire/index.ts +9 -1
  74. package/src/questionnaire/transport.ts +46 -11
  75. package/src/reviews/ReviewGate.tsx +61 -6
  76. package/src/reviews/index.ts +10 -1
  77. package/src/reviews/transport.ts +58 -12
  78. package/src/session/persistedSession.ts +10 -3
  79. package/src/session-analytics/useLifecycleEvents.ts +1 -1
  80. package/src/theme/ThemeContext.tsx +42 -1
  81. package/src/types.ts +66 -4
  82. package/src/utils/submitResult.ts +39 -0
package/dist/index.mjs CHANGED
@@ -1,406 +1,21 @@
1
- import { StyleSheet, Easing, Animated, BackHandler, Modal, Pressable, Text, View, TouchableOpacity, KeyboardAvoidingView, ScrollView, useWindowDimensions, TextInput, Image, AccessibilityInfo, Platform, Dimensions, I18nManager, AppState, NativeModules, TurboModuleRegistry } from 'react-native';
2
- import React18, { createContext, forwardRef, useRef, useState, useEffect, useCallback, useImperativeHandle, useMemo, useContext, useSyncExternalStore } from 'react';
1
+ import React19, { createContext, forwardRef, useRef, useState, useEffect, useCallback, useImperativeHandle, useMemo, useContext, useSyncExternalStore } from 'react';
3
2
  import { useWireAIThread, useWireAIAction, ComponentRenderer, WireAIProvider } from 'wireai-rn';
4
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import { StyleSheet, Easing, Animated, BackHandler, Modal, Pressable, Text, View, TouchableOpacity, KeyboardAvoidingView, ScrollView, useWindowDimensions, TextInput, Image, AccessibilityInfo, Platform, Dimensions, I18nManager, AppState } from 'react-native';
5
5
  import { SafeAreaView } from 'react-native-safe-area-context';
6
6
  import { z } from 'zod';
7
7
 
8
8
  var __defProp = Object.defineProperty;
9
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
- var __getOwnPropNames = Object.getOwnPropertyNames;
11
- var __hasOwnProp = Object.prototype.hasOwnProperty;
12
9
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
13
10
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
14
11
  }) : x)(function(x) {
15
12
  if (typeof require !== "undefined") return require.apply(this, arguments);
16
13
  throw Error('Dynamic require of "' + x + '" is not supported');
17
14
  });
18
- var __esm = (fn, res) => function __init() {
19
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
20
- };
21
15
  var __export = (target, all) => {
22
- for (var name2 in all)
23
- __defProp(target, name2, { get: all[name2], enumerable: true });
24
- };
25
- var __copyProps = (to, from, except, desc) => {
26
- if (from && typeof from === "object" || typeof from === "function") {
27
- for (let key of __getOwnPropNames(from))
28
- if (!__hasOwnProp.call(to, key) && key !== except)
29
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
30
- }
31
- return to;
16
+ for (var name in all)
17
+ __defProp(target, name, { get: all[name], enumerable: true });
32
18
  };
33
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
-
35
- // node_modules/expo-modules-core/src/errors/CodedError.ts
36
- var CodedError;
37
- var init_CodedError = __esm({
38
- "node_modules/expo-modules-core/src/errors/CodedError.ts"() {
39
- CodedError = class extends Error {
40
- constructor(code, message) {
41
- super(message);
42
- this.code = code;
43
- }
44
- };
45
- }
46
- });
47
-
48
- // node_modules/expo-modules-core/src/NativeModulesProxy.ts
49
- var NativeModulesProxy_default;
50
- var init_NativeModulesProxy = __esm({
51
- "node_modules/expo-modules-core/src/NativeModulesProxy.ts"() {
52
- NativeModulesProxy_default = {};
53
- }
54
- });
55
-
56
- // node_modules/expo-modules-core/src/TurboModuleToExpoModuleProxy.ts
57
- function createTurboModuleToExpoProxy(turboModule, name2) {
58
- return null;
59
- }
60
- var init_TurboModuleToExpoModuleProxy = __esm({
61
- "node_modules/expo-modules-core/src/TurboModuleToExpoModuleProxy.ts"() {
62
- }
63
- });
64
- var init_ensureNativeModulesAreInstalled = __esm({
65
- "node_modules/expo-modules-core/src/ensureNativeModulesAreInstalled.ts"() {
66
- }
67
- });
68
- function requireOptionalNativeModule(moduleName) {
69
- var _a2, _b, _c, _d, _e;
70
- try {
71
- return (_e = (_d = (_c = (_b = (_a2 = globalThis.expo) == null ? void 0 : _a2.modules) == null ? void 0 : _b[moduleName]) != null ? _c : NativeModulesProxy_default[moduleName]) != null ? _d : createTurboModuleToExpoProxy(TurboModuleRegistry.get(moduleName), moduleName)) != null ? _e : null;
72
- } catch (e) {
73
- const error = e;
74
- console.warn(`An error occurred while requiring the '${moduleName}' module: ${error.message}`);
75
- return null;
76
- }
77
- }
78
- var init_requireNativeModule = __esm({
79
- "node_modules/expo-modules-core/src/requireNativeModule.ts"() {
80
- init_NativeModulesProxy();
81
- init_TurboModuleToExpoModuleProxy();
82
- init_ensureNativeModulesAreInstalled();
83
- }
84
- });
85
-
86
- // node_modules/expo-modules-core/src/sweet/setUpJsLogger.fx.ts
87
- var init_setUpJsLogger_fx = __esm({
88
- "node_modules/expo-modules-core/src/sweet/setUpJsLogger.fx.ts"() {
89
- init_CodedError();
90
- init_requireNativeModule();
91
- if (__DEV__ && typeof window !== "undefined" && (process.env.EXPO_OS === "android" || process.env.EXPO_OS === "ios")) {
92
- const NativeJSLogger = requireOptionalNativeModule("ExpoModulesCoreJSLogger");
93
- if (NativeJSLogger) {
94
- const onNewException = {
95
- eventName: "ExpoModulesCoreJSLogger.onNewError",
96
- action: console.error
97
- };
98
- const onNewWarning = {
99
- eventName: "ExpoModulesCoreJSLogger.onNewWarning",
100
- action: console.warn
101
- };
102
- const onNewDebug = {
103
- eventName: "ExpoModulesCoreJSLogger.onNewDebug",
104
- action: console.debug
105
- };
106
- const onNewInfo = {
107
- eventName: "ExpoModulesCoreJSLogger.onNewInfo",
108
- action: console.info
109
- };
110
- const onNewTrace = {
111
- eventName: "ExpoModulesCoreJSLogger.onNewTrace",
112
- action: console.trace
113
- };
114
- const listeners = [
115
- onNewException,
116
- onNewWarning,
117
- onNewDebug,
118
- onNewInfo,
119
- onNewTrace
120
- ];
121
- for (const listener of listeners) {
122
- NativeJSLogger.addListener(listener.eventName, ({ message }) => {
123
- listener.action(message);
124
- });
125
- }
126
- }
127
- }
128
- globalThis.ExpoModulesCore_CodedError = CodedError;
129
- }
130
- });
131
-
132
- // node_modules/expo-modules-core/src/registerWebModule.ts
133
- var init_registerWebModule = __esm({
134
- "node_modules/expo-modules-core/src/registerWebModule.ts"() {
135
- }
136
- });
137
-
138
- // node_modules/expo-modules-core/src/TypedArrays.types.ts
139
- var init_TypedArrays_types = __esm({
140
- "node_modules/expo-modules-core/src/TypedArrays.types.ts"() {
141
- }
142
- });
143
-
144
- // node_modules/expo-modules-core/src/PermissionsInterface.ts
145
- var init_PermissionsInterface = __esm({
146
- "node_modules/expo-modules-core/src/PermissionsInterface.ts"() {
147
- }
148
- });
149
- var init_PermissionsHook = __esm({
150
- "node_modules/expo-modules-core/src/PermissionsHook.ts"() {
151
- "use client";
152
- }
153
- });
154
- var init_Refs = __esm({
155
- "node_modules/expo-modules-core/src/Refs.ts"() {
156
- }
157
- });
158
- var init_useReleasingSharedObject = __esm({
159
- "node_modules/expo-modules-core/src/hooks/useReleasingSharedObject.ts"() {
160
- "use client";
161
- }
162
- });
163
-
164
- // node_modules/expo-modules-core/src/reload.ts
165
- var init_reload = __esm({
166
- "node_modules/expo-modules-core/src/reload.ts"() {
167
- }
168
- });
169
-
170
- // node_modules/expo-modules-core/src/index.ts
171
- var init_src = __esm({
172
- "node_modules/expo-modules-core/src/index.ts"() {
173
- init_setUpJsLogger_fx();
174
- init_requireNativeModule();
175
- init_registerWebModule();
176
- init_TypedArrays_types();
177
- init_PermissionsInterface();
178
- init_PermissionsHook();
179
- init_Refs();
180
- init_useReleasingSharedObject();
181
- init_reload();
182
- init_CodedError();
183
- }
184
- });
185
-
186
- // node_modules/expo-constants/build/Constants.types.js
187
- var AppOwnership, ExecutionEnvironment, UserInterfaceIdiom;
188
- var init_Constants_types = __esm({
189
- "node_modules/expo-constants/build/Constants.types.js"() {
190
- (function(AppOwnership2) {
191
- AppOwnership2["Expo"] = "expo";
192
- })(AppOwnership || (AppOwnership = {}));
193
- (function(ExecutionEnvironment2) {
194
- ExecutionEnvironment2["Bare"] = "bare";
195
- ExecutionEnvironment2["Standalone"] = "standalone";
196
- ExecutionEnvironment2["StoreClient"] = "storeClient";
197
- })(ExecutionEnvironment || (ExecutionEnvironment = {}));
198
- (function(UserInterfaceIdiom2) {
199
- UserInterfaceIdiom2["Handset"] = "handset";
200
- UserInterfaceIdiom2["Tablet"] = "tablet";
201
- UserInterfaceIdiom2["Desktop"] = "desktop";
202
- UserInterfaceIdiom2["TV"] = "tv";
203
- UserInterfaceIdiom2["Unsupported"] = "unsupported";
204
- })(UserInterfaceIdiom || (UserInterfaceIdiom = {}));
205
- }
206
- });
207
-
208
- // node_modules/expo-constants/build/ExponentConstants.js
209
- var ExponentConstants_default;
210
- var init_ExponentConstants = __esm({
211
- "node_modules/expo-constants/build/ExponentConstants.js"() {
212
- init_src();
213
- ExponentConstants_default = requireOptionalNativeModule("ExponentConstants");
214
- }
215
- });
216
-
217
- // node_modules/expo-constants/build/Constants.js
218
- var Constants_exports = {};
219
- __export(Constants_exports, {
220
- AppOwnership: () => AppOwnership,
221
- ExecutionEnvironment: () => ExecutionEnvironment,
222
- UserInterfaceIdiom: () => UserInterfaceIdiom,
223
- default: () => Constants_default
224
- });
225
- function isEmbeddedManifest(manifest) {
226
- return !isExpoUpdatesManifest(manifest);
227
- }
228
- function isExpoUpdatesManifest(manifest) {
229
- return "metadata" in manifest;
230
- }
231
- function getManifest(suppressWarning = false) {
232
- if (!rawManifest) {
233
- const invalidManifestType = rawManifest === null ? "null" : "undefined";
234
- if (nativeConstants.executionEnvironment === ExecutionEnvironment.Bare && Platform.OS !== "web") {
235
- if (!suppressWarning) {
236
- console.warn(`Constants.manifest is ${invalidManifestType} because the embedded app.config could not be read. Ensure that you have installed the expo-constants build scripts if you need to read from Constants.manifest.`);
237
- }
238
- } else if (nativeConstants.executionEnvironment === ExecutionEnvironment.StoreClient || nativeConstants.executionEnvironment === ExecutionEnvironment.Standalone) {
239
- throw new CodedError("ERR_CONSTANTS_MANIFEST_UNAVAILABLE", `Constants.manifest is ${invalidManifestType}, must be an object.`);
240
- }
241
- }
242
- return rawManifest;
243
- }
244
- var ExpoUpdates, rawUpdatesManifest, rawDevLauncherManifest, rawAppConfig, _a, rawManifest, name, appOwnership, nativeConstants, constants, Constants_default;
245
- var init_Constants = __esm({
246
- "node_modules/expo-constants/build/Constants.js"() {
247
- init_src();
248
- init_Constants_types();
249
- init_ExponentConstants();
250
- init_Constants_types();
251
- if (!ExponentConstants_default) {
252
- console.warn("No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?");
253
- }
254
- ExpoUpdates = requireOptionalNativeModule("ExpoUpdates");
255
- rawUpdatesManifest = null;
256
- if (ExpoUpdates) {
257
- let updatesManifest;
258
- if (ExpoUpdates.manifest) {
259
- updatesManifest = ExpoUpdates.manifest;
260
- } else if (ExpoUpdates.manifestString) {
261
- updatesManifest = JSON.parse(ExpoUpdates.manifestString);
262
- }
263
- if (updatesManifest && Object.keys(updatesManifest).length > 0) {
264
- rawUpdatesManifest = updatesManifest;
265
- }
266
- }
267
- rawDevLauncherManifest = null;
268
- if (NativeModules.EXDevLauncher) {
269
- let devLauncherManifest;
270
- if (NativeModules.EXDevLauncher.manifestString) {
271
- devLauncherManifest = JSON.parse(NativeModules.EXDevLauncher.manifestString);
272
- }
273
- if (devLauncherManifest && Object.keys(devLauncherManifest).length > 0) {
274
- rawDevLauncherManifest = devLauncherManifest;
275
- }
276
- }
277
- rawAppConfig = null;
278
- if (ExponentConstants_default && ExponentConstants_default.manifest) {
279
- const appConfig = ExponentConstants_default.manifest;
280
- if (typeof appConfig === "string") {
281
- rawAppConfig = JSON.parse(appConfig);
282
- } else {
283
- rawAppConfig = appConfig;
284
- }
285
- }
286
- rawManifest = (_a = rawUpdatesManifest != null ? rawUpdatesManifest : rawDevLauncherManifest) != null ? _a : rawAppConfig;
287
- ({ name, appOwnership, ...nativeConstants } = ExponentConstants_default || {});
288
- constants = {
289
- ...nativeConstants,
290
- // Ensure this is null in bare workflow
291
- appOwnership: appOwnership != null ? appOwnership : null
292
- };
293
- Object.defineProperties(constants, {
294
- /**
295
- * Use `manifest` property by default.
296
- * This property is only used for internal purposes.
297
- * It behaves similarly to the original one, but suppresses warning upon no manifest available.
298
- * `expo-asset` uses it to prevent users from seeing mentioned warning.
299
- */
300
- __unsafeNoWarnManifest: {
301
- get() {
302
- const maybeManifest = getManifest(true);
303
- if (!maybeManifest || !isEmbeddedManifest(maybeManifest)) {
304
- return null;
305
- }
306
- return maybeManifest;
307
- },
308
- enumerable: false
309
- },
310
- __unsafeNoWarnManifest2: {
311
- get() {
312
- const maybeManifest = getManifest(true);
313
- if (!maybeManifest || !isExpoUpdatesManifest(maybeManifest)) {
314
- return null;
315
- }
316
- return maybeManifest;
317
- },
318
- enumerable: false
319
- },
320
- manifest: {
321
- get() {
322
- const maybeManifest = getManifest();
323
- if (!maybeManifest || !isEmbeddedManifest(maybeManifest)) {
324
- return null;
325
- }
326
- return maybeManifest;
327
- },
328
- enumerable: true
329
- },
330
- manifest2: {
331
- get() {
332
- const maybeManifest = getManifest();
333
- if (!maybeManifest || !isExpoUpdatesManifest(maybeManifest)) {
334
- return null;
335
- }
336
- return maybeManifest;
337
- },
338
- enumerable: true
339
- },
340
- expoConfig: {
341
- get() {
342
- var _a2, _b;
343
- const maybeManifest = getManifest(true);
344
- if (!maybeManifest) {
345
- return null;
346
- }
347
- if (ExpoUpdates && ExpoUpdates.isEmbeddedLaunch) {
348
- return rawAppConfig;
349
- }
350
- if (isExpoUpdatesManifest(maybeManifest)) {
351
- return (_b = (_a2 = maybeManifest.extra) == null ? void 0 : _a2.expoClient) != null ? _b : null;
352
- } else if (isEmbeddedManifest(maybeManifest)) {
353
- return maybeManifest;
354
- }
355
- return null;
356
- },
357
- enumerable: true
358
- },
359
- expoGoConfig: {
360
- get() {
361
- var _a2, _b;
362
- const maybeManifest = getManifest(true);
363
- if (!maybeManifest) {
364
- return null;
365
- }
366
- if (isExpoUpdatesManifest(maybeManifest)) {
367
- return (_b = (_a2 = maybeManifest.extra) == null ? void 0 : _a2.expoGo) != null ? _b : null;
368
- } else if (isEmbeddedManifest(maybeManifest)) {
369
- return maybeManifest;
370
- }
371
- return null;
372
- },
373
- enumerable: true
374
- },
375
- easConfig: {
376
- get() {
377
- var _a2, _b;
378
- const maybeManifest = getManifest(true);
379
- if (!maybeManifest) {
380
- return null;
381
- }
382
- if (isExpoUpdatesManifest(maybeManifest)) {
383
- return (_b = (_a2 = maybeManifest.extra) == null ? void 0 : _a2.eas) != null ? _b : null;
384
- } else if (isEmbeddedManifest(maybeManifest)) {
385
- return maybeManifest;
386
- }
387
- return null;
388
- },
389
- enumerable: true
390
- },
391
- __rawManifest_TEST: {
392
- get() {
393
- return rawManifest;
394
- },
395
- set(value) {
396
- rawManifest = value;
397
- },
398
- enumerable: false
399
- }
400
- });
401
- Constants_default = constants;
402
- }
403
- });
404
19
 
405
20
  // src/theme/defaultTheme.ts
406
21
  var defaultOnboardingTheme = {
@@ -458,7 +73,12 @@ var mergeTheme = (override) => {
458
73
  button: { ...defaultOnboardingTheme.button, ...override.button }
459
74
  };
460
75
  };
461
- var OnboardingThemeContext = createContext(null);
76
+ var THEME_CONTEXT_SLOT = /* @__PURE__ */ Symbol.for("@wireai/activation:themeContext");
77
+ var themeGlobal = globalThis;
78
+ if (!themeGlobal[THEME_CONTEXT_SLOT]) {
79
+ themeGlobal[THEME_CONTEXT_SLOT] = createContext(null);
80
+ }
81
+ var OnboardingThemeContext = themeGlobal[THEME_CONTEXT_SLOT];
462
82
  var OnboardingThemeProvider = ({
463
83
  theme,
464
84
  children
@@ -479,12 +99,12 @@ var IllustrationProvider = ({
479
99
  const value = useMemo(() => registry != null ? registry : EMPTY_REGISTRY, [registry]);
480
100
  return /* @__PURE__ */ jsx(IllustrationContext.Provider, { value, children });
481
101
  };
482
- var useIllustration = (name2) => {
102
+ var useIllustration = (name) => {
483
103
  const registry = useContext(IllustrationContext);
484
- if (!name2) return void 0;
485
- return registry[name2];
104
+ if (!name) return void 0;
105
+ return registry[name];
486
106
  };
487
- var Glyph = ({ children }) => {
107
+ var Disc = ({ children }) => {
488
108
  const t = useOnboardingTheme();
489
109
  return /* @__PURE__ */ jsx(
490
110
  View,
@@ -493,11 +113,23 @@ var Glyph = ({ children }) => {
493
113
  styles.disc,
494
114
  { backgroundColor: t.colors.primarySoft, borderRadius: t.radius.full }
495
115
  ],
496
- children: /* @__PURE__ */ jsx(Text, { style: [styles.glyphText, { color: t.colors.primary }], allowFontScaling: false, children })
116
+ children
497
117
  }
498
118
  );
499
119
  };
120
+ var Glyph = ({ children }) => {
121
+ const t = useOnboardingTheme();
122
+ return /* @__PURE__ */ jsx(Disc, { children: /* @__PURE__ */ jsx(Text, { style: [styles.glyphText, { color: t.colors.primary }], allowFontScaling: false, children }) });
123
+ };
500
124
  var MomentumGlyph = () => /* @__PURE__ */ jsx(Glyph, { children: "\u2197" });
125
+ var NotificationsGlyph = () => {
126
+ const t = useOnboardingTheme();
127
+ return /* @__PURE__ */ jsx(Disc, { children: /* @__PURE__ */ jsxs(View, { style: styles.bell, children: [
128
+ /* @__PURE__ */ jsx(View, { style: [styles.bellBody, { backgroundColor: t.colors.primary }] }),
129
+ /* @__PURE__ */ jsx(View, { style: [styles.bellRim, { backgroundColor: t.colors.primary }] }),
130
+ /* @__PURE__ */ jsx(View, { style: [styles.bellClapper, { backgroundColor: t.colors.primary }] })
131
+ ] }) });
132
+ };
501
133
  var BeforeAfterGlyph = () => {
502
134
  const t = useOnboardingTheme();
503
135
  return /* @__PURE__ */ jsxs(View, { style: styles.row, children: [
@@ -524,7 +156,8 @@ var BeforeAfterGlyph = () => {
524
156
  };
525
157
  var defaultIllustrations = {
526
158
  momentum: /* @__PURE__ */ jsx(MomentumGlyph, {}),
527
- "before-after": /* @__PURE__ */ jsx(BeforeAfterGlyph, {})
159
+ "before-after": /* @__PURE__ */ jsx(BeforeAfterGlyph, {}),
160
+ notifications: /* @__PURE__ */ jsx(NotificationsGlyph, {})
528
161
  };
529
162
  var styles = StyleSheet.create({
530
163
  disc: {
@@ -552,7 +185,12 @@ var styles = StyleSheet.create({
552
185
  arrow: {
553
186
  fontSize: 28,
554
187
  fontWeight: "700"
555
- }
188
+ },
189
+ // The bell: a domed body over a wider rim, with the clapper hanging below it.
190
+ bell: { alignItems: "center", justifyContent: "center" },
191
+ bellBody: { width: 34, height: 30, borderTopLeftRadius: 17, borderTopRightRadius: 17 },
192
+ bellRim: { width: 44, height: 5, borderRadius: 3, marginTop: 2 },
193
+ bellClapper: { width: 9, height: 9, borderRadius: 5, marginTop: 3 }
556
194
  });
557
195
  var EMPTY_REGISTRY2 = {};
558
196
  var IconContext = createContext(EMPTY_REGISTRY2);
@@ -563,11 +201,11 @@ var IconRegistryProvider = ({
563
201
  const value = useMemo(() => registry != null ? registry : EMPTY_REGISTRY2, [registry]);
564
202
  return /* @__PURE__ */ jsx(IconContext.Provider, { value, children });
565
203
  };
566
- var useHostIcon = (name2) => {
204
+ var useHostIcon = (name) => {
567
205
  const registry = useContext(IconContext);
568
- if (!name2) return void 0;
569
- if (!Object.prototype.hasOwnProperty.call(registry, name2)) return void 0;
570
- return registry[name2];
206
+ if (!name) return void 0;
207
+ if (!Object.prototype.hasOwnProperty.call(registry, name)) return void 0;
208
+ return registry[name];
571
209
  };
572
210
 
573
211
  // src/theme/typography.ts
@@ -583,9 +221,9 @@ var captionStyle = (f) => ({
583
221
  lineHeight: round(f.baseSize * 0.8125 * f.scale * 1.5)
584
222
  });
585
223
  var labelStyle = (f) => {
586
- var _a2;
224
+ var _a;
587
225
  return {
588
- fontFamily: (_a2 = f.medium) != null ? _a2 : f.bold,
226
+ fontFamily: (_a = f.medium) != null ? _a : f.bold,
589
227
  fontSize: round(f.baseSize * f.scale),
590
228
  lineHeight: round(f.baseSize * f.scale * 1.4),
591
229
  fontWeight: f.medium ? void 0 : "600"
@@ -598,9 +236,9 @@ var headingStyle = (f) => ({
598
236
  fontWeight: f.bold ? void 0 : "700"
599
237
  });
600
238
  var buttonLabelStyle = (f) => {
601
- var _a2;
239
+ var _a;
602
240
  return {
603
- fontFamily: (_a2 = f.bold) != null ? _a2 : f.medium,
241
+ fontFamily: (_a = f.bold) != null ? _a : f.medium,
604
242
  fontSize: round(f.baseSize * f.scale),
605
243
  fontWeight: f.bold ? void 0 : "600"
606
244
  };
@@ -802,7 +440,7 @@ var _AnimatedSparkle = ({ size = 30, color, variant = "spin" }) => {
802
440
  }
803
441
  ) });
804
442
  };
805
- var AnimatedSparkle = React18.memo(_AnimatedSparkle);
443
+ var AnimatedSparkle = React19.memo(_AnimatedSparkle);
806
444
  var styles2 = StyleSheet.create({
807
445
  box: { alignItems: "center", justifyContent: "center" },
808
446
  glyph: {
@@ -905,7 +543,7 @@ var _LoadingBlock = ({
905
543
  )
906
544
  ] });
907
545
  };
908
- var LoadingBlock = React18.memo(_LoadingBlock);
546
+ var LoadingBlock = React19.memo(_LoadingBlock);
909
547
  var styles3 = StyleSheet.create({
910
548
  center: { flex: 1, alignItems: "center", justifyContent: "center" },
911
549
  // Absolutely-positioned label column, pinned just under the centered stage: its top
@@ -950,7 +588,7 @@ var _LoadingScreen = ({ title, hint }) => {
950
588
  }
951
589
  );
952
590
  };
953
- var LoadingScreen = React18.memo(_LoadingScreen);
591
+ var LoadingScreen = React19.memo(_LoadingScreen);
954
592
  var styles4 = StyleSheet.create({
955
593
  flex: { flex: 1 }
956
594
  });
@@ -990,7 +628,7 @@ var _StepProgress = ({ step, complete, approxScreens }) => {
990
628
  }
991
629
  ) });
992
630
  };
993
- var StepProgress = React18.memo(_StepProgress);
631
+ var StepProgress = React19.memo(_StepProgress);
994
632
  var styles5 = StyleSheet.create({
995
633
  track: { height: 6, width: "100%", overflow: "hidden" },
996
634
  fill: { height: 6 }
@@ -1006,31 +644,31 @@ var _OnboardingScaffold = ({
1006
644
  children
1007
645
  }) => {
1008
646
  const t = useOnboardingTheme();
1009
- const styles17 = useMemo(() => makeStyles(t), [t]);
647
+ const styles18 = useMemo(() => makeStyles(t), [t]);
1010
648
  const hit = { top: 12, bottom: 12, left: 12, right: 12 };
1011
649
  return /* @__PURE__ */ jsxs(
1012
650
  SafeAreaView,
1013
651
  {
1014
652
  edges: ["top", "bottom"],
1015
- style: [styles17.flex, { backgroundColor: t.colors.background }],
653
+ style: [styles18.flex, { backgroundColor: t.colors.background }],
1016
654
  children: [
1017
- /* @__PURE__ */ jsxs(View, { style: [styles17.header, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }], children: [
1018
- /* @__PURE__ */ jsx(View, { style: styles17.progressWrap, children: /* @__PURE__ */ jsx(StepProgress, { step, complete, approxScreens }) }),
1019
- onSkip ? /* @__PURE__ */ jsx(TouchableOpacity, { onPress: onSkip, hitSlop: hit, style: styles17.skip, children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: skipLabel }) }) : null
655
+ /* @__PURE__ */ jsxs(View, { style: [styles18.header, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }], children: [
656
+ /* @__PURE__ */ jsx(View, { style: styles18.progressWrap, children: /* @__PURE__ */ jsx(StepProgress, { step, complete, approxScreens }) }),
657
+ onSkip ? /* @__PURE__ */ jsx(TouchableOpacity, { onPress: onSkip, hitSlop: hit, style: styles18.skip, children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: skipLabel }) }) : null
1020
658
  ] }),
1021
659
  /* @__PURE__ */ jsx(
1022
660
  View,
1023
661
  {
1024
- style: [styles17.body, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }],
662
+ style: [styles18.body, { paddingHorizontal: t.spacing.md, paddingTop: t.spacing.md }],
1025
663
  children
1026
664
  }
1027
665
  ),
1028
- onBack ? /* @__PURE__ */ jsx(View, { style: [styles17.footer, { paddingHorizontal: t.spacing.md, paddingBottom: t.spacing.sm }], children: /* @__PURE__ */ jsx(TouchableOpacity, { onPress: onBack, hitSlop: hit, children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: backLabel }) }) }) : null
666
+ onBack ? /* @__PURE__ */ jsx(View, { style: [styles18.footer, { paddingHorizontal: t.spacing.md, paddingBottom: t.spacing.sm }], children: /* @__PURE__ */ jsx(TouchableOpacity, { onPress: onBack, hitSlop: hit, children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted }], children: backLabel }) }) }) : null
1029
667
  ]
1030
668
  }
1031
669
  );
1032
670
  };
1033
- var OnboardingScaffold = React18.memo(_OnboardingScaffold);
671
+ var OnboardingScaffold = React19.memo(_OnboardingScaffold);
1034
672
  function makeStyles(t) {
1035
673
  return StyleSheet.create({
1036
674
  flex: { flex: 1 },
@@ -1131,7 +769,7 @@ var _Button = ({
1131
769
  }
1132
770
  );
1133
771
  };
1134
- var Button = React18.memo(_Button);
772
+ var Button = React19.memo(_Button);
1135
773
  var styles6 = StyleSheet.create({
1136
774
  base: { alignItems: "center", justifyContent: "center" },
1137
775
  fill: { width: "100%" }
@@ -1149,7 +787,7 @@ var _ErrorBlock = ({
1149
787
  onRetry ? /* @__PURE__ */ jsx(Button, { title: retryLabel, onPress: onRetry, variant: "outline" }) : null
1150
788
  ] });
1151
789
  };
1152
- var ErrorBlock = React18.memo(_ErrorBlock);
790
+ var ErrorBlock = React19.memo(_ErrorBlock);
1153
791
  var styles7 = StyleSheet.create({
1154
792
  center: { flex: 1, alignItems: "center", justifyContent: "center" }
1155
793
  });
@@ -1162,10 +800,10 @@ var _CardLayout = ({
1162
800
  titleNode
1163
801
  }) => {
1164
802
  const t = useOnboardingTheme();
1165
- const styles17 = useMemo(() => makeStyles2(t), [t]);
803
+ const styles18 = useMemo(() => makeStyles2(t), [t]);
1166
804
  const hasHeader = !!title || !!subtitle || !!titleNode;
1167
- return /* @__PURE__ */ jsxs(KeyboardAvoidingView, { style: styles17.fill, behavior: "padding", children: [
1168
- hasHeader ? /* @__PURE__ */ jsxs(View, { style: styles17.header, children: [
805
+ return /* @__PURE__ */ jsxs(KeyboardAvoidingView, { style: styles18.fill, behavior: "padding", children: [
806
+ hasHeader ? /* @__PURE__ */ jsxs(View, { style: styles18.header, children: [
1169
807
  titleNode != null ? titleNode : title ? /* @__PURE__ */ jsx(Text, { style: [labelStyle(t.fonts), { color: t.colors.text }], children: title }) : null,
1170
808
  subtitle ? /* @__PURE__ */ jsx(
1171
809
  Text,
@@ -1181,10 +819,10 @@ var _CardLayout = ({
1181
819
  /* @__PURE__ */ jsx(
1182
820
  ScrollView,
1183
821
  {
1184
- style: styles17.fill,
822
+ style: styles18.fill,
1185
823
  contentContainerStyle: [
1186
- styles17.scrollContent,
1187
- align === "center" && styles17.center
824
+ styles18.scrollContent,
825
+ align === "center" && styles18.center
1188
826
  ],
1189
827
  keyboardShouldPersistTaps: "handled",
1190
828
  keyboardDismissMode: "on-drag",
@@ -1192,10 +830,10 @@ var _CardLayout = ({
1192
830
  children
1193
831
  }
1194
832
  ),
1195
- footer ? /* @__PURE__ */ jsx(View, { style: styles17.footer, children: footer }) : null
833
+ footer ? /* @__PURE__ */ jsx(View, { style: styles18.footer, children: footer }) : null
1196
834
  ] });
1197
835
  };
1198
- var CardLayout = React18.memo(_CardLayout);
836
+ var CardLayout = React19.memo(_CardLayout);
1199
837
  function makeStyles2(t) {
1200
838
  return StyleSheet.create({
1201
839
  fill: { flex: 1 },
@@ -1320,7 +958,7 @@ var _CompletionView = ({
1320
958
  }
1321
959
  );
1322
960
  };
1323
- var CompletionView = React18.memo(_CompletionView);
961
+ var CompletionView = React19.memo(_CompletionView);
1324
962
  var styles8 = StyleSheet.create({
1325
963
  center: { width: "100%", alignItems: "center", justifyContent: "center" },
1326
964
  badgeStage: {
@@ -1349,7 +987,7 @@ var _CardHandoff = ({
1349
987
  const running = useRef({});
1350
988
  const mounted = useRef(false);
1351
989
  useEffect(() => {
1352
- var _a2, _b;
990
+ var _a, _b;
1353
991
  const last = prev.current;
1354
992
  prev.current = { key: transitionKey, node: children, variant };
1355
993
  if (!mounted.current) {
@@ -1358,7 +996,7 @@ var _CardHandoff = ({
1358
996
  return;
1359
997
  }
1360
998
  if (last.key === transitionKey) return;
1361
- (_a2 = running.current.enter) == null ? void 0 : _a2.stop();
999
+ (_a = running.current.enter) == null ? void 0 : _a.stop();
1362
1000
  (_b = running.current.exit) == null ? void 0 : _b.stop();
1363
1001
  setLeaving(last);
1364
1002
  enterT.setValue(0);
@@ -1383,8 +1021,8 @@ var _CardHandoff = ({
1383
1021
  });
1384
1022
  useEffect(
1385
1023
  () => () => {
1386
- var _a2, _b;
1387
- (_a2 = running.current.enter) == null ? void 0 : _a2.stop();
1024
+ var _a, _b;
1025
+ (_a = running.current.enter) == null ? void 0 : _a.stop();
1388
1026
  (_b = running.current.exit) == null ? void 0 : _b.stop();
1389
1027
  },
1390
1028
  []
@@ -1450,7 +1088,7 @@ var transformFor = (variant, t, reduced, layer, travel) => {
1450
1088
  }
1451
1089
  ];
1452
1090
  };
1453
- var CardHandoff = React18.memo(_CardHandoff);
1091
+ var CardHandoff = React19.memo(_CardHandoff);
1454
1092
  var styles9 = StyleSheet.create({
1455
1093
  fill: { flex: 1 }
1456
1094
  });
@@ -1465,13 +1103,13 @@ var tryParse = (s) => {
1465
1103
  }
1466
1104
  };
1467
1105
  var deriveAnswers = (messages) => {
1468
- var _a2, _b, _c;
1106
+ var _a, _b, _c;
1469
1107
  const out = {};
1470
1108
  for (let i = 0; i < messages.length; i++) {
1471
1109
  const m = messages[i];
1472
1110
  const r = m == null ? void 0 : m.response;
1473
1111
  if (!m || m.role !== "assistant" || !r || r.action !== "render") continue;
1474
- const props = (_a2 = r.props) != null ? _a2 : {};
1112
+ const props = (_a = r.props) != null ? _a : {};
1475
1113
  const progress = props.progress;
1476
1114
  const questionText = (_c = (_b = props.title) != null ? _b : props.label) != null ? _c : props.question;
1477
1115
  const key = (progress == null ? void 0 : progress.slot_id) || (progress == null ? void 0 : progress.key) || questionText;
@@ -1485,9 +1123,9 @@ var deriveAnswers = (messages) => {
1485
1123
 
1486
1124
  // src/utils/readProgress.ts
1487
1125
  var readProgress = (response) => {
1488
- var _a2;
1126
+ var _a;
1489
1127
  if (!response || response.action !== "render") return {};
1490
- const props = (_a2 = response.props) != null ? _a2 : {};
1128
+ const props = (_a = response.props) != null ? _a : {};
1491
1129
  const raw = props.progress;
1492
1130
  if (!raw || typeof raw !== "object") return {};
1493
1131
  const p = raw;
@@ -1503,13 +1141,24 @@ var readProgress = (response) => {
1503
1141
 
1504
1142
  // src/analytics/reportClientEvent.ts
1505
1143
  var makeSessionId = () => `wire_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
1144
+ var toWireEvents = (events) => events.map((event) => {
1145
+ if (typeof event.ts !== "number") return event;
1146
+ const { ts, ...rest } = event;
1147
+ if (!Number.isFinite(ts)) return rest;
1148
+ try {
1149
+ return { ...rest, ts: new Date(ts).toISOString() };
1150
+ } catch {
1151
+ return rest;
1152
+ }
1153
+ });
1506
1154
  var buildEventsRequest = (target, events) => {
1507
1155
  if (!(target == null ? void 0 : target.serverUrl) || events.length === 0) return null;
1508
1156
  try {
1509
1157
  const url = `${target.serverUrl.replace(/\/$/, "")}/v1/events`;
1510
1158
  const headers = { "Content-Type": "application/json" };
1511
1159
  if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
1512
- return { url, init: { method: "POST", headers, body: JSON.stringify({ events }) } };
1160
+ const body = JSON.stringify({ events: toWireEvents(events) });
1161
+ return { url, init: { method: "POST", headers, body } };
1513
1162
  } catch {
1514
1163
  return null;
1515
1164
  }
@@ -1521,7 +1170,13 @@ var readEventsAck = async (res) => {
1521
1170
  const body = await Promise.resolve(json.call(res));
1522
1171
  const skipped = body == null ? void 0 : body.skipped;
1523
1172
  if (typeof skipped !== "number" || !Number.isFinite(skipped)) return void 0;
1524
- 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") : [];
1173
+ const reasons = Array.isArray(body == null ? void 0 : body.errors) ? body.errors.map((e) => {
1174
+ const entry = e;
1175
+ const reason = entry == null ? void 0 : entry.reason;
1176
+ if (typeof reason !== "string") return void 0;
1177
+ const field = entry == null ? void 0 : entry.field;
1178
+ return typeof field === "string" && field.length > 0 ? `${reason} (field: ${field})` : reason;
1179
+ }).filter((r) => typeof r === "string") : [];
1525
1180
  return { written: typeof (body == null ? void 0 : body.written) === "number" ? body.written : void 0, skipped, reasons };
1526
1181
  } catch {
1527
1182
  return void 0;
@@ -1591,6 +1246,382 @@ var sendPreview = (target, { sessionId, userMessage }) => {
1591
1246
  } catch {
1592
1247
  }
1593
1248
  };
1249
+
1250
+ // src/permissions/permissionEvents.ts
1251
+ var WIRE_PERMISSION_EVENTS = {
1252
+ /** The priming screen became visible. The denominator for every rate below. */
1253
+ screenShown: "wire_permission_screen_shown",
1254
+ /** The user tapped the primary, so the OS dialog is about to open. The rationale worked. */
1255
+ primerAccepted: "wire_permission_primer_accepted",
1256
+ /** The OS granted it. */
1257
+ granted: "wire_permission_granted",
1258
+ /** The OS refused it (a permanently blocked answer reports here too, with `status: "blocked"`). */
1259
+ denied: "wire_permission_denied",
1260
+ /** The user took the secondary. The one native prompt was NOT spent. */
1261
+ skipped: "wire_permission_skipped",
1262
+ /** A blocked user was redirected to the OS settings page. */
1263
+ settingsOpened: "wire_permission_settings_opened"
1264
+ };
1265
+ var permissionEventName = (stage) => {
1266
+ switch (stage) {
1267
+ case "shown":
1268
+ return WIRE_PERMISSION_EVENTS.screenShown;
1269
+ case "accepted":
1270
+ return WIRE_PERMISSION_EVENTS.primerAccepted;
1271
+ case "granted":
1272
+ return WIRE_PERMISSION_EVENTS.granted;
1273
+ case "denied":
1274
+ return WIRE_PERMISSION_EVENTS.denied;
1275
+ case "skipped":
1276
+ return WIRE_PERMISSION_EVENTS.skipped;
1277
+ case "settings":
1278
+ return WIRE_PERMISSION_EVENTS.settingsOpened;
1279
+ default: {
1280
+ const _exhaustive = stage;
1281
+ return _exhaustive;
1282
+ }
1283
+ }
1284
+ };
1285
+ var permissionEventProps = (permission, status) => status ? { permission, status } : { permission };
1286
+ var normalizePermissionStatus = (value) => value === "granted" || value === "denied" || value === "blocked" ? value : "denied";
1287
+
1288
+ // src/haptics/haptics.ts
1289
+ var play = async (tone) => {
1290
+ try {
1291
+ const mod = await import('expo-haptics');
1292
+ if (!mod) return false;
1293
+ if (tone === "selection") ;
1294
+ if (tone === "light") ;
1295
+ await mod.notificationAsync(mod.NotificationFeedbackType.Success);
1296
+ return true;
1297
+ } catch {
1298
+ return false;
1299
+ }
1300
+ };
1301
+ var playHaptic = (tone) => {
1302
+ void play(tone);
1303
+ };
1304
+
1305
+ // src/utils/warnInDev.ts
1306
+ var warnInDev = (message) => {
1307
+ if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
1308
+ console.warn(message);
1309
+ return true;
1310
+ }
1311
+ return false;
1312
+ };
1313
+ var easeWire4 = Easing.bezier(...WIRE_BEZIER);
1314
+ var RISE_PX = 10;
1315
+ var PERMISSION_CARD_NAME = "PermissionCard";
1316
+ var REQUEST_WATCHDOG_MS = 9e4;
1317
+ var schema = z.object({
1318
+ permission: z.string().describe("Which OS permission this screen primes, e.g. 'notifications'"),
1319
+ title: z.string().describe("Headline for the ask"),
1320
+ message: z.string().describe("Why the app needs it, in the user's terms"),
1321
+ primaryLabel: z.string().describe("Primary button, the only control that can open the OS dialog"),
1322
+ secondaryLabel: z.string().describe("Secondary button, advances without spending the OS prompt"),
1323
+ blockedTitle: z.string().optional().describe("Headline once the permission is permanently refused"),
1324
+ blockedMessage: z.string().optional().describe("Rationale for the settings route"),
1325
+ settingsLabel: z.string().optional().describe("Primary button label on the blocked route"),
1326
+ continueLabel: z.string().optional().describe("Primary button label when there is nothing to ask"),
1327
+ illustration: z.string().optional().describe("Name of an app-provided illustration (defaults to the permission name)")
1328
+ });
1329
+ var _PermissionCard = ({
1330
+ permission,
1331
+ title,
1332
+ message,
1333
+ primaryLabel,
1334
+ secondaryLabel,
1335
+ blockedTitle,
1336
+ blockedMessage,
1337
+ settingsLabel,
1338
+ continueLabel,
1339
+ illustration,
1340
+ request,
1341
+ getStatus,
1342
+ openSettings,
1343
+ onStage,
1344
+ onSettled
1345
+ }) => {
1346
+ const t = useOnboardingTheme();
1347
+ const reduced = useReducedMotion();
1348
+ const art = useIllustration(illustration != null ? illustration : permission);
1349
+ const [status, setStatus] = useState(void 0);
1350
+ const [busy, setBusy] = useState(false);
1351
+ const settledRef = useRef(false);
1352
+ const acceptedRef = useRef(false);
1353
+ const watchdogRef = useRef(null);
1354
+ const clearWatchdog = useCallback(() => {
1355
+ if (watchdogRef.current) {
1356
+ clearTimeout(watchdogRef.current);
1357
+ watchdogRef.current = null;
1358
+ }
1359
+ }, []);
1360
+ useEffect(() => clearWatchdog, [clearWatchdog]);
1361
+ const onStageRef = useRef(onStage);
1362
+ onStageRef.current = onStage;
1363
+ const onSettledRef = useRef(onSettled);
1364
+ onSettledRef.current = onSettled;
1365
+ const getStatusRef = useRef(getStatus);
1366
+ getStatusRef.current = getStatus;
1367
+ const shownRef = useRef(false);
1368
+ useEffect(() => {
1369
+ var _a;
1370
+ if (shownRef.current) return;
1371
+ shownRef.current = true;
1372
+ (_a = onStageRef.current) == null ? void 0 : _a.call(onStageRef, "shown");
1373
+ }, []);
1374
+ useEffect(() => {
1375
+ const probe = getStatusRef.current;
1376
+ if (!probe) return;
1377
+ let cancelled = false;
1378
+ try {
1379
+ void Promise.resolve(probe()).then((value) => {
1380
+ if (!cancelled) setStatus(normalizePermissionStatus(value));
1381
+ }).catch(() => {
1382
+ });
1383
+ } catch {
1384
+ }
1385
+ return () => {
1386
+ cancelled = true;
1387
+ };
1388
+ }, []);
1389
+ const requestRef = useRef(request);
1390
+ requestRef.current = request;
1391
+ useEffect(() => {
1392
+ if (requestRef.current) return;
1393
+ warnInDev(
1394
+ `[wireai] <WireOnboarding> got a permission screen for "${permission}" with no \`request\` function, so it cannot open the OS dialog and renders as a plain continue. Pass request: () => Promise<'granted' | 'denied' | 'blocked'> (5 lines around expo-notifications, see the README).`
1395
+ );
1396
+ }, [permission]);
1397
+ const settle = useCallback((outcome) => {
1398
+ var _a;
1399
+ if (settledRef.current) return;
1400
+ settledRef.current = true;
1401
+ clearWatchdog();
1402
+ (_a = onSettledRef.current) == null ? void 0 : _a.call(onSettledRef, outcome);
1403
+ }, [clearWatchdog]);
1404
+ const primaryAction = status === "blocked" ? "settings" : status === "granted" || !request ? "continue" : "ask";
1405
+ const handlePrimary = useCallback(() => {
1406
+ var _a, _b, _c, _d;
1407
+ if (settledRef.current || busy) return;
1408
+ if (primaryAction === "settings") {
1409
+ (_a = onStageRef.current) == null ? void 0 : _a.call(onStageRef, "settings", "blocked");
1410
+ try {
1411
+ void Promise.resolve(openSettings == null ? void 0 : openSettings()).catch(() => {
1412
+ });
1413
+ } catch {
1414
+ }
1415
+ settle("blocked");
1416
+ return;
1417
+ }
1418
+ if (primaryAction === "continue") {
1419
+ if (status === "granted") {
1420
+ (_b = onStageRef.current) == null ? void 0 : _b.call(onStageRef, "granted", "granted");
1421
+ settle("granted");
1422
+ } else {
1423
+ (_c = onStageRef.current) == null ? void 0 : _c.call(onStageRef, "skipped");
1424
+ settle("skipped");
1425
+ }
1426
+ return;
1427
+ }
1428
+ if (!acceptedRef.current) {
1429
+ acceptedRef.current = true;
1430
+ (_d = onStageRef.current) == null ? void 0 : _d.call(onStageRef, "accepted");
1431
+ }
1432
+ setBusy(true);
1433
+ const finish = (value) => {
1434
+ var _a2, _b2;
1435
+ if (settledRef.current) return;
1436
+ clearWatchdog();
1437
+ const resolved = normalizePermissionStatus(value);
1438
+ setBusy(false);
1439
+ setStatus(resolved);
1440
+ if (resolved === "granted") {
1441
+ playHaptic("success");
1442
+ (_a2 = onStageRef.current) == null ? void 0 : _a2.call(onStageRef, "granted", "granted");
1443
+ } else {
1444
+ (_b2 = onStageRef.current) == null ? void 0 : _b2.call(onStageRef, "denied", resolved);
1445
+ }
1446
+ settle(resolved);
1447
+ };
1448
+ clearWatchdog();
1449
+ watchdogRef.current = setTimeout(() => {
1450
+ watchdogRef.current = null;
1451
+ if (settledRef.current) return;
1452
+ setBusy(false);
1453
+ warnInDev(
1454
+ `[wireai] the \`request\` for the "${permission}" permission screen has not settled after ${Math.round(REQUEST_WATCHDOG_MS / 1e3)}s, so the kit handed the controls back rather than leaving the user on a dead-end screen. It recorded NO outcome, because a pending request is not a denial. Make sure your request resolves to 'granted' | 'denied' | 'blocked' on every branch, including the one where the user dismisses the OS dialog.`
1455
+ );
1456
+ }, REQUEST_WATCHDOG_MS);
1457
+ try {
1458
+ void Promise.resolve(request == null ? void 0 : request()).then(finish, () => finish("denied"));
1459
+ } catch {
1460
+ finish("denied");
1461
+ }
1462
+ }, [busy, primaryAction, status, request, openSettings, settle, clearWatchdog, permission]);
1463
+ const handleSecondary = useCallback(() => {
1464
+ var _a;
1465
+ if (settledRef.current || busy) return;
1466
+ (_a = onStageRef.current) == null ? void 0 : _a.call(onStageRef, "skipped");
1467
+ settle("skipped");
1468
+ }, [busy, settle]);
1469
+ const popT = useRef(new Animated.Value(reduced ? 1 : 0)).current;
1470
+ const titleT = useRef(new Animated.Value(reduced ? 1 : 0)).current;
1471
+ const bodyT = useRef(new Animated.Value(reduced ? 1 : 0)).current;
1472
+ useEffect(() => {
1473
+ if (reduced) {
1474
+ popT.setValue(1);
1475
+ titleT.setValue(1);
1476
+ bodyT.setValue(1);
1477
+ return;
1478
+ }
1479
+ const rise = (value, delay) => Animated.timing(value, {
1480
+ toValue: 1,
1481
+ duration: scaledMs(INTERSTITIAL_HEAD_MS),
1482
+ delay,
1483
+ easing: easeWire4,
1484
+ useNativeDriver: true
1485
+ });
1486
+ const anims = [
1487
+ Animated.spring(popT, {
1488
+ toValue: 1,
1489
+ friction: STATUS_POP_SPRING.friction,
1490
+ tension: STATUS_POP_SPRING.tension,
1491
+ useNativeDriver: true
1492
+ }),
1493
+ rise(titleT, scaledMs(INTERSTITIAL_HEAD_STAGGER_MS)),
1494
+ rise(bodyT, scaledMs(INTERSTITIAL_HEAD_STAGGER_MS * 2))
1495
+ ];
1496
+ anims.forEach((a) => a.start());
1497
+ return () => anims.forEach((a) => a.stop());
1498
+ }, [reduced, popT, titleT, bodyT]);
1499
+ const popScale = popT.interpolate({
1500
+ inputRange: [0, 1],
1501
+ outputRange: [STATUS_POP_SCALE_FROM, 1]
1502
+ });
1503
+ const riseStyle = (value) => ({
1504
+ opacity: value,
1505
+ transform: [
1506
+ { translateY: value.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX, 0] }) }
1507
+ ]
1508
+ });
1509
+ const blocked = status === "blocked";
1510
+ const shownTitle = blocked ? blockedTitle != null ? blockedTitle : title : title;
1511
+ const shownMessage = blocked ? blockedMessage != null ? blockedMessage : message : message;
1512
+ const primaryTitle = primaryAction === "settings" ? settingsLabel != null ? settingsLabel : primaryLabel : primaryAction === "continue" ? continueLabel != null ? continueLabel : primaryLabel : primaryLabel;
1513
+ const showSecondary = status !== "granted";
1514
+ return /* @__PURE__ */ jsx(
1515
+ CardLayout,
1516
+ {
1517
+ align: "center",
1518
+ footer: /* @__PURE__ */ jsxs(View, { style: [styles10.footer, { gap: t.spacing.sm }], children: [
1519
+ /* @__PURE__ */ jsx(Button, { title: primaryTitle, onPress: handlePrimary, variant: "primary", disabled: busy }),
1520
+ showSecondary ? /* @__PURE__ */ jsx(
1521
+ Button,
1522
+ {
1523
+ title: secondaryLabel,
1524
+ onPress: handleSecondary,
1525
+ variant: "outline",
1526
+ disabled: busy
1527
+ }
1528
+ ) : null
1529
+ ] }),
1530
+ children: /* @__PURE__ */ jsxs(View, { style: [styles10.center, { gap: t.spacing.md }], children: [
1531
+ art ? /* @__PURE__ */ jsx(
1532
+ Animated.View,
1533
+ {
1534
+ style: [styles10.art, { opacity: popT, transform: [{ scale: popScale }] }],
1535
+ children: art
1536
+ }
1537
+ ) : null,
1538
+ /* @__PURE__ */ jsx(Animated.View, { style: riseStyle(titleT), children: /* @__PURE__ */ jsx(Text, { style: [headingStyle(t.fonts), { color: t.colors.text, textAlign: "center" }], children: shownTitle }) }),
1539
+ /* @__PURE__ */ jsx(Animated.View, { style: riseStyle(bodyT), children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted, textAlign: "center" }], children: shownMessage }) })
1540
+ ] })
1541
+ }
1542
+ );
1543
+ };
1544
+ var PermissionCardView = React19.memo(_PermissionCard);
1545
+ var PermissionCard = {
1546
+ name: PERMISSION_CARD_NAME,
1547
+ description: "A priming screen shown BEFORE an OS permission dialog: it explains why the app wants the permission and asks only on the primary tap. Never first, never last. The user is never blocked by it: the secondary advances the flow with the OS prompt unspent.",
1548
+ component: PermissionCardView,
1549
+ propsSchema: schema
1550
+ };
1551
+ var styles10 = StyleSheet.create({
1552
+ center: { width: "100%", alignItems: "center", justifyContent: "center" },
1553
+ art: { alignItems: "center", justifyContent: "center" },
1554
+ footer: { width: "100%", alignItems: "center" }
1555
+ });
1556
+
1557
+ // src/permissions/placement.ts
1558
+ var DEFAULT_PERMISSION_PLACEMENT = "beforeEnd";
1559
+ var normalizeAfterCard = (value) => Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
1560
+ var targetIndex = (placement) => {
1561
+ if (placement === "beforeEnd") return void 0;
1562
+ if (placement === "start") return 0;
1563
+ return normalizeAfterCard(placement.afterCard);
1564
+ };
1565
+ var isPermissionDue = (placement, position) => {
1566
+ if (position.cardIndex < 0) return false;
1567
+ const target = targetIndex(placement);
1568
+ if (target === void 0) return position.isTerminal;
1569
+ return position.cardIndex >= target || position.isTerminal;
1570
+ };
1571
+ var permissionScreenId = (screen, index) => {
1572
+ var _a;
1573
+ return (_a = screen.id) != null ? _a : `${screen.permission}:${index}`;
1574
+ };
1575
+ var selectDuePermissionScreen = (screens, settled, position) => {
1576
+ var _a;
1577
+ if (!screens || screens.length === 0) return void 0;
1578
+ for (let index = 0; index < screens.length; index++) {
1579
+ const screen = screens[index];
1580
+ if (!screen) continue;
1581
+ const id = permissionScreenId(screen, index);
1582
+ if (settled.includes(id)) continue;
1583
+ if (isPermissionDue((_a = screen.placement) != null ? _a : DEFAULT_PERMISSION_PLACEMENT, position)) {
1584
+ return { screen, id };
1585
+ }
1586
+ }
1587
+ return void 0;
1588
+ };
1589
+
1590
+ // src/permissions/permissionCopy.ts
1591
+ var NOTIFICATIONS_PERMISSION_COPY = {
1592
+ title: "Want a nudge at the right moment?",
1593
+ message: "Turn notifications on and we will remind you when it actually helps. No daily noise, and you can turn them off any time.",
1594
+ primaryLabel: "Enable notifications",
1595
+ secondaryLabel: "Maybe later",
1596
+ blockedTitle: "Notifications are switched off",
1597
+ blockedMessage: "Notifications are turned off for this app, so we cannot ask from here. You can switch them back on in Settings.",
1598
+ settingsLabel: "Open settings",
1599
+ continueLabel: "Continue"
1600
+ };
1601
+ var GENERIC_PERMISSION_COPY = {
1602
+ title: "One quick permission",
1603
+ message: "We need your permission for this part to work. You can change it any time.",
1604
+ primaryLabel: "Allow",
1605
+ secondaryLabel: "Maybe later",
1606
+ blockedTitle: "Permission is switched off",
1607
+ blockedMessage: "This permission is turned off for this app, so we cannot ask from here. You can switch it back on in Settings.",
1608
+ settingsLabel: "Open settings",
1609
+ continueLabel: "Continue"
1610
+ };
1611
+ var DEFAULT_PERMISSION_COPY = {
1612
+ notifications: NOTIFICATIONS_PERMISSION_COPY
1613
+ };
1614
+ var resolvePermissionCopy = (permission, overrides) => {
1615
+ var _a;
1616
+ const base = (_a = DEFAULT_PERMISSION_COPY[permission]) != null ? _a : GENERIC_PERMISSION_COPY;
1617
+ if (!overrides) return base;
1618
+ const merged = { ...base };
1619
+ for (const key of Object.keys(overrides)) {
1620
+ const value = overrides[key];
1621
+ if (typeof value === "string" && value.length > 0) merged[key] = value;
1622
+ }
1623
+ return merged;
1624
+ };
1594
1625
  var SKIP_ONE_SENTINEL = "__wireai_skip__";
1595
1626
  var ANSWER_CALLBACKS = ["onSubmit", "onSelect", "onConfirm", "onPress"];
1596
1627
  var DEFAULT_COPY = {
@@ -1619,9 +1650,13 @@ var OnboardingFlow = ({
1619
1650
  reportTarget,
1620
1651
  sessionId,
1621
1652
  resumed = false,
1622
- clientContext
1653
+ clientContext,
1654
+ permissionScreens,
1655
+ settledPermissions,
1656
+ permissionsPending = false,
1657
+ onPermissionSettled
1623
1658
  }) => {
1624
- var _a2, _b, _c, _d, _e, _f;
1659
+ var _a, _b, _c, _d, _e, _f;
1625
1660
  const { messages, error, isLoading, sendMessage, reset } = useWireAIThread();
1626
1661
  const makeActions = useWireAIAction(sendMessage);
1627
1662
  const c = useMemo(() => ({ ...DEFAULT_COPY, ...copy }), [copy]);
@@ -1641,7 +1676,8 @@ var OnboardingFlow = ({
1641
1676
  clientContextRef.current = clientContext;
1642
1677
  const lastScreenIndexRef = useRef(-1);
1643
1678
  const previewTimer = useRef(null);
1644
- const started = useRef(false);
1679
+ const [runId, setRunId] = useState(0);
1680
+ const startedRunRef = useRef(-1);
1645
1681
  const finished = useRef(false);
1646
1682
  const errored = useRef(false);
1647
1683
  const attempts = useRef(0);
@@ -1650,41 +1686,46 @@ var OnboardingFlow = ({
1650
1686
  const [timedOut, setTimedOut] = useState(false);
1651
1687
  const [validationError, setValidationError] = useState();
1652
1688
  const [validating, setValidating] = useState(false);
1689
+ const [locallySettledPermissions, setLocallySettledPermissions] = useState([]);
1690
+ const onPermissionSettledRef = useRef(onPermissionSettled);
1691
+ onPermissionSettledRef.current = onPermissionSettled;
1653
1692
  const lastCard = useMemo(
1654
1693
  () => [...messages].reverse().find((m) => {
1655
- var _a3;
1656
- return m.role === "assistant" && ((_a3 = m.response) == null ? void 0 : _a3.action) === "render";
1694
+ var _a2;
1695
+ return m.role === "assistant" && ((_a2 = m.response) == null ? void 0 : _a2.action) === "render";
1657
1696
  }),
1658
1697
  [messages]
1659
1698
  );
1660
1699
  const renderedCount = useMemo(
1661
1700
  () => messages.filter((m) => {
1662
- var _a3;
1663
- return m.role === "assistant" && ((_a3 = m.response) == null ? void 0 : _a3.action) === "render";
1701
+ var _a2;
1702
+ return m.role === "assistant" && ((_a2 = m.response) == null ? void 0 : _a2.action) === "render";
1664
1703
  }).length,
1665
1704
  [messages]
1666
1705
  );
1667
1706
  const progress = useMemo(() => readProgress(lastCard == null ? void 0 : lastCard.response), [lastCard]);
1668
1707
  useEffect(() => {
1669
- var _a3;
1670
- if (started.current) return;
1671
- started.current = true;
1672
- sendMessage(resumed ? SKIP_ONE_SENTINEL : startMessage);
1673
- (_a3 = onEventRef.current) == null ? void 0 : _a3.call(
1708
+ var _a2;
1709
+ if (startedRunRef.current === runId) return;
1710
+ const isFirstRun = startedRunRef.current < 0;
1711
+ startedRunRef.current = runId;
1712
+ sendMessage(isFirstRun && !resumed ? startMessage : SKIP_ONE_SENTINEL);
1713
+ if (!isFirstRun) return;
1714
+ (_a2 = onEventRef.current) == null ? void 0 : _a2.call(
1674
1715
  onEventRef,
1675
1716
  resumed ? { type: "resumed", contextId: sessionId } : { type: "started", contextId: sessionId }
1676
1717
  );
1677
- }, [sendMessage, startMessage, resumed, sessionId]);
1718
+ }, [sendMessage, startMessage, resumed, sessionId, runId]);
1678
1719
  useEffect(() => {
1679
1720
  if (lastCard) return;
1680
1721
  const timer = setTimeout(() => setTimedOut(true), startTimeoutMs);
1681
1722
  return () => clearTimeout(timer);
1682
- }, [lastCard, startTimeoutMs]);
1723
+ }, [lastCard, startTimeoutMs, runId]);
1683
1724
  useEffect(() => {
1684
- var _a3, _b2, _c2, _d2;
1725
+ var _a2, _b2, _c2, _d2;
1685
1726
  setValidationError(void 0);
1686
1727
  if (!(lastCard == null ? void 0 : lastCard.id)) return;
1687
- const step2 = (_a3 = progress.step) != null ? _a3 : renderedCount;
1728
+ const step2 = (_a2 = progress.step) != null ? _a2 : renderedCount;
1688
1729
  lastScreenIndexRef.current = Math.max(0, step2 - 1);
1689
1730
  (_c2 = onEventRef.current) == null ? void 0 : _c2.call(onEventRef, {
1690
1731
  type: "turn",
@@ -1700,13 +1741,13 @@ var OnboardingFlow = ({
1700
1741
  }, [lastCard == null ? void 0 : lastCard.id]);
1701
1742
  useEffect(() => {
1702
1743
  return () => {
1703
- var _a3, _b2, _c2;
1744
+ var _a2, _b2, _c2;
1704
1745
  if (finished.current || degradedRef.current) return;
1705
1746
  reportClientEvent(reportTargetRef.current, {
1706
1747
  event_type: "dropped",
1707
1748
  session_id: sessionIdRef.current,
1708
1749
  screen_index: lastScreenIndexRef.current >= 0 ? lastScreenIndexRef.current : void 0,
1709
- device: (_a3 = clientContextRef.current) == null ? void 0 : _a3.device,
1750
+ device: (_a2 = clientContextRef.current) == null ? void 0 : _a2.device,
1710
1751
  user_context: (_b2 = clientContextRef.current) == null ? void 0 : _b2.userContext,
1711
1752
  user_id: (_c2 = clientContextRef.current) == null ? void 0 : _c2.userId
1712
1753
  });
@@ -1714,17 +1755,17 @@ var OnboardingFlow = ({
1714
1755
  }, []);
1715
1756
  const restartThread = useCallback(() => {
1716
1757
  setTimedOut(false);
1717
- started.current = false;
1718
1758
  errored.current = false;
1759
+ setRunId((n) => n + 1);
1719
1760
  reset();
1720
1761
  }, [reset]);
1721
1762
  useEffect(() => {
1722
- var _a3, _b2, _c2, _d2, _e2, _f2, _g;
1763
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g;
1723
1764
  if (errored.current) return;
1724
1765
  if (!error && !timedOut) return;
1725
1766
  errored.current = true;
1726
1767
  const reason = error ? "backend" : "timeout";
1727
- (_a3 = onEventRef.current) == null ? void 0 : _a3.call(onEventRef, { type: "error", reason });
1768
+ (_a2 = onEventRef.current) == null ? void 0 : _a2.call(onEventRef, { type: "error", reason });
1728
1769
  attempts.current += 1;
1729
1770
  if (attempts.current <= maxRetries) {
1730
1771
  (_b2 = onEventRef.current) == null ? void 0 : _b2.call(onEventRef, { type: "retry", reason, attempt: attempts.current });
@@ -1760,6 +1801,36 @@ var OnboardingFlow = ({
1760
1801
  if (isLoading) return;
1761
1802
  sendMessage(SKIP_ONE_SENTINEL);
1762
1803
  }, [isLoading, sendMessage]);
1804
+ const emitPermissionStage = useCallback(
1805
+ (permission, stage, status) => {
1806
+ var _a2, _b2, _c2, _d2;
1807
+ (_a2 = onEventRef.current) == null ? void 0 : _a2.call(onEventRef, { type: "permission", permission, stage, status });
1808
+ reportClientEvent(reportTargetRef.current, {
1809
+ event_type: "app_event",
1810
+ session_id: sessionIdRef.current,
1811
+ question_key: permissionEventName(stage),
1812
+ component: PERMISSION_CARD_NAME,
1813
+ screen_index: lastScreenIndexRef.current >= 0 ? lastScreenIndexRef.current : void 0,
1814
+ meta: JSON.stringify(permissionEventProps(permission, status)),
1815
+ device: (_b2 = clientContextRef.current) == null ? void 0 : _b2.device,
1816
+ user_context: (_c2 = clientContextRef.current) == null ? void 0 : _c2.userContext,
1817
+ user_id: (_d2 = clientContextRef.current) == null ? void 0 : _d2.userId
1818
+ });
1819
+ },
1820
+ []
1821
+ );
1822
+ const settlePermission = useCallback(
1823
+ (id, screen, outcome) => {
1824
+ var _a2, _b2;
1825
+ setLocallySettledPermissions((prev) => prev.includes(id) ? prev : [...prev, id]);
1826
+ (_a2 = onPermissionSettledRef.current) == null ? void 0 : _a2.call(onPermissionSettledRef, id, outcome);
1827
+ try {
1828
+ (_b2 = screen.onResult) == null ? void 0 : _b2.call(screen, screen.permission, outcome);
1829
+ } catch {
1830
+ }
1831
+ },
1832
+ []
1833
+ );
1763
1834
  const previewOnSelect = useCallback((value) => {
1764
1835
  const target = reportTargetRef.current;
1765
1836
  if (!(target == null ? void 0 : target.serverUrl)) return;
@@ -1777,26 +1848,26 @@ var OnboardingFlow = ({
1777
1848
  }, []);
1778
1849
  const wrappedActions = useCallback(
1779
1850
  (messageId) => {
1780
- var _a3;
1851
+ var _a2;
1781
1852
  const base = makeActions(messageId);
1782
1853
  const validators2 = validatorsRef.current;
1783
- 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;
1854
+ const validator = (_a2 = progress.slot_id ? validators2 == null ? void 0 : validators2[progress.slot_id] : void 0) != null ? _a2 : progress.key ? validators2 == null ? void 0 : validators2[progress.key] : void 0;
1784
1855
  if (!validator) return base;
1785
1856
  const out = { ...base };
1786
- for (const name2 of ANSWER_CALLBACKS) {
1787
- const original = base[name2];
1857
+ for (const name of ANSWER_CALLBACKS) {
1858
+ const original = base[name];
1788
1859
  if (!original) continue;
1789
- out[name2] = (...args) => {
1860
+ out[name] = (...args) => {
1790
1861
  const value = args[0];
1791
1862
  if (typeof value !== "string") return original(...args);
1792
1863
  setValidating(true);
1793
1864
  validator(value).then((res) => {
1794
- var _a4;
1865
+ var _a3;
1795
1866
  if (res.ok) {
1796
1867
  setValidationError(void 0);
1797
1868
  original(...args);
1798
1869
  } else {
1799
- setValidationError((_a4 = res.error) != null ? _a4 : "That value isn't available.");
1870
+ setValidationError((_a3 = res.error) != null ? _a3 : "That value isn't available.");
1800
1871
  }
1801
1872
  }).catch(() => {
1802
1873
  original(...args);
@@ -1827,9 +1898,39 @@ var OnboardingFlow = ({
1827
1898
  if (!lastCard || !response) {
1828
1899
  return /* @__PURE__ */ jsx(LoadingScreen, { title: c.startingTitle, hint: c.startingHint });
1829
1900
  }
1830
- const step = (_a2 = progress.step) != null ? _a2 : renderedCount;
1901
+ const step = (_a = progress.step) != null ? _a : renderedCount;
1831
1902
  const total = (_b = progress.total) != null ? _b : approxScreens;
1832
1903
  const isTerminal = response.action === "render" && response.component === "StatusCard";
1904
+ const duePermission = permissionsPending ? void 0 : selectDuePermissionScreen(
1905
+ permissionScreens,
1906
+ settledPermissions ? [...settledPermissions, ...locallySettledPermissions] : locallySettledPermissions,
1907
+ { cardIndex: renderedCount - 1, isTerminal }
1908
+ );
1909
+ if (duePermission) {
1910
+ const { screen, id } = duePermission;
1911
+ const copy2 = resolvePermissionCopy(screen.permission, screen.copy);
1912
+ return /* @__PURE__ */ jsx(OnboardingScaffold, { step, approxScreens: total, children: /* @__PURE__ */ jsx(CardHandoff, { transitionKey: `permission:${id}`, variant: "spring", children: /* @__PURE__ */ jsx(
1913
+ PermissionCardView,
1914
+ {
1915
+ permission: screen.permission,
1916
+ title: copy2.title,
1917
+ message: copy2.message,
1918
+ primaryLabel: copy2.primaryLabel,
1919
+ secondaryLabel: copy2.secondaryLabel,
1920
+ blockedTitle: copy2.blockedTitle,
1921
+ blockedMessage: copy2.blockedMessage,
1922
+ settingsLabel: copy2.settingsLabel,
1923
+ continueLabel: copy2.continueLabel,
1924
+ illustration: screen.illustration,
1925
+ request: screen.request,
1926
+ getStatus: screen.getStatus,
1927
+ openSettings: screen.openSettings,
1928
+ onStage: (stage, status) => emitPermissionStage(screen.permission, stage, status),
1929
+ onSettled: (outcome) => settlePermission(id, screen, outcome)
1930
+ },
1931
+ id
1932
+ ) }) });
1933
+ }
1833
1934
  if (isTerminal) {
1834
1935
  const props = (_c = response.props) != null ? _c : {};
1835
1936
  return /* @__PURE__ */ jsx(OnboardingScaffold, { step, complete: true, approxScreens: total, children: /* @__PURE__ */ jsx(
@@ -1888,8 +1989,8 @@ var OnboardingFlow = ({
1888
1989
  }
1889
1990
  );
1890
1991
  };
1891
- var easeWire4 = Easing.bezier(...WIRE_BEZIER);
1892
- var schema = z.object({
1992
+ var easeWire5 = Easing.bezier(...WIRE_BEZIER);
1993
+ var schema2 = z.object({
1893
1994
  title: z.string().describe("Question or section header, e.g. 'Which season?'"),
1894
1995
  chips: z.array(z.string()).min(1).describe("List of option labels shown as chips, e.g. ['Spring','Summer','Autumn','Winter']"),
1895
1996
  multiSelect: z.boolean().optional().describe("Allow multiple chips selected at once, default true"),
@@ -1920,7 +2021,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
1920
2021
  const anim = Animated.timing(fillT, {
1921
2022
  toValue: isSelected ? 1 : 0,
1922
2023
  duration: scaledMs(stateChangeDuration(reduced, CHIP_FILL_MS)),
1923
- easing: easeWire4,
2024
+ easing: easeWire5,
1924
2025
  useNativeDriver: true
1925
2026
  });
1926
2027
  anim.start();
@@ -1960,7 +2061,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
1960
2061
  Animated.View,
1961
2062
  {
1962
2063
  style: [
1963
- styles10.chip,
2064
+ styles11.chip,
1964
2065
  {
1965
2066
  borderRadius: t.radius.full,
1966
2067
  paddingHorizontal: t.spacing.md,
@@ -1977,7 +2078,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
1977
2078
  pointerEvents: "none",
1978
2079
  style: [
1979
2080
  StyleSheet.absoluteFill,
1980
- styles10.fillOverlay,
2081
+ styles11.fillOverlay,
1981
2082
  {
1982
2083
  borderRadius: t.radius.full,
1983
2084
  borderColor: t.colors.primary,
@@ -1991,7 +2092,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
1991
2092
  Animated.Text,
1992
2093
  {
1993
2094
  style: [
1994
- styles10.check,
2095
+ styles11.check,
1995
2096
  { color: t.colors.onPrimary, opacity: checkT, transform: [{ scale: checkScale }] }
1996
2097
  ],
1997
2098
  children: "\u2713"
@@ -2002,7 +2103,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
2002
2103
  {
2003
2104
  style: [
2004
2105
  captionStyle(t.fonts),
2005
- styles10.chipLabel,
2106
+ styles11.chipLabel,
2006
2107
  { color: isSelected ? t.colors.onPrimary : t.colors.textMuted }
2007
2108
  ],
2008
2109
  children: chip
@@ -2014,7 +2115,7 @@ var _ChipItem = ({ chip, isSelected, multiSelect, onToggle }) => {
2014
2115
  }
2015
2116
  );
2016
2117
  };
2017
- var ChipItem = React18.memo(_ChipItem);
2118
+ var ChipItem = React19.memo(_ChipItem);
2018
2119
  var _ChipSelectCard = ({
2019
2120
  title,
2020
2121
  chips,
@@ -2064,7 +2165,7 @@ var _ChipSelectCard = ({
2064
2165
  disabled: selected.length === 0 || submitted
2065
2166
  }
2066
2167
  ),
2067
- children: /* @__PURE__ */ jsx(View, { style: [styles10.chipsRow, { gap: t.spacing.sm + t.spacing.xs }], children: chips.map((chip) => /* @__PURE__ */ jsx(
2168
+ children: /* @__PURE__ */ jsx(View, { style: [styles11.chipsRow, { gap: t.spacing.sm + t.spacing.xs }], children: chips.map((chip) => /* @__PURE__ */ jsx(
2068
2169
  ChipItem,
2069
2170
  {
2070
2171
  chip,
@@ -2080,18 +2181,18 @@ var _ChipSelectCard = ({
2080
2181
  var ChipSelectCard = {
2081
2182
  name: "ChipSelectCard",
2082
2183
  description: "Use for compact short labels: seasons, activities, travel styles, moods, categories. Ideal for 4\u201312 single-word or two-word options. Use SelectionCard instead when options need descriptions; use CardGridSelectCard for a smaller set (2\u20136) of visual choices that each deserve an icon.",
2083
- component: React18.memo(_ChipSelectCard),
2084
- propsSchema: schema,
2184
+ component: React19.memo(_ChipSelectCard),
2185
+ propsSchema: schema2,
2085
2186
  defaultProps: { multiSelect: true, submitLabel: "Continue" }
2086
2187
  };
2087
- var styles10 = StyleSheet.create({
2188
+ var styles11 = StyleSheet.create({
2088
2189
  chipsRow: { flexDirection: "row", flexWrap: "wrap" },
2089
2190
  chip: { borderWidth: 1.5, flexDirection: "row", alignItems: "center", gap: 6, overflow: "hidden" },
2090
2191
  fillOverlay: { borderWidth: 1.5 },
2091
2192
  chipLabel: { fontWeight: "600" },
2092
2193
  check: { fontSize: 13, fontWeight: "800", lineHeight: 15 }
2093
2194
  });
2094
- var schema2 = z.object({
2195
+ var schema3 = z.object({
2095
2196
  label: z.string().describe("Input field label / the question being asked"),
2096
2197
  hint: z.string().optional().describe(
2097
2198
  "One short line under the question giving context: what the answer is used for or why you ask. Add it whenever the question alone might be unclear."
@@ -2116,7 +2217,7 @@ var _TextInputCard = ({
2116
2217
  lines = 6
2117
2218
  }) => {
2118
2219
  const t = useOnboardingTheme();
2119
- const styles17 = useMemo(() => makeStyles3(t), [t]);
2220
+ const styles18 = useMemo(() => makeStyles3(t), [t]);
2120
2221
  const { height: screenHeight } = useWindowDimensions();
2121
2222
  const [value, setValue] = useState("");
2122
2223
  const [submitted, setSubmitted] = useState(false);
@@ -2143,7 +2244,7 @@ var _TextInputCard = ({
2143
2244
  disabled: !value.trim() || locked
2144
2245
  }
2145
2246
  ),
2146
- children: /* @__PURE__ */ jsxs(View, { style: styles17.row, children: [
2247
+ children: /* @__PURE__ */ jsxs(View, { style: styles18.row, children: [
2147
2248
  /* @__PURE__ */ jsx(
2148
2249
  TextInput,
2149
2250
  {
@@ -2157,7 +2258,7 @@ var _TextInputCard = ({
2157
2258
  textAlignVertical: multiline ? "top" : "center",
2158
2259
  style: [
2159
2260
  bodyStyle(t.fonts),
2160
- styles17.input,
2261
+ styles18.input,
2161
2262
  {
2162
2263
  color: t.colors.text,
2163
2264
  backgroundColor: t.colors.surface,
@@ -2177,8 +2278,8 @@ var _TextInputCard = ({
2177
2278
  var TextInputCard = {
2178
2279
  name: "TextInputCard",
2179
2280
  description: "Use when the user needs to type a free-text answer: an open-ended goal, notes, feedback, a name, a destination, a search query. Multi-line by default (great for open-ended goals); set multiline:false for a short single-line field like a name. Use NumberStepperCard for numeric ranges with known bounds.",
2180
- component: React18.memo(_TextInputCard),
2181
- propsSchema: schema2,
2281
+ component: React19.memo(_TextInputCard),
2282
+ propsSchema: schema3,
2182
2283
  defaultProps: { submitLabel: "Submit", multiline: true, lines: 6 }
2183
2284
  };
2184
2285
  function makeStyles3(t) {
@@ -2322,32 +2423,32 @@ var WIRE_ICON_GLYPHS = {
2322
2423
  other: { family: "MaterialCommunityIcons", name: "dots-horizontal-circle" }
2323
2424
  };
2324
2425
  var WIRE_ICON_NAMES = Object.keys(WIRE_ICON_GLYPHS).sort();
2325
- var lookupIconGlyph = (name2) => {
2326
- if (!name2) return void 0;
2327
- if (!Object.prototype.hasOwnProperty.call(WIRE_ICON_GLYPHS, name2)) return void 0;
2328
- return WIRE_ICON_GLYPHS[name2];
2426
+ var lookupIconGlyph = (name) => {
2427
+ if (!name) return void 0;
2428
+ if (!Object.prototype.hasOwnProperty.call(WIRE_ICON_GLYPHS, name)) return void 0;
2429
+ return WIRE_ICON_GLYPHS[name];
2329
2430
  };
2330
- var _WireIcon = ({ name: name2, size = 20, color, requireModule }) => {
2331
- const hostIcon = useHostIcon(name2);
2431
+ var _WireIcon = ({ name, size = 20, color, requireModule }) => {
2432
+ const hostIcon = useHostIcon(name);
2332
2433
  if (hostIcon) {
2333
2434
  return /* @__PURE__ */ jsx(
2334
2435
  View,
2335
2436
  {
2336
- style: styles11.decorative,
2437
+ style: styles12.decorative,
2337
2438
  accessible: false,
2338
2439
  importantForAccessibility: "no-hide-descendants",
2339
2440
  children: hostIcon
2340
2441
  }
2341
2442
  );
2342
2443
  }
2343
- const glyph = lookupIconGlyph(name2);
2444
+ const glyph = lookupIconGlyph(name);
2344
2445
  if (!glyph) return null;
2345
2446
  const Family = resolveIconFamily(glyph.family, requireModule);
2346
2447
  if (!Family) return null;
2347
2448
  return /* @__PURE__ */ jsx(
2348
2449
  View,
2349
2450
  {
2350
- style: styles11.decorative,
2451
+ style: styles12.decorative,
2351
2452
  accessible: false,
2352
2453
  importantForAccessibility: "no-hide-descendants",
2353
2454
  children: /* @__PURE__ */ jsx(
@@ -2362,9 +2463,9 @@ var _WireIcon = ({ name: name2, size = 20, color, requireModule }) => {
2362
2463
  }
2363
2464
  );
2364
2465
  };
2365
- var WireIcon = React18.memo(_WireIcon);
2466
+ var WireIcon = React19.memo(_WireIcon);
2366
2467
  WireIcon.displayName = "WireIcon";
2367
- var styles11 = StyleSheet.create({
2468
+ var styles12 = StyleSheet.create({
2368
2469
  // No size/margin of its own: the glyph decides its footprint, so an absent icon and a
2369
2470
  // present one differ by exactly the glyph — never by a wrapper.
2370
2471
  decorative: {}
@@ -2378,8 +2479,8 @@ var optionObjectSchema = z.object({
2378
2479
  var coerceOptions = (arr) => Array.isArray(arr) ? arr.map((item) => typeof item === "string" ? { value: item, label: item } : item) : arr;
2379
2480
  var optionsField = (description) => z.preprocess(coerceOptions, z.array(optionObjectSchema).min(1)).describe(description);
2380
2481
  var normalizeOptions = (options) => options.map((opt) => typeof opt === "string" ? { value: opt, label: opt } : opt);
2381
- var easeWire5 = Easing.bezier(...WIRE_BEZIER);
2382
- var schema3 = z.object({
2482
+ var easeWire6 = Easing.bezier(...WIRE_BEZIER);
2483
+ var schema4 = z.object({
2383
2484
  title: z.string().describe("Question or prompt for the user"),
2384
2485
  options: optionsField("List of choices"),
2385
2486
  submitLabel: z.string().optional().describe("Submit button label, default: Continue"),
@@ -2409,7 +2510,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
2409
2510
  const anim = Animated.timing(selectT, {
2410
2511
  toValue: isSelected ? 1 : 0,
2411
2512
  duration: scaledMs(stateChangeDuration(reduced, SELECT_FILL_MS)),
2412
- easing: easeWire5,
2513
+ easing: easeWire6,
2413
2514
  useNativeDriver: true
2414
2515
  });
2415
2516
  anim.start();
@@ -2449,7 +2550,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
2449
2550
  Animated.View,
2450
2551
  {
2451
2552
  style: [
2452
- styles12.option,
2553
+ styles13.option,
2453
2554
  {
2454
2555
  padding: t.spacing.md,
2455
2556
  borderRadius: t.radius.md,
@@ -2466,7 +2567,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
2466
2567
  pointerEvents: "none",
2467
2568
  style: [
2468
2569
  StyleSheet.absoluteFill,
2469
- styles12.selectedOverlay,
2570
+ styles13.selectedOverlay,
2470
2571
  {
2471
2572
  borderRadius: t.radius.md,
2472
2573
  borderColor: t.colors.primary,
@@ -2480,7 +2581,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
2480
2581
  View,
2481
2582
  {
2482
2583
  style: [
2483
- styles12.indicator,
2584
+ styles13.indicator,
2484
2585
  { borderRadius: t.radius.full },
2485
2586
  isSelected ? { borderColor: t.colors.primary, backgroundColor: t.colors.primary } : { borderColor: t.colors.borderStrong, backgroundColor: "transparent" }
2486
2587
  ],
@@ -2488,7 +2589,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
2488
2589
  Animated.Text,
2489
2590
  {
2490
2591
  style: [
2491
- styles12.check,
2592
+ styles13.check,
2492
2593
  { color: t.colors.onPrimary, opacity: checkT, transform: [{ scale: checkScale }] }
2493
2594
  ],
2494
2595
  children: "\u2713"
@@ -2504,7 +2605,7 @@ var _OptionRow = ({ opt, isSelected, multiSelect, onToggle }) => {
2504
2605
  }
2505
2606
  );
2506
2607
  };
2507
- var OptionRow = React18.memo(_OptionRow);
2608
+ var OptionRow = React19.memo(_OptionRow);
2508
2609
  var _SelectionCard = ({
2509
2610
  title,
2510
2611
  options,
@@ -2514,7 +2615,7 @@ var _SelectionCard = ({
2514
2615
  onSelectionChange
2515
2616
  }) => {
2516
2617
  const t = useOnboardingTheme();
2517
- const opts = React18.useMemo(() => normalizeOptions(options), [options]);
2618
+ const opts = React19.useMemo(() => normalizeOptions(options), [options]);
2518
2619
  const [selected, setSelected] = useState([]);
2519
2620
  const [submitted, setSubmitted] = useState(false);
2520
2621
  useEffect(() => {
@@ -2565,18 +2666,18 @@ var _SelectionCard = ({
2565
2666
  var SelectionCard = {
2566
2667
  name: "SelectionCard",
2567
2668
  description: "Use for mutually exclusive (radio) or multi-select (checkbox) choices from 2\u20138 options, as a vertical list of rows. Best when options are wordy or need reading. Options may carry an optional `icon` from the vocabulary to make the list scannable. Use ChipSelectCard instead when options are short single words; use CardGridSelectCard when the options are visual and each has an obvious icon (occasions, channels, categories).",
2568
- component: React18.memo(_SelectionCard),
2569
- propsSchema: schema3,
2669
+ component: React19.memo(_SelectionCard),
2670
+ propsSchema: schema4,
2570
2671
  defaultProps: { submitLabel: "Continue", multiSelect: false }
2571
2672
  };
2572
- var styles12 = StyleSheet.create({
2673
+ var styles13 = StyleSheet.create({
2573
2674
  option: { borderWidth: 1.5, flexDirection: "row", alignItems: "center", overflow: "hidden" },
2574
2675
  selectedOverlay: { borderWidth: 1.5 },
2575
2676
  indicator: { width: 24, height: 24, borderWidth: 2, alignItems: "center", justifyContent: "center" },
2576
2677
  check: { fontSize: 13, fontWeight: "800", lineHeight: 15 }
2577
2678
  });
2578
- var easeWire6 = Easing.bezier(...WIRE_BEZIER);
2579
- var schema4 = z.object({
2679
+ var easeWire7 = Easing.bezier(...WIRE_BEZIER);
2680
+ var schema5 = z.object({
2580
2681
  title: z.string().describe("Question or prompt for the user, e.g. 'What brings you here?'"),
2581
2682
  options: optionsField(
2582
2683
  "The choices, 2-6 of them. Give EVERY option an `icon` from the vocabulary \u2014 the icon is the point of this card, and an option without one renders as a bare label next to icon-bearing neighbours. Keep labels short (1-3 words) so they fit a half-width card."
@@ -2608,7 +2709,7 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
2608
2709
  const anim = Animated.timing(selectT, {
2609
2710
  toValue: isSelected ? 1 : 0,
2610
2711
  duration: scaledMs(stateChangeDuration(reduced, SELECT_FILL_MS)),
2611
- easing: easeWire6,
2712
+ easing: easeWire7,
2612
2713
  useNativeDriver: true
2613
2714
  });
2614
2715
  anim.start();
@@ -2623,12 +2724,12 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
2623
2724
  accessibilityRole: multiSelect ? "checkbox" : "radio",
2624
2725
  accessibilityState: multiSelect ? { checked: isSelected } : { selected: isSelected },
2625
2726
  accessibilityLabel: opt.label,
2626
- style: styles13.cell,
2727
+ style: styles14.cell,
2627
2728
  children: /* @__PURE__ */ jsxs(
2628
2729
  Animated.View,
2629
2730
  {
2630
2731
  style: [
2631
- styles13.card,
2732
+ styles14.card,
2632
2733
  {
2633
2734
  padding: t.spacing.md,
2634
2735
  borderRadius: t.radius.lg,
@@ -2645,7 +2746,7 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
2645
2746
  pointerEvents: "none",
2646
2747
  style: [
2647
2748
  StyleSheet.absoluteFill,
2648
- styles13.selectedOverlay,
2749
+ styles14.selectedOverlay,
2649
2750
  {
2650
2751
  borderRadius: t.radius.lg,
2651
2752
  borderColor: t.colors.primary,
@@ -2663,7 +2764,7 @@ var _OptionCard = ({ opt, isSelected, multiSelect, onToggle }) => {
2663
2764
  }
2664
2765
  );
2665
2766
  };
2666
- var OptionCard = React18.memo(_OptionCard);
2767
+ var OptionCard = React19.memo(_OptionCard);
2667
2768
  var _CardGridSelectCard = ({
2668
2769
  title,
2669
2770
  options,
@@ -2673,7 +2774,7 @@ var _CardGridSelectCard = ({
2673
2774
  onSelectionChange
2674
2775
  }) => {
2675
2776
  const t = useOnboardingTheme();
2676
- const opts = React18.useMemo(() => normalizeOptions(options), [options]);
2777
+ const opts = React19.useMemo(() => normalizeOptions(options), [options]);
2677
2778
  const [selected, setSelected] = useState([]);
2678
2779
  const [submitted, setSubmitted] = useState(false);
2679
2780
  useEffect(() => {
@@ -2710,7 +2811,7 @@ var _CardGridSelectCard = ({
2710
2811
  disabled: selected.length === 0 || submitted
2711
2812
  }
2712
2813
  ),
2713
- children: /* @__PURE__ */ jsx(View, { style: [styles13.grid, { gap: t.spacing.sm }], children: opts.map((opt) => /* @__PURE__ */ jsx(
2814
+ children: /* @__PURE__ */ jsx(View, { style: [styles14.grid, { gap: t.spacing.sm }], children: opts.map((opt) => /* @__PURE__ */ jsx(
2714
2815
  OptionCard,
2715
2816
  {
2716
2817
  opt,
@@ -2726,19 +2827,19 @@ var _CardGridSelectCard = ({
2726
2827
  var CardGridSelectCard = {
2727
2828
  name: "CardGridSelectCard",
2728
2829
  description: "Use for VISUAL, icon-led choices shown as a 2-column grid of tappable cards (icon on top, short label beneath). Ideal for 2\u20136 concrete options that each have an obvious icon \u2014 occasions, channels, goals, categories \u2014 e.g. 'What brings you here?' or 'Where did you hear about us?'. Multi-select by default. Every option should carry an `icon`. Use SelectionCard instead when options need descriptions or have no natural icon; use ChipSelectCard for many short word-like tags.",
2729
- component: React18.memo(_CardGridSelectCard),
2730
- propsSchema: schema4,
2830
+ component: React19.memo(_CardGridSelectCard),
2831
+ propsSchema: schema5,
2731
2832
  defaultProps: { submitLabel: "Continue", multiSelect: true }
2732
2833
  };
2733
- var styles13 = StyleSheet.create({
2834
+ var styles14 = StyleSheet.create({
2734
2835
  grid: { flexDirection: "row", flexWrap: "wrap" },
2735
2836
  // Two per row: ~47% basis leaves room for the gap, flexGrow fills the remainder exactly.
2736
2837
  cell: { flexBasis: "47%", flexGrow: 1 },
2737
2838
  card: { borderWidth: 1.5, alignItems: "flex-start", overflow: "hidden" },
2738
2839
  selectedOverlay: { borderWidth: 1.5 }
2739
2840
  });
2740
- var easeWire7 = Easing.bezier(...WIRE_BEZIER);
2741
- var schema5 = z.object({
2841
+ var easeWire8 = Easing.bezier(...WIRE_BEZIER);
2842
+ var schema6 = z.object({
2742
2843
  status: z.enum(["success", "warning", "error", "info"]).describe("Status type"),
2743
2844
  title: z.string().describe("Status title"),
2744
2845
  message: z.string().optional().describe("Supporting message"),
@@ -2753,7 +2854,7 @@ var STATUS_ICONS = {
2753
2854
  info: "\u2139"
2754
2855
  };
2755
2856
  var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSubmit }) => {
2756
- var _a2;
2857
+ var _a;
2757
2858
  const t = useOnboardingTheme();
2758
2859
  const reduced = useReducedMotion();
2759
2860
  const [submitted, setSubmitted] = useState(false);
@@ -2788,7 +2889,7 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
2788
2889
  toValue: 1,
2789
2890
  duration: scaledMs(STATUS_COPY_MS),
2790
2891
  delay: scaledMs(STATUS_COPY_STAGGER_MS),
2791
- easing: easeWire7,
2892
+ easing: easeWire8,
2792
2893
  useNativeDriver: true
2793
2894
  })
2794
2895
  ];
@@ -2810,8 +2911,8 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
2810
2911
  {
2811
2912
  align: "center",
2812
2913
  footer: ctaLabel ? /* @__PURE__ */ jsx(Button, { title: ctaLabel, onPress: handleContinue, variant: "primary", disabled: submitted }) : void 0,
2813
- children: /* @__PURE__ */ jsxs(View, { style: [styles14.center, { gap: t.spacing.sm }], children: [
2814
- /* @__PURE__ */ jsxs(View, { style: [styles14.titleRow, { gap: t.spacing.sm }], children: [
2914
+ children: /* @__PURE__ */ jsxs(View, { style: [styles15.center, { gap: t.spacing.sm }], children: [
2915
+ /* @__PURE__ */ jsxs(View, { style: [styles15.titleRow, { gap: t.spacing.sm }], children: [
2815
2916
  /* @__PURE__ */ jsx(
2816
2917
  Animated.Text,
2817
2918
  {
@@ -2819,7 +2920,7 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
2819
2920
  headingStyle(t.fonts),
2820
2921
  { color, opacity: popT, transform: [{ scale: popScale }] }
2821
2922
  ],
2822
- children: (_a2 = STATUS_ICONS[status]) != null ? _a2 : "\xB7"
2923
+ children: (_a = STATUS_ICONS[status]) != null ? _a : "\xB7"
2823
2924
  }
2824
2925
  ),
2825
2926
  /* @__PURE__ */ jsx(
@@ -2855,14 +2956,14 @@ var _StatusCard = ({ status, title, message, ctaLabel, onContinue, onPress, onSu
2855
2956
  var StatusCard = {
2856
2957
  name: "StatusCard",
2857
2958
  description: "Use ONLY for real outcomes: booking confirmed, data saved, action completed. NEVER for 'you just viewed X' acknowledgments. Always include ctaLabel so the user can continue after seeing the status.",
2858
- component: React18.memo(_StatusCard),
2859
- propsSchema: schema5
2959
+ component: React19.memo(_StatusCard),
2960
+ propsSchema: schema6
2860
2961
  };
2861
- var styles14 = StyleSheet.create({
2962
+ var styles15 = StyleSheet.create({
2862
2963
  center: { width: "100%", alignItems: "center", justifyContent: "center" },
2863
2964
  titleRow: { flexDirection: "row", alignItems: "center", justifyContent: "center" }
2864
2965
  });
2865
- var schema6 = z.object({
2966
+ var schema7 = z.object({
2866
2967
  label: z.string().describe("What is being counted, e.g. 'Number of days' or 'Travellers'"),
2867
2968
  min: z.number().optional().describe("Minimum value, default 1"),
2868
2969
  max: z.number().optional().describe("Maximum value, default 30"),
@@ -2883,7 +2984,7 @@ var _NumberStepperCard = ({
2883
2984
  onSubmit
2884
2985
  }) => {
2885
2986
  const t = useOnboardingTheme();
2886
- const styles17 = useMemo(() => makeStyles4(t), [t]);
2987
+ const styles18 = useMemo(() => makeStyles4(t), [t]);
2887
2988
  const safeMin = safeNum(min, 1);
2888
2989
  const safeMaxRaw = safeNum(max, 30);
2889
2990
  const safeMax = safeMaxRaw < safeMin ? safeMin : safeMaxRaw;
@@ -2907,7 +3008,7 @@ var _NumberStepperCard = ({
2907
3008
  const atMin = value <= safeMin;
2908
3009
  const atMax = value >= safeMax;
2909
3010
  const stepBtnStyle = (disabled) => [
2910
- styles17.stepBtn,
3011
+ styles18.stepBtn,
2911
3012
  { borderRadius: t.radius.full, backgroundColor: t.colors.background, borderColor: disabled ? t.colors.border : t.colors.primary }
2912
3013
  ];
2913
3014
  return /* @__PURE__ */ jsx(
@@ -2916,10 +3017,10 @@ var _NumberStepperCard = ({
2916
3017
  title: label,
2917
3018
  align: "center",
2918
3019
  footer: /* @__PURE__ */ jsx(Button, { title: submitLabel, onPress: handleSubmit, variant: "primary", disabled: submitted }),
2919
- children: /* @__PURE__ */ jsxs(View, { style: styles17.wrap, children: [
2920
- /* @__PURE__ */ jsxs(View, { style: [styles17.stepper, { gap: t.spacing.lg }], children: [
3020
+ children: /* @__PURE__ */ jsxs(View, { style: styles18.wrap, children: [
3021
+ /* @__PURE__ */ jsxs(View, { style: [styles18.stepper, { gap: t.spacing.lg }], children: [
2921
3022
  /* @__PURE__ */ jsx(Pressable, { onPress: atMin || submitted ? void 0 : handleDecrement, disabled: atMin || submitted, style: stepBtnStyle(atMin), children: /* @__PURE__ */ jsx(Text, { style: [headingStyle(t.fonts), { color: atMin ? t.colors.textMuted : t.colors.primary }], children: "\u2212" }) }),
2922
- /* @__PURE__ */ jsxs(View, { style: styles17.valueBox, children: [
3023
+ /* @__PURE__ */ jsxs(View, { style: styles18.valueBox, children: [
2923
3024
  /* @__PURE__ */ jsx(Text, { style: [headingStyle(t.fonts), { color: t.colors.primary }], children: String(value) }),
2924
3025
  unit ? /* @__PURE__ */ jsx(Text, { style: [captionStyle(t.fonts), { color: t.colors.textMuted }], children: unit }) : null
2925
3026
  ] }),
@@ -2933,8 +3034,8 @@ var _NumberStepperCard = ({
2933
3034
  var NumberStepperCard = {
2934
3035
  name: "NumberStepperCard",
2935
3036
  description: "Use for any bounded numeric input: days, people, portions, budget tiers, ratings. Best for ranges 1\u201399. Set unit (e.g. 'days', 'people') for clarity.",
2936
- component: React18.memo(_NumberStepperCard),
2937
- propsSchema: schema6,
3037
+ component: React19.memo(_NumberStepperCard),
3038
+ propsSchema: schema7,
2938
3039
  defaultProps: { min: 1, max: 30, defaultValue: 1, step: 1, submitLabel: "Confirm" }
2939
3040
  };
2940
3041
  function makeStyles4(t) {
@@ -2945,9 +3046,9 @@ function makeStyles4(t) {
2945
3046
  valueBox: { alignItems: "center", minWidth: 80 }
2946
3047
  });
2947
3048
  }
2948
- var easeWire8 = Easing.bezier(...WIRE_BEZIER);
2949
- var RISE_PX = 10;
2950
- var schema7 = z.object({
3049
+ var easeWire9 = Easing.bezier(...WIRE_BEZIER);
3050
+ var RISE_PX2 = 10;
3051
+ var schema8 = z.object({
2951
3052
  title: z.string().describe("Short, warm headline for the value/momentum moment"),
2952
3053
  body: z.string().optional().describe("One or two supporting lines that reflect the user's answers back and build momentum"),
2953
3054
  items: z.array(z.string()).max(4).optional().describe(
@@ -2984,7 +3085,7 @@ var _WorkItem = ({
2984
3085
  toValue: 1,
2985
3086
  duration: scaledMs(INTERSTITIAL_ITEM_MS),
2986
3087
  delay: scaledMs(interstitialItemDelay(index)),
2987
- easing: easeWire8,
3088
+ easing: easeWire9,
2988
3089
  useNativeDriver: true
2989
3090
  }),
2990
3091
  Animated.spring(checkT, {
@@ -2998,7 +3099,7 @@ var _WorkItem = ({
2998
3099
  anims.forEach((a) => a.start());
2999
3100
  return () => anims.forEach((a) => a.stop());
3000
3101
  }, [reduced, index, rowT, checkT]);
3001
- const rise = rowT.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX, 0] });
3102
+ const rise = rowT.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX2, 0] });
3002
3103
  const checkScale = checkT.interpolate({
3003
3104
  inputRange: [0, 1],
3004
3105
  outputRange: [INTERSTITIAL_CHECK_SCALE_FROM, 1]
@@ -3006,20 +3107,20 @@ var _WorkItem = ({
3006
3107
  return /* @__PURE__ */ jsxs(
3007
3108
  Animated.View,
3008
3109
  {
3009
- style: [styles15.itemRow, { gap: t.spacing.sm + t.spacing.xs, opacity: rowT, transform: [{ translateY: rise }] }],
3110
+ style: [styles16.itemRow, { gap: t.spacing.sm + t.spacing.xs, opacity: rowT, transform: [{ translateY: rise }] }],
3010
3111
  children: [
3011
3112
  /* @__PURE__ */ jsx(
3012
3113
  View,
3013
3114
  {
3014
3115
  style: [
3015
- styles15.itemBadge,
3116
+ styles16.itemBadge,
3016
3117
  { backgroundColor: t.colors.primarySoft, borderRadius: t.radius.full }
3017
3118
  ],
3018
3119
  children: /* @__PURE__ */ jsx(
3019
3120
  Animated.Text,
3020
3121
  {
3021
3122
  style: [
3022
- styles15.itemCheck,
3123
+ styles16.itemCheck,
3023
3124
  { color: t.colors.primary, opacity: checkT, transform: [{ scale: checkScale }] }
3024
3125
  ],
3025
3126
  children: "\u2713"
@@ -3027,12 +3128,12 @@ var _WorkItem = ({
3027
3128
  )
3028
3129
  }
3029
3130
  ),
3030
- /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), styles15.itemText, { color: t.colors.text }], children: text })
3131
+ /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), styles16.itemText, { color: t.colors.text }], children: text })
3031
3132
  ]
3032
3133
  }
3033
3134
  );
3034
3135
  };
3035
- var WorkItem = React18.memo(_WorkItem);
3136
+ var WorkItem = React19.memo(_WorkItem);
3036
3137
  var _InterstitialCard = ({
3037
3138
  title,
3038
3139
  body,
@@ -3069,7 +3170,7 @@ var _InterstitialCard = ({
3069
3170
  toValue: 1,
3070
3171
  duration: scaledMs(INTERSTITIAL_HEAD_MS),
3071
3172
  delay,
3072
- easing: easeWire8,
3173
+ easing: easeWire9,
3073
3174
  useNativeDriver: true
3074
3175
  });
3075
3176
  const anims = [
@@ -3082,7 +3183,7 @@ var _InterstitialCard = ({
3082
3183
  }, [reduced, artT, titleT, bodyT]);
3083
3184
  const riseStyle = (value) => ({
3084
3185
  opacity: value,
3085
- transform: [{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX, 0] }) }]
3186
+ transform: [{ translateY: value.interpolate({ inputRange: [0, 1], outputRange: [RISE_PX2, 0] }) }]
3086
3187
  });
3087
3188
  const handleContinue = useCallback(() => {
3088
3189
  if (submitted || !canAdvance) return;
@@ -3105,18 +3206,18 @@ var _InterstitialCard = ({
3105
3206
  disabled: submitted || !canAdvance
3106
3207
  }
3107
3208
  ),
3108
- children: /* @__PURE__ */ jsxs(View, { style: [styles15.center, { gap: t.spacing.md }], children: [
3109
- /* @__PURE__ */ jsx(Animated.View, { style: [styles15.fullWidth, riseStyle(artT)], children: showImage ? /* @__PURE__ */ jsx(
3209
+ children: /* @__PURE__ */ jsxs(View, { style: [styles16.center, { gap: t.spacing.md }], children: [
3210
+ /* @__PURE__ */ jsx(Animated.View, { style: [styles16.fullWidth, riseStyle(artT)], children: showImage ? /* @__PURE__ */ jsx(
3110
3211
  Image,
3111
3212
  {
3112
3213
  source: { uri: imageUrl },
3113
- style: styles15.image,
3214
+ style: styles16.image,
3114
3215
  resizeMode: "contain",
3115
3216
  onError: () => setImgFailed(true)
3116
3217
  }
3117
- ) : art ? /* @__PURE__ */ jsx(View, { style: styles15.art, children: art }) : null }),
3218
+ ) : art ? /* @__PURE__ */ jsx(View, { style: styles16.art, children: art }) : null }),
3118
3219
  /* @__PURE__ */ jsx(Animated.View, { style: riseStyle(titleT), children: /* @__PURE__ */ jsx(Text, { style: [headingStyle(t.fonts), { color: t.colors.text, textAlign: "center" }], children: title }) }),
3119
- (items == null ? void 0 : items.length) ? /* @__PURE__ */ jsx(View, { style: [styles15.items, { gap: t.spacing.md, marginTop: t.spacing.sm }], children: items.map((item, i) => /* @__PURE__ */ jsx(WorkItem, { text: item, index: i, reduced }, `${item}-${i}`)) }) : body ? /* @__PURE__ */ jsx(Animated.View, { style: riseStyle(bodyT), children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted, textAlign: "center" }], children: body }) }) : null
3220
+ (items == null ? void 0 : items.length) ? /* @__PURE__ */ jsx(View, { style: [styles16.items, { gap: t.spacing.md, marginTop: t.spacing.sm }], children: items.map((item, i) => /* @__PURE__ */ jsx(WorkItem, { text: item, index: i, reduced }, `${item}-${i}`)) }) : body ? /* @__PURE__ */ jsx(Animated.View, { style: riseStyle(bodyT), children: /* @__PURE__ */ jsx(Text, { style: [bodyStyle(t.fonts), { color: t.colors.textMuted, textAlign: "center" }], children: body }) }) : null
3120
3221
  ] })
3121
3222
  }
3122
3223
  );
@@ -3124,11 +3225,11 @@ var _InterstitialCard = ({
3124
3225
  var InterstitialCard = {
3125
3226
  name: "InterstitialCard",
3126
3227
  description: "Use ONCE mid-flow (never first, never last) as a momentum/value screen between questions \u2014 an illustration + a warm line that reflects answers back, like Duolingo/Cal-AI. NOT a question; the user just taps Continue. Set `illustration` to an app-registered artwork name. Prefer `items` (2-3 short ticked lines, each reflecting a real answer) when you have the signal. Skip it if you don't have enough signal to make the line specific.",
3127
- component: React18.memo(_InterstitialCard),
3128
- propsSchema: schema7,
3228
+ component: React19.memo(_InterstitialCard),
3229
+ propsSchema: schema8,
3129
3230
  defaultProps: { ctaLabel: "Continue", illustrationFallback: "momentum" }
3130
3231
  };
3131
- var styles15 = StyleSheet.create({
3232
+ var styles16 = StyleSheet.create({
3132
3233
  center: { width: "100%", alignItems: "center", justifyContent: "center" },
3133
3234
  fullWidth: { width: "100%", alignItems: "center" },
3134
3235
  art: { alignItems: "center", justifyContent: "center" },
@@ -3162,7 +3263,7 @@ var runtimeRequire2 = (moduleName) => {
3162
3263
  try {
3163
3264
  switch (moduleName) {
3164
3265
  case "expo-constants":
3165
- return init_Constants(), __toCommonJS(Constants_exports);
3266
+ return __require("expo-constants");
3166
3267
  case "expo-application":
3167
3268
  return __require("expo-application");
3168
3269
  default:
@@ -3187,14 +3288,14 @@ var safeInterop = (requireModule, moduleName) => {
3187
3288
  };
3188
3289
  var detectAppVersion = (requireModule = runtimeRequire2) => {
3189
3290
  try {
3190
- const constants2 = safeInterop(requireModule, "expo-constants");
3191
- if (constants2) {
3192
- const expoConfig = constants2.expoConfig;
3291
+ const constants = safeInterop(requireModule, "expo-constants");
3292
+ if (constants) {
3293
+ const expoConfig = constants.expoConfig;
3193
3294
  if (expoConfig && typeof expoConfig === "object") {
3194
3295
  const fromExpoConfig = coerceVersion(expoConfig.version);
3195
3296
  if (fromExpoConfig) return fromExpoConfig;
3196
3297
  }
3197
- const fromNative = coerceVersion(constants2.nativeAppVersion);
3298
+ const fromNative = coerceVersion(constants.nativeAppVersion);
3198
3299
  if (fromNative) return fromNative;
3199
3300
  }
3200
3301
  const application = safeInterop(requireModule, "expo-application");
@@ -3259,7 +3360,7 @@ var deriveFormFactor = (iosIdiom, width, height) => {
3259
3360
  return void 0;
3260
3361
  };
3261
3362
  var collectDeviceContext = () => {
3262
- var _a2;
3363
+ var _a;
3263
3364
  const ctx = { platform: Platform.OS };
3264
3365
  try {
3265
3366
  const version = Platform.Version;
@@ -3268,26 +3369,26 @@ var collectDeviceContext = () => {
3268
3369
  }
3269
3370
  } catch {
3270
3371
  }
3271
- let constants2 = {};
3372
+ let constants = {};
3272
3373
  try {
3273
- constants2 = (_a2 = Platform.constants) != null ? _a2 : {};
3374
+ constants = (_a = Platform.constants) != null ? _a : {};
3274
3375
  } catch {
3275
- constants2 = {};
3376
+ constants = {};
3276
3377
  }
3277
3378
  let iosIdiom;
3278
3379
  try {
3279
3380
  if (Platform.OS === "android") {
3280
- const brand = constants2.Brand;
3281
- const model = constants2.Model;
3282
- const release = constants2.Release;
3381
+ const brand = constants.Brand;
3382
+ const model = constants.Model;
3383
+ const release = constants.Release;
3283
3384
  if (typeof brand === "string" && brand) ctx.brand = brand;
3284
3385
  if (typeof model === "string" && model) ctx.model = model;
3285
3386
  if (release !== void 0 && release !== null && String(release)) {
3286
3387
  ctx.osVersion = String(release);
3287
3388
  }
3288
3389
  } else if (Platform.OS === "ios") {
3289
- const osVersion = constants2.osVersion;
3290
- const idiom = constants2.interfaceIdiom;
3390
+ const osVersion = constants.osVersion;
3391
+ const idiom = constants.interfaceIdiom;
3291
3392
  if (osVersion !== void 0 && osVersion !== null && String(osVersion)) {
3292
3393
  ctx.osVersion = String(osVersion);
3293
3394
  }
@@ -3338,11 +3439,11 @@ var provenanceRegistry = () => {
3338
3439
  };
3339
3440
  var provenanceKey = (space, scope) => `${space}:${scope != null ? scope : "default"}`;
3340
3441
  var resolveIdentity = (input) => {
3341
- var _a2;
3442
+ var _a;
3342
3443
  if (typeof input.value !== "string") return void 0;
3343
3444
  const value = input.value.trim();
3344
3445
  if (!value) return void 0;
3345
- const durable = (_a2 = input.durable) != null ? _a2 : input.source === "host";
3446
+ const durable = (_a = input.durable) != null ? _a : input.source === "host";
3346
3447
  if (input.source === "host") {
3347
3448
  provenanceRegistry().host.set(provenanceKey(input.space, input.scope), value);
3348
3449
  }
@@ -3376,8 +3477,8 @@ var startHydration = (registry, appId, storage, minted) => {
3376
3477
  if (existing) return existing;
3377
3478
  const slot = deviceIdStorageKey(appId);
3378
3479
  const degraded = () => {
3379
- var _a2;
3380
- return { value: (_a2 = registry.keys.get(appId)) != null ? _a2 : minted, durable: false };
3480
+ var _a;
3481
+ return { value: (_a = registry.keys.get(appId)) != null ? _a : minted, durable: false };
3381
3482
  };
3382
3483
  const adopted = (value) => ({ value, durable: true });
3383
3484
  let run;
@@ -3390,8 +3491,8 @@ var startHydration = (registry, appId, storage, minted) => {
3390
3491
  }
3391
3492
  return Promise.resolve(storage.setItem(slot, minted)).then(
3392
3493
  () => {
3393
- var _a2;
3394
- return adopted((_a2 = registry.keys.get(appId)) != null ? _a2 : minted);
3494
+ var _a;
3495
+ return adopted((_a = registry.keys.get(appId)) != null ? _a : minted);
3395
3496
  },
3396
3497
  degraded
3397
3498
  );
@@ -3401,17 +3502,17 @@ var startHydration = (registry, appId, storage, minted) => {
3401
3502
  }
3402
3503
  registry.pending.set(appId, run);
3403
3504
  void run.then((outcome) => {
3404
- var _a2;
3505
+ var _a;
3405
3506
  if (outcome.durable) return;
3406
- (_a2 = registry.pending) == null ? void 0 : _a2.delete(appId);
3507
+ (_a = registry.pending) == null ? void 0 : _a.delete(appId);
3407
3508
  registry.hydrating.delete(appId);
3408
3509
  });
3409
3510
  return run;
3410
3511
  };
3411
3512
  var resolveAutoDeviceKey = (opts = {}) => {
3412
- var _a2, _b;
3513
+ var _a, _b;
3413
3514
  const registry = autoDeviceKeyRegistry();
3414
- const appId = (_a2 = opts.appId) != null ? _a2 : "default";
3515
+ const appId = (_a = opts.appId) != null ? _a : "default";
3415
3516
  let id = registry.keys.get(appId);
3416
3517
  if (!id) {
3417
3518
  id = mintDeviceId();
@@ -3425,13 +3526,13 @@ var resolveAutoDeviceKey = (opts = {}) => {
3425
3526
  return (_b = registry.keys.get(appId)) != null ? _b : id;
3426
3527
  };
3427
3528
  var hydrateAutoDeviceKey = async (opts = {}) => {
3428
- var _a2, _b;
3429
- return (_b = (_a2 = await hydrateDeviceIdentity(opts)) == null ? void 0 : _a2.value) != null ? _b : resolveAutoDeviceKey(opts);
3529
+ var _a, _b;
3530
+ return (_b = (_a = await hydrateDeviceIdentity(opts)) == null ? void 0 : _a.value) != null ? _b : resolveAutoDeviceKey(opts);
3430
3531
  };
3431
3532
  var hydrateDeviceIdentity = async (opts = {}) => {
3432
- var _a2, _b, _c;
3533
+ var _a, _b, _c;
3433
3534
  const id = resolveAutoDeviceKey(opts);
3434
- const appId = (_a2 = opts.appId) != null ? _a2 : "default";
3535
+ const appId = (_a = opts.appId) != null ? _a : "default";
3435
3536
  const record = (value, durable) => resolveIdentity({ value, space: "device", source: "auto", durable, scope: appId });
3436
3537
  if (!opts.storage) return record(id, false);
3437
3538
  const registry = autoDeviceKeyRegistry();
@@ -3441,20 +3542,11 @@ var hydrateDeviceIdentity = async (opts = {}) => {
3441
3542
  return record(outcome.value, outcome.durable);
3442
3543
  };
3443
3544
  var resetAutoDeviceKeys = () => {
3444
- var _a2;
3545
+ var _a;
3445
3546
  const registry = autoDeviceKeyRegistry();
3446
3547
  registry.keys.clear();
3447
3548
  registry.hydrating.clear();
3448
- (_a2 = registry.pending) == null ? void 0 : _a2.clear();
3449
- };
3450
-
3451
- // src/utils/warnInDev.ts
3452
- var warnInDev = (message) => {
3453
- if (typeof __DEV__ !== "undefined" && __DEV__ && typeof console !== "undefined" && console.warn) {
3454
- console.warn(message);
3455
- return true;
3456
- }
3457
- return false;
3549
+ (_a = registry.pending) == null ? void 0 : _a.clear();
3458
3550
  };
3459
3551
 
3460
3552
  // src/analytics/currentSession.ts
@@ -3556,9 +3648,9 @@ var sanitizeUserId = (raw) => {
3556
3648
  };
3557
3649
  var looksLikeEmail = (value) => typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
3558
3650
  var identifyOnboarding = async (opts) => {
3559
- var _a2, _b, _c;
3651
+ var _a, _b, _c;
3560
3652
  const userId = sanitizeUserId(opts.userId);
3561
- if (!userId || !((_a2 = opts.config) == null ? void 0 : _a2.serverUrl)) return false;
3653
+ if (!userId || !((_a = opts.config) == null ? void 0 : _a.serverUrl)) return false;
3562
3654
  let contextId = ((_b = opts.contextId) == null ? void 0 : _b.trim()) || void 0;
3563
3655
  if (!contextId && opts.storage) {
3564
3656
  const key = (_c = opts.persistKey) != null ? _c : opts.appId ? sessionStorageKey(opts.appId) : void 0;
@@ -3629,11 +3721,11 @@ var clearUserContext = async (opts = {}) => {
3629
3721
  }
3630
3722
  };
3631
3723
  var activationJoinContext = (deviceKey) => {
3632
- var _a2;
3633
- return (_a2 = resolveUserContext({ deviceKey }).userContext) != null ? _a2 : {};
3724
+ var _a;
3725
+ return (_a = resolveUserContext({ deviceKey }).userContext) != null ? _a : {};
3634
3726
  };
3635
3727
  var resolveUserContext = (ctx = {}, opts = {}) => {
3636
- var _a2;
3728
+ var _a;
3637
3729
  const result = {};
3638
3730
  const bucket = {};
3639
3731
  const userId = sanitizeUserId(ctx.userId);
@@ -3643,7 +3735,7 @@ var resolveUserContext = (ctx = {}, opts = {}) => {
3643
3735
  result.deviceKey = deviceKey;
3644
3736
  bucket.device_key = deviceKey;
3645
3737
  }
3646
- const appVersion = (_a2 = cleanString(ctx.appVersion)) != null ? _a2 : cleanString(opts.autoAppVersion);
3738
+ const appVersion = (_a = cleanString(ctx.appVersion)) != null ? _a : cleanString(opts.autoAppVersion);
3647
3739
  if (appVersion) {
3648
3740
  result.appVersion = appVersion;
3649
3741
  bucket.app_version = appVersion;
@@ -3661,6 +3753,43 @@ var resolveUserContext = (ctx = {}, opts = {}) => {
3661
3753
  if (Object.keys(bucket).length > 0) result.userContext = bucket;
3662
3754
  return result;
3663
3755
  };
3756
+
3757
+ // src/permissions/permissionMemory.ts
3758
+ var permissionStorageKey = (appId) => `wireai:permissions:${appId}`;
3759
+ var readSettledPermissions = (raw, sessionId) => {
3760
+ if (!raw || !sessionId) return [];
3761
+ try {
3762
+ const parsed = JSON.parse(raw);
3763
+ if (typeof parsed !== "object" || parsed === null) return [];
3764
+ const record = parsed;
3765
+ if (record.sessionId !== sessionId || !Array.isArray(record.ids)) return [];
3766
+ return record.ids.filter((id) => typeof id === "string" && id.length > 0);
3767
+ } catch {
3768
+ return [];
3769
+ }
3770
+ };
3771
+ var loadSettledPermissions = async (storage, key, sessionId) => {
3772
+ try {
3773
+ return readSettledPermissions(await withTimeout(storage.getItem(key), READ_TIMEOUT_MS), sessionId);
3774
+ } catch {
3775
+ return [];
3776
+ }
3777
+ };
3778
+ var saveSettledPermissions = (storage, key, sessionId, ids) => {
3779
+ try {
3780
+ const record = { sessionId, ids: [...ids] };
3781
+ void storage.setItem(key, JSON.stringify(record)).catch(() => {
3782
+ });
3783
+ } catch {
3784
+ }
3785
+ };
3786
+ var clearSettledPermissions = (storage, key) => {
3787
+ try {
3788
+ void storage.removeItem(key).catch(() => {
3789
+ });
3790
+ } catch {
3791
+ }
3792
+ };
3664
3793
  var AUTO_JOIN_HYDRATION_TIMEOUT_MS = 1500;
3665
3794
  var WireOnboarding = ({
3666
3795
  config,
@@ -3685,9 +3814,10 @@ var WireOnboarding = ({
3685
3814
  retainSessionOnComplete,
3686
3815
  userContext,
3687
3816
  userId,
3688
- autoJoinKey = true
3817
+ autoJoinKey = true,
3818
+ permissionScreens
3689
3819
  }) => {
3690
- var _a2, _b, _c, _d, _e;
3820
+ var _a, _b, _c, _d, _e, _f;
3691
3821
  const boundUserId = useMemo(() => sanitizeUserId(userId), [userId]);
3692
3822
  const device = useMemo(() => {
3693
3823
  const collected = collectDeviceContext();
@@ -3729,7 +3859,7 @@ var WireOnboarding = ({
3729
3859
  clearTimeout(timer);
3730
3860
  };
3731
3861
  }, [wantsAutoJoin, autoJoinOutcome, config.appId, storage]);
3732
- const injectedJoinKey = wantsAutoJoin ? (_a2 = autoJoinOutcome == null ? void 0 : autoJoinOutcome.key) != null ? _a2 : void 0 : void 0;
3862
+ const injectedJoinKey = wantsAutoJoin ? (_a = autoJoinOutcome == null ? void 0 : autoJoinOutcome.key) != null ? _a : void 0 : void 0;
3733
3863
  const autoJoinPending = wantsAutoJoin && autoJoinOutcome === void 0;
3734
3864
  const effectiveUserContext = useMemo(
3735
3865
  () => injectedJoinKey ? { ...userContextStable, ...activationJoinContext(injectedJoinKey) } : userContextStable,
@@ -3775,6 +3905,7 @@ var WireOnboarding = ({
3775
3905
  () => storage ? null : { id: makeSessionId(), resumed: false }
3776
3906
  );
3777
3907
  const storageKey = persistKey != null ? persistKey : sessionStorageKey(config.appId);
3908
+ const permissionsKey = permissionStorageKey(config.appId);
3778
3909
  useEffect(() => {
3779
3910
  if (!storage || session) return;
3780
3911
  let cancelled = false;
@@ -3787,12 +3918,43 @@ var WireOnboarding = ({
3787
3918
  }, [storage, storageKey, sessionTtlMs, session]);
3788
3919
  const handleComplete = useCallback(
3789
3920
  (result) => {
3790
- if (storage && shouldClearOnComplete(retainSessionOnComplete)) clearPersistedSession(storage, storageKey);
3921
+ if (storage && shouldClearOnComplete(retainSessionOnComplete)) {
3922
+ clearPersistedSession(storage, storageKey);
3923
+ clearSettledPermissions(storage, permissionsKey);
3924
+ }
3791
3925
  onComplete(result);
3792
3926
  },
3793
- [storage, storageKey, retainSessionOnComplete, onComplete]
3927
+ [storage, storageKey, permissionsKey, retainSessionOnComplete, onComplete]
3794
3928
  );
3795
3929
  const sessionId = (_c = session == null ? void 0 : session.id) != null ? _c : "";
3930
+ const wantsPermissionMemory = Boolean(storage) && ((_d = permissionScreens == null ? void 0 : permissionScreens.length) != null ? _d : 0) > 0;
3931
+ const [settledPermissions, setSettledPermissions] = useState(void 0);
3932
+ useEffect(() => {
3933
+ if (!wantsPermissionMemory || !storage || !sessionId || settledPermissions !== void 0) return;
3934
+ let cancelled = false;
3935
+ void loadSettledPermissions(storage, permissionsKey, sessionId).then((ids) => {
3936
+ if (!cancelled) setSettledPermissions(ids);
3937
+ });
3938
+ return () => {
3939
+ cancelled = true;
3940
+ };
3941
+ }, [wantsPermissionMemory, storage, permissionsKey, sessionId, settledPermissions]);
3942
+ const settledPermissionsRef = useRef(void 0);
3943
+ settledPermissionsRef.current = settledPermissions;
3944
+ const handlePermissionSettled = useCallback(
3945
+ (id) => {
3946
+ var _a2;
3947
+ const current = (_a2 = settledPermissionsRef.current) != null ? _a2 : [];
3948
+ if (current.includes(id)) return;
3949
+ const next = [...current, id];
3950
+ settledPermissionsRef.current = next;
3951
+ setSettledPermissions(next);
3952
+ if (storage && wantsPermissionMemory && sessionId) {
3953
+ saveSettledPermissions(storage, permissionsKey, sessionId, next);
3954
+ }
3955
+ },
3956
+ [storage, wantsPermissionMemory, permissionsKey, sessionId]
3957
+ );
3796
3958
  const startupUserIdRef = useRef(boundUserId);
3797
3959
  const metadataKey = config.metadata ? JSON.stringify(config.metadata) : "";
3798
3960
  const metadataStable = useMemo(() => metadataKey ? JSON.parse(metadataKey) : void 0, [metadataKey]);
@@ -3853,8 +4015,8 @@ var WireOnboarding = ({
3853
4015
  return /* @__PURE__ */ jsx(OnboardingThemeProvider, { theme, children: /* @__PURE__ */ jsx(
3854
4016
  LoadingScreen,
3855
4017
  {
3856
- title: (_d = copy == null ? void 0 : copy.restoringTitle) != null ? _d : DEFAULT_COPY.restoringTitle,
3857
- hint: (_e = copy == null ? void 0 : copy.restoringHint) != null ? _e : DEFAULT_COPY.restoringHint
4018
+ title: (_e = copy == null ? void 0 : copy.restoringTitle) != null ? _e : DEFAULT_COPY.restoringTitle,
4019
+ hint: (_f = copy == null ? void 0 : copy.restoringHint) != null ? _f : DEFAULT_COPY.restoringHint
3858
4020
  }
3859
4021
  ) });
3860
4022
  }
@@ -3875,7 +4037,11 @@ var WireOnboarding = ({
3875
4037
  reportTarget,
3876
4038
  sessionId,
3877
4039
  resumed: session.resumed,
3878
- clientContext
4040
+ clientContext,
4041
+ permissionScreens,
4042
+ settledPermissions,
4043
+ permissionsPending: wantsPermissionMemory && settledPermissions === void 0,
4044
+ onPermissionSettled: handlePermissionSettled
3879
4045
  }
3880
4046
  ) }) }) }) });
3881
4047
  };
@@ -3892,7 +4058,7 @@ function DemoOnboarding({
3892
4058
  const [open, setOpen] = useState(false);
3893
4059
  const [runId, setRunId] = useState(0);
3894
4060
  const t = useMemo(() => mergeTheme(theme != null ? theme : {}), [theme]);
3895
- const styles17 = useMemo(() => makeStyles5(t), [t]);
4061
+ const styles18 = useMemo(() => makeStyles5(t), [t]);
3896
4062
  const openDemo = useCallback(() => {
3897
4063
  setRunId((n) => n + 1);
3898
4064
  setOpen(true);
@@ -3906,7 +4072,7 @@ function DemoOnboarding({
3906
4072
  [onComplete]
3907
4073
  );
3908
4074
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3909
- renderTrigger ? renderTrigger(openDemo) : /* @__PURE__ */ jsx(Pressable, { onPress: openDemo, style: styles17.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles17.triggerText, children: label }) }),
4075
+ renderTrigger ? renderTrigger(openDemo) : /* @__PURE__ */ jsx(Pressable, { onPress: openDemo, style: styles18.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles18.triggerText, children: label }) }),
3910
4076
  /* @__PURE__ */ jsx(
3911
4077
  Modal,
3912
4078
  {
@@ -3914,7 +4080,7 @@ function DemoOnboarding({
3914
4080
  animationType: "slide",
3915
4081
  presentationStyle: "fullScreen",
3916
4082
  onRequestClose: close,
3917
- children: /* @__PURE__ */ jsx(View, { style: styles17.modal, children: config ? /* @__PURE__ */ jsx(
4083
+ children: /* @__PURE__ */ jsx(View, { style: styles18.modal, children: config ? /* @__PURE__ */ jsx(
3918
4084
  WireOnboarding,
3919
4085
  {
3920
4086
  config,
@@ -3927,10 +4093,10 @@ function DemoOnboarding({
3927
4093
  onError: close
3928
4094
  },
3929
4095
  runId
3930
- ) : /* @__PURE__ */ jsxs(View, { style: styles17.notice, children: [
3931
- /* @__PURE__ */ jsx(Text, { style: styles17.noticeTitle, children: "Wire AI not configured" }),
3932
- /* @__PURE__ */ jsx(Text, { style: styles17.noticeBody, children: "Set the Wire AI key + server URL (e.g. via wireConfigFromEnv) to demo the AI onboarding here." }),
3933
- /* @__PURE__ */ jsx(Pressable, { onPress: close, style: styles17.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles17.triggerText, children: "Close" }) })
4096
+ ) : /* @__PURE__ */ jsxs(View, { style: styles18.notice, children: [
4097
+ /* @__PURE__ */ jsx(Text, { style: styles18.noticeTitle, children: "Wire AI not configured" }),
4098
+ /* @__PURE__ */ jsx(Text, { style: styles18.noticeBody, children: "Set the Wire AI key + server URL (e.g. via wireConfigFromEnv) to demo the AI onboarding here." }),
4099
+ /* @__PURE__ */ jsx(Pressable, { onPress: close, style: styles18.trigger, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles18.triggerText, children: "Close" }) })
3934
4100
  ] }) })
3935
4101
  }
3936
4102
  )
@@ -4080,25 +4246,25 @@ var _CenteredModal = forwardRef(
4080
4246
  /* @__PURE__ */ jsx(
4081
4247
  Animated.View,
4082
4248
  {
4083
- style: [styles16.backdrop, { opacity: backdropOpacity }],
4249
+ style: [styles17.backdrop, { opacity: backdropOpacity }],
4084
4250
  pointerEvents: "none"
4085
4251
  }
4086
4252
  ),
4087
4253
  /* @__PURE__ */ jsx(
4088
4254
  Pressable,
4089
4255
  {
4090
- style: styles16.fill,
4256
+ style: styles17.fill,
4091
4257
  onPress: onBackdrop,
4092
4258
  accessibilityRole: "button",
4093
4259
  accessibilityLabel: "Dismiss",
4094
- children: /* @__PURE__ */ jsx(SafeAreaView, { style: styles16.center, pointerEvents: "box-none", children: /* @__PURE__ */ jsx(Pressable, { onPress: () => {
4095
- }, style: styles16.cardWrap, children: /* @__PURE__ */ jsx(
4260
+ children: /* @__PURE__ */ jsx(SafeAreaView, { style: styles17.center, pointerEvents: "box-none", children: /* @__PURE__ */ jsx(Pressable, { onPress: () => {
4261
+ }, style: styles17.cardWrap, children: /* @__PURE__ */ jsx(
4096
4262
  Animated.View,
4097
4263
  {
4098
4264
  accessibilityViewIsModal: true,
4099
4265
  accessibilityRole: "alert",
4100
4266
  style: [
4101
- styles16.card,
4267
+ styles17.card,
4102
4268
  {
4103
4269
  backgroundColor: theme.colors.surface,
4104
4270
  borderRadius: theme.radius.lg,
@@ -4119,8 +4285,8 @@ var _CenteredModal = forwardRef(
4119
4285
  }
4120
4286
  );
4121
4287
  _CenteredModal.displayName = "CenteredModal";
4122
- var CenteredModal = React18.memo(_CenteredModal);
4123
- var styles16 = StyleSheet.create({
4288
+ var CenteredModal = React19.memo(_CenteredModal);
4289
+ var styles17 = StyleSheet.create({
4124
4290
  fill: { flex: 1 },
4125
4291
  backdrop: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "#000" },
4126
4292
  center: { flex: 1, alignItems: "center", justifyContent: "center", padding: 24 },
@@ -4153,10 +4319,10 @@ var readEnabled = (raw) => {
4153
4319
  return { enabled: true };
4154
4320
  };
4155
4321
  var parseWireFeatures = (raw) => {
4156
- var _a2;
4322
+ var _a;
4157
4323
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return defaultWireFeatures;
4158
4324
  const src = raw;
4159
- const modeRaw = (_a2 = src.onboarding) == null ? void 0 : _a2.mode;
4325
+ const modeRaw = (_a = src.onboarding) == null ? void 0 : _a.mode;
4160
4326
  const mode = typeof modeRaw === "string" && VALID_MODES.includes(modeRaw) ? modeRaw : "ai";
4161
4327
  return {
4162
4328
  coachmarks: readEnabled(src.coachmarks),
@@ -4213,10 +4379,10 @@ var writeCachedFeatures = (storage, key, features) => {
4213
4379
  // src/features/fetchWireFeatures.ts
4214
4380
  var DEFAULT_TIMEOUT_MS = 4e3;
4215
4381
  var failOpen = async (storage, key) => {
4216
- var _a2;
4382
+ var _a;
4217
4383
  if (!storage) return defaultWireFeatures;
4218
4384
  const cached2 = await readCachedFeatures(storage, key);
4219
- return (_a2 = cached2 == null ? void 0 : cached2.features) != null ? _a2 : defaultWireFeatures;
4385
+ return (_a = cached2 == null ? void 0 : cached2.features) != null ? _a : defaultWireFeatures;
4220
4386
  };
4221
4387
  var fetchWithTimeout = async (url, apiKey, timeoutMs) => {
4222
4388
  const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
@@ -4275,7 +4441,7 @@ var useWireFeatures = (config) => {
4275
4441
  return flags;
4276
4442
  };
4277
4443
  var CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.context");
4278
- var globalObj = global;
4444
+ var globalObj = globalThis;
4279
4445
  if (!globalObj[CONTEXT_SYMBOL]) {
4280
4446
  globalObj[CONTEXT_SYMBOL] = createContext(null);
4281
4447
  }
@@ -4293,11 +4459,11 @@ var WireFeaturesProvider = ({
4293
4459
  WireFeaturesProvider.displayName = "WireFeaturesProvider";
4294
4460
  var useWireFeaturesContext = () => useContext(WireFeaturesContext);
4295
4461
  var useResolvedFeatures = (options) => {
4296
- var _a2, _b, _c;
4462
+ var _a, _b, _c;
4297
4463
  const ctx = useWireFeaturesContext();
4298
4464
  const shouldFetch = !(options == null ? void 0 : options.flags) && ctx == null;
4299
4465
  const fetched = useWireFeatures(shouldFetch ? options == null ? void 0 : options.config : void 0);
4300
- return (_c = (_b = (_a2 = options == null ? void 0 : options.flags) != null ? _a2 : ctx) != null ? _b : fetched) != null ? _c : defaultWireFeatures;
4466
+ return (_c = (_b = (_a = options == null ? void 0 : options.flags) != null ? _a : ctx) != null ? _b : fetched) != null ? _c : defaultWireFeatures;
4301
4467
  };
4302
4468
 
4303
4469
  // src/config/wireConfigFromEnv.ts
@@ -4307,8 +4473,8 @@ var WIRE_ENV_VARS = [
4307
4473
  "EXPO_PUBLIC_WIREAI_APP_ID"
4308
4474
  ];
4309
4475
  var wireConfigFromEnv = (overrides) => {
4310
- var _a2, _b, _c, _d, _e;
4311
- const apiKey = (_a2 = overrides == null ? void 0 : overrides.apiKey) != null ? _a2 : process.env.EXPO_PUBLIC_WIREAI_API_KEY;
4476
+ var _a, _b, _c, _d, _e;
4477
+ const apiKey = (_a = overrides == null ? void 0 : overrides.apiKey) != null ? _a : process.env.EXPO_PUBLIC_WIREAI_API_KEY;
4312
4478
  const serverUrl = (_b = overrides == null ? void 0 : overrides.serverUrl) != null ? _b : process.env.EXPO_PUBLIC_WIREAI_SERVER_URL;
4313
4479
  const appId = (_d = (_c = overrides == null ? void 0 : overrides.appId) != null ? _c : process.env.EXPO_PUBLIC_WIREAI_APP_ID) != null ? _d : "default";
4314
4480
  if (!apiKey || !serverUrl) {
@@ -4333,10 +4499,10 @@ var wireConfigFromEnv = (overrides) => {
4333
4499
 
4334
4500
  // src/config/onboardingFlag.ts
4335
4501
  var isOnboardingEnabled = (opts) => {
4336
- var _a2;
4502
+ var _a;
4337
4503
  const transportPresent = wireConfigFromEnv(opts == null ? void 0 : opts.config) !== null;
4338
4504
  if (!transportPresent) return false;
4339
- return (_a2 = opts == null ? void 0 : opts.remote) != null ? _a2 : true;
4505
+ return (_a = opts == null ? void 0 : opts.remote) != null ? _a : true;
4340
4506
  };
4341
4507
 
4342
4508
  // src/analytics/analyticsEvent.ts
@@ -4371,6 +4537,11 @@ var toAnalyticsEvent = (event) => {
4371
4537
  };
4372
4538
  case "fallback":
4373
4539
  return { name: WIRE_ONBOARDING_EVENTS.fallback, params: { reason: event.reason } };
4540
+ case "permission":
4541
+ return {
4542
+ name: permissionEventName(event.stage),
4543
+ params: permissionEventProps(event.permission, event.status)
4544
+ };
4374
4545
  default: {
4375
4546
  const _exhaustive = event;
4376
4547
  return _exhaustive;
@@ -4426,9 +4597,9 @@ var resetActivationRevalidation = () => {
4426
4597
  // src/activation/wireActivation.ts
4427
4598
  var clean = cleanString;
4428
4599
  var createWireActivation = (config) => {
4429
- var _a2, _b;
4600
+ var _a, _b;
4430
4601
  const target = { serverUrl: config.serverUrl, apiKey: config.apiKey };
4431
- const explicitDeviceKey = (_b = clean(config.deviceKey)) != null ? _b : clean((_a2 = config.userContext) == null ? void 0 : _a2.deviceKey);
4602
+ const explicitDeviceKey = (_b = clean(config.deviceKey)) != null ? _b : clean((_a = config.userContext) == null ? void 0 : _a.deviceKey);
4432
4603
  resolveIdentity({
4433
4604
  value: explicitDeviceKey,
4434
4605
  space: "device",
@@ -4443,11 +4614,11 @@ var createWireActivation = (config) => {
4443
4614
  if (!explicitDeviceKey) resolveAutoDeviceKey(autoDeviceKeyOptions);
4444
4615
  const detectedAppVersion = detectAppVersion();
4445
4616
  const applyContext = (event) => {
4446
- var _a3, _b2, _c;
4617
+ var _a2, _b2, _c;
4447
4618
  const resolved = resolveUserContext(
4448
4619
  // `??` is lazy on purpose: an explicit key must never even touch the auto registry.
4449
4620
  {
4450
- ...(_a3 = config.userContext) != null ? _a3 : {},
4621
+ ...(_a2 = config.userContext) != null ? _a2 : {},
4451
4622
  deviceKey: explicitDeviceKey != null ? explicitDeviceKey : resolveAutoDeviceKey(autoDeviceKeyOptions)
4452
4623
  },
4453
4624
  { autoAppVersion: (_b2 = config.appVersion) != null ? _b2 : detectedAppVersion }
@@ -4457,13 +4628,13 @@ var createWireActivation = (config) => {
4457
4628
  }
4458
4629
  if (resolved.userId && !event.user_id) event.user_id = resolved.userId;
4459
4630
  };
4460
- const track = async (name2, meta) => {
4461
- if (!clean(name2)) return false;
4631
+ const track = async (name, meta) => {
4632
+ if (!clean(name)) return false;
4462
4633
  const sessionId = ensureCurrentSessionId();
4463
4634
  const event = {
4464
4635
  event_type: "app_event",
4465
4636
  session_id: sessionId,
4466
- question_key: name2
4637
+ question_key: name
4467
4638
  };
4468
4639
  if (meta && Object.keys(meta).length > 0) event.meta = JSON.stringify(meta);
4469
4640
  applyContext(event);
@@ -4486,7 +4657,7 @@ var useActivationRevalidation = () => useSyncExternalStore(
4486
4657
  getActivationRevalidationVersion
4487
4658
  );
4488
4659
  var useWireActivation = (config) => {
4489
- var _a2;
4660
+ var _a;
4490
4661
  const ref = useRef(void 0);
4491
4662
  const prevKeys = useRef("");
4492
4663
  const currentKeys = [
@@ -4494,7 +4665,7 @@ var useWireActivation = (config) => {
4494
4665
  config.apiKey,
4495
4666
  config.appId,
4496
4667
  config.deviceKey,
4497
- (_a2 = config.userContext) == null ? void 0 : _a2.deviceKey
4668
+ (_a = config.userContext) == null ? void 0 : _a.deviceKey
4498
4669
  ].join("|");
4499
4670
  if (!ref.current || prevKeys.current !== currentKeys) {
4500
4671
  prevKeys.current = currentKeys;
@@ -4520,8 +4691,8 @@ var WIRE_PURCHASE_EVENTS = {
4520
4691
  var PLAN_TIER_CONTEXT_KEY = "plan_tier";
4521
4692
  var asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
4522
4693
  var activeEntitlement = (info, entitlementId) => {
4523
- var _a2, _b;
4524
- const active = asRecord((_b = asRecord((_a2 = asRecord(info)) == null ? void 0 : _a2.entitlements)) == null ? void 0 : _b.active);
4694
+ var _a, _b;
4695
+ const active = asRecord((_b = asRecord((_a = asRecord(info)) == null ? void 0 : _a.entitlements)) == null ? void 0 : _b.active);
4525
4696
  const found = active == null ? void 0 : active[entitlementId];
4526
4697
  const entitlement = asRecord(found);
4527
4698
  if (!entitlement) return void 0;
@@ -4594,19 +4765,19 @@ var createRevenueCatBridge = (config) => {
4594
4765
  }
4595
4766
  };
4596
4767
  const syncPlanTier = (customerInfo) => {
4597
- var _a2;
4768
+ var _a;
4598
4769
  const tier = resolvePlanTier(customerInfo, entitlementId);
4599
4770
  if (!writeTier) return tier;
4600
4771
  try {
4601
- (_a2 = analytics.setUserContext) == null ? void 0 : _a2.call(analytics, { extra: { [PLAN_TIER_CONTEXT_KEY]: tier } });
4772
+ (_a = analytics.setUserContext) == null ? void 0 : _a.call(analytics, { extra: { [PLAN_TIER_CONTEXT_KEY]: tier } });
4602
4773
  } catch {
4603
4774
  }
4604
4775
  return tier;
4605
4776
  };
4606
4777
  const paywallShown = (offering, props) => {
4607
- var _a2, _b;
4778
+ var _a, _b;
4608
4779
  const shown = {
4609
- packages_count: (_b = (_a2 = offering == null ? void 0 : offering.availablePackages) == null ? void 0 : _a2.length) != null ? _b : 0
4780
+ packages_count: (_b = (_a = offering == null ? void 0 : offering.availablePackages) == null ? void 0 : _a.length) != null ? _b : 0
4610
4781
  };
4611
4782
  if (typeof (offering == null ? void 0 : offering.identifier) === "string") shown.offering_id = offering.identifier;
4612
4783
  emit(WIRE_PURCHASE_EVENTS.paywallShown, { ...shown, ...props });
@@ -4660,10 +4831,10 @@ var resetSessionStartGuard = () => {
4660
4831
  _emitted.clear();
4661
4832
  };
4662
4833
  var reportSessionStart = (opts) => {
4663
- var _a2;
4834
+ var _a;
4664
4835
  const target = opts.target;
4665
4836
  if (!opts.sink && !(target == null ? void 0 : target.serverUrl)) return;
4666
- const sessionId = (_a2 = opts.sessionId) != null ? _a2 : makeSessionId();
4837
+ const sessionId = (_a = opts.sessionId) != null ? _a : makeSessionId();
4667
4838
  setCurrentSessionId(sessionId);
4668
4839
  if (opts.once !== false) {
4669
4840
  if (_emitted.has(sessionId)) return;
@@ -4723,11 +4894,11 @@ var useSessionStart = (config, options = {}) => {
4723
4894
  return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
4724
4895
  };
4725
4896
  const fire = () => {
4726
- var _a2, _b;
4897
+ var _a, _b;
4727
4898
  const { config: cfg, options: opts } = latest.current;
4728
4899
  if (!(cfg == null ? void 0 : cfg.serverUrl)) return;
4729
4900
  if (opts.enabled === false) return;
4730
- const target = { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" };
4901
+ const target = { serverUrl: cfg.serverUrl, apiKey: (_a = cfg.apiKey) != null ? _a : "" };
4731
4902
  const device = collectDeviceContext();
4732
4903
  if (cfg.appVersion) device.appVersion = cfg.appVersion;
4733
4904
  reportSessionStart({
@@ -4778,7 +4949,7 @@ var resetFirstOpenLatch = () => {
4778
4949
  _firstOpenLatched.clear();
4779
4950
  };
4780
4951
  var buildLifecycleEvent = (questionKey, opts) => {
4781
- var _a2;
4952
+ var _a;
4782
4953
  const userContext = {};
4783
4954
  if (opts.deviceKey) userContext.device_key = opts.deviceKey;
4784
4955
  if (typeof opts.sessionCount === "number" && Number.isFinite(opts.sessionCount)) {
@@ -4790,7 +4961,7 @@ var buildLifecycleEvent = (questionKey, opts) => {
4790
4961
  const event = {
4791
4962
  event_type: "app_event",
4792
4963
  question_key: questionKey,
4793
- session_id: (_a2 = opts.sessionId) != null ? _a2 : makeSessionId()
4964
+ session_id: (_a = opts.sessionId) != null ? _a : makeSessionId()
4794
4965
  };
4795
4966
  const userId = sanitizeUserId(opts.userId);
4796
4967
  if (userId) event.user_id = userId;
@@ -4816,8 +4987,8 @@ var emitFirstOpen = (opts) => {
4816
4987
  routeLifecycleEvent(buildLifecycleEvent(FIRST_OPEN_EVENT, opts), opts);
4817
4988
  };
4818
4989
  var reportFirstOpen = (opts) => {
4819
- var _a2;
4820
- const appId = (_a2 = opts.appId) != null ? _a2 : "default";
4990
+ var _a;
4991
+ const appId = (_a = opts.appId) != null ? _a : "default";
4821
4992
  if (_firstOpenLatched.has(appId)) return;
4822
4993
  _firstOpenLatched.add(appId);
4823
4994
  const storage = opts.storage;
@@ -4842,8 +5013,8 @@ var reportFirstOpen = (opts) => {
4842
5013
  })();
4843
5014
  };
4844
5015
  var wireLifecycleEvents = (opts) => {
4845
- var _a2;
4846
- const sessionId = (_a2 = opts.sessionId) != null ? _a2 : makeSessionId();
5016
+ var _a;
5017
+ const sessionId = (_a = opts.sessionId) != null ? _a : makeSessionId();
4847
5018
  reportFirstOpen({ ...opts, sessionId });
4848
5019
  reportSessionStart({
4849
5020
  target: opts.target,
@@ -4892,10 +5063,11 @@ var claimQueueKey = (preferred, explicit) => {
4892
5063
  );
4893
5064
  return key;
4894
5065
  };
5066
+ var READ_TIMED_OUT = /* @__PURE__ */ Symbol("wireai:storage-read-timeout");
4895
5067
  var withTimeout4 = (p, ms) => {
4896
5068
  let timer;
4897
5069
  const timeout = new Promise((resolve) => {
4898
- timer = setTimeout(() => resolve(void 0), ms);
5070
+ timer = setTimeout(() => resolve(READ_TIMED_OUT), ms);
4899
5071
  });
4900
5072
  return Promise.race([p, timeout]).finally(() => clearTimeout(timer));
4901
5073
  };
@@ -4920,10 +5092,10 @@ var parsePersisted2 = (raw) => {
4920
5092
  }
4921
5093
  };
4922
5094
  var createEventQueue = (options) => {
4923
- var _a2, _b, _c, _d, _e, _f, _g;
5095
+ var _a, _b, _c, _d, _e, _f, _g;
4924
5096
  const target = options.target;
4925
5097
  const storage = options.storage;
4926
- const defaultKey = (_b = options.storageKey) != null ? _b : `wireai:evtq:${(_a2 = options.appId) != null ? _a2 : "default"}`;
5098
+ const defaultKey = (_b = options.storageKey) != null ? _b : `wireai:evtq:${(_a = options.appId) != null ? _a : "default"}`;
4927
5099
  const key = storage ? claimQueueKey(defaultKey, options.storageKey !== void 0) : defaultKey;
4928
5100
  const maxSize = (_c = options.maxSize) != null ? _c : DEFAULTS.maxSize;
4929
5101
  const batchSize = (_d = options.batchSize) != null ? _d : DEFAULTS.batchSize;
@@ -4935,6 +5107,7 @@ var createEventQueue = (options) => {
4935
5107
  let flushing = false;
4936
5108
  let attempt = 0;
4937
5109
  let retryTimer;
5110
+ let backlogUnread = false;
4938
5111
  const resolveEnvelope = () => {
4939
5112
  try {
4940
5113
  return typeof options.envelope === "function" ? options.envelope() : options.envelope;
@@ -4943,14 +5116,14 @@ var createEventQueue = (options) => {
4943
5116
  }
4944
5117
  };
4945
5118
  const stamp = (event) => {
4946
- var _a3;
5119
+ var _a2;
4947
5120
  const env = resolveEnvelope();
4948
5121
  const stamped = { ...event };
4949
5122
  if (stamped.ts === void 0) stamped.ts = Date.now();
4950
5123
  if (!env) return stamped;
4951
5124
  if (!stamped.device && env.device) stamped.device = env.device;
4952
5125
  if (!stamped.session_id && env.sessionId) stamped.session_id = env.sessionId;
4953
- const uc = { ...(_a3 = stamped.user_context) != null ? _a3 : {} };
5126
+ const uc = { ...(_a2 = stamped.user_context) != null ? _a2 : {} };
4954
5127
  if (env.appVersion && uc.app_version === void 0) uc.app_version = env.appVersion;
4955
5128
  if (env.appBuild && uc.app_build === void 0) uc.app_build = env.appBuild;
4956
5129
  if (env.networkType && uc.network_type === void 0) uc.network_type = env.networkType;
@@ -4959,6 +5132,7 @@ var createEventQueue = (options) => {
4959
5132
  };
4960
5133
  const persist = () => {
4961
5134
  if (!storage) return;
5135
+ if (backlogUnread) return;
4962
5136
  try {
4963
5137
  if (pending.length === 0) {
4964
5138
  void storage.removeItem(key).catch(() => {
@@ -4981,23 +5155,44 @@ var createEventQueue = (options) => {
4981
5155
  return `__nosig_${nextId}_${Math.random()}`;
4982
5156
  }
4983
5157
  };
5158
+ const mergePersisted = (persistedItems) => {
5159
+ if (persistedItems.length === 0) return;
5160
+ const seen = new Set(pending.map((item) => item.sig));
5161
+ const restored = [];
5162
+ for (const persisted of persistedItems) {
5163
+ const sig = safeSig(persisted.event);
5164
+ if (seen.has(sig)) continue;
5165
+ seen.add(sig);
5166
+ restored.push({ id: nextId++, event: persisted.event, sig });
5167
+ }
5168
+ if (restored.length === 0) return;
5169
+ pending = [...restored, ...pending];
5170
+ enforceSizeCap();
5171
+ persist();
5172
+ };
4984
5173
  const loadPromise = (async () => {
4985
5174
  if (!storage) return;
4986
5175
  try {
4987
- const persistedItems = parsePersisted2(await withTimeout4(storage.getItem(key), READ_TIMEOUT_MS4));
4988
- if (persistedItems.length === 0) return;
4989
- const events = [...persistedItems.map((p) => p.event), ...pending.map((p) => p.event)];
4990
- pending = [];
4991
- nextId = 0;
4992
- const seen = /* @__PURE__ */ new Set();
4993
- for (const event of events) {
4994
- const sig = safeSig(event);
4995
- if (seen.has(sig)) continue;
4996
- seen.add(sig);
4997
- pending.push({ id: nextId++, event, sig });
5176
+ const read = Promise.resolve(storage.getItem(key));
5177
+ read.catch(() => {
5178
+ });
5179
+ const raced = await withTimeout4(read, READ_TIMEOUT_MS4);
5180
+ if (raced === READ_TIMED_OUT) {
5181
+ backlogUnread = true;
5182
+ warnInDev(
5183
+ `[wireai] the persisted analytics backlog at "${key}" took longer than ${READ_TIMEOUT_MS4}ms to read, so the queue started without it. The stored events are NOT discarded: writes are held back until the read lands, and the backlog is merged in then. If you see this on every cold start, your storage adapter is too slow to be on the launch path.`
5184
+ );
5185
+ void read.then((late) => {
5186
+ backlogUnread = false;
5187
+ mergePersisted(parsePersisted2(late));
5188
+ flush();
5189
+ }).catch(() => {
5190
+ backlogUnread = false;
5191
+ persist();
5192
+ });
5193
+ return;
4998
5194
  }
4999
- enforceSizeCap();
5000
- persist();
5195
+ mergePersisted(parsePersisted2(raced));
5001
5196
  } catch {
5002
5197
  }
5003
5198
  })();
@@ -5094,13 +5289,13 @@ var useLifecycleEvents = (config, options = {}) => {
5094
5289
  const queueRef = useRef(void 0);
5095
5290
  useEffect(() => {
5096
5291
  const resolveSink = () => {
5097
- var _a2, _b;
5292
+ var _a, _b;
5098
5293
  const { config: cfg, options: opts } = latest.current;
5099
5294
  if (opts.sink) return opts.sink;
5100
5295
  if (!(cfg == null ? void 0 : cfg.serverUrl)) return void 0;
5101
5296
  if (!queueRef.current) {
5102
5297
  queueRef.current = createEventQueue({
5103
- target: { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" },
5298
+ target: { serverUrl: cfg.serverUrl, apiKey: (_a = cfg.apiKey) != null ? _a : "" },
5104
5299
  storage: cfg.storage,
5105
5300
  // Dedicated key so the hook's internal queue never collides with a host's main queue.
5106
5301
  storageKey: `wireai:evtq:lifecycle:${(_b = cfg.appId) != null ? _b : "default"}`,
@@ -5110,24 +5305,24 @@ var useLifecycleEvents = (config, options = {}) => {
5110
5305
  return queueRef.current.enqueue;
5111
5306
  };
5112
5307
  const targetOf = (cfg) => {
5113
- var _a2;
5114
- return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (_a2 = cfg.apiKey) != null ? _a2 : "" } : void 0;
5308
+ var _a;
5309
+ return (cfg == null ? void 0 : cfg.serverUrl) ? { serverUrl: cfg.serverUrl, apiKey: (_a = cfg.apiKey) != null ? _a : "" } : void 0;
5115
5310
  };
5116
5311
  const resolveDeviceKey = (cfg, opts) => {
5117
- var _a2;
5118
- const host = (_a2 = resolveIdentity({
5312
+ var _a;
5313
+ const host = (_a = resolveIdentity({
5119
5314
  value: opts.deviceKey,
5120
5315
  space: "device",
5121
5316
  source: "host",
5122
5317
  scope: cfg == null ? void 0 : cfg.appId
5123
- })) == null ? void 0 : _a2.value;
5318
+ })) == null ? void 0 : _a.value;
5124
5319
  if (host) return host;
5125
5320
  if (!(cfg == null ? void 0 : cfg.storage)) return void 0;
5126
5321
  return resolveAutoDeviceKey({ appId: cfg.appId, storage: cfg.storage });
5127
5322
  };
5128
5323
  const mountOpenSessionId = makeSessionId();
5129
5324
  const fireSession = (sessionId) => {
5130
- var _a2;
5325
+ var _a;
5131
5326
  const { config: cfg, options: opts } = latest.current;
5132
5327
  if (opts.enabled === false) return;
5133
5328
  if (!(cfg == null ? void 0 : cfg.serverUrl) && !opts.sink) return;
@@ -5140,14 +5335,14 @@ var useLifecycleEvents = (config, options = {}) => {
5140
5335
  userId: opts.userId,
5141
5336
  deviceKey: resolveDeviceKey(cfg, opts),
5142
5337
  sessionCount: opts.sessionCount,
5143
- appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
5338
+ appVersion: (_a = cfg == null ? void 0 : cfg.appVersion) != null ? _a : device.appVersion,
5144
5339
  platform: Platform.OS,
5145
5340
  device,
5146
5341
  meta: opts.meta
5147
5342
  });
5148
5343
  };
5149
5344
  const fireMountOpen = () => {
5150
- var _a2;
5345
+ var _a;
5151
5346
  fireSession(mountOpenSessionId);
5152
5347
  const { config: cfg, options: opts } = latest.current;
5153
5348
  if (opts.enabled === false) return;
@@ -5162,7 +5357,7 @@ var useLifecycleEvents = (config, options = {}) => {
5162
5357
  userId: opts.userId,
5163
5358
  deviceKey: resolveDeviceKey(cfg, opts),
5164
5359
  sessionCount: opts.sessionCount,
5165
- appVersion: (_a2 = cfg == null ? void 0 : cfg.appVersion) != null ? _a2 : device.appVersion,
5360
+ appVersion: (_a = cfg == null ? void 0 : cfg.appVersion) != null ? _a : device.appVersion,
5166
5361
  platform: Platform.OS,
5167
5362
  device,
5168
5363
  meta: opts.meta
@@ -5198,6 +5393,6 @@ var useLifecycleEvents = (config, options = {}) => {
5198
5393
  }, []);
5199
5394
  };
5200
5395
 
5201
- export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, CardGridSelectCard, CardHandoff, CenteredModal, ChipSelectCard, CompletionView, DEFAULT_FEATURES_TTL_MS, DEFAULT_SESSION_TTL_MS, DemoOnboarding, EXTRA_KEY_PREFIX, ErrorBlock, FIRST_OPEN_EVENT, IconRegistryProvider, IllustrationProvider, InterstitialCard, LoadingBlock, LoadingScreen, NumberStepperCard, Button as OnboardingButton, OnboardingFlow, OnboardingScaffold, OnboardingThemeProvider, PLAN_TIER_CONTEXT_KEY, 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, hostIdentity, hydrateAutoDeviceKey, hydrateDeviceIdentity, 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, resetIdentityProvenance, resetSessionStartGuard, resolveAutoDeviceKey, resolveIdentity, resolvePlanTier, resolveUserContext, sanitizeUserId, savePersistedSession, sessionStorageKey, setCurrentSessionId, subscribeActivationRevalidation, themeFromBrand, toAnalyticsEvent, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
5396
+ export { AUTO_DEVICE_ID_PREFIX, AnimatedSparkle, BACKGROUND_SESSION_MS, CardGridSelectCard, CardHandoff, CenteredModal, ChipSelectCard, CompletionView, DEFAULT_FEATURES_TTL_MS, DEFAULT_PERMISSION_COPY, DEFAULT_PERMISSION_PLACEMENT, DEFAULT_SESSION_TTL_MS, DemoOnboarding, EXTRA_KEY_PREFIX, ErrorBlock, FIRST_OPEN_EVENT, GENERIC_PERMISSION_COPY, IconRegistryProvider, IllustrationProvider, InterstitialCard, LoadingBlock, LoadingScreen, NOTIFICATIONS_PERMISSION_COPY, NumberStepperCard, Button as OnboardingButton, OnboardingFlow, OnboardingScaffold, OnboardingThemeProvider, PERMISSION_CARD_NAME, PLAN_TIER_CONTEXT_KEY, PermissionCard, PermissionCardView, SESSION_STARTED_EVENT, SelectionCard, StatusCard, StepProgress, TextInputCard, USER_ID_MAX_LENGTH, WIRE_ENV_VARS, WIRE_ICON_GLYPHS, WIRE_ICON_NAMES, WIRE_ONBOARDING_EVENTS, WIRE_PERMISSION_EVENTS, WIRE_PURCHASE_EVENTS, WireFeaturesProvider, WireIcon, WireOnboarding, activationJoinContext, activeEntitlement, analyticsUserIdStorageKey, attributionMetadata, bumpActivationRevalidation, clearPersistedSession, clearPiiFromContext, clearSettledPermissions, clearUserContext, collectDeviceContext, createRevenueCatBridge, createWireActivation, defaultIllustrations, defaultOnboardingTheme, defaultWireFeatures, deriveAnswers, describeEntitlement, describeFailure, describePackage, detectAppVersion, detectNativeModel, deviceIdStorageKey, ensureCurrentSessionId, featuresCacheKey, featuresEqual, fetchWireFeatures, firstOpenStorageKey, getActivationRevalidationVersion, getCurrentSessionId, hashEmailFnv1a, hostIdentity, hydrateAutoDeviceKey, hydrateDeviceIdentity, identifyOnboarding, isFeaturesFresh, isOnboardingEnabled, isPermissionDue, isUserCancelled, isWireScalar, loadPersistedSession, loadSettledPermissions, looksLikeEmail, lookupIconGlyph, makeSessionId, mergeTheme, mintDeviceId, motionSpec_exports as motionSpec, namespaceExtra, normalizeAfterCard, normalizePermissionStatus, onboardingComponents, parseWireFeatures, peekPersistedSession, permissionEventName, permissionEventProps, permissionScreenId, permissionStorageKey, readCachedFeatures, readProgress, readSettledPermissions, reportClientEvent, reportClientEventAwait, reportClientEvents, reportClientEventsAwait, reportFirstOpen, reportSessionStart, resetActivationRevalidation, resetAutoDeviceKeys, resetCurrentSessionId, resetFirstOpenLatch, resetIdentityProvenance, resetSessionStartGuard, resolveAutoDeviceKey, resolveIdentity, resolvePermissionCopy, resolvePlanTier, resolveUserContext, sanitizeUserId, savePersistedSession, saveSettledPermissions, selectDuePermissionScreen, sessionStorageKey, setCurrentSessionId, subscribeActivationRevalidation, themeFromBrand, toAnalyticsEvent, useActivationRevalidation, useHostIcon, useIllustration, useLifecycleEvents, useOnboardingTheme, useReducedMotion, useResolvedFeatures, useSessionStart, useWireActivation, useWireFeatures, useWireFeaturesContext, wireConfigFromEnv, wireLifecycleEvents, writeCachedFeatures };
5202
5397
  //# sourceMappingURL=index.mjs.map
5203
5398
  //# sourceMappingURL=index.mjs.map