@nodii/onboarding 0.0.1 → 0.1.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/README.md +75 -2
- package/dist/chunk-7NS7ENJV.js +232 -0
- package/dist/chunk-7NS7ENJV.js.map +1 -0
- package/dist/chunk-AZE3NPSY.js +186 -0
- package/dist/chunk-AZE3NPSY.js.map +1 -0
- package/dist/chunk-BMQINH6O.js +401 -0
- package/dist/chunk-BMQINH6O.js.map +1 -0
- package/dist/chunk-F75ZJERM.js +199 -0
- package/dist/chunk-F75ZJERM.js.map +1 -0
- package/dist/chunk-FIRSA7EH.js +3 -0
- package/dist/chunk-FIRSA7EH.js.map +1 -0
- package/dist/chunk-IPAKPLIF.js +1660 -0
- package/dist/chunk-IPAKPLIF.js.map +1 -0
- package/dist/chunk-JFDQZ3AC.js +3 -0
- package/dist/chunk-JFDQZ3AC.js.map +1 -0
- package/dist/chunk-JFIONONR.js +3 -0
- package/dist/chunk-JFIONONR.js.map +1 -0
- package/dist/chunk-KQTS47FC.js +546 -0
- package/dist/chunk-KQTS47FC.js.map +1 -0
- package/dist/chunk-LVJM4CTG.js +306 -0
- package/dist/chunk-LVJM4CTG.js.map +1 -0
- package/dist/chunk-SEKNVHD3.js +59 -0
- package/dist/chunk-SEKNVHD3.js.map +1 -0
- package/dist/chunk-SIMLMQPT.js +37 -0
- package/dist/chunk-SIMLMQPT.js.map +1 -0
- package/dist/chunk-U56GQITG.js +79 -0
- package/dist/chunk-U56GQITG.js.map +1 -0
- package/dist/chunk-U6AXKGYQ.js +101 -0
- package/dist/chunk-U6AXKGYQ.js.map +1 -0
- package/dist/chunk-VH6FWDWI.js +3 -0
- package/dist/chunk-VH6FWDWI.js.map +1 -0
- package/dist/chunk-XJTJPBJB.js +191 -0
- package/dist/chunk-XJTJPBJB.js.map +1 -0
- package/dist/chunk-Z4PA6C2Z.js +3 -0
- package/dist/chunk-Z4PA6C2Z.js.map +1 -0
- package/dist/client-CqE2dF9A.d.ts +86 -0
- package/dist/consent/index.d.ts +59 -0
- package/dist/consent/index.js +7 -0
- package/dist/consent/index.js.map +1 -0
- package/dist/controller-BQb62D0N.d.ts +177 -0
- package/dist/dynamic/index.d.ts +235 -0
- package/dist/dynamic/index.js +6 -0
- package/dist/dynamic/index.js.map +1 -0
- package/dist/errors-vJkye4a0.d.ts +110 -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-Dqfa890U.d.ts +83 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +18 -2
- package/dist/index.js.map +1 -0
- package/dist/model-ESLSEbi0.d.ts +640 -0
- package/dist/model-mnjAEtKe.d.ts +253 -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/render-DC7P2BGQ.js +5 -0
- package/dist/render-DC7P2BGQ.js.map +1 -0
- package/dist/schema-BrXb9gnh.d.ts +267 -0
- package/dist/signup-client-BL5DfarJ.d.ts +392 -0
- package/dist/spec/index.d.ts +17 -0
- package/dist/spec/index.js +5 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/submit/index.d.ts +42 -0
- package/dist/submit/index.js +6 -0
- package/dist/submit/index.js.map +1 -0
- package/dist/viewer/index.d.ts +4 -0
- package/dist/viewer/index.js +5 -0
- package/dist/viewer/index.js.map +1 -0
- package/dist/widget/index.d.ts +262 -0
- package/dist/widget/index.js +12 -0
- package/dist/widget/index.js.map +1 -0
- package/package.json +96 -6
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { z } from 'zod/v3';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* D543 §4 ConsentPack spec model — the `consentPack` block that GET
|
|
5
|
+
* /api/v1/public/onboarding/spec grows on top of the D540 shape:
|
|
6
|
+
*
|
|
7
|
+
* consentPack: {
|
|
8
|
+
* documents: [
|
|
9
|
+
* { doc_type, custom_key?, title, version_no, content_hash,
|
|
10
|
+
* download_url, acceptance_level, required }
|
|
11
|
+
* ]
|
|
12
|
+
* }
|
|
13
|
+
*
|
|
14
|
+
* The intake projects ONLY `live` versions into this block (D543 §4);
|
|
15
|
+
* `download_url` is a short-TTL presigned GET the SDK renders/opens.
|
|
16
|
+
*
|
|
17
|
+
* `acceptance_level` (D543 §2) is a per-document GATE:
|
|
18
|
+
* - "checkbox" — a single accept checkbox (basic clickwrap).
|
|
19
|
+
* - "scroll_then_accept" — accept disabled until the doc is scrolled to
|
|
20
|
+
* the end (client asserts evidence.scrolled_to_end).
|
|
21
|
+
* - "open_then_accept" — accept disabled until the doc is opened/viewed
|
|
22
|
+
* (client asserts evidence.opened).
|
|
23
|
+
* (E-signature is a deferred future level, D543 §2 — NOT modeled here.)
|
|
24
|
+
*
|
|
25
|
+
* FAIL-CLOSED (R1 + D543 §5 / D540 §1): a malformed consentPack throws
|
|
26
|
+
* OnboardingSpecInvalidError at parse time — never rendered half-parsed
|
|
27
|
+
* (a dropped `required` doc would let a user submit without consent, and a
|
|
28
|
+
* missing `content_hash`/`version_no` would break the server's re-validation
|
|
29
|
+
* match). The SDK refuses to render a consent step it cannot trust.
|
|
30
|
+
*
|
|
31
|
+
* DOM-ID HARDENING: a document's DOM-id token is derived from `doc_type`
|
|
32
|
+
* (a fixed enum — safe) or, for custom docs, from `custom_key` (free-form
|
|
33
|
+
* from the served spec). Custom keys are interpolated into element ids and
|
|
34
|
+
* (historically) selectors by the widget layer, so they are constrained to
|
|
35
|
+
* the SAME strict identifier alphabet as field keys (CUSTOM_KEY_PATTERN,
|
|
36
|
+
* identical to the spec model's FIELD_KEY_PATTERN) and REJECTED at parse time
|
|
37
|
+
* if they carry CSS/selector metacharacters. This is layer 1; the widget also
|
|
38
|
+
* CSS.escapes every id token as defense-in-depth.
|
|
39
|
+
*
|
|
40
|
+
* SUBMIT PIN (P4): the submit array carries {legalDocumentId, versionNo,
|
|
41
|
+
* accepted, evidence} — the server matches on legalDocumentId + versionNo
|
|
42
|
+
* (contentHash is spec-side integrity metadata, NOT echoed on submit; a
|
|
43
|
+
* content change publishes a new versionNo, so versionNo is a complete pin).
|
|
44
|
+
*
|
|
45
|
+
* DRIFT 5e3df7a3 (2026-07-14, consumer-visible) — RESOLVED by the canonical
|
|
46
|
+
* shape: D543 §4 as literally written omitted `legal_document_id` from the
|
|
47
|
+
* spec block, yet the submit array is KEYED on it (the server matches
|
|
48
|
+
* legalDocumentId + versionNo against the live version). The
|
|
49
|
+
* canonical alignment (both tiers, camelCase) INCLUDES `legalDocumentId` in
|
|
50
|
+
* the spec `consentPack.documents[]`, exactly as the drift proposed. This
|
|
51
|
+
* model REQUIRES it (fail-closed OnboardingSpecInvalidError if missing).
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/** D543 §2 acceptance-level enum. Extensible (adding a level is additive). */
|
|
55
|
+
declare const ACCEPTANCE_LEVELS: readonly ["checkbox", "scroll_then_accept", "open_then_accept"];
|
|
56
|
+
type AcceptanceLevel = (typeof ACCEPTANCE_LEVELS)[number];
|
|
57
|
+
declare const acceptanceLevelSchema: z.ZodEnum<["checkbox", "scroll_then_accept", "open_then_accept"]>;
|
|
58
|
+
/** D543 §3 docType enum. */
|
|
59
|
+
declare const DOC_TYPES: readonly ["tos", "privacy", "dpa", "custom"];
|
|
60
|
+
type ConsentDocType = (typeof DOC_TYPES)[number];
|
|
61
|
+
/**
|
|
62
|
+
* One live legal document projected into the consent step. Mirrors the D543
|
|
63
|
+
* §4 `consentPack.documents[]` element — CANONICAL camelCase wire shape (both
|
|
64
|
+
* tenant + platform tiers aligned to this): { legalDocumentId, docType,
|
|
65
|
+
* customKey (nullable), title, versionNo, contentHash, downloadUrl,
|
|
66
|
+
* acceptanceLevel, required }. The `acceptanceLevel` enum VALUES stay snake
|
|
67
|
+
* (checkbox | scroll_then_accept | open_then_accept).
|
|
68
|
+
*
|
|
69
|
+
* Cross-field invariant (D543 §3): `customKey` is a non-null identifier when
|
|
70
|
+
* `docType === "custom"` and MUST be null otherwise (a canonical tos/privacy/
|
|
71
|
+
* dpa doc is keyed by docType; only custom docs carry a key). The custom-key
|
|
72
|
+
* alphabet is DOM-id safe.
|
|
73
|
+
*/
|
|
74
|
+
declare const consentDocumentSchema: z.ZodEffects<z.ZodObject<{
|
|
75
|
+
legalDocumentId: z.ZodString;
|
|
76
|
+
docType: z.ZodEnum<["tos", "privacy", "dpa", "custom"]>;
|
|
77
|
+
customKey: z.ZodNullable<z.ZodString>;
|
|
78
|
+
title: z.ZodString;
|
|
79
|
+
versionNo: z.ZodNumber;
|
|
80
|
+
contentHash: z.ZodString;
|
|
81
|
+
downloadUrl: z.ZodString;
|
|
82
|
+
acceptanceLevel: z.ZodEnum<["checkbox", "scroll_then_accept", "open_then_accept"]>;
|
|
83
|
+
required: z.ZodBoolean;
|
|
84
|
+
}, "strict", z.ZodTypeAny, {
|
|
85
|
+
legalDocumentId: string;
|
|
86
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
87
|
+
customKey: string | null;
|
|
88
|
+
title: string;
|
|
89
|
+
versionNo: number;
|
|
90
|
+
contentHash: string;
|
|
91
|
+
downloadUrl: string;
|
|
92
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
93
|
+
required: boolean;
|
|
94
|
+
}, {
|
|
95
|
+
legalDocumentId: string;
|
|
96
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
97
|
+
customKey: string | null;
|
|
98
|
+
title: string;
|
|
99
|
+
versionNo: number;
|
|
100
|
+
contentHash: string;
|
|
101
|
+
downloadUrl: string;
|
|
102
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
103
|
+
required: boolean;
|
|
104
|
+
}>, {
|
|
105
|
+
legalDocumentId: string;
|
|
106
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
107
|
+
customKey: string | null;
|
|
108
|
+
title: string;
|
|
109
|
+
versionNo: number;
|
|
110
|
+
contentHash: string;
|
|
111
|
+
downloadUrl: string;
|
|
112
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
113
|
+
required: boolean;
|
|
114
|
+
}, {
|
|
115
|
+
legalDocumentId: string;
|
|
116
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
117
|
+
customKey: string | null;
|
|
118
|
+
title: string;
|
|
119
|
+
versionNo: number;
|
|
120
|
+
contentHash: string;
|
|
121
|
+
downloadUrl: string;
|
|
122
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
123
|
+
required: boolean;
|
|
124
|
+
}>;
|
|
125
|
+
type ConsentDocument = z.infer<typeof consentDocumentSchema>;
|
|
126
|
+
/**
|
|
127
|
+
* The `consentPack` block. `documents` may be empty (an onboarder with no
|
|
128
|
+
* required legal docs) — the consent stage is then omitted from the flow.
|
|
129
|
+
*
|
|
130
|
+
* Uniqueness: no two documents may share the same STABLE key (docType, or
|
|
131
|
+
* custom:<customKey> for custom docs). A duplicate would collide their DOM
|
|
132
|
+
* ids AND their consent records — fail-closed at parse (the server keys the
|
|
133
|
+
* registry on (scope, docType) / (scope, customKey) per D543 §3, so a
|
|
134
|
+
* duplicate here is a projection bug, not a renderable spec).
|
|
135
|
+
*/
|
|
136
|
+
declare const consentPackSchema: z.ZodEffects<z.ZodObject<{
|
|
137
|
+
documents: z.ZodArray<z.ZodEffects<z.ZodObject<{
|
|
138
|
+
legalDocumentId: z.ZodString;
|
|
139
|
+
docType: z.ZodEnum<["tos", "privacy", "dpa", "custom"]>;
|
|
140
|
+
customKey: z.ZodNullable<z.ZodString>;
|
|
141
|
+
title: z.ZodString;
|
|
142
|
+
versionNo: z.ZodNumber;
|
|
143
|
+
contentHash: z.ZodString;
|
|
144
|
+
downloadUrl: z.ZodString;
|
|
145
|
+
acceptanceLevel: z.ZodEnum<["checkbox", "scroll_then_accept", "open_then_accept"]>;
|
|
146
|
+
required: z.ZodBoolean;
|
|
147
|
+
}, "strict", z.ZodTypeAny, {
|
|
148
|
+
legalDocumentId: string;
|
|
149
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
150
|
+
customKey: string | null;
|
|
151
|
+
title: string;
|
|
152
|
+
versionNo: number;
|
|
153
|
+
contentHash: string;
|
|
154
|
+
downloadUrl: string;
|
|
155
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
156
|
+
required: boolean;
|
|
157
|
+
}, {
|
|
158
|
+
legalDocumentId: string;
|
|
159
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
160
|
+
customKey: string | null;
|
|
161
|
+
title: string;
|
|
162
|
+
versionNo: number;
|
|
163
|
+
contentHash: string;
|
|
164
|
+
downloadUrl: string;
|
|
165
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
166
|
+
required: boolean;
|
|
167
|
+
}>, {
|
|
168
|
+
legalDocumentId: string;
|
|
169
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
170
|
+
customKey: string | null;
|
|
171
|
+
title: string;
|
|
172
|
+
versionNo: number;
|
|
173
|
+
contentHash: string;
|
|
174
|
+
downloadUrl: string;
|
|
175
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
176
|
+
required: boolean;
|
|
177
|
+
}, {
|
|
178
|
+
legalDocumentId: string;
|
|
179
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
180
|
+
customKey: string | null;
|
|
181
|
+
title: string;
|
|
182
|
+
versionNo: number;
|
|
183
|
+
contentHash: string;
|
|
184
|
+
downloadUrl: string;
|
|
185
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
186
|
+
required: boolean;
|
|
187
|
+
}>, "many">;
|
|
188
|
+
}, "strict", z.ZodTypeAny, {
|
|
189
|
+
documents: {
|
|
190
|
+
legalDocumentId: string;
|
|
191
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
192
|
+
customKey: string | null;
|
|
193
|
+
title: string;
|
|
194
|
+
versionNo: number;
|
|
195
|
+
contentHash: string;
|
|
196
|
+
downloadUrl: string;
|
|
197
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
198
|
+
required: boolean;
|
|
199
|
+
}[];
|
|
200
|
+
}, {
|
|
201
|
+
documents: {
|
|
202
|
+
legalDocumentId: string;
|
|
203
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
204
|
+
customKey: string | null;
|
|
205
|
+
title: string;
|
|
206
|
+
versionNo: number;
|
|
207
|
+
contentHash: string;
|
|
208
|
+
downloadUrl: string;
|
|
209
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
210
|
+
required: boolean;
|
|
211
|
+
}[];
|
|
212
|
+
}>, {
|
|
213
|
+
documents: {
|
|
214
|
+
legalDocumentId: string;
|
|
215
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
216
|
+
customKey: string | null;
|
|
217
|
+
title: string;
|
|
218
|
+
versionNo: number;
|
|
219
|
+
contentHash: string;
|
|
220
|
+
downloadUrl: string;
|
|
221
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
222
|
+
required: boolean;
|
|
223
|
+
}[];
|
|
224
|
+
}, {
|
|
225
|
+
documents: {
|
|
226
|
+
legalDocumentId: string;
|
|
227
|
+
docType: "custom" | "tos" | "privacy" | "dpa";
|
|
228
|
+
customKey: string | null;
|
|
229
|
+
title: string;
|
|
230
|
+
versionNo: number;
|
|
231
|
+
contentHash: string;
|
|
232
|
+
downloadUrl: string;
|
|
233
|
+
acceptanceLevel: "checkbox" | "scroll_then_accept" | "open_then_accept";
|
|
234
|
+
required: boolean;
|
|
235
|
+
}[];
|
|
236
|
+
}>;
|
|
237
|
+
type ConsentPack = z.infer<typeof consentPackSchema>;
|
|
238
|
+
/**
|
|
239
|
+
* Stable, collision-proof identity for a consent document, used as the map
|
|
240
|
+
* key in the controller and the DOM-id token in the widget. `docType` is a
|
|
241
|
+
* fixed enum; `custom:` is prefixed for custom docs so a customKey of
|
|
242
|
+
* "tos" can never alias the canonical tos doc.
|
|
243
|
+
*
|
|
244
|
+
* Note: this is NOT the submit key — the submit array keys on the server's
|
|
245
|
+
* opaque `legalDocumentId` (D543 §4), which the SDK does not synthesize.
|
|
246
|
+
* This is a purely CLIENT-side identity for state + DOM.
|
|
247
|
+
*/
|
|
248
|
+
declare function consentDocKey(doc: {
|
|
249
|
+
docType: ConsentDocType;
|
|
250
|
+
customKey?: string | null | undefined;
|
|
251
|
+
}): string;
|
|
252
|
+
|
|
253
|
+
export { ACCEPTANCE_LEVELS as A, type ConsentDocType as C, DOC_TYPES as D, type AcceptanceLevel as a, type ConsentDocument as b, type ConsentPack as c, acceptanceLevelSchema as d, consentDocKey as e, consentDocumentSchema as f, consentPackSchema as g };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reCAPTCHA v3 loader and token executor.
|
|
3
|
+
*
|
|
4
|
+
* Per D537:
|
|
5
|
+
* - Site key is public (supplied at mount time from the spec response).
|
|
6
|
+
* - Secret key is NEVER in the browser — only the site key is here.
|
|
7
|
+
* - v3 score-based by default; the operator may configure a v2 fallback
|
|
8
|
+
* on the server side for low-score requests.
|
|
9
|
+
* - The loader injects the reCAPTCHA script once and exposes execute()
|
|
10
|
+
* to obtain a fresh token before each submit.
|
|
11
|
+
*
|
|
12
|
+
* Failure semantics (all recoverable, all bounded by opts.timeoutMs / 10s):
|
|
13
|
+
* - A script load failure (adblock / CSP / offline) REJECTS with
|
|
14
|
+
* RecaptchaError(kind:"load_failed"), EVICTS the cached promise, and
|
|
15
|
+
* REMOVES the injected script tag — the next loadRecaptcha call starts
|
|
16
|
+
* fresh. A transient failure never poisons the siteKey.
|
|
17
|
+
* - EVERY wait is bounded, including grecaptcha.ready() AFTER onload and on
|
|
18
|
+
* the adoption/poll paths: if api.js serves but the inner runtime never
|
|
19
|
+
* boots (ready() never fires), the loader rejects RecaptchaError(
|
|
20
|
+
* kind:"timeout") and evicts, rather than hanging the widget on
|
|
21
|
+
* "Sending…" forever.
|
|
22
|
+
* - The "existing script tag but no grecaptcha global" poll is BOUNDED,
|
|
23
|
+
* then the subsequent ready() is bounded by the remaining budget.
|
|
24
|
+
*
|
|
25
|
+
* Multi-siteKey + foreign-global handling (honest):
|
|
26
|
+
* - The v3 script loads with `?render=<siteKey>` and initializes for ONE
|
|
27
|
+
* site key per page. A SECOND different siteKey after our first load is
|
|
28
|
+
* rejected RecaptchaError(kind:"sitekey_mismatch").
|
|
29
|
+
* - If the HOST page pre-loaded grecaptcha with an unknown render key (a
|
|
30
|
+
* FOREIGN global this SDK did not create), we CANNOT introspect its key,
|
|
31
|
+
* so executing our key against it would be the exact silent misfire we
|
|
32
|
+
* promise to prevent. We reject RecaptchaError(kind:"sitekey_mismatch")
|
|
33
|
+
* instead. (Detection: we only adopt a global we brought up ourselves or
|
|
34
|
+
* that our own script tag is loading.)
|
|
35
|
+
*
|
|
36
|
+
* execute() rejections (invalid key at execute time, Google-internal errors,
|
|
37
|
+
* often plain strings) are wrapped in RecaptchaError(kind:"execute_failed").
|
|
38
|
+
*
|
|
39
|
+
* This module is browser-only. It accesses the `window` and `document`
|
|
40
|
+
* globals explicitly.
|
|
41
|
+
*/
|
|
42
|
+
declare global {
|
|
43
|
+
interface Window {
|
|
44
|
+
grecaptcha?: Grecaptcha;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
interface Grecaptcha {
|
|
48
|
+
ready(callback: () => void): void;
|
|
49
|
+
execute(siteKey: string, options: {
|
|
50
|
+
action: string;
|
|
51
|
+
}): Promise<string>;
|
|
52
|
+
}
|
|
53
|
+
type RecaptchaErrorKind = "load_failed" | "timeout" | "sitekey_mismatch" | "execute_failed" | "unavailable";
|
|
54
|
+
/** Typed error for every reCAPTCHA loader failure path. */
|
|
55
|
+
declare class RecaptchaError extends Error {
|
|
56
|
+
readonly kind: RecaptchaErrorKind;
|
|
57
|
+
constructor(kind: RecaptchaErrorKind, message: string);
|
|
58
|
+
}
|
|
59
|
+
interface RecaptchaLoadOptions {
|
|
60
|
+
/**
|
|
61
|
+
* Max time to wait for the script / grecaptcha global to become ready
|
|
62
|
+
* before rejecting with RecaptchaError(kind:"timeout"). Default 10s.
|
|
63
|
+
*/
|
|
64
|
+
timeoutMs?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Inject the reCAPTCHA v3 script for the given siteKey.
|
|
68
|
+
* Idempotent per siteKey: concurrent/repeated calls share one load.
|
|
69
|
+
* A FAILED load is evicted — the next call retries from scratch.
|
|
70
|
+
*
|
|
71
|
+
* @throws {RecaptchaError} kind:"sitekey_mismatch" — a different siteKey
|
|
72
|
+
* is already active (single-render-script limitation, see module doc).
|
|
73
|
+
* @throws {RecaptchaError} kind:"load_failed" — script failed to load.
|
|
74
|
+
* @throws {RecaptchaError} kind:"timeout" — script/global never became ready.
|
|
75
|
+
* @throws {RecaptchaError} kind:"unavailable" — no DOM (not a browser).
|
|
76
|
+
*/
|
|
77
|
+
declare function loadRecaptcha(siteKey: string, opts?: RecaptchaLoadOptions): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Obtain a fresh reCAPTCHA v3 token for the given action.
|
|
80
|
+
* Loads the script if not already loaded. A previous load FAILURE does not
|
|
81
|
+
* block this call — the loader retries from scratch (see loadRecaptcha).
|
|
82
|
+
*
|
|
83
|
+
* @param siteKey - The public reCAPTCHA site key (from the spec endpoint).
|
|
84
|
+
* @param action - The action name (e.g. "contact_submit"). Used for score analytics.
|
|
85
|
+
* @param opts - Optional load options (timeoutMs — also bounds execute()).
|
|
86
|
+
* @returns A fresh reCAPTCHA token. Valid for ~2 minutes.
|
|
87
|
+
*
|
|
88
|
+
* @throws {RecaptchaError} kind:"timeout" if execute() does not settle within
|
|
89
|
+
* the timeout (Google runtime hung) — bounded so the widget re-enables.
|
|
90
|
+
* @throws {RecaptchaError} on any load failure (see loadRecaptcha kinds) or
|
|
91
|
+
* an execute() rejection (kind:"execute_failed").
|
|
92
|
+
*/
|
|
93
|
+
declare function executeRecaptcha(siteKey: string, action: string, opts?: RecaptchaLoadOptions): Promise<string>;
|
|
94
|
+
/**
|
|
95
|
+
* Reset ALL loader state: cached load promise, active siteKey, and the
|
|
96
|
+
* injected script tag (removed from the DOM if present). Primarily for
|
|
97
|
+
* tests and for host pages that intentionally tear down reCAPTCHA.
|
|
98
|
+
* Does NOT unset window.grecaptcha (the script may still own it).
|
|
99
|
+
*/
|
|
100
|
+
declare function _resetRecaptchaState(): void;
|
|
101
|
+
|
|
102
|
+
export { RecaptchaError, type RecaptchaErrorKind, type RecaptchaLoadOptions, _resetRecaptchaState, executeRecaptcha, loadRecaptcha };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"render-DC7P2BGQ.js"}
|
|
@@ -0,0 +1,267 @@
|
|
|
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.ZodOptional<z.ZodString>;
|
|
28
|
+
companyName: z.ZodString;
|
|
29
|
+
contactName: z.ZodString;
|
|
30
|
+
email: z.ZodString;
|
|
31
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
32
|
+
message: z.ZodOptional<z.ZodString>;
|
|
33
|
+
interestModules: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
34
|
+
sizeBand: z.ZodOptional<z.ZodString>;
|
|
35
|
+
attribution: z.ZodOptional<z.ZodObject<{
|
|
36
|
+
campaignTags: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
37
|
+
referringSite: z.ZodOptional<z.ZodString>;
|
|
38
|
+
landingPage: z.ZodOptional<z.ZodString>;
|
|
39
|
+
button: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, "strict", z.ZodTypeAny, {
|
|
41
|
+
campaignTags?: Record<string, string> | undefined;
|
|
42
|
+
referringSite?: string | undefined;
|
|
43
|
+
landingPage?: string | undefined;
|
|
44
|
+
button?: string | undefined;
|
|
45
|
+
}, {
|
|
46
|
+
campaignTags?: Record<string, string> | undefined;
|
|
47
|
+
referringSite?: string | undefined;
|
|
48
|
+
landingPage?: string | undefined;
|
|
49
|
+
button?: string | undefined;
|
|
50
|
+
}>>;
|
|
51
|
+
privacyNoticeAcknowledged: z.ZodEffects<z.ZodBoolean, boolean, boolean>;
|
|
52
|
+
marketingOptIn: z.ZodBoolean;
|
|
53
|
+
intakeKind: z.ZodEnum<["contact", "enquiry"]>;
|
|
54
|
+
website: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
companyName: string;
|
|
57
|
+
contactName: string;
|
|
58
|
+
email: string;
|
|
59
|
+
interestModules: string[];
|
|
60
|
+
privacyNoticeAcknowledged: boolean;
|
|
61
|
+
marketingOptIn: boolean;
|
|
62
|
+
intakeKind: "contact" | "enquiry";
|
|
63
|
+
name?: string | undefined;
|
|
64
|
+
phone?: string | undefined;
|
|
65
|
+
message?: string | undefined;
|
|
66
|
+
sizeBand?: string | undefined;
|
|
67
|
+
attribution?: {
|
|
68
|
+
campaignTags?: Record<string, string> | undefined;
|
|
69
|
+
referringSite?: string | undefined;
|
|
70
|
+
landingPage?: string | undefined;
|
|
71
|
+
button?: string | undefined;
|
|
72
|
+
} | undefined;
|
|
73
|
+
website?: string | undefined;
|
|
74
|
+
}, {
|
|
75
|
+
companyName: string;
|
|
76
|
+
contactName: string;
|
|
77
|
+
email: string;
|
|
78
|
+
privacyNoticeAcknowledged: boolean;
|
|
79
|
+
marketingOptIn: boolean;
|
|
80
|
+
intakeKind: "contact" | "enquiry";
|
|
81
|
+
name?: string | undefined;
|
|
82
|
+
phone?: string | undefined;
|
|
83
|
+
message?: string | undefined;
|
|
84
|
+
interestModules?: string[] | undefined;
|
|
85
|
+
sizeBand?: string | undefined;
|
|
86
|
+
attribution?: {
|
|
87
|
+
campaignTags?: Record<string, string> | undefined;
|
|
88
|
+
referringSite?: string | undefined;
|
|
89
|
+
landingPage?: string | undefined;
|
|
90
|
+
button?: string | undefined;
|
|
91
|
+
} | undefined;
|
|
92
|
+
website?: string | undefined;
|
|
93
|
+
}>;
|
|
94
|
+
type ContactFormValues = z.infer<typeof contactFormSchema>;
|
|
95
|
+
/**
|
|
96
|
+
* The full wire payload — contactFormSchema + botToken.
|
|
97
|
+
*
|
|
98
|
+
* STRICT mode: unknown keys are REJECTED (not stripped), mirroring the
|
|
99
|
+
* server's `additionalProperties: false`. `submitLead` runs every outgoing
|
|
100
|
+
* payload through this schema before the POST — an extra key never reaches
|
|
101
|
+
* the wire; it fails fast client-side with OnboardingValidationError.
|
|
102
|
+
*/
|
|
103
|
+
declare const leadsWireSchema: z.ZodObject<{
|
|
104
|
+
name: z.ZodOptional<z.ZodString>;
|
|
105
|
+
companyName: z.ZodString;
|
|
106
|
+
contactName: z.ZodString;
|
|
107
|
+
email: z.ZodString;
|
|
108
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
109
|
+
message: z.ZodOptional<z.ZodString>;
|
|
110
|
+
interestModules: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
111
|
+
sizeBand: z.ZodOptional<z.ZodString>;
|
|
112
|
+
attribution: z.ZodOptional<z.ZodObject<{
|
|
113
|
+
campaignTags: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
114
|
+
referringSite: z.ZodOptional<z.ZodString>;
|
|
115
|
+
landingPage: z.ZodOptional<z.ZodString>;
|
|
116
|
+
button: z.ZodOptional<z.ZodString>;
|
|
117
|
+
}, "strict", z.ZodTypeAny, {
|
|
118
|
+
campaignTags?: Record<string, string> | undefined;
|
|
119
|
+
referringSite?: string | undefined;
|
|
120
|
+
landingPage?: string | undefined;
|
|
121
|
+
button?: string | undefined;
|
|
122
|
+
}, {
|
|
123
|
+
campaignTags?: Record<string, string> | undefined;
|
|
124
|
+
referringSite?: string | undefined;
|
|
125
|
+
landingPage?: string | undefined;
|
|
126
|
+
button?: string | undefined;
|
|
127
|
+
}>>;
|
|
128
|
+
privacyNoticeAcknowledged: z.ZodEffects<z.ZodBoolean, boolean, boolean>;
|
|
129
|
+
marketingOptIn: z.ZodBoolean;
|
|
130
|
+
intakeKind: z.ZodEnum<["contact", "enquiry"]>;
|
|
131
|
+
website: z.ZodOptional<z.ZodString>;
|
|
132
|
+
} & {
|
|
133
|
+
botToken: z.ZodOptional<z.ZodString>;
|
|
134
|
+
}, "strict", z.ZodTypeAny, {
|
|
135
|
+
companyName: string;
|
|
136
|
+
contactName: string;
|
|
137
|
+
email: string;
|
|
138
|
+
interestModules: string[];
|
|
139
|
+
privacyNoticeAcknowledged: boolean;
|
|
140
|
+
marketingOptIn: boolean;
|
|
141
|
+
intakeKind: "contact" | "enquiry";
|
|
142
|
+
name?: string | undefined;
|
|
143
|
+
phone?: string | undefined;
|
|
144
|
+
message?: string | undefined;
|
|
145
|
+
sizeBand?: string | undefined;
|
|
146
|
+
attribution?: {
|
|
147
|
+
campaignTags?: Record<string, string> | undefined;
|
|
148
|
+
referringSite?: string | undefined;
|
|
149
|
+
landingPage?: string | undefined;
|
|
150
|
+
button?: string | undefined;
|
|
151
|
+
} | undefined;
|
|
152
|
+
website?: string | undefined;
|
|
153
|
+
botToken?: string | undefined;
|
|
154
|
+
}, {
|
|
155
|
+
companyName: string;
|
|
156
|
+
contactName: string;
|
|
157
|
+
email: string;
|
|
158
|
+
privacyNoticeAcknowledged: boolean;
|
|
159
|
+
marketingOptIn: boolean;
|
|
160
|
+
intakeKind: "contact" | "enquiry";
|
|
161
|
+
name?: string | undefined;
|
|
162
|
+
phone?: string | undefined;
|
|
163
|
+
message?: string | undefined;
|
|
164
|
+
interestModules?: string[] | undefined;
|
|
165
|
+
sizeBand?: string | undefined;
|
|
166
|
+
attribution?: {
|
|
167
|
+
campaignTags?: Record<string, string> | undefined;
|
|
168
|
+
referringSite?: string | undefined;
|
|
169
|
+
landingPage?: string | undefined;
|
|
170
|
+
button?: string | undefined;
|
|
171
|
+
} | undefined;
|
|
172
|
+
website?: string | undefined;
|
|
173
|
+
botToken?: string | undefined;
|
|
174
|
+
}>;
|
|
175
|
+
type LeadsWirePayload = z.infer<typeof leadsWireSchema>;
|
|
176
|
+
/**
|
|
177
|
+
* Validate user-visible form values (no botToken required here).
|
|
178
|
+
* Returns a Zod SafeParseReturnType (inferred).
|
|
179
|
+
*/
|
|
180
|
+
declare function validateContactForm(values: unknown): z.SafeParseReturnType<{
|
|
181
|
+
companyName: string;
|
|
182
|
+
contactName: string;
|
|
183
|
+
email: string;
|
|
184
|
+
privacyNoticeAcknowledged: boolean;
|
|
185
|
+
marketingOptIn: boolean;
|
|
186
|
+
intakeKind: "contact" | "enquiry";
|
|
187
|
+
name?: string | undefined;
|
|
188
|
+
phone?: string | undefined;
|
|
189
|
+
message?: string | undefined;
|
|
190
|
+
interestModules?: string[] | undefined;
|
|
191
|
+
sizeBand?: string | undefined;
|
|
192
|
+
attribution?: {
|
|
193
|
+
campaignTags?: Record<string, string> | undefined;
|
|
194
|
+
referringSite?: string | undefined;
|
|
195
|
+
landingPage?: string | undefined;
|
|
196
|
+
button?: string | undefined;
|
|
197
|
+
} | undefined;
|
|
198
|
+
website?: string | undefined;
|
|
199
|
+
}, {
|
|
200
|
+
companyName: string;
|
|
201
|
+
contactName: string;
|
|
202
|
+
email: string;
|
|
203
|
+
interestModules: string[];
|
|
204
|
+
privacyNoticeAcknowledged: boolean;
|
|
205
|
+
marketingOptIn: boolean;
|
|
206
|
+
intakeKind: "contact" | "enquiry";
|
|
207
|
+
name?: string | undefined;
|
|
208
|
+
phone?: string | undefined;
|
|
209
|
+
message?: string | undefined;
|
|
210
|
+
sizeBand?: string | undefined;
|
|
211
|
+
attribution?: {
|
|
212
|
+
campaignTags?: Record<string, string> | undefined;
|
|
213
|
+
referringSite?: string | undefined;
|
|
214
|
+
landingPage?: string | undefined;
|
|
215
|
+
button?: string | undefined;
|
|
216
|
+
} | undefined;
|
|
217
|
+
website?: string | undefined;
|
|
218
|
+
}>;
|
|
219
|
+
/**
|
|
220
|
+
* Validate the full wire payload (including botToken) before submission.
|
|
221
|
+
* STRICT: unknown keys are rejected, matching additionalProperties:false.
|
|
222
|
+
* This is the exact validation `submitLead` applies on the wire path.
|
|
223
|
+
* Returns a Zod SafeParseReturnType (inferred).
|
|
224
|
+
*/
|
|
225
|
+
declare function validateLeadsPayload(payload: unknown): z.SafeParseReturnType<{
|
|
226
|
+
companyName: string;
|
|
227
|
+
contactName: string;
|
|
228
|
+
email: string;
|
|
229
|
+
privacyNoticeAcknowledged: boolean;
|
|
230
|
+
marketingOptIn: boolean;
|
|
231
|
+
intakeKind: "contact" | "enquiry";
|
|
232
|
+
name?: string | undefined;
|
|
233
|
+
phone?: string | undefined;
|
|
234
|
+
message?: string | undefined;
|
|
235
|
+
interestModules?: string[] | undefined;
|
|
236
|
+
sizeBand?: string | undefined;
|
|
237
|
+
attribution?: {
|
|
238
|
+
campaignTags?: Record<string, string> | undefined;
|
|
239
|
+
referringSite?: string | undefined;
|
|
240
|
+
landingPage?: string | undefined;
|
|
241
|
+
button?: string | undefined;
|
|
242
|
+
} | undefined;
|
|
243
|
+
website?: string | undefined;
|
|
244
|
+
botToken?: string | undefined;
|
|
245
|
+
}, {
|
|
246
|
+
companyName: string;
|
|
247
|
+
contactName: string;
|
|
248
|
+
email: string;
|
|
249
|
+
interestModules: string[];
|
|
250
|
+
privacyNoticeAcknowledged: boolean;
|
|
251
|
+
marketingOptIn: boolean;
|
|
252
|
+
intakeKind: "contact" | "enquiry";
|
|
253
|
+
name?: string | undefined;
|
|
254
|
+
phone?: string | undefined;
|
|
255
|
+
message?: string | undefined;
|
|
256
|
+
sizeBand?: string | undefined;
|
|
257
|
+
attribution?: {
|
|
258
|
+
campaignTags?: Record<string, string> | undefined;
|
|
259
|
+
referringSite?: string | undefined;
|
|
260
|
+
landingPage?: string | undefined;
|
|
261
|
+
button?: string | undefined;
|
|
262
|
+
} | undefined;
|
|
263
|
+
website?: string | undefined;
|
|
264
|
+
botToken?: string | undefined;
|
|
265
|
+
}>;
|
|
266
|
+
|
|
267
|
+
export { type ContactFormValues as C, type LeadsWirePayload as L, validateLeadsPayload as a, contactFormSchema as c, leadsWireSchema as l, validateContactForm as v };
|