@wireai/activation 0.14.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +96 -21
- package/CHANGELOG.md +780 -0
- package/INTEGRATION_PROMPT.md +61 -23
- package/README.md +110 -31
- package/dist/analytics/index.d.mts +35 -13
- package/dist/analytics/index.d.ts +35 -13
- package/dist/analytics/index.js +288 -127
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +288 -127
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/coachmarks/index.d.mts +15 -1
- package/dist/coachmarks/index.d.ts +15 -1
- package/dist/coachmarks/index.js +120 -22
- package/dist/coachmarks/index.js.map +1 -1
- package/dist/coachmarks/index.mjs +120 -22
- package/dist/coachmarks/index.mjs.map +1 -1
- package/dist/{currentSession-CUvTOchb.d.mts → currentSession-Bz7G6lno.d.mts} +35 -39
- package/dist/{currentSession-CW_5Mq4O.d.ts → currentSession-z-CZ55ad.d.ts} +35 -39
- package/dist/{decision-Bgo17oH7.d.mts → decision-3vWLuBlO.d.ts} +11 -2
- package/dist/{decision-Bkh_LigV.d.ts → decision-yBj2AyPW.d.mts} +11 -2
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +125 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +125 -36
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +3 -16
- package/dist/questionnaire/index.d.ts +3 -16
- package/dist/questionnaire/index.js +202 -46
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +203 -47
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.d.mts +10 -6
- package/dist/reviews/index.d.ts +10 -6
- package/dist/reviews/index.js +269 -52
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +270 -53
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/showcase/index.d.mts +1 -1
- package/dist/showcase/index.d.ts +1 -1
- package/dist/showcase/index.js +106 -20
- package/dist/showcase/index.js.map +1 -1
- package/dist/showcase/index.mjs +107 -21
- package/dist/showcase/index.mjs.map +1 -1
- package/dist/{transport-j5gFfJhK.d.mts → transport-s5QxA-ci.d.mts} +18 -13
- package/dist/{transport-B_0SgCBe.d.ts → transport-xqqSFqxs.d.ts} +18 -13
- package/dist/{types-Cju-1_jT.d.mts → types-Byx306Kv.d.mts} +25 -10
- package/dist/{types-BcmagF6K.d.mts → types-D_0B0yay.d.mts} +7 -2
- package/dist/{types-BcmagF6K.d.ts → types-D_0B0yay.d.ts} +7 -2
- package/dist/{types-h2BZvl1t.d.ts → types-tdATL5z0.d.ts} +25 -10
- package/llms.txt +9 -9
- package/package.json +6 -9
- package/src/WireOnboarding.tsx +4 -1
- package/src/analytics/currentSession.ts +141 -4
- package/src/analytics/index.ts +6 -1
- package/src/analytics/reportClientEvent.ts +19 -10
- package/src/analytics/useAnalytics.ts +74 -15
- package/src/analytics/wireDoctor.ts +152 -7
- package/src/coachmarks/CoachmarkProvider.tsx +26 -5
- package/src/coachmarks/runtime.ts +156 -2
- package/src/coachmarks/types.ts +7 -2
- package/src/coachmarks/useCoachmarkTour.ts +51 -1
- package/src/context/deviceId.ts +72 -6
- package/src/features/WireFeaturesProvider.tsx +72 -12
- package/src/features/fetchWireFeatures.ts +49 -11
- package/src/features/useWireFeatures.ts +39 -3
- package/src/identity/identityRecord.ts +15 -2
- package/src/questionnaire/QuestionnaireGate.tsx +40 -1
- package/src/questionnaire/transport.ts +22 -8
- package/src/questionnaire/useQuestionnaireGate.ts +58 -7
- package/src/reviews/ReviewGate.tsx +125 -37
- package/src/reviews/decision.ts +11 -1
- package/src/reviews/idempotency.ts +109 -0
- package/src/reviews/index.ts +4 -2
- package/src/reviews/runtime.ts +44 -13
- package/src/reviews/transport.ts +39 -20
- package/src/reviews/types.ts +7 -0
- package/src/reviews/useReviewGate.ts +57 -7
- package/src/session-analytics/lifecycle.ts +16 -0
- package/src/session-analytics/useLifecycleEvents.ts +30 -2
- package/src/session-analytics/useSessionStart.ts +22 -2
- package/src/showcase/FeatureShowcase.tsx +50 -3
- package/src/types.ts +15 -8
- package/src/utils/submitResult.ts +17 -9
- package/src/utils/withDeadline.ts +70 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/motion/useReducedMotion.ts","../../src/coachmarks/reanimated.ts","../../src/coachmarks/GestureHint.tsx","../../src/coachmarks/runtime.ts","../../src/features/defaults.ts","../../src/features/cache.ts","../../src/features/fetchWireFeatures.ts","../../src/features/useWireFeatures.ts","../../src/features/WireFeaturesProvider.tsx","../../src/theme/defaultTheme.ts","../../src/theme/ThemeContext.tsx","../../src/showcase/blazejOnboarding.ts","../../src/showcase/showcaseColors.ts","../../src/showcase/FeatureShowcase.tsx","../../src/showcase/selectShowcaseSlides.ts"],"names":["StaticAnimatedView","_a","api","useReducedMotion","View","useEffect","cached","useRef","useState","createContext","useContext","runtimeRequire","useMemo","jsx","styles","StyleSheet","jsxs","React"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * useReducedMotion — the kit's ONE reduce-motion gate. Reads the OS setting via\n * AccessibilityInfo and stays subscribed to `reduceMotionChanged`, so every\n * animated component lands on its final frame (or a ~120ms fade) the moment the\n * user flips the setting — no restart needed.\n *\n * This closes the gap documented in ai_rules/rules/performance.md §3: every\n * animation in the kit must consume this hook (usually through the pure helpers\n * in motionSpec.ts: `entranceSpec` / `stateChangeDuration` / `loopEnabled`).\n */\nimport { useEffect, useState } from \"react\";\nimport { AccessibilityInfo } from \"react-native\";\n\n// Last-known value, module-level: cards remount every turn (keyed on message id),\n// and a `useState(false)` default would flash one animated frame per turn for a\n// reduce-motion user before the async read resolves.\nlet lastKnown = false;\n\nexport const useReducedMotion = (): boolean => {\n const [reduced, setReduced] = useState(lastKnown);\n\n useEffect(() => {\n let mounted = true;\n AccessibilityInfo.isReduceMotionEnabled()\n .then((value) => {\n lastKnown = value;\n if (mounted) setReduced(value);\n })\n .catch(() => {\n // Unavailable (e.g. some test envs): keep the last-known value.\n });\n const sub = AccessibilityInfo.addEventListener(\"reduceMotionChanged\", (value) => {\n lastKnown = value;\n setReduced(value);\n });\n return () => {\n mounted = false;\n sub?.remove();\n };\n }, []);\n\n return reduced;\n};\n","/**\n * reanimated — resolve `react-native-reanimated`, lazily and optionally.\n *\n * ── WHY THIS DOES NOT BREAK THE NO-NATIVE-DEPENDENCY POLICY ──────────────────────────────\n *\n * `react-native-reanimated` is an OPTIONAL peer of the coachmarks subpath. `SpotlightOverlay` and\n * `GestureHint` animate with it WHEN it is installed, and fall back to a STATIC render of the same\n * visual when it is not — same ring, same tooltip, same glyph, same copy, same gestures, just\n * without motion. So a host that never installs it can still run the guided tour and the feature\n * showcase, and an Expo Go / Lite build is not forced into a native module it cannot take.\n *\n * Before this file, both components did `import Animated, { … } from \"react-native-reanimated\"` at\n * module scope, and `coachmarks/index.ts` re-exports them with no wildcard escape — so importing\n * ANYTHING from `@wireai/activation/coachmarks` (even `setCoachmarkStorage`) dragged the peer in,\n * and a host without it hit a Metro resolution failure. `@wireai/activation/showcase` inherited the\n * same edge through `GestureHint`. This resolver removes it. Same class as the 0.14.2 `expo-blur`\n * fix (`expoBlur.ts`), same shape, one size up.\n *\n * ── THE SPECIFIER MUST BE A STRING LITERAL, INSIDE A TRY/CATCH ───────────────────────────\n *\n * This follows `icons/expoIcons.ts` and `coachmarks/expoBlur.ts` exactly, and expoIcons' header\n * carries the full autopsy. In short: Metro collects dependencies STATICALLY, matching a call whose\n * callee is literally the identifier `require` and whose argument is literally a string — an\n * aliased callee (`const req = require; req(name)`) or a variable specifier is collected NOWHERE,\n * so the module never enters the bundle (that shape shipped broken in 0.8.0). And the call sitting\n * inside a TRY/CATCH is literally how Metro marks the dependency `isOptional`, which is what lets\n * an absent peer degrade instead of failing the build. Do NOT \"simplify\" either half away.\n *\n * ── WHY THE EXPORTS ARE BARE FUNCTIONS WITH THE PEER'S OWN NAMES ─────────────────────────\n *\n * The call sites import `useAnimatedStyle` / `useAnimatedProps` / `withTiming` … from HERE instead\n * of from the peer, and call them unqualified, exactly as before. That is load-bearing, not style:\n * reanimated's Babel plugin decides what to workletize by the CALLEE NAME (`react-native-worklets`\n * `plugin/index.js` → `reanimatedFunctionHooks` / `reanimatedFunctionArgsToWorkletize`; it reads\n * `callee.name`, or `callee.property.name` for a member call, and never checks which module the\n * name came from). Keeping the names identical keeps every worklet in `SpotlightOverlay` and\n * `GestureHint` workletized byte-for-byte on a host that HAS the peer. Rename them and the\n * animations silently stop running on the UI thread.\n *\n * ── THE DEGRADE: THE FINAL FRAME, NOT A DEAD ONE ─────────────────────────────────────────\n *\n * The shim resolves every animation to its RESTING value — `withTiming(to)` is `to`,\n * `withSequence(a, b)` is `b`, `withRepeat(x)` is `x` — so a component lands on the pose it would\n * have settled into anyway (ring at scale 1, glyph at full opacity, blur at BLUR_INTENSITY) rather\n * than on frame zero, which for the blur would have meant a fully transparent overlay. Shared\n * values are state-backed so a write from an effect actually reaches the next render; reanimated's\n * own values do not need this because they drive the UI thread directly. The kit's own\n * AccessibilityInfo-backed `useReducedMotion` stands in for the peer's, so the reduce-motion\n * contract in ai_rules/rules/performance.md §3 holds with or without the peer.\n *\n * This is also what `ai_rules/rules/frequent_rules.md` #1 prescribes: when the kit needs motion\n * without the optional peer, it uses core React Native, never Reanimated.\n */\nimport {\n createElement,\n forwardRef,\n useReducer,\n useRef,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { View, type ViewProps, type ViewStyle } from \"react-native\";\n\nimport { useReducedMotion as useOsReducedMotion } from \"../motion/useReducedMotion\";\n\n// Metro injects a module-scoped `require`; it is ABSENT in a pure-ESM runtime (the kit's own tests\n// run under `node --test` as ESM). Declared locally so this type-checks without ambient Node types;\n// the `typeof` guard keeps the reference ESM-safe.\ndeclare const require: ((id: string) => unknown) | undefined;\n\n/** A `require`-like resolver. Injectable in tests; production uses the guarded literal require. */\nexport type OptionalRequire = (moduleName: string) => unknown;\n\n/** A reanimated shared value, narrowed to the one member the kit uses. */\nexport interface SharedValue<T> {\n value: T;\n}\n\n/** Props `Animated.View` accepts on top of a plain View (layout-animation descriptors). */\nexport interface AnimatedViewProps extends ViewProps {\n entering?: unknown;\n exiting?: unknown;\n children?: ReactNode;\n}\n\n/** A component built by `createAnimatedComponent`: its own props plus reanimated's driven props. */\nexport type AnimatedComponent<P> = ComponentType<P & { animatedProps?: object }>;\n\n/** The slice of reanimated the coachmark surfaces actually use. */\nexport interface ReanimatedApi {\n /** True when the real peer resolved; false when this is the static fallback. */\n present: boolean;\n View: ComponentType<AnimatedViewProps>;\n createAnimatedComponent: <P extends object>(component: ComponentType<P>) => AnimatedComponent<P>;\n useSharedValue: <T>(initial: T) => SharedValue<T>;\n useAnimatedStyle: (factory: () => ViewStyle) => ViewStyle;\n useAnimatedProps: <P extends object>(factory: () => P) => P;\n useReducedMotion: () => boolean;\n withTiming: (toValue: number, config?: object) => number;\n withRepeat: (animation: number, count?: number, reverse?: boolean) => number;\n withSequence: (...animations: number[]) => number;\n withDelay: (ms: number, animation: number) => number;\n /** The `entering` / `exiting` descriptors, or undefined when the peer is absent. */\n fadeIn: (durationMs: number) => unknown;\n fadeOut: (durationMs: number) => unknown;\n}\n\n/**\n * The production resolver. The specifier is a LITERAL so Metro collects it (see the header); the\n * `moduleName` parameter exists only to keep the `OptionalRequire` seam shape, so anything other\n * than the one module this file owns resolves to undefined.\n */\nconst runtimeRequire: OptionalRequire = (moduleName) => {\n if (moduleName !== \"react-native-reanimated\") return undefined;\n if (typeof require !== \"function\") return undefined;\n try {\n return require(\"react-native-reanimated\");\n } catch {\n return undefined;\n }\n};\n\n/**\n * TEST-ONLY seam. `SpotlightOverlay` / `GestureHint` have frozen public props, so neither can take\n * a `requireModule` the way `WireIcon` does — this lets a component render exercise the PRESENT\n * path. Production never sets it; `runtimeRequire` is the only resolver.\n */\nlet testRequire: OptionalRequire | undefined;\nexport const __setReanimatedRequireForTests = (fn: OptionalRequire | undefined): void => {\n testRequire = fn;\n cached = undefined;\n};\n\n// ── the static fallback ───────────────────────────────────────────────────────\n\n/**\n * A shared value that re-renders its owner on write. Reanimated's own value drives the UI thread\n * and deliberately does NOT re-render; here the render IS the only output, so a value written from\n * an effect (`intensity.value = withTiming(26)`) has to reach it or the overlay would sit on frame\n * zero forever — a fully transparent blur. The box identity is stable for the component's lifetime,\n * exactly like the real one, so it stays safe in a dependency list.\n */\nconst useStaticSharedValue = <T,>(initial: T): SharedValue<T> => {\n const [, bump] = useReducer((n: number): number => n + 1, 0);\n const box = useRef<SharedValue<T> | null>(null);\n if (box.current === null) {\n let current = initial;\n box.current = {\n get value(): T {\n return current;\n },\n set value(next: T) {\n if (Object.is(next, current)) return;\n current = next;\n bump();\n },\n };\n }\n return box.current;\n};\n\n/** Run a worklet body on the JS side. It must never throw into the render — degrade, don't crash. */\nconst runWorklet = <R extends object>(factory: () => R, fallback: R): R => {\n try {\n return factory() ?? fallback;\n } catch {\n return fallback;\n }\n};\n\n/** `Animated.View` without the peer: a plain View, with the layout-animation props dropped. */\nconst StaticAnimatedView = forwardRef<View, AnimatedViewProps>(function StaticAnimatedView(\n { entering: _entering, exiting: _exiting, children, ...rest },\n ref,\n) {\n return createElement(View, { ...rest, ref }, children);\n});\n\n/**\n * `createAnimatedComponent` without the peer. The wrapper MERGES `animatedProps` into the real\n * props, because that object is the only carrier for values the worklet would have driven (the\n * spotlight's blur `intensity`). Built once per wrapped component at the call site's `useMemo`, so\n * the returned type identity is stable and React never remounts the subtree.\n */\nconst staticCreateAnimatedComponent = <P extends object>(\n component: ComponentType<P>,\n): AnimatedComponent<P> =>\n function StaticAnimatedComponent({ animatedProps, ...rest }) {\n return createElement(component, { ...(rest as P), ...(animatedProps as object) });\n };\n\n/**\n * The peer-absent API. Every animation resolves to its RESTING value, so components render the\n * frame they would have settled on. Nothing here schedules work, allocates a native module, or\n * throws.\n */\nconst staticApi: ReanimatedApi = {\n present: false,\n View: StaticAnimatedView,\n createAnimatedComponent: staticCreateAnimatedComponent,\n useSharedValue: useStaticSharedValue,\n useAnimatedStyle: (factory) => runWorklet(factory, {}),\n useAnimatedProps: (factory) => runWorklet(factory, {} as never),\n useReducedMotion: useOsReducedMotion,\n withTiming: (toValue) => toValue,\n withRepeat: (animation) => animation,\n withSequence: (...animations) => animations[animations.length - 1] ?? 0,\n withDelay: (_ms, animation) => animation,\n fadeIn: () => undefined,\n fadeOut: () => undefined,\n};\n\n// ── the real peer ─────────────────────────────────────────────────────────────\n\nconst isFunction = (value: unknown): boolean => typeof value === \"function\";\n\n/** A React component is a function, or an object carrying `$$typeof` (memo / forwardRef). */\nconst isComponent = (value: unknown): boolean =>\n typeof value === \"function\" || (!!value && typeof value === \"object\" && \"$$typeof\" in value);\n\n/**\n * Build the API from a resolved module namespace, or undefined when it is not the module we expect.\n *\n * The hooks are NAMED exports; `View` and `createAnimatedComponent` live on the DEFAULT export (the\n * `Animated` object). A CJS interop wrapper puts everything one level down under `default`, so both\n * are looked up on the namespace first and the default second. EVERY member is verified before the\n * namespace is accepted: a partial module must degrade to the static fallback, never crash halfway\n * through a render.\n */\nconst fromModule = (mod: unknown): ReanimatedApi | undefined => {\n if (!mod || typeof mod !== \"object\") return undefined;\n const ns = mod as Record<string, unknown>;\n const def =\n ns.default && typeof ns.default === \"object\"\n ? (ns.default as Record<string, unknown>)\n : undefined;\n const pick = (name: string): unknown => ns[name] ?? def?.[name];\n\n const view = def?.View ?? ns.View;\n const createAnimated = def?.createAnimatedComponent ?? ns.createAnimatedComponent;\n const hooks = {\n useSharedValue: pick(\"useSharedValue\"),\n useAnimatedStyle: pick(\"useAnimatedStyle\"),\n useAnimatedProps: pick(\"useAnimatedProps\"),\n useReducedMotion: pick(\"useReducedMotion\"),\n withTiming: pick(\"withTiming\"),\n withRepeat: pick(\"withRepeat\"),\n withSequence: pick(\"withSequence\"),\n withDelay: pick(\"withDelay\"),\n };\n const fadeIn = pick(\"FadeIn\");\n const fadeOut = pick(\"FadeOut\");\n\n if (!isComponent(view) || !isFunction(createAnimated)) return undefined;\n if (Object.values(hooks).some((member) => !isFunction(member))) return undefined;\n if (!fadeIn || !fadeOut) return undefined;\n\n // The single narrowing seam. Everything above proved the members exist and are callable; the peer\n // is untyped here (it is resolved through `unknown`), so the cast happens once, at the boundary,\n // and the exported signatures above are the contract from here on.\n const api = {\n present: true,\n View: view,\n createAnimatedComponent: createAnimated,\n ...hooks,\n fadeIn: (durationMs: number) => (fadeIn as { duration: (ms: number) => unknown }).duration(durationMs),\n fadeOut: (durationMs: number) => (fadeOut as { duration: (ms: number) => unknown }).duration(durationMs),\n } as unknown as ReanimatedApi;\n return api;\n};\n\n/**\n * Module-level memo. Holds the RESOLVED api (real or static), so an absent peer costs exactly one\n * failed require per process, not one per mount — and, more importantly, so the implementation can\n * never change between two renders of the same component, which would break the rules of hooks.\n */\nlet cached: ReanimatedApi | undefined;\n\n/** Reset the memo. TEST-ONLY seam — production never calls it. */\nexport const resetReanimatedModuleCache = (): void => {\n cached = undefined;\n};\n\n/**\n * Resolve the reanimated API, or the static fallback when the peer is absent/unresolvable.\n * Never throws and never returns undefined: an absent animation library must degrade to a still\n * frame, never break the tour.\n */\nexport const resolveReanimated = (\n requireModule: OptionalRequire = testRequire ?? runtimeRequire,\n): ReanimatedApi => {\n try {\n if (cached === undefined || requireModule !== runtimeRequire) {\n const resolved = fromModule(requireModule(\"react-native-reanimated\")) ?? staticApi;\n // Don't poison the module memo from an injected test require.\n if (requireModule === runtimeRequire) cached = resolved;\n return resolved;\n }\n return cached;\n } catch {\n return staticApi;\n }\n};\n\n// ── the call-site surface: the peer's own names, resolved lazily ──────────────\n//\n// Each one delegates on every call, so nothing is resolved at import time. `api()` is memoized, so\n// the delegation is a property read.\n\nconst api = (): ReanimatedApi => resolveReanimated();\n\n/**\n * The `Animated` namespace, with `View` behind a getter so merely importing this module never\n * touches the peer. The component identity it returns is stable (the peer's own `Animated.View`, or\n * the module-level `StaticAnimatedView`), so React never remounts the tree under it.\n */\nexport const Animated: {\n readonly View: ComponentType<AnimatedViewProps>;\n createAnimatedComponent: <P extends object>(component: ComponentType<P>) => AnimatedComponent<P>;\n} = {\n get View() {\n return api().View;\n },\n createAnimatedComponent: (component) => api().createAnimatedComponent(component),\n};\n\n/** Layout-animation descriptors. `.duration()` is the only builder the kit uses. */\nexport const FadeIn = { duration: (durationMs: number): unknown => api().fadeIn(durationMs) };\nexport const FadeOut = { duration: (durationMs: number): unknown => api().fadeOut(durationMs) };\n\nexport const useSharedValue = <T,>(initial: T): SharedValue<T> => api().useSharedValue(initial);\nexport const useAnimatedStyle = (factory: () => ViewStyle): ViewStyle =>\n api().useAnimatedStyle(factory);\nexport const useAnimatedProps = <P extends object>(factory: () => P): P =>\n api().useAnimatedProps(factory);\nexport const useReducedMotion = (): boolean => api().useReducedMotion();\nexport const withTiming = (toValue: number, config?: object): number =>\n api().withTiming(toValue, config);\nexport const withRepeat = (animation: number, count?: number, reverse?: boolean): number =>\n api().withRepeat(animation, count, reverse);\nexport const withSequence = (...animations: number[]): number => api().withSequence(...animations);\nexport const withDelay = (ms: number, animation: number): number => api().withDelay(ms, animation);\n","import React, { useEffect, useMemo, type ReactNode } from \"react\";\nimport { StyleSheet, View } from \"react-native\";\n\nimport {\n Animated,\n useAnimatedStyle,\n useReducedMotion,\n useSharedValue,\n withDelay,\n withRepeat,\n withSequence,\n withTiming,\n} from \"./reanimated\";\nimport type { GestureKind } from \"./types\";\n\n/**\n * Abstract gesture pictogram shown beside a coachmark tooltip. With the OPTIONAL\n * `react-native-reanimated` peer installed every animation runs on the UI thread\n * (shared values + worklets), never setState, so it costs nothing on the JS\n * thread. Honors Reduce Motion by dropping the motion loop and rendering the\n * glyph static.\n *\n * The peer is reached through the guarded lazy require in `reanimated.ts`, never\n * a static import, so `@wireai/activation/coachmarks` (and `/showcase`, which\n * reaches this component through FeatureShowcase) builds on a host that never\n * installed it. Absent, the glyph renders STATICALLY at its resting frame — the\n * same capsules, ring, dot and motion track, at full opacity and no travel, with\n * one render instead of a UI-thread loop. The pictogram never disappears.\n *\n * NO drawn-hand anatomy. Swipes render the standard two-finger swipe glyph: two\n * rounded vertical capsules (an abstract index + middle finger, slightly\n * different heights) with a short, fading motion track trailing behind them along\n * the swipe axis. The whole glyph is rotated per direction (up/down/left/right)\n * and the capsules slide along the axis, fading, in a UI-thread loop. Pinch/zoom\n * reuse the two-capsule abstraction spreading apart. Tap / double-tap render a\n * minimal pulsing tap-target (ring + dot).\n *\n * Every glyph is a self-drawn primitive built from Views/borders (no vector-icon\n * dependency, like AnimatedSparkle). Pass `renderHand` — the glyph slot — to\n * substitute your own node while keeping the tuned motion. (The name is kept for\n * backward compatibility; despite it, the default is a glyph, not a drawn hand.)\n *\n * NOTE: the coachmark path (SpotlightOverlay) and the showcase path\n * (FeatureShowcase) both SKIP this component for `tap` / `double_tap` — those\n * steps show only the highlight ring + tooltip, no glyph. The tap visual here\n * exists for direct / standalone use.\n */\nexport interface GestureHintProps {\n type: GestureKind;\n /** Overall glyph size in px. */\n size?: number;\n /** Glyph color. Defaults to white (reads on the dark blur backdrop). */\n color?: string;\n /**\n * Provide a custom glyph node in place of the default self-drawn primitive; it\n * inherits the tuned motion (slide+fade for swipes, pulse for tap). Kept as\n * `renderHand` for backward compatibility — despite the name it is just the\n * glyph slot, no longer a drawn hand.\n */\n renderHand?: (props: { size: number; color: string }) => ReactNode;\n}\n\n/** Travel distance for the directional swipe loop (local glyph axis). */\nconst TRAVEL = 26;\nconst SWIPE_MS = 700;\nconst TAP_MS = 320;\nconst SPREAD_MS = 620;\n\n/**\n * Per-direction rotation of the whole glyph. Canonical orientation is \"up\":\n * capsules point up, travel up, motion track trailing below. Rotating the\n * container reorients both the capsules and the track together, and rotates the\n * local translate axis so the same upward loop reads correctly per direction.\n */\nconst GLYPH_ROTATION: Record<string, string> = {\n swipe_up: \"0deg\",\n swipe_down: \"180deg\",\n swipe_left: \"-90deg\",\n swipe_right: \"90deg\",\n};\n\n/**\n * The two-finger abstraction: two rounded vertical capsules side by side with\n * slightly different heights (index taller than middle), aligned at the base —\n * the standard swipe pictogram look. Self-drawn from Views only.\n */\nconst FingerPair: React.FC<{ size: number; color: string }> = ({ size, color }) => {\n const { row, index, middle } = useMemo(() => {\n const w = size * 0.2;\n const r = w / 2;\n return {\n row: { flexDirection: \"row\" as const, alignItems: \"flex-end\" as const, gap: size * 0.08 },\n index: { width: w, height: size * 0.54, borderRadius: r, backgroundColor: color },\n middle: { width: w, height: size * 0.44, borderRadius: r, backgroundColor: color },\n };\n }, [size, color]);\n\n return (\n <View style={row} pointerEvents=\"none\">\n <View style={index} />\n <View style={middle} />\n </View>\n );\n};\n\n/**\n * A short, tapering motion track that sits behind the capsules (below, in the\n * canonical \"up\" orientation) — two slim, fading ticks that shrink and dim with\n * distance. Subtle: it reads as the path the fingers just travelled, not a comet\n * tail. Static (the capsules carry the motion via the slide loop).\n */\nconst MotionTrack: React.FC<{ size: number; color: string }> = ({ size, color }) => {\n const { wrap, tick0, tick1 } = useMemo(() => {\n const h = Math.max(2, size * 0.05);\n return {\n wrap: { alignItems: \"center\" as const, marginTop: size * 0.1, gap: size * 0.06 },\n tick0: {\n width: size * 0.3,\n height: h,\n borderRadius: h / 2,\n backgroundColor: color,\n opacity: 0.4,\n },\n tick1: {\n width: size * 0.18,\n height: h,\n borderRadius: h / 2,\n backgroundColor: color,\n opacity: 0.16,\n },\n };\n }, [size, color]);\n\n return (\n <View style={wrap} pointerEvents=\"none\">\n <View style={tick0} />\n <View style={tick1} />\n </View>\n );\n};\n\nconst GestureHintComponent: React.FC<GestureHintProps> = ({\n type,\n size = 34,\n color = \"white\",\n renderHand,\n}) => {\n const translate = useSharedValue(0);\n const opacity = useSharedValue(1);\n const pulse = useSharedValue(1);\n const spread = useSharedValue(0);\n const reduced = useReducedMotion();\n\n const isSwipe =\n type === \"swipe_up\" ||\n type === \"swipe_down\" ||\n type === \"swipe_left\" ||\n type === \"swipe_right\";\n const isSpread = type === \"pinch\" || type === \"zoom\";\n const isTap = type === \"tap\" || type === \"double_tap\";\n\n useEffect(() => {\n if (type === \"none\" || reduced) return undefined;\n\n if (isTap) {\n pulse.value = withRepeat(\n withSequence(\n withTiming(0.82, { duration: TAP_MS }),\n withTiming(1, { duration: TAP_MS }),\n ),\n -1,\n false,\n );\n opacity.value = withRepeat(\n withSequence(\n withTiming(0.55, { duration: TAP_MS }),\n withTiming(1, { duration: TAP_MS }),\n ),\n -1,\n false,\n );\n return undefined;\n }\n\n if (isSpread) {\n // Two capsules easing apart and back — a minimal pinch/zoom abstraction.\n spread.value = withRepeat(\n withSequence(\n withTiming(size * 0.26, { duration: SPREAD_MS }),\n withTiming(0, { duration: SPREAD_MS }),\n ),\n -1,\n false,\n );\n return undefined;\n }\n\n // Directional swipe: slide the capsules along the local \"up\" axis, fading\n // out, then snap back and repeat. The container rotation (below) reorients\n // this loop per direction, so the local motion is always the same.\n translate.value = withRepeat(\n withSequence(\n withTiming(0, { duration: 0 }),\n withTiming(-TRAVEL, { duration: SWIPE_MS }),\n withDelay(140, withTiming(0, { duration: 0 })),\n ),\n -1,\n false,\n );\n opacity.value = withRepeat(\n withSequence(\n withTiming(1, { duration: SWIPE_MS / 2 }),\n withTiming(0, { duration: SWIPE_MS / 2 }),\n withDelay(140, withTiming(1, { duration: 0 })),\n ),\n -1,\n false,\n );\n return undefined;\n }, [type, reduced, isTap, isSpread, translate, opacity, pulse, spread, size]);\n\n const swipeAnimatedStyle = useAnimatedStyle(() => ({\n opacity: opacity.value,\n transform: [{ translateY: translate.value }],\n }));\n const tapAnimatedStyle = useAnimatedStyle(() => ({\n opacity: opacity.value,\n transform: [{ scale: pulse.value }],\n }));\n const spreadLeftStyle = useAnimatedStyle(() => ({\n transform: [{ translateX: -spread.value }],\n }));\n const spreadRightStyle = useAnimatedStyle(() => ({\n transform: [{ translateX: spread.value }],\n }));\n\n if (type === \"none\") return null;\n\n const customGlyph = renderHand ? renderHand({ size, color }) : null;\n\n if (isSwipe) {\n return (\n <View\n style={{ transform: [{ rotate: GLYPH_ROTATION[type] ?? \"0deg\" }] }}\n pointerEvents=\"none\"\n >\n <View style={styles.swipeStack}>\n <Animated.View style={swipeAnimatedStyle} pointerEvents=\"none\">\n {customGlyph ?? <FingerPair size={size} color={color} />}\n </Animated.View>\n <MotionTrack size={size} color={color} />\n </View>\n </View>\n );\n }\n\n if (isSpread) {\n const w = size * 0.2;\n const capsule = {\n width: w,\n height: size * 0.5,\n borderRadius: w / 2,\n backgroundColor: color,\n };\n return (\n <View style={[styles.spreadRow, { gap: size * 0.12 }]} pointerEvents=\"none\">\n <Animated.View style={spreadLeftStyle}>\n <View style={capsule} />\n </Animated.View>\n <Animated.View style={spreadRightStyle}>\n <View style={capsule} />\n </Animated.View>\n </View>\n );\n }\n\n // tap / double_tap — a minimal pulsing tap-target (ring + center dot).\n const ringSize = size * 0.86;\n const ringBorder = Math.max(2, size * 0.08);\n const dotSize = size * 0.32;\n return (\n <View style={[styles.tapWrap, { width: size, height: size }]} pointerEvents=\"none\">\n {customGlyph ? (\n <Animated.View style={tapAnimatedStyle} pointerEvents=\"none\">\n {customGlyph}\n </Animated.View>\n ) : (\n <>\n <Animated.View\n style={[\n styles.tapRing,\n {\n width: ringSize,\n height: ringSize,\n borderRadius: ringSize / 2,\n borderWidth: ringBorder,\n borderColor: color,\n },\n tapAnimatedStyle,\n ]}\n pointerEvents=\"none\"\n />\n <View\n style={{\n position: \"absolute\",\n width: dotSize,\n height: dotSize,\n borderRadius: dotSize / 2,\n backgroundColor: color,\n }}\n />\n </>\n )}\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n swipeStack: {\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n spreadRow: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n tapWrap: {\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n tapRing: {\n backgroundColor: \"transparent\",\n },\n});\n\nexport const GestureHint = React.memo(GestureHintComponent);\nGestureHint.displayName = \"GestureHint\";\n\nexport default GestureHint;\n","/**\n * Module-level runtime for the coachmark engine: the injected sync storage, the\n * global `isTestingCoachmark` flag, and the seen-gate helpers built on top.\n *\n * WHY module singletons (not just context): the tour hooks and the anchor\n * registry are driven imperatively from anywhere in the tree (a screen deep\n * under the navigator), while the storage + testing flag are configured once at\n * the root by `CoachmarkProvider`. Singletons let a hook read the gate without\n * every call site threading the storage through props. The provider is still the\n * single writer — it calls `setCoachmarkStorage` / `setCoachmarkTesting` on mount.\n *\n * ── WHY A globalThis SLOT, NOT PLAIN MODULE VARIABLES ─────────────────────────────────────────\n * These three values used to be plain module `let`s, and this module is inlined by tsup into FOUR\n * dist bundles (`./coachmarks`, `./reviews`, `./questionnaire`, `./showcase`). Under `dist`\n * resolution — node `import`/`require`, SSR, jest, RN-web, anything that is not Metro — a host that\n * mounts `CoachmarkProvider` from `@wireai/activation/coachmarks` wrote the COACHMARKS copy, while\n * `useReviewGate` from `@wireai/activation/reviews` read the REVIEWS copy, which was still `null`.\n * Everything downstream then failed silently: `readInt(null, …)` returns 0, so `bumpSessionCount`\n * returns 1 forever and the fail-closed `minSessions: 2` default is unsatisfiable (the gate NEVER\n * fires); the `seen` once-gate never persists; and a tenant's coachmarks kill switch never reaches\n * the reviews bundle. Metro masked it by collapsing every subpath back to one `src/` file through\n * the `react-native` export condition, which is a bundler accident, not a guarantee.\n *\n * Same remedy this repo already applies to `currentSession`, the auto device-key registry and the\n * activation revalidation counter: ONE record in a `globalThis` slot keyed by `Symbol.for(...)`, so\n * every inlined copy of this module addresses the SAME state.\n */\nimport type { CoachmarkStorage } from \"./types\";\n\n/**\n * Well-known key into the runtime-global symbol registry — one coachmark runtime across bundles.\n *\n * @globalSlot LATCH — the RUNTIME RECORD is created once and its identity is then stable. A second\n * write replaces the record `subscribeCoachmarksEnabled` registered its listeners on, so a\n * kill-switch flip notifies an orphaned set while a tour that believes it is running paints nothing\n * — the exact limbo `coachmarkKillSwitch` canaries. Its FIELDS (`storage`, `testing`,\n * `coachmarksEnabled`, `listeners`) are live, which is why every accessor calls `coachmarkRuntime()`\n * instead of holding the record, and why `coachmarksEnabled` is subscribable rather than sampled.\n */\nconst COACHMARK_RUNTIME_SLOT: unique symbol = Symbol.for(\"@wireai/activation:coachmarkRuntime\");\n\n/** The shared runtime: the provider-injected storage, the QA replay flag, and the kill switch. */\ntype CoachmarkRuntime = {\n storage: CoachmarkStorage | null;\n testing: boolean;\n // The coachmarks feature kill switch (from GET /v1/features). Default true = fail-open: with no\n // flags fetched, coachmarks behave exactly as before. CoachmarkProvider writes it from the\n // resolved flags. Disabled → the tour never ARMS and the overlay `show()` is a no-op, so nothing\n // paints and — critically — no once-gate is written, so re-enabling replays the tour correctly.\n coachmarksEnabled: boolean;\n // Subscribers to the kill switch. OPTIONAL on the type (never on the behaviour) so a record left\n // in the registry by an inlined copy from an OLDER kit version — which had no listener set — is\n // upgraded in place rather than read as corrupt.\n listeners?: Set<() => void>;\n};\n\ntype GlobalWithCoachmarkRuntime = typeof globalThis & {\n [COACHMARK_RUNTIME_SLOT]?: CoachmarkRuntime;\n};\n\nconst runtimeGlobal = globalThis as GlobalWithCoachmarkRuntime;\n\nconst coachmarkRuntime = (): CoachmarkRuntime => {\n const existing = runtimeGlobal[COACHMARK_RUNTIME_SLOT];\n if (existing) return existing;\n const created: CoachmarkRuntime = { storage: null, testing: false, coachmarksEnabled: true };\n runtimeGlobal[COACHMARK_RUNTIME_SLOT] = created;\n return created;\n};\n\nconst enabledListeners = (): Set<() => void> => {\n const runtime = coachmarkRuntime();\n if (!runtime.listeners) runtime.listeners = new Set();\n return runtime.listeners;\n};\n\n/**\n * Wake the subscribers on a MICROTASK, never synchronously.\n *\n * `CoachmarkProvider` writes this flag during its RENDER phase on purpose (so a child's mount\n * effect already sees the resolved value). Notifying from there synchronously would schedule a\n * React update while a *different* component is rendering. Every subscriber reads the value\n * through `areCoachmarksEnabled()` at render time anyway, so the notification only has to wake\n * the components that are not already re-rendering — one microtask later is soon enough, and it\n * keeps the write side legal from anywhere.\n */\nconst notifyCoachmarksEnabled = (): void => {\n if (enabledListeners().size === 0) return;\n void Promise.resolve().then(() => {\n for (const listener of [...enabledListeners()]) {\n try {\n listener();\n } catch {\n // A broken subscriber must never break the kill switch for the others.\n }\n }\n });\n};\n\n/**\n * Set the coachmarks master switch (from the resolved feature flags). Default true (fail-open).\n * Written by CoachmarkProvider; read imperatively by the tour arm + the overlay store, and\n * SUBSCRIBED to by `useCoachmarkTour` (see `subscribeCoachmarksEnabled`).\n *\n * No-ops when the value is unchanged, which matters because the provider writes it on every\n * render — without that guard every render would fan out a notification.\n */\nexport const setCoachmarksEnabled = (value: boolean): void => {\n const runtime = coachmarkRuntime();\n if (runtime.coachmarksEnabled === value) return;\n runtime.coachmarksEnabled = value;\n notifyCoachmarksEnabled();\n};\n\n/** Whether the coachmarks module is enabled. False → tours/overlays are silently skipped. */\nexport const areCoachmarksEnabled = (): boolean => coachmarkRuntime().coachmarksEnabled;\n\n/**\n * Subscribe to kill-switch flips. Returns the unsubscribe function — the `useSyncExternalStore`\n * contract, and deliberately the SAME shape as `coachmarkOverlay.subscribe` next door rather than\n * a second pattern to keep correct.\n *\n * WHY IT EXISTS: the flag is a mutable `globalThis` value, so on its own it can only be SAMPLED.\n * A tour that samples it cannot notice a tenant flipping it off mid-flight — the overlay's\n * `show()` quietly becomes a no-op while the tour still believes it is running, so nothing paints,\n * nothing can be tapped to advance, and no terminal path is reachable. `useCoachmarkTour`\n * subscribes instead. The listener set lives in the SAME `globalThis` record as the flag, so every\n * inlined copy of this module shares one subscriber list.\n */\nexport const subscribeCoachmarksEnabled = (listener: () => void): (() => void) => {\n const listeners = enabledListeners();\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\n/** Set (or clear) the injected sync gate storage. Called by CoachmarkProvider. */\nexport const setCoachmarkStorage = (storage: CoachmarkStorage | null): void => {\n coachmarkRuntime().storage = storage;\n};\n\n/** The currently-injected gate storage, or null if no provider is mounted. */\nexport const getCoachmarkStorage = (): CoachmarkStorage | null => coachmarkRuntime().storage;\n\n/**\n * Toggle the global QA replay flag. When true, EVERY seen-gate reads as unseen\n * and every seen-write is suppressed, so every tour + showcase replays on each\n * mount. The app flips ONE boolean to QA the whole coachmark surface.\n */\nexport const setCoachmarkTesting = (value: boolean): void => {\n coachmarkRuntime().testing = value;\n};\n\n/** Whether replay-everything QA mode is on. */\nexport const isCoachmarkTesting = (): boolean => coachmarkRuntime().testing;\n\n/** Gate key for a tour: `wire_coachmark_<tourId>_seen`. */\nexport const coachmarkGateKey = (tourId: string): string =>\n `wire_coachmark_${tourId}_seen`;\n\n/** Gate key for a feature showcase: `wire_showcase_<id>_seen`. */\nexport const showcaseGateKey = (showcaseId: string): string =>\n `wire_showcase_${showcaseId}_seen`;\n\n/** Marker value written for a seen gate. */\nconst SEEN_VALUE = \"1\";\n\n/**\n * Read a seen gate. Testing mode ALWAYS reports unseen (so everything replays).\n * A missing storage (no provider) also reports unseen — the safe default is to\n * show the hint rather than silently swallow it. `storageOverride` /\n * `testingOverride` let a self-contained component (e.g. FeatureShowcase) pass\n * its own storage without relying on the provider singleton.\n */\nexport const hasSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): boolean => {\n if (testingOverride ?? isCoachmarkTesting()) return false;\n const storage = storageOverride ?? getCoachmarkStorage();\n if (!storage) return false;\n try {\n return storage.getItem(key) === SEEN_VALUE;\n } catch {\n return false;\n }\n};\n\n/**\n * Mark a gate seen. Suppressed in testing mode (so replay never persists) and a\n * no-op without storage. Best-effort — a throwing adapter never breaks the tour.\n */\nexport const markSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): void => {\n if (testingOverride ?? isCoachmarkTesting()) return;\n const storage = storageOverride ?? getCoachmarkStorage();\n if (!storage) return;\n try {\n storage.setItem(key, SEEN_VALUE);\n } catch {\n // Best-effort: a failed write just means the hint may show once more.\n }\n};\n","/**\n * The fail-open defaults + a tolerant parser for the server's flags payload.\n *\n * THE CONTRACT: fail-open, never fail-dark. An absent server object, a missing module key, a\n * malformed value, or an unreachable endpoint must resolve to the MOST PERMISSIVE state — every\n * module ON, onboarding `ai` — so a control-plane outage can only ever be more permissive than\n * the dashboard intends. It can never dark a tenant's activation. Matches the server's own\n * documented fail-open default (FEATURES.md: \"local defaults — every module on, onboarding ai\").\n */\nimport type { OnboardingMode, WireFeatures } from \"./types\";\n\n/**\n * ALL ON, onboarding `ai`. Frozen + module-level so its reference is stable across every call\n * (consumers that list resolved flags in an effect dep array never loop on a fresh identity).\n */\nexport const defaultWireFeatures: WireFeatures = Object.freeze({\n coachmarks: Object.freeze({ enabled: true }),\n showcase: Object.freeze({ enabled: true }),\n onboarding: Object.freeze({ mode: \"ai\" as OnboardingMode }),\n review: Object.freeze({ enabled: true }),\n questionnaire: Object.freeze({ enabled: true }),\n announcements: Object.freeze({ enabled: true }),\n}) as WireFeatures;\n\nconst VALID_MODES: readonly OnboardingMode[] = [\"ai\", \"static\", \"off\"];\n\n/** Read a `{ enabled: boolean }` module, defaulting to ON when absent/malformed (fail-open). */\nconst readEnabled = (raw: unknown): { enabled: boolean } => {\n if (raw && typeof raw === \"object\" && typeof (raw as { enabled?: unknown }).enabled === \"boolean\") {\n return { enabled: (raw as { enabled: boolean }).enabled };\n }\n return { enabled: true };\n};\n\n/**\n * Narrow the server's (untrusted) JSON to a complete `WireFeatures`. Every field is filled with\n * its fail-open default when the server omits it or sends the wrong type, so a partial or\n * malformed payload degrades PERMISSIVELY rather than throwing. A non-object input (null, array,\n * string) → the full defaults. Never throws.\n */\nexport const parseWireFeatures = (raw: unknown): WireFeatures => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return defaultWireFeatures;\n const src = raw as Record<string, unknown>;\n const modeRaw = (src.onboarding as { mode?: unknown } | undefined)?.mode;\n const mode: OnboardingMode =\n typeof modeRaw === \"string\" && VALID_MODES.includes(modeRaw as OnboardingMode)\n ? (modeRaw as OnboardingMode)\n : \"ai\";\n return {\n coachmarks: readEnabled(src.coachmarks),\n showcase: readEnabled(src.showcase),\n onboarding: { mode },\n review: readEnabled(src.review),\n questionnaire: readEnabled(src.questionnaire),\n announcements: readEnabled(src.announcements),\n };\n};\n\n/** Value-equality of two resolved flags — lets the hook hold a stable reference across churn. */\nexport const featuresEqual = (a: WireFeatures, b: WireFeatures): boolean =>\n a === b ||\n (a.coachmarks.enabled === b.coachmarks.enabled &&\n a.showcase.enabled === b.showcase.enabled &&\n a.onboarding.mode === b.onboarding.mode &&\n a.review.enabled === b.review.enabled &&\n a.questionnaire.enabled === b.questionnaire.enabled &&\n a.announcements.enabled === b.announcements.enabled);\n","/**\n * The last-known-flags cache — persisted through the host's optional `storage`.\n *\n * WHY: the fetch is best-effort and fail-open. When the control plane is unreachable we serve the\n * LAST value we saw rather than snapping to defaults, so a tenant that intentionally disabled a\n * module during an incident keeps it disabled across an outage instead of flapping back on. That\n * is \"stale-while-error\": a fresh cache (< TTL) is trusted, and on a fetch error even a STALE\n * cache is served (any age beats a guess). Every operation is best-effort — a broken/hung storage\n * degrades to defaults, never a throw and never a stuck gate (mirrors persistedSession).\n */\nimport { parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\n/**\n * TTL for a cached flags entry, aligned to the server's `Cache-Control: private, max-age=300`.\n * A cache younger than this is \"fresh\"; older is \"stale\" (still served on a fetch error).\n */\nexport const DEFAULT_FEATURES_TTL_MS = 300_000;\n\n/** Ceiling on the storage read so a hung adapter degrades to defaults, never a stuck resolve. */\nconst READ_TIMEOUT_MS = 1_500;\n\n/** Storage key for a tenant's cached flags, e.g. `wireai:features:acme`. */\nexport const featuresCacheKey = (appId?: string): string =>\n `wireai:features:${appId && appId.length > 0 ? appId : \"default\"}`;\n\n/** A cached flags entry: the resolved flags + the epoch-ms they were fetched. */\nexport interface CachedFeatures {\n features: WireFeatures;\n /** Age of the entry in ms at read time. */\n ageMs: number;\n}\n\nconst withTimeout = <T>(p: Promise<T>, ms: number): Promise<T | undefined> => {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), ms);\n });\n return Promise.race([p, timeout]).finally(() => clearTimeout(timer));\n};\n\n/** Whether a cache entry is still within the TTL (server max-age aligned). */\nexport const isFeaturesFresh = (ageMs: number, ttlMs: number = DEFAULT_FEATURES_TTL_MS): boolean =>\n ageMs >= 0 && ageMs < ttlMs;\n\n/**\n * Read the cached flags for `key`, or `undefined` when absent/corrupt/timed-out. Returns the\n * value AND its age so a caller can apply a TTL (fresh) or ignore it (stale-while-error). Never\n * throws; never hangs past the read timeout. The stored value is re-parsed through\n * `parseWireFeatures`, so a partially-corrupt entry still degrades fail-open.\n */\nexport const readCachedFeatures = async (\n storage: WireOnboardingStorage,\n key: string,\n): Promise<CachedFeatures | undefined> => {\n let raw: string | null | undefined;\n try {\n raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);\n } catch {\n return undefined;\n }\n if (!raw) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && typeof (parsed as { ts?: unknown }).ts === \"number\") {\n const ts = (parsed as { ts: number }).ts;\n return {\n features: parseWireFeatures((parsed as { features?: unknown }).features),\n ageMs: Date.now() - ts,\n };\n }\n } catch {\n // Corrupt entry → treat as absent; the caller falls back to defaults / a fresh fetch.\n }\n return undefined;\n};\n\n/** Persist `{ features, ts }` under `key` — fire-and-forget, all errors swallowed. */\nexport const writeCachedFeatures = (\n storage: WireOnboardingStorage,\n key: string,\n features: WireFeatures,\n): void => {\n try {\n void storage\n .setItem(key, JSON.stringify({ features, ts: Date.now() }))\n .catch(() => {});\n } catch {\n // Best-effort: a failed write just means the next launch has no cache to fall back to.\n }\n};\n","/**\n * fetchWireFeatures — read the per-module kill switches from `GET {serverUrl}/v1/features`.\n *\n * Contract (server: chohra-med/wireai-onboarding-server, routers/onboarding.py):\n * GET {serverUrl}/v1/features\n * Authorization: Bearer {apiKey}\n * 200 → { coachmarks:{enabled}, showcase:{enabled}, onboarding:{mode}, review:{enabled},\n * announcements:{enabled} } (Cache-Control: private, max-age=300)\n *\n * THE CONTRACT — fail-open, never fail-dark. Unreachable, timed-out, unauthorized (401),\n * server-error (5xx), or malformed JSON all resolve to the LAST CACHED value, else the\n * all-on defaults. No throw ever reaches the host: this is timeout-capped and swallows every\n * error, exactly like the session's best-effort reads. A control-plane outage can only ever be\n * MORE permissive than the dashboard intends — it can never dark a tenant's activation.\n */\nimport { readCachedFeatures, featuresCacheKey, writeCachedFeatures } from \"./cache\";\nimport { defaultWireFeatures, parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\nconst DEFAULT_TIMEOUT_MS = 4_000;\n\n/** The fail-open fallback: last cached value (any age — stale-while-error), else defaults. */\nconst failOpen = async (\n storage: WireOnboardingStorage | undefined,\n key: string,\n): Promise<WireFeatures> => {\n if (!storage) return defaultWireFeatures;\n const cached = await readCachedFeatures(storage, key);\n return cached?.features ?? defaultWireFeatures;\n};\n\n/** GET with a hard timeout via AbortController (falls back to no-abort where unsupported). */\nconst fetchWithTimeout = async (\n url: string,\n apiKey: string,\n timeoutMs: number,\n): Promise<Response> => {\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : undefined;\n const timer = setTimeout(() => controller?.abort(), timeoutMs);\n try {\n return await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\", Authorization: `Bearer ${apiKey}` },\n signal: controller?.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n};\n\n/**\n * Resolve the tenant's feature flags. Attempts the network once; on ANY failure returns the\n * cached value (any age), else the all-on defaults. On success, persists the fresh value to the\n * cache (fire-and-forget) and returns it. Never throws.\n *\n * const flags = await fetchWireFeatures({ serverUrl, apiKey, appId, storage });\n * if (!flags.coachmarks.enabled) { /* skip the tour * / }\n */\nexport const fetchWireFeatures = async (\n config?: WireFeaturesConfig,\n): Promise<WireFeatures> => {\n const key = featuresCacheKey(config?.appId);\n const storage = config?.storage;\n\n // Nothing to fetch (no creds) → cache, else defaults. Lets a host mount the provider before\n // its config is ready without ever darking.\n if (!config?.serverUrl || !config?.apiKey) return failOpen(storage, key);\n\n const url = `${config.serverUrl.replace(/\\/$/, \"\")}/v1/features`;\n const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;\n\n try {\n const res = await fetchWithTimeout(url, config.apiKey, timeoutMs);\n // 401 (bad/rotated key), 5xx, any non-2xx → last-known, never dark.\n if (!res || !res.ok) return failOpen(storage, key);\n const json: unknown = await res.json(); // throws on malformed body → caught below\n const features = parseWireFeatures(json);\n if (storage) writeCachedFeatures(storage, key, features);\n return features;\n } catch {\n // Timeout/abort, network error, missing fetch, or malformed JSON — all fail open.\n return failOpen(storage, key);\n }\n};\n","/**\n * useWireFeatures — resolve the tenant's feature flags for a component tree, once per mount.\n *\n * Returns the all-on defaults immediately (fail-open), then swaps to the fetched value when the\n * network resolves. When no `serverUrl`+`apiKey` is supplied it never fetches and just returns\n * defaults, so a host that never adopts flags sees ZERO behavior change and ZERO network calls.\n *\n * frequent_rules #11 (unstable inline props): the config is idiomatically passed inline\n * (`config={{ serverUrl, apiKey }}`), a fresh identity every render. We stabilize the fetch key\n * by VALUE so the effect fires once per real credential change, and we only swap the returned\n * flags object when its VALUES change — so a host that lists the returned flags in an effect dep\n * array settles in a bounded number of commits instead of looping (enforced by the canary suite).\n */\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { defaultWireFeatures, featuresEqual } from \"./defaults\";\nimport { fetchWireFeatures } from \"./fetchWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\n/** Hold a stable reference for a value while its CONTENT is unchanged (see reviews/equality.ts). */\nconst useStableValue = <T,>(value: T, isEqual: (a: T, b: T) => boolean): T => {\n const ref = useRef(value);\n if (!isEqual(ref.current, value)) ref.current = value;\n return ref.current;\n};\n\n/** The credential slice that actually drives a refetch — stabilized by value. */\nconst sameFetchKey = (a: WireFeaturesConfig | undefined, b: WireFeaturesConfig | undefined): boolean =>\n a?.serverUrl === b?.serverUrl && a?.apiKey === b?.apiKey && a?.appId === b?.appId;\n\nexport const useWireFeatures = (config?: WireFeaturesConfig): WireFeatures => {\n const stableConfig = useStableValue(config, sameFetchKey);\n const [flags, setFlags] = useState<WireFeatures>(defaultWireFeatures);\n\n const canFetch = !!stableConfig?.serverUrl && !!stableConfig?.apiKey;\n\n useEffect(() => {\n if (!canFetch) {\n // No creds → stay on the all-on defaults (and reset if creds were removed).\n setFlags((prev) => (featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures));\n return;\n }\n let alive = true;\n // fetchWireFeatures never throws — the .then always runs with a fail-open value.\n void fetchWireFeatures(stableConfig).then((next) => {\n if (!alive) return;\n // Only adopt a NEW reference on a real value change, so a host effect keyed on the\n // returned flags doesn't loop (frequent_rules #11).\n setFlags((prev) => (featuresEqual(prev, next) ? prev : next));\n });\n return () => {\n alive = false;\n };\n }, [canFetch, stableConfig]);\n\n return flags;\n};\n","/**\n * WireFeaturesProvider + useResolvedFeatures — the OPTIONAL one-fetch-serves-all-modules layer.\n *\n * Mount `WireFeaturesProvider` once near your app root with the tenant `config` and it fetches the\n * flags ONCE; every gated surface below it (coachmarks / showcase / reviews) reads the same\n * resolved value from context instead of each fetching its own. It is entirely optional: with no\n * provider, every surface falls back to its own lazy fetch (when given a config) or to the all-on\n * defaults, so modules work with zero setup and a host that never adopts flags is unchanged.\n *\n * NOTE on the built npm subpaths: React context is shared across the kit's subpath entries in the\n * SOURCE-consumption path (the monorepo apps) and in this test suite — one module instance, one\n * context. If you consume the built `@wireai/activation/*` subpaths as separate bundles, pass the\n * resolved flags (or a `featuresConfig`) to each surface explicitly instead of relying on context.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\n\nimport { defaultWireFeatures } from \"./defaults\";\nimport { useWireFeatures } from \"./useWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\n/**\n * @globalSlot LATCH — the React context object is minted by the first copy of this module to load\n * and every later copy ADOPTS it (the `if (!…)` guard below). A second write would re-split the\n * identity the guard exists to keep whole: the provider would publish into one context while a\n * subpath bundle's `useContext` read another, and `useResolvedFeatures`' null fallback would serve\n * the all-on defaults with no crash and no warning. Because it is a latch, and only because of\n * that, the module-local `const WireFeaturesContext` below may cache it.\n */\nconst CONTEXT_SYMBOL = Symbol.for(\"wireai.features.context\");\n// `globalThis`, not `global`: the other nine `Symbol.for` slots in this kit all use it, and `global`\n// simply does not exist in a plain browser (RN-web / SSR-in-the-browser), where this line would\n// throw a ReferenceError before the provider could render anything.\nconst globalObj = globalThis as any;\n\nif (!globalObj[CONTEXT_SYMBOL]) {\n globalObj[CONTEXT_SYMBOL] = createContext<WireFeatures | null>(null);\n}\nconst WireFeaturesContext = globalObj[CONTEXT_SYMBOL];\n\nexport interface WireFeaturesProviderProps {\n /** Tenant creds (+ optional storage) to fetch the flags once for the whole tree. */\n config?: WireFeaturesConfig;\n /**\n * Pre-resolved flags to provide directly instead of fetching (e.g. you already have them, or\n * you drive them from your own remote-config). Takes precedence over `config`.\n */\n flags?: WireFeatures;\n children: React.ReactNode;\n}\n\n/**\n * Fetch (or accept) the flags once and broadcast them to descendants. The provider VALUE is\n * memoized (performance rule #6) so a fresh object each render doesn't re-render every consumer.\n */\nexport const WireFeaturesProvider: React.FC<WireFeaturesProviderProps> = ({\n config,\n flags,\n children,\n}) => {\n // Always call the hook (rules of hooks); when `flags` is supplied we pass no config so it\n // never fetches and the explicit flags win below.\n const fetched = useWireFeatures(flags ? undefined : config);\n const value = flags ?? fetched;\n const stable = useMemo(() => value, [value]);\n return <WireFeaturesContext.Provider value={stable}>{children}</WireFeaturesContext.Provider>;\n};\n\nWireFeaturesProvider.displayName = \"WireFeaturesProvider\";\n\n/** Raw context read — `null` when no `WireFeaturesProvider` is mounted above. */\nexport const useWireFeaturesContext = (): WireFeatures | null =>\n useContext(WireFeaturesContext);\n\n/** Options for `useResolvedFeatures`: an explicit override and/or a lazy-fetch config. */\nexport interface ResolveFeaturesOptions {\n /** Explicit flags — win over everything (a surface's own `features` prop). */\n flags?: WireFeatures;\n /** Lazy-fetch config, used ONLY when there is no explicit `flags` and no provider above. */\n config?: WireFeaturesConfig;\n}\n\n/**\n * The resolution every gated surface uses. Precedence:\n * 1. explicit `options.flags` (a surface's own prop) →\n * 2. the nearest `WireFeaturesProvider` (context) →\n * 3. a lazy fetch from `options.config` (serverUrl + apiKey) →\n * 4. the all-on defaults.\n * Always fail-open, always a stable reference for a given value (so it's safe in effect deps).\n */\nexport const useResolvedFeatures = (options?: ResolveFeaturesOptions): WireFeatures => {\n const ctx = useWireFeaturesContext();\n // Only lazily fetch when nothing else provides the flags — otherwise pass no config so the\n // hook stays inert (defaults, no network). The hook is always called (rules of hooks).\n const shouldFetch = !options?.flags && ctx == null;\n const fetched = useWireFeatures(shouldFetch ? options?.config : undefined);\n return options?.flags ?? ctx ?? fetched ?? defaultWireFeatures;\n};\n","/**\n * defaultOnboardingTheme — a neutral, light, brand-agnostic baseline. Consumers\n * pass a `Partial<OnboardingTheme>` that is deep-merged over this (see\n * `mergeTheme`), so they only override what differs from neutral.\n */\nimport type { OnboardingTheme } from \"./types\";\n\nexport const defaultOnboardingTheme: OnboardingTheme = {\n colors: {\n background: \"#FFFFFF\",\n surface: \"#F7F7F8\",\n text: \"#101114\",\n textMuted: \"#6B7280\",\n primary: \"#111111\",\n onPrimary: \"#FFFFFF\",\n primarySoft: \"rgba(17,17,17,0.06)\",\n border: \"#E4E4E7\",\n borderStrong: \"#C7C7CC\",\n disabled: \"#EBEBEB\",\n success: \"#16A34A\",\n warning: \"#D97706\",\n error: \"#DC2626\",\n info: \"#2563EB\",\n },\n fonts: {\n regular: undefined,\n medium: undefined,\n bold: undefined,\n baseSize: 16,\n scale: 1,\n },\n radius: {\n sm: 8,\n md: 12,\n lg: 16,\n full: 9999,\n },\n spacing: {\n xs: 4,\n sm: 8,\n md: 16,\n lg: 24,\n xl: 32,\n },\n // Circled (pill) CTA by default; an app can pass `button: { radius: 12 }` for\n // a rounded rectangle, or override height/paddingX to match its design system.\n button: {\n radius: 9999,\n height: 52,\n paddingX: 24,\n },\n};\n\n/**\n * Deep-merge a partial theme over the default. Two levels deep is enough — the\n * theme is intentionally shallow (colors/fonts/radius/spacing), so we merge each\n * known sub-object and leave scalars to overwrite.\n */\nexport const mergeTheme = (\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return defaultOnboardingTheme;\n return {\n colors: { ...defaultOnboardingTheme.colors, ...override.colors },\n fonts: { ...defaultOnboardingTheme.fonts, ...override.fonts },\n radius: { ...defaultOnboardingTheme.radius, ...override.radius },\n spacing: { ...defaultOnboardingTheme.spacing, ...override.spacing },\n button: { ...defaultOnboardingTheme.button, ...override.button },\n };\n};\n","/**\n * ThemeContext — provides the resolved OnboardingTheme to every shell element and\n * themed card via `useOnboardingTheme()`. WHY a context rather than prop-drilling:\n * the cards are mounted by the SDK's ComponentRenderer (not by us), so we can't\n * pass them props directly — they must read the theme from context.\n *\n * ── WHY THE CONTEXT LIVES ON A `Symbol.for` SLOT ───────────────────────────────────────────────\n *\n * It was a plain `createContext(...)`, and tsup inlines this module into FIVE dist bundles\n * (`.`, `./reviews`, `./questionnaire`, `./coachmarks`, `./showcase`) — so each one carried its own\n * context instance. `OnboardingThemeProvider` is exported ONLY from the root barrel, so on any\n * `dist` resolution path (plain RN CLI, `unstable_enablePackageExports: false`, node, jest, SSR) a\n * host that wrapped its tree in `<OnboardingThemeProvider>` and rendered `<ReviewGate>` from\n * `@wireai/activation/reviews` was writing one context and reading another. Nothing crashed and\n * nothing warned: `useOnboardingTheme`'s `ctx ?? mergeTheme()` fallback quietly served the NEUTRAL\n * default theme, so the tenant's brand simply did not apply to the gate. On-device this was masked\n * only because Metro's `react-native` export condition collapses every subpath back to this one\n * `src/` file — the same \"bundler accident, not a guarantee\" the `currentSession` header names, and\n * the same root cause as the optional-peers bug 0.13.3 fixed.\n *\n * The bundler-agnostic fix, exactly as `coachmarks/runtime`, `analytics/currentSession`,\n * `context/deviceId` and `features/WireFeaturesProvider` already do it: park the ONE context on a\n * well-known `globalThis` slot keyed by `Symbol.for(...)`. `Symbol.for` uses the runtime-global\n * symbol registry, so every inlined copy of this module resolves the SAME symbol, finds the slot\n * already filled, and reuses that instance — one context identity however many copies exist.\n * `globalThis` is present and identical in Hermes/React Native, Node and SSR (we never touch\n * `window`), so this is safe on every host. `test/canary/themeContextIdentity.test.tsx` measures it\n * in the BUILT artifact, because the defect is invisible in source.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { mergeTheme } from \"./defaultTheme\";\nimport type { OnboardingTheme } from \"./types\";\n\n/**\n * Well-known key into the runtime-global symbol registry. `Symbol.for` (NOT a plain `Symbol()`) is\n * what makes this cross-bundle: it returns the SAME symbol for the same string across every copy of\n * this module, so duplicated inlined copies all address one slot.\n *\n * @globalSlot LATCH — the React context object is minted by the first copy of this module to load\n * and every later copy ADOPTS it (the `if (!…)` guard below says so in one line). A second write\n * re-splits the identity: `<OnboardingThemeProvider>` (root barrel only) publishes into one context\n * while `<ReviewGate>` from a subpath reads another, and `useOnboardingTheme`'s `ctx ?? mergeTheme()`\n * fallback quietly serves the NEUTRAL theme. Because it is a latch, and only because of that, the\n * module-local `const OnboardingThemeContext` below may cache it.\n */\nconst THEME_CONTEXT_SLOT: unique symbol = Symbol.for(\"@wireai/activation:themeContext\");\n\ntype GlobalWithThemeContext = typeof globalThis & {\n [THEME_CONTEXT_SLOT]?: React.Context<OnboardingTheme | null>;\n};\n\nconst themeGlobal = globalThis as GlobalWithThemeContext;\n\n// First copy to load creates the context; every later copy adopts it. Never overwrite an existing\n// slot — a second `createContext` here would re-split the identity this guard exists to keep whole.\nif (!themeGlobal[THEME_CONTEXT_SLOT]) {\n themeGlobal[THEME_CONTEXT_SLOT] = createContext<OnboardingTheme | null>(null);\n}\nconst OnboardingThemeContext = themeGlobal[THEME_CONTEXT_SLOT] as React.Context<OnboardingTheme | null>;\n\nexport type OnboardingThemeProviderProps = {\n /** Partial overrides merged over the neutral default theme. */\n theme?: Partial<OnboardingTheme>;\n children: React.ReactNode;\n};\n\nexport const OnboardingThemeProvider: React.FC<OnboardingThemeProviderProps> = ({\n theme,\n children,\n}) => {\n const resolved = useMemo(() => mergeTheme(theme), [theme]);\n return (\n <OnboardingThemeContext.Provider value={resolved}>\n {children}\n </OnboardingThemeContext.Provider>\n );\n};\n\n/**\n * Read the active theme. Falls back to the default theme when used outside a\n * provider so a stray card never crashes — it just renders neutral.\n */\nexport const useOnboardingTheme = (): OnboardingTheme => {\n const ctx = useContext(OnboardingThemeContext);\n return ctx ?? mergeTheme();\n};\n","/**\n * blazejOnboarding — resolve `@blazejkustra/react-native-onboarding`, lazily and optionally.\n *\n * ── WHY THIS DOES NOT BREAK THE NO-NATIVE-DEPENDENCY POLICY ──────────────────────────────\n *\n * `@blazejkustra/react-native-onboarding` is an OPTIONAL peer of the showcase subpath — it is the\n * slide pager `FeatureShowcase` wraps. Before this file, `FeatureShowcase.tsx` imported its default\n * export at module scope, and `showcase/index.ts` re-exports the component with no wildcard escape,\n * so importing ANYTHING from `@wireai/activation/showcase` (even `selectShowcaseSlides`) dragged\n * the peer in, and a host that skipped the \"optional\" peer hit a Metro resolution failure. This\n * resolver removes that static edge. Same class and same shape as the 0.14.2 `expo-blur` fix\n * (`coachmarks/expoBlur.ts`), whose header carries the reasoning in full.\n *\n * The TYPES stay statically imported on purpose: a type-only import is erased by every toolchain\n * (babel, esbuild and sucrase all drop it), so it creates no runtime edge and no bundle dependency,\n * and `showcaseColors.ts` already relies on exactly that.\n *\n * ── THE SPECIFIER MUST BE A STRING LITERAL, INSIDE A TRY/CATCH ───────────────────────────\n *\n * Metro collects dependencies statically and matches only a call whose callee is literally the\n * identifier `require` and whose argument is literally a string; the try/catch around it is what\n * marks the dependency `isOptional`. Both halves are load-bearing — see `icons/expoIcons.ts` for\n * the full autopsy of the 0.8.0 shape that aliased the callee and was collected nowhere.\n *\n * ── THE DEGRADE ─────────────────────────────────────────────────────────────────────────\n *\n * Absent → `FeatureShowcase` renders null and calls `onDone` from an effect, which is the SAME path\n * the feature kill switch already takes. The host's flow always advances (a showcase that cannot\n * render must never strand the user on a blank screen), and the seen-gate is deliberately NOT\n * written, so installing the peer later still plays the showcase once.\n */\nimport type { ComponentType } from \"react\";\n\nimport type { OnboardingProps } from \"@blazejkustra/react-native-onboarding\";\n\n// Metro injects a module-scoped `require`; it is ABSENT in a pure-ESM runtime (the kit's own tests\n// run under `node --test` as ESM). Declared locally so this type-checks without ambient Node types;\n// the `typeof` guard keeps the reference ESM-safe.\ndeclare const require: ((id: string) => unknown) | undefined;\n\n/** A `require`-like resolver. Injectable in tests; production uses the guarded literal require. */\nexport type OptionalRequire = (moduleName: string) => unknown;\n\n/** The pager component `FeatureShowcase` wraps. */\nexport type OnboardingComponent = ComponentType<OnboardingProps>;\n\nconst MODULE_NAME = \"@blazejkustra/react-native-onboarding\";\n\n/**\n * The production resolver. The specifier is a LITERAL so Metro collects it (see the header); the\n * `moduleName` parameter exists only to keep the `OptionalRequire` seam shape, so anything other\n * than the one module this file owns resolves to undefined.\n */\nconst runtimeRequire: OptionalRequire = (moduleName) => {\n if (moduleName !== MODULE_NAME) return undefined;\n if (typeof require !== \"function\") return undefined;\n try {\n return require(\"@blazejkustra/react-native-onboarding\");\n } catch {\n return undefined;\n }\n};\n\n/**\n * TEST-ONLY seam. `FeatureShowcase`'s public props are frozen, so it cannot take a `requireModule`\n * the way `WireIcon` does — this lets a component render exercise the PRESENT path without the peer\n * installed. Production never sets it; `runtimeRequire` is the only resolver.\n */\nlet testRequire: OptionalRequire | undefined;\nexport const __setShowcaseOnboardingRequireForTests = (fn: OptionalRequire | undefined): void => {\n testRequire = fn;\n cached = undefined;\n};\n\n/**\n * Read the component off the module. The package ships it as a DEFAULT export; a CJS build may put\n * the component directly on `module.exports` instead, so both shapes are accepted.\n */\nconst interop = (mod: unknown): unknown => {\n if (typeof mod === \"function\") return mod;\n if (!mod || typeof mod !== \"object\") return undefined;\n const ns = mod as Record<string, unknown>;\n if (ns.default) return ns.default;\n // `module.exports = forwardRef(...)`: the component IS the namespace, and it is an object rather\n // than a function, so it would slip past the check above.\n if (\"$$typeof\" in ns) return ns;\n return undefined;\n};\n\n/**\n * Narrow an unknown export to something mountable: a real component (function or class) or a\n * React.memo / forwardRef wrapper (an object carrying `$$typeof`). Reject anything else rather than\n * handing the reconciler a non-component.\n */\nconst asComponent = (value: unknown): OnboardingComponent | undefined => {\n if (typeof value === \"function\") return value as OnboardingComponent;\n if (value && typeof value === \"object\" && \"$$typeof\" in (value as object)) {\n return value as OnboardingComponent;\n }\n return undefined;\n};\n\n/**\n * Module-level memo. `null` = \"we looked and it is not there\" (distinct from \"not looked yet\"), so\n * an absent peer costs exactly one failed require per process, not one per showcase mount.\n */\nlet cached: OnboardingComponent | null | undefined;\n\n/** Reset the memo. TEST-ONLY seam — production never calls it. */\nexport const resetShowcaseOnboardingCache = (): void => {\n cached = undefined;\n};\n\n/**\n * Resolve the pager component, or undefined when the peer is absent/unresolvable. Never throws: an\n * absent showcase must advance the host's flow, never break it.\n *\n * `requireModule` is injectable so tests can exercise BOTH the found and absent paths without\n * installing the peer (same convention as `resolveBlurView` / `resolveIconFamily`).\n */\nexport const resolveShowcaseOnboarding = (\n requireModule: OptionalRequire = testRequire ?? runtimeRequire,\n): OnboardingComponent | undefined => {\n try {\n if (cached === undefined || requireModule !== runtimeRequire) {\n const component = asComponent(interop(requireModule(MODULE_NAME)));\n // Don't poison the module memo from an injected test require.\n if (requireModule === runtimeRequire) cached = component ?? null;\n return component;\n }\n if (cached === null) return undefined;\n return cached;\n } catch {\n return undefined;\n }\n};\n","import type { OnboardingColors } from \"@blazejkustra/react-native-onboarding\";\n\nimport type { OnboardingTheme } from \"../theme/types\";\n\n/**\n * Map the kit's semantic `OnboardingTheme` onto the color contract of\n * `@blazejkustra/react-native-onboarding` (what `FeatureShowcase` wraps).\n *\n * ⚠️ CRITICAL — that package's color NAMES do NOT line up with the kit's roles.\n * From its source (`utils/theme.ts` + the button/panel components):\n * • `background.primary` → the PRIMARY BUTTON background, the highlighted intro\n * title word (`OnboardingIntroPanel`), and the image\n * hero panel (`OnboardingImageContainer`). It is the\n * package's BRAND / ACTION color — NOT a screen bg.\n * • `background.secondary` → the screen / modal / step-panel background.\n * • `background.label` → the step-label chip background.\n * • `background.accent` → the SECONDARY (outline) button border ONLY.\n * • `text.contrast` → the primary button label (sits on `background.primary`).\n * • `text.primary` → body copy; `text.secondary` → hints/subtitles.\n *\n * The earlier mapping set `background.primary` to the kit's `background`, which\n * painted the primary CTA in the app's SCREEN background color — an invisible /\n * wrong-colored button (white-on-white in light, dark-on-dark in dark mode). The\n * primary button must be the brand `accent`. Keep this in sync with the package's\n * actual usage, not its key names.\n *\n * ⚠️ CONSEQUENCE of the fix above (the 0.3.2 flood): because `background.primary`\n * is ONE key driving THREE surfaces, painting it `accent` also paints the large\n * IMAGE HERO PANEL (`OnboardingImageContainer`'s `colorBg`) in the accent — a\n * full-bleed wash that dominates the first slide and \"hides\" the app's brand.\n * The package offers no per-surface color key to split them, BUT it does expose a\n * `background?: () => ReactNode` render prop that REPLACES that hero panel fill\n * outright (see `showcasePanelBackground` + `FeatureShowcase`). So the button\n * keeps `accent` here and the panel is calmed separately — one accent value, two\n * different surfaces, cleanly split.\n */\nexport const showcaseColorsFromTheme = (\n t: OnboardingTheme,\n accent: string,\n): OnboardingColors => ({\n background: {\n // Brand action color → primary button bg + intro highlight + image hero panel.\n // (The hero panel is overridden to a calm surface via the package's\n // `background` render prop — see showcasePanelBackground — so in practice\n // this only paints the primary button + the intro highlight word.)\n primary: accent,\n // Neutral screen / modal / step-panel background.\n secondary: t.colors.background,\n // Step-label chip background (a soft wash of the brand).\n label: t.colors.primarySoft,\n // Secondary (outline) button border.\n accent,\n },\n text: {\n primary: t.colors.text,\n secondary: t.colors.textMuted,\n // Primary button label — sits on `background.primary` (the accent).\n contrast: t.colors.onPrimary,\n },\n});\n\n/**\n * Opacity of the accent tint layered over the theme surface for the showcase's\n * image hero panel. Kept in a calm 8–12% band so the panel reads as a subtle\n * brand wash — a hint of the accent, never the full-bleed flood that `accent`\n * as a solid fill produced (the 0.3.1 → 0.3.2 bug seen in a host app).\n */\nexport const SHOWCASE_PANEL_TINT_OPACITY = 0.1;\n\n/** The calm hero-panel background: a neutral surface base + a faint accent tint. */\nexport interface ShowcasePanelBackground {\n /** The calm base fill — the theme SURFACE, deliberately NOT the accent. */\n base: string;\n /** A very subtle accent wash layered over the base (8–12% opacity). */\n tint: { color: string; opacity: number };\n}\n\n/**\n * Background for the showcase's image/hero panel, fed to the underlying\n * package's `background` render prop (which REPLACES its `bg.primary`-filled\n * `colorBg`). Returns a neutral surface base with a faint accent tint on top, so\n * the panel is calm and on-brand instead of an accent flood. The primary button\n * and intro highlight keep the full accent (they read `bg.primary` directly).\n */\nexport const showcasePanelBackground = (\n t: OnboardingTheme,\n accent: string,\n): ShowcasePanelBackground => ({\n base: t.colors.surface,\n tint: { color: accent, opacity: SHOWCASE_PANEL_TINT_OPACITY },\n});\n","import type {\n OnboardingColors,\n OnboardingFonts,\n OnboardingProps,\n OnboardingStep,\n} from \"@blazejkustra/react-native-onboarding\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type ImageSourcePropType, StyleSheet, View } from \"react-native\";\n\nimport { GestureHint } from \"../coachmarks/GestureHint\";\nimport { hasSeenGate, markSeenGate, showcaseGateKey } from \"../coachmarks/runtime\";\nimport { useResolvedFeatures } from \"../features/WireFeaturesProvider\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport type { OnboardingTheme } from \"../theme/types\";\nimport { resolveShowcaseOnboarding } from \"./blazejOnboarding\";\nimport { showcaseColorsFromTheme, showcasePanelBackground } from \"./showcaseColors\";\nimport type { FeatureShowcaseProps } from \"./types\";\n\n/** 1×1 transparent GIF — the fallback for a slide with no image (the underlying\n * package requires an image area per step). */\nconst TRANSPARENT_PX: ImageSourcePropType = {\n uri: \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n};\n\nconst mergeThemeOver = (\n base: OnboardingTheme,\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return base;\n return {\n colors: { ...base.colors, ...override.colors },\n fonts: { ...base.fonts, ...override.fonts },\n radius: { ...base.radius, ...override.radius },\n spacing: { ...base.spacing, ...override.spacing },\n button: { ...base.button, ...override.button },\n };\n};\n\n/**\n * FeatureShowcase — the pre-onboarding \"app intro\" slides.\n *\n * Wraps `@blazejkustra/react-native-onboarding`: the app supplies a declarative\n * `ShowcaseConfig` (slides + optional intro panel) and the kit maps it to the\n * package's API, bakes in the Wire onboarding theme colors, overlays the\n * perf-tuned GestureHint on any slide that asks for one, and gates the whole\n * thing once through the same sync storage as the coachmark tours\n * (`wire_showcase_<id>_seen`; the global testing flag bypasses it).\n *\n * When the gate says \"seen\", it renders nothing and calls `onDone` from an\n * effect (never during render).\n *\n * The underlying package is an OPTIONAL peer, resolved through the guarded lazy\n * require in `blazejOnboarding.ts` rather than a static import, so the showcase\n * subpath builds on a host that never installed it. Absent, this takes the SAME\n * path as the kill switch — render null, call `onDone`, write no gate — so the\n * host's flow always advances and the showcase still plays once if the peer is\n * added later.\n */\nconst _FeatureShowcase: React.FC<FeatureShowcaseProps> = ({\n config,\n onDone,\n theme: themeOverride,\n accentColor,\n buttonLabel = \"Next\",\n storage,\n isTesting,\n features,\n featuresConfig,\n}) => {\n const active = useOnboardingTheme();\n const t = useMemo(\n () => mergeThemeOver(active, themeOverride),\n [active, themeOverride],\n );\n const accent = accentColor ?? t.colors.primary;\n\n // Feature kill switch: disabled → treat like \"already seen\" (render nothing, call onDone so the\n // host flow continues) but WITHOUT writing the seen gate, so re-enabling replays the showcase.\n const flags = useResolvedFeatures({ flags: features, config: featuresConfig });\n const disabled = !flags.showcase.enabled;\n\n // The optional pager peer. Resolved once, on first render, instead of at module scope — so\n // merely importing this file (and thus the showcase subpath) never needs it. Absent → treated\n // exactly like the kill switch below: no render, no gate write, `onDone` from the effect.\n const Onboarding = useMemo(() => resolveShowcaseOnboarding(), []);\n\n const gateKey = showcaseGateKey(config.id);\n const seen = useMemo(\n () => hasSeenGate(gateKey, storage, isTesting),\n [gateKey, storage, isTesting],\n );\n // Already-seen, feature-disabled OR the peer missing short-circuits the showcase. Only the seen\n // path is a gate write (in `finish`); the other two never persist, so the showcase replays once\n // the feature is re-enabled or the peer is installed.\n const skip = seen || disabled || !Onboarding;\n\n const doneRef = useRef(false);\n const finish = useCallback(() => {\n if (doneRef.current) return;\n doneRef.current = true;\n markSeenGate(gateKey, storage, isTesting);\n onDone();\n }, [gateKey, storage, isTesting, onDone]);\n\n // Already seen OR disabled → skip without rendering; call onDone from an effect so the host's\n // navigation continues (never write the gate here — `finish` owns the seen write).\n useEffect(() => {\n if (skip && !doneRef.current) {\n doneRef.current = true;\n onDone();\n }\n }, [skip, onDone]);\n\n const [activeIndex, setActiveIndex] = useState(0);\n\n const steps: OnboardingStep[] = useMemo(\n () =>\n config.slides.map((slide) => ({\n title: slide.title,\n description: slide.description,\n buttonLabel: slide.buttonLabel ?? buttonLabel,\n image: slide.image ?? TRANSPARENT_PX,\n position: slide.imagePosition ?? \"top\",\n })),\n [config.slides, buttonLabel],\n );\n\n const introPanel: OnboardingProps[\"introPanel\"] = useMemo(\n () =>\n config.introPanel\n ? {\n title: config.introPanel.title,\n subtitle: config.introPanel.subtitle,\n button: config.introPanel.button,\n image: config.introPanel.image,\n }\n : { button: buttonLabel },\n [config.introPanel, buttonLabel],\n );\n\n // The package's color KEYS don't match the kit's role names — most importantly\n // its `background.primary` drives the PRIMARY BUTTON (not the screen bg), so the\n // accent must land there. See showcaseColorsFromTheme for the full contract.\n const colors: OnboardingColors = useMemo(\n () => showcaseColorsFromTheme(t, accent),\n [t, accent],\n );\n\n // Calm the large image/hero panel. The package's `background.primary` is a\n // SINGLE key that fills the primary button, the intro highlight AND this hero\n // panel — painting it `accent` (correct for the button) also flooded the first\n // slide with the app color (0.3.1). The package exposes a\n // `background` render prop that REPLACES that panel fill outright, so we keep\n // the button accent (via `colors`) and paint the panel a calm surface + faint\n // accent tint here. See showcasePanelBackground.\n const panelBg = useMemo(() => showcasePanelBackground(t, accent), [t, accent]);\n const renderPanelBackground = useCallback(\n () => (\n <View\n style={[\n styles.panelBase,\n { backgroundColor: panelBg.base, borderRadius: t.radius.md },\n ]}\n >\n <View\n style={[\n StyleSheet.absoluteFill,\n {\n backgroundColor: panelBg.tint.color,\n opacity: panelBg.tint.opacity,\n },\n ]}\n />\n </View>\n ),\n [panelBg, t.radius.md],\n );\n\n const fonts: OnboardingFonts = useMemo(\n () => ({\n introTitle: t.fonts.bold,\n introSubtitle: t.fonts.regular,\n introButton: t.fonts.bold,\n stepLabel: t.fonts.medium,\n stepTitle: t.fonts.bold,\n stepDescription: t.fonts.regular,\n stepButton: t.fonts.bold,\n primaryButton: t.fonts.bold,\n secondaryButton: t.fonts.medium,\n }),\n [t],\n );\n\n // `!Onboarding` is already folded into `skip`; it is repeated here so the narrowing is explicit\n // to the reader and to the compiler at the JSX below.\n if (skip || !Onboarding) return null;\n\n const activeGesture = config.slides[activeIndex]?.gesture;\n // Same rule as the coachmark path: tap / double-tap slides show no glyph.\n const showGesture =\n !!activeGesture &&\n activeGesture !== \"none\" &&\n activeGesture !== \"tap\" &&\n activeGesture !== \"double_tap\";\n\n return (\n <View style={styles.fill}>\n <Onboarding\n introPanel={introPanel}\n steps={steps}\n colors={colors}\n fonts={fonts}\n background={renderPanelBackground}\n onComplete={finish}\n onSkip={finish}\n onStepChange={setActiveIndex}\n />\n\n {/* Perf-tuned gesture glyph overlaid on the active slide, if it asks for\n one (tap / double-tap slides show no glyph — same rule as coachmarks). */}\n {showGesture && (\n <View style={styles.gestureLayer} pointerEvents=\"none\">\n <GestureHint type={activeGesture} color={accent} />\n </View>\n )}\n </View>\n );\n};\n\nexport const FeatureShowcase = React.memo(_FeatureShowcase);\nFeatureShowcase.displayName = \"FeatureShowcase\";\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n // Fills the package's animated background box; clips the accent tint to the\n // rounded corners so the calm panel reads as a card, not a bleed.\n panelBase: { flex: 1, overflow: \"hidden\" },\n gestureLayer: {\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n paddingBottom: 140,\n },\n});\n\nexport default FeatureShowcase;\n","/**\n * selectShowcaseSlides — the value-bridge selection seam for the feature showcase.\n *\n * The recommended shape (v0.2.1+) renders the showcase AS A PERSONALIZED VALUE\n * BRIDGE right AFTER the AI onboarding completes: the user just told you what they\n * want in `result.answers`, so you show only the 2-3 slides that answer it, in the\n * most-relevant-first order — \"you said you want X → here's how the app does X\"\n * (the Duolingo / Headspace terminal-moment pattern). The host declares the full\n * slide catalog once and passes an ordered id list computed from the answers:\n *\n * // Full deck, declared order (pre-onboarding placement, or thin answers):\n * const slides = selectShowcaseSlides(catalog);\n *\n * // Personalized bridge, post-onboarding: subset + order chosen from answers:\n * const slides = selectShowcaseSlides(catalog, idsFromAnswers(result.answers));\n *\n * Contract (identical to `selectTourSteps`):\n * - `selection` absent → returns the catalog unchanged (identity / declared order).\n * - `selection` present → returns only catalog entries whose `id` appears in\n * `selection`, ordered by `selection` (unknown ids are skipped; duplicates in\n * `selection` are ignored after the first match).\n *\n * v2 SERVER SEAM (document-only, not built here): the onboarding server's final\n * turn will later return an ordered `showcase: string[]` slide-key list chosen\n * server-side from the same answers. The host passes it straight in as `selection`\n * — same catalog, same contract, AI is a drop-in. Old kits that don't read the new\n * field simply ignore it, so shipping the extra field is backward-safe.\n */\nexport const selectShowcaseSlides = <T extends { id: string }>(\n catalog: T[],\n selection?: string[],\n): T[] => {\n if (!selection) return catalog;\n\n const byId = new Map(catalog.map((item) => [item.id, item]));\n const seen = new Set<string>();\n const ordered: T[] = [];\n for (const id of selection) {\n if (seen.has(id)) continue;\n seen.add(id);\n const item = byId.get(id);\n if (item) ordered.push(item);\n }\n return ordered;\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/motion/useReducedMotion.ts","../../src/coachmarks/reanimated.ts","../../src/coachmarks/GestureHint.tsx","../../src/coachmarks/runtime.ts","../../src/features/defaults.ts","../../src/features/cache.ts","../../src/features/fetchWireFeatures.ts","../../src/features/useWireFeatures.ts","../../src/features/WireFeaturesProvider.tsx","../../src/session/persistedSession.ts","../../src/theme/defaultTheme.ts","../../src/theme/ThemeContext.tsx","../../src/showcase/blazejOnboarding.ts","../../src/showcase/showcaseColors.ts","../../src/showcase/FeatureShowcase.tsx","../../src/showcase/selectShowcaseSlides.ts"],"names":["StaticAnimatedView","_a","api","useReducedMotion","View","useEffect","cached","useRef","useState","useMemo","READ_TIMEOUT_MS","createContext","useContext","runtimeRequire","jsx","styles","StyleSheet","jsxs","React"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * useReducedMotion — the kit's ONE reduce-motion gate. Reads the OS setting via\n * AccessibilityInfo and stays subscribed to `reduceMotionChanged`, so every\n * animated component lands on its final frame (or a ~120ms fade) the moment the\n * user flips the setting — no restart needed.\n *\n * This closes the gap documented in ai_rules/rules/performance.md §3: every\n * animation in the kit must consume this hook (usually through the pure helpers\n * in motionSpec.ts: `entranceSpec` / `stateChangeDuration` / `loopEnabled`).\n */\nimport { useEffect, useState } from \"react\";\nimport { AccessibilityInfo } from \"react-native\";\n\n// Last-known value, module-level: cards remount every turn (keyed on message id),\n// and a `useState(false)` default would flash one animated frame per turn for a\n// reduce-motion user before the async read resolves.\nlet lastKnown = false;\n\nexport const useReducedMotion = (): boolean => {\n const [reduced, setReduced] = useState(lastKnown);\n\n useEffect(() => {\n let mounted = true;\n AccessibilityInfo.isReduceMotionEnabled()\n .then((value) => {\n lastKnown = value;\n if (mounted) setReduced(value);\n })\n .catch(() => {\n // Unavailable (e.g. some test envs): keep the last-known value.\n });\n const sub = AccessibilityInfo.addEventListener(\"reduceMotionChanged\", (value) => {\n lastKnown = value;\n setReduced(value);\n });\n return () => {\n mounted = false;\n sub?.remove();\n };\n }, []);\n\n return reduced;\n};\n","/**\n * reanimated — resolve `react-native-reanimated`, lazily and optionally.\n *\n * ── WHY THIS DOES NOT BREAK THE NO-NATIVE-DEPENDENCY POLICY ──────────────────────────────\n *\n * `react-native-reanimated` is an OPTIONAL peer of the coachmarks subpath. `SpotlightOverlay` and\n * `GestureHint` animate with it WHEN it is installed, and fall back to a STATIC render of the same\n * visual when it is not — same ring, same tooltip, same glyph, same copy, same gestures, just\n * without motion. So a host that never installs it can still run the guided tour and the feature\n * showcase, and an Expo Go / Lite build is not forced into a native module it cannot take.\n *\n * Before this file, both components did `import Animated, { … } from \"react-native-reanimated\"` at\n * module scope, and `coachmarks/index.ts` re-exports them with no wildcard escape — so importing\n * ANYTHING from `@wireai/activation/coachmarks` (even `setCoachmarkStorage`) dragged the peer in,\n * and a host without it hit a Metro resolution failure. `@wireai/activation/showcase` inherited the\n * same edge through `GestureHint`. This resolver removes it. Same class as the 0.14.2 `expo-blur`\n * fix (`expoBlur.ts`), same shape, one size up.\n *\n * ── THE SPECIFIER MUST BE A STRING LITERAL, INSIDE A TRY/CATCH ───────────────────────────\n *\n * This follows `icons/expoIcons.ts` and `coachmarks/expoBlur.ts` exactly, and expoIcons' header\n * carries the full autopsy. In short: Metro collects dependencies STATICALLY, matching a call whose\n * callee is literally the identifier `require` and whose argument is literally a string — an\n * aliased callee (`const req = require; req(name)`) or a variable specifier is collected NOWHERE,\n * so the module never enters the bundle (that shape shipped broken in 0.8.0). And the call sitting\n * inside a TRY/CATCH is literally how Metro marks the dependency `isOptional`, which is what lets\n * an absent peer degrade instead of failing the build. Do NOT \"simplify\" either half away.\n *\n * ── WHY THE EXPORTS ARE BARE FUNCTIONS WITH THE PEER'S OWN NAMES ─────────────────────────\n *\n * The call sites import `useAnimatedStyle` / `useAnimatedProps` / `withTiming` … from HERE instead\n * of from the peer, and call them unqualified, exactly as before. That is load-bearing, not style:\n * reanimated's Babel plugin decides what to workletize by the CALLEE NAME (`react-native-worklets`\n * `plugin/index.js` → `reanimatedFunctionHooks` / `reanimatedFunctionArgsToWorkletize`; it reads\n * `callee.name`, or `callee.property.name` for a member call, and never checks which module the\n * name came from). Keeping the names identical keeps every worklet in `SpotlightOverlay` and\n * `GestureHint` workletized byte-for-byte on a host that HAS the peer. Rename them and the\n * animations silently stop running on the UI thread.\n *\n * ── THE DEGRADE: THE FINAL FRAME, NOT A DEAD ONE ─────────────────────────────────────────\n *\n * The shim resolves every animation to its RESTING value — `withTiming(to)` is `to`,\n * `withSequence(a, b)` is `b`, `withRepeat(x)` is `x` — so a component lands on the pose it would\n * have settled into anyway (ring at scale 1, glyph at full opacity, blur at BLUR_INTENSITY) rather\n * than on frame zero, which for the blur would have meant a fully transparent overlay. Shared\n * values are state-backed so a write from an effect actually reaches the next render; reanimated's\n * own values do not need this because they drive the UI thread directly. The kit's own\n * AccessibilityInfo-backed `useReducedMotion` stands in for the peer's, so the reduce-motion\n * contract in ai_rules/rules/performance.md §3 holds with or without the peer.\n *\n * This is also what `ai_rules/rules/frequent_rules.md` #1 prescribes: when the kit needs motion\n * without the optional peer, it uses core React Native, never Reanimated.\n */\nimport {\n createElement,\n forwardRef,\n useReducer,\n useRef,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { View, type ViewProps, type ViewStyle } from \"react-native\";\n\nimport { useReducedMotion as useOsReducedMotion } from \"../motion/useReducedMotion\";\n\n// Metro injects a module-scoped `require`; it is ABSENT in a pure-ESM runtime (the kit's own tests\n// run under `node --test` as ESM). Declared locally so this type-checks without ambient Node types;\n// the `typeof` guard keeps the reference ESM-safe.\ndeclare const require: ((id: string) => unknown) | undefined;\n\n/** A `require`-like resolver. Injectable in tests; production uses the guarded literal require. */\nexport type OptionalRequire = (moduleName: string) => unknown;\n\n/** A reanimated shared value, narrowed to the one member the kit uses. */\nexport interface SharedValue<T> {\n value: T;\n}\n\n/** Props `Animated.View` accepts on top of a plain View (layout-animation descriptors). */\nexport interface AnimatedViewProps extends ViewProps {\n entering?: unknown;\n exiting?: unknown;\n children?: ReactNode;\n}\n\n/** A component built by `createAnimatedComponent`: its own props plus reanimated's driven props. */\nexport type AnimatedComponent<P> = ComponentType<P & { animatedProps?: object }>;\n\n/** The slice of reanimated the coachmark surfaces actually use. */\nexport interface ReanimatedApi {\n /** True when the real peer resolved; false when this is the static fallback. */\n present: boolean;\n View: ComponentType<AnimatedViewProps>;\n createAnimatedComponent: <P extends object>(component: ComponentType<P>) => AnimatedComponent<P>;\n useSharedValue: <T>(initial: T) => SharedValue<T>;\n useAnimatedStyle: (factory: () => ViewStyle) => ViewStyle;\n useAnimatedProps: <P extends object>(factory: () => P) => P;\n useReducedMotion: () => boolean;\n withTiming: (toValue: number, config?: object) => number;\n withRepeat: (animation: number, count?: number, reverse?: boolean) => number;\n withSequence: (...animations: number[]) => number;\n withDelay: (ms: number, animation: number) => number;\n /** The `entering` / `exiting` descriptors, or undefined when the peer is absent. */\n fadeIn: (durationMs: number) => unknown;\n fadeOut: (durationMs: number) => unknown;\n}\n\n/**\n * The production resolver. The specifier is a LITERAL so Metro collects it (see the header); the\n * `moduleName` parameter exists only to keep the `OptionalRequire` seam shape, so anything other\n * than the one module this file owns resolves to undefined.\n */\nconst runtimeRequire: OptionalRequire = (moduleName) => {\n if (moduleName !== \"react-native-reanimated\") return undefined;\n if (typeof require !== \"function\") return undefined;\n try {\n return require(\"react-native-reanimated\");\n } catch {\n return undefined;\n }\n};\n\n/**\n * TEST-ONLY seam. `SpotlightOverlay` / `GestureHint` have frozen public props, so neither can take\n * a `requireModule` the way `WireIcon` does — this lets a component render exercise the PRESENT\n * path. Production never sets it; `runtimeRequire` is the only resolver.\n */\nlet testRequire: OptionalRequire | undefined;\nexport const __setReanimatedRequireForTests = (fn: OptionalRequire | undefined): void => {\n testRequire = fn;\n cached = undefined;\n};\n\n// ── the static fallback ───────────────────────────────────────────────────────\n\n/**\n * A shared value that re-renders its owner on write. Reanimated's own value drives the UI thread\n * and deliberately does NOT re-render; here the render IS the only output, so a value written from\n * an effect (`intensity.value = withTiming(26)`) has to reach it or the overlay would sit on frame\n * zero forever — a fully transparent blur. The box identity is stable for the component's lifetime,\n * exactly like the real one, so it stays safe in a dependency list.\n */\nconst useStaticSharedValue = <T,>(initial: T): SharedValue<T> => {\n const [, bump] = useReducer((n: number): number => n + 1, 0);\n const box = useRef<SharedValue<T> | null>(null);\n if (box.current === null) {\n let current = initial;\n box.current = {\n get value(): T {\n return current;\n },\n set value(next: T) {\n if (Object.is(next, current)) return;\n current = next;\n bump();\n },\n };\n }\n return box.current;\n};\n\n/** Run a worklet body on the JS side. It must never throw into the render — degrade, don't crash. */\nconst runWorklet = <R extends object>(factory: () => R, fallback: R): R => {\n try {\n return factory() ?? fallback;\n } catch {\n return fallback;\n }\n};\n\n/** `Animated.View` without the peer: a plain View, with the layout-animation props dropped. */\nconst StaticAnimatedView = forwardRef<View, AnimatedViewProps>(function StaticAnimatedView(\n { entering: _entering, exiting: _exiting, children, ...rest },\n ref,\n) {\n return createElement(View, { ...rest, ref }, children);\n});\n\n/**\n * `createAnimatedComponent` without the peer. The wrapper MERGES `animatedProps` into the real\n * props, because that object is the only carrier for values the worklet would have driven (the\n * spotlight's blur `intensity`). Built once per wrapped component at the call site's `useMemo`, so\n * the returned type identity is stable and React never remounts the subtree.\n */\nconst staticCreateAnimatedComponent = <P extends object>(\n component: ComponentType<P>,\n): AnimatedComponent<P> =>\n function StaticAnimatedComponent({ animatedProps, ...rest }) {\n return createElement(component, { ...(rest as P), ...(animatedProps as object) });\n };\n\n/**\n * The peer-absent API. Every animation resolves to its RESTING value, so components render the\n * frame they would have settled on. Nothing here schedules work, allocates a native module, or\n * throws.\n */\nconst staticApi: ReanimatedApi = {\n present: false,\n View: StaticAnimatedView,\n createAnimatedComponent: staticCreateAnimatedComponent,\n useSharedValue: useStaticSharedValue,\n useAnimatedStyle: (factory) => runWorklet(factory, {}),\n useAnimatedProps: (factory) => runWorklet(factory, {} as never),\n useReducedMotion: useOsReducedMotion,\n withTiming: (toValue) => toValue,\n withRepeat: (animation) => animation,\n withSequence: (...animations) => animations[animations.length - 1] ?? 0,\n withDelay: (_ms, animation) => animation,\n fadeIn: () => undefined,\n fadeOut: () => undefined,\n};\n\n// ── the real peer ─────────────────────────────────────────────────────────────\n\nconst isFunction = (value: unknown): boolean => typeof value === \"function\";\n\n/** A React component is a function, or an object carrying `$$typeof` (memo / forwardRef). */\nconst isComponent = (value: unknown): boolean =>\n typeof value === \"function\" || (!!value && typeof value === \"object\" && \"$$typeof\" in value);\n\n/**\n * Build the API from a resolved module namespace, or undefined when it is not the module we expect.\n *\n * The hooks are NAMED exports; `View` and `createAnimatedComponent` live on the DEFAULT export (the\n * `Animated` object). A CJS interop wrapper puts everything one level down under `default`, so both\n * are looked up on the namespace first and the default second. EVERY member is verified before the\n * namespace is accepted: a partial module must degrade to the static fallback, never crash halfway\n * through a render.\n */\nconst fromModule = (mod: unknown): ReanimatedApi | undefined => {\n if (!mod || typeof mod !== \"object\") return undefined;\n const ns = mod as Record<string, unknown>;\n const def =\n ns.default && typeof ns.default === \"object\"\n ? (ns.default as Record<string, unknown>)\n : undefined;\n const pick = (name: string): unknown => ns[name] ?? def?.[name];\n\n const view = def?.View ?? ns.View;\n const createAnimated = def?.createAnimatedComponent ?? ns.createAnimatedComponent;\n const hooks = {\n useSharedValue: pick(\"useSharedValue\"),\n useAnimatedStyle: pick(\"useAnimatedStyle\"),\n useAnimatedProps: pick(\"useAnimatedProps\"),\n useReducedMotion: pick(\"useReducedMotion\"),\n withTiming: pick(\"withTiming\"),\n withRepeat: pick(\"withRepeat\"),\n withSequence: pick(\"withSequence\"),\n withDelay: pick(\"withDelay\"),\n };\n const fadeIn = pick(\"FadeIn\");\n const fadeOut = pick(\"FadeOut\");\n\n if (!isComponent(view) || !isFunction(createAnimated)) return undefined;\n if (Object.values(hooks).some((member) => !isFunction(member))) return undefined;\n if (!fadeIn || !fadeOut) return undefined;\n\n // The single narrowing seam. Everything above proved the members exist and are callable; the peer\n // is untyped here (it is resolved through `unknown`), so the cast happens once, at the boundary,\n // and the exported signatures above are the contract from here on.\n const api = {\n present: true,\n View: view,\n createAnimatedComponent: createAnimated,\n ...hooks,\n fadeIn: (durationMs: number) => (fadeIn as { duration: (ms: number) => unknown }).duration(durationMs),\n fadeOut: (durationMs: number) => (fadeOut as { duration: (ms: number) => unknown }).duration(durationMs),\n } as unknown as ReanimatedApi;\n return api;\n};\n\n/**\n * Module-level memo. Holds the RESOLVED api (real or static), so an absent peer costs exactly one\n * failed require per process, not one per mount — and, more importantly, so the implementation can\n * never change between two renders of the same component, which would break the rules of hooks.\n */\nlet cached: ReanimatedApi | undefined;\n\n/** Reset the memo. TEST-ONLY seam — production never calls it. */\nexport const resetReanimatedModuleCache = (): void => {\n cached = undefined;\n};\n\n/**\n * Resolve the reanimated API, or the static fallback when the peer is absent/unresolvable.\n * Never throws and never returns undefined: an absent animation library must degrade to a still\n * frame, never break the tour.\n */\nexport const resolveReanimated = (\n requireModule: OptionalRequire = testRequire ?? runtimeRequire,\n): ReanimatedApi => {\n try {\n if (cached === undefined || requireModule !== runtimeRequire) {\n const resolved = fromModule(requireModule(\"react-native-reanimated\")) ?? staticApi;\n // Don't poison the module memo from an injected test require.\n if (requireModule === runtimeRequire) cached = resolved;\n return resolved;\n }\n return cached;\n } catch {\n return staticApi;\n }\n};\n\n// ── the call-site surface: the peer's own names, resolved lazily ──────────────\n//\n// Each one delegates on every call, so nothing is resolved at import time. `api()` is memoized, so\n// the delegation is a property read.\n\nconst api = (): ReanimatedApi => resolveReanimated();\n\n/**\n * The `Animated` namespace, with `View` behind a getter so merely importing this module never\n * touches the peer. The component identity it returns is stable (the peer's own `Animated.View`, or\n * the module-level `StaticAnimatedView`), so React never remounts the tree under it.\n */\nexport const Animated: {\n readonly View: ComponentType<AnimatedViewProps>;\n createAnimatedComponent: <P extends object>(component: ComponentType<P>) => AnimatedComponent<P>;\n} = {\n get View() {\n return api().View;\n },\n createAnimatedComponent: (component) => api().createAnimatedComponent(component),\n};\n\n/** Layout-animation descriptors. `.duration()` is the only builder the kit uses. */\nexport const FadeIn = { duration: (durationMs: number): unknown => api().fadeIn(durationMs) };\nexport const FadeOut = { duration: (durationMs: number): unknown => api().fadeOut(durationMs) };\n\nexport const useSharedValue = <T,>(initial: T): SharedValue<T> => api().useSharedValue(initial);\nexport const useAnimatedStyle = (factory: () => ViewStyle): ViewStyle =>\n api().useAnimatedStyle(factory);\nexport const useAnimatedProps = <P extends object>(factory: () => P): P =>\n api().useAnimatedProps(factory);\nexport const useReducedMotion = (): boolean => api().useReducedMotion();\nexport const withTiming = (toValue: number, config?: object): number =>\n api().withTiming(toValue, config);\nexport const withRepeat = (animation: number, count?: number, reverse?: boolean): number =>\n api().withRepeat(animation, count, reverse);\nexport const withSequence = (...animations: number[]): number => api().withSequence(...animations);\nexport const withDelay = (ms: number, animation: number): number => api().withDelay(ms, animation);\n","import React, { useEffect, useMemo, type ReactNode } from \"react\";\nimport { StyleSheet, View } from \"react-native\";\n\nimport {\n Animated,\n useAnimatedStyle,\n useReducedMotion,\n useSharedValue,\n withDelay,\n withRepeat,\n withSequence,\n withTiming,\n} from \"./reanimated\";\nimport type { GestureKind } from \"./types\";\n\n/**\n * Abstract gesture pictogram shown beside a coachmark tooltip. With the OPTIONAL\n * `react-native-reanimated` peer installed every animation runs on the UI thread\n * (shared values + worklets), never setState, so it costs nothing on the JS\n * thread. Honors Reduce Motion by dropping the motion loop and rendering the\n * glyph static.\n *\n * The peer is reached through the guarded lazy require in `reanimated.ts`, never\n * a static import, so `@wireai/activation/coachmarks` (and `/showcase`, which\n * reaches this component through FeatureShowcase) builds on a host that never\n * installed it. Absent, the glyph renders STATICALLY at its resting frame — the\n * same capsules, ring, dot and motion track, at full opacity and no travel, with\n * one render instead of a UI-thread loop. The pictogram never disappears.\n *\n * NO drawn-hand anatomy. Swipes render the standard two-finger swipe glyph: two\n * rounded vertical capsules (an abstract index + middle finger, slightly\n * different heights) with a short, fading motion track trailing behind them along\n * the swipe axis. The whole glyph is rotated per direction (up/down/left/right)\n * and the capsules slide along the axis, fading, in a UI-thread loop. Pinch/zoom\n * reuse the two-capsule abstraction spreading apart. Tap / double-tap render a\n * minimal pulsing tap-target (ring + dot).\n *\n * Every glyph is a self-drawn primitive built from Views/borders (no vector-icon\n * dependency, like AnimatedSparkle). Pass `renderHand` — the glyph slot — to\n * substitute your own node while keeping the tuned motion. (The name is kept for\n * backward compatibility; despite it, the default is a glyph, not a drawn hand.)\n *\n * NOTE: the coachmark path (SpotlightOverlay) and the showcase path\n * (FeatureShowcase) both SKIP this component for `tap` / `double_tap` — those\n * steps show only the highlight ring + tooltip, no glyph. The tap visual here\n * exists for direct / standalone use.\n */\nexport interface GestureHintProps {\n type: GestureKind;\n /** Overall glyph size in px. */\n size?: number;\n /** Glyph color. Defaults to white (reads on the dark blur backdrop). */\n color?: string;\n /**\n * Provide a custom glyph node in place of the default self-drawn primitive; it\n * inherits the tuned motion (slide+fade for swipes, pulse for tap). Kept as\n * `renderHand` for backward compatibility — despite the name it is just the\n * glyph slot, no longer a drawn hand.\n */\n renderHand?: (props: { size: number; color: string }) => ReactNode;\n}\n\n/** Travel distance for the directional swipe loop (local glyph axis). */\nconst TRAVEL = 26;\nconst SWIPE_MS = 700;\nconst TAP_MS = 320;\nconst SPREAD_MS = 620;\n\n/**\n * Per-direction rotation of the whole glyph. Canonical orientation is \"up\":\n * capsules point up, travel up, motion track trailing below. Rotating the\n * container reorients both the capsules and the track together, and rotates the\n * local translate axis so the same upward loop reads correctly per direction.\n */\nconst GLYPH_ROTATION: Record<string, string> = {\n swipe_up: \"0deg\",\n swipe_down: \"180deg\",\n swipe_left: \"-90deg\",\n swipe_right: \"90deg\",\n};\n\n/**\n * The two-finger abstraction: two rounded vertical capsules side by side with\n * slightly different heights (index taller than middle), aligned at the base —\n * the standard swipe pictogram look. Self-drawn from Views only.\n */\nconst FingerPair: React.FC<{ size: number; color: string }> = ({ size, color }) => {\n const { row, index, middle } = useMemo(() => {\n const w = size * 0.2;\n const r = w / 2;\n return {\n row: { flexDirection: \"row\" as const, alignItems: \"flex-end\" as const, gap: size * 0.08 },\n index: { width: w, height: size * 0.54, borderRadius: r, backgroundColor: color },\n middle: { width: w, height: size * 0.44, borderRadius: r, backgroundColor: color },\n };\n }, [size, color]);\n\n return (\n <View style={row} pointerEvents=\"none\">\n <View style={index} />\n <View style={middle} />\n </View>\n );\n};\n\n/**\n * A short, tapering motion track that sits behind the capsules (below, in the\n * canonical \"up\" orientation) — two slim, fading ticks that shrink and dim with\n * distance. Subtle: it reads as the path the fingers just travelled, not a comet\n * tail. Static (the capsules carry the motion via the slide loop).\n */\nconst MotionTrack: React.FC<{ size: number; color: string }> = ({ size, color }) => {\n const { wrap, tick0, tick1 } = useMemo(() => {\n const h = Math.max(2, size * 0.05);\n return {\n wrap: { alignItems: \"center\" as const, marginTop: size * 0.1, gap: size * 0.06 },\n tick0: {\n width: size * 0.3,\n height: h,\n borderRadius: h / 2,\n backgroundColor: color,\n opacity: 0.4,\n },\n tick1: {\n width: size * 0.18,\n height: h,\n borderRadius: h / 2,\n backgroundColor: color,\n opacity: 0.16,\n },\n };\n }, [size, color]);\n\n return (\n <View style={wrap} pointerEvents=\"none\">\n <View style={tick0} />\n <View style={tick1} />\n </View>\n );\n};\n\nconst GestureHintComponent: React.FC<GestureHintProps> = ({\n type,\n size = 34,\n color = \"white\",\n renderHand,\n}) => {\n const translate = useSharedValue(0);\n const opacity = useSharedValue(1);\n const pulse = useSharedValue(1);\n const spread = useSharedValue(0);\n const reduced = useReducedMotion();\n\n const isSwipe =\n type === \"swipe_up\" ||\n type === \"swipe_down\" ||\n type === \"swipe_left\" ||\n type === \"swipe_right\";\n const isSpread = type === \"pinch\" || type === \"zoom\";\n const isTap = type === \"tap\" || type === \"double_tap\";\n\n useEffect(() => {\n if (type === \"none\" || reduced) return undefined;\n\n if (isTap) {\n pulse.value = withRepeat(\n withSequence(\n withTiming(0.82, { duration: TAP_MS }),\n withTiming(1, { duration: TAP_MS }),\n ),\n -1,\n false,\n );\n opacity.value = withRepeat(\n withSequence(\n withTiming(0.55, { duration: TAP_MS }),\n withTiming(1, { duration: TAP_MS }),\n ),\n -1,\n false,\n );\n return undefined;\n }\n\n if (isSpread) {\n // Two capsules easing apart and back — a minimal pinch/zoom abstraction.\n spread.value = withRepeat(\n withSequence(\n withTiming(size * 0.26, { duration: SPREAD_MS }),\n withTiming(0, { duration: SPREAD_MS }),\n ),\n -1,\n false,\n );\n return undefined;\n }\n\n // Directional swipe: slide the capsules along the local \"up\" axis, fading\n // out, then snap back and repeat. The container rotation (below) reorients\n // this loop per direction, so the local motion is always the same.\n translate.value = withRepeat(\n withSequence(\n withTiming(0, { duration: 0 }),\n withTiming(-TRAVEL, { duration: SWIPE_MS }),\n withDelay(140, withTiming(0, { duration: 0 })),\n ),\n -1,\n false,\n );\n opacity.value = withRepeat(\n withSequence(\n withTiming(1, { duration: SWIPE_MS / 2 }),\n withTiming(0, { duration: SWIPE_MS / 2 }),\n withDelay(140, withTiming(1, { duration: 0 })),\n ),\n -1,\n false,\n );\n return undefined;\n }, [type, reduced, isTap, isSpread, translate, opacity, pulse, spread, size]);\n\n const swipeAnimatedStyle = useAnimatedStyle(() => ({\n opacity: opacity.value,\n transform: [{ translateY: translate.value }],\n }));\n const tapAnimatedStyle = useAnimatedStyle(() => ({\n opacity: opacity.value,\n transform: [{ scale: pulse.value }],\n }));\n const spreadLeftStyle = useAnimatedStyle(() => ({\n transform: [{ translateX: -spread.value }],\n }));\n const spreadRightStyle = useAnimatedStyle(() => ({\n transform: [{ translateX: spread.value }],\n }));\n\n if (type === \"none\") return null;\n\n const customGlyph = renderHand ? renderHand({ size, color }) : null;\n\n if (isSwipe) {\n return (\n <View\n style={{ transform: [{ rotate: GLYPH_ROTATION[type] ?? \"0deg\" }] }}\n pointerEvents=\"none\"\n >\n <View style={styles.swipeStack}>\n <Animated.View style={swipeAnimatedStyle} pointerEvents=\"none\">\n {customGlyph ?? <FingerPair size={size} color={color} />}\n </Animated.View>\n <MotionTrack size={size} color={color} />\n </View>\n </View>\n );\n }\n\n if (isSpread) {\n const w = size * 0.2;\n const capsule = {\n width: w,\n height: size * 0.5,\n borderRadius: w / 2,\n backgroundColor: color,\n };\n return (\n <View style={[styles.spreadRow, { gap: size * 0.12 }]} pointerEvents=\"none\">\n <Animated.View style={spreadLeftStyle}>\n <View style={capsule} />\n </Animated.View>\n <Animated.View style={spreadRightStyle}>\n <View style={capsule} />\n </Animated.View>\n </View>\n );\n }\n\n // tap / double_tap — a minimal pulsing tap-target (ring + center dot).\n const ringSize = size * 0.86;\n const ringBorder = Math.max(2, size * 0.08);\n const dotSize = size * 0.32;\n return (\n <View style={[styles.tapWrap, { width: size, height: size }]} pointerEvents=\"none\">\n {customGlyph ? (\n <Animated.View style={tapAnimatedStyle} pointerEvents=\"none\">\n {customGlyph}\n </Animated.View>\n ) : (\n <>\n <Animated.View\n style={[\n styles.tapRing,\n {\n width: ringSize,\n height: ringSize,\n borderRadius: ringSize / 2,\n borderWidth: ringBorder,\n borderColor: color,\n },\n tapAnimatedStyle,\n ]}\n pointerEvents=\"none\"\n />\n <View\n style={{\n position: \"absolute\",\n width: dotSize,\n height: dotSize,\n borderRadius: dotSize / 2,\n backgroundColor: color,\n }}\n />\n </>\n )}\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n swipeStack: {\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n spreadRow: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n tapWrap: {\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n tapRing: {\n backgroundColor: \"transparent\",\n },\n});\n\nexport const GestureHint = React.memo(GestureHintComponent);\nGestureHint.displayName = \"GestureHint\";\n\nexport default GestureHint;\n","/**\n * Module-level runtime for the coachmark engine: the injected sync storage, the\n * global `isTestingCoachmark` flag, and the seen-gate helpers built on top.\n *\n * WHY module singletons (not just context): the tour hooks and the anchor\n * registry are driven imperatively from anywhere in the tree (a screen deep\n * under the navigator), while the storage + testing flag are configured once at\n * the root by `CoachmarkProvider`. Singletons let a hook read the gate without\n * every call site threading the storage through props. The provider is still the\n * single writer — it calls `setCoachmarkStorage` / `setCoachmarkTesting` on mount.\n *\n * ── WHY A globalThis SLOT, NOT PLAIN MODULE VARIABLES ─────────────────────────────────────────\n * These three values used to be plain module `let`s, and this module is inlined by tsup into FOUR\n * dist bundles (`./coachmarks`, `./reviews`, `./questionnaire`, `./showcase`). Under `dist`\n * resolution — node `import`/`require`, SSR, jest, RN-web, anything that is not Metro — a host that\n * mounts `CoachmarkProvider` from `@wireai/activation/coachmarks` wrote the COACHMARKS copy, while\n * `useReviewGate` from `@wireai/activation/reviews` read the REVIEWS copy, which was still `null`.\n * Everything downstream then failed silently: `readInt(null, …)` returns 0, so `bumpSessionCount`\n * returns 1 forever and the fail-closed `minSessions: 2` default is unsatisfiable (the gate NEVER\n * fires); the `seen` once-gate never persists; and a tenant's coachmarks kill switch never reaches\n * the reviews bundle. Metro masked it by collapsing every subpath back to one `src/` file through\n * the `react-native` export condition, which is a bundler accident, not a guarantee.\n *\n * Same remedy this repo already applies to `currentSession`, the auto device-key registry and the\n * activation revalidation counter: ONE record in a `globalThis` slot keyed by `Symbol.for(...)`, so\n * every inlined copy of this module addresses the SAME state.\n */\nimport type { CoachmarkStorage } from \"./types\";\n\n/** RN sets this global; absent under node/SSR. Read defensively via the async-adapter warn below. */\ndeclare const __DEV__: boolean | undefined;\n\n/**\n * Well-known key into the runtime-global symbol registry — one coachmark runtime across bundles.\n *\n * @globalSlot LATCH — the RUNTIME RECORD is created once and its identity is then stable. A second\n * write replaces the record `subscribeCoachmarksEnabled` registered its listeners on, so a\n * kill-switch flip notifies an orphaned set while a tour that believes it is running paints nothing\n * — the exact limbo `coachmarkKillSwitch` canaries. Its FIELDS (`storage`, `testing`,\n * `coachmarksEnabled`, `listeners`) are live, which is why every accessor calls `coachmarkRuntime()`\n * instead of holding the record, and why `coachmarksEnabled` is subscribable rather than sampled.\n */\nconst COACHMARK_RUNTIME_SLOT: unique symbol = Symbol.for(\"@wireai/activation:coachmarkRuntime\");\n\n/** The shared runtime: the provider-injected storage, the QA replay flag, and the kill switch. */\ntype CoachmarkRuntime = {\n storage: CoachmarkStorage | null;\n testing: boolean;\n // The coachmarks feature kill switch (from GET /v1/features). Default true = fail-open: with no\n // flags fetched, coachmarks behave exactly as before. CoachmarkProvider writes it from the\n // resolved flags. Disabled → the tour never ARMS and the overlay `show()` is a no-op, so nothing\n // paints and — critically — no once-gate is written, so re-enabling replays the tour correctly.\n coachmarksEnabled: boolean;\n // Whether `coachmarksEnabled` is an ANSWER from the tenant, or still the optimistic all-on\n // default nobody has confirmed. Default true = fail-open, and OPTIONAL on the type for the same\n // reason as `listeners` below: a record left by an inlined copy from an OLDER kit version has no\n // such field, and reading that absence as `false` would stop every tour under it from arming.\n // See setCoachmarksResolved for why this is a SECOND flag and not a third state on the first.\n coachmarksResolved?: boolean;\n // Subscribers to the kill switch. OPTIONAL on the type (never on the behaviour) so a record left\n // in the registry by an inlined copy from an OLDER kit version — which had no listener set — is\n // upgraded in place rather than read as corrupt.\n listeners?: Set<() => void>;\n};\n\ntype GlobalWithCoachmarkRuntime = typeof globalThis & {\n [COACHMARK_RUNTIME_SLOT]?: CoachmarkRuntime;\n};\n\nconst runtimeGlobal = globalThis as GlobalWithCoachmarkRuntime;\n\nconst coachmarkRuntime = (): CoachmarkRuntime => {\n const existing = runtimeGlobal[COACHMARK_RUNTIME_SLOT];\n if (existing) return existing;\n const created: CoachmarkRuntime = { storage: null, testing: false, coachmarksEnabled: true };\n runtimeGlobal[COACHMARK_RUNTIME_SLOT] = created;\n return created;\n};\n\nconst enabledListeners = (): Set<() => void> => {\n const runtime = coachmarkRuntime();\n if (!runtime.listeners) runtime.listeners = new Set();\n return runtime.listeners;\n};\n\n/**\n * Wake the subscribers on a MICROTASK, never synchronously.\n *\n * `CoachmarkProvider` writes this flag during its RENDER phase on purpose (so a child's mount\n * effect already sees the resolved value). Notifying from there synchronously would schedule a\n * React update while a *different* component is rendering. Every subscriber reads the value\n * through `areCoachmarksEnabled()` at render time anyway, so the notification only has to wake\n * the components that are not already re-rendering — one microtask later is soon enough, and it\n * keeps the write side legal from anywhere.\n */\nconst notifyCoachmarksEnabled = (): void => {\n if (enabledListeners().size === 0) return;\n void Promise.resolve().then(() => {\n for (const listener of [...enabledListeners()]) {\n try {\n listener();\n } catch {\n // A broken subscriber must never break the kill switch for the others.\n }\n }\n });\n};\n\n/**\n * Set the coachmarks master switch (from the resolved feature flags). Default true (fail-open).\n * Written by CoachmarkProvider; read imperatively by the tour arm + the overlay store, and\n * SUBSCRIBED to by `useCoachmarkTour` (see `subscribeCoachmarksEnabled`).\n *\n * No-ops when the value is unchanged, which matters because the provider writes it on every\n * render — without that guard every render would fan out a notification.\n */\nexport const setCoachmarksEnabled = (value: boolean): void => {\n const runtime = coachmarkRuntime();\n if (runtime.coachmarksEnabled === value) return;\n runtime.coachmarksEnabled = value;\n notifyCoachmarksEnabled();\n};\n\n/** Whether the coachmarks module is enabled. False → tours/overlays are silently skipped. */\nexport const areCoachmarksEnabled = (): boolean => coachmarkRuntime().coachmarksEnabled;\n\n/**\n * Mark whether the value in `coachmarksEnabled` is the tenant's ANSWER or still the optimistic\n * default nobody has confirmed. Written by CoachmarkProvider from the resolved features' `settled`;\n * read (subscribed) by `useCoachmarkTour`'s ARM effect, and by nothing else.\n *\n * ── WHY A SECOND FLAG AND NOT A THIRD STATE ON `coachmarksEnabled` ──────────────────────────────\n * The features fetch seeds the all-on defaults and swaps when `GET /v1/features` resolves, so on\n * every cold start there is a window where \"coachmarks: on\" only means \"nobody has asked yet\". A\n * tenant who switched the module OFF still gets the first tour of every launch out of that window.\n *\n * The obvious repair — hold the surface by writing `setCoachmarksEnabled(false)` until the answer\n * lands — CANNOT be used here, and would ship a strictly worse defect. That flag is TERMINAL: the\n * tour subscribes to it and a flip to false calls `exit()`, ending the tour. Writing it `false`\n * during the wait would end the tour of every ENABLED tenant on every cold start. So the two facts\n * are kept apart, and only one of them is terminal:\n * • `coachmarksEnabled` — the verdict. `false` tears a tour down. Stays `true` while the answer\n * is unknown, so nothing is ever torn down on a guess.\n * • `coachmarksResolved` — \"is that verdict an answer?\". `false` only blocks ARMING a NEW tour.\n * No timer starts, no overlay shows, and no once-gate is consumed, so the tour plays in full\n * the moment an ON answer lands.\n *\n * \"Resolved\" means the fetch ANSWERED, not that it SUCCEEDED — `fetchWireFeatures` swallows a\n * timeout / 401 / 5xx into the all-on defaults and that fallback IS the answer, so an unreachable\n * control plane arms the tour rather than darking it (fail-open, unchanged).\n *\n * Shares the kill switch's listener set: a subscriber has to wake on either fact changing, and one\n * set is one thing to keep correct rather than two.\n */\nexport const setCoachmarksResolved = (value: boolean): void => {\n const runtime = coachmarkRuntime();\n if ((runtime.coachmarksResolved ?? true) === value) return;\n runtime.coachmarksResolved = value;\n notifyCoachmarksEnabled();\n};\n\n/**\n * Whether the coachmarks verdict is an ANSWER yet. False → a NEW tour must not arm (a tour already\n * in flight is untouched). Absent field → true: no provider, or an older inlined copy's record,\n * means nothing is going to answer this, which is the same fail-open default the features\n * `settled` context takes.\n */\nexport const areCoachmarksResolved = (): boolean =>\n coachmarkRuntime().coachmarksResolved ?? true;\n\n/**\n * Subscribe to kill-switch flips. Returns the unsubscribe function — the `useSyncExternalStore`\n * contract, and deliberately the SAME shape as `coachmarkOverlay.subscribe` next door rather than\n * a second pattern to keep correct.\n *\n * WHY IT EXISTS: the flag is a mutable `globalThis` value, so on its own it can only be SAMPLED.\n * A tour that samples it cannot notice a tenant flipping it off mid-flight — the overlay's\n * `show()` quietly becomes a no-op while the tour still believes it is running, so nothing paints,\n * nothing can be tapped to advance, and no terminal path is reachable. `useCoachmarkTour`\n * subscribes instead. The listener set lives in the SAME `globalThis` record as the flag, so every\n * inlined copy of this module shares one subscriber list.\n *\n * It also carries `coachmarksResolved` (see `setCoachmarksResolved`): both facts wake the same\n * listeners, so a `useSyncExternalStore` over either one uses this same subscribe function.\n */\nexport const subscribeCoachmarksEnabled = (listener: () => void): (() => void) => {\n const listeners = enabledListeners();\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\n/** Set (or clear) the injected sync gate storage. Called by CoachmarkProvider. */\nexport const setCoachmarkStorage = (storage: CoachmarkStorage | null): void => {\n coachmarkRuntime().storage = storage;\n};\n\n/** The currently-injected gate storage, or null if no provider is mounted. */\nexport const getCoachmarkStorage = (): CoachmarkStorage | null => coachmarkRuntime().storage;\n\n/**\n * Toggle the global QA replay flag. When true, EVERY seen-gate reads as unseen\n * and every seen-write is suppressed, so every tour + showcase replays on each\n * mount. The app flips ONE boolean to QA the whole coachmark surface.\n */\nexport const setCoachmarkTesting = (value: boolean): void => {\n coachmarkRuntime().testing = value;\n};\n\n/** Whether replay-everything QA mode is on. */\nexport const isCoachmarkTesting = (): boolean => coachmarkRuntime().testing;\n\n/** Gate key for a tour: `wire_coachmark_<tourId>_seen`. */\nexport const coachmarkGateKey = (tourId: string): string =>\n `wire_coachmark_${tourId}_seen`;\n\n/** Gate key for a feature showcase: `wire_showcase_<id>_seen`. */\nexport const showcaseGateKey = (showcaseId: string): string =>\n `wire_showcase_${showcaseId}_seen`;\n\n/** Marker value written for a seen gate. */\nconst SEEN_VALUE = \"1\";\n\n/** Key used only by the one-off synchronicity probe below. Never carries a meaningful value. */\nconst GATE_PROBE_KEY = \"wire_gate_probe\";\n\n/** Once-per-process latch on its own `Symbol.for` slot, mirroring `gateStorageWarned` next door\n * in reviews/runtime: a plain `let` would warn once per inlined bundle copy, and the gates live\n * in three of them.\n *\n * @globalSlot LATCH — written `true` by the first probe that caught an ASYNC gate adapter, and\n * never again. A second differing write re-arms a warning the process already spent, so a host\n * whose broken adapter reaches three gates gets the same paragraph three times and stops reading. */\nconst ASYNC_GATE_STORAGE_WARNED_SLOT: unique symbol = Symbol.for(\n \"@wireai/activation:asyncGateStorageWarned\",\n);\n\ntype GlobalWithAsyncGateWarn = typeof globalThis & {\n [ASYNC_GATE_STORAGE_WARNED_SLOT]?: boolean;\n};\n\nconst asyncGateWarnGlobal = globalThis as GlobalWithAsyncGateWarn;\n\n/**\n * The substitute for an adapter whose `getItem` returned a thenable (an ASYNC adapter, e.g.\n * AsyncStorage handed straight in). Every seen-gate reads SEEN and every write is dropped, so\n * nothing shows and nothing fires — FAIL CLOSED, deliberately in both directions the async bug\n * could err: a Promise is never `=== \"1\"`, so a raw async adapter reports every gate UNSEEN\n * forever — tours and showcases replay on every open, and a review gate with `minSessions` 0/1\n * RE-FIRES its prompt each open (the 2026-07-16 one-star incident class). Never-fire is the only\n * direction a once-per-user gate may err in.\n */\nconst closedGateStorage: CoachmarkStorage = Object.freeze({\n getItem: (): string => SEEN_VALUE,\n setItem: (): void => {},\n});\n\n/** Adapters probed sync (or throwing, which every reader already tolerates): pass through. */\nconst syncGateAdapters = new WeakSet<CoachmarkStorage>();\n/** Adapters caught returning a thenable: substituted, and never probed again. */\nconst asyncGateAdapters = new WeakSet<CoachmarkStorage>();\n\n/** Warn once, in dev builds only, when a gate adapter turned out to be async. */\nconst warnAsyncGateStorage = (): void => {\n if (asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT]) return;\n if (typeof __DEV__ === \"undefined\" || !__DEV__) return;\n if (typeof console === \"undefined\" || !console.warn) return;\n asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT] = true;\n console.warn(\n \"[wireai] the gate storage's getItem returned a Promise — an async adapter (e.g. AsyncStorage) \" +\n \"cannot drive the once-per-user gates, so coachmark tours, showcases and the review/questionnaire \" +\n \"gates are all DISABLED (fail closed: nothing shows, nothing fires) until a synchronous adapter \" +\n \"is provided. Pass a sync adapter (e.g. MMKV: `{ getItem: (k) => mmkv.getString(k) ?? null, \" +\n \"setItem: (k, v) => mmkv.set(k, v) }`) to CoachmarkProvider or the gate's `storage` prop.\",\n );\n};\n\n/** Test-only: forget the once-per-process async-adapter warn latch. */\nexport const resetAsyncGateStorageWarning = (): void => {\n asyncGateWarnGlobal[ASYNC_GATE_STORAGE_WARNED_SLOT] = undefined;\n};\n\n/**\n * The thenable probe (fail closed): resolve an adapter to itself when its `getItem` is\n * synchronous, and to `closedGateStorage` when it returns a thenable. Called on every gate READ\n * rather than at injection, so (a) a host handing storage straight to a gate's `storage` prop is\n * probed too, and (b) `CoachmarkProvider`'s unmount cleanup — which compares the singleton to its\n * own prop by IDENTITY — keeps seeing the object the host passed. Verdicts are WeakSet-cached, so\n * each adapter pays for exactly one probe read.\n */\nexport const validateGateStorage = (\n storage: CoachmarkStorage | null,\n): CoachmarkStorage | null => {\n if (!storage) return null;\n if (syncGateAdapters.has(storage)) return storage;\n if (asyncGateAdapters.has(storage)) return closedGateStorage;\n let probed: unknown;\n try {\n probed = storage.getItem(GATE_PROBE_KEY);\n } catch {\n // A throwing adapter is synchronous, which is all the probe rules on; every reader already\n // tolerates the throw itself.\n syncGateAdapters.add(storage);\n return storage;\n }\n if (probed != null && typeof (probed as { then?: unknown }).then === \"function\") {\n asyncGateAdapters.add(storage);\n try {\n // Detach the probe's promise so an adapter that REJECTS (e.g. a broken native store) cannot\n // surface as an unhandled rejection the host never scheduled.\n (probed as PromiseLike<unknown>).then(undefined, () => {});\n } catch {\n // A hostile thenable whose `then` throws is still async; the verdict stands.\n }\n warnAsyncGateStorage();\n return closedGateStorage;\n }\n syncGateAdapters.add(storage);\n return storage;\n};\n\n/**\n * Read a seen gate. Testing mode ALWAYS reports unseen (so everything replays).\n * A missing storage (no provider) also reports unseen — the safe default is to\n * show the hint rather than silently swallow it. `storageOverride` /\n * `testingOverride` let a self-contained component (e.g. FeatureShowcase) pass\n * its own storage without relying on the provider singleton.\n */\nexport const hasSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): boolean => {\n if (testingOverride ?? isCoachmarkTesting()) return false;\n const storage = validateGateStorage(storageOverride ?? getCoachmarkStorage());\n if (!storage) return false;\n try {\n return storage.getItem(key) === SEEN_VALUE;\n } catch {\n return false;\n }\n};\n\n/**\n * Mark a gate seen. Suppressed in testing mode (so replay never persists) and a\n * no-op without storage. Best-effort — a throwing adapter never breaks the tour.\n */\nexport const markSeenGate = (\n key: string,\n storageOverride?: CoachmarkStorage | null,\n testingOverride?: boolean,\n): void => {\n if (testingOverride ?? isCoachmarkTesting()) return;\n const storage = validateGateStorage(storageOverride ?? getCoachmarkStorage());\n if (!storage) return;\n try {\n storage.setItem(key, SEEN_VALUE);\n } catch {\n // Best-effort: a failed write just means the hint may show once more.\n }\n};\n","/**\n * The fail-open defaults + a tolerant parser for the server's flags payload.\n *\n * THE CONTRACT: fail-open, never fail-dark. An absent server object, a missing module key, a\n * malformed value, or an unreachable endpoint must resolve to the MOST PERMISSIVE state — every\n * module ON, onboarding `ai` — so a control-plane outage can only ever be more permissive than\n * the dashboard intends. It can never dark a tenant's activation. Matches the server's own\n * documented fail-open default (FEATURES.md: \"local defaults — every module on, onboarding ai\").\n */\nimport type { OnboardingMode, WireFeatures } from \"./types\";\n\n/**\n * ALL ON, onboarding `ai`. Frozen + module-level so its reference is stable across every call\n * (consumers that list resolved flags in an effect dep array never loop on a fresh identity).\n */\nexport const defaultWireFeatures: WireFeatures = Object.freeze({\n coachmarks: Object.freeze({ enabled: true }),\n showcase: Object.freeze({ enabled: true }),\n onboarding: Object.freeze({ mode: \"ai\" as OnboardingMode }),\n review: Object.freeze({ enabled: true }),\n questionnaire: Object.freeze({ enabled: true }),\n announcements: Object.freeze({ enabled: true }),\n}) as WireFeatures;\n\nconst VALID_MODES: readonly OnboardingMode[] = [\"ai\", \"static\", \"off\"];\n\n/** Read a `{ enabled: boolean }` module, defaulting to ON when absent/malformed (fail-open). */\nconst readEnabled = (raw: unknown): { enabled: boolean } => {\n if (raw && typeof raw === \"object\" && typeof (raw as { enabled?: unknown }).enabled === \"boolean\") {\n return { enabled: (raw as { enabled: boolean }).enabled };\n }\n return { enabled: true };\n};\n\n/**\n * Narrow the server's (untrusted) JSON to a complete `WireFeatures`. Every field is filled with\n * its fail-open default when the server omits it or sends the wrong type, so a partial or\n * malformed payload degrades PERMISSIVELY rather than throwing. A non-object input (null, array,\n * string) → the full defaults. Never throws.\n */\nexport const parseWireFeatures = (raw: unknown): WireFeatures => {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return defaultWireFeatures;\n const src = raw as Record<string, unknown>;\n const modeRaw = (src.onboarding as { mode?: unknown } | undefined)?.mode;\n const mode: OnboardingMode =\n typeof modeRaw === \"string\" && VALID_MODES.includes(modeRaw as OnboardingMode)\n ? (modeRaw as OnboardingMode)\n : \"ai\";\n return {\n coachmarks: readEnabled(src.coachmarks),\n showcase: readEnabled(src.showcase),\n onboarding: { mode },\n review: readEnabled(src.review),\n questionnaire: readEnabled(src.questionnaire),\n announcements: readEnabled(src.announcements),\n };\n};\n\n/** Value-equality of two resolved flags — lets the hook hold a stable reference across churn. */\nexport const featuresEqual = (a: WireFeatures, b: WireFeatures): boolean =>\n a === b ||\n (a.coachmarks.enabled === b.coachmarks.enabled &&\n a.showcase.enabled === b.showcase.enabled &&\n a.onboarding.mode === b.onboarding.mode &&\n a.review.enabled === b.review.enabled &&\n a.questionnaire.enabled === b.questionnaire.enabled &&\n a.announcements.enabled === b.announcements.enabled);\n","/**\n * The last-known-flags cache — persisted through the host's optional `storage`.\n *\n * WHY: the fetch is best-effort and fail-open. When the control plane is unreachable we serve the\n * LAST value we saw rather than snapping to defaults, so a tenant that intentionally disabled a\n * module during an incident keeps it disabled across an outage instead of flapping back on. That\n * is \"stale-while-error\": a fresh cache (< TTL) is trusted, and on a fetch error even a STALE\n * cache is served (any age beats a guess). Every operation is best-effort — a broken/hung storage\n * degrades to defaults, never a throw and never a stuck gate (mirrors persistedSession).\n */\nimport { parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\n/**\n * TTL for a cached flags entry, aligned to the server's `Cache-Control: private, max-age=300`.\n * A cache younger than this is \"fresh\"; older is \"stale\" (still served on a fetch error).\n */\nexport const DEFAULT_FEATURES_TTL_MS = 300_000;\n\n/** Ceiling on the storage read so a hung adapter degrades to defaults, never a stuck resolve. */\nconst READ_TIMEOUT_MS = 1_500;\n\n/** Storage key for a tenant's cached flags, e.g. `wireai:features:acme`. */\nexport const featuresCacheKey = (appId?: string): string =>\n `wireai:features:${appId && appId.length > 0 ? appId : \"default\"}`;\n\n/** A cached flags entry: the resolved flags + the epoch-ms they were fetched. */\nexport interface CachedFeatures {\n features: WireFeatures;\n /** Age of the entry in ms at read time. */\n ageMs: number;\n}\n\nconst withTimeout = <T>(p: Promise<T>, ms: number): Promise<T | undefined> => {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), ms);\n });\n return Promise.race([p, timeout]).finally(() => clearTimeout(timer));\n};\n\n/** Whether a cache entry is still within the TTL (server max-age aligned). */\nexport const isFeaturesFresh = (ageMs: number, ttlMs: number = DEFAULT_FEATURES_TTL_MS): boolean =>\n ageMs >= 0 && ageMs < ttlMs;\n\n/**\n * Read the cached flags for `key`, or `undefined` when absent/corrupt/timed-out. Returns the\n * value AND its age so a caller can apply a TTL (fresh) or ignore it (stale-while-error). Never\n * throws; never hangs past the read timeout. The stored value is re-parsed through\n * `parseWireFeatures`, so a partially-corrupt entry still degrades fail-open.\n */\nexport const readCachedFeatures = async (\n storage: WireOnboardingStorage,\n key: string,\n): Promise<CachedFeatures | undefined> => {\n let raw: string | null | undefined;\n try {\n raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);\n } catch {\n return undefined;\n }\n if (!raw) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && typeof (parsed as { ts?: unknown }).ts === \"number\") {\n const ts = (parsed as { ts: number }).ts;\n return {\n features: parseWireFeatures((parsed as { features?: unknown }).features),\n ageMs: Date.now() - ts,\n };\n }\n } catch {\n // Corrupt entry → treat as absent; the caller falls back to defaults / a fresh fetch.\n }\n return undefined;\n};\n\n/** Persist `{ features, ts }` under `key` — fire-and-forget, all errors swallowed. */\nexport const writeCachedFeatures = (\n storage: WireOnboardingStorage,\n key: string,\n features: WireFeatures,\n): void => {\n try {\n void storage\n .setItem(key, JSON.stringify({ features, ts: Date.now() }))\n .catch(() => {});\n } catch {\n // Best-effort: a failed write just means the next launch has no cache to fall back to.\n }\n};\n","/**\n * fetchWireFeatures — read the per-module kill switches from `GET {serverUrl}/v1/features`.\n *\n * Contract (server: chohra-med/wireai-onboarding-server, routers/onboarding.py):\n * GET {serverUrl}/v1/features\n * Authorization: Bearer {apiKey}\n * 200 → { coachmarks:{enabled}, showcase:{enabled}, onboarding:{mode}, review:{enabled},\n * announcements:{enabled} } (Cache-Control: private, max-age=300)\n *\n * THE CONTRACT — fail-open, never fail-dark. Unreachable, timed-out, unauthorized (401),\n * server-error (5xx), or malformed JSON all resolve to the LAST CACHED value, else the\n * all-on defaults. No throw ever reaches the host: this is timeout-capped and swallows every\n * error, exactly like the session's best-effort reads. A control-plane outage can only ever be\n * MORE permissive than the dashboard intends — it can never dark a tenant's activation.\n */\nimport { readCachedFeatures, featuresCacheKey, writeCachedFeatures } from \"./cache\";\nimport { defaultWireFeatures, parseWireFeatures } from \"./defaults\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\nimport type { WireOnboardingStorage } from \"../session/persistedSession\";\n\nconst DEFAULT_TIMEOUT_MS = 4_000;\n\n/** The fail-open fallback: last cached value (any age — stale-while-error), else defaults. */\nconst failOpen = async (\n storage: WireOnboardingStorage | undefined,\n key: string,\n): Promise<WireFeatures> => {\n if (!storage) return defaultWireFeatures;\n const cached = await readCachedFeatures(storage, key);\n return cached?.features ?? defaultWireFeatures;\n};\n\n/** \"The exchange produced nothing usable\" — a non-2xx, or a deadline the body never met. Both mean\n * the caller must fail OPEN, and neither is distinguishable to it. A symbol so it can never\n * collide with a JSON body the server actually sent. */\nconst NO_ANSWER: unique symbol = Symbol(\"wire-features-no-answer\");\n\n/**\n * GET **and read the body** under ONE deadline. Never pends longer than `timeoutMs`.\n *\n * ── THE DEFECT THIS CLOSES ─────────────────────────────────────────────────────────────────────\n * The timer used to be cleared in a `finally` around the `fetch` alone, so it died the moment the\n * HEADERS landed and `await res.json()` ran with NO ceiling at all. A 200 whose body then stalls —\n * a half-open connection, a proxy that flushes headers and hangs, a captive portal — left this\n * function pending forever. `settled` never flips, so `useReviewGate` and `useQuestionnaireGate`\n * never become ready and BOTH gates stay dark for the life of the process, silently. That INVERTS\n * this module's own stated contract at the top of the file: fail-open, never fail-dark.\n *\n * SCOPE, honestly: on native RN `fetch` is the XHR polyfill and the body is already buffered by the\n * time the promise resolves, so this was effectively unreachable there. On RN-Web / Expo web — which\n * the kit explicitly supports (`WireFeaturesProvider`) — it is real.\n *\n * TWO mechanisms, deliberately, because they fail differently. The abort tears the socket DOWN\n * (a stalled stream is not just un-awaited, it is cancelled); the race guarantees this promise\n * SETTLES even on a runtime that ignores `signal` once the body has started. A ceiling that depends\n * on the host honouring abort is not a ceiling on a surface whose whole contract is \"never dark\".\n */\nconst fetchFeaturesJson = async (\n url: string,\n apiKey: string,\n timeoutMs: number,\n): Promise<unknown> => {\n const controller =\n typeof AbortController !== \"undefined\" ? new AbortController() : undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const expired = new Promise<typeof NO_ANSWER>((resolve) => {\n timer = setTimeout(() => {\n controller?.abort();\n resolve(NO_ANSWER);\n }, timeoutMs);\n });\n const exchange = (async (): Promise<unknown> => {\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\", Authorization: `Bearer ${apiKey}` },\n signal: controller?.signal,\n });\n // 401 (bad/rotated key), 5xx, any non-2xx → last-known, never dark.\n if (!res || !res.ok) return NO_ANSWER;\n return (await res.json()) as unknown; // throws on malformed body → caught by the caller\n })();\n try {\n return await Promise.race([exchange, expired]);\n } finally {\n clearTimeout(timer);\n // The loser can still settle after the race is decided and nothing is awaiting it. An\n // unobserved rejection is a hard crash on some hosts, so it gets a handler either way.\n void exchange.catch(() => {});\n }\n};\n\n/**\n * Resolve the tenant's feature flags. Attempts the network once; on ANY failure returns the\n * cached value (any age), else the all-on defaults. On success, persists the fresh value to the\n * cache (fire-and-forget) and returns it. Never throws.\n *\n * const flags = await fetchWireFeatures({ serverUrl, apiKey, appId, storage });\n * if (!flags.coachmarks.enabled) { /* skip the tour * / }\n */\nexport const fetchWireFeatures = async (\n config?: WireFeaturesConfig,\n): Promise<WireFeatures> => {\n const key = featuresCacheKey(config?.appId);\n const storage = config?.storage;\n\n // Nothing to fetch (no creds) → cache, else defaults. Lets a host mount the provider before\n // its config is ready without ever darking.\n if (!config?.serverUrl || !config?.apiKey) return failOpen(storage, key);\n\n const url = `${config.serverUrl.replace(/\\/$/, \"\")}/v1/features`;\n const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;\n\n try {\n const json: unknown = await fetchFeaturesJson(url, config.apiKey, timeoutMs);\n // A non-2xx, or a headers-then-stall body that never met the deadline → last-known, never dark.\n if (json === NO_ANSWER) return failOpen(storage, key);\n const features = parseWireFeatures(json);\n if (storage) writeCachedFeatures(storage, key, features);\n return features;\n } catch {\n // Abort, network error, missing fetch, or malformed JSON — all fail open.\n return failOpen(storage, key);\n }\n};\n","/**\n * useWireFeatures — resolve the tenant's feature flags for a component tree, once per mount.\n *\n * Returns the all-on defaults immediately (fail-open), then swaps to the fetched value when the\n * network resolves. When no `serverUrl`+`apiKey` is supplied it never fetches and just returns\n * defaults, so a host that never adopts flags sees ZERO behavior change and ZERO network calls.\n *\n * ⚠️ THE OPTIMISTIC DEFAULT IS A GUESS, AND SOME CONSUMERS CANNOT ACT ON A GUESS. Fail-open is the\n * right resting state, but \"all on because we have not asked yet\" and \"all on because the tenant\n * says so\" are different answers and the returned flags cannot tell them apart. A surface whose\n * first render is IRREVERSIBLE — the review gate posts a `review_prompt_shown` and can take a row\n * the moment it appears — needs the difference, or a tenant with `review.enabled: false` still gets\n * one impression on every launch before the answer lands. {@link useWireFeaturesState} exposes it as\n * `settled`; `useWireFeatures` is the flags-only wrapper and is unchanged.\n *\n * frequent_rules #11 (unstable inline props): the config is idiomatically passed inline\n * (`config={{ serverUrl, apiKey }}`), a fresh identity every render. We stabilize the fetch key\n * by VALUE so the effect fires once per real credential change, and we only swap the returned\n * flags object when its VALUES change — so a host that lists the returned flags in an effect dep\n * array settles in a bounded number of commits instead of looping (enforced by the canary suite).\n */\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { defaultWireFeatures, featuresEqual } from \"./defaults\";\nimport { fetchWireFeatures } from \"./fetchWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\n/** Hold a stable reference for a value while its CONTENT is unchanged (see reviews/equality.ts). */\nconst useStableValue = <T,>(value: T, isEqual: (a: T, b: T) => boolean): T => {\n const ref = useRef(value);\n if (!isEqual(ref.current, value)) ref.current = value;\n return ref.current;\n};\n\n/** The credential slice that actually drives a refetch — stabilized by value. */\nconst sameFetchKey = (a: WireFeaturesConfig | undefined, b: WireFeaturesConfig | undefined): boolean =>\n a?.serverUrl === b?.serverUrl && a?.apiKey === b?.apiKey && a?.appId === b?.appId;\n\n/**\n * The flags PLUS whether they are an answer yet — the shape `useWireFeatures` returns half of.\n *\n * `settled: false` means \"nobody has answered; these are the optimistic defaults\". It becomes\n * `true` the moment the fetch resolves (fail-open included: an unreachable control plane resolves\n * to the defaults and that IS a settled answer, because it is the answer we are keeping), and it\n * starts `true` whenever there is nothing to wait for — no creds, so no flag can ever arrive.\n */\nexport interface WireFeaturesState {\n flags: WireFeatures;\n /** `false` only while a fetch that could still change the answer is in flight. */\n settled: boolean;\n}\n\nexport const useWireFeaturesState = (config?: WireFeaturesConfig): WireFeaturesState => {\n const stableConfig = useStableValue(config, sameFetchKey);\n const [flags, setFlags] = useState<WireFeatures>(defaultWireFeatures);\n\n const canFetch = !!stableConfig?.serverUrl && !!stableConfig?.apiKey;\n // Nothing to fetch → the defaults are already the final answer, so a consumer that waits for an\n // answer must not wait forever. Only ever moves to `true`: a later credential change refreshes a\n // KNOWN answer, and un-answering it would re-hide a surface the user is already looking at.\n const [settled, setSettled] = useState<boolean>(!canFetch);\n\n useEffect(() => {\n if (!canFetch) {\n // No creds → stay on the all-on defaults (and reset if creds were removed).\n setFlags((prev) => (featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures));\n setSettled(true);\n return;\n }\n let alive = true;\n // fetchWireFeatures never throws — the .then always runs with a fail-open value.\n void fetchWireFeatures(stableConfig).then((next) => {\n if (!alive) return;\n // Only adopt a NEW reference on a real value change, so a host effect keyed on the\n // returned flags doesn't loop (frequent_rules #11).\n setFlags((prev) => (featuresEqual(prev, next) ? prev : next));\n // Settled on EVERY resolution, including the fail-open one: `fetchWireFeatures` swallows a\n // timeout / 401 / 5xx into the defaults, and that fallback is the final answer, not a\n // pending one. This is what keeps fail-open intact — a broken control plane resolves fast\n // and permissive, it does not leave a gated surface waiting.\n setSettled(true);\n });\n return () => {\n alive = false;\n };\n }, [canFetch, stableConfig]);\n\n return useMemo(() => ({ flags, settled }), [flags, settled]);\n};\n\n/** The flags alone — the original hook, unchanged for every consumer that cannot act on `settled`. */\nexport const useWireFeatures = (config?: WireFeaturesConfig): WireFeatures =>\n useWireFeaturesState(config).flags;\n","/**\n * WireFeaturesProvider + useResolvedFeatures — the OPTIONAL one-fetch-serves-all-modules layer.\n *\n * Mount `WireFeaturesProvider` once near your app root with the tenant `config` and it fetches the\n * flags ONCE; every gated surface below it (coachmarks / showcase / reviews) reads the same\n * resolved value from context instead of each fetching its own. It is entirely optional: with no\n * provider, every surface falls back to its own lazy fetch (when given a config) or to the all-on\n * defaults, so modules work with zero setup and a host that never adopts flags is unchanged.\n *\n * NOTE on the built npm subpaths: React context is shared across the kit's subpath entries in the\n * SOURCE-consumption path (the monorepo apps) and in this test suite — one module instance, one\n * context. If you consume the built `@wireai/activation/*` subpaths as separate bundles, pass the\n * resolved flags (or a `featuresConfig`) to each surface explicitly instead of relying on context.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\n\nimport { defaultWireFeatures } from \"./defaults\";\nimport { useWireFeaturesState, type WireFeaturesState } from \"./useWireFeatures\";\nimport type { WireFeatures, WireFeaturesConfig } from \"./types\";\n\n/**\n * @globalSlot LATCH — the React context object is minted by the first copy of this module to load\n * and every later copy ADOPTS it (the `if (!…)` guard below). A second write would re-split the\n * identity the guard exists to keep whole: the provider would publish into one context while a\n * subpath bundle's `useContext` read another, and `useResolvedFeatures`' null fallback would serve\n * the all-on defaults with no crash and no warning. Because it is a latch, and only because of\n * that, the module-local `const WireFeaturesContext` below may cache it.\n */\nconst CONTEXT_SYMBOL: unique symbol = Symbol.for(\"wireai.features.context\");\n// `globalThis`, not `global`: the other nine `Symbol.for` slots in this kit all use it, and `global`\n// simply does not exist in a plain browser (RN-web / SSR-in-the-browser), where this line would\n// throw a ReferenceError before the provider could render anything.\n//\n// The slot is TYPED rather than cast through `any` (which is banned, `ai_rules/rules/core.md`). The\n// cast was not cosmetic: with `any` on both sides, BOTH contexts below were inferred `any`, so every\n// `<X.Provider value={...}>` in this file and every `useContext` read of them was type-unchecked —\n// a provider publishing the wrong shape into either one would have compiled. Declaring each key\n// `unique symbol` is what lets it appear as a property key in a type at all.\ntype GlobalWithFeaturesContext = typeof globalThis & {\n [CONTEXT_SYMBOL]?: React.Context<WireFeatures | null>;\n};\nconst featuresContextGlobal = globalThis as GlobalWithFeaturesContext;\n\nif (!featuresContextGlobal[CONTEXT_SYMBOL]) {\n featuresContextGlobal[CONTEXT_SYMBOL] = createContext<WireFeatures | null>(null);\n}\nconst WireFeaturesContext = featuresContextGlobal[CONTEXT_SYMBOL];\n\n/**\n * @globalSlot LATCH — the SECOND context, carrying only \"has the provider's fetch answered yet?\".\n *\n * WHY A SECOND CONTEXT AND NOT A WIDER VALUE: the value published above is a `WireFeatures`, and\n * tsup inlines a copy of this module per subpath bundle. Changing the published SHAPE would mean a\n * provider from one copy publishing an object a consumer from another copy reads as flags —\n * silently wrong flags rather than a crash. An extra context is additive: a consumer that reads it\n * without a provider (or under an OLDER copy's provider that publishes nothing here) gets the\n * default below.\n *\n * THE DEFAULT IS `true`, AND FAIL-OPEN DEPENDS ON IT: \"settled\" gates a surface's first render, so\n * defaulting to `false` would let a missing provider suppress a gate forever. `true` means \"nothing\n * above is going to answer this for you\", which is the truth when there is no provider at all.\n */\nconst SETTLED_SYMBOL: unique symbol = Symbol.for(\"wireai.features.settled.context\");\ntype GlobalWithSettledContext = typeof globalThis & {\n [SETTLED_SYMBOL]?: React.Context<boolean>;\n};\nconst settledContextGlobal = globalThis as GlobalWithSettledContext;\nif (!settledContextGlobal[SETTLED_SYMBOL]) {\n settledContextGlobal[SETTLED_SYMBOL] = createContext<boolean>(true);\n}\nconst WireFeaturesSettledContext = settledContextGlobal[SETTLED_SYMBOL];\n\nexport interface WireFeaturesProviderProps {\n /** Tenant creds (+ optional storage) to fetch the flags once for the whole tree. */\n config?: WireFeaturesConfig;\n /**\n * Pre-resolved flags to provide directly instead of fetching (e.g. you already have them, or\n * you drive them from your own remote-config). Takes precedence over `config`.\n */\n flags?: WireFeatures;\n children: React.ReactNode;\n}\n\n/**\n * Fetch (or accept) the flags once and broadcast them to descendants. The provider VALUE is\n * memoized (performance rule #6) so a fresh object each render doesn't re-render every consumer.\n */\nexport const WireFeaturesProvider: React.FC<WireFeaturesProviderProps> = ({\n config,\n flags,\n children,\n}) => {\n // Always call the hook (rules of hooks); when `flags` is supplied we pass no config so it\n // never fetches and the explicit flags win below.\n const fetched = useWireFeaturesState(flags ? undefined : config);\n const value = flags ?? fetched.flags;\n // Explicit `flags` are an answer by definition; otherwise the fetch decides.\n const settled = flags ? true : fetched.settled;\n const stable = useMemo(() => value, [value]);\n return (\n <WireFeaturesSettledContext.Provider value={settled}>\n <WireFeaturesContext.Provider value={stable}>{children}</WireFeaturesContext.Provider>\n </WireFeaturesSettledContext.Provider>\n );\n};\n\nWireFeaturesProvider.displayName = \"WireFeaturesProvider\";\n\n/** Raw context read — `null` when no `WireFeaturesProvider` is mounted above. */\nexport const useWireFeaturesContext = (): WireFeatures | null =>\n useContext(WireFeaturesContext);\n\n/** Options for `useResolvedFeatures`: an explicit override and/or a lazy-fetch config. */\nexport interface ResolveFeaturesOptions {\n /** Explicit flags — win over everything (a surface's own `features` prop). */\n flags?: WireFeatures;\n /** Lazy-fetch config, used ONLY when there is no explicit `flags` and no provider above. */\n config?: WireFeaturesConfig;\n}\n\n/**\n * The resolution every gated surface uses. Precedence:\n * 1. explicit `options.flags` (a surface's own prop) →\n * 2. the nearest `WireFeaturesProvider` (context) →\n * 3. a lazy fetch from `options.config` (serverUrl + apiKey) →\n * 4. the all-on defaults.\n * Always fail-open, always a stable reference for a given value (so it's safe in effect deps).\n */\nexport const useResolvedFeatures = (options?: ResolveFeaturesOptions): WireFeatures =>\n useResolvedFeaturesState(options).flags;\n\n/**\n * The same resolution, plus whether the value is an ANSWER or still the optimistic default —\n * `useResolvedFeatures` is the flags-only wrapper over this.\n *\n * A gated surface whose first render is irreversible (the review gate fires `review_prompt_shown`\n * and can take a review row the moment it appears) must hold that first render until `settled`,\n * or a tenant that turned the module OFF still gets one impression per launch while the fetch is\n * in flight — the kill switch working everywhere except the one moment it is read.\n *\n * `settled` follows the same precedence as the flags: explicit `flags` are an answer; under a\n * provider it is the PROVIDER's fetch that has to answer; otherwise it is this surface's own lazy\n * fetch, which is already `true` when there is nothing to fetch. Deliberately INTERNAL (not in the\n * root barrel): it exists for the kit's own gated surfaces, and the public flags-only contract is\n * unchanged.\n */\nexport const useResolvedFeaturesState = (options?: ResolveFeaturesOptions): WireFeaturesState => {\n const ctx = useWireFeaturesContext();\n const ctxSettled: boolean = useContext(WireFeaturesSettledContext);\n // Only lazily fetch when nothing else provides the flags — otherwise pass no config so the\n // hook stays inert (defaults, no network). The hook is always called (rules of hooks).\n const shouldFetch = !options?.flags && ctx == null;\n const fetched = useWireFeaturesState(shouldFetch ? options?.config : undefined);\n const flags = options?.flags ?? ctx ?? fetched.flags ?? defaultWireFeatures;\n const settled = options?.flags ? true : ctx != null ? ctxSettled : fetched.settled;\n return useMemo(() => ({ flags, settled }), [flags, settled]);\n};\n","/**\n * Session-id persistence — the kit caching its OWN correlation seed across app kills.\n *\n * WHY: the session id is minted per mount and forwarded to the backend as the A2A\n * `contextId` (see WireOnboarding). Without persistence, an app KILL mid-onboarding\n * mints a NEW id on relaunch — the server counts a second `session_started` and the\n * orphaned first session reads as a phantom \"drop\", inflating the funnel's `started`\n * denominator. Persisting `{ id, ts }` and reusing a still-fresh id keeps a\n * kill-and-relaunch a SINGLE session in analytics.\n *\n * SCOPE: this persists the correlation seed ONLY — never answers. Answer persistence\n * stays a host concern via `onComplete` (the kit/host boundary is unchanged).\n *\n * The host injects the storage via the `storage` prop (an AsyncStorage-compatible\n * subset), keeping the kit dependency-free: an MMKV wrapper and AsyncStorage itself\n * both fit. Every operation is best-effort — a broken or hung storage must NEVER\n * break (or indefinitely gate) onboarding: reads race a short timeout, writes and\n * removes swallow all errors.\n */\nimport { makeSessionId } from \"../analytics/reportClientEvent\";\n\n/**\n * The storage the host injects. Deliberately the AsyncStorage-compatible subset so\n * `@react-native-async-storage/async-storage` can be passed as-is, and an MMKV (or\n * any other) wrapper is three one-line methods.\n */\nexport type WireOnboardingStorage = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\n/**\n * Matches the backend's session TTL (SESSION_TTL_SECONDS = 3600): an id older than\n * this can't be resumed server-side anyway, so the client mints fresh past it.\n */\nexport const DEFAULT_SESSION_TTL_MS = 3_600_000;\n\n/** Ceiling on the storage read — a hung adapter degrades to a fresh mint, never a stuck gate. */\nexport const READ_TIMEOUT_MS = 1_500;\n\n/** Storage key for an app's cached session, e.g. `wireai:session:acme`. */\nexport const sessionStorageKey = (appId: string): string => `wireai:session:${appId}`;\n\ntype PersistedSession = { id: string; ts: number };\n\n/** Resolved session for a mount: the id to use + whether it was restored from storage. */\nexport type LoadedSession = {\n id: string;\n /** True when a stored, still-fresh id was reused — the flow resumes instead of starting. */\n resumed: boolean;\n};\n\n/**\n * The verdict of a read that RAN OUT OF TIME. A distinct value, and deliberately never `undefined`:\n * an `undefined` here is byte-identical to \"the adapter answered, there is nothing stored\", and that\n * conflation is what let a timed-out read mint a fresh session id and WRITE IT OVER the still-valid\n * one it had not managed to read yet. The event queue reached the same conclusion independently\n * (`analytics/eventQueue.ts`); this is the same sentinel for the same reason.\n *\n * \"Did not answer in time\" is not \"there is nothing there\", and the difference is the difference\n * between starting clean and destroying a session mid-onboarding.\n */\nexport const READ_TIMED_OUT: unique symbol = Symbol(\"wireai:storage-read-timeout\");\n\n/**\n * Race a storage read against a ceiling, resolving {@link READ_TIMED_OUT} when the adapter did not\n * answer in time.\n * Exported so the permission memory reads through the same ceiling as the session seed rather than\n * carrying a second copy of it. NOT the kit's only such helper: `features/cache.ts`,\n * `session-analytics/lifecycle.ts` and `analytics/eventQueue.ts` each keep their own local timeout\n * for their own transports. Consolidating those is a separate change, not this one.\n */\nexport const withTimeout = <T>(p: Promise<T>, ms: number): Promise<T | typeof READ_TIMED_OUT> => {\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<typeof READ_TIMED_OUT>((resolve) => {\n timer = setTimeout(() => resolve(READ_TIMED_OUT), ms);\n });\n // Clear the timer once the race settles, so a won read doesn't leave a ≤ms no-op\n // timer holding the closure alive.\n return Promise.race([p, timeout]).finally(() => clearTimeout(timer));\n};\n\nconst parsePersisted = (raw: string | null | undefined): PersistedSession | undefined => {\n if (!raw) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n typeof (parsed as PersistedSession).id === \"string\" &&\n typeof (parsed as PersistedSession).ts === \"number\"\n ) {\n return parsed as PersistedSession;\n }\n } catch {\n // Corrupt entry → treat as absent; the caller mints fresh and overwrites it.\n }\n return undefined;\n};\n\n/**\n * Resolve the session id for this mount: reuse the stored one while it's fresh\n * (→ `resumed: true`), else mint via `makeSessionId`, persist it, and start clean.\n * Never throws; never hangs past the read timeout.\n */\nexport const loadPersistedSession = async (\n storage: WireOnboardingStorage,\n key: string,\n ttlMs: number = DEFAULT_SESSION_TTL_MS,\n): Promise<LoadedSession> => {\n let raw: string | null | typeof READ_TIMED_OUT;\n try {\n raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);\n } catch {\n raw = null;\n }\n // TIMED OUT: the mount cannot wait, so it still gets an id and starts clean — but it must NOT\n // persist it. Writing here overwrites a session the read was still fetching, and a valid\n // mid-onboarding session id is exactly the thing whose loss the server reads as a phantom drop.\n // Losing persistence for ONE launch is recoverable; overwriting the blob is not.\n if (raw === READ_TIMED_OUT) return { id: makeSessionId(), resumed: false };\n\n const stored = parsePersisted(raw);\n if (stored && Date.now() - stored.ts < ttlMs) {\n return { id: stored.id, resumed: true };\n }\n const id = makeSessionId();\n savePersistedSession(storage, key, id);\n return { id, resumed: false };\n};\n\n/**\n * Read the persisted session WITHOUT minting a fresh one (unlike `loadPersistedSession`).\n * Returns the stored `{ id, ts }` or `undefined` when absent/corrupt/timed-out. Used by the\n * post-onboarding `identifyOnboarding` helper to recover the contextId to bind a user to.\n * Never throws; never hangs past the read timeout.\n */\nexport const peekPersistedSession = async (\n storage: WireOnboardingStorage,\n key: string,\n): Promise<{ id: string; ts: number } | undefined> => {\n try {\n const raw = await withTimeout(storage.getItem(key), READ_TIMEOUT_MS);\n // A timed-out read is `undefined` here exactly as before: this function only READS, so\n // \"unknown\" and \"absent\" lead to the same caller behaviour and nothing destructive follows.\n if (raw === READ_TIMED_OUT) return undefined;\n return parsePersisted(raw);\n } catch {\n return undefined;\n }\n};\n\n/** Persist `{ id, ts }` under `key` — fire-and-forget, all errors swallowed. */\nexport const savePersistedSession = (\n storage: WireOnboardingStorage,\n key: string,\n id: string,\n): void => {\n try {\n void storage.setItem(key, JSON.stringify({ id, ts: Date.now() })).catch(() => {});\n } catch {\n // Best-effort: a failed write just means the next launch starts a fresh session.\n }\n};\n\n/** Remove the cached id (fired on completion) — fire-and-forget, all errors swallowed. */\nexport const clearPersistedSession = (storage: WireOnboardingStorage, key: string): void => {\n try {\n void storage.removeItem(key).catch(() => {});\n } catch {\n // Best-effort.\n }\n};\n\n/**\n * The opt-in decision for `WireOnboarding.handleComplete`: given the host's\n * `retainSessionOnComplete` opt-in, whether a completion should CLEAR the persisted seed.\n * (The caller still gates on `storage` being present — this only encodes the opt-in axis, so the\n * legacy `if (storage) clearPersistedSession(...)` guard stays byte-for-byte for a host that does\n * not opt in.)\n *\n * - undefined / false (the default) → `true`: clear on completion, so the NEXT onboarding on this\n * device mints a fresh session. This is the legacy single-stage behavior.\n * - true → `false`: LEAVE the seed in place so a same-signup re-entry/remount within the TTL\n * resumes the SAME session (one funnel start) instead of minting a phantom second `started`.\n * Freshness for a genuinely new run is then governed by the TTL (past `sessionTtlMs` → fresh\n * mint) and an explicit new-run signal (a changed `persistKey`).\n */\nexport const shouldClearOnComplete = (retainSessionOnComplete: boolean | undefined): boolean =>\n !retainSessionOnComplete;\n","/**\n * defaultOnboardingTheme — a neutral, light, brand-agnostic baseline. Consumers\n * pass a `Partial<OnboardingTheme>` that is deep-merged over this (see\n * `mergeTheme`), so they only override what differs from neutral.\n */\nimport type { OnboardingTheme } from \"./types\";\n\nexport const defaultOnboardingTheme: OnboardingTheme = {\n colors: {\n background: \"#FFFFFF\",\n surface: \"#F7F7F8\",\n text: \"#101114\",\n textMuted: \"#6B7280\",\n primary: \"#111111\",\n onPrimary: \"#FFFFFF\",\n primarySoft: \"rgba(17,17,17,0.06)\",\n border: \"#E4E4E7\",\n borderStrong: \"#C7C7CC\",\n disabled: \"#EBEBEB\",\n success: \"#16A34A\",\n warning: \"#D97706\",\n error: \"#DC2626\",\n info: \"#2563EB\",\n },\n fonts: {\n regular: undefined,\n medium: undefined,\n bold: undefined,\n baseSize: 16,\n scale: 1,\n },\n radius: {\n sm: 8,\n md: 12,\n lg: 16,\n full: 9999,\n },\n spacing: {\n xs: 4,\n sm: 8,\n md: 16,\n lg: 24,\n xl: 32,\n },\n // Circled (pill) CTA by default; an app can pass `button: { radius: 12 }` for\n // a rounded rectangle, or override height/paddingX to match its design system.\n button: {\n radius: 9999,\n height: 52,\n paddingX: 24,\n },\n};\n\n/**\n * Deep-merge a partial theme over the default. Two levels deep is enough — the\n * theme is intentionally shallow (colors/fonts/radius/spacing), so we merge each\n * known sub-object and leave scalars to overwrite.\n */\nexport const mergeTheme = (\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return defaultOnboardingTheme;\n return {\n colors: { ...defaultOnboardingTheme.colors, ...override.colors },\n fonts: { ...defaultOnboardingTheme.fonts, ...override.fonts },\n radius: { ...defaultOnboardingTheme.radius, ...override.radius },\n spacing: { ...defaultOnboardingTheme.spacing, ...override.spacing },\n button: { ...defaultOnboardingTheme.button, ...override.button },\n };\n};\n","/**\n * ThemeContext — provides the resolved OnboardingTheme to every shell element and\n * themed card via `useOnboardingTheme()`. WHY a context rather than prop-drilling:\n * the cards are mounted by the SDK's ComponentRenderer (not by us), so we can't\n * pass them props directly — they must read the theme from context.\n *\n * ── WHY THE CONTEXT LIVES ON A `Symbol.for` SLOT ───────────────────────────────────────────────\n *\n * It was a plain `createContext(...)`, and tsup inlines this module into FIVE dist bundles\n * (`.`, `./reviews`, `./questionnaire`, `./coachmarks`, `./showcase`) — so each one carried its own\n * context instance. `OnboardingThemeProvider` is exported ONLY from the root barrel, so on any\n * `dist` resolution path (plain RN CLI, `unstable_enablePackageExports: false`, node, jest, SSR) a\n * host that wrapped its tree in `<OnboardingThemeProvider>` and rendered `<ReviewGate>` from\n * `@wireai/activation/reviews` was writing one context and reading another. Nothing crashed and\n * nothing warned: `useOnboardingTheme`'s `ctx ?? mergeTheme()` fallback quietly served the NEUTRAL\n * default theme, so the tenant's brand simply did not apply to the gate. On-device this was masked\n * only because Metro's `react-native` export condition collapses every subpath back to this one\n * `src/` file — the same \"bundler accident, not a guarantee\" the `currentSession` header names, and\n * the same root cause as the optional-peers bug 0.13.3 fixed.\n *\n * The bundler-agnostic fix, exactly as `coachmarks/runtime`, `analytics/currentSession`,\n * `context/deviceId` and `features/WireFeaturesProvider` already do it: park the ONE context on a\n * well-known `globalThis` slot keyed by `Symbol.for(...)`. `Symbol.for` uses the runtime-global\n * symbol registry, so every inlined copy of this module resolves the SAME symbol, finds the slot\n * already filled, and reuses that instance — one context identity however many copies exist.\n * `globalThis` is present and identical in Hermes/React Native, Node and SSR (we never touch\n * `window`), so this is safe on every host. `test/canary/themeContextIdentity.test.tsx` measures it\n * in the BUILT artifact, because the defect is invisible in source.\n */\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { mergeTheme } from \"./defaultTheme\";\nimport type { OnboardingTheme } from \"./types\";\n\n/**\n * Well-known key into the runtime-global symbol registry. `Symbol.for` (NOT a plain `Symbol()`) is\n * what makes this cross-bundle: it returns the SAME symbol for the same string across every copy of\n * this module, so duplicated inlined copies all address one slot.\n *\n * @globalSlot LATCH — the React context object is minted by the first copy of this module to load\n * and every later copy ADOPTS it (the `if (!…)` guard below says so in one line). A second write\n * re-splits the identity: `<OnboardingThemeProvider>` (root barrel only) publishes into one context\n * while `<ReviewGate>` from a subpath reads another, and `useOnboardingTheme`'s `ctx ?? mergeTheme()`\n * fallback quietly serves the NEUTRAL theme. Because it is a latch, and only because of that, the\n * module-local `const OnboardingThemeContext` below may cache it.\n */\nconst THEME_CONTEXT_SLOT: unique symbol = Symbol.for(\"@wireai/activation:themeContext\");\n\ntype GlobalWithThemeContext = typeof globalThis & {\n [THEME_CONTEXT_SLOT]?: React.Context<OnboardingTheme | null>;\n};\n\nconst themeGlobal = globalThis as GlobalWithThemeContext;\n\n// First copy to load creates the context; every later copy adopts it. Never overwrite an existing\n// slot — a second `createContext` here would re-split the identity this guard exists to keep whole.\nif (!themeGlobal[THEME_CONTEXT_SLOT]) {\n themeGlobal[THEME_CONTEXT_SLOT] = createContext<OnboardingTheme | null>(null);\n}\nconst OnboardingThemeContext = themeGlobal[THEME_CONTEXT_SLOT] as React.Context<OnboardingTheme | null>;\n\nexport type OnboardingThemeProviderProps = {\n /** Partial overrides merged over the neutral default theme. */\n theme?: Partial<OnboardingTheme>;\n children: React.ReactNode;\n};\n\nexport const OnboardingThemeProvider: React.FC<OnboardingThemeProviderProps> = ({\n theme,\n children,\n}) => {\n const resolved = useMemo(() => mergeTheme(theme), [theme]);\n return (\n <OnboardingThemeContext.Provider value={resolved}>\n {children}\n </OnboardingThemeContext.Provider>\n );\n};\n\n/**\n * Read the active theme. Falls back to the default theme when used outside a\n * provider so a stray card never crashes — it just renders neutral.\n */\nexport const useOnboardingTheme = (): OnboardingTheme => {\n const ctx = useContext(OnboardingThemeContext);\n return ctx ?? mergeTheme();\n};\n","/**\n * blazejOnboarding — resolve `@blazejkustra/react-native-onboarding`, lazily and optionally.\n *\n * ── WHY THIS DOES NOT BREAK THE NO-NATIVE-DEPENDENCY POLICY ──────────────────────────────\n *\n * `@blazejkustra/react-native-onboarding` is an OPTIONAL peer of the showcase subpath — it is the\n * slide pager `FeatureShowcase` wraps. Before this file, `FeatureShowcase.tsx` imported its default\n * export at module scope, and `showcase/index.ts` re-exports the component with no wildcard escape,\n * so importing ANYTHING from `@wireai/activation/showcase` (even `selectShowcaseSlides`) dragged\n * the peer in, and a host that skipped the \"optional\" peer hit a Metro resolution failure. This\n * resolver removes that static edge. Same class and same shape as the 0.14.2 `expo-blur` fix\n * (`coachmarks/expoBlur.ts`), whose header carries the reasoning in full.\n *\n * The TYPES stay statically imported on purpose: a type-only import is erased by every toolchain\n * (babel, esbuild and sucrase all drop it), so it creates no runtime edge and no bundle dependency,\n * and `showcaseColors.ts` already relies on exactly that.\n *\n * ── THE SPECIFIER MUST BE A STRING LITERAL, INSIDE A TRY/CATCH ───────────────────────────\n *\n * Metro collects dependencies statically and matches only a call whose callee is literally the\n * identifier `require` and whose argument is literally a string; the try/catch around it is what\n * marks the dependency `isOptional`. Both halves are load-bearing — see `icons/expoIcons.ts` for\n * the full autopsy of the 0.8.0 shape that aliased the callee and was collected nowhere.\n *\n * ── THE DEGRADE ─────────────────────────────────────────────────────────────────────────\n *\n * Absent → `FeatureShowcase` renders null and calls `onDone` from an effect, which is the SAME path\n * the feature kill switch already takes. The host's flow always advances (a showcase that cannot\n * render must never strand the user on a blank screen), and the seen-gate is deliberately NOT\n * written, so installing the peer later still plays the showcase once.\n */\nimport type { ComponentType } from \"react\";\n\nimport type { OnboardingProps } from \"@blazejkustra/react-native-onboarding\";\n\n// Metro injects a module-scoped `require`; it is ABSENT in a pure-ESM runtime (the kit's own tests\n// run under `node --test` as ESM). Declared locally so this type-checks without ambient Node types;\n// the `typeof` guard keeps the reference ESM-safe.\ndeclare const require: ((id: string) => unknown) | undefined;\n\n/** A `require`-like resolver. Injectable in tests; production uses the guarded literal require. */\nexport type OptionalRequire = (moduleName: string) => unknown;\n\n/** The pager component `FeatureShowcase` wraps. */\nexport type OnboardingComponent = ComponentType<OnboardingProps>;\n\nconst MODULE_NAME = \"@blazejkustra/react-native-onboarding\";\n\n/**\n * The production resolver. The specifier is a LITERAL so Metro collects it (see the header); the\n * `moduleName` parameter exists only to keep the `OptionalRequire` seam shape, so anything other\n * than the one module this file owns resolves to undefined.\n */\nconst runtimeRequire: OptionalRequire = (moduleName) => {\n if (moduleName !== MODULE_NAME) return undefined;\n if (typeof require !== \"function\") return undefined;\n try {\n return require(\"@blazejkustra/react-native-onboarding\");\n } catch {\n return undefined;\n }\n};\n\n/**\n * TEST-ONLY seam. `FeatureShowcase`'s public props are frozen, so it cannot take a `requireModule`\n * the way `WireIcon` does — this lets a component render exercise the PRESENT path without the peer\n * installed. Production never sets it; `runtimeRequire` is the only resolver.\n */\nlet testRequire: OptionalRequire | undefined;\nexport const __setShowcaseOnboardingRequireForTests = (fn: OptionalRequire | undefined): void => {\n testRequire = fn;\n cached = undefined;\n};\n\n/**\n * Read the component off the module. The package ships it as a DEFAULT export; a CJS build may put\n * the component directly on `module.exports` instead, so both shapes are accepted.\n */\nconst interop = (mod: unknown): unknown => {\n if (typeof mod === \"function\") return mod;\n if (!mod || typeof mod !== \"object\") return undefined;\n const ns = mod as Record<string, unknown>;\n if (ns.default) return ns.default;\n // `module.exports = forwardRef(...)`: the component IS the namespace, and it is an object rather\n // than a function, so it would slip past the check above.\n if (\"$$typeof\" in ns) return ns;\n return undefined;\n};\n\n/**\n * Narrow an unknown export to something mountable: a real component (function or class) or a\n * React.memo / forwardRef wrapper (an object carrying `$$typeof`). Reject anything else rather than\n * handing the reconciler a non-component.\n */\nconst asComponent = (value: unknown): OnboardingComponent | undefined => {\n if (typeof value === \"function\") return value as OnboardingComponent;\n if (value && typeof value === \"object\" && \"$$typeof\" in (value as object)) {\n return value as OnboardingComponent;\n }\n return undefined;\n};\n\n/**\n * Module-level memo. `null` = \"we looked and it is not there\" (distinct from \"not looked yet\"), so\n * an absent peer costs exactly one failed require per process, not one per showcase mount.\n */\nlet cached: OnboardingComponent | null | undefined;\n\n/** Reset the memo. TEST-ONLY seam — production never calls it. */\nexport const resetShowcaseOnboardingCache = (): void => {\n cached = undefined;\n};\n\n/**\n * Resolve the pager component, or undefined when the peer is absent/unresolvable. Never throws: an\n * absent showcase must advance the host's flow, never break it.\n *\n * `requireModule` is injectable so tests can exercise BOTH the found and absent paths without\n * installing the peer (same convention as `resolveBlurView` / `resolveIconFamily`).\n */\nexport const resolveShowcaseOnboarding = (\n requireModule: OptionalRequire = testRequire ?? runtimeRequire,\n): OnboardingComponent | undefined => {\n try {\n if (cached === undefined || requireModule !== runtimeRequire) {\n const component = asComponent(interop(requireModule(MODULE_NAME)));\n // Don't poison the module memo from an injected test require.\n if (requireModule === runtimeRequire) cached = component ?? null;\n return component;\n }\n if (cached === null) return undefined;\n return cached;\n } catch {\n return undefined;\n }\n};\n","import type { OnboardingColors } from \"@blazejkustra/react-native-onboarding\";\n\nimport type { OnboardingTheme } from \"../theme/types\";\n\n/**\n * Map the kit's semantic `OnboardingTheme` onto the color contract of\n * `@blazejkustra/react-native-onboarding` (what `FeatureShowcase` wraps).\n *\n * ⚠️ CRITICAL — that package's color NAMES do NOT line up with the kit's roles.\n * From its source (`utils/theme.ts` + the button/panel components):\n * • `background.primary` → the PRIMARY BUTTON background, the highlighted intro\n * title word (`OnboardingIntroPanel`), and the image\n * hero panel (`OnboardingImageContainer`). It is the\n * package's BRAND / ACTION color — NOT a screen bg.\n * • `background.secondary` → the screen / modal / step-panel background.\n * • `background.label` → the step-label chip background.\n * • `background.accent` → the SECONDARY (outline) button border ONLY.\n * • `text.contrast` → the primary button label (sits on `background.primary`).\n * • `text.primary` → body copy; `text.secondary` → hints/subtitles.\n *\n * The earlier mapping set `background.primary` to the kit's `background`, which\n * painted the primary CTA in the app's SCREEN background color — an invisible /\n * wrong-colored button (white-on-white in light, dark-on-dark in dark mode). The\n * primary button must be the brand `accent`. Keep this in sync with the package's\n * actual usage, not its key names.\n *\n * ⚠️ CONSEQUENCE of the fix above (the 0.3.2 flood): because `background.primary`\n * is ONE key driving THREE surfaces, painting it `accent` also paints the large\n * IMAGE HERO PANEL (`OnboardingImageContainer`'s `colorBg`) in the accent — a\n * full-bleed wash that dominates the first slide and \"hides\" the app's brand.\n * The package offers no per-surface color key to split them, BUT it does expose a\n * `background?: () => ReactNode` render prop that REPLACES that hero panel fill\n * outright (see `showcasePanelBackground` + `FeatureShowcase`). So the button\n * keeps `accent` here and the panel is calmed separately — one accent value, two\n * different surfaces, cleanly split.\n */\nexport const showcaseColorsFromTheme = (\n t: OnboardingTheme,\n accent: string,\n): OnboardingColors => ({\n background: {\n // Brand action color → primary button bg + intro highlight + image hero panel.\n // (The hero panel is overridden to a calm surface via the package's\n // `background` render prop — see showcasePanelBackground — so in practice\n // this only paints the primary button + the intro highlight word.)\n primary: accent,\n // Neutral screen / modal / step-panel background.\n secondary: t.colors.background,\n // Step-label chip background (a soft wash of the brand).\n label: t.colors.primarySoft,\n // Secondary (outline) button border.\n accent,\n },\n text: {\n primary: t.colors.text,\n secondary: t.colors.textMuted,\n // Primary button label — sits on `background.primary` (the accent).\n contrast: t.colors.onPrimary,\n },\n});\n\n/**\n * Opacity of the accent tint layered over the theme surface for the showcase's\n * image hero panel. Kept in a calm 8–12% band so the panel reads as a subtle\n * brand wash — a hint of the accent, never the full-bleed flood that `accent`\n * as a solid fill produced (the 0.3.1 → 0.3.2 bug seen in a host app).\n */\nexport const SHOWCASE_PANEL_TINT_OPACITY = 0.1;\n\n/** The calm hero-panel background: a neutral surface base + a faint accent tint. */\nexport interface ShowcasePanelBackground {\n /** The calm base fill — the theme SURFACE, deliberately NOT the accent. */\n base: string;\n /** A very subtle accent wash layered over the base (8–12% opacity). */\n tint: { color: string; opacity: number };\n}\n\n/**\n * Background for the showcase's image/hero panel, fed to the underlying\n * package's `background` render prop (which REPLACES its `bg.primary`-filled\n * `colorBg`). Returns a neutral surface base with a faint accent tint on top, so\n * the panel is calm and on-brand instead of an accent flood. The primary button\n * and intro highlight keep the full accent (they read `bg.primary` directly).\n */\nexport const showcasePanelBackground = (\n t: OnboardingTheme,\n accent: string,\n): ShowcasePanelBackground => ({\n base: t.colors.surface,\n tint: { color: accent, opacity: SHOWCASE_PANEL_TINT_OPACITY },\n});\n","import type {\n OnboardingColors,\n OnboardingFonts,\n OnboardingProps,\n OnboardingStep,\n} from \"@blazejkustra/react-native-onboarding\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type ImageSourcePropType, StyleSheet, View } from \"react-native\";\n\nimport { GestureHint } from \"../coachmarks/GestureHint\";\nimport { hasSeenGate, markSeenGate, showcaseGateKey } from \"../coachmarks/runtime\";\nimport { useResolvedFeaturesState } from \"../features/WireFeaturesProvider\";\nimport { READ_TIMEOUT_MS } from \"../session/persistedSession\";\nimport { useOnboardingTheme } from \"../theme/ThemeContext\";\nimport type { OnboardingTheme } from \"../theme/types\";\nimport { resolveShowcaseOnboarding } from \"./blazejOnboarding\";\nimport { showcaseColorsFromTheme, showcasePanelBackground } from \"./showcaseColors\";\nimport type { FeatureShowcaseProps } from \"./types\";\n\n/** 1×1 transparent GIF — the fallback for a slide with no image (the underlying\n * package requires an image area per step). */\nconst TRANSPARENT_PX: ImageSourcePropType = {\n uri: \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n};\n\nconst mergeThemeOver = (\n base: OnboardingTheme,\n override?: Partial<OnboardingTheme>,\n): OnboardingTheme => {\n if (!override) return base;\n return {\n colors: { ...base.colors, ...override.colors },\n fonts: { ...base.fonts, ...override.fonts },\n radius: { ...base.radius, ...override.radius },\n spacing: { ...base.spacing, ...override.spacing },\n button: { ...base.button, ...override.button },\n };\n};\n\n/**\n * FeatureShowcase — the pre-onboarding \"app intro\" slides.\n *\n * Wraps `@blazejkustra/react-native-onboarding`: the app supplies a declarative\n * `ShowcaseConfig` (slides + optional intro panel) and the kit maps it to the\n * package's API, bakes in the Wire onboarding theme colors, overlays the\n * perf-tuned GestureHint on any slide that asks for one, and gates the whole\n * thing once through the same sync storage as the coachmark tours\n * (`wire_showcase_<id>_seen`; the global testing flag bypasses it).\n *\n * When the gate says \"seen\", it renders nothing and calls `onDone` from an\n * effect (never during render).\n *\n * When the tenant's feature answer has not landed yet AND the flags could still change the\n * outcome (an unseen gate + a resolvable pager), it renders nothing and calls nothing for up to\n * `READ_TIMEOUT_MS`, then falls through to the optimistic path. That window is bounded, and only\n * ever reached on the launch the showcase would actually play; see the hold note below.\n *\n * The underlying package is an OPTIONAL peer, resolved through the guarded lazy\n * require in `blazejOnboarding.ts` rather than a static import, so the showcase\n * subpath builds on a host that never installed it. Absent, this takes the SAME\n * path as the kill switch — render null, call `onDone`, write no gate — so the\n * host's flow always advances and the showcase still plays once if the peer is\n * added later.\n */\nconst _FeatureShowcase: React.FC<FeatureShowcaseProps> = ({\n config,\n onDone,\n theme: themeOverride,\n accentColor,\n buttonLabel = \"Next\",\n storage,\n isTesting,\n features,\n featuresConfig,\n}) => {\n const active = useOnboardingTheme();\n const t = useMemo(\n () => mergeThemeOver(active, themeOverride),\n [active, themeOverride],\n );\n const accent = accentColor ?? t.colors.primary;\n\n // Feature kill switch: disabled → treat like \"already seen\" (render nothing, call onDone so the\n // host flow continues) but WITHOUT writing the seen gate, so re-enabling replays the showcase.\n // `settled` separates the tenant's ANSWER from the optimistic all-on default; see the hold below.\n const { flags, settled } = useResolvedFeaturesState({\n flags: features,\n config: featuresConfig,\n });\n const disabled = !flags.showcase.enabled;\n\n // The optional pager peer. Resolved once, on first render, instead of at module scope — so\n // merely importing this file (and thus the showcase subpath) never needs it. Absent → treated\n // exactly like the kill switch below: no render, no gate write, `onDone` from the effect.\n const Onboarding = useMemo(() => resolveShowcaseOnboarding(), []);\n\n const gateKey = showcaseGateKey(config.id);\n const seen = useMemo(\n () => hasSeenGate(gateKey, storage, isTesting),\n [gateKey, storage, isTesting],\n );\n // Already-seen, feature-disabled OR the peer missing short-circuits the showcase. Only the seen\n // path is a gate write (in `finish`); the other two never persist, so the showcase replays once\n // the feature is re-enabled or the peer is installed.\n const skip = seen || disabled || !Onboarding;\n\n /**\n * THE FIRST-FRAME HOLD, and why it is scoped this tightly.\n *\n * The flags start all-on and swap when `GET /v1/features` resolves, so on a cold start `disabled`\n * reads false because nobody has asked yet. A tenant who switched the showcase OFF therefore got\n * the whole full-screen intro anyway — and if the user tapped through it inside that window,\n * `finish` wrote the seen gate, so the showcase never replayed even after the tenant re-enabled\n * it. Silent, permanent, once per install.\n *\n * The seam the review + questionnaire gates use — hold the first render outright until the\n * flags settle — does not port unchanged: this component's disabled path calls `onDone`, so a\n * naive hold on `!settled` would leave a blank full screen, and on every launch, including the\n * ones where the flags cannot change the outcome at all.\n * Two things bound it:\n * • `flagsCouldMatter` — an already-seen gate or an absent pager skips whatever the tenant\n * answers, so those launches (which is every launch after the first) never wait at all;\n * • `READ_TIMEOUT_MS` — the repo's one exported read ceiling, reused rather than a third\n * number invented here. The features fetch's own ceiling is 4000ms, which is too long to\n * stare at nothing, so an answer that has not arrived by then falls through to the previous\n * optimistic behaviour. Fail-open in the time dimension: the worst case is what shipped\n * before, reached later.\n */\n const flagsCouldMatter = !seen && !!Onboarding;\n const [holdExpired, setHoldExpired] = useState(false);\n useEffect(() => {\n if (settled || holdExpired || !flagsCouldMatter) return undefined;\n const timer = setTimeout(() => setHoldExpired(true), READ_TIMEOUT_MS);\n return () => clearTimeout(timer);\n }, [settled, holdExpired, flagsCouldMatter]);\n const holding = flagsCouldMatter && !settled && !holdExpired;\n\n const doneRef = useRef(false);\n const finish = useCallback(() => {\n if (doneRef.current) return;\n doneRef.current = true;\n markSeenGate(gateKey, storage, isTesting);\n onDone();\n }, [gateKey, storage, isTesting, onDone]);\n\n // Already seen OR disabled → skip without rendering; call onDone from an effect so the host's\n // navigation continues (never write the gate here — `finish` owns the seen write).\n useEffect(() => {\n // Never advance the host while holding: `onDone` is the host's navigation, and a skip decided\n // on the optimistic default is the same guess the render path refuses below.\n if (holding) return;\n if (skip && !doneRef.current) {\n doneRef.current = true;\n onDone();\n }\n }, [holding, skip, onDone]);\n\n const [activeIndex, setActiveIndex] = useState(0);\n\n const steps: OnboardingStep[] = useMemo(\n () =>\n config.slides.map((slide) => ({\n title: slide.title,\n description: slide.description,\n buttonLabel: slide.buttonLabel ?? buttonLabel,\n image: slide.image ?? TRANSPARENT_PX,\n position: slide.imagePosition ?? \"top\",\n })),\n [config.slides, buttonLabel],\n );\n\n const introPanel: OnboardingProps[\"introPanel\"] = useMemo(\n () =>\n config.introPanel\n ? {\n title: config.introPanel.title,\n subtitle: config.introPanel.subtitle,\n button: config.introPanel.button,\n image: config.introPanel.image,\n }\n : { button: buttonLabel },\n [config.introPanel, buttonLabel],\n );\n\n // The package's color KEYS don't match the kit's role names — most importantly\n // its `background.primary` drives the PRIMARY BUTTON (not the screen bg), so the\n // accent must land there. See showcaseColorsFromTheme for the full contract.\n const colors: OnboardingColors = useMemo(\n () => showcaseColorsFromTheme(t, accent),\n [t, accent],\n );\n\n // Calm the large image/hero panel. The package's `background.primary` is a\n // SINGLE key that fills the primary button, the intro highlight AND this hero\n // panel — painting it `accent` (correct for the button) also flooded the first\n // slide with the app color (0.3.1). The package exposes a\n // `background` render prop that REPLACES that panel fill outright, so we keep\n // the button accent (via `colors`) and paint the panel a calm surface + faint\n // accent tint here. See showcasePanelBackground.\n const panelBg = useMemo(() => showcasePanelBackground(t, accent), [t, accent]);\n const renderPanelBackground = useCallback(\n () => (\n <View\n style={[\n styles.panelBase,\n { backgroundColor: panelBg.base, borderRadius: t.radius.md },\n ]}\n >\n <View\n style={[\n StyleSheet.absoluteFill,\n {\n backgroundColor: panelBg.tint.color,\n opacity: panelBg.tint.opacity,\n },\n ]}\n />\n </View>\n ),\n [panelBg, t.radius.md],\n );\n\n const fonts: OnboardingFonts = useMemo(\n () => ({\n introTitle: t.fonts.bold,\n introSubtitle: t.fonts.regular,\n introButton: t.fonts.bold,\n stepLabel: t.fonts.medium,\n stepTitle: t.fonts.bold,\n stepDescription: t.fonts.regular,\n stepButton: t.fonts.bold,\n primaryButton: t.fonts.bold,\n secondaryButton: t.fonts.medium,\n }),\n [t],\n );\n\n // Holding for the tenant's answer: render nothing AND advance nothing (the effect above is\n // gated too), so a disabled tenant never gets the first frame and never burns the seen gate.\n if (holding) return null;\n // `!Onboarding` is already folded into `skip`; it is repeated here so the narrowing is explicit\n // to the reader and to the compiler at the JSX below.\n if (skip || !Onboarding) return null;\n\n const activeGesture = config.slides[activeIndex]?.gesture;\n // Same rule as the coachmark path: tap / double-tap slides show no glyph.\n const showGesture =\n !!activeGesture &&\n activeGesture !== \"none\" &&\n activeGesture !== \"tap\" &&\n activeGesture !== \"double_tap\";\n\n return (\n <View style={styles.fill}>\n <Onboarding\n introPanel={introPanel}\n steps={steps}\n colors={colors}\n fonts={fonts}\n background={renderPanelBackground}\n onComplete={finish}\n onSkip={finish}\n onStepChange={setActiveIndex}\n />\n\n {/* Perf-tuned gesture glyph overlaid on the active slide, if it asks for\n one (tap / double-tap slides show no glyph — same rule as coachmarks). */}\n {showGesture && (\n <View style={styles.gestureLayer} pointerEvents=\"none\">\n <GestureHint type={activeGesture} color={accent} />\n </View>\n )}\n </View>\n );\n};\n\nexport const FeatureShowcase = React.memo(_FeatureShowcase);\nFeatureShowcase.displayName = \"FeatureShowcase\";\n\nconst styles = StyleSheet.create({\n fill: { flex: 1 },\n // Fills the package's animated background box; clips the accent tint to the\n // rounded corners so the calm panel reads as a card, not a bleed.\n panelBase: { flex: 1, overflow: \"hidden\" },\n gestureLayer: {\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n paddingBottom: 140,\n },\n});\n\nexport default FeatureShowcase;\n","/**\n * selectShowcaseSlides — the value-bridge selection seam for the feature showcase.\n *\n * The recommended shape (v0.2.1+) renders the showcase AS A PERSONALIZED VALUE\n * BRIDGE right AFTER the AI onboarding completes: the user just told you what they\n * want in `result.answers`, so you show only the 2-3 slides that answer it, in the\n * most-relevant-first order — \"you said you want X → here's how the app does X\"\n * (the Duolingo / Headspace terminal-moment pattern). The host declares the full\n * slide catalog once and passes an ordered id list computed from the answers:\n *\n * // Full deck, declared order (pre-onboarding placement, or thin answers):\n * const slides = selectShowcaseSlides(catalog);\n *\n * // Personalized bridge, post-onboarding: subset + order chosen from answers:\n * const slides = selectShowcaseSlides(catalog, idsFromAnswers(result.answers));\n *\n * Contract (identical to `selectTourSteps`):\n * - `selection` absent → returns the catalog unchanged (identity / declared order).\n * - `selection` present → returns only catalog entries whose `id` appears in\n * `selection`, ordered by `selection` (unknown ids are skipped; duplicates in\n * `selection` are ignored after the first match).\n *\n * v2 SERVER SEAM (document-only, not built here): the onboarding server's final\n * turn will later return an ordered `showcase: string[]` slide-key list chosen\n * server-side from the same answers. The host passes it straight in as `selection`\n * — same catalog, same contract, AI is a drop-in. Old kits that don't read the new\n * field simply ignore it, so shipping the extra field is backward-safe.\n */\nexport const selectShowcaseSlides = <T extends { id: string }>(\n catalog: T[],\n selection?: string[],\n): T[] => {\n if (!selection) return catalog;\n\n const byId = new Map(catalog.map((item) => [item.id, item]));\n const seen = new Set<string>();\n const ordered: T[] = [];\n for (const id of selection) {\n if (seen.has(id)) continue;\n seen.add(id);\n const item = byId.get(id);\n if (item) ordered.push(item);\n }\n return ordered;\n};\n"]}
|