@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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
2
|
import { O as OnboardingTheme } from '../types-BKfpdZzX.mjs';
|
|
3
|
-
import { C as CoachmarkStorage } from '../types-
|
|
4
|
-
import { W as WireFeatures, a as WireFeaturesConfig } from '../types-
|
|
5
|
-
export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-
|
|
6
|
-
import '../types-
|
|
3
|
+
import { C as CoachmarkStorage } from '../types-BcmagF6K.mjs';
|
|
4
|
+
import { W as WireFeatures, a as WireFeaturesConfig } from '../types-CKFhyrMu.mjs';
|
|
5
|
+
export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-Bl_M2y3r.mjs';
|
|
6
|
+
import '../types-CNUqMK0D.mjs';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The firing verdict - the SAME contract on both sides of the seam. `decideQuestionnaire`
|
|
@@ -24,13 +24,19 @@ interface QuestionnaireDecision {
|
|
|
24
24
|
interface QuestionnaireDefinition {
|
|
25
25
|
/** Gate key. Seen/last-shown/session keys derive from it (`wire_questionnaire_<id>_*`). */
|
|
26
26
|
id: string;
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* @deprecated NOT RENDERED since 2026-07-16. The gate is one-question-per-step, so each
|
|
29
|
+
* step's own question is its heading; a title above it was a second asking-text, repeated
|
|
30
|
+
* on all three steps and briefly drawn twice mid-slide. Malik cut it on device. The field
|
|
31
|
+
* stays in the type because tenants still send it and the server contract is unchanged —
|
|
32
|
+
* dropping it from the wire is a separate, server-side decision.
|
|
33
|
+
*/
|
|
28
34
|
title?: string;
|
|
29
|
-
/** Label for the
|
|
35
|
+
/** Label for the SKIPPABLE opinion step ("what do you think about the app"). */
|
|
30
36
|
opinion_label?: string;
|
|
31
|
-
/** Label for the
|
|
37
|
+
/** Label for the SKIPPABLE "help us improve" step. */
|
|
32
38
|
improve_label?: string;
|
|
33
|
-
/** Label for the
|
|
39
|
+
/** Label for the REQUIRED "suggestions" step — the one answer the user cannot skip. */
|
|
34
40
|
suggestions_label?: string;
|
|
35
41
|
/** Master local switch. Default true. */
|
|
36
42
|
enabled?: boolean;
|
|
@@ -50,13 +56,20 @@ interface QuestionnaireDefinition {
|
|
|
50
56
|
*/
|
|
51
57
|
timeoutFallbackMs?: number | null;
|
|
52
58
|
}
|
|
53
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* The user's three answers.
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ `opinion` is TYPED as always-present because the wire shape says so, but since
|
|
63
|
+
* 2026-07-16 its step is skippable, so "" is a legitimate value. The live server still
|
|
64
|
+
* validates it with minLength=1 and 422s an empty one — a server-side fix this client
|
|
65
|
+
* depends on. See the REQUIRED_STEPS note in steps.ts.
|
|
66
|
+
*/
|
|
54
67
|
interface QuestionnaireAnswers {
|
|
55
|
-
/** The
|
|
68
|
+
/** The "what do you think about the app" free text. Skippable → may be "". */
|
|
56
69
|
opinion: string;
|
|
57
|
-
/** The
|
|
70
|
+
/** The "help us improve" free text. Skippable → may be "" / absent. */
|
|
58
71
|
improve?: string;
|
|
59
|
-
/** The
|
|
72
|
+
/** The "any improvements or feedback" free text. REQUIRED of the user in the gate. */
|
|
60
73
|
suggestions?: string;
|
|
61
74
|
}
|
|
62
75
|
/** Non-PII correlation extras sent with a submission (the `meta` bucket in the POST body). */
|
|
@@ -121,7 +134,13 @@ interface QuestionnaireGateProps {
|
|
|
121
134
|
onShown?: () => void;
|
|
122
135
|
/** Partial theme merged over the active onboarding theme. */
|
|
123
136
|
theme?: Partial<OnboardingTheme>;
|
|
124
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* Whether the WHOLE popup can be dismissed — backdrop tap and Android hardware back.
|
|
139
|
+
* Default true (never a dead end), and the only escape from the required last step, so
|
|
140
|
+
* turning it off traps a user who has nothing to say. That path is what fires
|
|
141
|
+
* `questionnaire_dismissed`; the in-card "Not now" link it used to name is gone.
|
|
142
|
+
* Per-step Skip is separate and is driven by `steps.ts`, not by this flag.
|
|
143
|
+
*/
|
|
125
144
|
dismissible?: boolean;
|
|
126
145
|
}
|
|
127
146
|
/** Options for `useQuestionnaireGate` - the WHEN decision. */
|
|
@@ -161,15 +180,40 @@ interface QuestionnaireGateController {
|
|
|
161
180
|
}
|
|
162
181
|
|
|
163
182
|
/**
|
|
164
|
-
* QuestionnaireGate - the
|
|
183
|
+
* QuestionnaireGate - the multi-step questionnaire popup.
|
|
184
|
+
*
|
|
185
|
+
* ONE question per step. Steps 1-2 are skippable; the LAST step is REQUIRED (Malik's
|
|
186
|
+
* device test 2026-07-16: "i want at least something forced"). The user chooses which
|
|
187
|
+
* thing they tell us, not whether they tell us anything. `steps.ts` owns that rule and
|
|
188
|
+
* every transition as pure functions, unit-tested under node:test without mounting React;
|
|
189
|
+
* this component is a thin renderer over that machine.
|
|
190
|
+
*
|
|
191
|
+
* The CHROME (back icon + step dots) is a static header, deliberately NOT part of the
|
|
192
|
+
* sliding pane - see the four notes below. Only the question, its box and its controls move.
|
|
193
|
+
*
|
|
194
|
+
* - No title. The gate used to render `questionnaire.title` as a heading ON EVERY STEP,
|
|
195
|
+
* directly above the step's own question. Two asking-texts stacked, one of them the same
|
|
196
|
+
* string three times, and mid-slide the outgoing and incoming panes each drew their own
|
|
197
|
+
* copy so it was briefly on screen TWICE. Malik saw it on the last step, where the
|
|
198
|
+
* forced question most needs the focus. The question IS the heading now; it renders once.
|
|
199
|
+
* - No "Question 2 of 3" counter. `StepDots` says it without spending a line next to the
|
|
200
|
+
* question, which is what the user is supposed to be reading.
|
|
201
|
+
* - Back is a top-left icon, not a link in the button stack, and it is simply absent on
|
|
202
|
+
* step 1 rather than present-but-dead.
|
|
203
|
+
* - No "Not now". Per-step Skip is the only in-card opt-out. `questionnaire_dismissed`
|
|
204
|
+
* moved to the modal's dismiss path (backdrop tap / Android back) - see `handleDismissed`.
|
|
205
|
+
*
|
|
206
|
+
* The wire shape is UNCHANGED. `buildQuestionnaireSubmission` still builds the exact same
|
|
207
|
+
* `POST /v1/questionnaires/{id}/responses` body from the same three answers; a skipped
|
|
208
|
+
* step is simply an empty answer, which is what the builder already handled.
|
|
209
|
+
*
|
|
210
|
+
* ⚠️ This gate now REQUIRES the server to accept an empty `answers.opinion` - step 1 is
|
|
211
|
+
* skippable and the live endpoint still 422s a blank opinion, silently (the transport is
|
|
212
|
+
* fire-and-forget). See the REQUIRED_STEPS note in steps.ts. Server fix, not a client one.
|
|
165
213
|
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* Send is disabled ONLY until the opinion box has text; the two optional boxes never gate it.
|
|
170
|
-
* The gate is ALWAYS skippable (a "Not now"/"Skip" link plays the popup exit), so it is never
|
|
171
|
-
* a dead end. On send it builds the contract body and fire-and-forgets it to the Wire server,
|
|
172
|
-
* then shows a warm thank-you until the user taps the backdrop to close.
|
|
214
|
+
* Motion: `ModalPaneHost` slides step→step (and mirrors the slide on Back) and resizes the
|
|
215
|
+
* card; `StepDots` fills; `DoneCheck` plays the submit payoff. All shared, all reduce-motion
|
|
216
|
+
* aware. Haptics are lazy + optional (`haptics/haptics.ts`) and silently absent otherwise.
|
|
173
217
|
*
|
|
174
218
|
* The form NEVER asks for identity (no name / email / contact field): the host already
|
|
175
219
|
* identifies the user via `sessionId` + `meta` (user_id, device_key, session_count), which is
|
|
@@ -187,8 +231,10 @@ declare const useQuestionnaireGate: ({ config: configProp, decision: decisionPro
|
|
|
187
231
|
*/
|
|
188
232
|
declare const decideQuestionnaire: (local: QuestionnaireDecision, decision?: QuestionnaireDecision) => QuestionnaireDecision;
|
|
189
233
|
/**
|
|
190
|
-
* Build the `POST /v1/questionnaires/{id}/responses` body. `opinion` is
|
|
191
|
-
*
|
|
234
|
+
* Build the `POST /v1/questionnaires/{id}/responses` body. `opinion` is always sent as a
|
|
235
|
+
* string (trimmed, possibly "" now that its step is skippable — the live server still
|
|
236
|
+
* rejects that, see steps.ts REQUIRED_STEPS); `improve`/`suggestions` are trimmed and sent
|
|
237
|
+
* as `null` when empty. The
|
|
192
238
|
* `meta` bucket carries the non-PII correlation fields (user_id / device_key / session_count),
|
|
193
239
|
* each defaulting to null. Free text lives ONLY here, never in analytics events.
|
|
194
240
|
*/
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
2
|
import { O as OnboardingTheme } from '../types-BKfpdZzX.js';
|
|
3
|
-
import { C as CoachmarkStorage } from '../types-
|
|
4
|
-
import { W as WireFeatures, a as WireFeaturesConfig } from '../types-
|
|
5
|
-
export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-
|
|
6
|
-
import '../types-
|
|
3
|
+
import { C as CoachmarkStorage } from '../types-BcmagF6K.js';
|
|
4
|
+
import { W as WireFeatures, a as WireFeaturesConfig } from '../types-CKFhyrMu.js';
|
|
5
|
+
export { G as GateRules, a as GateSignals, e as evaluateGate, r as resolveRules } from '../decision-Cau5KmP6.js';
|
|
6
|
+
import '../types-Buj9Lw9t.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The firing verdict - the SAME contract on both sides of the seam. `decideQuestionnaire`
|
|
@@ -24,13 +24,19 @@ interface QuestionnaireDecision {
|
|
|
24
24
|
interface QuestionnaireDefinition {
|
|
25
25
|
/** Gate key. Seen/last-shown/session keys derive from it (`wire_questionnaire_<id>_*`). */
|
|
26
26
|
id: string;
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* @deprecated NOT RENDERED since 2026-07-16. The gate is one-question-per-step, so each
|
|
29
|
+
* step's own question is its heading; a title above it was a second asking-text, repeated
|
|
30
|
+
* on all three steps and briefly drawn twice mid-slide. Malik cut it on device. The field
|
|
31
|
+
* stays in the type because tenants still send it and the server contract is unchanged —
|
|
32
|
+
* dropping it from the wire is a separate, server-side decision.
|
|
33
|
+
*/
|
|
28
34
|
title?: string;
|
|
29
|
-
/** Label for the
|
|
35
|
+
/** Label for the SKIPPABLE opinion step ("what do you think about the app"). */
|
|
30
36
|
opinion_label?: string;
|
|
31
|
-
/** Label for the
|
|
37
|
+
/** Label for the SKIPPABLE "help us improve" step. */
|
|
32
38
|
improve_label?: string;
|
|
33
|
-
/** Label for the
|
|
39
|
+
/** Label for the REQUIRED "suggestions" step — the one answer the user cannot skip. */
|
|
34
40
|
suggestions_label?: string;
|
|
35
41
|
/** Master local switch. Default true. */
|
|
36
42
|
enabled?: boolean;
|
|
@@ -50,13 +56,20 @@ interface QuestionnaireDefinition {
|
|
|
50
56
|
*/
|
|
51
57
|
timeoutFallbackMs?: number | null;
|
|
52
58
|
}
|
|
53
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* The user's three answers.
|
|
61
|
+
*
|
|
62
|
+
* ⚠️ `opinion` is TYPED as always-present because the wire shape says so, but since
|
|
63
|
+
* 2026-07-16 its step is skippable, so "" is a legitimate value. The live server still
|
|
64
|
+
* validates it with minLength=1 and 422s an empty one — a server-side fix this client
|
|
65
|
+
* depends on. See the REQUIRED_STEPS note in steps.ts.
|
|
66
|
+
*/
|
|
54
67
|
interface QuestionnaireAnswers {
|
|
55
|
-
/** The
|
|
68
|
+
/** The "what do you think about the app" free text. Skippable → may be "". */
|
|
56
69
|
opinion: string;
|
|
57
|
-
/** The
|
|
70
|
+
/** The "help us improve" free text. Skippable → may be "" / absent. */
|
|
58
71
|
improve?: string;
|
|
59
|
-
/** The
|
|
72
|
+
/** The "any improvements or feedback" free text. REQUIRED of the user in the gate. */
|
|
60
73
|
suggestions?: string;
|
|
61
74
|
}
|
|
62
75
|
/** Non-PII correlation extras sent with a submission (the `meta` bucket in the POST body). */
|
|
@@ -121,7 +134,13 @@ interface QuestionnaireGateProps {
|
|
|
121
134
|
onShown?: () => void;
|
|
122
135
|
/** Partial theme merged over the active onboarding theme. */
|
|
123
136
|
theme?: Partial<OnboardingTheme>;
|
|
124
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* Whether the WHOLE popup can be dismissed — backdrop tap and Android hardware back.
|
|
139
|
+
* Default true (never a dead end), and the only escape from the required last step, so
|
|
140
|
+
* turning it off traps a user who has nothing to say. That path is what fires
|
|
141
|
+
* `questionnaire_dismissed`; the in-card "Not now" link it used to name is gone.
|
|
142
|
+
* Per-step Skip is separate and is driven by `steps.ts`, not by this flag.
|
|
143
|
+
*/
|
|
125
144
|
dismissible?: boolean;
|
|
126
145
|
}
|
|
127
146
|
/** Options for `useQuestionnaireGate` - the WHEN decision. */
|
|
@@ -161,15 +180,40 @@ interface QuestionnaireGateController {
|
|
|
161
180
|
}
|
|
162
181
|
|
|
163
182
|
/**
|
|
164
|
-
* QuestionnaireGate - the
|
|
183
|
+
* QuestionnaireGate - the multi-step questionnaire popup.
|
|
184
|
+
*
|
|
185
|
+
* ONE question per step. Steps 1-2 are skippable; the LAST step is REQUIRED (Malik's
|
|
186
|
+
* device test 2026-07-16: "i want at least something forced"). The user chooses which
|
|
187
|
+
* thing they tell us, not whether they tell us anything. `steps.ts` owns that rule and
|
|
188
|
+
* every transition as pure functions, unit-tested under node:test without mounting React;
|
|
189
|
+
* this component is a thin renderer over that machine.
|
|
190
|
+
*
|
|
191
|
+
* The CHROME (back icon + step dots) is a static header, deliberately NOT part of the
|
|
192
|
+
* sliding pane - see the four notes below. Only the question, its box and its controls move.
|
|
193
|
+
*
|
|
194
|
+
* - No title. The gate used to render `questionnaire.title` as a heading ON EVERY STEP,
|
|
195
|
+
* directly above the step's own question. Two asking-texts stacked, one of them the same
|
|
196
|
+
* string three times, and mid-slide the outgoing and incoming panes each drew their own
|
|
197
|
+
* copy so it was briefly on screen TWICE. Malik saw it on the last step, where the
|
|
198
|
+
* forced question most needs the focus. The question IS the heading now; it renders once.
|
|
199
|
+
* - No "Question 2 of 3" counter. `StepDots` says it without spending a line next to the
|
|
200
|
+
* question, which is what the user is supposed to be reading.
|
|
201
|
+
* - Back is a top-left icon, not a link in the button stack, and it is simply absent on
|
|
202
|
+
* step 1 rather than present-but-dead.
|
|
203
|
+
* - No "Not now". Per-step Skip is the only in-card opt-out. `questionnaire_dismissed`
|
|
204
|
+
* moved to the modal's dismiss path (backdrop tap / Android back) - see `handleDismissed`.
|
|
205
|
+
*
|
|
206
|
+
* The wire shape is UNCHANGED. `buildQuestionnaireSubmission` still builds the exact same
|
|
207
|
+
* `POST /v1/questionnaires/{id}/responses` body from the same three answers; a skipped
|
|
208
|
+
* step is simply an empty answer, which is what the builder already handled.
|
|
209
|
+
*
|
|
210
|
+
* ⚠️ This gate now REQUIRES the server to accept an empty `answers.opinion` - step 1 is
|
|
211
|
+
* skippable and the live endpoint still 422s a blank opinion, silently (the transport is
|
|
212
|
+
* fire-and-forget). See the REQUIRED_STEPS note in steps.ts. Server fix, not a client one.
|
|
165
213
|
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* Send is disabled ONLY until the opinion box has text; the two optional boxes never gate it.
|
|
170
|
-
* The gate is ALWAYS skippable (a "Not now"/"Skip" link plays the popup exit), so it is never
|
|
171
|
-
* a dead end. On send it builds the contract body and fire-and-forgets it to the Wire server,
|
|
172
|
-
* then shows a warm thank-you until the user taps the backdrop to close.
|
|
214
|
+
* Motion: `ModalPaneHost` slides step→step (and mirrors the slide on Back) and resizes the
|
|
215
|
+
* card; `StepDots` fills; `DoneCheck` plays the submit payoff. All shared, all reduce-motion
|
|
216
|
+
* aware. Haptics are lazy + optional (`haptics/haptics.ts`) and silently absent otherwise.
|
|
173
217
|
*
|
|
174
218
|
* The form NEVER asks for identity (no name / email / contact field): the host already
|
|
175
219
|
* identifies the user via `sessionId` + `meta` (user_id, device_key, session_count), which is
|
|
@@ -187,8 +231,10 @@ declare const useQuestionnaireGate: ({ config: configProp, decision: decisionPro
|
|
|
187
231
|
*/
|
|
188
232
|
declare const decideQuestionnaire: (local: QuestionnaireDecision, decision?: QuestionnaireDecision) => QuestionnaireDecision;
|
|
189
233
|
/**
|
|
190
|
-
* Build the `POST /v1/questionnaires/{id}/responses` body. `opinion` is
|
|
191
|
-
*
|
|
234
|
+
* Build the `POST /v1/questionnaires/{id}/responses` body. `opinion` is always sent as a
|
|
235
|
+
* string (trimmed, possibly "" now that its step is skippable — the live server still
|
|
236
|
+
* rejects that, see steps.ts REQUIRED_STEPS); `improve`/`suggestions` are trimmed and sent
|
|
237
|
+
* as `null` when empty. The
|
|
192
238
|
* `meta` bucket carries the non-PII correlation fields (user_id / device_key / session_count),
|
|
193
239
|
* each defaulting to null. Free text lives ONLY here, never in analytics events.
|
|
194
240
|
*/
|