@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.
- package/AGENTS.md +82 -40
- package/CHANGELOG.md +17 -2
- package/INTEGRATION_PROMPT.md +8 -8
- package/README.md +38 -38
- package/dist/analytics/index.d.mts +92 -0
- package/dist/analytics/index.d.ts +92 -0
- package/dist/analytics/index.js +439 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/index.mjs +426 -0
- package/dist/analytics/index.mjs.map +1 -0
- package/dist/coachmarks/index.js.map +1 -1
- package/dist/coachmarks/index.mjs.map +1 -1
- package/dist/decision-BzbiKwk3.d.mts +79 -0
- package/dist/decision-plDEOCkt.d.ts +79 -0
- package/dist/eventQueue-CxKi7Qd5.d.mts +546 -0
- package/dist/eventQueue-rV1dtJJR.d.ts +546 -0
- package/dist/index.d.mts +162 -418
- package/dist/index.d.ts +162 -418
- package/dist/index.js +407 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +402 -5
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +2 -1
- package/dist/questionnaire/index.d.ts +2 -1
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.d.mts +5 -40
- package/dist/reviews/index.d.ts +5 -40
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/showcase/index.js.map +1 -1
- package/dist/showcase/index.mjs.map +1 -1
- package/dist/transport-BeO_Brcu.d.mts +40 -0
- package/dist/transport-DLpd1v5_.d.ts +40 -0
- package/dist/{decision-Cl8OFYzu.d.mts → types-A6pTxIZV.d.mts} +1 -77
- package/dist/{decision-CFvGY6nP.d.ts → types-BhpXJGlg.d.ts} +1 -77
- package/llms.txt +7 -7
- package/metro/index.d.ts +3 -3
- package/metro/index.js +3 -3
- package/package.json +15 -1
- package/src/analytics/contextEnvelope.ts +72 -0
- package/src/analytics/eventQueue.ts +331 -0
- package/src/analytics/index.ts +47 -0
- package/src/analytics/screenTracking.ts +122 -0
- package/src/analytics/useScreenTracking.ts +48 -0
- package/src/coachmarks/index.ts +2 -2
- package/src/features/WireFeaturesProvider.tsx +1 -1
- package/src/features/index.ts +2 -2
- package/src/index.ts +18 -1
- package/src/questionnaire/index.ts +2 -2
- package/src/reviews/index.ts +2 -2
- package/src/session-analytics/index.ts +20 -0
- package/src/session-analytics/lifecycle.ts +236 -0
- package/src/session-analytics/reportSessionStart.ts +27 -7
- package/src/session-analytics/useLifecycleEvents.ts +184 -0
- package/src/showcase/index.ts +2 -2
- package/src/types.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,73 +1,115 @@
|
|
|
1
|
-
# AGENTS.md
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
18
|
-
Expo/RN app already ships
|
|
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
|
|
20
|
+
Use it whenever someone wants "AI / dynamic / personalized onboarding" in a React Native / Expo app.
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Subpath entry points (what you can import)
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- `
|
|
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
|
|
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` | `
|
|
37
|
-
| `onComplete` | `(result: { answers, raw }) => void` |
|
|
38
|
-
| `theme` | `Partial<OnboardingTheme>` |
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
| `startMessage` | `string` |
|
|
48
|
-
| `startTimeoutMs` | `number` |
|
|
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
|
|
53
|
-
2. **Install
|
|
54
|
-
3. **Metro
|
|
55
|
-
4. **Config
|
|
56
|
-
5. **Fonts
|
|
57
|
-
6. **Theme
|
|
58
|
-
7. **Render + continuation
|
|
59
|
-
8. **Gate
|
|
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*
|
|
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
|
|
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
|
|
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
|
|
4
|
-
|
|
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
|
|
package/INTEGRATION_PROMPT.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# Claude integration prompt
|
|
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
|
|
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
|
|
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/
|
|
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:
|
|
26
|
-
package manager (yarn/npm/pnpm
|
|
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
|
-
|
|
29
|
-
of react/react-native/wireai-rn/zod
|
|
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
|
|
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 [
|
|
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
|
-
[](https://www.npmjs.com/package/@wireai/activation)
|
|
14
|
+
[](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/
|
|
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
|
|
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
|
|
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
|
|
135
|
+
npm install @wireai/activation
|
|
136
136
|
# …or from a tarball (see Distribution below)
|
|
137
|
-
npm install
|
|
137
|
+
npm install ./@wireai/activation-0.1.3.tgz
|
|
138
138
|
# …or over SSH
|
|
139
|
-
npm install git+ssh://git@github.com/<org
|
|
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
|
|
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
|
|
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
|
|
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
|
|
182
|
+
const { withWireOnboarding } = require("@wireai/activation/metro");
|
|
183
183
|
|
|
184
184
|
module.exports = withWireOnboarding(getDefaultConfig(__dirname), {
|
|
185
|
-
source: path.join(__dirname, "../../getwire_ai
|
|
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
|
|
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
|
-
|
|
202
|
-
CHANGELOG. The primary channel is **npm** (`npm install wireai
|
|
203
|
-
tarball (`npm 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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 };
|