@wireai/activation 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/AGENTS.md +82 -40
  2. package/CHANGELOG.md +17 -2
  3. package/INTEGRATION_PROMPT.md +8 -8
  4. package/README.md +38 -38
  5. package/dist/analytics/index.d.mts +92 -0
  6. package/dist/analytics/index.d.ts +92 -0
  7. package/dist/analytics/index.js +439 -0
  8. package/dist/analytics/index.js.map +1 -0
  9. package/dist/analytics/index.mjs +426 -0
  10. package/dist/analytics/index.mjs.map +1 -0
  11. package/dist/coachmarks/index.js.map +1 -1
  12. package/dist/coachmarks/index.mjs.map +1 -1
  13. package/dist/decision-BzbiKwk3.d.mts +79 -0
  14. package/dist/decision-plDEOCkt.d.ts +79 -0
  15. package/dist/eventQueue-CxKi7Qd5.d.mts +546 -0
  16. package/dist/eventQueue-rV1dtJJR.d.ts +546 -0
  17. package/dist/index.d.mts +162 -418
  18. package/dist/index.d.ts +162 -418
  19. package/dist/index.js +407 -4
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +402 -5
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/questionnaire/index.d.mts +2 -1
  24. package/dist/questionnaire/index.d.ts +2 -1
  25. package/dist/questionnaire/index.js.map +1 -1
  26. package/dist/questionnaire/index.mjs.map +1 -1
  27. package/dist/reviews/index.d.mts +5 -40
  28. package/dist/reviews/index.d.ts +5 -40
  29. package/dist/reviews/index.js.map +1 -1
  30. package/dist/reviews/index.mjs.map +1 -1
  31. package/dist/showcase/index.js.map +1 -1
  32. package/dist/showcase/index.mjs.map +1 -1
  33. package/dist/transport-BeO_Brcu.d.mts +40 -0
  34. package/dist/transport-DLpd1v5_.d.ts +40 -0
  35. package/dist/{decision-Cl8OFYzu.d.mts → types-A6pTxIZV.d.mts} +1 -77
  36. package/dist/{decision-CFvGY6nP.d.ts → types-BhpXJGlg.d.ts} +1 -77
  37. package/llms.txt +7 -7
  38. package/metro/index.d.ts +3 -3
  39. package/metro/index.js +3 -3
  40. package/package.json +15 -1
  41. package/src/analytics/contextEnvelope.ts +72 -0
  42. package/src/analytics/eventQueue.ts +331 -0
  43. package/src/analytics/index.ts +47 -0
  44. package/src/analytics/screenTracking.ts +122 -0
  45. package/src/analytics/useScreenTracking.ts +48 -0
  46. package/src/coachmarks/index.ts +2 -2
  47. package/src/features/WireFeaturesProvider.tsx +1 -1
  48. package/src/features/index.ts +2 -2
  49. package/src/index.ts +18 -1
  50. package/src/questionnaire/index.ts +2 -2
  51. package/src/reviews/index.ts +2 -2
  52. package/src/session-analytics/index.ts +20 -0
  53. package/src/session-analytics/lifecycle.ts +236 -0
  54. package/src/session-analytics/reportSessionStart.ts +27 -7
  55. package/src/session-analytics/useLifecycleEvents.ts +184 -0
  56. package/src/showcase/index.ts +2 -2
  57. package/src/types.ts +1 -1
package/AGENTS.md CHANGED
@@ -1,73 +1,115 @@
1
- # AGENTS.md wireai-onboarding (agent integration brief)
1
+ # AGENTS.md: @wireai/activation (agent integration brief)
2
2
 
3
3
  > For an AI agent asked to **install / integrate / consume** this package in a host app.
4
4
  > Everything you need to wire it correctly without reading the source is here.
5
- > (Editing this kit's *own* source instead? Read `CLAUDE.md` different job.)
5
+ > (Editing this kit's *own* source instead? Read `CLAUDE.md`, a different job.)
6
6
  > Full prose + examples: `README.md` → "How to include it in an app (end-to-end)".
7
7
 
8
8
  ## What it is (the goal)
9
9
 
10
- A **drop-in React Native onboarding kit** over the OSS `wireai-rn` SDK. One component,
10
+ A **drop-in mobile-app onboarding kit** over the OSS `wireai-rn` SDK. One component,
11
11
  `<WireOnboarding>`, runs an entire **AI-driven, backend-orchestrated** first-run flow:
12
12
  themed native cards (chosen by an LLM, one per turn over A2A), a progress bar, a mid-flow
13
- value screen, per-step validation, and a completion recap ending with the user's
13
+ value screen, per-step validation, and a completion recap, ending with the user's
14
14
  structured answers for the app to persist. The host supplies a tenant config, a theme,
15
- and brand artwork; the kit owns the flow. **Nearly pure JS no reanimated, no SVG/icon
16
- deps.** Peers: `react`, `react-native`, `wireai-rn`, `zod`, and `react-native-safe-area-context`
17
- (>=4.0.0, for safe-area insets; the host must render a `SafeAreaProvider` ancestor — every
18
- Expo/RN app already ships it).
15
+ and brand artwork; the kit owns the flow. **Nearly pure JS (no reanimated, no SVG/icon
16
+ deps).** Peers: `react`, `react-native`, `wireai-rn`, `zod`, and `react-native-safe-area-context`
17
+ (>=4.0.0, for safe-area insets; the host must render a `SafeAreaProvider` ancestor, which
18
+ every Expo/RN app already ships).
19
19
 
20
- Use it whenever someone wants "AI / dynamic / personalized onboarding" in an RN/Expo app.
20
+ Use it whenever someone wants "AI / dynamic / personalized onboarding" in a React Native / Expo app.
21
21
 
22
- ## Public API (import from `wireai-onboarding`)
22
+ ## Subpath entry points (what you can import)
23
23
 
24
- - `WireOnboarding` the component (props below).
25
- - `DemoOnboarding` dev/QA modal trigger to run the flow on demand (no account, re-runnable; place in a `__DEV__` Settings row). Props: `config` (or `null`), `theme`, `illustrations`, `label?`, `onComplete?`, `renderTrigger?`.
26
- - `wireConfigFromEnv({ appId })` — build `config` from `EXPO_PUBLIC_WIREAI_*` env; returns `null` if keys missing (use as your gate).
27
- - `themeFromBrand({ primary })` derive a full theme from one brand color.
24
+ Everything an integration needs lives on the ROOT import (`@wireai/activation`). The other
25
+ subpaths are optional secondary feature modules; import one only if you use it.
26
+
27
+ - `@wireai/activation` (root): `WireOnboarding`, the helpers/types below, and the app-event/analytics reporters.
28
+ - `@wireai/activation/coachmarks`: in-app coachmark tour (`CoachmarkProvider`, `useCoachmarkTour`).
29
+ - `@wireai/activation/showcase`: post-onboarding feature showcase (`FeatureShowcase`).
30
+ - `@wireai/activation/reviews`: store-review gating (`ReviewGate`, `ReviewModal`).
31
+ - `@wireai/activation/questionnaire`: in-app questionnaire gating (`QuestionnaireGate`).
32
+ - `@wireai/activation/metro`: the `withWireOnboarding` Metro helper (see step 3).
33
+
34
+ There is no `analytics` subpath: the app-event / analytics API is exported from the ROOT
35
+ (see "App events / analytics" below).
36
+
37
+ ## Public API (import from `@wireai/activation`)
38
+
39
+ - `WireOnboarding`: the component (props below).
40
+ - `DemoOnboarding`: dev/QA modal trigger to run the flow on demand (no account, re-runnable; place in a `__DEV__` Settings row). Props: `config` (or `null`), `theme`, `illustrations`, `label?`, `onComplete?`, `renderTrigger?`.
41
+ - `wireConfigFromEnv({ appId })`: build `config` from `EXPO_PUBLIC_WIREAI_*` env; returns `null` if keys missing (use as your gate).
42
+ - `isOnboardingEnabled({ remote? })`: the standard entry gate (transport present: `apiKey` + `serverUrl`, plus an optional host-passed kill switch).
43
+ - `themeFromBrand({ primary })`: derive a full theme from one brand color.
28
44
  - `mergeTheme`, `defaultOnboardingTheme`, `OnboardingThemeProvider`, `useOnboardingTheme`.
29
- - `defaultIllustrations` dependency-free fallback art; spread your own over it.
30
- - Types: `OnboardingTheme`, `OnboardingResult`, `OnboardingEvent`, `WireOnboardingConfig`, `StepValidator`, `OnboardingCopy`, `IllustrationRegistry`.
45
+ - `defaultIllustrations`: dependency-free fallback art; spread your own over it.
46
+ - Types: `OnboardingTheme`, `OnboardingResult`, `OnboardingEvent`, `WireOnboardingConfig`, `WireOnboardingProps`, `StepValidator`, `OnboardingCopy`, `IllustrationRegistry`.
31
47
 
32
48
  ## `<WireOnboarding>` props
33
49
 
34
50
  | Prop | Type | Required | Notes |
35
51
  |---|---|---|---|
36
- | `config` | `{ apiKey, serverUrl, appId, metadata? }` | | A2A transport. `apiKey` (`wai_…`) resolves the tenant server-side; get it from the getwireai console / `register_<app>.py`. |
37
- | `onComplete` | `(result: { answers, raw }) => void` | | Terminal recap CTA tapped. Persist `answers` via your profile-update path, then navigate on. |
38
- | `theme` | `Partial<OnboardingTheme>` | | Colors + font family names + radius/spacing, deep-merged over a neutral default. For dark/light, pass a different theme per app theme-state. |
39
- | `illustrations` | `Record<string, ReactNode>` | | Host artwork for `InterstitialCard`, keyed by name. `{ ...defaultIllustrations, ...myArt }`. |
40
- | `validators` | `Record<string, StepValidator>` | | Per base-question key (e.g. `username`). Blocks advance + inline error. |
41
- | `onSkip` | `() => void` | | User skipped navigate on. |
42
- | `onError` | `(err) => void` | | Backend error/timeout host recovery (e.g. static onboarding). Without it, inline retry. |
43
- | `onEvent` | `(e: OnboardingEvent) => void` | | `started` / `turn` / `error` for analytics (kit owns the loop). |
44
- | `copy` | `Partial<OnboardingCopy>` | | Localize built-in English strings. |
45
- | `approxScreens` | `number` | | Paces the bar; backend `progress.total` wins, so usually unneeded. |
46
- | `components` | `WireAIComponent[]` | | Override registered cards (default `onboardingComponents`). |
47
- | `startMessage` | `string` | | First backend message. Default `"start"`. |
48
- | `startTimeoutMs` | `number` | | First-card watchdog. Default `15000`. |
52
+ | `config` | `WireOnboardingConfig` | yes | A2A transport + tenant. See the `config` fields table below. |
53
+ | `onComplete` | `(result: { answers, raw }) => void` | yes | Terminal recap CTA tapped. Persist `answers` via your profile-update path, then navigate on. |
54
+ | `theme` | `Partial<OnboardingTheme>` | no | Colors + font family names + radius/spacing, deep-merged over a neutral default. For dark/light, pass a different theme per app theme-state. |
55
+ | `components` | `WireAIComponent[]` | no | Override registered cards (default `onboardingComponents`). |
56
+ | `illustrations` | `Record<string, ReactNode>` | no | Host artwork for `InterstitialCard`, keyed by name. `{ ...defaultIllustrations, ...myArt }`. |
57
+ | `validators` | `Record<string, StepValidator>` | no | Per base-question key (e.g. `username`). Blocks advance + inline error. |
58
+ | `onSkip` | `() => void` | no | Retained for back-compat. Per-question Skip is now internal (the kit advances one question on `skippable` screens), so this is no longer wired to that control. |
59
+ | `onError` | `(err) => void` | no | Backend error/timeout after retries. Host recovery (e.g. static onboarding). `fallbackFlow` takes precedence over it. |
60
+ | `onEvent` | `(e: OnboardingEvent) => void` | no | Lifecycle events for analytics (kit owns the loop). Variants: `started`, `resumed`, `turn`, `error`, `retry`, `fallback` (see `OnboardingEvent`). |
61
+ | `copy` | `Partial<OnboardingCopy>` | no | Localize built-in English strings. |
62
+ | `approxScreens` | `number` | no | Paces the bar; backend `progress.total` wins, so usually unneeded. |
63
+ | `startMessage` | `string` | no | First backend message. Default `"start"`. |
64
+ | `startTimeoutMs` | `number` | no | First-card watchdog, ms. Default `15000`. |
65
+ | `fallbackFlow` | `ReactNode` | no | Your existing STATIC onboarding, rendered in place when the AI flow fails and retries are exhausted, so a generation/backend/timeout error degrades instead of breaking the app. Takes precedence over `onError`. |
66
+ | `maxRetries` | `number` | no | Consecutive failures to auto-retry before degrading to `fallbackFlow`/`onError`. Default `1`. `0` degrades on the first failure. |
67
+ | `storage` | `WireOnboardingStorage` | no | Host-injected AsyncStorage-compatible storage. When set, the kit caches its session id so an app kill mid-onboarding resumes the SAME backend session (keeps the `started` count honest). Persists the correlation seed only, never answers. |
68
+ | `sessionTtlMs` | `number` | no | How long a persisted session id stays resumable, ms. Default `3600000` (1h). Only meaningful with `storage`. |
69
+ | `persistKey` | `string` | no | Override the storage key (default `wireai:session:<config.appId>`). Scope it per-user if one device runs onboarding for multiple accounts. Only meaningful with `storage`. |
70
+ | `userContext` | `Record<string, string \| number \| boolean>` | no | Host-injected, non-PII context (signup method, referral, plan tier, a hashed user id). Forwarded to the backend + client events for funnel segmentation. No raw PII. |
71
+ | `userId` | `string` | no | The host's OPAQUE PSEUDONYMOUS user id (not an email/name/phone), so onboarding sessions reconcile to real users. Late binding supported (mount, mid-session, or post-flow via `identifyOnboarding`). Capped at 128 chars. |
72
+
73
+ ### `config` fields (`WireOnboardingConfig`)
74
+
75
+ | Field | Type | Required | Notes |
76
+ |---|---|---|---|
77
+ | `apiKey` | `string` | yes | Tenant key (`wai_…`); resolves the app server-side. Get it from the getwireai console / `register_<app>.py`. |
78
+ | `serverUrl` | `string` | yes | Base server URL; the kit appends `/a2a`. |
79
+ | `appId` | `string` | yes | Passed as the A2A `model` (informational; the key resolves the app). |
80
+ | `metadata` | `Record<string, unknown>` | no | Merged into every A2A request (e.g. install attribution). The kit reserves `sessionId` + `supportedComponents`; do not override them. |
81
+ | `appVersion` | `string` | no | Host app version string (e.g. `"1.4.2"`); forwarded to the backend + client events so analytics can segment the funnel by app version. |
82
+
83
+ ## App events / analytics (root export)
84
+
85
+ The app-event / analytics API is exported from the ROOT (`@wireai/activation`), NOT a subpath.
86
+
87
+ - `WIRE_ONBOARDING_EVENTS` + `toAnalyticsEvent(event)`: canonical `wire_onboarding_*` funnel names; log via the app's own analytics.
88
+ - `reportClientEvent(target, event)` / `reportClientEvents(target, events)`: report device-only funnel events. Contract: `POST {serverUrl}/v1/events`, header `Authorization: Bearer {apiKey}`, body `{ "events": [ ... ] }`. `target = { serverUrl, apiKey }` is derived from `WireOnboardingConfig`. Fire-and-forget: never throws into the UI.
89
+ - `makeSessionId()`: a unique-per-onboarding session id (also seeds the A2A `contextId` so client and server events correlate).
90
+ - `ClientEventType` is `"screen_skipped" | "dropped" | "client_fallback" | "identify"`. `<WireOnboarding>` auto-reports `dropped` (unmount without complete) and `client_fallback` (degrade to static). Hosts must NOT double-report fallback.
49
91
 
50
92
  ## Integration steps (ordered)
51
93
 
52
- 1. **Tenant key** create the app in the getwireai console (or run `register_<app>.py`) → `wai_…` key + server URL. Nothing renders without both.
53
- 2. **Install** `npm install wireai-onboarding wireai-rn` (react + react-native are peers). A tarball or `git+ssh://…` works for pre-publish/pinned builds.
54
- 3. **Metro** `module.exports = withWireOnboarding(getDefaultConfig(__dirname))` (from `wireai-onboarding/metro`); pins one React/RN/wireai-rn/zod copy.
55
- 4. **Config** set `EXPO_PUBLIC_WIREAI_API_KEY` / `_SERVER_URL` / `_APP_ID`; build via `wireConfigFromEnv({ appId })`.
56
- 5. **Fonts** host must load the font families named in `theme.fonts.regular/medium/bold` (e.g. `expo-font`), else text falls back to system font.
57
- 6. **Theme** `themeFromBrand({ primary })` or a full `Partial<OnboardingTheme>`; for dark/light, pick the theme by the app's theme state.
58
- 7. **Render + continuation** drop `<WireOnboarding>` into the signup flow; `onComplete` → persist + navigate, `onSkip` → navigate.
59
- 8. **Gate** wrap behind a flag (env for dev, remote config for prod) **AND** `config != null`; fall through to existing onboarding when off/unconfigured. Decide who sees it (e.g. new signups only) in host nav logic.
94
+ 1. **Tenant key**: create the app in the getwireai console (or run `register_<app>.py`) → `wai_…` key + server URL. Nothing renders without both.
95
+ 2. **Install**: `npm install @wireai/activation wireai-rn` (react + react-native are peers). A tarball or `git+ssh://…` works for pre-publish/pinned builds.
96
+ 3. **Metro**: `module.exports = withWireOnboarding(getDefaultConfig(__dirname))` (from `@wireai/activation/metro`); pins one React/RN/wireai-rn/zod copy.
97
+ 4. **Config**: set `EXPO_PUBLIC_WIREAI_API_KEY` / `_SERVER_URL` / `_APP_ID`; build via `wireConfigFromEnv({ appId })`.
98
+ 5. **Fonts**: host must load the font families named in `theme.fonts.regular/medium/bold` (e.g. `expo-font`), else text falls back to system font.
99
+ 6. **Theme**: `themeFromBrand({ primary })` or a full `Partial<OnboardingTheme>`; for dark/light, pick the theme by the app's theme state.
100
+ 7. **Render + continuation**: drop `<WireOnboarding>` into the signup flow; `onComplete` → persist + navigate, `onSkip` → navigate.
101
+ 8. **Gate**: wrap behind a flag (env for dev, remote config for prod) **AND** `config != null`; fall through to existing onboarding when off/unconfigured. Decide who sees it (e.g. new signups only) in host nav logic.
60
102
 
61
103
  ## Gotchas (do not miss)
62
104
 
63
- - **EAS / cloud builds:** install via **git URL or registry**, never a local `file:` path *outside the app repo* EAS won't resolve it.
105
+ - **EAS / cloud builds:** install via **git URL or registry**, never a local `file:` path *outside the app repo* (EAS won't resolve it).
64
106
  - **Single React copy:** always use the `withWireOnboarding` Metro helper (a 2nd React instance crashes RN).
65
107
  - **No native rebuild for the kit's own code** (JS + one prebuilt native peer, `react-native-safe-area-context`, that every RN/Expo app already ships). A rebuild is only needed if *your* gating mechanism is a native module (e.g. Firebase Remote Config), or if the app didn't already have safe-area-context installed.
66
- - **New cards:** registering a card in the kit is not enough the backend validates emissions; add it to the server `KNOWN_COMPONENTS` + the tenant `allowed_components` (see README → "Backend coupling").
108
+ - **New cards:** registering a card in the kit is not enough (the backend validates emissions); add it to the server `KNOWN_COMPONENTS` + the tenant `allowed_components` (see README → "Backend coupling").
67
109
  - **Secrets:** the `apiKey` is a tenant key (safe in the bundle); never log host secrets in `onEvent`.
68
110
 
69
111
  ## Fastest path
70
112
 
71
- Run the **`wire-rn-integration`** Claude skill it performs all the steps above
113
+ Run the **`wire-rn-integration`** Claude skill. It performs all the steps above
72
114
  automatically (detect conventions → register tenant → install → Metro → theme →
73
115
  scaffold screen → wire navigation + fallback → typecheck).
package/CHANGELOG.md CHANGED
@@ -1,7 +1,22 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to `wireai-onboarding`. Consumed from source (unpublished),
4
- so versions are informational.
3
+ All notable changes to `@wireai/activation` (formerly `wireai-onboarding`).
4
+ Historical entries below the rename keep the old package name on purpose.
5
+
6
+ ## [0.1.0] — 2026-07-12
7
+
8
+ ### Renamed: `wireai-onboarding` is now `@wireai/activation`
9
+
10
+ - The package name changed to the scoped `@wireai/activation`. Imports change from
11
+ `wireai-onboarding` to `@wireai/activation`, and every subpath moves with it
12
+ (`wireai-onboarding/reviews` becomes `@wireai/activation/reviews`, and the same for
13
+ `coachmarks`, `showcase`, `questionnaire`, `analytics`, `metro`). The `exports` keys are
14
+ unchanged, so the subpaths themselves are identical.
15
+ - No API change. Same components, hooks, types, and runtime behavior. The Metro helper's
16
+ internal source alias now maps the `@wireai/activation` specifier; consumers that call
17
+ `withWireOnboarding({ source })` need no code change beyond the import string.
18
+ - Version reset to `0.1.0` to mark the start of the new package line. The GitHub repository
19
+ stays `chohra-med/wireai-onboarding`.
5
20
 
6
21
  ## [0.7.0] — Unreleased
7
22
 
@@ -1,17 +1,17 @@
1
- # Claude integration prompt wireai-onboarding
1
+ # Claude integration prompt: @wireai/activation
2
2
 
3
3
  Copy everything in the block below and paste it into Claude Code (or any coding agent) **from the
4
4
  root of your React Native / Expo app**. Fill in the two values at the top first.
5
5
 
6
- > Fastest path instead of this prompt: run the **`wire-rn-integration`** Claude skill same job,
6
+ > Fastest path instead of this prompt: run the **`wire-rn-integration`** Claude skill, the same job
7
7
  > fully automated. Use this prompt when you don't have that skill installed.
8
8
 
9
9
  ---
10
10
 
11
11
  ```
12
- You are integrating the `wireai-onboarding` package into THIS React Native / Expo app a drop-in
12
+ You are integrating the `@wireai/activation` package into THIS React Native / Expo app, a drop-in
13
13
  AI onboarding flow. Do it end to end, match my app's existing conventions, and leave it
14
- type-checking green. Read the package's README.md, llms.txt, and AGENTS.md (in node_modules/wireai-onboarding
14
+ type-checking green. Read the package's README.md, llms.txt, and AGENTS.md (in node_modules/@wireai/activation
15
15
  after install) before writing code.
16
16
 
17
17
  MY VALUES:
@@ -22,11 +22,11 @@ MY VALUES:
22
22
  STEPS (do them in order, stop and ask if a convention is ambiguous):
23
23
  1. Detect my conventions: navigation lib + where the signup/first-run flow lives, my env-var
24
24
  typing, my profile-update / persistence path, my theme tokens (colors/fonts), my path aliases.
25
- 2. Install: `wireai-onboarding` and `wireai-rn` (react + react-native are already peers). Use my
26
- package manager (yarn/npm/pnpm detect it).
25
+ 2. Install: `@wireai/activation` and `wireai-rn` (react + react-native are already peers). Use my
26
+ package manager (yarn/npm/pnpm, detect it).
27
27
  3. Metro: set `module.exports = withWireOnboarding(getDefaultConfig(__dirname))` from
28
- `wireai-onboarding/metro` in metro.config.js (preserve my existing config). This pins one copy
29
- of react/react-native/wireai-rn/zod do NOT skip it.
28
+ `@wireai/activation/metro` in metro.config.js (preserve my existing config). This pins one copy
29
+ of react/react-native/wireai-rn/zod; do NOT skip it.
30
30
  4. Env: add EXPO_PUBLIC_WIREAI_API_KEY, EXPO_PUBLIC_WIREAI_SERVER_URL, EXPO_PUBLIC_WIREAI_APP_ID
31
31
  to my env files and my env typing.
32
32
  5. Theme: build a theme from my brand with `themeFromBrand({ primary: "<my brand color>" })` or a
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # wireai-onboarding
1
+ # @wireai/activation
2
2
 
3
3
  A premium, fully-themable **drop-in onboarding kit** on top of the open-source
4
4
  [`wireai-rn`](https://github.com/chohra-med/wireai-rn) SDK. You give it a tenant
@@ -6,12 +6,12 @@ config; it runs an entire AI-driven, backend-orchestrated onboarding — themed
6
6
  cards, a progress bar, a mid-flow value screen, per-step validation, and a
7
7
  completion recap — behind one component.
8
8
 
9
- > MIT-licensed. Install from npm as [`wireai-onboarding`](https://www.npmjs.com/package/wireai-onboarding), or consume **from source** for live kit-edit (as the apps in this repo do).
9
+ > MIT-licensed. Install from npm as [`@wireai/activation`](https://www.npmjs.com/package/@wireai/activation), or consume **from source** for live kit-edit (as the apps in this repo do).
10
10
 
11
11
  <div align="center">
12
12
 
13
- [![npm](https://img.shields.io/npm/v/wireai-onboarding.svg)](https://www.npmjs.com/package/wireai-onboarding)
14
- [![license](https://img.shields.io/npm/l/wireai-onboarding.svg)](LICENSE)
13
+ [![npm](https://img.shields.io/npm/v/@wireai/activation.svg)](https://www.npmjs.com/package/@wireai/activation)
14
+ [![license](https://img.shields.io/npm/l/@wireai/activation.svg)](LICENSE)
15
15
 
16
16
  Created by [**Malik Chohra**](https://getwireai.com?utm_source=github&utm_medium=readme&utm_campaign=creator) · [Code Meet AI newsletter](https://codemeetai.substack.com?utm_source=github&utm_medium=readme&utm_campaign=newsletter)
17
17
 
@@ -24,7 +24,7 @@ Sponsored by [AI Mobile Launcher](https://aimobilelauncher.com?utm_source=github
24
24
  | Layer | Repo / path | Role |
25
25
  |---|---|---|
26
26
  | **SDK (OSS)** | `wireai-rn` | `WireAIProvider` + `ComponentRenderer` + `useWireAIThread`; renders whatever components the host registers; A2A transport. |
27
- | **This kit** | `getwire_ai/wireai-onboarding` | `<WireOnboarding>` — themed cards, sparkle loader, countless stepper, `InterstitialCard` value screen, animated-checkmark completion, validators. **The single onboarding UI engine.** |
27
+ | **This kit** | `getwire_ai/@wireai/activation` | `<WireOnboarding>` — themed cards, sparkle loader, countless stepper, `InterstitialCard` value screen, animated-checkmark completion, validators. **The single onboarding UI engine.** |
28
28
  | **Backend** | `wire-rn/examples/dynamic-onboarding/server` | Multi-tenant LangGraph engine. Per-app `product_context` + `allowed_components`; validates every emission against `KNOWN_COMPONENTS`. Live on fly dev. |
29
29
  | **Consumers** | Production B2C mobile apps | Each hosts `<WireOnboarding>` with its own theme + illustration registry. |
30
30
 
@@ -48,7 +48,7 @@ dev/prod URL). Nothing renders without these two.
48
48
  **1. Install the package** (plus its peers):
49
49
 
50
50
  ```bash
51
- npm install wireai-onboarding wireai-rn
51
+ npm install @wireai/activation wireai-rn
52
52
  # react + react-native are peers (already in any RN/Expo app)
53
53
  ```
54
54
 
@@ -62,7 +62,7 @@ instance crashes RN):
62
62
 
63
63
  ```js
64
64
  const { getDefaultConfig } = require("expo/metro-config");
65
- const { withWireOnboarding } = require("wireai-onboarding/metro");
65
+ const { withWireOnboarding } = require("@wireai/activation/metro");
66
66
  module.exports = withWireOnboarding(getDefaultConfig(__dirname));
67
67
  ```
68
68
 
@@ -132,24 +132,24 @@ Install the package and wire Metro with the one-call helper:
132
132
 
133
133
  ```bash
134
134
  # from npm (public)
135
- npm install wireai-onboarding
135
+ npm install @wireai/activation
136
136
  # …or from a tarball (see Distribution below)
137
- npm install ./wireai-onboarding-0.1.3.tgz
137
+ npm install ./@wireai/activation-0.1.3.tgz
138
138
  # …or over SSH
139
- npm install git+ssh://git@github.com/<org>/wireai-onboarding.git
139
+ npm install git+ssh://git@github.com/<org>/@wireai/activation.git
140
140
  ```
141
141
 
142
142
  ```js
143
143
  // metro.config.js — replaces the hand-written ~25-line block
144
144
  const { getDefaultConfig } = require("expo/metro-config");
145
- const { withWireOnboarding } = require("wireai-onboarding/metro");
145
+ const { withWireOnboarding } = require("@wireai/activation/metro");
146
146
 
147
147
  module.exports = withWireOnboarding(getDefaultConfig(__dirname));
148
148
  ```
149
149
 
150
150
  ```tsx
151
151
  // 3-line minimal usage — themed from a brand color, config from env, default art
152
- import { WireOnboarding, themeFromBrand, wireConfigFromEnv, defaultIllustrations } from "wireai-onboarding";
152
+ import { WireOnboarding, themeFromBrand, wireConfigFromEnv, defaultIllustrations } from "@wireai/activation";
153
153
 
154
154
  export function Onboarding() {
155
155
  const config = wireConfigFromEnv({ appId: "my-app" }); // null if env keys missing
@@ -174,15 +174,15 @@ name: `illustrations={{ ...defaultIllustrations, ...myIllustrations }}`.
174
174
  ### 2. Source consumers (your monorepo apps)
175
175
 
176
176
  Same helper, with `source` pointed at the kit's `src/` (adds it to `watchFolders`
177
- and maps the `wireai-onboarding` specifier to source). Keep the tsconfig path alias.
177
+ and maps the `@wireai/activation` specifier to source). Keep the tsconfig path alias.
178
178
 
179
179
  ```js
180
180
  const path = require("path");
181
181
  const { getDefaultConfig } = require("expo/metro-config");
182
- const { withWireOnboarding } = require("wireai-onboarding/metro");
182
+ const { withWireOnboarding } = require("@wireai/activation/metro");
183
183
 
184
184
  module.exports = withWireOnboarding(getDefaultConfig(__dirname), {
185
- source: path.join(__dirname, "../../getwire_ai/wireai-onboarding/src"),
185
+ source: path.join(__dirname, "../../getwire_ai/@wireai/activation/src"),
186
186
  });
187
187
  ```
188
188
 
@@ -191,22 +191,22 @@ module.exports = withWireOnboarding(getDefaultConfig(__dirname), {
191
191
  crashes RN), merges with any `extraNodeModules` / `watchFolders` you already set, and
192
192
  returns the same config. `options.appRoot` defaults to `process.cwd()`.
193
193
 
194
- > The `"react-native"` export condition resolves `wireai-onboarding` to `src/index.ts`
194
+ > The `"react-native"` export condition resolves `@wireai/activation` to `src/index.ts`
195
195
  > for Metro (it transforms the kit's source), while `import`/`require` resolve to the
196
196
  > built `dist`. So both npm consumers and source consumers work; the dist build is additive.
197
197
 
198
198
  ## Distribution
199
199
 
200
200
  `npm run pack:tarball` runs the build (via `prepack`) and produces
201
- `wireai-onboarding-x.y.z.tgz` containing `dist` + `src` + `metro` + README +
202
- CHANGELOG. The primary channel is **npm** (`npm install wireai-onboarding`); a
203
- tarball (`npm install ./wireai-onboarding-x.y.z.tgz`) or a `git+ssh://…` install
201
+ `@wireai/activation-x.y.z.tgz` containing `dist` + `src` + `metro` + README +
202
+ CHANGELOG. The primary channel is **npm** (`npm install @wireai/activation`); a
203
+ tarball (`npm install ./@wireai/activation-x.y.z.tgz`) or a `git+ssh://…` install
204
204
  work too for pre-publish or pinned builds.
205
205
 
206
206
  ## Quick start
207
207
 
208
208
  ```tsx
209
- import { WireOnboarding } from "wireai-onboarding";
209
+ import { WireOnboarding } from "@wireai/activation";
210
210
 
211
211
  <WireOnboarding
212
212
  config={{ apiKey, serverUrl, appId: "my-app" }}
@@ -315,7 +315,7 @@ setUserId(newUser.id); // the kit fires `identify` and binds the running session
315
315
  **3. The user registers after the flow.** Capture the `contextId` from the `started` (or `resumed`) `onEvent` while onboarding runs, then call `identifyOnboarding(...)` once you have the id. Completion clears the persisted session, so the captured `contextId` is the reliable handle.
316
316
 
317
317
  ```tsx
318
- import { identifyOnboarding } from "wireai-onboarding";
318
+ import { identifyOnboarding } from "@wireai/activation";
319
319
 
320
320
  const contextIdRef = useRef<string>();
321
321
 
@@ -384,7 +384,7 @@ If your app already keeps a session counter (Myelino and Morrow do), call the pl
384
384
  from your own "app opened" path and pass the counter value:
385
385
 
386
386
  ```tsx
387
- import { reportSessionStart } from "wireai-onboarding";
387
+ import { reportSessionStart } from "@wireai/activation";
388
388
 
389
389
  // In your app-open effect (or wherever you bump your session counter):
390
390
  reportSessionStart({
@@ -401,7 +401,7 @@ to the foreground after at least 30 minutes in the background (a real new open,
401
401
  app-switch):
402
402
 
403
403
  ```tsx
404
- import { useSessionStart } from "wireai-onboarding";
404
+ import { useSessionStart } from "@wireai/activation";
405
405
 
406
406
  useSessionStart(
407
407
  { serverUrl: config.serverUrl, apiKey: config.apiKey, appVersion },
@@ -430,7 +430,7 @@ flow in a modal, runs it once, and closes (no loop, no account, no navigation si
430
430
  effects). Put it behind `__DEV__` anywhere — a Settings row is typical:
431
431
 
432
432
  ```tsx
433
- import { DemoOnboarding, wireConfigFromEnv } from "wireai-onboarding";
433
+ import { DemoOnboarding, wireConfigFromEnv } from "@wireai/activation";
434
434
 
435
435
  {__DEV__ && (
436
436
  <DemoOnboarding
@@ -488,10 +488,10 @@ server validates every emission and replaces unknown components with a safe
488
488
 
489
489
  The monorepo apps resolve the kit from source. In each app:
490
490
 
491
- - **`tsconfig.json`** → `"paths": { "wireai-onboarding": ["<rel>/wireai-onboarding/src/index.ts"], "wireai-onboarding/*": ["<rel>/wireai-onboarding/src/*"] }`
491
+ - **`tsconfig.json`** → `"paths": { "@wireai/activation": ["<rel>/@wireai/activation/src/index.ts"], "@wireai/activation/*": ["<rel>/@wireai/activation/src/*"] }`
492
492
  - **`metro.config.js`** → use the `withWireOnboarding` helper with `source` (see
493
493
  [Installation → source consumers](#2-source-consumers-your-monorepo-apps)). It
494
- watches the kit `src`, maps the `wireai-onboarding` specifier to it, and pins
494
+ watches the kit `src`, maps the `@wireai/activation` specifier to it, and pins
495
495
  `react` / `react-native` / `wireai-rn` / `zod` to the app's own `node_modules`
496
496
  (a second React instance crashes RN) — the same wiring the apps spell out by hand.
497
497
 
@@ -510,10 +510,10 @@ consuming app, since the kit has no local TS install).
510
510
  ## Coachmarks & guided tours
511
511
 
512
512
  The kit ships a performance-first guided-tour engine on a **subpath** so the main
513
- barrel stays dependency-free — import it from `wireai-onboarding/coachmarks`. It
513
+ barrel stays dependency-free — import it from `@wireai/activation/coachmarks`. It
514
514
  pulls in two **optional** peers only when you use it: `react-native-reanimated`
515
515
  (UI-thread gesture + ring animation) and `expo-blur` (the frosted spotlight).
516
- Source consumers get it through the existing `wireai-onboarding/*` tsconfig path
516
+ Source consumers get it through the existing `@wireai/activation/*` tsconfig path
517
517
  mapping; installed apps resolve the subpath export.
518
518
 
519
519
  The split: **the kit owns the animation/blur/ring/measure/queue**, the **app
@@ -528,7 +528,7 @@ storage adapter — gate reads must not be async or a ring flashes before the
528
528
  "already seen" check resolves. An MMKV wrapper is three lines:
529
529
 
530
530
  ```tsx
531
- import { CoachmarkProvider } from "wireai-onboarding/coachmarks";
531
+ import { CoachmarkProvider } from "@wireai/activation/coachmarks";
532
532
  import { storage } from "./mmkv"; // your MMKV instance
533
533
 
534
534
  const coachmarkStorage = {
@@ -551,7 +551,7 @@ survives measurement). Pass `null` to register nothing (e.g. only the first row
551
551
  of a list):
552
552
 
553
553
  ```tsx
554
- import { useCoachmarkAnchor } from "wireai-onboarding/coachmarks";
554
+ import { useCoachmarkAnchor } from "@wireai/activation/coachmarks";
555
555
 
556
556
  const groupTab = useCoachmarkAnchor("group_tab");
557
557
  <View ref={groupTab} collapsable={false}>{tabButton}</View>;
@@ -563,7 +563,7 @@ storage, so the app keeps only its own domain gates. Steps must be a memoized
563
563
  array; step callbacks are held in a ref (parent re-renders never re-fire a step):
564
564
 
565
565
  ```tsx
566
- import { useCoachmarkTour } from "wireai-onboarding/coachmarks";
566
+ import { useCoachmarkTour } from "@wireai/activation/coachmarks";
567
567
 
568
568
  const steps = useMemo(
569
569
  () => [
@@ -606,7 +606,7 @@ captured intent; you pass it straight to `selectTourSteps(catalog, selection)` a
606
606
  nothing else changes — same contract, AI is a drop-in:
607
607
 
608
608
  ```ts
609
- import { selectTourSteps } from "wireai-onboarding/coachmarks";
609
+ import { selectTourSteps } from "@wireai/activation/coachmarks";
610
610
 
611
611
  // catalog = your feature map; each entry has a stable `id`
612
612
  const catalog = [
@@ -625,7 +625,7 @@ duplicates ignored).
625
625
 
626
626
  ## Feature showcase (the personalized value bridge)
627
627
 
628
- `wireai-onboarding/showcase` wraps [`@blazejkustra/react-native-onboarding`](https://github.com/software-mansion-labs/react-native-onboarding)
628
+ `@wireai/activation/showcase` wraps [`@blazejkustra/react-native-onboarding`](https://github.com/software-mansion-labs/react-native-onboarding)
629
629
  (the **optional** peer) as a small deck of declarative slides. You supply a
630
630
  `ShowcaseConfig`; the kit maps it to the package's API, bakes in the onboarding
631
631
  theme colors, and gates once through the same storage as the tours
@@ -640,7 +640,7 @@ Duolingo / Headspace pattern). Select them from the answers with
640
640
  `selectShowcaseSlides`:
641
641
 
642
642
  ```tsx
643
- import { FeatureShowcase, selectShowcaseSlides } from "wireai-onboarding/showcase";
643
+ import { FeatureShowcase, selectShowcaseSlides } from "@wireai/activation/showcase";
644
644
 
645
645
  // The app declares the full slide catalog once (stable ids):
646
646
  const catalog = [
@@ -694,7 +694,7 @@ don't read it simply ignore it (backward-safe).
694
694
 
695
695
  ## In-app reviews (sentiment gate)
696
696
 
697
- `wireai-onboarding/reviews` is the drop-in in-app review flow. It asks one neutral
697
+ `@wireai/activation/reviews` is the drop-in in-app review flow. It asks one neutral
698
698
  question, then splits honestly on the rating:
699
699
 
700
700
  - **5 stars** route to the native store review. It calls the **optional** peer
@@ -718,7 +718,7 @@ own analytics; the four moments are `review_prompt_shown`, `review_rating_select
718
718
  Feedback text goes only in the POST body.
719
719
 
720
720
  ```tsx
721
- import { ReviewGate, useReviewGate } from "wireai-onboarding/reviews";
721
+ import { ReviewGate, useReviewGate } from "@wireai/activation/reviews";
722
722
 
723
723
  // The gate owns WHEN to show. v1 uses the local rules below; pass a server `decision`
724
724
  // object and it overrides them (the AI seam, see below).
@@ -806,7 +806,7 @@ Mount `WireFeaturesProvider` once near your root and every gated surface below i
806
806
  resolved flags from context (one fetch serves all modules):
807
807
 
808
808
  ```tsx
809
- import { WireFeaturesProvider } from "wireai-onboarding";
809
+ import { WireFeaturesProvider } from "@wireai/activation";
810
810
 
811
811
  <WireFeaturesProvider config={{ serverUrl, apiKey, appId, storage }}>
812
812
  <App />
@@ -878,7 +878,7 @@ Then add it to your agent client's MCP config:
878
878
  "mcpServers": {
879
879
  "wireai": {
880
880
  "command": "node",
881
- "args": ["<abs-path>/wireai-onboarding/mcp/dist/index.js"],
881
+ "args": ["<abs-path>/@wireai/activation/mcp/dist/index.js"],
882
882
  "env": {
883
883
  "WIREAI_SERVER_URL": "https://<your-backend>.fly.dev",
884
884
  "WIREAI_API_KEY": "wai_<tenant-key>",
@@ -0,0 +1,92 @@
1
+ export { R as ReportAppEventOptions, r as reportAppEvent } from '../transport-BeO_Brcu.mjs';
2
+ export { A as AnalyticsEvent, C as ClientEvent, a as ClientEventTarget, b as ClientEventType, c as ContextEnvelope, d as ContextEnvelopeInput, E as EnvelopeSource, e as EventQueue, f as EventQueueOptions, W as WIRE_ONBOARDING_EVENTS, g as WireOnboardingEventName, h as buildContextEnvelope, i as createEventQueue, m as makeSessionId, r as reportClientEvent, j as reportClientEvents, t as toAnalyticsEvent } from '../eventQueue-CxKi7Qd5.mjs';
3
+ import '../types-A6pTxIZV.mjs';
4
+ import '../types-BKfpdZzX.mjs';
5
+ import '../types-GL_hQ0TN.mjs';
6
+ import '../types-CMuOexw0.mjs';
7
+ import 'react';
8
+ import 'wireai-rn';
9
+ import 'react-native';
10
+
11
+ /** A single route inside a React-Navigation-shaped state (structural — no `@react-navigation`). */
12
+ interface NavigationRouteLike {
13
+ name: string;
14
+ /** A nested navigator's own state, when this route hosts one. */
15
+ state?: NavigationStateLike;
16
+ /** Route params are intentionally left `unknown` — this helper never reads them. */
17
+ params?: unknown;
18
+ }
19
+ /** A React-Navigation-shaped navigator state (structural type; no library import). */
20
+ interface NavigationStateLike {
21
+ /** Index of the active route within `routes`. */
22
+ index?: number;
23
+ routes?: NavigationRouteLike[];
24
+ }
25
+ /** Options for {@link createScreenTracker}. */
26
+ interface ScreenTrackerOptions {
27
+ /**
28
+ * Where to POST. `{ serverUrl, apiKey }` — same shape the kit's review/analytics config
29
+ * exposes. When omitted, the tracker still de-dups and fires `onScreen`, but sends nothing.
30
+ */
31
+ target?: {
32
+ serverUrl: string;
33
+ apiKey: string;
34
+ };
35
+ /** The onboarding/session id to correlate screen views with, when known. */
36
+ sessionId?: string;
37
+ /** A stable, non-PII device id — groups a device's sessions server-side. */
38
+ deviceKey?: string;
39
+ /** Called on every REAL screen change (after de-dup), before the network emit. */
40
+ onScreen?: (screen: string) => void;
41
+ /**
42
+ * Per-screen filter. Return `false` to skip the NETWORK emit for a screen (last-screen memory
43
+ * is still advanced + `onScreen` still fires) — e.g. to keep a sensitive route out of analytics.
44
+ */
45
+ shouldTrack?: (screen: string) => boolean;
46
+ }
47
+ /** The screen tracker returned by {@link createScreenTracker}. */
48
+ interface ScreenTracker {
49
+ /** Report the active screen. Ignores `undefined`/empty and de-dups repeats of the last screen. */
50
+ track: (screen: string | undefined) => void;
51
+ /** Clear the last-screen memory (e.g. on logout) so the next `track` always emits. */
52
+ reset: () => void;
53
+ }
54
+ /**
55
+ * Walk a React-Navigation-shaped state to the DEEPEST active route and return its NAME (never
56
+ * its params). Recurses `routes[index]` while a nested `.state` exists. Returns `undefined` for
57
+ * a missing/empty/malformed state — the caller treats that as "nothing to report".
58
+ */
59
+ declare const getActiveRouteName: (state: NavigationStateLike | undefined) => string | undefined;
60
+ /**
61
+ * Build a stateful screen tracker. `track` de-dups against the last reported screen so only a
62
+ * REAL change emits; `reset` clears that memory. Fire-and-forget throughout — a missing `target`
63
+ * skips the network but keeps the de-dup + `onScreen` behaviour intact.
64
+ */
65
+ declare const createScreenTracker: (options?: ScreenTrackerOptions) => ScreenTracker;
66
+ /**
67
+ * Adapt a tracker into a React-Navigation `onStateChange` handler — the one-place wiring:
68
+ *
69
+ * <NavigationContainer onStateChange={screenTrackingHandler(tracker)}>
70
+ *
71
+ * It resolves the deepest active route name and hands it to `tracker.track` (which de-dups).
72
+ */
73
+ declare const screenTrackingHandler: (tracker: ScreenTracker) => (state: NavigationStateLike | undefined) => void;
74
+
75
+ /**
76
+ * The structural slice of a React-Navigation container ref this hook needs — no
77
+ * `@react-navigation` import. `getCurrentRoute` yields the active route; `addListener("state", …)`
78
+ * fires on every navigation state change and returns its own unsubscribe.
79
+ */
80
+ interface NavigationRefLike {
81
+ getCurrentRoute?: () => {
82
+ name?: string;
83
+ } | undefined;
84
+ addListener?: (type: "state", callback: () => void) => () => void;
85
+ }
86
+ /**
87
+ * Subscribe screen tracking to a host navigation ref. Safe to call with a not-yet-ready ref
88
+ * (the effect no-ops until `addListener` exists). Returns nothing — it wires side effects only.
89
+ */
90
+ declare const useScreenTracking: (navigationRef: NavigationRefLike | undefined, options?: ScreenTrackerOptions) => void;
91
+
92
+ export { type NavigationRefLike, type NavigationRouteLike, type NavigationStateLike, type ScreenTracker, type ScreenTrackerOptions, createScreenTracker, getActiveRouteName, screenTrackingHandler, useScreenTracking };