@wireai/activation 0.8.0 → 0.9.1
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 +29 -5
- package/CHANGELOG.md +202 -6
- package/README.md +105 -10
- package/dist/analytics/index.d.mts +6 -6
- package/dist/analytics/index.d.ts +6 -6
- package/dist/analytics/index.js +447 -49
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +447 -49
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/coachmarks/index.d.mts +2 -2
- package/dist/coachmarks/index.d.ts +2 -2
- package/dist/coachmarks/index.js.map +1 -1
- package/dist/coachmarks/index.mjs.map +1 -1
- package/dist/{currentSession-f7LWcdWG.d.ts → currentSession-61dcm3V-.d.ts} +10 -2
- package/dist/{currentSession-d9CrBxwe.d.mts → currentSession-Bs2JfTJ8.d.mts} +10 -2
- package/dist/{decision-BzbiKwk3.d.mts → decision-Bl_M2y3r.d.mts} +1 -1
- package/dist/{decision-plDEOCkt.d.ts → decision-Cau5KmP6.d.ts} +1 -1
- package/dist/index.d.mts +558 -15
- package/dist/index.d.ts +558 -15
- package/dist/index.js +1144 -375
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +969 -207
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +69 -23
- package/dist/questionnaire/index.d.ts +69 -23
- package/dist/questionnaire/index.js +643 -172
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +608 -137
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.d.mts +24 -12
- package/dist/reviews/index.d.ts +24 -12
- package/dist/reviews/index.js +507 -173
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +462 -129
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/showcase/index.d.mts +2 -2
- package/dist/showcase/index.d.ts +2 -2
- package/dist/showcase/index.js.map +1 -1
- package/dist/showcase/index.mjs.map +1 -1
- package/dist/transport-B31G0Cib.d.ts +128 -0
- package/dist/transport-Bzb-bcB2.d.mts +128 -0
- package/dist/{types-GL_hQ0TN.d.mts → types-BcmagF6K.d.mts} +1 -1
- package/dist/{types-GL_hQ0TN.d.ts → types-BcmagF6K.d.ts} +1 -1
- package/dist/{types-BhpXJGlg.d.ts → types-Buj9Lw9t.d.ts} +15 -3
- package/dist/{types-CMuOexw0.d.mts → types-CKFhyrMu.d.mts} +1 -1
- package/dist/{types-CMuOexw0.d.ts → types-CKFhyrMu.d.ts} +1 -1
- package/dist/{types-A6pTxIZV.d.mts → types-CNUqMK0D.d.mts} +15 -3
- package/metro/index.d.ts +18 -1
- package/metro/index.js +80 -0
- package/package.json +9 -1
- package/src/WireOnboarding.tsx +4 -0
- package/src/analytics/currentSession.ts +1 -1
- package/src/cards/CardGridSelectCard.tsx +253 -0
- package/src/cards/ChipSelectCard.tsx +1 -1
- package/src/cards/SelectionCard.tsx +15 -19
- package/src/cards/index.ts +13 -1
- package/src/cards/optionSchema.ts +65 -0
- package/src/coachmarks/types.ts +1 -1
- package/src/components/CardHandoff.tsx +39 -7
- package/src/components/DoneCheck.tsx +94 -0
- package/src/components/ModalPaneHost.tsx +141 -0
- package/src/components/StepDots.tsx +112 -0
- package/src/device/appVersion.ts +29 -8
- package/src/device/deviceModel.ts +21 -8
- package/src/features/cache.ts +1 -1
- package/src/haptics/expo-haptics.d.ts +31 -0
- package/src/haptics/haptics.ts +58 -0
- package/src/icons/IconRegistry.tsx +53 -0
- package/src/icons/WireIcon.tsx +85 -0
- package/src/icons/expoIcons.ts +165 -0
- package/src/icons/index.ts +18 -0
- package/src/icons/vocabulary.ts +154 -0
- package/src/index.ts +20 -0
- package/src/questionnaire/QuestionnaireGate.tsx +315 -164
- package/src/questionnaire/decision.ts +4 -2
- package/src/questionnaire/index.ts +3 -2
- package/src/questionnaire/steps.ts +261 -0
- package/src/questionnaire/types.ts +33 -12
- package/src/reviews/ReviewGate.tsx +250 -152
- package/src/reviews/index.ts +7 -3
- package/src/reviews/transport.ts +119 -3
- package/src/reviews/types.ts +13 -0
- package/src/session/persistedSession.ts +1 -1
- package/src/session-analytics/lifecycle.ts +1 -1
- package/src/session-analytics/useSessionStart.ts +2 -2
- package/src/showcase/FeatureShowcase.tsx +1 -1
- package/src/showcase/showcaseColors.ts +1 -1
- package/src/theme/mergeThemeOver.ts +27 -0
- package/src/types.ts +8 -0
- package/dist/transport-BeO_Brcu.d.mts +0 -40
- package/dist/transport-DLpd1v5_.d.ts +0 -40
package/src/reviews/transport.ts
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
* (analytics/reviews must never break the app). Mirrors analytics/reportClientEvent: a
|
|
4
4
|
* thin fetch wrapper, Bearer tenant key, swallow every error.
|
|
5
5
|
*
|
|
6
|
-
* • submitReview
|
|
7
|
-
* •
|
|
6
|
+
* • submitReview → POST {serverUrl}/v1/reviews (the review row)
|
|
7
|
+
* • fetchReviewDecision → GET {serverUrl}/v1/reviews/decision (best-effort, the AI seam)
|
|
8
|
+
* • reportAppEvent → POST {serverUrl}/v1/events (generic app.* namespace)
|
|
8
9
|
*
|
|
9
10
|
* `reportAppEvent` is the strategic extension: it lets a host report arbitrary in-app
|
|
10
11
|
* events through the SAME transport (stored server-side as event_type='app_event',
|
|
11
12
|
* question_key=<name>), which is what the backend review-firing rules evaluate on — and
|
|
12
13
|
* it seeds the broader app-analytics stream. Keep payloads minimal + non-PII.
|
|
13
14
|
*/
|
|
14
|
-
import type { ReviewSubmission, ReviewTarget } from "./types";
|
|
15
|
+
import type { ReviewDecisionResponse, ReviewSubmission, ReviewTarget } from "./types";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* POST a review (the 1-4 feedback path). Fire-and-forget: a missing target, a build error,
|
|
@@ -38,6 +39,121 @@ export const submitReview = (
|
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Options for the best-effort review decision fetch.
|
|
44
|
+
*
|
|
45
|
+
* ── WHAT THE DEPLOYED SERVER ACTUALLY READS (verified 2026-07-17) ────────────────────────
|
|
46
|
+
*
|
|
47
|
+
* `GET /v1/reviews/decision` declares exactly two query params — `session_id` and
|
|
48
|
+
* `device_key` — plus the `Authorization` header. That is the whole wire. Verified against
|
|
49
|
+
* the deployed OpenAPI schema, not against intent.
|
|
50
|
+
*
|
|
51
|
+
* This type is CLOSED on purpose. Hosts that hand-rolled this fetch invented `user_id` and
|
|
52
|
+
* `session_count` query params believing "the server ignores what it doesn't read, so passing
|
|
53
|
+
* it is always safe". Both are no-ops: the route declares neither. `session_count` is real, but
|
|
54
|
+
* only on the questionnaire POST body — which is precisely how it copy-pasted its way into a
|
|
55
|
+
* reviews call site and sat there doing nothing. They cost a wire lie — a call site that reads as though
|
|
56
|
+
* identity and a session counter reach the firing brain when neither does. So they are not
|
|
57
|
+
* offered here. Pass identity as `deviceKey`; the session count the server reasons about is the
|
|
58
|
+
* one IT derives from the event stream keyed by `deviceKey`, not one the client asserts.
|
|
59
|
+
*
|
|
60
|
+
* The client-side session floor is a LOCAL rule, not a wire param: use `ReviewConfig.minSessions`
|
|
61
|
+
* (evaluated by `useReviewGate` against the kit's own `wire_review_<id>_sessions` counter).
|
|
62
|
+
*/
|
|
63
|
+
export interface FetchReviewDecisionOptions {
|
|
64
|
+
/**
|
|
65
|
+
* The onboarding session id, when there IS one. OPTIONAL on purpose: the review gate lives on
|
|
66
|
+
* the home feed, where a user legitimately has no onboarding session. `deviceKey` is the real
|
|
67
|
+
* identity for this call. (The server relaxed `session_id` to optional on 2026-07-16 and the
|
|
68
|
+
* relaxation IS deployed — the route no longer 422s without it. Permissive wire: do NOT make
|
|
69
|
+
* this required here.)
|
|
70
|
+
*/
|
|
71
|
+
sessionId?: string;
|
|
72
|
+
/**
|
|
73
|
+
* A stable, non-PII device id — THE identity for this call. The decision endpoint reads it for
|
|
74
|
+
* cooldown + min-sessions, and it is the key the server groups a device's events under. A host
|
|
75
|
+
* whose own identity is a user id passes that id here rather than reaching for a `user_id`
|
|
76
|
+
* param the route does not declare.
|
|
77
|
+
*/
|
|
78
|
+
deviceKey?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Best-effort fetch of the SERVER's review firing decision. The mirror of
|
|
83
|
+
* `fetchQuestionnaireDecision`, and the primitive whose absence caused a live incident.
|
|
84
|
+
*
|
|
85
|
+
* ── WHY THIS LIVES IN THE KIT (Malik, 2026-07-16) ────────────────────────────────────────
|
|
86
|
+
*
|
|
87
|
+
* The questionnaire module has always had its decision fetch; reviews never did. So a host
|
|
88
|
+
* hand-rolled one, and got it subtly wrong: its helper collapsed an explicit `{fire:false}`
|
|
89
|
+
* into `undefined`. `decideReview` is `(local, decision) => decision ?? local`, so `undefined`
|
|
90
|
+
* means "the server has no opinion, use the local rules" — and the local timer fired. The
|
|
91
|
+
* server could therefore only ever turn review prompts ON, never OFF. A real user was asked to
|
|
92
|
+
* rate the app ~3 minutes into their FIRST session, having seen nothing yet, and left 1 star.
|
|
93
|
+
*
|
|
94
|
+
* The bug was not that the host was careless. It was that the kit made every host invent this.
|
|
95
|
+
* So the primitive moves here and hosts keep a thin call site.
|
|
96
|
+
*
|
|
97
|
+
* ── THE CONTRACT THAT MATTERS ────────────────────────────────────────────────────────────
|
|
98
|
+
*
|
|
99
|
+
* • 2xx → the FULL `{fire, reason, arm}`, INCLUDING `fire:false`. Never collapse a false
|
|
100
|
+
* into null. That collapse IS the bug: a false must reach `decideReview` intact so
|
|
101
|
+
* it can override the local rules and keep the gate shut.
|
|
102
|
+
* • else → null, and ONLY then. Null means "the server genuinely has no opinion", which is
|
|
103
|
+
* the one case where falling back to local rules is correct.
|
|
104
|
+
*
|
|
105
|
+
* Never throws: unreachable, non-2xx, bad JSON, or a missing `fetch` all resolve to null. The
|
|
106
|
+
* kit does not call this internally; a host awaits it and passes the result straight to
|
|
107
|
+
* `useReviewGate({ decision })`.
|
|
108
|
+
*
|
|
109
|
+
* ── DON'T RACE THIS AGAINST A LOCAL TIMER ────────────────────────────────────────────────
|
|
110
|
+
*
|
|
111
|
+
* The return type is `ReviewDecisionResponse`, which carries `arm` alongside `{fire, reason}`.
|
|
112
|
+
* Hand the WHOLE object to the gate and echo `arm` into the submission's `meta.firing_arm`;
|
|
113
|
+
* narrowing it to `{fire, reason}` on the way through silently kills per-arm attribution
|
|
114
|
+
* across a reweighting of the experiment.
|
|
115
|
+
*
|
|
116
|
+
* A host that starts its own dwell timer in parallel with this fetch has built a race a slow
|
|
117
|
+
* server loses: the timer fires, the local rules show the prompt, and the `{fire:false}` still
|
|
118
|
+
* in flight arrives too late to stop it. Do not hand-roll that. `useReviewGate` already owns
|
|
119
|
+
* the wait — set `ReviewConfig.timeoutFallbackMs` and the local rules stay parked until either
|
|
120
|
+
* the decision lands or the window expires, whichever comes first.
|
|
121
|
+
*
|
|
122
|
+
* const decision = await fetchReviewDecision(target, { deviceKey });
|
|
123
|
+
* const gate = useReviewGate({
|
|
124
|
+
* config: { id: "home", minSessions: 2, timeoutFallbackMs: 3000 },
|
|
125
|
+
* decision: decision ?? undefined, // pass it whole — keep `arm`
|
|
126
|
+
* storage,
|
|
127
|
+
* });
|
|
128
|
+
*/
|
|
129
|
+
export const fetchReviewDecision = async (
|
|
130
|
+
target: ReviewTarget | undefined,
|
|
131
|
+
options: FetchReviewDecisionOptions = {},
|
|
132
|
+
): Promise<ReviewDecisionResponse | null> => {
|
|
133
|
+
if (!target?.serverUrl) return null;
|
|
134
|
+
try {
|
|
135
|
+
const base = target.serverUrl.replace(/\/$/, "");
|
|
136
|
+
const params = new URLSearchParams();
|
|
137
|
+
if (options.sessionId) params.set("session_id", options.sessionId);
|
|
138
|
+
if (options.deviceKey) params.set("device_key", options.deviceKey);
|
|
139
|
+
const qs = params.toString();
|
|
140
|
+
const url = `${base}/v1/reviews/decision${qs ? `?${qs}` : ""}`;
|
|
141
|
+
const headers: Record<string, string> = {};
|
|
142
|
+
if (target.apiKey) headers.Authorization = `Bearer ${target.apiKey}`;
|
|
143
|
+
const res = await fetch(url, { headers });
|
|
144
|
+
if (!res || !res.ok) return null;
|
|
145
|
+
const json = (await res.json()) as ReviewDecisionResponse | null;
|
|
146
|
+
// A body without a boolean `fire` is not a decision. Guard it explicitly rather than
|
|
147
|
+
// letting `{}` through as a truthy object that `decideReview` would treat as a verdict
|
|
148
|
+
// (`{}.fire === undefined` is falsy, so it would silently read as "never fire").
|
|
149
|
+
if (!json || typeof json.fire !== "boolean") return null;
|
|
150
|
+
return json;
|
|
151
|
+
} catch {
|
|
152
|
+
/* unreachable / non-2xx / bad JSON / missing-fetch → the server has no opinion */
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
41
157
|
/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */
|
|
42
158
|
export interface ReportAppEventOptions {
|
|
43
159
|
/** The onboarding/session id to correlate with, when known. */
|
package/src/reviews/types.ts
CHANGED
|
@@ -19,6 +19,19 @@ export interface ReviewDecision {
|
|
|
19
19
|
reason?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* The `GET /v1/reviews/decision` response: `ReviewDecision` plus the additive `arm`.
|
|
24
|
+
*
|
|
25
|
+
* `arm` is the firing experiment's sticky assignment for this device/session. Echo it back in
|
|
26
|
+
* the submission's `meta.firing_arm` and the server keeps it verbatim (`_stamp_firing_arm`:
|
|
27
|
+
* "an arm the kit already echoed is left as-is"); omit it and the server recomputes from the
|
|
28
|
+
* sticky hash. Echoing is what makes per-arm attribution survive a later reweighting of the
|
|
29
|
+
* experiment, so a host running one should pass it through.
|
|
30
|
+
*/
|
|
31
|
+
export interface ReviewDecisionResponse extends ReviewDecision {
|
|
32
|
+
arm?: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
/** Where to route a rating: 5 stars → the store, 1-4 → the feedback form. */
|
|
23
36
|
export type RatingRoute = "store" | "feedback";
|
|
24
37
|
|
|
@@ -39,7 +39,7 @@ export const DEFAULT_SESSION_TTL_MS = 3_600_000;
|
|
|
39
39
|
/** Ceiling on the storage read — a hung adapter degrades to a fresh mint, never a stuck gate. */
|
|
40
40
|
const READ_TIMEOUT_MS = 1_500;
|
|
41
41
|
|
|
42
|
-
/** Storage key for an app's cached session, e.g. `wireai:session:
|
|
42
|
+
/** Storage key for an app's cached session, e.g. `wireai:session:acme`. */
|
|
43
43
|
export const sessionStorageKey = (appId: string): string => `wireai:session:${appId}`;
|
|
44
44
|
|
|
45
45
|
type PersistedSession = { id: string; ts: number };
|
|
@@ -44,7 +44,7 @@ import { reportSessionStart, SESSION_STARTED_EVENT } from "./reportSessionStart"
|
|
|
44
44
|
* {@link SESSION_STARTED_EVENT}; a trigger keys off this exact string. */
|
|
45
45
|
export const FIRST_OPEN_EVENT = "app.first_open" as const;
|
|
46
46
|
|
|
47
|
-
/** Storage key for the once-ever first-open flag, e.g. `wireai:first_open:
|
|
47
|
+
/** Storage key for the once-ever first-open flag, e.g. `wireai:first_open:acme`. Mirrors the
|
|
48
48
|
* `wireai:<concern>:<appId>` namespacing of {@link sessionStorageKey}. */
|
|
49
49
|
export const firstOpenStorageKey = (appId: string): string => `wireai:first_open:${appId}`;
|
|
50
50
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useSessionStart — the optional convenience hook that fires {@link reportSessionStart} for you.
|
|
3
3
|
*
|
|
4
|
-
* Two firing moments, mirroring the
|
|
4
|
+
* Two firing moments, mirroring the reference apps' session-counter semantics:
|
|
5
5
|
* • ON MOUNT — the app opened (cold start or the provider first rendered).
|
|
6
6
|
* • ON FOREGROUND after a real background — when AppState returns to `active` having been
|
|
7
7
|
* backgrounded for at least {@link BACKGROUND_SESSION_MS} (30 min), that's a NEW open, so a
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Each firing mints its OWN per-open `session_id` (held in a ref so a re-render never re-fires),
|
|
11
11
|
* so grouping over time is by `deviceKey`/`userId`, never by session_id (see reportSessionStart).
|
|
12
12
|
*
|
|
13
|
-
* The hook is OPTIONAL. A host that already owns a session counter (
|
|
13
|
+
* The hook is OPTIONAL. A host that already owns a session counter (most hosts do) can skip
|
|
14
14
|
* the hook and call `reportSessionStart(...)` directly from its own "app opened" path — BOTH
|
|
15
15
|
* paths are first-class. This hook is the batteries-included option for a host that has none.
|
|
16
16
|
*
|
|
@@ -135,7 +135,7 @@ const _FeatureShowcase: React.FC<FeatureShowcaseProps> = ({
|
|
|
135
135
|
// Calm the large image/hero panel. The package's `background.primary` is a
|
|
136
136
|
// SINGLE key that fills the primary button, the intro highlight AND this hero
|
|
137
137
|
// panel — painting it `accent` (correct for the button) also flooded the first
|
|
138
|
-
// slide with the app color (
|
|
138
|
+
// slide with the app color (0.3.1). The package exposes a
|
|
139
139
|
// `background` render prop that REPLACES that panel fill outright, so we keep
|
|
140
140
|
// the button accent (via `colors`) and paint the panel a calm surface + faint
|
|
141
141
|
// accent tint here. See showcasePanelBackground.
|
|
@@ -63,7 +63,7 @@ export const showcaseColorsFromTheme = (
|
|
|
63
63
|
* Opacity of the accent tint layered over the theme surface for the showcase's
|
|
64
64
|
* image hero panel. Kept in a calm 8–12% band so the panel reads as a subtle
|
|
65
65
|
* brand wash — a hint of the accent, never the full-bleed flood that `accent`
|
|
66
|
-
* as a solid fill produced (the 0.3.1 → 0.3.2 bug
|
|
66
|
+
* as a solid fill produced (the 0.3.1 → 0.3.2 bug seen in a host app).
|
|
67
67
|
*/
|
|
68
68
|
export const SHOWCASE_PANEL_TINT_OPACITY = 0.1;
|
|
69
69
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mergeThemeOver — merge a partial theme over an ARBITRARY base theme.
|
|
3
|
+
*
|
|
4
|
+
* Sibling of `mergeTheme` (defaultTheme.ts), which merges over the DEFAULT theme only.
|
|
5
|
+
* Gates need the other shape: a `theme` prop merged over whatever the host's active
|
|
6
|
+
* ThemeContext currently is. That helper was copy-pasted verbatim into ReviewGate and
|
|
7
|
+
* QuestionnaireGate; it lives here once instead, so a new theme section can never be
|
|
8
|
+
* added to one gate and forgotten in the other.
|
|
9
|
+
*
|
|
10
|
+
* Two levels deep, matching `mergeTheme`: the theme is intentionally shallow, so each
|
|
11
|
+
* known sub-object is merged and scalars overwrite.
|
|
12
|
+
*/
|
|
13
|
+
import type { OnboardingTheme } from "./types";
|
|
14
|
+
|
|
15
|
+
export const mergeThemeOver = (
|
|
16
|
+
base: OnboardingTheme,
|
|
17
|
+
override?: Partial<OnboardingTheme>,
|
|
18
|
+
): OnboardingTheme => {
|
|
19
|
+
if (!override) return base;
|
|
20
|
+
return {
|
|
21
|
+
colors: { ...base.colors, ...override.colors },
|
|
22
|
+
fonts: { ...base.fonts, ...override.fonts },
|
|
23
|
+
radius: { ...base.radius, ...override.radius },
|
|
24
|
+
spacing: { ...base.spacing, ...override.spacing },
|
|
25
|
+
button: { ...base.button, ...override.button },
|
|
26
|
+
};
|
|
27
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -108,6 +108,14 @@ export type WireOnboardingProps = {
|
|
|
108
108
|
* via `illustration`; the kit slots the matching node (keeping itself dependency-free).
|
|
109
109
|
*/
|
|
110
110
|
illustrations?: Record<string, import("react").ReactNode>;
|
|
111
|
+
/**
|
|
112
|
+
* App-supplied ICON nodes, keyed by the semantic vocabulary name the AI emits (e.g.
|
|
113
|
+
* `{ instagram: <BrandIg/> }`). Checked FIRST, so a host can override any icon with its own
|
|
114
|
+
* brand mark, supply icons without installing `@expo/vector-icons`, or extend the vocabulary
|
|
115
|
+
* with names of its own. Anything not listed falls back to `@expo/vector-icons` when that
|
|
116
|
+
* optional peer is present, and to no icon at all when it isn't — never a crash.
|
|
117
|
+
*/
|
|
118
|
+
icons?: Record<string, import("react").ReactNode>;
|
|
111
119
|
/** Per-step validators keyed by base-question key, e.g. `{ username: checkUsername }`. */
|
|
112
120
|
validators?: Record<string, StepValidator>;
|
|
113
121
|
/** Fired once the flow reaches its terminal StatusCard. */
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { j as ReviewTarget, i as ReviewSubmission } from './types-A6pTxIZV.mjs';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* transport.ts — kit → Wire server requests for the review module, all fire-and-forget
|
|
5
|
-
* (analytics/reviews must never break the app). Mirrors analytics/reportClientEvent: a
|
|
6
|
-
* thin fetch wrapper, Bearer tenant key, swallow every error.
|
|
7
|
-
*
|
|
8
|
-
* • submitReview → POST {serverUrl}/v1/reviews (the 1-4 feedback body)
|
|
9
|
-
* • reportAppEvent → POST {serverUrl}/v1/events (generic app.* namespace)
|
|
10
|
-
*
|
|
11
|
-
* `reportAppEvent` is the strategic extension: it lets a host report arbitrary in-app
|
|
12
|
-
* events through the SAME transport (stored server-side as event_type='app_event',
|
|
13
|
-
* question_key=<name>), which is what the backend review-firing rules evaluate on — and
|
|
14
|
-
* it seeds the broader app-analytics stream. Keep payloads minimal + non-PII.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* POST a review (the 1-4 feedback path). Fire-and-forget: a missing target, a build error,
|
|
19
|
-
* a missing `fetch`, or a network failure is swallowed and the call returns immediately.
|
|
20
|
-
*/
|
|
21
|
-
declare const submitReview: (target: ReviewTarget | undefined, review: ReviewSubmission) => void;
|
|
22
|
-
/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */
|
|
23
|
-
interface ReportAppEventOptions {
|
|
24
|
-
/** The onboarding/session id to correlate with, when known. */
|
|
25
|
-
sessionId?: string;
|
|
26
|
-
/** A stable, non-PII device id — the review-decision endpoint reads it for min-sessions. */
|
|
27
|
-
deviceKey?: string;
|
|
28
|
-
/** Small non-PII extras. */
|
|
29
|
-
meta?: Record<string, unknown>;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Report a generic in-app event through the existing events transport. Stored server-side
|
|
33
|
-
* as `event_type='app_event'`, `question_key=<name>`. Fire-and-forget. Keep `name` a short
|
|
34
|
-
* stable identifier and `meta` small + non-PII.
|
|
35
|
-
*
|
|
36
|
-
* reportAppEvent(target, "content_share", { sessionId, deviceKey });
|
|
37
|
-
*/
|
|
38
|
-
declare const reportAppEvent: (target: ReviewTarget | undefined, name: string, options?: ReportAppEventOptions) => void;
|
|
39
|
-
|
|
40
|
-
export { type ReportAppEventOptions as R, reportAppEvent as r, submitReview as s };
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { j as ReviewTarget, i as ReviewSubmission } from './types-BhpXJGlg.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* transport.ts — kit → Wire server requests for the review module, all fire-and-forget
|
|
5
|
-
* (analytics/reviews must never break the app). Mirrors analytics/reportClientEvent: a
|
|
6
|
-
* thin fetch wrapper, Bearer tenant key, swallow every error.
|
|
7
|
-
*
|
|
8
|
-
* • submitReview → POST {serverUrl}/v1/reviews (the 1-4 feedback body)
|
|
9
|
-
* • reportAppEvent → POST {serverUrl}/v1/events (generic app.* namespace)
|
|
10
|
-
*
|
|
11
|
-
* `reportAppEvent` is the strategic extension: it lets a host report arbitrary in-app
|
|
12
|
-
* events through the SAME transport (stored server-side as event_type='app_event',
|
|
13
|
-
* question_key=<name>), which is what the backend review-firing rules evaluate on — and
|
|
14
|
-
* it seeds the broader app-analytics stream. Keep payloads minimal + non-PII.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* POST a review (the 1-4 feedback path). Fire-and-forget: a missing target, a build error,
|
|
19
|
-
* a missing `fetch`, or a network failure is swallowed and the call returns immediately.
|
|
20
|
-
*/
|
|
21
|
-
declare const submitReview: (target: ReviewTarget | undefined, review: ReviewSubmission) => void;
|
|
22
|
-
/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */
|
|
23
|
-
interface ReportAppEventOptions {
|
|
24
|
-
/** The onboarding/session id to correlate with, when known. */
|
|
25
|
-
sessionId?: string;
|
|
26
|
-
/** A stable, non-PII device id — the review-decision endpoint reads it for min-sessions. */
|
|
27
|
-
deviceKey?: string;
|
|
28
|
-
/** Small non-PII extras. */
|
|
29
|
-
meta?: Record<string, unknown>;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Report a generic in-app event through the existing events transport. Stored server-side
|
|
33
|
-
* as `event_type='app_event'`, `question_key=<name>`. Fire-and-forget. Keep `name` a short
|
|
34
|
-
* stable identifier and `meta` small + non-PII.
|
|
35
|
-
*
|
|
36
|
-
* reportAppEvent(target, "content_share", { sessionId, deviceKey });
|
|
37
|
-
*/
|
|
38
|
-
declare const reportAppEvent: (target: ReviewTarget | undefined, name: string, options?: ReportAppEventOptions) => void;
|
|
39
|
-
|
|
40
|
-
export { type ReportAppEventOptions as R, reportAppEvent as r, submitReview as s };
|