@wireai/activation 0.14.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +144 -0
  3. package/README.md +23 -9
  4. package/dist/analytics/index.d.mts +5 -5
  5. package/dist/analytics/index.d.ts +5 -5
  6. package/dist/analytics/index.js.map +1 -1
  7. package/dist/analytics/index.mjs.map +1 -1
  8. package/dist/coachmarks/index.d.mts +13 -5
  9. package/dist/coachmarks/index.d.ts +13 -5
  10. package/dist/coachmarks/index.js +252 -58
  11. package/dist/coachmarks/index.js.map +1 -1
  12. package/dist/coachmarks/index.mjs +204 -9
  13. package/dist/coachmarks/index.mjs.map +1 -1
  14. package/dist/{currentSession-CW_5Mq4O.d.ts → currentSession-CFSRZ2wg.d.ts} +10 -4
  15. package/dist/{currentSession-CUvTOchb.d.mts → currentSession-orZy5p1e.d.mts} +10 -4
  16. package/dist/{decision-Bgo17oH7.d.mts → decision-3vWLuBlO.d.ts} +11 -2
  17. package/dist/{decision-Bkh_LigV.d.ts → decision-yBj2AyPW.d.mts} +11 -2
  18. package/dist/index.d.mts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/questionnaire/index.d.mts +3 -3
  23. package/dist/questionnaire/index.d.ts +3 -3
  24. package/dist/questionnaire/index.js +48 -3
  25. package/dist/questionnaire/index.js.map +1 -1
  26. package/dist/questionnaire/index.mjs +48 -3
  27. package/dist/questionnaire/index.mjs.map +1 -1
  28. package/dist/reviews/index.d.mts +10 -6
  29. package/dist/reviews/index.d.ts +10 -6
  30. package/dist/reviews/index.js +167 -18
  31. package/dist/reviews/index.js.map +1 -1
  32. package/dist/reviews/index.mjs +167 -18
  33. package/dist/reviews/index.mjs.map +1 -1
  34. package/dist/showcase/index.d.mts +1 -1
  35. package/dist/showcase/index.d.ts +1 -1
  36. package/dist/showcase/index.js +282 -48
  37. package/dist/showcase/index.js.map +1 -1
  38. package/dist/showcase/index.mjs +248 -12
  39. package/dist/showcase/index.mjs.map +1 -1
  40. package/dist/{transport-j5gFfJhK.d.mts → transport-s5QxA-ci.d.mts} +18 -13
  41. package/dist/{transport-B_0SgCBe.d.ts → transport-xqqSFqxs.d.ts} +18 -13
  42. package/dist/{types-Cju-1_jT.d.mts → types-Byx306Kv.d.mts} +25 -10
  43. package/dist/{types-BcmagF6K.d.mts → types-D_0B0yay.d.mts} +7 -2
  44. package/dist/{types-BcmagF6K.d.ts → types-D_0B0yay.d.ts} +7 -2
  45. package/dist/{types-h2BZvl1t.d.ts → types-tdATL5z0.d.ts} +25 -10
  46. package/metro/index.js +16 -5
  47. package/package.json +1 -1
  48. package/src/WireOnboarding.tsx +4 -1
  49. package/src/coachmarks/GestureHint.tsx +16 -7
  50. package/src/coachmarks/SpotlightOverlay.tsx +19 -13
  51. package/src/coachmarks/index.ts +7 -2
  52. package/src/coachmarks/reanimated.ts +342 -0
  53. package/src/coachmarks/runtime.ts +103 -2
  54. package/src/coachmarks/types.ts +7 -2
  55. package/src/context/deviceId.ts +32 -0
  56. package/src/reviews/ReviewGate.tsx +86 -37
  57. package/src/reviews/decision.ts +11 -1
  58. package/src/reviews/idempotency.ts +71 -0
  59. package/src/reviews/index.ts +4 -2
  60. package/src/reviews/runtime.ts +5 -3
  61. package/src/reviews/transport.ts +17 -12
  62. package/src/reviews/types.ts +7 -0
  63. package/src/showcase/FeatureShowcase.tsx +25 -9
  64. package/src/showcase/blazejOnboarding.ts +136 -0
  65. package/src/showcase/index.ts +8 -4
  66. package/src/types.ts +10 -4
  67. package/src/utils/submitResult.ts +17 -9
@@ -1,10 +1,159 @@
1
- import Onboarding from '@blazejkustra/react-native-onboarding';
2
- import React, { createContext, useEffect, useMemo, useRef, useCallback, useState, useContext } from 'react';
3
- import { StyleSheet, View } from 'react-native';
4
- import Animated, { useSharedValue, useReducedMotion, withRepeat, withSequence, withTiming, withDelay, useAnimatedStyle } from 'react-native-reanimated';
1
+ import React, { forwardRef, createElement, createContext, useEffect, useMemo, useRef, useCallback, useState, useContext, useReducer } from 'react';
2
+ import { View, StyleSheet, AccessibilityInfo } from 'react-native';
5
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
4
 
7
- // src/showcase/FeatureShowcase.tsx
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
11
+ var lastKnown = false;
12
+ var useReducedMotion = () => {
13
+ const [reduced, setReduced] = useState(lastKnown);
14
+ useEffect(() => {
15
+ let mounted = true;
16
+ AccessibilityInfo.isReduceMotionEnabled().then((value) => {
17
+ lastKnown = value;
18
+ if (mounted) setReduced(value);
19
+ }).catch(() => {
20
+ });
21
+ const sub = AccessibilityInfo.addEventListener("reduceMotionChanged", (value) => {
22
+ lastKnown = value;
23
+ setReduced(value);
24
+ });
25
+ return () => {
26
+ mounted = false;
27
+ sub == null ? void 0 : sub.remove();
28
+ };
29
+ }, []);
30
+ return reduced;
31
+ };
32
+
33
+ // src/coachmarks/reanimated.ts
34
+ var runtimeRequire = (moduleName) => {
35
+ if (moduleName !== "react-native-reanimated") return void 0;
36
+ if (typeof __require !== "function") return void 0;
37
+ try {
38
+ return __require("react-native-reanimated");
39
+ } catch {
40
+ return void 0;
41
+ }
42
+ };
43
+ var useStaticSharedValue = (initial) => {
44
+ const [, bump] = useReducer((n) => n + 1, 0);
45
+ const box = useRef(null);
46
+ if (box.current === null) {
47
+ let current = initial;
48
+ box.current = {
49
+ get value() {
50
+ return current;
51
+ },
52
+ set value(next) {
53
+ if (Object.is(next, current)) return;
54
+ current = next;
55
+ bump();
56
+ }
57
+ };
58
+ }
59
+ return box.current;
60
+ };
61
+ var runWorklet = (factory, fallback) => {
62
+ var _a;
63
+ try {
64
+ return (_a = factory()) != null ? _a : fallback;
65
+ } catch {
66
+ return fallback;
67
+ }
68
+ };
69
+ var StaticAnimatedView = forwardRef(function StaticAnimatedView2({ entering: _entering, exiting: _exiting, children, ...rest }, ref) {
70
+ return createElement(View, { ...rest, ref }, children);
71
+ });
72
+ var staticCreateAnimatedComponent = (component) => function StaticAnimatedComponent({ animatedProps, ...rest }) {
73
+ return createElement(component, { ...rest, ...animatedProps });
74
+ };
75
+ var staticApi = {
76
+ present: false,
77
+ View: StaticAnimatedView,
78
+ createAnimatedComponent: staticCreateAnimatedComponent,
79
+ useSharedValue: useStaticSharedValue,
80
+ useAnimatedStyle: (factory) => runWorklet(factory, {}),
81
+ useAnimatedProps: (factory) => runWorklet(factory, {}),
82
+ useReducedMotion,
83
+ withTiming: (toValue) => toValue,
84
+ withRepeat: (animation) => animation,
85
+ withSequence: (...animations) => {
86
+ var _a;
87
+ return (_a = animations[animations.length - 1]) != null ? _a : 0;
88
+ },
89
+ withDelay: (_ms, animation) => animation,
90
+ fadeIn: () => void 0,
91
+ fadeOut: () => void 0
92
+ };
93
+ var isFunction = (value) => typeof value === "function";
94
+ var isComponent = (value) => typeof value === "function" || !!value && typeof value === "object" && "$$typeof" in value;
95
+ var fromModule = (mod) => {
96
+ var _a, _b;
97
+ if (!mod || typeof mod !== "object") return void 0;
98
+ const ns = mod;
99
+ const def = ns.default && typeof ns.default === "object" ? ns.default : void 0;
100
+ const pick = (name) => {
101
+ var _a2;
102
+ return (_a2 = ns[name]) != null ? _a2 : def == null ? void 0 : def[name];
103
+ };
104
+ const view = (_a = def == null ? void 0 : def.View) != null ? _a : ns.View;
105
+ const createAnimated = (_b = def == null ? void 0 : def.createAnimatedComponent) != null ? _b : ns.createAnimatedComponent;
106
+ const hooks = {
107
+ useSharedValue: pick("useSharedValue"),
108
+ useAnimatedStyle: pick("useAnimatedStyle"),
109
+ useAnimatedProps: pick("useAnimatedProps"),
110
+ useReducedMotion: pick("useReducedMotion"),
111
+ withTiming: pick("withTiming"),
112
+ withRepeat: pick("withRepeat"),
113
+ withSequence: pick("withSequence"),
114
+ withDelay: pick("withDelay")
115
+ };
116
+ const fadeIn = pick("FadeIn");
117
+ const fadeOut = pick("FadeOut");
118
+ if (!isComponent(view) || !isFunction(createAnimated)) return void 0;
119
+ if (Object.values(hooks).some((member) => !isFunction(member))) return void 0;
120
+ if (!fadeIn || !fadeOut) return void 0;
121
+ const api2 = {
122
+ present: true,
123
+ View: view,
124
+ createAnimatedComponent: createAnimated,
125
+ ...hooks,
126
+ fadeIn: (durationMs) => fadeIn.duration(durationMs),
127
+ fadeOut: (durationMs) => fadeOut.duration(durationMs)
128
+ };
129
+ return api2;
130
+ };
131
+ var cached;
132
+ var resolveReanimated = (requireModule = runtimeRequire) => {
133
+ var _a;
134
+ try {
135
+ if (cached === void 0 || requireModule !== runtimeRequire) {
136
+ const resolved = (_a = fromModule(requireModule("react-native-reanimated"))) != null ? _a : staticApi;
137
+ if (requireModule === runtimeRequire) cached = resolved;
138
+ return resolved;
139
+ }
140
+ return cached;
141
+ } catch {
142
+ return staticApi;
143
+ }
144
+ };
145
+ var api = () => resolveReanimated();
146
+ var Animated = {
147
+ get View() {
148
+ return api().View;
149
+ }};
150
+ var useSharedValue = (initial) => api().useSharedValue(initial);
151
+ var useAnimatedStyle = (factory) => api().useAnimatedStyle(factory);
152
+ var useReducedMotion2 = () => api().useReducedMotion();
153
+ var withTiming = (toValue, config) => api().withTiming(toValue, config);
154
+ var withRepeat = (animation, count, reverse) => api().withRepeat(animation, count, reverse);
155
+ var withSequence = (...animations) => api().withSequence(...animations);
156
+ var withDelay = (ms, animation) => api().withDelay(ms, animation);
8
157
  var SWIPE_MS = 700;
9
158
  var TAP_MS = 320;
10
159
  var SPREAD_MS = 620;
@@ -66,7 +215,7 @@ var GestureHintComponent = ({
66
215
  const opacity = useSharedValue(1);
67
216
  const pulse = useSharedValue(1);
68
217
  const spread = useSharedValue(0);
69
- const reduced = useReducedMotion();
218
+ const reduced = useReducedMotion2();
70
219
  const isSwipe = type === "swipe_up" || type === "swipe_down" || type === "swipe_left" || type === "swipe_right";
71
220
  const isSpread = type === "pinch" || type === "zoom";
72
221
  const isTap = type === "tap" || type === "double_tap";
@@ -234,9 +383,54 @@ var getCoachmarkStorage = () => coachmarkRuntime().storage;
234
383
  var isCoachmarkTesting = () => coachmarkRuntime().testing;
235
384
  var showcaseGateKey = (showcaseId) => `wire_showcase_${showcaseId}_seen`;
236
385
  var SEEN_VALUE = "1";
386
+ var GATE_PROBE_KEY = "wire_gate_probe";
387
+ var ASYNC_GATE_STORAGE_WARNED_SLOT = /* @__PURE__ */ Symbol.for(
388
+ "@wireai/activation:asyncGateStorageWarned"
389
+ );
390
+ var asyncGateWarnGlobal = globalThis;
391
+ var closedGateStorage = Object.freeze({
392
+ getItem: () => SEEN_VALUE,
393
+ setItem: () => {
394
+ }
395
+ });
396
+ var syncGateAdapters = /* @__PURE__ */ new WeakSet();
397
+ var asyncGateAdapters = /* @__PURE__ */ new WeakSet();
398
+ var warnAsyncGateStorage = () => {
399
+ if (asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT]) return;
400
+ if (typeof __DEV__ === "undefined" || !__DEV__) return;
401
+ if (typeof console === "undefined" || !console.warn) return;
402
+ asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT] = true;
403
+ console.warn(
404
+ "[wireai] the gate storage's getItem returned a Promise \u2014 an async adapter (e.g. AsyncStorage) cannot drive the once-per-user gates, so coachmark tours, showcases and the review/questionnaire gates are all DISABLED (fail closed: nothing shows, nothing fires) until a synchronous adapter is provided. Pass a sync adapter (e.g. MMKV: `{ getItem: (k) => mmkv.getString(k) ?? null, setItem: (k, v) => mmkv.set(k, v) }`) to CoachmarkProvider or the gate's `storage` prop."
405
+ );
406
+ };
407
+ var validateGateStorage = (storage) => {
408
+ if (!storage) return null;
409
+ if (syncGateAdapters.has(storage)) return storage;
410
+ if (asyncGateAdapters.has(storage)) return closedGateStorage;
411
+ let probed;
412
+ try {
413
+ probed = storage.getItem(GATE_PROBE_KEY);
414
+ } catch {
415
+ syncGateAdapters.add(storage);
416
+ return storage;
417
+ }
418
+ if (probed != null && typeof probed.then === "function") {
419
+ asyncGateAdapters.add(storage);
420
+ try {
421
+ probed.then(void 0, () => {
422
+ });
423
+ } catch {
424
+ }
425
+ warnAsyncGateStorage();
426
+ return closedGateStorage;
427
+ }
428
+ syncGateAdapters.add(storage);
429
+ return storage;
430
+ };
237
431
  var hasSeenGate = (key, storageOverride, testingOverride) => {
238
432
  if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return false;
239
- const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
433
+ const storage = validateGateStorage(storageOverride != null ? storageOverride : getCoachmarkStorage());
240
434
  if (!storage) return false;
241
435
  try {
242
436
  return storage.getItem(key) === SEEN_VALUE;
@@ -246,7 +440,7 @@ var hasSeenGate = (key, storageOverride, testingOverride) => {
246
440
  };
247
441
  var markSeenGate = (key, storageOverride, testingOverride) => {
248
442
  if (testingOverride != null ? testingOverride : isCoachmarkTesting()) return;
249
- const storage = storageOverride != null ? storageOverride : getCoachmarkStorage();
443
+ const storage = validateGateStorage(storageOverride != null ? storageOverride : getCoachmarkStorage());
250
444
  if (!storage) return;
251
445
  try {
252
446
  storage.setItem(key, SEEN_VALUE);
@@ -331,8 +525,8 @@ var DEFAULT_TIMEOUT_MS = 4e3;
331
525
  var failOpen = async (storage, key) => {
332
526
  var _a;
333
527
  if (!storage) return defaultWireFeatures;
334
- const cached = await readCachedFeatures(storage, key);
335
- return (_a = cached == null ? void 0 : cached.features) != null ? _a : defaultWireFeatures;
528
+ const cached3 = await readCachedFeatures(storage, key);
529
+ return (_a = cached3 == null ? void 0 : cached3.features) != null ? _a : defaultWireFeatures;
336
530
  };
337
531
  var fetchWithTimeout = async (url, apiKey, timeoutMs) => {
338
532
  const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
@@ -467,6 +661,47 @@ var useOnboardingTheme = () => {
467
661
  return ctx != null ? ctx : mergeTheme();
468
662
  };
469
663
 
664
+ // src/showcase/blazejOnboarding.ts
665
+ var MODULE_NAME = "@blazejkustra/react-native-onboarding";
666
+ var runtimeRequire2 = (moduleName) => {
667
+ if (moduleName !== MODULE_NAME) return void 0;
668
+ if (typeof __require !== "function") return void 0;
669
+ try {
670
+ return __require("@blazejkustra/react-native-onboarding");
671
+ } catch {
672
+ return void 0;
673
+ }
674
+ };
675
+ var interop = (mod) => {
676
+ if (typeof mod === "function") return mod;
677
+ if (!mod || typeof mod !== "object") return void 0;
678
+ const ns = mod;
679
+ if (ns.default) return ns.default;
680
+ if ("$$typeof" in ns) return ns;
681
+ return void 0;
682
+ };
683
+ var asComponent = (value) => {
684
+ if (typeof value === "function") return value;
685
+ if (value && typeof value === "object" && "$$typeof" in value) {
686
+ return value;
687
+ }
688
+ return void 0;
689
+ };
690
+ var cached2;
691
+ var resolveShowcaseOnboarding = (requireModule = runtimeRequire2) => {
692
+ try {
693
+ if (cached2 === void 0 || requireModule !== runtimeRequire2) {
694
+ const component = asComponent(interop(requireModule(MODULE_NAME)));
695
+ if (requireModule === runtimeRequire2) cached2 = component != null ? component : null;
696
+ return component;
697
+ }
698
+ if (cached2 === null) return void 0;
699
+ return cached2;
700
+ } catch {
701
+ return void 0;
702
+ }
703
+ };
704
+
470
705
  // src/showcase/showcaseColors.ts
471
706
  var showcaseColorsFromTheme = (t, accent) => ({
472
707
  background: {
@@ -527,12 +762,13 @@ var _FeatureShowcase = ({
527
762
  const accent = accentColor != null ? accentColor : t.colors.primary;
528
763
  const flags = useResolvedFeatures({ flags: features, config: featuresConfig });
529
764
  const disabled = !flags.showcase.enabled;
765
+ const Onboarding = useMemo(() => resolveShowcaseOnboarding(), []);
530
766
  const gateKey = showcaseGateKey(config.id);
531
767
  const seen = useMemo(
532
768
  () => hasSeenGate(gateKey, storage, isTesting),
533
769
  [gateKey, storage, isTesting]
534
770
  );
535
- const skip = seen || disabled;
771
+ const skip = seen || disabled || !Onboarding;
536
772
  const doneRef = useRef(false);
537
773
  const finish = useCallback(() => {
538
774
  if (doneRef.current) return;
@@ -612,7 +848,7 @@ var _FeatureShowcase = ({
612
848
  }),
613
849
  [t]
614
850
  );
615
- if (skip) return null;
851
+ if (skip || !Onboarding) return null;
616
852
  const activeGesture = (_a = config.slides[activeIndex]) == null ? void 0 : _a.gesture;
617
853
  const showGesture = !!activeGesture && activeGesture !== "none" && activeGesture !== "tap" && activeGesture !== "double_tap";
618
854
  return /* @__PURE__ */ jsxs(View, { style: styles2.fill, children: [