@wireai/activation 0.9.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/CHANGELOG.md +39 -0
- package/dist/analytics/index.d.mts +1 -1
- package/dist/analytics/index.d.ts +1 -1
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/reviews/index.d.mts +1 -1
- package/dist/reviews/index.d.ts +1 -1
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/{transport-DzU-TqZz.d.ts → transport-B31G0Cib.d.ts} +51 -9
- package/dist/{transport-f5VVB5hH.d.mts → transport-Bzb-bcB2.d.mts} +51 -9
- package/package.json +1 -1
- package/src/reviews/transport.ts +51 -9
|
@@ -20,17 +20,42 @@ import { k as ReviewTarget, g as ReviewDecisionResponse, j as ReviewSubmission }
|
|
|
20
20
|
* a missing `fetch`, or a network failure is swallowed and the call returns immediately.
|
|
21
21
|
*/
|
|
22
22
|
declare const submitReview: (target: ReviewTarget | undefined, review: ReviewSubmission) => void;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Options for the best-effort review decision fetch.
|
|
25
|
+
*
|
|
26
|
+
* ── WHAT THE DEPLOYED SERVER ACTUALLY READS (verified 2026-07-17) ────────────────────────
|
|
27
|
+
*
|
|
28
|
+
* `GET /v1/reviews/decision` declares exactly two query params — `session_id` and
|
|
29
|
+
* `device_key` — plus the `Authorization` header. That is the whole wire. Verified against
|
|
30
|
+
* the deployed OpenAPI schema, not against intent.
|
|
31
|
+
*
|
|
32
|
+
* This type is CLOSED on purpose. Hosts that hand-rolled this fetch invented `user_id` and
|
|
33
|
+
* `session_count` query params believing "the server ignores what it doesn't read, so passing
|
|
34
|
+
* it is always safe". Both are no-ops: the route declares neither. `session_count` is real, but
|
|
35
|
+
* only on the questionnaire POST body — which is precisely how it copy-pasted its way into a
|
|
36
|
+
* reviews call site and sat there doing nothing. They cost a wire lie — a call site that reads as though
|
|
37
|
+
* identity and a session counter reach the firing brain when neither does. So they are not
|
|
38
|
+
* offered here. Pass identity as `deviceKey`; the session count the server reasons about is the
|
|
39
|
+
* one IT derives from the event stream keyed by `deviceKey`, not one the client asserts.
|
|
40
|
+
*
|
|
41
|
+
* The client-side session floor is a LOCAL rule, not a wire param: use `ReviewConfig.minSessions`
|
|
42
|
+
* (evaluated by `useReviewGate` against the kit's own `wire_review_<id>_sessions` counter).
|
|
43
|
+
*/
|
|
24
44
|
interface FetchReviewDecisionOptions {
|
|
25
45
|
/**
|
|
26
46
|
* The onboarding session id, when there IS one. OPTIONAL on purpose: the review gate lives on
|
|
27
47
|
* the home feed, where a user legitimately has no onboarding session. `deviceKey` is the real
|
|
28
|
-
* identity for this call. (
|
|
29
|
-
*
|
|
30
|
-
*
|
|
48
|
+
* identity for this call. (The server relaxed `session_id` to optional on 2026-07-16 and the
|
|
49
|
+
* relaxation IS deployed — the route no longer 422s without it. Permissive wire: do NOT make
|
|
50
|
+
* this required here.)
|
|
31
51
|
*/
|
|
32
52
|
sessionId?: string;
|
|
33
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* A stable, non-PII device id — THE identity for this call. The decision endpoint reads it for
|
|
55
|
+
* cooldown + min-sessions, and it is the key the server groups a device's events under. A host
|
|
56
|
+
* whose own identity is a user id passes that id here rather than reaching for a `user_id`
|
|
57
|
+
* param the route does not declare.
|
|
58
|
+
*/
|
|
34
59
|
deviceKey?: string;
|
|
35
60
|
}
|
|
36
61
|
/**
|
|
@@ -57,12 +82,29 @@ interface FetchReviewDecisionOptions {
|
|
|
57
82
|
* • else → null, and ONLY then. Null means "the server genuinely has no opinion", which is
|
|
58
83
|
* the one case where falling back to local rules is correct.
|
|
59
84
|
*
|
|
60
|
-
* Never throws: unreachable, non-2xx
|
|
61
|
-
*
|
|
62
|
-
*
|
|
85
|
+
* Never throws: unreachable, non-2xx, bad JSON, or a missing `fetch` all resolve to null. The
|
|
86
|
+
* kit does not call this internally; a host awaits it and passes the result straight to
|
|
87
|
+
* `useReviewGate({ decision })`.
|
|
88
|
+
*
|
|
89
|
+
* ── DON'T RACE THIS AGAINST A LOCAL TIMER ────────────────────────────────────────────────
|
|
90
|
+
*
|
|
91
|
+
* The return type is `ReviewDecisionResponse`, which carries `arm` alongside `{fire, reason}`.
|
|
92
|
+
* Hand the WHOLE object to the gate and echo `arm` into the submission's `meta.firing_arm`;
|
|
93
|
+
* narrowing it to `{fire, reason}` on the way through silently kills per-arm attribution
|
|
94
|
+
* across a reweighting of the experiment.
|
|
95
|
+
*
|
|
96
|
+
* A host that starts its own dwell timer in parallel with this fetch has built a race a slow
|
|
97
|
+
* server loses: the timer fires, the local rules show the prompt, and the `{fire:false}` still
|
|
98
|
+
* in flight arrives too late to stop it. Do not hand-roll that. `useReviewGate` already owns
|
|
99
|
+
* the wait — set `ReviewConfig.timeoutFallbackMs` and the local rules stay parked until either
|
|
100
|
+
* the decision lands or the window expires, whichever comes first.
|
|
63
101
|
*
|
|
64
102
|
* const decision = await fetchReviewDecision(target, { deviceKey });
|
|
65
|
-
* const gate = useReviewGate({
|
|
103
|
+
* const gate = useReviewGate({
|
|
104
|
+
* config: { id: "home", minSessions: 2, timeoutFallbackMs: 3000 },
|
|
105
|
+
* decision: decision ?? undefined, // pass it whole — keep `arm`
|
|
106
|
+
* storage,
|
|
107
|
+
* });
|
|
66
108
|
*/
|
|
67
109
|
declare const fetchReviewDecision: (target: ReviewTarget | undefined, options?: FetchReviewDecisionOptions) => Promise<ReviewDecisionResponse | null>;
|
|
68
110
|
/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */
|
|
@@ -20,17 +20,42 @@ import { k as ReviewTarget, g as ReviewDecisionResponse, j as ReviewSubmission }
|
|
|
20
20
|
* a missing `fetch`, or a network failure is swallowed and the call returns immediately.
|
|
21
21
|
*/
|
|
22
22
|
declare const submitReview: (target: ReviewTarget | undefined, review: ReviewSubmission) => void;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Options for the best-effort review decision fetch.
|
|
25
|
+
*
|
|
26
|
+
* ── WHAT THE DEPLOYED SERVER ACTUALLY READS (verified 2026-07-17) ────────────────────────
|
|
27
|
+
*
|
|
28
|
+
* `GET /v1/reviews/decision` declares exactly two query params — `session_id` and
|
|
29
|
+
* `device_key` — plus the `Authorization` header. That is the whole wire. Verified against
|
|
30
|
+
* the deployed OpenAPI schema, not against intent.
|
|
31
|
+
*
|
|
32
|
+
* This type is CLOSED on purpose. Hosts that hand-rolled this fetch invented `user_id` and
|
|
33
|
+
* `session_count` query params believing "the server ignores what it doesn't read, so passing
|
|
34
|
+
* it is always safe". Both are no-ops: the route declares neither. `session_count` is real, but
|
|
35
|
+
* only on the questionnaire POST body — which is precisely how it copy-pasted its way into a
|
|
36
|
+
* reviews call site and sat there doing nothing. They cost a wire lie — a call site that reads as though
|
|
37
|
+
* identity and a session counter reach the firing brain when neither does. So they are not
|
|
38
|
+
* offered here. Pass identity as `deviceKey`; the session count the server reasons about is the
|
|
39
|
+
* one IT derives from the event stream keyed by `deviceKey`, not one the client asserts.
|
|
40
|
+
*
|
|
41
|
+
* The client-side session floor is a LOCAL rule, not a wire param: use `ReviewConfig.minSessions`
|
|
42
|
+
* (evaluated by `useReviewGate` against the kit's own `wire_review_<id>_sessions` counter).
|
|
43
|
+
*/
|
|
24
44
|
interface FetchReviewDecisionOptions {
|
|
25
45
|
/**
|
|
26
46
|
* The onboarding session id, when there IS one. OPTIONAL on purpose: the review gate lives on
|
|
27
47
|
* the home feed, where a user legitimately has no onboarding session. `deviceKey` is the real
|
|
28
|
-
* identity for this call. (
|
|
29
|
-
*
|
|
30
|
-
*
|
|
48
|
+
* identity for this call. (The server relaxed `session_id` to optional on 2026-07-16 and the
|
|
49
|
+
* relaxation IS deployed — the route no longer 422s without it. Permissive wire: do NOT make
|
|
50
|
+
* this required here.)
|
|
31
51
|
*/
|
|
32
52
|
sessionId?: string;
|
|
33
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* A stable, non-PII device id — THE identity for this call. The decision endpoint reads it for
|
|
55
|
+
* cooldown + min-sessions, and it is the key the server groups a device's events under. A host
|
|
56
|
+
* whose own identity is a user id passes that id here rather than reaching for a `user_id`
|
|
57
|
+
* param the route does not declare.
|
|
58
|
+
*/
|
|
34
59
|
deviceKey?: string;
|
|
35
60
|
}
|
|
36
61
|
/**
|
|
@@ -57,12 +82,29 @@ interface FetchReviewDecisionOptions {
|
|
|
57
82
|
* • else → null, and ONLY then. Null means "the server genuinely has no opinion", which is
|
|
58
83
|
* the one case where falling back to local rules is correct.
|
|
59
84
|
*
|
|
60
|
-
* Never throws: unreachable, non-2xx
|
|
61
|
-
*
|
|
62
|
-
*
|
|
85
|
+
* Never throws: unreachable, non-2xx, bad JSON, or a missing `fetch` all resolve to null. The
|
|
86
|
+
* kit does not call this internally; a host awaits it and passes the result straight to
|
|
87
|
+
* `useReviewGate({ decision })`.
|
|
88
|
+
*
|
|
89
|
+
* ── DON'T RACE THIS AGAINST A LOCAL TIMER ────────────────────────────────────────────────
|
|
90
|
+
*
|
|
91
|
+
* The return type is `ReviewDecisionResponse`, which carries `arm` alongside `{fire, reason}`.
|
|
92
|
+
* Hand the WHOLE object to the gate and echo `arm` into the submission's `meta.firing_arm`;
|
|
93
|
+
* narrowing it to `{fire, reason}` on the way through silently kills per-arm attribution
|
|
94
|
+
* across a reweighting of the experiment.
|
|
95
|
+
*
|
|
96
|
+
* A host that starts its own dwell timer in parallel with this fetch has built a race a slow
|
|
97
|
+
* server loses: the timer fires, the local rules show the prompt, and the `{fire:false}` still
|
|
98
|
+
* in flight arrives too late to stop it. Do not hand-roll that. `useReviewGate` already owns
|
|
99
|
+
* the wait — set `ReviewConfig.timeoutFallbackMs` and the local rules stay parked until either
|
|
100
|
+
* the decision lands or the window expires, whichever comes first.
|
|
63
101
|
*
|
|
64
102
|
* const decision = await fetchReviewDecision(target, { deviceKey });
|
|
65
|
-
* const gate = useReviewGate({
|
|
103
|
+
* const gate = useReviewGate({
|
|
104
|
+
* config: { id: "home", minSessions: 2, timeoutFallbackMs: 3000 },
|
|
105
|
+
* decision: decision ?? undefined, // pass it whole — keep `arm`
|
|
106
|
+
* storage,
|
|
107
|
+
* });
|
|
66
108
|
*/
|
|
67
109
|
declare const fetchReviewDecision: (target: ReviewTarget | undefined, options?: FetchReviewDecisionOptions) => Promise<ReviewDecisionResponse | null>;
|
|
68
110
|
/** Options for a reported app event. `deviceKey` groups a device's sessions server-side. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wireai/activation",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Premium, fully-themable drop-in AI onboarding kit for React Native / Expo, on top of the open-source wireai-rn SDK.",
|
|
6
6
|
"author": "Malik Chohra <malik@getwireai.com>",
|
package/src/reviews/transport.ts
CHANGED
|
@@ -39,17 +39,42 @@ export const submitReview = (
|
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
/**
|
|
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
|
+
*/
|
|
43
63
|
export interface FetchReviewDecisionOptions {
|
|
44
64
|
/**
|
|
45
65
|
* The onboarding session id, when there IS one. OPTIONAL on purpose: the review gate lives on
|
|
46
66
|
* the home feed, where a user legitimately has no onboarding session. `deviceKey` is the real
|
|
47
|
-
* identity for this call. (
|
|
48
|
-
*
|
|
49
|
-
*
|
|
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.)
|
|
50
70
|
*/
|
|
51
71
|
sessionId?: string;
|
|
52
|
-
/**
|
|
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
|
+
*/
|
|
53
78
|
deviceKey?: string;
|
|
54
79
|
}
|
|
55
80
|
|
|
@@ -77,12 +102,29 @@ export interface FetchReviewDecisionOptions {
|
|
|
77
102
|
* • else → null, and ONLY then. Null means "the server genuinely has no opinion", which is
|
|
78
103
|
* the one case where falling back to local rules is correct.
|
|
79
104
|
*
|
|
80
|
-
* Never throws: unreachable, non-2xx
|
|
81
|
-
*
|
|
82
|
-
*
|
|
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.
|
|
83
121
|
*
|
|
84
122
|
* const decision = await fetchReviewDecision(target, { deviceKey });
|
|
85
|
-
* const gate = useReviewGate({
|
|
123
|
+
* const gate = useReviewGate({
|
|
124
|
+
* config: { id: "home", minSessions: 2, timeoutFallbackMs: 3000 },
|
|
125
|
+
* decision: decision ?? undefined, // pass it whole — keep `arm`
|
|
126
|
+
* storage,
|
|
127
|
+
* });
|
|
86
128
|
*/
|
|
87
129
|
export const fetchReviewDecision = async (
|
|
88
130
|
target: ReviewTarget | undefined,
|