@nodii/onboarding 0.0.1 → 0.1.0-dev.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/dist/chunk-34BQX2KR.js +164 -0
- package/dist/chunk-34BQX2KR.js.map +1 -0
- package/dist/chunk-4SWOVHZ2.js +434 -0
- package/dist/chunk-4SWOVHZ2.js.map +1 -0
- package/dist/chunk-7NS7ENJV.js +232 -0
- package/dist/chunk-7NS7ENJV.js.map +1 -0
- package/dist/chunk-AFCJLUPK.js +92 -0
- package/dist/chunk-AFCJLUPK.js.map +1 -0
- package/dist/chunk-AW7W3HAC.js +154 -0
- package/dist/chunk-AW7W3HAC.js.map +1 -0
- package/dist/chunk-BIFANV7M.js +22 -0
- package/dist/chunk-BIFANV7M.js.map +1 -0
- package/dist/chunk-BQCTDU5V.js +327 -0
- package/dist/chunk-BQCTDU5V.js.map +1 -0
- package/dist/chunk-JFIONONR.js +3 -0
- package/dist/chunk-JFIONONR.js.map +1 -0
- package/dist/chunk-SWMIIUXR.js +1162 -0
- package/dist/chunk-SWMIIUXR.js.map +1 -0
- package/dist/chunk-VH6FWDWI.js +3 -0
- package/dist/chunk-VH6FWDWI.js.map +1 -0
- package/dist/chunk-Z4PA6C2Z.js +3 -0
- package/dist/chunk-Z4PA6C2Z.js.map +1 -0
- package/dist/chunk-ZDY2I6KY.js +3 -0
- package/dist/chunk-ZDY2I6KY.js.map +1 -0
- package/dist/dynamic/index.d.ts +184 -0
- package/dist/dynamic/index.js +4 -0
- package/dist/dynamic/index.js.map +1 -0
- package/dist/form/index.d.ts +64 -0
- package/dist/form/index.js +5 -0
- package/dist/form/index.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -0
- package/dist/model-IEyDI54w.d.ts +487 -0
- package/dist/recaptcha/index.d.ts +102 -0
- package/dist/recaptcha/index.js +4 -0
- package/dist/recaptcha/index.js.map +1 -0
- package/dist/schema-TfyBU6JW.d.ts +107 -0
- package/dist/signup-client-Bl6eUrxR.d.ts +259 -0
- package/dist/spec/index.d.ts +88 -0
- package/dist/spec/index.js +4 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/submit/index.d.ts +106 -0
- package/dist/submit/index.js +6 -0
- package/dist/submit/index.js.map +1 -0
- package/dist/widget/index.d.ts +219 -0
- package/dist/widget/index.js +10 -0
- package/dist/widget/index.js.map +1 -0
- package/package.json +77 -6
- package/README.md +0 -5
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Contact-form Zod schema — mirrors the LOCKED hub REST contract exactly:
|
|
5
|
+
* POST /api/v1/public/onboarding/leads
|
|
6
|
+
* Schema: PublicOnboardingLeadsRequest (hub id 8686dd33)
|
|
7
|
+
*
|
|
8
|
+
* Constraints (per hub JSON Schema):
|
|
9
|
+
* name — string, 1-200 chars, required
|
|
10
|
+
* email — email format, required
|
|
11
|
+
* phone — string, optional (no server-side constraint beyond string)
|
|
12
|
+
* message — string, ≤4000 chars, optional
|
|
13
|
+
* botToken — string, required (reCAPTCHA token, D537)
|
|
14
|
+
*
|
|
15
|
+
* additionalProperties: false
|
|
16
|
+
*
|
|
17
|
+
* The schema intentionally does NOT include botToken in the public-facing
|
|
18
|
+
* ContactFormValues type — that field is injected by the submit client right
|
|
19
|
+
* before the POST (the widget/form never exposes it to the user).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The user-visible contact form fields. Validated client-side for UX.
|
|
24
|
+
* Server re-validates authoritatively (D540 §2).
|
|
25
|
+
*/
|
|
26
|
+
declare const contactFormSchema: z.ZodObject<{
|
|
27
|
+
name: z.ZodString;
|
|
28
|
+
email: z.ZodString;
|
|
29
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
30
|
+
message: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, "strip", z.ZodTypeAny, {
|
|
32
|
+
name: string;
|
|
33
|
+
email: string;
|
|
34
|
+
phone?: string | undefined;
|
|
35
|
+
message?: string | undefined;
|
|
36
|
+
}, {
|
|
37
|
+
name: string;
|
|
38
|
+
email: string;
|
|
39
|
+
phone?: string | undefined;
|
|
40
|
+
message?: string | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
type ContactFormValues = z.infer<typeof contactFormSchema>;
|
|
43
|
+
/**
|
|
44
|
+
* The full wire payload — contactFormSchema + botToken.
|
|
45
|
+
*
|
|
46
|
+
* STRICT mode: unknown keys are REJECTED (not stripped), mirroring the
|
|
47
|
+
* server's `additionalProperties: false`. `submitLead` runs every outgoing
|
|
48
|
+
* payload through this schema before the POST — an extra key never reaches
|
|
49
|
+
* the wire; it fails fast client-side with OnboardingValidationError.
|
|
50
|
+
*/
|
|
51
|
+
declare const leadsWireSchema: z.ZodObject<{
|
|
52
|
+
name: z.ZodString;
|
|
53
|
+
email: z.ZodString;
|
|
54
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
55
|
+
message: z.ZodOptional<z.ZodString>;
|
|
56
|
+
} & {
|
|
57
|
+
botToken: z.ZodString;
|
|
58
|
+
}, "strict", z.ZodTypeAny, {
|
|
59
|
+
name: string;
|
|
60
|
+
email: string;
|
|
61
|
+
botToken: string;
|
|
62
|
+
phone?: string | undefined;
|
|
63
|
+
message?: string | undefined;
|
|
64
|
+
}, {
|
|
65
|
+
name: string;
|
|
66
|
+
email: string;
|
|
67
|
+
botToken: string;
|
|
68
|
+
phone?: string | undefined;
|
|
69
|
+
message?: string | undefined;
|
|
70
|
+
}>;
|
|
71
|
+
type LeadsWirePayload = z.infer<typeof leadsWireSchema>;
|
|
72
|
+
/**
|
|
73
|
+
* Validate user-visible form values (no botToken required here).
|
|
74
|
+
* Returns a Zod SafeParseReturnType (inferred).
|
|
75
|
+
*/
|
|
76
|
+
declare function validateContactForm(values: unknown): z.SafeParseReturnType<{
|
|
77
|
+
name: string;
|
|
78
|
+
email: string;
|
|
79
|
+
phone?: string | undefined;
|
|
80
|
+
message?: string | undefined;
|
|
81
|
+
}, {
|
|
82
|
+
name: string;
|
|
83
|
+
email: string;
|
|
84
|
+
phone?: string | undefined;
|
|
85
|
+
message?: string | undefined;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Validate the full wire payload (including botToken) before submission.
|
|
89
|
+
* STRICT: unknown keys are rejected, matching additionalProperties:false.
|
|
90
|
+
* This is the exact validation `submitLead` applies on the wire path.
|
|
91
|
+
* Returns a Zod SafeParseReturnType (inferred).
|
|
92
|
+
*/
|
|
93
|
+
declare function validateLeadsPayload(payload: unknown): z.SafeParseReturnType<{
|
|
94
|
+
name: string;
|
|
95
|
+
email: string;
|
|
96
|
+
botToken: string;
|
|
97
|
+
phone?: string | undefined;
|
|
98
|
+
message?: string | undefined;
|
|
99
|
+
}, {
|
|
100
|
+
name: string;
|
|
101
|
+
email: string;
|
|
102
|
+
botToken: string;
|
|
103
|
+
phone?: string | undefined;
|
|
104
|
+
message?: string | undefined;
|
|
105
|
+
}>;
|
|
106
|
+
|
|
107
|
+
export { type ContactFormValues as C, type LeadsWirePayload as L, validateLeadsPayload as a, contactFormSchema as c, leadsWireSchema as l, validateContactForm as v };
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
import { T as TerminalStage } from './model-IEyDI54w.js';
|
|
3
|
+
import { C as ContactFormValues } from './schema-TfyBU6JW.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Submit client for POST /api/v1/public/onboarding/leads.
|
|
7
|
+
*
|
|
8
|
+
* Contract per D540 + hub REST interface 8686dd33:
|
|
9
|
+
* - Idempotency-Key header REQUIRED (uuid v4, generated ONCE per logical
|
|
10
|
+
* submission, REUSED on retries — same key = exactly-once delivery).
|
|
11
|
+
* - Outgoing payload validated through leadsWireSchema (STRICT — unknown
|
|
12
|
+
* keys rejected, matching additionalProperties:false) BEFORE any fetch.
|
|
13
|
+
* - botToken in request body (D537).
|
|
14
|
+
* - Response: { accepted: true } on 200/202 (empty/non-JSON 2xx body is
|
|
15
|
+
* treated as acceptance; a JSON body that does not confirm acceptance
|
|
16
|
+
* throws OnboardingServerError — see parseSuccessBody).
|
|
17
|
+
* - 403 bot_challenge_failed → throw OnboardingBotChallengeError (no retry)
|
|
18
|
+
* - 409 spec_stale (D540) → throw OnboardingSpecStaleError (no retry)
|
|
19
|
+
* - 422 → throw OnboardingValidationError (no retry)
|
|
20
|
+
* - 429 → throw OnboardingRateLimitError (no auto-retry)
|
|
21
|
+
* - 5xx → retry with SAME idempotency key, capped backoff
|
|
22
|
+
* - network error → retry with SAME idempotency key, capped backoff
|
|
23
|
+
*
|
|
24
|
+
* Max retries: 3 attempts total (1 initial + 2 retries).
|
|
25
|
+
* Backoff: 1s, 2s (capped at 2 retries).
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A bot token, or a provider that mints a FRESH one per attempt.
|
|
30
|
+
*
|
|
31
|
+
* reCAPTCHA tokens are SINGLE-USE — the server consumes them at siteverify.
|
|
32
|
+
* If a 5xx happens AFTER the token was consumed, resending the same token on
|
|
33
|
+
* retry gets 403. Pass a provider function to mint a fresh token per attempt;
|
|
34
|
+
* a bare string is back-compat but the caller then OWNS that risk.
|
|
35
|
+
*/
|
|
36
|
+
type BotTokenSource = string | (() => string | Promise<string>);
|
|
37
|
+
declare function resolveBotToken(source: BotTokenSource): Promise<string>;
|
|
38
|
+
interface LeadsSubmitOptions {
|
|
39
|
+
baseUrl: string;
|
|
40
|
+
/**
|
|
41
|
+
* reCAPTCHA token (D537), or a provider called ONCE PER ATTEMPT to mint a
|
|
42
|
+
* fresh token (recommended — tokens are single-use; a fixed string on a
|
|
43
|
+
* retried request risks 403 after the first attempt consumed it).
|
|
44
|
+
*/
|
|
45
|
+
botToken: BotTokenSource;
|
|
46
|
+
/**
|
|
47
|
+
* Stable idempotency key for this submission. Generate ONCE with
|
|
48
|
+
* `generateIdempotencyKey()` and pass the same key for retries.
|
|
49
|
+
* The server chains this key through to D538 for exactly-once delivery.
|
|
50
|
+
*/
|
|
51
|
+
idempotencyKey: string;
|
|
52
|
+
/** Optional custom fetch implementation (defaults to global fetch). */
|
|
53
|
+
fetch?: typeof globalThis.fetch;
|
|
54
|
+
/**
|
|
55
|
+
* Per-attempt request timeout in ms (default 15s). A stalled intake aborts
|
|
56
|
+
* with OnboardingNetworkError so the widget re-enables instead of hanging.
|
|
57
|
+
*/
|
|
58
|
+
timeoutMs?: number;
|
|
59
|
+
/** Optional onAttempt callback for observability (attempt number, 1-based). */
|
|
60
|
+
onAttempt?: (attempt: number) => void;
|
|
61
|
+
}
|
|
62
|
+
interface LeadsSubmitResult {
|
|
63
|
+
accepted: true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generate a stable idempotency key for one logical submission.
|
|
67
|
+
* Uses the Web Crypto API (available in all modern browsers + Bun/Node >= 19).
|
|
68
|
+
* Call ONCE per user submission, pass the SAME key on retries.
|
|
69
|
+
*/
|
|
70
|
+
declare function generateIdempotencyKey(): string;
|
|
71
|
+
/**
|
|
72
|
+
* Compute a stable fingerprint of the outgoing lead payload, EXCLUDING
|
|
73
|
+
* botToken (which is fresh per attempt by design).
|
|
74
|
+
*
|
|
75
|
+
* The widget uses this to decide whether a resubmission is a RETRY of the
|
|
76
|
+
* same logical submission (same fingerprint → reuse the Idempotency-Key)
|
|
77
|
+
* or a NEW logical submission (fingerprint changed because the user edited
|
|
78
|
+
* fields → mint a NEW key). This mirrors the server's D538 payload-match
|
|
79
|
+
* guard: same key + different payload is INVALID_ARGUMENT server-side.
|
|
80
|
+
*
|
|
81
|
+
* FNV-1a 32-bit over a stable JSON serialization of [name, email, phone,
|
|
82
|
+
* message]. Collision risk is irrelevant here — a collision only means an
|
|
83
|
+
* unnecessary key reuse across two submissions from the same browser tab.
|
|
84
|
+
*/
|
|
85
|
+
declare function computePayloadFingerprint(values: ContactFormValues): string;
|
|
86
|
+
/**
|
|
87
|
+
* Submit a contact-form lead to the onboarding intake.
|
|
88
|
+
*
|
|
89
|
+
* The outgoing payload is validated through leadsWireSchema in STRICT mode
|
|
90
|
+
* before any network I/O — unknown keys are rejected client-side, exactly
|
|
91
|
+
* mirroring the server's additionalProperties:false.
|
|
92
|
+
*
|
|
93
|
+
* Handles retry semantics: 5xx and network errors are retried up to
|
|
94
|
+
* MAX_ATTEMPTS total, always with the SAME idempotencyKey to guarantee
|
|
95
|
+
* exactly-once server-side processing (D538 idempotency chain).
|
|
96
|
+
*
|
|
97
|
+
* 403, 409, 422 and 429 are NOT retried — caller handles them.
|
|
98
|
+
*
|
|
99
|
+
* @throws {OnboardingValidationError} if the payload fails the strict wire
|
|
100
|
+
* schema (unknown keys, constraint violations) — thrown BEFORE any fetch
|
|
101
|
+
* @throws {OnboardingBotChallengeError} on 403, or if the bot-token provider
|
|
102
|
+
* throws (reCAPTCHA unreachable) on any attempt
|
|
103
|
+
* @throws {OnboardingConflictError} on 409 (leads has no spec_stale concept)
|
|
104
|
+
* @throws {OnboardingRateLimitError} on 429
|
|
105
|
+
* @throws {OnboardingServerError} on 5xx after all retries exhausted, or on
|
|
106
|
+
* a 2xx whose JSON body does not confirm acceptance
|
|
107
|
+
* @throws {OnboardingNetworkError} on network failure OR timeout after all
|
|
108
|
+
* retries exhausted
|
|
109
|
+
* @throws {OnboardingValidationError} on 422 (server-side re-validation)
|
|
110
|
+
*/
|
|
111
|
+
declare function submitLead(values: ContactFormValues, options: LeadsSubmitOptions): Promise<LeadsSubmitResult>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Submit client for POST /api/v1/public/onboarding/submit (D540 §2).
|
|
115
|
+
*
|
|
116
|
+
* Contract per the LOCKED hub REST interface (PublicOnboardingSubmitRequest):
|
|
117
|
+
* - Body: { specVersion, answers, selectedServices?, botToken,
|
|
118
|
+
* consent:{tosAccepted:true, privacyAccepted:true},
|
|
119
|
+
* credentials:{email, password(12-256)} }
|
|
120
|
+
* additionalProperties: false — validated STRICTLY client-side before
|
|
121
|
+
* any fetch (unknown keys are rejected, not stripped).
|
|
122
|
+
* - Idempotency-Key header REQUIRED (same D538 discipline as leads:
|
|
123
|
+
* stable across retries of the SAME payload; the widget mints a new
|
|
124
|
+
* key when the payload fingerprint changes).
|
|
125
|
+
* - specVersion policy is reject-stale: 409 → OnboardingSpecStaleError
|
|
126
|
+
* carrying the server's current version. The CALLER refetches the spec
|
|
127
|
+
* and surfaces re-validation to the user — NEVER silent auto-resubmit.
|
|
128
|
+
* - Response: { accepted:true, terminalStage, verificationEmailSent? }.
|
|
129
|
+
*
|
|
130
|
+
* Success-body rule for /submit (DIFFERENT from /leads, deliberately):
|
|
131
|
+
* the response carries REQUIRED routing data (terminalStage decides what
|
|
132
|
+
* the UI shows next), so a 2xx with an empty/unparseable/garbage body is
|
|
133
|
+
* an OnboardingServerError — the SDK will not fabricate a terminal stage.
|
|
134
|
+
* (/leads tolerates body-less 2xx because its only signal IS the status.)
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* STRICT wire schema — mirrors PublicOnboardingSubmitRequest exactly
|
|
139
|
+
* (additionalProperties: false; consent booleans are const-true; password
|
|
140
|
+
* length 12-256 per the locked schema).
|
|
141
|
+
*/
|
|
142
|
+
declare const signupWireSchema: z.ZodObject<{
|
|
143
|
+
specVersion: z.ZodString;
|
|
144
|
+
answers: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
145
|
+
selectedServices: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
146
|
+
botToken: z.ZodString;
|
|
147
|
+
consent: z.ZodObject<{
|
|
148
|
+
tosAccepted: z.ZodLiteral<true>;
|
|
149
|
+
privacyAccepted: z.ZodLiteral<true>;
|
|
150
|
+
}, "strict", z.ZodTypeAny, {
|
|
151
|
+
tosAccepted: true;
|
|
152
|
+
privacyAccepted: true;
|
|
153
|
+
}, {
|
|
154
|
+
tosAccepted: true;
|
|
155
|
+
privacyAccepted: true;
|
|
156
|
+
}>;
|
|
157
|
+
credentials: z.ZodObject<{
|
|
158
|
+
email: z.ZodString;
|
|
159
|
+
password: z.ZodString;
|
|
160
|
+
}, "strict", z.ZodTypeAny, {
|
|
161
|
+
email: string;
|
|
162
|
+
password: string;
|
|
163
|
+
}, {
|
|
164
|
+
email: string;
|
|
165
|
+
password: string;
|
|
166
|
+
}>;
|
|
167
|
+
}, "strict", z.ZodTypeAny, {
|
|
168
|
+
botToken: string;
|
|
169
|
+
specVersion: string;
|
|
170
|
+
credentials: {
|
|
171
|
+
email: string;
|
|
172
|
+
password: string;
|
|
173
|
+
};
|
|
174
|
+
answers: Record<string, unknown>;
|
|
175
|
+
consent: {
|
|
176
|
+
tosAccepted: true;
|
|
177
|
+
privacyAccepted: true;
|
|
178
|
+
};
|
|
179
|
+
selectedServices?: string[] | undefined;
|
|
180
|
+
}, {
|
|
181
|
+
botToken: string;
|
|
182
|
+
specVersion: string;
|
|
183
|
+
credentials: {
|
|
184
|
+
email: string;
|
|
185
|
+
password: string;
|
|
186
|
+
};
|
|
187
|
+
answers: Record<string, unknown>;
|
|
188
|
+
consent: {
|
|
189
|
+
tosAccepted: true;
|
|
190
|
+
privacyAccepted: true;
|
|
191
|
+
};
|
|
192
|
+
selectedServices?: string[] | undefined;
|
|
193
|
+
}>;
|
|
194
|
+
type SignupWirePayload = z.infer<typeof signupWireSchema>;
|
|
195
|
+
/** The payload the caller assembles (botToken attached by the transport). */
|
|
196
|
+
interface SignupSubmitBody {
|
|
197
|
+
specVersion: string;
|
|
198
|
+
answers: Record<string, unknown>;
|
|
199
|
+
selectedServices?: string[];
|
|
200
|
+
consent: {
|
|
201
|
+
tosAccepted: true;
|
|
202
|
+
privacyAccepted: true;
|
|
203
|
+
};
|
|
204
|
+
credentials: {
|
|
205
|
+
email: string;
|
|
206
|
+
password: string;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
interface SignupSubmitOptions {
|
|
210
|
+
baseUrl: string;
|
|
211
|
+
/**
|
|
212
|
+
* reCAPTCHA token (D537), or a provider called ONCE PER ATTEMPT to mint a
|
|
213
|
+
* fresh token. Tokens are single-use (consumed at siteverify), so a fixed
|
|
214
|
+
* string on a retried request risks 403 after the first attempt consumed
|
|
215
|
+
* it — pass a provider for retry-safe recovery.
|
|
216
|
+
*/
|
|
217
|
+
botToken: BotTokenSource;
|
|
218
|
+
/** Stable idempotency key — same discipline as submitLead. */
|
|
219
|
+
idempotencyKey: string;
|
|
220
|
+
fetch?: typeof globalThis.fetch;
|
|
221
|
+
/**
|
|
222
|
+
* Per-attempt request timeout in ms (default 15s). A stalled intake aborts
|
|
223
|
+
* with OnboardingNetworkError so the widget re-enables instead of hanging.
|
|
224
|
+
*/
|
|
225
|
+
timeoutMs?: number;
|
|
226
|
+
onAttempt?: (attempt: number) => void;
|
|
227
|
+
}
|
|
228
|
+
interface SignupSubmitResult {
|
|
229
|
+
accepted: true;
|
|
230
|
+
/** Stage the existing engine landed the applicant at (D540 §2). */
|
|
231
|
+
terminalStage: TerminalStage;
|
|
232
|
+
verificationEmailSent?: boolean;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Stable fingerprint of a signup submission, EXCLUDING botToken (fresh per
|
|
236
|
+
* attempt by design). Same role as computePayloadFingerprint for leads:
|
|
237
|
+
* same fingerprint ⇒ retry (reuse the Idempotency-Key); changed
|
|
238
|
+
* fingerprint ⇒ new logical submission (mint a new key) — mirroring the
|
|
239
|
+
* server's D538 payload-match guard.
|
|
240
|
+
*/
|
|
241
|
+
declare function computeSignupFingerprint(body: SignupSubmitBody): string;
|
|
242
|
+
/**
|
|
243
|
+
* Submit a full signup to the onboarding intake.
|
|
244
|
+
*
|
|
245
|
+
* @throws {OnboardingValidationError} strict wire-schema failure — BEFORE any fetch
|
|
246
|
+
* @throws {OnboardingBotChallengeError} on 403, or if the bot-token provider
|
|
247
|
+
* throws (reCAPTCHA unreachable) on any attempt
|
|
248
|
+
* @throws {OnboardingSpecStaleError} on 409 with code:"spec_stale" (caller
|
|
249
|
+
* refetches spec); carries the server's currentSpecVersion
|
|
250
|
+
* @throws {OnboardingConflictError} on a 409 that is NOT spec_stale
|
|
251
|
+
* @throws {OnboardingRateLimitError} on 429
|
|
252
|
+
* @throws {OnboardingValidationError} on 422 (server re-validation)
|
|
253
|
+
* @throws {OnboardingServerError} on 5xx after retries, or a 2xx without
|
|
254
|
+
* the required {accepted:true, terminalStage} body
|
|
255
|
+
* @throws {OnboardingNetworkError} on network failure OR timeout after retries
|
|
256
|
+
*/
|
|
257
|
+
declare function submitSignup(body: SignupSubmitBody, options: SignupSubmitOptions): Promise<SignupSubmitResult>;
|
|
258
|
+
|
|
259
|
+
export { type BotTokenSource as B, type LeadsSubmitOptions as L, type SignupSubmitBody as S, type LeadsSubmitResult as a, type SignupSubmitOptions as b, type SignupSubmitResult as c, type SignupWirePayload as d, computePayloadFingerprint as e, computeSignupFingerprint as f, generateIdempotencyKey as g, submitLead as h, submitSignup as i, resolveBotToken as r, signupWireSchema as s };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { a as OnboardingSpec } from '../model-IEyDI54w.js';
|
|
2
|
+
export { F as FIELD_KEY_PATTERN, O as OnboarderTier, P as PiiClass, S as SpecField, b as SpecStage, c as SpecStep, T as TerminalStage, o as onboardingSpecSchema, s as specFieldSchema, d as specStepSchema, v as validateOnboardingSpec } from '../model-IEyDI54w.js';
|
|
3
|
+
import 'zod/v3';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Config-fetch client for GET /api/v1/public/onboarding/spec (D540 §1/§3).
|
|
7
|
+
*
|
|
8
|
+
* - The onboarder is derived SERVER-side from the request Host (D536) —
|
|
9
|
+
* it is NOT sent by the client. The `onboarder` value here is purely the
|
|
10
|
+
* CLIENT-side cache key (D540 §3: "cache key (onboarder, specVersion)").
|
|
11
|
+
* - The spec response is validated against the LOCKED D540 shape before
|
|
12
|
+
* it is returned; a malformed spec throws OnboardingSpecInvalidError.
|
|
13
|
+
* - Cache semantics: every successful fetch is stored under
|
|
14
|
+
* (onboarder, specVersion) and as the onboarder's "latest". The versioned
|
|
15
|
+
* entries let the 409 spec_stale flow diff the previously-served version
|
|
16
|
+
* against the refetched one (see `diffSpecFields` + the signup widget's
|
|
17
|
+
* handleSpecStale, which reads the cached prior version before refetching).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* In-memory spec cache keyed by (onboarder, specVersion), with a "latest"
|
|
22
|
+
* pointer per onboarder. Purely client-side; no TTL — the reject-stale
|
|
23
|
+
* policy (409 spec_stale on submit) is the authoritative staleness signal,
|
|
24
|
+
* and a refetch overwrites "latest".
|
|
25
|
+
*/
|
|
26
|
+
declare class OnboardingSpecCache {
|
|
27
|
+
private readonly byVersion;
|
|
28
|
+
private readonly latest;
|
|
29
|
+
/**
|
|
30
|
+
* Collision-proof composite key. Uses JSON.stringify of the tuple so an
|
|
31
|
+
* onboarder or version containing the delimiter can never alias another
|
|
32
|
+
* entry — and, critically, contains NO control characters (an earlier
|
|
33
|
+
* NUL-separator made git treat this whole file as binary/undiffable).
|
|
34
|
+
*/
|
|
35
|
+
private static versionKey;
|
|
36
|
+
get(onboarder: string, specVersion: string): OnboardingSpec | undefined;
|
|
37
|
+
getLatest(onboarder: string): OnboardingSpec | undefined;
|
|
38
|
+
set(onboarder: string, spec: OnboardingSpec): void;
|
|
39
|
+
clear(): void;
|
|
40
|
+
}
|
|
41
|
+
/** Module-level default cache (one per page). Injectable for tests/apps. */
|
|
42
|
+
declare const defaultSpecCache: OnboardingSpecCache;
|
|
43
|
+
/**
|
|
44
|
+
* Diff two spec versions' signup field sets — used by the 409 spec_stale
|
|
45
|
+
* flow to tell the user WHAT changed. Compares by field key across all
|
|
46
|
+
* signup steps.
|
|
47
|
+
*/
|
|
48
|
+
interface SpecFieldDiff {
|
|
49
|
+
added: string[];
|
|
50
|
+
removed: string[];
|
|
51
|
+
changed: string[];
|
|
52
|
+
}
|
|
53
|
+
declare function diffSpecFields(prev: OnboardingSpec, next: OnboardingSpec): SpecFieldDiff;
|
|
54
|
+
interface SpecFetchOptions {
|
|
55
|
+
baseUrl: string;
|
|
56
|
+
/**
|
|
57
|
+
* Client-side cache key ONLY (never transmitted; trust is host-derived
|
|
58
|
+
* per D536). Use the onboarder slug/id your embed is configured with.
|
|
59
|
+
*/
|
|
60
|
+
onboarder: string;
|
|
61
|
+
/** Custom fetch implementation (defaults to globalThis.fetch). */
|
|
62
|
+
fetch?: typeof globalThis.fetch;
|
|
63
|
+
/** Cache to read/write (defaults to the module-level cache). */
|
|
64
|
+
cache?: OnboardingSpecCache;
|
|
65
|
+
/**
|
|
66
|
+
* Request timeout in ms (default 15s). A stalled intake aborts with
|
|
67
|
+
* OnboardingNetworkError so the boot doesn't hang on "Loading signup form…".
|
|
68
|
+
*/
|
|
69
|
+
timeoutMs?: number;
|
|
70
|
+
/**
|
|
71
|
+
* When true, return the cached "latest" for this onboarder if present
|
|
72
|
+
* WITHOUT a network round-trip. Default false (spec fetches are cheap
|
|
73
|
+
* and the server bumps specVersion on any change). The signup widget's
|
|
74
|
+
* boot passes preferCached:true so a remount reuses the loaded spec.
|
|
75
|
+
*/
|
|
76
|
+
preferCached?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Fetch (and validate, and cache) the onboarding spec.
|
|
80
|
+
*
|
|
81
|
+
* @throws {OnboardingSpecInvalidError} response does not match D540 §1
|
|
82
|
+
* @throws {OnboardingRateLimitError} on 429
|
|
83
|
+
* @throws {OnboardingServerError} on any other non-2xx status
|
|
84
|
+
* @throws {OnboardingNetworkError} on network failure OR timeout
|
|
85
|
+
*/
|
|
86
|
+
declare function fetchOnboardingSpec(options: SpecFetchOptions): Promise<OnboardingSpec>;
|
|
87
|
+
|
|
88
|
+
export { OnboardingSpec, OnboardingSpecCache, type SpecFetchOptions, type SpecFieldDiff, defaultSpecCache, diffSpecFields, fetchOnboardingSpec };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FIELD_KEY_PATTERN, OnboardingSpecCache, defaultSpecCache, diffSpecFields, fetchOnboardingSpec, onboardingSpecSchema, specFieldSchema, specStepSchema, validateOnboardingSpec } from '../chunk-34BQX2KR.js';
|
|
2
|
+
import '../chunk-AW7W3HAC.js';
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export { B as BotTokenSource, L as LeadsSubmitOptions, a as LeadsSubmitResult, S as SignupSubmitBody, b as SignupSubmitOptions, c as SignupSubmitResult, d as SignupWirePayload, e as computePayloadFingerprint, f as computeSignupFingerprint, g as generateIdempotencyKey, r as resolveBotToken, s as signupWireSchema, h as submitLead, i as submitSignup } from '../signup-client-Bl6eUrxR.js';
|
|
2
|
+
import 'zod/v3';
|
|
3
|
+
import '../model-IEyDI54w.js';
|
|
4
|
+
import '../schema-TfyBU6JW.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared HTTP helper: fetch bounded by a timeout via AbortController.
|
|
8
|
+
*
|
|
9
|
+
* Every SDK wire call (spec fetch, leads submit, signup submit) MUST be
|
|
10
|
+
* bounded — the widgets flip to a disabled/"Sending…"/"Loading…" state
|
|
11
|
+
* BEFORE the await, so an intake that accepts the connection and then stalls
|
|
12
|
+
* would otherwise hang the UI forever. On timeout the fetch is aborted and a
|
|
13
|
+
* typed OnboardingNetworkError is raised by the caller (which maps abort/
|
|
14
|
+
* network failures uniformly).
|
|
15
|
+
*/
|
|
16
|
+
/** Default per-request timeout. Generous enough for a slow-but-alive intake. */
|
|
17
|
+
declare const DEFAULT_REQUEST_TIMEOUT_MS = 15000;
|
|
18
|
+
interface TimeoutFetchOptions extends RequestInit {
|
|
19
|
+
/** Per-request timeout in ms. Default DEFAULT_REQUEST_TIMEOUT_MS. */
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
/** The fetch implementation to use (defaults to globalThis.fetch). */
|
|
22
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* fetch() with a hard timeout. Aborts the request when the deadline elapses;
|
|
26
|
+
* the resulting AbortError propagates to the caller (who wraps it as an
|
|
27
|
+
* OnboardingNetworkError). A caller-supplied `signal` is respected too — if
|
|
28
|
+
* either the caller aborts OR the timeout fires, the request is aborted.
|
|
29
|
+
*/
|
|
30
|
+
declare function fetchWithTimeout(url: string, options?: TimeoutFetchOptions): Promise<Response>;
|
|
31
|
+
/**
|
|
32
|
+
* Run a promise with a timeout. On timeout, rejects with `onTimeout()`'s
|
|
33
|
+
* error. Used to bound calls that don't take an AbortSignal (grecaptcha
|
|
34
|
+
* .execute()). The underlying op is NOT cancelled (grecaptcha has no abort),
|
|
35
|
+
* but the caller no longer waits on it — the widget re-enables.
|
|
36
|
+
*/
|
|
37
|
+
declare function withTimeout<T>(op: Promise<T>, timeoutMs: number, onTimeout: () => Error): Promise<T>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Error taxonomy for the onboarding submit client.
|
|
41
|
+
*
|
|
42
|
+
* Maps HTTP status codes and server error bodies to typed errors:
|
|
43
|
+
* 403 bot_challenge_failed → OnboardingBotChallengeError
|
|
44
|
+
* 409 spec_stale (SUBMIT) → OnboardingSpecStaleError (submit endpoint only,
|
|
45
|
+
* body { error:true, code:"spec_stale",
|
|
46
|
+
* currentSpecVersion })
|
|
47
|
+
* 409 (other / LEADS) → OnboardingConflictError (generic conflict)
|
|
48
|
+
* 429 → OnboardingRateLimitError
|
|
49
|
+
* 5xx → OnboardingServerError (retryable)
|
|
50
|
+
* network / timeout → OnboardingNetworkError
|
|
51
|
+
*/
|
|
52
|
+
type OnboardingErrorKind = "bot_challenge_failed" | "spec_stale" | "spec_invalid" | "conflict" | "rate_limited" | "server_error" | "network_error" | "validation_error";
|
|
53
|
+
declare class OnboardingError extends Error {
|
|
54
|
+
readonly kind: OnboardingErrorKind;
|
|
55
|
+
readonly statusCode: number | null;
|
|
56
|
+
constructor(kind: OnboardingErrorKind, message: string, statusCode?: number | null);
|
|
57
|
+
}
|
|
58
|
+
declare class OnboardingBotChallengeError extends OnboardingError {
|
|
59
|
+
constructor(message?: string);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A 409 that is NOT spec_stale. On the /leads path there is no spec_stale
|
|
63
|
+
* concept (the payload carries no specVersion); on /submit, a 409 that
|
|
64
|
+
* lacks `code:"spec_stale"` also lands here. Distinct from
|
|
65
|
+
* OnboardingSpecStaleError so headless consumers switching on `kind` get the
|
|
66
|
+
* correct diagnosis (a generic conflict, e.g. a D538 same-key concurrent
|
|
67
|
+
* race) rather than a "form has been updated, refresh" recovery message.
|
|
68
|
+
*/
|
|
69
|
+
declare class OnboardingConflictError extends OnboardingError {
|
|
70
|
+
constructor(statusCode?: number, message?: string);
|
|
71
|
+
}
|
|
72
|
+
declare class OnboardingRateLimitError extends OnboardingError {
|
|
73
|
+
readonly retryAfterSeconds: number | null;
|
|
74
|
+
constructor(retryAfterSeconds?: number | null);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A /submit 409 whose body carries `code:"spec_stale"` (D540 reject-stale).
|
|
78
|
+
* The PINNED body shape (confirmed against the crm intake) is exactly:
|
|
79
|
+
* { error: true, code: "spec_stale", currentSpecVersion: string }
|
|
80
|
+
* The version is read ONLY from `currentSpecVersion` — no field hedging.
|
|
81
|
+
* Submit-endpoint only; /leads 409s are OnboardingConflictError.
|
|
82
|
+
*/
|
|
83
|
+
declare class OnboardingSpecStaleError extends OnboardingError {
|
|
84
|
+
readonly currentSpecVersion: string;
|
|
85
|
+
constructor(currentSpecVersion: string);
|
|
86
|
+
}
|
|
87
|
+
declare class OnboardingServerError extends OnboardingError {
|
|
88
|
+
constructor(statusCode: number, message?: string);
|
|
89
|
+
}
|
|
90
|
+
declare class OnboardingNetworkError extends OnboardingError {
|
|
91
|
+
constructor(cause?: unknown);
|
|
92
|
+
}
|
|
93
|
+
declare class OnboardingValidationError extends OnboardingError {
|
|
94
|
+
constructor(message: string);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The spec endpoint returned a body that does not conform to the LOCKED
|
|
98
|
+
* D540 §1 response shape. This is a server-side contract violation — the
|
|
99
|
+
* SDK refuses to render a form from a malformed spec (a half-parsed spec
|
|
100
|
+
* could silently drop required fields).
|
|
101
|
+
*/
|
|
102
|
+
declare class OnboardingSpecInvalidError extends OnboardingError {
|
|
103
|
+
constructor(detail: string);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { DEFAULT_REQUEST_TIMEOUT_MS, OnboardingBotChallengeError, OnboardingConflictError, OnboardingError, type OnboardingErrorKind, OnboardingNetworkError, OnboardingRateLimitError, OnboardingServerError, OnboardingSpecInvalidError, OnboardingSpecStaleError, OnboardingValidationError, fetchWithTimeout, withTimeout };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import '../chunk-Z4PA6C2Z.js';
|
|
2
|
+
export { computePayloadFingerprint, computeSignupFingerprint, generateIdempotencyKey, resolveBotToken, signupWireSchema, submitLead, submitSignup } from '../chunk-BQCTDU5V.js';
|
|
3
|
+
import '../chunk-BIFANV7M.js';
|
|
4
|
+
export { DEFAULT_REQUEST_TIMEOUT_MS, OnboardingBotChallengeError, OnboardingConflictError, OnboardingError, OnboardingNetworkError, OnboardingRateLimitError, OnboardingServerError, OnboardingSpecInvalidError, OnboardingSpecStaleError, OnboardingValidationError, fetchWithTimeout, withTimeout } from '../chunk-AW7W3HAC.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|