@nodii/onboarding 0.1.0-dev.0 → 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 +78 -0
- package/dist/chunk-AZE3NPSY.js +186 -0
- package/dist/chunk-AZE3NPSY.js.map +1 -0
- package/dist/{chunk-BQCTDU5V.js → chunk-BMQINH6O.js} +89 -15
- package/dist/chunk-BMQINH6O.js.map +1 -0
- package/dist/{chunk-34BQX2KR.js → chunk-F75ZJERM.js} +41 -6
- package/dist/chunk-F75ZJERM.js.map +1 -0
- package/dist/chunk-FIRSA7EH.js +3 -0
- package/dist/{chunk-ZDY2I6KY.js.map → chunk-FIRSA7EH.js.map} +1 -1
- package/dist/{chunk-SWMIIUXR.js → chunk-IPAKPLIF.js} +590 -92
- 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-4SWOVHZ2.js → chunk-KQTS47FC.js} +129 -17
- 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-AFCJLUPK.js → chunk-U6AXKGYQ.js} +14 -5
- package/dist/chunk-U6AXKGYQ.js.map +1 -0
- package/dist/{chunk-AW7W3HAC.js → chunk-XJTJPBJB.js} +40 -3
- package/dist/chunk-XJTJPBJB.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 +57 -6
- package/dist/dynamic/index.js +4 -2
- package/dist/errors-vJkye4a0.d.ts +110 -0
- package/dist/form/index.d.ts +2 -2
- package/dist/form/index.js +2 -2
- package/dist/index-Dqfa890U.d.ts +83 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.js +12 -8
- package/dist/{model-IEyDI54w.d.ts → model-ESLSEbi0.d.ts} +199 -46
- package/dist/model-mnjAEtKe.d.ts +253 -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-Bl6eUrxR.d.ts → signup-client-BL5DfarJ.d.ts} +152 -19
- package/dist/spec/index.d.ts +10 -81
- package/dist/spec/index.js +3 -2
- package/dist/submit/index.d.ts +7 -71
- package/dist/submit/index.js +3 -3
- 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 +50 -7
- package/dist/widget/index.js +9 -7
- package/package.json +21 -2
- package/dist/chunk-34BQX2KR.js.map +0 -1
- package/dist/chunk-4SWOVHZ2.js.map +0 -1
- package/dist/chunk-AFCJLUPK.js.map +0 -1
- package/dist/chunk-AW7W3HAC.js.map +0 -1
- package/dist/chunk-BIFANV7M.js +0 -22
- package/dist/chunk-BIFANV7M.js.map +0 -1
- package/dist/chunk-BQCTDU5V.js.map +0 -1
- package/dist/chunk-SWMIIUXR.js.map +0 -1
- package/dist/chunk-ZDY2I6KY.js +0 -3
- package/dist/schema-TfyBU6JW.d.ts +0 -107
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodii/onboarding",
|
|
3
|
-
"version": "0.1.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Browser SDK for the Nodii self-signup onboarding flow. Headless form state, reCAPTCHA integration, and a default themeable vanilla-TS widget. D540/D537 contract client.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,12 @@
|
|
|
33
33
|
"default": "./dist/dynamic/index.js"
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
+
"./consent": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/consent/index.d.ts",
|
|
39
|
+
"default": "./dist/consent/index.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
36
42
|
"./submit": {
|
|
37
43
|
"import": {
|
|
38
44
|
"types": "./dist/submit/index.d.ts",
|
|
@@ -50,6 +56,12 @@
|
|
|
50
56
|
"types": "./dist/widget/index.d.ts",
|
|
51
57
|
"default": "./dist/widget/index.js"
|
|
52
58
|
}
|
|
59
|
+
},
|
|
60
|
+
"./viewer": {
|
|
61
|
+
"import": {
|
|
62
|
+
"types": "./dist/viewer/index.d.ts",
|
|
63
|
+
"default": "./dist/viewer/index.js"
|
|
64
|
+
}
|
|
53
65
|
}
|
|
54
66
|
},
|
|
55
67
|
"files": [
|
|
@@ -62,13 +74,20 @@
|
|
|
62
74
|
"dev": "tsup --watch",
|
|
63
75
|
"typecheck": "tsc --noEmit",
|
|
64
76
|
"test": "bun test",
|
|
65
|
-
"
|
|
77
|
+
"typecheck:browser": "tsc --noEmit -p browser-tests/tsconfig.json",
|
|
78
|
+
"test:browser:bundle": "bun build browser-tests/fixtures/harness-entry.ts --target=browser --format=esm --outfile=browser-tests/.bundle/sdk.js",
|
|
79
|
+
"test:browser": "bun run test:browser:bundle && playwright test",
|
|
80
|
+
"clean": "rm -rf dist browser-tests/.bundle test-results playwright-report"
|
|
66
81
|
},
|
|
67
82
|
"dependencies": {
|
|
83
|
+
"dompurify": "^3.4.12",
|
|
84
|
+
"marked": "^18.0.6",
|
|
85
|
+
"pdfjs-dist": "^6.1.200",
|
|
68
86
|
"zod": "^3.25.76"
|
|
69
87
|
},
|
|
70
88
|
"devDependencies": {
|
|
71
89
|
"@happy-dom/global-registrator": "^20.10.6",
|
|
90
|
+
"@playwright/test": "^1.61.1",
|
|
72
91
|
"tsup": "^8.3.5",
|
|
73
92
|
"typescript": "^5.9.3"
|
|
74
93
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/spec/model.ts","../src/spec/client.ts"],"names":[],"mappings":";;;AAyCO,IAAM,iBAAA,GAAoB;AAE1B,IAAM,eAAA,GAAkB,EAAE,MAAA,CAAO;AAAA,EACtC,KAAK,CAAA,CACF,MAAA,EAAO,CACP,GAAA,CAAI,CAAC,CAAA,CACL,KAAA;AAAA,IACC,iBAAA;AAAA,IACA;AAAA,GACF;AAAA,EACF,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACtB,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,EAChB,QAAA,EAAU,EAAE,OAAA,EAAQ;AAAA,EACpB,YAAY,CAAA,CAAE,MAAA,CAAO,EAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EAC3C,SAAS,CAAA,CAAE,KAAA,CAAM,EAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EACvC,gBAAA,EAAkB,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACvC,QAAA,EAAU,CAAA,CAAE,IAAA,CAAK,CAAC,MAAA,EAAQ,WAAW,QAAA,EAAU,WAAW,CAAC,CAAA,CAAE,QAAA;AAC/D,CAAC;AAIM,IAAM,cAAA,GAAiB,EAAE,MAAA,CAAO;AAAA,EACrC,OAAO,CAAA,CAAE,IAAA,CAAK,CAAC,MAAA,EAAQ,UAAA,EAAY,YAAY,CAAC,CAAA;AAAA,EAChD,MAAA,EAAQ,CAAA,CAAE,KAAA,CAAM,eAAe;AACjC,CAAC;AAIM,IAAM,oBAAA,GAAuB,EAAE,MAAA,CAAO;AAAA,EAC3C,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC7B,eAAe,CAAA,CAAE,IAAA,CAAK,CAAC,UAAA,EAAY,QAAQ,CAAC,CAAA;AAAA,EAC5C,YAAA,EAAc,EAAE,MAAA,CAAO;AAAA,IACrB,QAAA,EAAU,CAAA,CAAE,OAAA,CAAQ,WAAW,CAAA;AAAA,IAC/B,OAAA,EAAS,EAAE,MAAA;AAAO,GACnB,CAAA;AAAA,EACD,KAAA,EAAO,EAAE,MAAA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOd,OAAA,EAAS,EAAE,MAAA,CAAO,EAAE,QAAQ,CAAA,CAAE,KAAA,CAAM,eAAe,CAAA,EAAG,CAAA;AAAA,IACtD,MAAA,EAAQ,EAAE,MAAA,CAAO,EAAE,OAAO,CAAA,CAAE,KAAA,CAAM,cAAc,CAAA,EAAG;AAAA,GACpD;AACH,CAAC;AAQM,SAAS,uBAAuB,KAAA,EAAgB;AACrD,EAAA,OAAO,oBAAA,CAAqB,UAAU,KAAK,CAAA;AAC7C;;;ACjEA,IAAM,SAAA,GAAY,gCAAA;AAQX,IAAM,mBAAA,GAAN,MAAM,oBAAA,CAAoB;AAAA,EACd,SAAA,uBAAgB,GAAA,EAA4B;AAAA,EAC5C,MAAA,uBAAa,GAAA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ1D,OAAe,UAAA,CAAW,SAAA,EAAmB,WAAA,EAA6B;AACxE,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,CAAC,SAAA,EAAW,WAAW,CAAC,CAAA;AAAA,EAChD;AAAA,EAEA,GAAA,CAAI,WAAmB,WAAA,EAAiD;AACtE,IAAA,OAAO,KAAK,SAAA,CAAU,GAAA;AAAA,MACpB,oBAAA,CAAoB,UAAA,CAAW,SAAA,EAAW,WAAW;AAAA,KACvD;AAAA,EACF;AAAA,EAEA,UAAU,SAAA,EAA+C;AACvD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,SAAS,CAAA;AAAA,EAClC;AAAA,EAEA,GAAA,CAAI,WAAmB,IAAA,EAA4B;AACjD,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA;AAAA,MACb,oBAAA,CAAoB,UAAA,CAAW,SAAA,EAAW,IAAA,CAAK,WAAW,CAAA;AAAA,MAC1D;AAAA,KACF;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,IAAI,CAAA;AAAA,EACjC;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AACrB,IAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,EACpB;AACF;AAGO,IAAM,gBAAA,GAAmB,IAAI,mBAAA;AAapC,SAAS,eAAe,IAAA,EAA8C;AACpE,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAuB;AACvC,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,KAAA,EAAO;AAC1C,IAAA,KAAA,MAAW,SAAS,IAAA,CAAK,MAAA,MAAY,GAAA,CAAI,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,EAC3D;AACA,EAAA,OAAO,GAAA;AACT;AAEO,SAAS,cAAA,CACd,MACA,IAAA,EACe;AACf,EAAA,MAAM,OAAA,GAAU,eAAe,IAAI,CAAA;AACnC,EAAA,MAAM,OAAA,GAAU,eAAe,IAAI,CAAA;AACnC,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,GAAA,IAAO,OAAA,CAAQ,IAAA,EAAK,EAAG;AAChC,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG,KAAA,CAAM,KAAK,GAAG,CAAA;AAAA,EACvC;AACA,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,SAAS,CAAA,IAAK,OAAA,EAAS;AACtC,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA;AACjC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,OAAA,CAAQ,KAAK,GAAG,CAAA;AAChB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,KAAK,SAAA,CAAU,SAAS,MAAM,IAAA,CAAK,SAAA,CAAU,SAAS,CAAA,EAAG;AAC3D,MAAA,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAClB;AAAA,EACF;AACA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAM,IAAA,EAAK;AAAA,IAClB,OAAA,EAAS,QAAQ,IAAA,EAAK;AAAA,IACtB,OAAA,EAAS,QAAQ,IAAA;AAAK,GACxB;AACF;AA2BA,SAAS,QAAA,CAAS,SAAiB,IAAA,EAAsB;AACvD,EAAA,MAAM,IAAA,GAAO,QAAQ,QAAA,CAAS,GAAG,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GAAI,OAAA;AAC5D,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,EAAG,IAAI,CAAA,CAAA;AACvB;AAUA,eAAsB,oBACpB,OAAA,EACyB;AACzB,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,gBAAA;AAE/B,EAAA,IAAI,QAAQ,YAAA,EAAc;AACxB,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,SAAA,CAAU,OAAA,CAAQ,SAAS,CAAA;AAChD,IAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,EACrB;AAEA,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AAC9C,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,0BAAA;AACvC,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,OAAA,CAAQ,OAAA,EAAS,SAAS,CAAA;AAE/C,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,iBAAiB,GAAA,EAAK;AAAA,MACrC,MAAA,EAAQ,KAAA;AAAA,MACR,SAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,uBAAuB,GAAG,CAAA;AAAA,EACtC;AAEA,EAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,IAAA,MAAM,gBAAA,GAAmB,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AAC3D,IAAA,MAAM,aAAa,gBAAA,GACf,MAAA,CAAO,SAAS,gBAAA,EAAkB,EAAE,IACpC,MAAA,CAAO,GAAA;AACX,IAAA,MAAM,IAAI,wBAAA;AAAA,MACR,MAAA,CAAO,KAAA,CAAM,UAAU,CAAA,GAAI,IAAA,GAAO;AAAA,KACpC;AAAA,EACF;AACA,EAAA,IAAI,QAAA,CAAS,MAAA,GAAS,GAAA,IAAO,QAAA,CAAS,UAAU,GAAA,EAAK;AACnD,IAAA,MAAM,IAAI,qBAAA;AAAA,MACR,QAAA,CAAS,MAAA;AAAA,MACT,CAAA,8BAAA,EAAiC,SAAS,MAAM,CAAA;AAAA,KAClD;AAAA,EACF;AAEA,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,MAAM,SAAS,IAAA,EAAK;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,2BAA2B,2BAA2B,CAAA;AAAA,EAClE;AAEA,EAAA,MAAM,MAAA,GAAS,uBAAuB,IAAI,CAAA;AAC1C,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,MAAA,CACzB,KAAA,CAAM,GAAG,CAAC,CAAA,CACV,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,EAAE,IAAA,CAAK,IAAA,CAAK,GAAG,CAAA,IAAK,QAAQ,CAAA,EAAA,EAAK,EAAE,OAAO,CAAA,CAAE,CAAA,CAC1D,IAAA,CAAK,IAAI,CAAA;AACZ,IAAA,MAAM,IAAI,2BAA2B,MAAM,CAAA;AAAA,EAC7C;AAEA,EAAA,KAAA,CAAM,GAAA,CAAI,OAAA,CAAQ,SAAA,EAAW,MAAA,CAAO,IAAI,CAAA;AACxC,EAAA,OAAO,MAAA,CAAO,IAAA;AAChB","file":"chunk-34BQX2KR.js","sourcesContent":["/**\n * D540 §1 onboarding-spec model — mirrors the LOCKED hub REST contract:\n * GET /api/v1/public/onboarding/spec (PublicOnboardingSpecResponse)\n *\n * Response shape (hub JSON Schema, both tiers identical):\n * {\n * specVersion: string (monotonic; echo on submit; stale ⇒ 409),\n * onboarderTier: \"platform\" | \"tenant\",\n * botChallenge: { provider: \"recaptcha\", siteKey: string },\n * forms: {\n * contact: { fields: SpecField[] },\n * signup: { steps: [{ stage: \"lead\"|\"prospect\"|\"activation\",\n * fields: SpecField[] }] }\n * }\n * }\n *\n * SpecField (required: key, type, label, required):\n * { key, type, label, required, validation?, options?, serviceSelection?,\n * piiClass?: \"none\"|\"context\"|\"always\"|\"reference\" }\n *\n * The Zod schema below validates a fetched spec BEFORE the SDK renders\n * anything from it — a malformed spec throws OnboardingSpecInvalidError\n * (a half-parsed spec could silently drop required fields).\n */\n\nimport { z } from \"zod/v3\";\n\nexport type OnboarderTier = \"platform\" | \"tenant\";\nexport type PiiClass = \"none\" | \"context\" | \"always\" | \"reference\";\nexport type SpecStage = \"lead\" | \"prospect\" | \"activation\";\nexport type TerminalStage = \"prospect\" | \"inactive\" | \"active\";\n\n/**\n * Field keys are interpolated into DOM element ids and (historically) CSS\n * selectors by the widget layer. Constrain them to a strict identifier\n * alphabet so a MALICIOUS or compromised onboarder spec cannot smuggle CSS\n * metacharacters or selector-breakout payloads (e.g. `evil], [onclick=…`)\n * through the fetched spec. A spec with an out-of-alphabet key is REJECTED\n * at parse time → OnboardingSpecInvalidError (fail-closed; never rendered).\n * This is layer 1; the widget also CSS.escapes ids as defense-in-depth.\n */\nexport const FIELD_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;\n\nexport const specFieldSchema = z.object({\n key: z\n .string()\n .min(1)\n .regex(\n FIELD_KEY_PATTERN,\n \"field key must contain only letters, digits, underscore, or hyphen\",\n ),\n type: z.string().min(1),\n label: z.string(),\n required: z.boolean(),\n validation: z.record(z.unknown()).optional(),\n options: z.array(z.unknown()).optional(),\n serviceSelection: z.boolean().optional(),\n piiClass: z.enum([\"none\", \"context\", \"always\", \"reference\"]).optional(),\n});\n\nexport type SpecField = z.infer<typeof specFieldSchema>;\n\nexport const specStepSchema = z.object({\n stage: z.enum([\"lead\", \"prospect\", \"activation\"]),\n fields: z.array(specFieldSchema),\n});\n\nexport type SpecStep = z.infer<typeof specStepSchema>;\n\nexport const onboardingSpecSchema = z.object({\n specVersion: z.string().min(1),\n onboarderTier: z.enum([\"platform\", \"tenant\"]),\n botChallenge: z.object({\n provider: z.literal(\"recaptcha\"),\n siteKey: z.string(),\n }),\n forms: z.object({\n // ADVISORY-ONLY (by design, plan §12.2 / D540): the Contact-Us form is\n // INTENTIONALLY a fixed barebones shape (name/email/phone/message) and is\n // NOT onboarder-configurable. `mountContactForm` renders that fixed set\n // directly and does NOT read forms.contact.fields — the field is modeled\n // (and validated) so the SDK can round-trip the full spec, but it drives\n // no rendering. Only forms.signup is spec-driven (the dynamic stepper).\n contact: z.object({ fields: z.array(specFieldSchema) }),\n signup: z.object({ steps: z.array(specStepSchema) }),\n }),\n});\n\nexport type OnboardingSpec = z.infer<typeof onboardingSpecSchema>;\n\n/**\n * Parse an unknown value as an OnboardingSpec.\n * Returns a SafeParseReturnType (inferred).\n */\nexport function validateOnboardingSpec(value: unknown) {\n return onboardingSpecSchema.safeParse(value);\n}\n","/**\n * Config-fetch client for GET /api/v1/public/onboarding/spec (D540 §1/§3).\n *\n * - The onboarder is derived SERVER-side from the request Host (D536) —\n * it is NOT sent by the client. The `onboarder` value here is purely the\n * CLIENT-side cache key (D540 §3: \"cache key (onboarder, specVersion)\").\n * - The spec response is validated against the LOCKED D540 shape before\n * it is returned; a malformed spec throws OnboardingSpecInvalidError.\n * - Cache semantics: every successful fetch is stored under\n * (onboarder, specVersion) and as the onboarder's \"latest\". The versioned\n * entries let the 409 spec_stale flow diff the previously-served version\n * against the refetched one (see `diffSpecFields` + the signup widget's\n * handleSpecStale, which reads the cached prior version before refetching).\n */\n\nimport {\n OnboardingNetworkError,\n OnboardingRateLimitError,\n OnboardingServerError,\n OnboardingSpecInvalidError,\n} from \"../submit/errors.js\";\nimport {\n DEFAULT_REQUEST_TIMEOUT_MS,\n fetchWithTimeout,\n} from \"../submit/http.js\";\nimport {\n validateOnboardingSpec,\n type OnboardingSpec,\n type SpecField,\n} from \"./model.js\";\n\nconst SPEC_PATH = \"/api/v1/public/onboarding/spec\";\n\n/**\n * In-memory spec cache keyed by (onboarder, specVersion), with a \"latest\"\n * pointer per onboarder. Purely client-side; no TTL — the reject-stale\n * policy (409 spec_stale on submit) is the authoritative staleness signal,\n * and a refetch overwrites \"latest\".\n */\nexport class OnboardingSpecCache {\n private readonly byVersion = new Map<string, OnboardingSpec>();\n private readonly latest = new Map<string, OnboardingSpec>();\n\n /**\n * Collision-proof composite key. Uses JSON.stringify of the tuple so an\n * onboarder or version containing the delimiter can never alias another\n * entry — and, critically, contains NO control characters (an earlier\n * NUL-separator made git treat this whole file as binary/undiffable).\n */\n private static versionKey(onboarder: string, specVersion: string): string {\n return JSON.stringify([onboarder, specVersion]);\n }\n\n get(onboarder: string, specVersion: string): OnboardingSpec | undefined {\n return this.byVersion.get(\n OnboardingSpecCache.versionKey(onboarder, specVersion),\n );\n }\n\n getLatest(onboarder: string): OnboardingSpec | undefined {\n return this.latest.get(onboarder);\n }\n\n set(onboarder: string, spec: OnboardingSpec): void {\n this.byVersion.set(\n OnboardingSpecCache.versionKey(onboarder, spec.specVersion),\n spec,\n );\n this.latest.set(onboarder, spec);\n }\n\n clear(): void {\n this.byVersion.clear();\n this.latest.clear();\n }\n}\n\n/** Module-level default cache (one per page). Injectable for tests/apps. */\nexport const defaultSpecCache = new OnboardingSpecCache();\n\n/**\n * Diff two spec versions' signup field sets — used by the 409 spec_stale\n * flow to tell the user WHAT changed. Compares by field key across all\n * signup steps.\n */\nexport interface SpecFieldDiff {\n added: string[];\n removed: string[];\n changed: string[];\n}\n\nfunction signupFieldMap(spec: OnboardingSpec): Map<string, SpecField> {\n const map = new Map<string, SpecField>();\n for (const step of spec.forms.signup.steps) {\n for (const field of step.fields) map.set(field.key, field);\n }\n return map;\n}\n\nexport function diffSpecFields(\n prev: OnboardingSpec,\n next: OnboardingSpec,\n): SpecFieldDiff {\n const prevMap = signupFieldMap(prev);\n const nextMap = signupFieldMap(next);\n const added: string[] = [];\n const removed: string[] = [];\n const changed: string[] = [];\n for (const key of nextMap.keys()) {\n if (!prevMap.has(key)) added.push(key);\n }\n for (const [key, prevField] of prevMap) {\n const nextField = nextMap.get(key);\n if (!nextField) {\n removed.push(key);\n continue;\n }\n if (JSON.stringify(prevField) !== JSON.stringify(nextField)) {\n changed.push(key);\n }\n }\n return {\n added: added.sort(),\n removed: removed.sort(),\n changed: changed.sort(),\n };\n}\n\nexport interface SpecFetchOptions {\n baseUrl: string;\n /**\n * Client-side cache key ONLY (never transmitted; trust is host-derived\n * per D536). Use the onboarder slug/id your embed is configured with.\n */\n onboarder: string;\n /** Custom fetch implementation (defaults to globalThis.fetch). */\n fetch?: typeof globalThis.fetch;\n /** Cache to read/write (defaults to the module-level cache). */\n cache?: OnboardingSpecCache;\n /**\n * Request timeout in ms (default 15s). A stalled intake aborts with\n * OnboardingNetworkError so the boot doesn't hang on \"Loading signup form…\".\n */\n timeoutMs?: number;\n /**\n * When true, return the cached \"latest\" for this onboarder if present\n * WITHOUT a network round-trip. Default false (spec fetches are cheap\n * and the server bumps specVersion on any change). The signup widget's\n * boot passes preferCached:true so a remount reuses the loaded spec.\n */\n preferCached?: boolean;\n}\n\nfunction buildUrl(baseUrl: string, path: string): string {\n const base = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n return `${base}${path}`;\n}\n\n/**\n * Fetch (and validate, and cache) the onboarding spec.\n *\n * @throws {OnboardingSpecInvalidError} response does not match D540 §1\n * @throws {OnboardingRateLimitError} on 429\n * @throws {OnboardingServerError} on any other non-2xx status\n * @throws {OnboardingNetworkError} on network failure OR timeout\n */\nexport async function fetchOnboardingSpec(\n options: SpecFetchOptions,\n): Promise<OnboardingSpec> {\n const cache = options.cache ?? defaultSpecCache;\n\n if (options.preferCached) {\n const cached = cache.getLatest(options.onboarder);\n if (cached) return cached;\n }\n\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const url = buildUrl(options.baseUrl, SPEC_PATH);\n\n let response: Response;\n try {\n response = await fetchWithTimeout(url, {\n method: \"GET\",\n timeoutMs,\n fetchImpl,\n });\n } catch (err) {\n throw new OnboardingNetworkError(err);\n }\n\n if (response.status === 429) {\n const retryAfterHeader = response.headers.get(\"retry-after\");\n const retryAfter = retryAfterHeader\n ? Number.parseInt(retryAfterHeader, 10)\n : Number.NaN;\n throw new OnboardingRateLimitError(\n Number.isNaN(retryAfter) ? null : retryAfter,\n );\n }\n if (response.status < 200 || response.status >= 300) {\n throw new OnboardingServerError(\n response.status,\n `Spec fetch failed with status ${response.status}`,\n );\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n throw new OnboardingSpecInvalidError(\"response body is not JSON\");\n }\n\n const parsed = validateOnboardingSpec(body);\n if (!parsed.success) {\n const detail = parsed.error.issues\n .slice(0, 5)\n .map((i) => `${i.path.join(\".\") || \"(root)\"}: ${i.message}`)\n .join(\"; \");\n throw new OnboardingSpecInvalidError(detail);\n }\n\n cache.set(options.onboarder, parsed.data);\n return parsed.data;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dynamic/derive.ts","../src/dynamic/stepper.ts"],"names":["z"],"mappings":"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","file":"chunk-4SWOVHZ2.js","sourcesContent":["/**\n * Spec → Zod validator derivation (D540 §3).\n *\n * Turns arbitrary SpecField descriptors from the served spec into Zod\n * schemas for CLIENT-side UX validation. The server re-validates\n * authoritatively (D540 §2) — client validation is a convenience layer,\n * so the derivation is deliberately conservative:\n *\n * - Known `type`s map to typed schemas (see FIELD TYPE MAP below).\n * - An UNKNOWN type falls back to z.string() (never blocks a field the\n * server knows how to validate).\n * - Known `validation` keys are applied (minLength, maxLength, min, max,\n * pattern, format:\"email\"). Unknown validation keys are IGNORED\n * client-side — the server enforces them.\n * - `required:false` fields accept undefined AND \"\" (an empty input is\n * \"not provided\").\n * - select/radio values must be one of `options`; multiselect values\n * must be a subset.\n *\n * FIELD TYPE MAP:\n * text | textarea | tel | (unknown) → string\n * email → string().email()\n * number → coerce.number (DOM inputs are strings)\n * checkbox | boolean → boolean\n * select | radio → string ∈ options\n * multiselect → string[] ⊆ options\n * date → string, parseable as a date\n */\n\nimport { z } from \"zod/v3\";\nimport type { SpecField, SpecStep } from \"../spec/model.js\";\n\n/** Extract the comparable value of an option entry ({value}, {key}, or scalar). */\nexport function optionValue(option: unknown): string {\n if (option !== null && typeof option === \"object\") {\n const o = option as Record<string, unknown>;\n if (\"value\" in o) return String(o[\"value\"]);\n if (\"key\" in o) return String(o[\"key\"]);\n }\n return String(option);\n}\n\ninterface KnownValidation {\n minLength?: number;\n maxLength?: number;\n min?: number;\n max?: number;\n pattern?: string;\n format?: string;\n}\n\nfunction knownValidation(field: SpecField): KnownValidation {\n const v = field.validation ?? {};\n const out: KnownValidation = {};\n if (typeof v[\"minLength\"] === \"number\") out.minLength = v[\"minLength\"];\n if (typeof v[\"maxLength\"] === \"number\") out.maxLength = v[\"maxLength\"];\n if (typeof v[\"min\"] === \"number\") out.min = v[\"min\"];\n if (typeof v[\"max\"] === \"number\") out.max = v[\"max\"];\n if (typeof v[\"pattern\"] === \"string\") out.pattern = v[\"pattern\"];\n if (typeof v[\"format\"] === \"string\") out.format = v[\"format\"];\n return out;\n}\n\nfunction stringSchema(field: SpecField): z.ZodTypeAny {\n const v = knownValidation(field);\n let s = z.string();\n if (field.type === \"email\" || v.format === \"email\") {\n s = s.email(`${field.label} must be a valid email`);\n }\n if (v.minLength !== undefined) {\n s = s.min(\n v.minLength,\n `${field.label} must be at least ${v.minLength} characters`,\n );\n }\n if (v.maxLength !== undefined) {\n s = s.max(\n v.maxLength,\n `${field.label} must be at most ${v.maxLength} characters`,\n );\n }\n if (v.pattern !== undefined) {\n try {\n s = s.regex(\n new RegExp(v.pattern),\n `${field.label} has an invalid format`,\n );\n } catch {\n // Invalid regex in the spec — skip client-side; server enforces.\n }\n }\n return s;\n}\n\nfunction numberSchema(field: SpecField): z.ZodTypeAny {\n const v = knownValidation(field);\n let s = z.coerce.number({\n invalid_type_error: `${field.label} must be a number`,\n });\n if (v.min !== undefined) {\n s = s.min(v.min, `${field.label} must be at least ${v.min}`);\n }\n if (v.max !== undefined) {\n s = s.max(v.max, `${field.label} must be at most ${v.max}`);\n }\n return s;\n}\n\nfunction enumSchema(field: SpecField): z.ZodTypeAny {\n const allowed = (field.options ?? []).map(optionValue);\n if (allowed.length === 0) return z.string();\n return z.string().refine((val) => allowed.includes(val), {\n message: `${field.label} must be one of the offered options`,\n });\n}\n\nfunction multiEnumSchema(field: SpecField): z.ZodTypeAny {\n const allowed = (field.options ?? []).map(optionValue);\n const item =\n allowed.length === 0\n ? z.string()\n : z.string().refine((val) => allowed.includes(val), {\n message: `${field.label} contains a value outside the offered options`,\n });\n return z.array(item);\n}\n\nfunction dateSchema(field: SpecField): z.ZodTypeAny {\n return z.string().refine((val) => !Number.isNaN(Date.parse(val)), {\n message: `${field.label} must be a valid date`,\n });\n}\n\n/** Derive the value schema for one field, BEFORE the required/optional wrap. */\nfunction baseSchema(field: SpecField): z.ZodTypeAny {\n switch (field.type) {\n case \"email\":\n return stringSchema(field);\n case \"number\":\n return numberSchema(field);\n case \"checkbox\":\n case \"boolean\":\n return z.boolean();\n case \"select\":\n case \"radio\":\n return enumSchema(field);\n case \"multiselect\":\n return multiEnumSchema(field);\n case \"date\":\n return dateSchema(field);\n default:\n // text | textarea | tel | any unknown type → string with validation\n return stringSchema(field);\n }\n}\n\n/**\n * Derive the full Zod schema for one SpecField.\n * Optional fields accept undefined and \"\" (\"not provided\" in a form UI).\n * Required fields additionally reject \"\" for string-typed inputs.\n */\nexport function deriveFieldSchema(field: SpecField): z.ZodTypeAny {\n const base = baseSchema(field);\n if (field.required) {\n // Required string inputs must be non-empty.\n if (\n field.type !== \"checkbox\" &&\n field.type !== \"boolean\" &&\n field.type !== \"number\" &&\n field.type !== \"multiselect\"\n ) {\n return z\n .string({ required_error: `${field.label} is required` })\n .min(1, `${field.label} is required`)\n .pipe(base);\n }\n if (field.type === \"number\") {\n // A required number must be PRESENT. Without this guard,\n // z.coerce.number(\"\") coerces the empty DOM value to 0 and passes —\n // then buildSubmitPayload drops the \"\" answer, so the client declares\n // the form valid while the server 422s on a missing required field.\n // Reject empty/missing BEFORE coercion; a provided value flows to\n // the coercing number schema (min/max still apply).\n return z\n .any()\n .refine(\n (val) => val !== \"\" && val !== undefined && val !== null,\n `${field.label} is required`,\n )\n .pipe(base);\n }\n if (field.type === \"multiselect\") {\n return base.refine(\n (val) => Array.isArray(val) && val.length > 0,\n `${field.label} requires at least one selection`,\n );\n }\n return base;\n }\n // Optional: \"\" normalizes to undefined before validation.\n return z.preprocess(\n (val) =>\n val === \"\" || val === undefined || val === null ? undefined : val,\n base.optional(),\n );\n}\n\n/**\n * Derive a STRICT Zod object schema for one step's fields — unknown answer\n * keys within the step are rejected (mirrors the server's authoritative\n * re-validation posture; a stale client must not silently carry fields the\n * spec no longer defines).\n */\nexport function deriveStepSchema(step: SpecStep) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const field of step.fields) {\n shape[field.key] = deriveFieldSchema(field);\n }\n return z.object(shape).strict();\n}\n\n/**\n * Derive the STRICT schema for the complete answers object across all\n * steps (used at submit time and by the 409-stale re-validation).\n */\nexport function deriveAnswersSchema(steps: SpecStep[]) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const step of steps) {\n for (const field of step.fields) {\n shape[field.key] = deriveFieldSchema(field);\n }\n }\n return z.object(shape).strict();\n}\n","/**\n * Headless dynamic signup stepper (D540 §1/§3).\n *\n * The steps are GENERATED from the served spec: fields bucket by `stage`\n * server-side → the spec's forms.signup.steps array. More configured\n * fields ⇒ more steps. The final `activation` stage carries the\n * service-selection inputs feeding the existing terminal-stage guards.\n *\n * Framework-agnostic: same subscribe/mutate contract as the Phase-1\n * contact-form state. The default component layer renders it; framework\n * integrations can wrap it.\n *\n * 409 spec_stale flow (D540 reject-stale): the CALLER (widget/submit\n * orchestration) refetches the spec on OnboardingSpecStaleError and calls\n * `applyNewSpec(newSpec)`. The stepper re-validates every answer against\n * the NEW derived schema, DROPS answers whose fields no longer exist,\n * marks `specStale: true`, and repositions to the first step with errors —\n * the user re-confirms; the SDK NEVER silently auto-resubmits.\n */\n\nimport { z, type ZodIssue } from \"zod/v3\";\nimport type { OnboardingSpec, SpecStep, TerminalStage } from \"../spec/model.js\";\nimport { deriveAnswersSchema, deriveStepSchema } from \"./derive.js\";\nimport type { FieldError } from \"../form/state.js\";\n\nexport type StepperStatus = \"editing\" | \"submitting\" | \"success\" | \"error\";\n\nexport interface SignupConsent {\n tosAccepted: boolean;\n privacyAccepted: boolean;\n}\n\nexport interface SignupCredentials {\n email: string;\n password: string;\n}\n\nexport interface SignupStepperState {\n /** Zero-based index of the current step. */\n stepIndex: number;\n stepCount: number;\n currentStep: SpecStep | null;\n /** Answers keyed by field key (only keys defined by the active spec). */\n answers: Record<string, unknown>;\n /** Derived from serviceSelection-flagged answers (see buildSubmitPayload). */\n selectedServices: string[];\n /** Validation errors for the CURRENT step (or full-form at submit). */\n errors: FieldError[];\n /** Credential/consent errors (submit-time). */\n accountErrors: FieldError[];\n consent: SignupConsent;\n credentials: SignupCredentials;\n status: StepperStatus;\n serverError: string | null;\n /** True after a 409-stale spec swap until the user re-validates. */\n specStale: boolean;\n /** The specVersion currently driving the form (echoed on submit). */\n specVersion: string;\n /** Set on success from the submit response. */\n terminalStage: TerminalStage | null;\n}\n\nexport type SignupStepperListener = (state: SignupStepperState) => void;\n\n/** The locked credential constraints (PublicOnboardingSubmitRequest). */\nconst credentialsSchema = z.object({\n email: z.string().email(\"A valid account email is required\"),\n password: z\n .string()\n .min(12, \"Password must be at least 12 characters\")\n .max(256, \"Password must be at most 256 characters\"),\n});\n\nfunction zodIssuesToFieldErrors(issues: ZodIssue[]): FieldError[] {\n return issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n}\n\n/** Flatten a serviceSelection field's answer into service ids. */\nfunction serviceIdsOf(key: string, value: unknown): string[] {\n if (typeof value === \"string\" && value !== \"\") return [value];\n if (Array.isArray(value)) return value.map((v) => String(v));\n if (value === true) return [key];\n return [];\n}\n\nexport interface SignupStepperControl {\n getState(): SignupStepperState;\n setAnswer(key: string, value: unknown): void;\n setConsent(consent: Partial<SignupConsent>): void;\n setCredentials(credentials: Partial<SignupCredentials>): void;\n /** Validate ONLY the current step. Returns true when clean. */\n validateStep(): boolean;\n /** Validate current step; advance when clean. Returns true if advanced. */\n next(): boolean;\n back(): void;\n isFirstStep(): boolean;\n isLastStep(): boolean;\n /**\n * Full-form validation: every step's answers + credentials + consent.\n * Populates errors/accountErrors. Returns true when submittable.\n */\n validateAll(): boolean;\n /**\n * The submit payload body (minus botToken, which the transport attaches).\n * Call ONLY after validateAll() returns true.\n */\n buildSubmitPayload(): {\n specVersion: string;\n answers: Record<string, unknown>;\n selectedServices?: string[];\n consent: { tosAccepted: true; privacyAccepted: true };\n credentials: SignupCredentials;\n };\n /**\n * Swap in a refetched spec after 409 spec_stale. Drops answers for\n * removed fields, re-validates the rest, marks specStale, repositions\n * to the first step with errors. NEVER auto-resubmits.\n */\n applyNewSpec(spec: OnboardingSpec): void;\n /** Clear the specStale flag once the user has re-confirmed. */\n acknowledgeSpecStale(): void;\n setSubmitting(): void;\n setSuccess(terminalStage: TerminalStage): void;\n setError(message: string): void;\n /**\n * Reset to the pristine initial state against the CURRENT spec: step 0,\n * status \"editing\", answers/credentials/consent/errors cleared. This is\n * the only transition back OUT of \"success\"/\"error\"; the widget's reset()\n * relies on it (otherwise a post-success keystroke would re-emit\n * status \"success\" and re-hide the form).\n */\n reset(): void;\n subscribe(listener: SignupStepperListener): () => void;\n}\n\n/**\n * Create a headless stepper for the spec's signup form.\n *\n * @example\n * ```ts\n * const spec = await fetchOnboardingSpec({ baseUrl, onboarder });\n * const stepper = createSignupStepper(spec);\n * stepper.subscribe(render);\n * stepper.setAnswer(\"company_name\", \"ACME\");\n * if (stepper.next()) { ... }\n * ```\n */\nexport function createSignupStepper(\n spec: OnboardingSpec,\n): SignupStepperControl {\n let steps: SpecStep[] = spec.forms.signup.steps;\n let specVersion = spec.specVersion;\n\n let state: SignupStepperState = {\n stepIndex: 0,\n stepCount: steps.length,\n currentStep: steps[0] ?? null,\n answers: {},\n selectedServices: [],\n errors: [],\n accountErrors: [],\n consent: { tosAccepted: false, privacyAccepted: false },\n credentials: { email: \"\", password: \"\" },\n status: \"editing\",\n serverError: null,\n specStale: false,\n specVersion,\n terminalStage: null,\n };\n\n // Which step indices have been validated at least once. Once a step has\n // been validated, EVERY subsequent setAnswer revalidates it — so a\n // fix-then-rebreak on that step re-shows the error immediately (matching\n // the Phase-1 contact-form `hasValidated` fix). Before a step is validated,\n // typing does not spray errors. Cleared on reset()/applyNewSpec.\n let validatedSteps = new Set<number>();\n\n const listeners = new Set<SignupStepperListener>();\n\n function emit(): void {\n for (const listener of listeners) {\n listener(structuredClone(state));\n }\n }\n\n function knownFieldKeys(): Set<string> {\n const keys = new Set<string>();\n for (const step of steps) {\n for (const field of step.fields) keys.add(field.key);\n }\n return keys;\n }\n\n /** Answers restricted to the current step's fields. */\n function stepAnswers(step: SpecStep): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const field of step.fields) {\n if (field.key in state.answers) out[field.key] = state.answers[field.key];\n }\n return out;\n }\n\n function deriveSelectedServices(): string[] {\n const services: string[] = [];\n for (const step of steps) {\n for (const field of step.fields) {\n if (field.serviceSelection === true) {\n services.push(...serviceIdsOf(field.key, state.answers[field.key]));\n }\n }\n }\n return [...new Set(services)];\n }\n\n function runStepValidation(step: SpecStep): FieldError[] {\n const result = deriveStepSchema(step).safeParse(stepAnswers(step));\n return result.success ? [] : zodIssuesToFieldErrors(result.error.issues);\n }\n\n function firstStepWithErrors(): number {\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n if (step && runStepValidation(step).length > 0) return i;\n }\n return 0;\n }\n\n return {\n getState() {\n return structuredClone(state);\n },\n\n setAnswer(key, value) {\n state = {\n ...state,\n answers: { ...state.answers, [key]: value },\n };\n state.selectedServices = deriveSelectedServices();\n // Live-revalidate once THIS step has been validated at least once —\n // regardless of whether errors are currently showing. This is the\n // fix-then-rebreak fix: after fixing a field (errors → 0), breaking it\n // again must re-show the error without a fresh next()/validateStep().\n if (validatedSteps.has(state.stepIndex) && state.currentStep) {\n state = { ...state, errors: runStepValidation(state.currentStep) };\n }\n emit();\n },\n\n setConsent(consent) {\n state = { ...state, consent: { ...state.consent, ...consent } };\n emit();\n },\n\n setCredentials(credentials) {\n state = {\n ...state,\n credentials: { ...state.credentials, ...credentials },\n };\n emit();\n },\n\n validateStep() {\n if (!state.currentStep) return true;\n validatedSteps.add(state.stepIndex);\n const errors = runStepValidation(state.currentStep);\n state = { ...state, errors };\n emit();\n return errors.length === 0;\n },\n\n next() {\n if (!state.currentStep) return false;\n validatedSteps.add(state.stepIndex);\n const errors = runStepValidation(state.currentStep);\n if (errors.length > 0) {\n state = { ...state, errors };\n emit();\n return false;\n }\n if (state.stepIndex >= steps.length - 1) return false;\n const stepIndex = state.stepIndex + 1;\n state = {\n ...state,\n stepIndex,\n currentStep: steps[stepIndex] ?? null,\n errors: [],\n };\n emit();\n return true;\n },\n\n back() {\n if (state.stepIndex === 0) return;\n const stepIndex = state.stepIndex - 1;\n state = {\n ...state,\n stepIndex,\n currentStep: steps[stepIndex] ?? null,\n errors: [],\n };\n emit();\n },\n\n isFirstStep() {\n return state.stepIndex === 0;\n },\n\n isLastStep() {\n return state.stepIndex >= steps.length - 1;\n },\n\n validateAll() {\n // A full validation counts as validating every step.\n for (let i = 0; i < steps.length; i++) validatedSteps.add(i);\n // Answers across ALL steps (strict — unknown keys rejected).\n const answersResult = deriveAnswersSchema(steps).safeParse(state.answers);\n const errors = answersResult.success\n ? []\n : zodIssuesToFieldErrors(answersResult.error.issues);\n\n // Credentials + consent (locked submit contract).\n const accountErrors: FieldError[] = [];\n const credResult = credentialsSchema.safeParse(state.credentials);\n if (!credResult.success) {\n accountErrors.push(...zodIssuesToFieldErrors(credResult.error.issues));\n }\n if (state.consent.tosAccepted !== true) {\n accountErrors.push({\n path: \"tosAccepted\",\n message: \"You must accept the Terms of Service\",\n });\n }\n if (state.consent.privacyAccepted !== true) {\n accountErrors.push({\n path: \"privacyAccepted\",\n message: \"You must accept the Privacy Policy\",\n });\n }\n\n state = { ...state, errors, accountErrors };\n emit();\n return errors.length === 0 && accountErrors.length === 0;\n },\n\n buildSubmitPayload() {\n // COMPLIANCE-CRITICAL: never fabricate legal consent. Read the ACTUAL\n // consent state and refuse to build a payload unless the user genuinely\n // accepted both. A headless caller that skips validateAll() must not be\n // able to transmit consent:true for a user who never consented.\n if (\n state.consent.tosAccepted !== true ||\n state.consent.privacyAccepted !== true\n ) {\n throw new Error(\n \"buildSubmitPayload: cannot build a submit payload without genuine \" +\n \"user consent (tosAccepted && privacyAccepted must both be true). \" +\n \"Call validateAll() and surface the consent errors to the user first.\",\n );\n }\n\n // Run answers through the derived schema so the wire carries COERCED\n // typed values (e.g. number fields as numbers, not raw DOM strings) —\n // this is the exact validation validateAll() applies, so a payload can\n // only be built from a state that would pass. A required field that is\n // empty/missing FAILS here (see deriveFieldSchema's required wrap),\n // so buildSubmitPayload throws rather than silently dropping it.\n const parsed = deriveAnswersSchema(steps).safeParse(state.answers);\n if (!parsed.success) {\n const detail = parsed.error.issues\n .map((i) => `${i.path.join(\".\") || \"(answers)\"}: ${i.message}`)\n .join(\"; \");\n throw new Error(\n `buildSubmitPayload: answers failed validation — call validateAll() first (${detail}).`,\n );\n }\n\n // Only keys the active spec defines, with empty optionals omitted.\n const known = knownFieldKeys();\n const answers: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(parsed.data)) {\n if (known.has(key) && value !== undefined && value !== \"\") {\n answers[key] = value;\n }\n }\n const selectedServices = deriveSelectedServices();\n return {\n specVersion,\n answers,\n ...(selectedServices.length > 0 ? { selectedServices } : {}),\n consent: {\n tosAccepted: state.consent.tosAccepted,\n privacyAccepted: state.consent.privacyAccepted,\n } as { tosAccepted: true; privacyAccepted: true },\n credentials: { ...state.credentials },\n };\n },\n\n applyNewSpec(newSpec) {\n steps = newSpec.forms.signup.steps;\n specVersion = newSpec.specVersion;\n\n // Drop answers for fields the new spec no longer defines.\n const known = new Set<string>();\n for (const step of steps) {\n for (const field of step.fields) known.add(field.key);\n }\n const answers: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(state.answers)) {\n if (known.has(key)) answers[key] = value;\n }\n\n state = {\n ...state,\n answers,\n stepCount: steps.length,\n specVersion,\n specStale: true,\n status: \"editing\",\n serverError: null,\n };\n state.selectedServices = deriveSelectedServices();\n\n // Reposition to the first step with errors under the NEW schema so\n // the user reviews exactly what changed; errors render immediately.\n const stepIndex = Math.min(firstStepWithErrors(), steps.length - 1);\n const currentStep = steps[Math.max(stepIndex, 0)] ?? null;\n // The repositioned step is being shown with errors → treat it as\n // validated so live-revalidation is active there immediately.\n validatedSteps = new Set<number>([Math.max(stepIndex, 0)]);\n state = {\n ...state,\n stepIndex: Math.max(stepIndex, 0),\n currentStep,\n errors: currentStep ? runStepValidation(currentStep) : [],\n };\n emit();\n },\n\n acknowledgeSpecStale() {\n state = { ...state, specStale: false };\n emit();\n },\n\n setSubmitting() {\n state = {\n ...state,\n status: \"submitting\",\n serverError: null,\n };\n emit();\n },\n\n setSuccess(terminalStage) {\n state = { ...state, status: \"success\", terminalStage, serverError: null };\n emit();\n },\n\n setError(message) {\n state = { ...state, status: \"error\", serverError: message };\n emit();\n },\n\n reset() {\n validatedSteps = new Set<number>();\n state = {\n stepIndex: 0,\n stepCount: steps.length,\n currentStep: steps[0] ?? null,\n answers: {},\n selectedServices: [],\n errors: [],\n accountErrors: [],\n consent: { tosAccepted: false, privacyAccepted: false },\n credentials: { email: \"\", password: \"\" },\n status: \"editing\",\n serverError: null,\n specStale: false,\n specVersion,\n terminalStage: null,\n };\n emit();\n },\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/form/state.ts"],"names":[],"mappings":"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","file":"chunk-AFCJLUPK.js","sourcesContent":["/**\n * Headless form state manager for the contact form.\n *\n * Designed to be framework-agnostic — callers supply a change callback\n * and call the returned mutators. The widget layer uses this internally;\n * framework integrations (React, Vue, etc.) can wrap it in their own hooks.\n */\n\nimport type { ZodIssue } from \"zod/v3\";\nimport { contactFormSchema, type ContactFormValues } from \"./schema.js\";\n\nexport interface FieldError {\n path: string;\n message: string;\n}\n\nexport type FormStatus = \"idle\" | \"submitting\" | \"success\" | \"error\";\n\nexport interface ContactFormState {\n values: ContactFormValues;\n /** Per-field validation errors from the last validate() call. */\n errors: FieldError[];\n /** Cross-field / server error message. */\n serverError: string | null;\n status: FormStatus;\n /** True if values have been touched at least once. */\n dirty: boolean;\n}\n\nexport type ContactFormStateListener = (state: ContactFormState) => void;\n\nexport interface ContactFormControl {\n /** Current snapshot of form state. */\n getState(): ContactFormState;\n /** Update a single field value and re-validate if dirty. */\n setValue<K extends keyof ContactFormValues>(\n field: K,\n value: ContactFormValues[K],\n ): void;\n /**\n * Run full client-side validation. Returns true if valid.\n * Also marks the form dirty so future setValue calls auto-validate.\n */\n validate(): boolean;\n /** Mark the form as submitting. Called by the submit client. */\n setSubmitting(): void;\n /** Mark the form as successfully submitted. */\n setSuccess(): void;\n /** Set a server-side error (e.g. 429 rate limited). */\n setError(message: string): void;\n /** Reset to initial idle state. */\n reset(): void;\n /** Subscribe to state changes. Returns unsubscribe function. */\n subscribe(listener: ContactFormStateListener): () => void;\n}\n\nfunction zodIssuesToFieldErrors(issues: ZodIssue[]): FieldError[] {\n return issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n}\n\nconst INITIAL_VALUES: ContactFormValues = {\n name: \"\",\n email: \"\",\n phone: undefined,\n message: undefined,\n};\n\n/**\n * Create a new headless contact form state controller.\n *\n * @example\n * ```ts\n * const form = createContactFormState();\n * form.subscribe((state) => renderUI(state));\n * form.setValue(\"name\", \"Alice\");\n * const valid = form.validate();\n * if (valid) await submitContact(form.getState().values, botToken);\n * ```\n */\nexport function createContactFormState(): ContactFormControl {\n let state: ContactFormState = {\n values: { ...INITIAL_VALUES },\n errors: [],\n serverError: null,\n status: \"idle\",\n dirty: false,\n };\n\n const listeners = new Set<ContactFormStateListener>();\n\n function emit(): void {\n for (const listener of listeners) {\n listener({ ...state, values: { ...state.values } });\n }\n }\n\n function runValidation(): FieldError[] {\n const result = contactFormSchema.safeParse(state.values);\n if (result.success) return [];\n return zodIssuesToFieldErrors(result.error.issues);\n }\n\n // Once validate() has run at least once, EVERY subsequent setValue\n // revalidates — errors both clear when a field is fixed AND reappear\n // when a fixed field is broken again. (Previously the revalidation was\n // gated on errors.length > 0, so fix-then-rebreak silently showed no\n // error until the next explicit validate().)\n let hasValidated = false;\n\n return {\n getState() {\n return { ...state, values: { ...state.values } };\n },\n\n setValue(field, value) {\n state = {\n ...state,\n values: { ...state.values, [field]: value },\n dirty: true,\n };\n if (hasValidated) {\n state = { ...state, errors: runValidation() };\n }\n emit();\n },\n\n validate() {\n hasValidated = true;\n const errors = runValidation();\n state = { ...state, errors, dirty: true };\n emit();\n return errors.length === 0;\n },\n\n setSubmitting() {\n state = { ...state, status: \"submitting\", serverError: null, errors: [] };\n emit();\n },\n\n setSuccess() {\n state = { ...state, status: \"success\", serverError: null };\n emit();\n },\n\n setError(message) {\n state = { ...state, status: \"error\", serverError: message };\n emit();\n },\n\n reset() {\n hasValidated = false;\n state = {\n values: { ...INITIAL_VALUES },\n errors: [],\n serverError: null,\n status: \"idle\",\n dirty: false,\n };\n emit();\n },\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/submit/errors.ts","../src/submit/http.ts"],"names":[],"mappings":"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","file":"chunk-AW7W3HAC.js","sourcesContent":["/**\n * Error taxonomy for the onboarding submit client.\n *\n * Maps HTTP status codes and server error bodies to typed errors:\n * 403 bot_challenge_failed → OnboardingBotChallengeError\n * 409 spec_stale (SUBMIT) → OnboardingSpecStaleError (submit endpoint only,\n * body { error:true, code:\"spec_stale\",\n * currentSpecVersion })\n * 409 (other / LEADS) → OnboardingConflictError (generic conflict)\n * 429 → OnboardingRateLimitError\n * 5xx → OnboardingServerError (retryable)\n * network / timeout → OnboardingNetworkError\n */\n\nexport type OnboardingErrorKind =\n | \"bot_challenge_failed\"\n | \"spec_stale\"\n | \"spec_invalid\"\n | \"conflict\"\n | \"rate_limited\"\n | \"server_error\"\n | \"network_error\"\n | \"validation_error\";\n\nexport class OnboardingError extends Error {\n public readonly kind: OnboardingErrorKind;\n public readonly statusCode: number | null;\n\n constructor(\n kind: OnboardingErrorKind,\n message: string,\n statusCode: number | null = null,\n ) {\n super(message);\n this.name = \"OnboardingError\";\n this.kind = kind;\n this.statusCode = statusCode;\n }\n}\n\nexport class OnboardingBotChallengeError extends OnboardingError {\n constructor(message?: string) {\n super(\n \"bot_challenge_failed\",\n message ??\n \"Bot challenge verification failed (403 bot_challenge_failed). Refresh the CAPTCHA and try again.\",\n 403,\n );\n this.name = \"OnboardingBotChallengeError\";\n }\n}\n\n/**\n * A 409 that is NOT spec_stale. On the /leads path there is no spec_stale\n * concept (the payload carries no specVersion); on /submit, a 409 that\n * lacks `code:\"spec_stale\"` also lands here. Distinct from\n * OnboardingSpecStaleError so headless consumers switching on `kind` get the\n * correct diagnosis (a generic conflict, e.g. a D538 same-key concurrent\n * race) rather than a \"form has been updated, refresh\" recovery message.\n */\nexport class OnboardingConflictError extends OnboardingError {\n constructor(statusCode = 409, message?: string) {\n super(\n \"conflict\",\n message ??\n `Request conflicted with the current server state (${statusCode}).`,\n statusCode,\n );\n this.name = \"OnboardingConflictError\";\n }\n}\n\nexport class OnboardingRateLimitError extends OnboardingError {\n public readonly retryAfterSeconds: number | null;\n\n constructor(retryAfterSeconds: number | null = null) {\n super(\n \"rate_limited\",\n retryAfterSeconds !== null\n ? `Rate limited. Retry after ${retryAfterSeconds}s.`\n : \"Rate limited. Please wait before retrying.\",\n 429,\n );\n this.name = \"OnboardingRateLimitError\";\n this.retryAfterSeconds = retryAfterSeconds;\n }\n}\n\n/**\n * A /submit 409 whose body carries `code:\"spec_stale\"` (D540 reject-stale).\n * The PINNED body shape (confirmed against the crm intake) is exactly:\n * { error: true, code: \"spec_stale\", currentSpecVersion: string }\n * The version is read ONLY from `currentSpecVersion` — no field hedging.\n * Submit-endpoint only; /leads 409s are OnboardingConflictError.\n */\nexport class OnboardingSpecStaleError extends OnboardingError {\n public readonly currentSpecVersion: string;\n\n constructor(currentSpecVersion: string) {\n super(\n \"spec_stale\",\n `The onboarding form has been updated (new version: ${currentSpecVersion}). Please refresh and try again.`,\n 409,\n );\n this.name = \"OnboardingSpecStaleError\";\n this.currentSpecVersion = currentSpecVersion;\n }\n}\n\nexport class OnboardingServerError extends OnboardingError {\n constructor(statusCode: number, message?: string) {\n super(\n \"server_error\",\n message ?? `Server error (${statusCode}). The request will be retried.`,\n statusCode,\n );\n this.name = \"OnboardingServerError\";\n }\n}\n\nexport class OnboardingNetworkError extends OnboardingError {\n constructor(cause?: unknown) {\n super(\n \"network_error\",\n \"Network error — check your connection and try again.\",\n null,\n );\n this.name = \"OnboardingNetworkError\";\n if (cause instanceof Error) {\n this.cause = cause;\n }\n }\n}\n\nexport class OnboardingValidationError extends OnboardingError {\n constructor(message: string) {\n super(\"validation_error\", message, 422);\n this.name = \"OnboardingValidationError\";\n }\n}\n\n/**\n * The spec endpoint returned a body that does not conform to the LOCKED\n * D540 §1 response shape. This is a server-side contract violation — the\n * SDK refuses to render a form from a malformed spec (a half-parsed spec\n * could silently drop required fields).\n */\nexport class OnboardingSpecInvalidError extends OnboardingError {\n constructor(detail: string) {\n super(\n \"spec_invalid\",\n `The onboarding spec response does not match the D540 contract: ${detail}`,\n null,\n );\n this.name = \"OnboardingSpecInvalidError\";\n }\n}\n","/**\n * Shared HTTP helper: fetch bounded by a timeout via AbortController.\n *\n * Every SDK wire call (spec fetch, leads submit, signup submit) MUST be\n * bounded — the widgets flip to a disabled/\"Sending…\"/\"Loading…\" state\n * BEFORE the await, so an intake that accepts the connection and then stalls\n * would otherwise hang the UI forever. On timeout the fetch is aborted and a\n * typed OnboardingNetworkError is raised by the caller (which maps abort/\n * network failures uniformly).\n */\n\n/** Default per-request timeout. Generous enough for a slow-but-alive intake. */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;\n\nexport interface TimeoutFetchOptions extends RequestInit {\n /** Per-request timeout in ms. Default DEFAULT_REQUEST_TIMEOUT_MS. */\n timeoutMs?: number;\n /** The fetch implementation to use (defaults to globalThis.fetch). */\n fetchImpl?: typeof globalThis.fetch;\n}\n\n/**\n * fetch() with a hard timeout. Aborts the request when the deadline elapses;\n * the resulting AbortError propagates to the caller (who wraps it as an\n * OnboardingNetworkError). A caller-supplied `signal` is respected too — if\n * either the caller aborts OR the timeout fires, the request is aborted.\n */\nexport async function fetchWithTimeout(\n url: string,\n options: TimeoutFetchOptions = {},\n): Promise<Response> {\n const {\n timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS,\n fetchImpl = globalThis.fetch,\n signal: callerSignal,\n ...init\n } = options;\n\n const controller = new AbortController();\n const timer = setTimeout(() => {\n controller.abort(new Error(`request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n // Forward a caller abort into our controller.\n if (callerSignal) {\n if (callerSignal.aborted) {\n clearTimeout(timer);\n controller.abort(callerSignal.reason);\n } else {\n callerSignal.addEventListener(\n \"abort\",\n () => controller.abort(callerSignal.reason),\n { once: true },\n );\n }\n }\n\n try {\n return await fetchImpl(url, { ...init, signal: controller.signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Run a promise with a timeout. On timeout, rejects with `onTimeout()`'s\n * error. Used to bound calls that don't take an AbortSignal (grecaptcha\n * .execute()). The underlying op is NOT cancelled (grecaptcha has no abort),\n * but the caller no longer waits on it — the widget re-enables.\n */\nexport function withTimeout<T>(\n op: Promise<T>,\n timeoutMs: number,\n onTimeout: () => Error,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n reject(onTimeout());\n }, timeoutMs);\n op.then(\n (v) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(v);\n },\n (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n"]}
|
package/dist/chunk-BIFANV7M.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod/v3';
|
|
2
|
-
|
|
3
|
-
// src/form/schema.ts
|
|
4
|
-
var contactFormSchema = z.object({
|
|
5
|
-
name: z.string().min(1, "Name is required").max(200, "Name must be 200 characters or fewer"),
|
|
6
|
-
email: z.string().email("A valid email address is required"),
|
|
7
|
-
phone: z.string().optional(),
|
|
8
|
-
message: z.string().max(4e3, "Message must be 4000 characters or fewer").optional()
|
|
9
|
-
});
|
|
10
|
-
var leadsWireSchema = contactFormSchema.extend({
|
|
11
|
-
botToken: z.string().min(1, "botToken is required")
|
|
12
|
-
}).strict();
|
|
13
|
-
function validateContactForm(values) {
|
|
14
|
-
return contactFormSchema.safeParse(values);
|
|
15
|
-
}
|
|
16
|
-
function validateLeadsPayload(payload) {
|
|
17
|
-
return leadsWireSchema.safeParse(payload);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export { contactFormSchema, leadsWireSchema, validateContactForm, validateLeadsPayload };
|
|
21
|
-
//# sourceMappingURL=chunk-BIFANV7M.js.map
|
|
22
|
-
//# sourceMappingURL=chunk-BIFANV7M.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/form/schema.ts"],"names":[],"mappings":";;;AAyBO,IAAM,iBAAA,GAAoB,EAAE,MAAA,CAAO;AAAA,EACxC,IAAA,EAAM,CAAA,CACH,MAAA,EAAO,CACP,GAAA,CAAI,GAAG,kBAAkB,CAAA,CACzB,GAAA,CAAI,GAAA,EAAK,sCAAsC,CAAA;AAAA,EAClD,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,MAAM,mCAAmC,CAAA;AAAA,EAC3D,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,OAAA,EAAS,EACN,MAAA,EAAO,CACP,IAAI,GAAA,EAAM,0CAA0C,EACpD,QAAA;AACL,CAAC;AAYM,IAAM,eAAA,GAAkB,kBAC5B,MAAA,CAAO;AAAA,EACN,UAAU,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,sBAAsB;AACpD,CAAC,EACA,MAAA;AAQI,SAAS,oBAAoB,MAAA,EAAiB;AACnD,EAAA,OAAO,iBAAA,CAAkB,UAAU,MAAM,CAAA;AAC3C;AAQO,SAAS,qBAAqB,OAAA,EAAkB;AACrD,EAAA,OAAO,eAAA,CAAgB,UAAU,OAAO,CAAA;AAC1C","file":"chunk-BIFANV7M.js","sourcesContent":["/**\n * Contact-form Zod schema — mirrors the LOCKED hub REST contract exactly:\n * POST /api/v1/public/onboarding/leads\n * Schema: PublicOnboardingLeadsRequest (hub id 8686dd33)\n *\n * Constraints (per hub JSON Schema):\n * name — string, 1-200 chars, required\n * email — email format, required\n * phone — string, optional (no server-side constraint beyond string)\n * message — string, ≤4000 chars, optional\n * botToken — string, required (reCAPTCHA token, D537)\n *\n * additionalProperties: false\n *\n * The schema intentionally does NOT include botToken in the public-facing\n * ContactFormValues type — that field is injected by the submit client right\n * before the POST (the widget/form never exposes it to the user).\n */\n\nimport { z } from \"zod/v3\";\n\n/**\n * The user-visible contact form fields. Validated client-side for UX.\n * Server re-validates authoritatively (D540 §2).\n */\nexport const contactFormSchema = z.object({\n name: z\n .string()\n .min(1, \"Name is required\")\n .max(200, \"Name must be 200 characters or fewer\"),\n email: z.string().email(\"A valid email address is required\"),\n phone: z.string().optional(),\n message: z\n .string()\n .max(4000, \"Message must be 4000 characters or fewer\")\n .optional(),\n});\n\nexport type ContactFormValues = z.infer<typeof contactFormSchema>;\n\n/**\n * The full wire payload — contactFormSchema + botToken.\n *\n * STRICT mode: unknown keys are REJECTED (not stripped), mirroring the\n * server's `additionalProperties: false`. `submitLead` runs every outgoing\n * payload through this schema before the POST — an extra key never reaches\n * the wire; it fails fast client-side with OnboardingValidationError.\n */\nexport const leadsWireSchema = contactFormSchema\n .extend({\n botToken: z.string().min(1, \"botToken is required\"),\n })\n .strict();\n\nexport type LeadsWirePayload = z.infer<typeof leadsWireSchema>;\n\n/**\n * Validate user-visible form values (no botToken required here).\n * Returns a Zod SafeParseReturnType (inferred).\n */\nexport function validateContactForm(values: unknown) {\n return contactFormSchema.safeParse(values);\n}\n\n/**\n * Validate the full wire payload (including botToken) before submission.\n * STRICT: unknown keys are rejected, matching additionalProperties:false.\n * This is the exact validation `submitLead` applies on the wire path.\n * Returns a Zod SafeParseReturnType (inferred).\n */\nexport function validateLeadsPayload(payload: unknown) {\n return leadsWireSchema.safeParse(payload);\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/submit/client.ts","../src/submit/signup-client.ts"],"names":["MAX_ATTEMPTS","RETRY_DELAYS_MS","buildUrl","parseRetryAfter","sleep"],"mappings":"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","file":"chunk-BQCTDU5V.js","sourcesContent":["/**\n * Submit client for POST /api/v1/public/onboarding/leads.\n *\n * Contract per D540 + hub REST interface 8686dd33:\n * - Idempotency-Key header REQUIRED (uuid v4, generated ONCE per logical\n * submission, REUSED on retries — same key = exactly-once delivery).\n * - Outgoing payload validated through leadsWireSchema (STRICT — unknown\n * keys rejected, matching additionalProperties:false) BEFORE any fetch.\n * - botToken in request body (D537).\n * - Response: { accepted: true } on 200/202 (empty/non-JSON 2xx body is\n * treated as acceptance; a JSON body that does not confirm acceptance\n * throws OnboardingServerError — see parseSuccessBody).\n * - 403 bot_challenge_failed → throw OnboardingBotChallengeError (no retry)\n * - 409 spec_stale (D540) → throw OnboardingSpecStaleError (no retry)\n * - 422 → throw OnboardingValidationError (no retry)\n * - 429 → throw OnboardingRateLimitError (no auto-retry)\n * - 5xx → retry with SAME idempotency key, capped backoff\n * - network error → retry with SAME idempotency key, capped backoff\n *\n * Max retries: 3 attempts total (1 initial + 2 retries).\n * Backoff: 1s, 2s (capped at 2 retries).\n */\n\nimport { validateLeadsPayload } from \"../form/schema.js\";\nimport type { ContactFormValues } from \"../form/schema.js\";\nimport {\n OnboardingBotChallengeError,\n OnboardingConflictError,\n OnboardingNetworkError,\n OnboardingRateLimitError,\n OnboardingServerError,\n OnboardingValidationError,\n} from \"./errors.js\";\nimport { DEFAULT_REQUEST_TIMEOUT_MS, fetchWithTimeout } from \"./http.js\";\n\nconst LEADS_PATH = \"/api/v1/public/onboarding/leads\";\nconst MAX_ATTEMPTS = 3;\nconst RETRY_DELAYS_MS = [1000, 2000] as const;\n\n/**\n * Resolve a bot token inside the retry loop, mapping ANY provider failure to\n * a typed OnboardingBotChallengeError. The provider is usually\n * executeRecaptcha, which throws a RecaptchaError if reCAPTCHA is unreachable\n * — that raw error must NOT escape submitLead/submitSignup (the @throws\n * contract is Onboarding* only) and must not silently burn the retry budget.\n */\nexport async function resolveBotTokenGuarded(\n source: BotTokenSource,\n): Promise<string> {\n try {\n return await resolveBotToken(source);\n } catch (err) {\n throw new OnboardingBotChallengeError(\n err instanceof Error\n ? `Could not obtain a bot-challenge token: ${err.message}`\n : \"Could not obtain a bot-challenge token.\",\n );\n }\n}\n\n/**\n * A bot token, or a provider that mints a FRESH one per attempt.\n *\n * reCAPTCHA tokens are SINGLE-USE — the server consumes them at siteverify.\n * If a 5xx happens AFTER the token was consumed, resending the same token on\n * retry gets 403. Pass a provider function to mint a fresh token per attempt;\n * a bare string is back-compat but the caller then OWNS that risk.\n */\nexport type BotTokenSource = string | (() => string | Promise<string>);\n\nexport async function resolveBotToken(source: BotTokenSource): Promise<string> {\n return typeof source === \"function\" ? source() : source;\n}\n\nexport interface LeadsSubmitOptions {\n baseUrl: string;\n /**\n * reCAPTCHA token (D537), or a provider called ONCE PER ATTEMPT to mint a\n * fresh token (recommended — tokens are single-use; a fixed string on a\n * retried request risks 403 after the first attempt consumed it).\n */\n botToken: BotTokenSource;\n /**\n * Stable idempotency key for this submission. Generate ONCE with\n * `generateIdempotencyKey()` and pass the same key for retries.\n * The server chains this key through to D538 for exactly-once delivery.\n */\n idempotencyKey: string;\n /** Optional custom fetch implementation (defaults to global fetch). */\n fetch?: typeof globalThis.fetch;\n /**\n * Per-attempt request timeout in ms (default 15s). A stalled intake aborts\n * with OnboardingNetworkError so the widget re-enables instead of hanging.\n */\n timeoutMs?: number;\n /** Optional onAttempt callback for observability (attempt number, 1-based). */\n onAttempt?: (attempt: number) => void;\n}\n\nexport interface LeadsSubmitResult {\n accepted: true;\n}\n\n/**\n * Generate a stable idempotency key for one logical submission.\n * Uses the Web Crypto API (available in all modern browsers + Bun/Node >= 19).\n * Call ONCE per user submission, pass the SAME key on retries.\n */\nexport function generateIdempotencyKey(): string {\n // crypto.randomUUID() is available in all modern browsers, Bun, and Node >= 14.17\n return globalThis.crypto.randomUUID();\n}\n\nfunction buildUrl(baseUrl: string, path: string): string {\n const base = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n return `${base}${path}`;\n}\n\nfunction parseRetryAfter(response: Response): number | null {\n const header = response.headers.get(\"retry-after\");\n if (!header) return null;\n const seconds = Number.parseInt(header, 10);\n return Number.isNaN(seconds) ? null : seconds;\n}\n\nasync function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Compute a stable fingerprint of the outgoing lead payload, EXCLUDING\n * botToken (which is fresh per attempt by design).\n *\n * The widget uses this to decide whether a resubmission is a RETRY of the\n * same logical submission (same fingerprint → reuse the Idempotency-Key)\n * or a NEW logical submission (fingerprint changed because the user edited\n * fields → mint a NEW key). This mirrors the server's D538 payload-match\n * guard: same key + different payload is INVALID_ARGUMENT server-side.\n *\n * FNV-1a 32-bit over a stable JSON serialization of [name, email, phone,\n * message]. Collision risk is irrelevant here — a collision only means an\n * unnecessary key reuse across two submissions from the same browser tab.\n */\nexport function computePayloadFingerprint(values: ContactFormValues): string {\n const canonical = JSON.stringify([\n values.name,\n values.email,\n values.phone ?? null,\n values.message ?? null,\n ]);\n let hash = 0x811c9dc5;\n for (let i = 0; i < canonical.length; i++) {\n hash ^= canonical.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Parse a success-status (200/202) response body.\n *\n * Documented behavior (one rule, tested):\n * - EMPTY body or NON-JSON body → treated as acceptance. The locked\n * contract response is `{accepted:true}` and the status is already\n * 2xx; load balancers / CDNs occasionally strip or replace bodies on\n * 202, and a 2xx from the intake IS the acceptance signal.\n * - A PARSEABLE JSON body that is not `{accepted: true}` (e.g.\n * `{accepted:false}` or an unrelated shape) → OnboardingServerError.\n * A server-signaled soft-rejection on a success status must NOT be\n * masked as success. Not auto-retried (the status was 2xx; the server\n * state is ambiguous — the caller decides).\n */\nasync function parseSuccessBody(\n response: Response,\n): Promise<LeadsSubmitResult> {\n let text: string;\n try {\n text = await response.text();\n } catch {\n // Unreadable body on a 2xx — acceptance per the rule above.\n return { accepted: true };\n }\n if (text.trim() === \"\") {\n return { accepted: true };\n }\n let json: unknown;\n try {\n json = JSON.parse(text);\n } catch {\n // Non-JSON body on a 2xx (LB/CDN interstitial) — acceptance.\n return { accepted: true };\n }\n if (\n typeof json === \"object\" &&\n json !== null &&\n (json as { accepted?: unknown }).accepted === true\n ) {\n return { accepted: true };\n }\n throw new OnboardingServerError(\n response.status,\n `Success status ${response.status} but response body did not confirm acceptance.`,\n );\n}\n\n/**\n * Submit a contact-form lead to the onboarding intake.\n *\n * The outgoing payload is validated through leadsWireSchema in STRICT mode\n * before any network I/O — unknown keys are rejected client-side, exactly\n * mirroring the server's additionalProperties:false.\n *\n * Handles retry semantics: 5xx and network errors are retried up to\n * MAX_ATTEMPTS total, always with the SAME idempotencyKey to guarantee\n * exactly-once server-side processing (D538 idempotency chain).\n *\n * 403, 409, 422 and 429 are NOT retried — caller handles them.\n *\n * @throws {OnboardingValidationError} if the payload fails the strict wire\n * schema (unknown keys, constraint violations) — thrown BEFORE any fetch\n * @throws {OnboardingBotChallengeError} on 403, or if the bot-token provider\n * throws (reCAPTCHA unreachable) on any attempt\n * @throws {OnboardingConflictError} on 409 (leads has no spec_stale concept)\n * @throws {OnboardingRateLimitError} on 429\n * @throws {OnboardingServerError} on 5xx after all retries exhausted, or on\n * a 2xx whose JSON body does not confirm acceptance\n * @throws {OnboardingNetworkError} on network failure OR timeout after all\n * retries exhausted\n * @throws {OnboardingValidationError} on 422 (server-side re-validation)\n */\nexport async function submitLead(\n values: ContactFormValues,\n options: LeadsSubmitOptions,\n): Promise<LeadsSubmitResult> {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const url = buildUrl(options.baseUrl, LEADS_PATH);\n\n // Normalize non-token fields once (empty optionals → omitted). The token\n // is attached PER ATTEMPT below so a retry can carry a FRESH single-use\n // token; the body is therefore serialized inside the loop.\n const base: Record<string, unknown> = { ...values };\n if (base[\"phone\"] === \"\" || base[\"phone\"] === undefined) {\n delete base[\"phone\"];\n }\n if (base[\"message\"] === \"\" || base[\"message\"] === undefined) {\n delete base[\"message\"];\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": options.idempotencyKey,\n };\n\n let lastError: unknown = null;\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n options.onAttempt?.(attempt);\n\n // Mint a fresh token per attempt (single-use tokens; see BotTokenSource).\n // Guarded: a provider failure (reCAPTCHA down) becomes a typed\n // OnboardingBotChallengeError, never a raw RecaptchaError escaping.\n const botToken = await resolveBotTokenGuarded(options.botToken);\n\n // Strict wire-schema validation BEFORE the network I/O of THIS attempt.\n // Extra keys are REJECTED (additionalProperties:false), not stripped.\n const parsed = validateLeadsPayload({ ...base, botToken });\n if (!parsed.success) {\n const detail = parsed.error.issues\n .map((i) => `${i.path.join(\".\") || \"(payload)\"}: ${i.message}`)\n .join(\"; \");\n throw new OnboardingValidationError(\n `Payload failed wire-schema validation: ${detail}`,\n );\n }\n const body = JSON.stringify(parsed.data);\n\n let response: Response;\n\n try {\n response = await fetchWithTimeout(url, {\n method: \"POST\",\n headers,\n body,\n timeoutMs,\n fetchImpl,\n });\n } catch (err) {\n // Timeout (abort) and network failures are both retryable transient.\n lastError = new OnboardingNetworkError(err);\n const delay = RETRY_DELAYS_MS[attempt - 1];\n if (attempt < MAX_ATTEMPTS && delay !== undefined) {\n await sleep(delay);\n continue;\n }\n throw lastError;\n }\n\n // 200/202 → success (body parse guarded; see parseSuccessBody)\n if (response.status === 200 || response.status === 202) {\n return parseSuccessBody(response);\n }\n\n // 403 → bot challenge failed — NOT retryable\n if (response.status === 403) {\n throw new OnboardingBotChallengeError();\n }\n\n // 409 on /leads is NOT spec_stale (the leads payload has no specVersion;\n // spec_stale is a /submit-only concept per D540). A leads 409 is a\n // generic conflict (e.g. a D538 same-key concurrent-processing race) —\n // surface OnboardingConflictError so headless consumers switching on\n // `kind` get the right diagnosis, not a \"form has been updated\" message.\n if (response.status === 409) {\n throw new OnboardingConflictError(409);\n }\n\n // 429 → rate limited — NOT auto-retried (caller decides when to retry)\n if (response.status === 429) {\n const retryAfter = parseRetryAfter(response);\n throw new OnboardingRateLimitError(retryAfter);\n }\n\n // 422 → validation error (client-side should have caught this)\n if (response.status === 422) {\n throw new OnboardingValidationError(\n \"Server rejected the submission (422). Please check your inputs.\",\n );\n }\n\n // 5xx → retryable server error\n if (response.status >= 500) {\n lastError = new OnboardingServerError(response.status);\n const delay = RETRY_DELAYS_MS[attempt - 1];\n if (attempt < MAX_ATTEMPTS && delay !== undefined) {\n await sleep(delay);\n continue;\n }\n throw lastError;\n }\n\n // Any other unexpected status\n throw new OnboardingServerError(\n response.status,\n `Unexpected response status ${response.status}`,\n );\n }\n\n // Should not be reachable; guard for type safety\n throw lastError ?? new OnboardingNetworkError();\n}\n","/**\n * Submit client for POST /api/v1/public/onboarding/submit (D540 §2).\n *\n * Contract per the LOCKED hub REST interface (PublicOnboardingSubmitRequest):\n * - Body: { specVersion, answers, selectedServices?, botToken,\n * consent:{tosAccepted:true, privacyAccepted:true},\n * credentials:{email, password(12-256)} }\n * additionalProperties: false — validated STRICTLY client-side before\n * any fetch (unknown keys are rejected, not stripped).\n * - Idempotency-Key header REQUIRED (same D538 discipline as leads:\n * stable across retries of the SAME payload; the widget mints a new\n * key when the payload fingerprint changes).\n * - specVersion policy is reject-stale: 409 → OnboardingSpecStaleError\n * carrying the server's current version. The CALLER refetches the spec\n * and surfaces re-validation to the user — NEVER silent auto-resubmit.\n * - Response: { accepted:true, terminalStage, verificationEmailSent? }.\n *\n * Success-body rule for /submit (DIFFERENT from /leads, deliberately):\n * the response carries REQUIRED routing data (terminalStage decides what\n * the UI shows next), so a 2xx with an empty/unparseable/garbage body is\n * an OnboardingServerError — the SDK will not fabricate a terminal stage.\n * (/leads tolerates body-less 2xx because its only signal IS the status.)\n */\n\nimport { z } from \"zod/v3\";\nimport type { TerminalStage } from \"../spec/model.js\";\nimport {\n OnboardingBotChallengeError,\n OnboardingConflictError,\n OnboardingNetworkError,\n OnboardingRateLimitError,\n OnboardingServerError,\n OnboardingSpecStaleError,\n OnboardingValidationError,\n} from \"./errors.js\";\nimport { type BotTokenSource, resolveBotTokenGuarded } from \"./client.js\";\nimport { DEFAULT_REQUEST_TIMEOUT_MS, fetchWithTimeout } from \"./http.js\";\n\nconst SUBMIT_PATH = \"/api/v1/public/onboarding/submit\";\nconst MAX_ATTEMPTS = 3;\nconst RETRY_DELAYS_MS = [1000, 2000] as const;\n\n/**\n * STRICT wire schema — mirrors PublicOnboardingSubmitRequest exactly\n * (additionalProperties: false; consent booleans are const-true; password\n * length 12-256 per the locked schema).\n */\nexport const signupWireSchema = z\n .object({\n specVersion: z.string().min(1, \"specVersion is required\"),\n answers: z.record(z.unknown()),\n selectedServices: z.array(z.string()).optional(),\n botToken: z.string().min(1, \"botToken is required\"),\n consent: z\n .object({\n tosAccepted: z.literal(true, {\n errorMap: () => ({ message: \"Terms of Service must be accepted\" }),\n }),\n privacyAccepted: z.literal(true, {\n errorMap: () => ({ message: \"Privacy Policy must be accepted\" }),\n }),\n })\n .strict(),\n credentials: z\n .object({\n email: z.string().email(\"A valid account email is required\"),\n password: z\n .string()\n .min(12, \"Password must be at least 12 characters\")\n .max(256, \"Password must be at most 256 characters\"),\n })\n .strict(),\n })\n .strict();\n\nexport type SignupWirePayload = z.infer<typeof signupWireSchema>;\n\n/** The payload the caller assembles (botToken attached by the transport). */\nexport interface SignupSubmitBody {\n specVersion: string;\n answers: Record<string, unknown>;\n selectedServices?: string[];\n consent: { tosAccepted: true; privacyAccepted: true };\n credentials: { email: string; password: string };\n}\n\nexport interface SignupSubmitOptions {\n baseUrl: string;\n /**\n * reCAPTCHA token (D537), or a provider called ONCE PER ATTEMPT to mint a\n * fresh token. Tokens are single-use (consumed at siteverify), so a fixed\n * string on a retried request risks 403 after the first attempt consumed\n * it — pass a provider for retry-safe recovery.\n */\n botToken: BotTokenSource;\n /** Stable idempotency key — same discipline as submitLead. */\n idempotencyKey: string;\n fetch?: typeof globalThis.fetch;\n /**\n * Per-attempt request timeout in ms (default 15s). A stalled intake aborts\n * with OnboardingNetworkError so the widget re-enables instead of hanging.\n */\n timeoutMs?: number;\n onAttempt?: (attempt: number) => void;\n}\n\nexport interface SignupSubmitResult {\n accepted: true;\n /** Stage the existing engine landed the applicant at (D540 §2). */\n terminalStage: TerminalStage;\n verificationEmailSent?: boolean;\n}\n\n/**\n * Stable fingerprint of a signup submission, EXCLUDING botToken (fresh per\n * attempt by design). Same role as computePayloadFingerprint for leads:\n * same fingerprint ⇒ retry (reuse the Idempotency-Key); changed\n * fingerprint ⇒ new logical submission (mint a new key) — mirroring the\n * server's D538 payload-match guard.\n */\nexport function computeSignupFingerprint(body: SignupSubmitBody): string {\n const canonical = JSON.stringify([\n body.specVersion,\n // Sort answer keys for stability regardless of insertion order.\n Object.keys(body.answers)\n .sort()\n .map((k) => [k, body.answers[k]]),\n [...(body.selectedServices ?? [])].sort(),\n body.credentials.email,\n body.credentials.password,\n body.consent.tosAccepted,\n body.consent.privacyAccepted,\n ]);\n let hash = 0x811c9dc5;\n for (let i = 0; i < canonical.length; i++) {\n hash ^= canonical.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\nfunction buildUrl(baseUrl: string, path: string): string {\n const base = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n return `${base}${path}`;\n}\n\nfunction parseRetryAfter(response: Response): number | null {\n const header = response.headers.get(\"retry-after\");\n if (!header) return null;\n const seconds = Number.parseInt(header, 10);\n return Number.isNaN(seconds) ? null : seconds;\n}\n\nasync function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nconst TERMINAL_STAGES: readonly TerminalStage[] = [\n \"prospect\",\n \"inactive\",\n \"active\",\n];\n\n/** Parse the REQUIRED submit response shape; anything else → ServerError. */\nasync function parseSubmitSuccess(\n response: Response,\n): Promise<SignupSubmitResult> {\n let json: unknown;\n try {\n json = await response.json();\n } catch {\n throw new OnboardingServerError(\n response.status,\n `Success status ${response.status} but the submit response body was not JSON — terminalStage is unknown.`,\n );\n }\n if (\n typeof json === \"object\" &&\n json !== null &&\n (json as { accepted?: unknown }).accepted === true\n ) {\n const stage = (json as { terminalStage?: unknown }).terminalStage;\n if (\n typeof stage === \"string\" &&\n (TERMINAL_STAGES as readonly string[]).includes(stage)\n ) {\n const verificationEmailSent = (\n json as { verificationEmailSent?: unknown }\n ).verificationEmailSent;\n return {\n accepted: true,\n terminalStage: stage as TerminalStage,\n ...(typeof verificationEmailSent === \"boolean\"\n ? { verificationEmailSent }\n : {}),\n };\n }\n }\n throw new OnboardingServerError(\n response.status,\n `Success status ${response.status} but the submit response did not carry {accepted:true, terminalStage}.`,\n );\n}\n\n/**\n * Submit a full signup to the onboarding intake.\n *\n * @throws {OnboardingValidationError} strict wire-schema failure — BEFORE any fetch\n * @throws {OnboardingBotChallengeError} on 403, or if the bot-token provider\n * throws (reCAPTCHA unreachable) on any attempt\n * @throws {OnboardingSpecStaleError} on 409 with code:\"spec_stale\" (caller\n * refetches spec); carries the server's currentSpecVersion\n * @throws {OnboardingConflictError} on a 409 that is NOT spec_stale\n * @throws {OnboardingRateLimitError} on 429\n * @throws {OnboardingValidationError} on 422 (server re-validation)\n * @throws {OnboardingServerError} on 5xx after retries, or a 2xx without\n * the required {accepted:true, terminalStage} body\n * @throws {OnboardingNetworkError} on network failure OR timeout after retries\n */\nexport async function submitSignup(\n body: SignupSubmitBody,\n options: SignupSubmitOptions,\n): Promise<SignupSubmitResult> {\n const fetchImpl = options.fetch ?? globalThis.fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const url = buildUrl(options.baseUrl, SUBMIT_PATH);\n\n // Non-token fields normalized once; token attached PER ATTEMPT (single-use)\n // so a retry carries a fresh token — the body is serialized inside the loop.\n const base: Record<string, unknown> = { ...body };\n if (base[\"selectedServices\"] === undefined) {\n delete base[\"selectedServices\"];\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": options.idempotencyKey,\n };\n\n let lastError: unknown = null;\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n options.onAttempt?.(attempt);\n\n // Guarded: a token-provider failure (reCAPTCHA unreachable on a retry)\n // becomes a typed OnboardingBotChallengeError, never a raw RecaptchaError.\n const botToken = await resolveBotTokenGuarded(options.botToken);\n const parsed = signupWireSchema.safeParse({ ...base, botToken });\n if (!parsed.success) {\n const detail = parsed.error.issues\n .map((i) => `${i.path.join(\".\") || \"(payload)\"}: ${i.message}`)\n .join(\"; \");\n throw new OnboardingValidationError(\n `Signup payload failed wire-schema validation: ${detail}`,\n );\n }\n const wireBody = JSON.stringify(parsed.data);\n\n let response: Response;\n try {\n response = await fetchWithTimeout(url, {\n method: \"POST\",\n headers,\n body: wireBody,\n timeoutMs,\n fetchImpl,\n });\n } catch (err) {\n lastError = new OnboardingNetworkError(err);\n const delay = RETRY_DELAYS_MS[attempt - 1];\n if (attempt < MAX_ATTEMPTS && delay !== undefined) {\n await sleep(delay);\n continue;\n }\n throw lastError;\n }\n\n if (response.status === 200 || response.status === 202) {\n return parseSubmitSuccess(response);\n }\n\n if (response.status === 403) {\n throw new OnboardingBotChallengeError();\n }\n\n // 409 — the PINNED spec_stale body is exactly\n // { error: true, code: \"spec_stale\", currentSpecVersion: string }\n // (confirmed against the crm intake). ONLY a 409 carrying\n // code:\"spec_stale\" maps to OnboardingSpecStaleError; any other 409 is a\n // generic conflict. Read ONLY currentSpecVersion — no field hedging.\n if (response.status === 409) {\n let code: unknown;\n let currentSpecVersion = \"unknown\";\n try {\n const body409 = (await response.json()) as Record<string, unknown>;\n code = body409[\"code\"];\n const v = body409[\"currentSpecVersion\"];\n if (typeof v === \"string\" && v !== \"\") currentSpecVersion = v;\n } catch {\n // keep defaults; a body-less 409 is treated as a generic conflict\n }\n if (code === \"spec_stale\") {\n throw new OnboardingSpecStaleError(currentSpecVersion);\n }\n throw new OnboardingConflictError(409);\n }\n\n if (response.status === 429) {\n throw new OnboardingRateLimitError(parseRetryAfter(response));\n }\n\n if (response.status === 422) {\n throw new OnboardingValidationError(\n \"The server rejected the submission (422). Please review your inputs.\",\n );\n }\n\n if (response.status >= 500) {\n lastError = new OnboardingServerError(response.status);\n const delay = RETRY_DELAYS_MS[attempt - 1];\n if (attempt < MAX_ATTEMPTS && delay !== undefined) {\n await sleep(delay);\n continue;\n }\n throw lastError;\n }\n\n throw new OnboardingServerError(\n response.status,\n `Unexpected response status ${response.status}`,\n );\n }\n\n throw lastError ?? new OnboardingNetworkError();\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/widget/dom-utils.ts","../src/widget/styles.ts","../src/widget/contact-form.ts","../src/widget/signup-form.ts","../src/widget/index.ts"],"names":["el"],"mappings":"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","file":"chunk-SWMIIUXR.js","sourcesContent":["/**\n * Shared DOM helpers for the widget layer.\n *\n * `idSelector` builds a `#id` CSS selector with the id CSS-escaped, so a field\n * key (which originates in the fetched onboarder spec) can never break out of\n * the selector or match unintended nodes. This is defense-in-depth: the spec\n * model already constrains field keys to `[A-Za-z0-9_-]+` (FIELD_KEY_PATTERN),\n * but the escaping guarantees selector safety even for the widget's own\n * internally-composed ids and for any future relaxation of that alphabet.\n */\n\n/**\n * CSS-escape a string for safe use as an identifier in a selector.\n * Uses the standard `CSS.escape` when available (all modern browsers), with a\n * spec-compliant-enough fallback for non-DOM/test runtimes: escape everything\n * that is not an ASCII identifier char.\n */\nexport function cssEscape(value: string): string {\n const g = globalThis as { CSS?: { escape?: (v: string) => string } };\n if (g.CSS && typeof g.CSS.escape === \"function\") {\n return g.CSS.escape(value);\n }\n // Fallback: backslash-escape any char outside [A-Za-z0-9_-]. Sufficient to\n // neutralize CSS metacharacters ([]().,#*:>+~ whitespace, quotes, etc.).\n return value.replace(/[^A-Za-z0-9_-]/g, (ch) => `\\\\${ch}`);\n}\n\n/** Build a safe `#id` selector with the id CSS-escaped. */\nexport function idSelector(id: string): string {\n return `#${cssEscape(id)}`;\n}\n","/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Default CSS for the onboarding contact form widget.\n *\n * Uses CSS custom properties (variables) for theming. Consumers override\n * these on the host element or globally:\n *\n * --nodii-onboarding-font-family\n * --nodii-onboarding-primary-color\n * --nodii-onboarding-primary-hover\n * --nodii-onboarding-error-color\n * --nodii-onboarding-border-color\n * --nodii-onboarding-input-bg\n * --nodii-onboarding-label-color\n * --nodii-onboarding-radius\n * --nodii-onboarding-spacing\n *\n * The widget scopes all styles under `.nodii-onboarding-widget` to avoid\n * leaking into the host page.\n */\n\nexport const DEFAULT_WIDGET_CSS = `\n.nodii-onboarding-widget {\n --_font: var(--nodii-onboarding-font-family, system-ui, -apple-system, sans-serif);\n --_primary: var(--nodii-onboarding-primary-color, #2563eb);\n --_primary-hover: var(--nodii-onboarding-primary-hover, #1d4ed8);\n --_error: var(--nodii-onboarding-error-color, #dc2626);\n --_border: var(--nodii-onboarding-border-color, #d1d5db);\n --_input-bg: var(--nodii-onboarding-input-bg, #fff);\n --_label: var(--nodii-onboarding-label-color, #374151);\n --_radius: var(--nodii-onboarding-radius, 6px);\n --_spacing: var(--nodii-onboarding-spacing, 16px);\n\n font-family: var(--_font);\n box-sizing: border-box;\n}\n\n.nodii-onboarding-widget *,\n.nodii-onboarding-widget *::before,\n.nodii-onboarding-widget *::after {\n box-sizing: inherit;\n}\n\n.nodii-onboarding-field {\n display: flex;\n flex-direction: column;\n gap: calc(var(--_spacing) * 0.25);\n margin-bottom: var(--_spacing);\n}\n\n.nodii-onboarding-label {\n font-size: 0.875rem;\n font-weight: 500;\n color: var(--_label);\n}\n\n.nodii-onboarding-label.required::after {\n content: \" *\";\n color: var(--_error);\n}\n\n.nodii-onboarding-input,\n.nodii-onboarding-textarea {\n width: 100%;\n padding: calc(var(--_spacing) * 0.5) calc(var(--_spacing) * 0.75);\n border: 1px solid var(--_border);\n border-radius: var(--_radius);\n background: var(--_input-bg);\n font-family: var(--_font);\n font-size: 1rem;\n line-height: 1.5;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.nodii-onboarding-input:focus,\n.nodii-onboarding-textarea:focus {\n border-color: var(--_primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--_primary) 20%, transparent);\n}\n\n.nodii-onboarding-input.has-error,\n.nodii-onboarding-textarea.has-error {\n border-color: var(--_error);\n}\n\n.nodii-onboarding-textarea {\n min-height: 100px;\n resize: vertical;\n}\n\n.nodii-onboarding-field-error {\n font-size: 0.75rem;\n color: var(--_error);\n margin-top: 2px;\n}\n\n.nodii-onboarding-server-error {\n padding: calc(var(--_spacing) * 0.75);\n border-radius: var(--_radius);\n background: color-mix(in srgb, var(--_error) 8%, transparent);\n border: 1px solid color-mix(in srgb, var(--_error) 30%, transparent);\n color: var(--_error);\n font-size: 0.875rem;\n margin-bottom: var(--_spacing);\n}\n\n.nodii-onboarding-success {\n padding: var(--_spacing);\n border-radius: var(--_radius);\n background: #f0fdf4;\n border: 1px solid #bbf7d0;\n color: #15803d;\n font-size: 0.9375rem;\n text-align: center;\n}\n\n.nodii-onboarding-submit-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n padding: calc(var(--_spacing) * 0.625) var(--_spacing);\n background: var(--_primary);\n color: #fff;\n border: none;\n border-radius: var(--_radius);\n font-family: var(--_font);\n font-size: 1rem;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.nodii-onboarding-submit-btn:hover:not(:disabled) {\n background: var(--_primary-hover);\n}\n\n.nodii-onboarding-submit-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.nodii-onboarding-spinner {\n display: inline-block;\n width: 1em;\n height: 1em;\n border: 2px solid rgba(255,255,255,0.4);\n border-top-color: #fff;\n border-radius: 50%;\n animation: nodii-spin 0.6s linear infinite;\n margin-right: 0.5em;\n}\n\n@keyframes nodii-spin {\n to { transform: rotate(360deg); }\n}\n\n.nodii-onboarding-recaptcha-notice {\n font-size: 0.7rem;\n color: #6b7280;\n margin-top: calc(var(--_spacing) * 0.5);\n text-align: center;\n}\n\n.nodii-onboarding-recaptcha-notice a {\n color: inherit;\n}\n\n/* ── dynamic stepper (signup form) ── */\n\n.nodii-onboarding-steps {\n display: flex;\n gap: calc(var(--_spacing) * 0.5);\n margin-bottom: var(--_spacing);\n}\n\n.nodii-onboarding-step-dot {\n flex: 1;\n height: 4px;\n border-radius: 2px;\n background: var(--_border);\n}\n\n.nodii-onboarding-step-dot.active {\n background: var(--_primary);\n}\n\n.nodii-onboarding-stage-title {\n font-size: 1.0625rem;\n font-weight: 600;\n color: var(--_label);\n margin: 0 0 var(--_spacing) 0;\n}\n\n.nodii-onboarding-nav {\n display: flex;\n gap: calc(var(--_spacing) * 0.5);\n margin-top: var(--_spacing);\n}\n\n.nodii-onboarding-back-btn {\n padding: calc(var(--_spacing) * 0.625) var(--_spacing);\n background: transparent;\n color: var(--_label);\n border: 1px solid var(--_border);\n border-radius: var(--_radius);\n font-family: var(--_font);\n font-size: 1rem;\n cursor: pointer;\n}\n\n.nodii-onboarding-stale-banner {\n padding: calc(var(--_spacing) * 0.75);\n border-radius: var(--_radius);\n background: #fffbeb;\n border: 1px solid #fcd34d;\n color: #92400e;\n font-size: 0.875rem;\n margin-bottom: var(--_spacing);\n}\n\n.nodii-onboarding-consent-row {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--_spacing) * 0.5);\n margin-bottom: calc(var(--_spacing) * 0.5);\n font-size: 0.875rem;\n color: var(--_label);\n}\n\n.nodii-onboarding-consent-row input[type=\"checkbox\"] {\n margin-top: 3px;\n}\n\n.nodii-onboarding-account-section {\n border-top: 1px solid var(--_border);\n margin-top: var(--_spacing);\n padding-top: var(--_spacing);\n}\n\n.nodii-onboarding-loading {\n padding: var(--_spacing);\n text-align: center;\n color: var(--_label);\n}\n`;\n\n/**\n * Inject the default widget CSS once into the document head.\n * Idempotent — will not add a duplicate style tag.\n */\nexport function injectWidgetStyles(): void {\n if (typeof document === \"undefined\") return;\n const styleId = \"__nodii_onboarding_styles__\";\n if (document.getElementById(styleId)) return;\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = DEFAULT_WIDGET_CSS;\n document.head.appendChild(style);\n}\n","/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Default vanilla-TS contact form widget.\n *\n * Renders a form into a host element and handles the full lifecycle:\n * 1. Render fields (name, email, phone, message)\n * 2. Client-side validation on submit\n * 3. reCAPTCHA token acquisition (D537)\n * 4. POST to /api/v1/public/onboarding/leads via submit client\n * 5. Retry on 5xx with SAME idempotency key\n * 6. Show success or error state\n *\n * No React or framework required. CSS via injectWidgetStyles().\n */\n\nimport {\n createContactFormState,\n type ContactFormControl,\n type FieldError,\n} from \"../form/state.js\";\nimport type { ContactFormValues } from \"../form/schema.js\";\nimport {\n submitLead,\n generateIdempotencyKey,\n computePayloadFingerprint,\n} from \"../submit/client.js\";\nimport {\n OnboardingBotChallengeError,\n OnboardingRateLimitError,\n} from \"../submit/errors.js\";\nimport { executeRecaptcha, loadRecaptcha } from \"../recaptcha/loader.js\";\nimport { idSelector } from \"./dom-utils.js\";\nimport { injectWidgetStyles } from \"./styles.js\";\n\nexport interface ContactFormMountOptions {\n /**\n * The onboarder identifier (slug or UUID).\n *\n * NOT transmitted on the wire — by design. Per LOCKED D536, onboarder\n * trust/scoping is derived server-side from the request Host at the edge\n * (\"onboarder derived from the bundle, never client-supplied\", D540 §1);\n * a client-supplied identifier is never trusted and therefore never sent.\n *\n * This option is reserved for Phase 2, where it becomes the client-side\n * cache key for the spec-fetch (`(onboarder, specVersion)` per D540 §3).\n * In Phase 1 it has no runtime effect.\n */\n onboarder: string;\n /**\n * Base URL for the intake service.\n * e.g. \"https://api.acme.nucleus-cloud.in\"\n */\n baseUrl: string;\n /**\n * reCAPTCHA v3 site key. Obtained from the spec endpoint (D540 §1)\n * or passed directly in Phase 1 before spec-fetch is wired.\n */\n siteKey: string;\n /**\n * Which form to render. Phase 1 supports \"contact\" only.\n * Phase 2 will add \"signup\" (dynamic stepper from spec).\n */\n form: \"contact\";\n /** Called after a successful lead submission. */\n onSuccess?: () => void;\n /** Called on non-retryable errors (bot challenge, rate limit). */\n onError?: (error: unknown) => void;\n /** Custom fetch implementation (defaults to globalThis.fetch). */\n fetch?: typeof globalThis.fetch;\n /**\n * Per-request timeout in ms (default 15s), applied to BOTH the reCAPTCHA\n * execute() and the submit POST so a hung dependency re-enables the form.\n */\n timeoutMs?: number;\n /** Success message override. */\n successMessage?: string;\n /** Submit button label override. */\n submitLabel?: string;\n}\n\nexport interface MountedWidget {\n /** Unmount and clean up the widget from the host element. */\n unmount(): void;\n /** Reset the form to its initial state. */\n reset(): void;\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs: Record<string, string> = {},\n children: Array<HTMLElement | Text | string> = [],\n): HTMLElementTagNameMap[K] {\n const element = document.createElement(tag);\n for (const [key, value] of Object.entries(attrs)) {\n element.setAttribute(key, value);\n }\n for (const child of children) {\n if (typeof child === \"string\") {\n element.appendChild(document.createTextNode(child));\n } else {\n element.appendChild(child);\n }\n }\n return element;\n}\n\nfunction createFieldEl(\n id: string,\n label: string,\n input: HTMLInputElement | HTMLTextAreaElement,\n required: boolean,\n): HTMLElement {\n const labelEl = el(\n \"label\",\n { for: id, class: `nodii-onboarding-label${required ? \" required\" : \"\"}` },\n [label],\n );\n const errorEl = el(\"div\", {\n class: \"nodii-onboarding-field-error\",\n id: `${id}-error`,\n role: \"alert\",\n \"aria-live\": \"polite\",\n });\n const field = el(\"div\", { class: \"nodii-onboarding-field\" }, [\n labelEl,\n input,\n errorEl,\n ]);\n return field;\n}\n\nfunction setFieldError(\n container: HTMLElement,\n fieldId: string,\n message: string,\n): void {\n // CSS-escape the id: fieldId derives from spec field keys — never build a\n // selector from unescaped, spec-controlled input.\n const errorEl = container.querySelector(idSelector(`${fieldId}-error`));\n if (errorEl) errorEl.textContent = message;\n const inputEl = container.querySelector(idSelector(fieldId));\n if (inputEl) inputEl.classList.add(\"has-error\");\n}\n\nfunction clearFieldErrors(container: HTMLElement): void {\n for (const el of container.querySelectorAll(\n \".nodii-onboarding-field-error\",\n )) {\n el.textContent = \"\";\n }\n for (const el of container.querySelectorAll(\".has-error\")) {\n el.classList.remove(\"has-error\");\n }\n}\n\nfunction applyErrors(container: HTMLElement, errors: FieldError[]): void {\n clearFieldErrors(container);\n for (const err of errors) {\n // Zod paths are bare field names (\"name\", \"email\"); the DOM ids carry\n // the \"nodii-\" prefix (\"nodii-name\"). Map explicitly — a bare path\n // would querySelector nothing and silently drop the error display.\n setFieldError(container, `nodii-${err.path}`, err.message);\n }\n}\n\n/**\n * Mount the contact form widget into a host element.\n *\n * @example\n * ```ts\n * import { OnboardingWidget } from \"@nodii/onboarding/widget\";\n * const widget = OnboardingWidget.mount(document.getElementById(\"signup\"), {\n * onboarder: \"acme-corp\",\n * form: \"contact\",\n * baseUrl: \"https://api.acme.nucleus-cloud.in\",\n * siteKey: \"6Lc...\",\n * });\n * ```\n */\nexport function mountContactForm(\n host: HTMLElement,\n options: ContactFormMountOptions,\n): MountedWidget {\n injectWidgetStyles();\n\n const formControl: ContactFormControl = createContactFormState();\n\n // Pre-load reCAPTCHA script to minimize latency at submit time.\n // Non-fatal: the loader evicts its cache on failure, so a failed\n // pre-load genuinely retries from scratch at submit time.\n loadRecaptcha(options.siteKey).catch(() => {\n // Swallowed by design — executeRecaptcha at submit re-attempts.\n });\n\n // --- Build DOM ---\n const wrapper = el(\"div\", { class: \"nodii-onboarding-widget\" });\n\n const nameInput = el(\"input\", {\n type: \"text\",\n id: \"nodii-name\",\n name: \"name\",\n class: \"nodii-onboarding-input\",\n placeholder: \"Your name\",\n autocomplete: \"name\",\n maxlength: \"200\",\n required: \"required\",\n }) as HTMLInputElement;\n\n const emailInput = el(\"input\", {\n type: \"email\",\n id: \"nodii-email\",\n name: \"email\",\n class: \"nodii-onboarding-input\",\n placeholder: \"you@company.com\",\n autocomplete: \"email\",\n required: \"required\",\n }) as HTMLInputElement;\n\n const phoneInput = el(\"input\", {\n type: \"tel\",\n id: \"nodii-phone\",\n name: \"phone\",\n class: \"nodii-onboarding-input\",\n placeholder: \"+1 555 000 0000\",\n autocomplete: \"tel\",\n }) as HTMLInputElement;\n\n const messageInput = el(\"textarea\", {\n id: \"nodii-message\",\n name: \"message\",\n class: \"nodii-onboarding-textarea\",\n placeholder: \"How can we help?\",\n maxlength: \"4000\",\n rows: \"4\",\n }) as HTMLTextAreaElement;\n\n const serverErrorEl = el(\"div\", {\n class: \"nodii-onboarding-server-error\",\n role: \"alert\",\n \"aria-live\": \"assertive\",\n style: \"display:none\",\n });\n\n const successEl = el(\n \"div\",\n {\n class: \"nodii-onboarding-success\",\n role: \"status\",\n style: \"display:none\",\n },\n [options.successMessage ?? \"Thank you! We'll be in touch shortly.\"],\n );\n\n const submitBtn = el(\n \"button\",\n {\n type: \"submit\",\n class: \"nodii-onboarding-submit-btn\",\n },\n [options.submitLabel ?? \"Get in touch\"],\n );\n\n const recaptchaNotice = el(\n \"p\",\n { class: \"nodii-onboarding-recaptcha-notice\" },\n [\n \"Protected by reCAPTCHA. \",\n Object.assign(\n el(\"a\", {\n href: \"https://policies.google.com/privacy\",\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n }),\n { textContent: \"Privacy\" },\n ),\n \" & \",\n Object.assign(\n el(\"a\", {\n href: \"https://policies.google.com/terms\",\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n }),\n { textContent: \"Terms\" },\n ),\n ],\n );\n\n const form = el(\"form\", {\n novalidate: \"true\",\n \"aria-label\": \"Contact us\",\n });\n\n form.appendChild(createFieldEl(\"nodii-name\", \"Name\", nameInput, true));\n form.appendChild(createFieldEl(\"nodii-email\", \"Email\", emailInput, true));\n form.appendChild(\n createFieldEl(\"nodii-phone\", \"Phone (optional)\", phoneInput, false),\n );\n form.appendChild(\n createFieldEl(\"nodii-message\", \"Message (optional)\", messageInput, false),\n );\n form.appendChild(serverErrorEl);\n form.appendChild(submitBtn);\n form.appendChild(recaptchaNotice);\n\n wrapper.appendChild(successEl);\n wrapper.appendChild(form);\n host.appendChild(wrapper);\n\n // --- Wire input events ---\n nameInput.addEventListener(\"input\", () => {\n formControl.setValue(\"name\", nameInput.value);\n });\n emailInput.addEventListener(\"input\", () => {\n formControl.setValue(\"email\", emailInput.value);\n });\n phoneInput.addEventListener(\"input\", () => {\n formControl.setValue(\"phone\", phoneInput.value || undefined);\n });\n messageInput.addEventListener(\"input\", () => {\n formControl.setValue(\"message\", messageInput.value || undefined);\n });\n\n const submitLabel = options.submitLabel ?? \"Get in touch\";\n\n // Render the submit button content via DOM nodes ONLY — never innerHTML.\n // options.submitLabel may be integrator/CMS-influenced text; text nodes\n // guarantee it can never be interpreted as markup.\n function renderSubmitButton(submitting: boolean): void {\n while (submitBtn.firstChild) {\n submitBtn.removeChild(submitBtn.firstChild);\n }\n if (submitting) {\n const spinner = document.createElement(\"span\");\n spinner.className = \"nodii-onboarding-spinner\";\n submitBtn.appendChild(spinner);\n submitBtn.appendChild(document.createTextNode(\"Sending…\"));\n } else {\n submitBtn.appendChild(document.createTextNode(submitLabel));\n }\n }\n\n // Subscribe to state changes\n const unsubscribe = formControl.subscribe((state) => {\n // Update submit button state\n submitBtn.disabled = state.status === \"submitting\";\n renderSubmitButton(state.status === \"submitting\");\n\n // Apply field errors\n applyErrors(wrapper, state.errors);\n\n // Server error\n if (state.serverError) {\n serverErrorEl.textContent = state.serverError;\n serverErrorEl.style.display = \"\";\n } else {\n serverErrorEl.style.display = \"none\";\n }\n\n // Success state\n if (state.status === \"success\") {\n successEl.style.display = \"\";\n form.style.display = \"none\";\n }\n });\n\n // --- Submit handler ---\n //\n // Idempotency-Key discipline (mirrors the server's D538 payload-match\n // guard — same key + different payload is INVALID_ARGUMENT server-side):\n // - The key is stable across RETRIES of the SAME payload (fingerprint\n // of the outgoing body minus botToken).\n // - If the user EDITS any field after a failed attempt, the fingerprint\n // changes → a NEW key is minted: an edited resubmission is a NEW\n // logical submission, not a retry.\n // - Cleared on success and on reset().\n let idempotencyKey: string | null = null;\n let lastFingerprint: string | null = null;\n\n form.addEventListener(\"submit\", async (event: Event) => {\n event.preventDefault();\n\n // Sync inputs to state\n formControl.setValue(\"name\", nameInput.value);\n formControl.setValue(\"email\", emailInput.value);\n formControl.setValue(\"phone\", phoneInput.value || undefined);\n formControl.setValue(\"message\", messageInput.value || undefined);\n\n const valid = formControl.validate();\n if (!valid) return;\n\n formControl.setSubmitting();\n\n const values = formControl.getState().values as ContactFormValues;\n\n // Key management per the discipline above.\n const fingerprint = computePayloadFingerprint(values);\n if (idempotencyKey === null || fingerprint !== lastFingerprint) {\n idempotencyKey = generateIdempotencyKey();\n lastFingerprint = fingerprint;\n }\n\n // Acquire the FIRST token up front so a mount-time reCAPTCHA failure\n // surfaces a clear message before any HTTP. On retries, submitLead mints\n // a FRESH token per attempt via this same provider (tokens are\n // single-use — reusing one after a 5xx would 403). Bounded by timeoutMs.\n let firstToken: string;\n try {\n firstToken = await executeRecaptcha(options.siteKey, \"contact_submit\", {\n timeoutMs: options.timeoutMs,\n });\n } catch (recaptchaErr) {\n formControl.setError(\"Could not load bot protection. Please try again.\");\n options.onError?.(recaptchaErr);\n return;\n }\n let usedFirst = false;\n const tokenProvider = async (): Promise<string> => {\n if (!usedFirst) {\n usedFirst = true;\n return firstToken;\n }\n return executeRecaptcha(options.siteKey, \"contact_submit\", {\n timeoutMs: options.timeoutMs,\n });\n };\n\n try {\n await submitLead(values, {\n baseUrl: options.baseUrl,\n botToken: tokenProvider,\n idempotencyKey,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n // Clear for the next logical submission.\n idempotencyKey = null;\n lastFingerprint = null;\n formControl.setSuccess();\n options.onSuccess?.();\n } catch (err) {\n if (err instanceof OnboardingBotChallengeError) {\n formControl.setError(\n \"Bot protection check failed. Please refresh the page and try again.\",\n );\n options.onError?.(err);\n } else if (err instanceof OnboardingRateLimitError) {\n const msg =\n err.retryAfterSeconds !== null\n ? `Too many requests. Please wait ${err.retryAfterSeconds}s.`\n : \"Too many requests. Please wait a moment.\";\n formControl.setError(msg);\n options.onError?.(err);\n } else {\n formControl.setError(\n \"Something went wrong. Please try again in a moment.\",\n );\n options.onError?.(err);\n }\n }\n });\n\n return {\n unmount() {\n unsubscribe();\n host.removeChild(wrapper);\n },\n reset() {\n idempotencyKey = null;\n lastFingerprint = null;\n formControl.reset();\n form.style.display = \"\";\n successEl.style.display = \"none\";\n nameInput.value = \"\";\n emailInput.value = \"\";\n phoneInput.value = \"\";\n messageInput.value = \"\";\n },\n };\n}\n","/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * Default vanilla-TS dynamic signup stepper widget (D540 Phase 2).\n *\n * Mount flow:\n * 1. Fetch + validate the spec (GET /api/v1/public/onboarding/spec);\n * the reCAPTCHA siteKey comes FROM THE SPEC (botChallenge.siteKey) —\n * the mount-option siteKey is only an override/fallback.\n * 2. Build the headless stepper from spec.forms.signup.steps.\n * 3. Render the current step's fields per descriptor type; Back/Next\n * navigate with per-step validation.\n * 4. The FINAL step carries the account section (credentials + consent\n * clickwrap) and the submit button.\n * 5. Submit: validateAll → payload-fingerprint key management (same\n * D538 discipline as the contact widget) → reCAPTCHA token →\n * submitSignup.\n * 6. 409 spec_stale: refetch the spec, applyNewSpec (drops removed\n * fields, re-validates), show a \"form updated — please review\"\n * banner. The SDK NEVER auto-resubmits a stale submission.\n */\n\nimport {\n fetchOnboardingSpec,\n OnboardingSpecCache,\n defaultSpecCache,\n diffSpecFields,\n type OnboardingSpec,\n} from \"../spec/index.js\";\nimport type { SpecField } from \"../spec/model.js\";\nimport {\n createSignupStepper,\n type SignupStepperControl,\n type SignupStepperState,\n} from \"../dynamic/stepper.js\";\nimport { optionValue } from \"../dynamic/derive.js\";\nimport {\n submitSignup,\n computeSignupFingerprint,\n type SignupSubmitResult,\n} from \"../submit/signup-client.js\";\nimport { generateIdempotencyKey } from \"../submit/client.js\";\nimport {\n OnboardingBotChallengeError,\n OnboardingRateLimitError,\n OnboardingSpecStaleError,\n} from \"../submit/errors.js\";\nimport { executeRecaptcha } from \"../recaptcha/loader.js\";\nimport { idSelector } from \"./dom-utils.js\";\nimport { injectWidgetStyles } from \"./styles.js\";\nimport type { MountedWidget } from \"./contact-form.js\";\n\nexport interface SignupFormMountOptions {\n /**\n * The onboarder identifier — the CLIENT-side spec-cache key\n * (D540 §3 `(onboarder, specVersion)`). NOT transmitted: per LOCKED\n * D536, onboarder trust/scoping is host-derived at the edge.\n */\n onboarder: string;\n baseUrl: string;\n /**\n * OPTIONAL siteKey override. Normally the widget uses the siteKey the\n * spec serves (botChallenge.siteKey, D537/D540); pass this only for\n * environments where the spec cannot carry it yet.\n */\n siteKey?: string;\n form: \"signup\";\n onSuccess?: (result: SignupSubmitResult) => void;\n onError?: (error: unknown) => void;\n /** Called after the spec loads and the stepper renders. */\n onReady?: (spec: OnboardingSpec) => void;\n fetch?: typeof globalThis.fetch;\n /**\n * Per-request timeout in ms (default 15s), applied to the boot spec fetch,\n * the reCAPTCHA execute(), the submit POST, and the 409 refetch — so a hung\n * dependency never leaves \"Loading signup form…\"/\"Sending…\" stuck.\n */\n timeoutMs?: number;\n submitLabel?: string;\n tosUrl?: string;\n privacyUrl?: string;\n /** Spec cache override (defaults to the module-level cache). */\n cache?: OnboardingSpecCache;\n}\n\nconst STAGE_TITLES: Record<string, string> = {\n lead: \"About you\",\n prospect: \"Your business\",\n activation: \"Choose your services\",\n};\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs: Record<string, string> = {},\n children: Array<HTMLElement | Text | string> = [],\n): HTMLElementTagNameMap[K] {\n const element = document.createElement(tag);\n for (const [key, value] of Object.entries(attrs)) {\n element.setAttribute(key, value);\n }\n for (const child of children) {\n if (typeof child === \"string\") {\n element.appendChild(document.createTextNode(child));\n } else {\n element.appendChild(child);\n }\n }\n return element;\n}\n\nfunction optionLabel(option: unknown): string {\n if (option !== null && typeof option === \"object\") {\n const o = option as Record<string, unknown>;\n if (typeof o[\"label\"] === \"string\") return o[\"label\"];\n }\n return optionValue(option);\n}\n\n/** Build the input element for one spec field descriptor. */\nfunction buildFieldInput(\n field: SpecField,\n currentValue: unknown,\n onChange: (value: unknown) => void,\n): HTMLElement {\n const id = `nodii-f-${field.key}`;\n\n switch (field.type) {\n case \"textarea\": {\n const input = el(\"textarea\", {\n id,\n class: \"nodii-onboarding-textarea\",\n rows: \"4\",\n }) as HTMLTextAreaElement;\n if (typeof currentValue === \"string\") input.value = currentValue;\n input.addEventListener(\"input\", () => onChange(input.value));\n return input;\n }\n case \"checkbox\":\n case \"boolean\": {\n const input = el(\"input\", {\n type: \"checkbox\",\n id,\n }) as HTMLInputElement;\n input.checked = currentValue === true;\n input.addEventListener(\"change\", () => onChange(input.checked));\n return input;\n }\n case \"select\":\n case \"radio\": {\n const select = el(\"select\", {\n id,\n class: \"nodii-onboarding-input\",\n }) as HTMLSelectElement;\n select.appendChild(el(\"option\", { value: \"\" }, [\"— select —\"]));\n for (const opt of field.options ?? []) {\n const value = optionValue(opt);\n const optionEl = el(\"option\", { value }, [optionLabel(opt)]);\n select.appendChild(optionEl);\n }\n if (typeof currentValue === \"string\") select.value = currentValue;\n select.addEventListener(\"change\", () => onChange(select.value));\n return select;\n }\n case \"multiselect\": {\n const select = el(\"select\", {\n id,\n class: \"nodii-onboarding-input\",\n multiple: \"multiple\",\n }) as HTMLSelectElement;\n const current = Array.isArray(currentValue)\n ? currentValue.map(String)\n : [];\n for (const opt of field.options ?? []) {\n const value = optionValue(opt);\n const optionEl = el(\"option\", { value }, [\n optionLabel(opt),\n ]) as HTMLOptionElement;\n if (current.includes(value)) optionEl.selected = true;\n select.appendChild(optionEl);\n }\n select.addEventListener(\"change\", () => {\n const values: string[] = [];\n for (const o of Array.from(select.options)) {\n if (o.selected && o.value !== \"\") values.push(o.value);\n }\n onChange(values);\n });\n return select;\n }\n default: {\n // text | email | tel | number | date | unknown → typed <input>\n const typeAttr =\n field.type === \"email\" ||\n field.type === \"tel\" ||\n field.type === \"number\" ||\n field.type === \"date\"\n ? field.type\n : \"text\";\n const input = el(\"input\", {\n type: typeAttr,\n id,\n class: \"nodii-onboarding-input\",\n }) as HTMLInputElement;\n if (typeof currentValue === \"string\") input.value = currentValue;\n if (typeof currentValue === \"number\") input.value = String(currentValue);\n input.addEventListener(\"input\", () => onChange(input.value));\n return input;\n }\n }\n}\n\n/**\n * Build a labelled field row. The label `for`, the input id, and the error\n * element id must ALL agree so click-to-focus and screen-reader association\n * work. Callers whose input id is NOT `nodii-f-<key>` (the account section,\n * whose inputs are `nodii-account-*`) pass `idOverride` so the label points\n * at the REAL input — never a dangling id patched up post-hoc.\n */\nfunction fieldRow(\n field: SpecField,\n input: HTMLElement,\n idOverride?: string,\n): HTMLElement {\n const id = idOverride ?? `nodii-f-${field.key}`;\n const labelEl = el(\n \"label\",\n {\n for: id,\n class: `nodii-onboarding-label${field.required ? \" required\" : \"\"}`,\n },\n [field.label],\n );\n const errorEl = el(\"div\", {\n class: \"nodii-onboarding-field-error\",\n id: `${id}-error`,\n role: \"alert\",\n \"aria-live\": \"polite\",\n });\n return el(\"div\", { class: \"nodii-onboarding-field\" }, [\n labelEl,\n input,\n errorEl,\n ]);\n}\n\n/**\n * Mount the dynamic signup stepper into a host element.\n * Returns synchronously; the spec loads in the background (loading state\n * rendered meanwhile; onReady fires when interactive).\n */\nexport function mountSignupForm(\n host: HTMLElement,\n options: SignupFormMountOptions,\n): MountedWidget {\n injectWidgetStyles();\n\n const wrapper = el(\"div\", { class: \"nodii-onboarding-widget\" });\n const loadingEl = el(\"div\", { class: \"nodii-onboarding-loading\" }, [\n \"Loading signup form…\",\n ]);\n wrapper.appendChild(loadingEl);\n host.appendChild(wrapper);\n\n const cache = options.cache ?? defaultSpecCache;\n let stepper: SignupStepperControl | null = null;\n let unsubscribe: (() => void) | null = null;\n let unmounted = false;\n let siteKey = options.siteKey ?? \"\";\n let idempotencyKey: string | null = null;\n let lastFingerprint: string | null = null;\n let renderedStepIndex = -1;\n let renderedStale = false;\n // The (onboarder, specVersion) currently driving the form — used to READ\n // the prior cached version back out on a 409 and diff what changed.\n let currentSpecVersion: string | null = null;\n let staleDiffSummary = \"\";\n\n // DOM regions (populated by renderShell)\n const stepArea = el(\"div\", {});\n const staleBanner = el(\"div\", {\n class: \"nodii-onboarding-stale-banner\",\n role: \"alert\",\n style: \"display:none\",\n });\n const serverErrorEl = el(\"div\", {\n class: \"nodii-onboarding-server-error\",\n role: \"alert\",\n \"aria-live\": \"assertive\",\n style: \"display:none\",\n });\n const successEl = el(\"div\", {\n class: \"nodii-onboarding-success\",\n role: \"status\",\n style: \"display:none\",\n });\n const stepsIndicator = el(\"div\", { class: \"nodii-onboarding-steps\" });\n const form = el(\"form\", { novalidate: \"true\", \"aria-label\": \"Sign up\" });\n\n function setFieldErrorsInPlace(\n container: HTMLElement,\n errors: Array<{ path: string; message: string }>,\n idPrefix: (path: string) => string,\n ): void {\n for (const errEl of container.querySelectorAll(\n \".nodii-onboarding-field-error\",\n )) {\n errEl.textContent = \"\";\n }\n for (const marked of container.querySelectorAll(\".has-error\")) {\n marked.classList.remove(\"has-error\");\n }\n for (const err of errors) {\n const id = idPrefix(err.path);\n // CSS-escape: id derives from spec field keys (err.path).\n const errorNode = container.querySelector(idSelector(`${id}-error`));\n if (errorNode) errorNode.textContent = err.message;\n const inputNode = container.querySelector(idSelector(id));\n if (inputNode) inputNode.classList.add(\"has-error\");\n }\n }\n\n function accountIdOf(path: string): string {\n if (path === \"email\") return \"nodii-account-email\";\n if (path === \"password\") return \"nodii-account-password\";\n if (path === \"tosAccepted\") return \"nodii-consent-tos\";\n if (path === \"privacyAccepted\") return \"nodii-consent-privacy\";\n return `nodii-account-${path}`;\n }\n\n function renderStepsIndicator(state: SignupStepperState): void {\n while (stepsIndicator.firstChild) {\n stepsIndicator.removeChild(stepsIndicator.firstChild);\n }\n for (let i = 0; i < state.stepCount; i++) {\n stepsIndicator.appendChild(\n el(\"div\", {\n class: `nodii-onboarding-step-dot${i <= state.stepIndex ? \" active\" : \"\"}`,\n }),\n );\n }\n }\n\n function renderAccountSection(\n control: SignupStepperControl,\n state: SignupStepperState,\n ): HTMLElement {\n const section = el(\"div\", { class: \"nodii-onboarding-account-section\" });\n\n const emailInput = el(\"input\", {\n type: \"email\",\n id: \"nodii-account-email\",\n class: \"nodii-onboarding-input\",\n autocomplete: \"email\",\n }) as HTMLInputElement;\n emailInput.value = state.credentials.email;\n emailInput.addEventListener(\"input\", () =>\n control.setCredentials({ email: emailInput.value }),\n );\n section.appendChild(\n fieldRow(\n {\n key: \"account-email\",\n type: \"email\",\n label: \"Account email\",\n required: true,\n },\n emailInput,\n \"nodii-account-email\", // label for + error id match the real input id\n ),\n );\n\n const passwordInput = el(\"input\", {\n type: \"password\",\n id: \"nodii-account-password\",\n class: \"nodii-onboarding-input\",\n autocomplete: \"new-password\",\n minlength: \"12\",\n maxlength: \"256\",\n }) as HTMLInputElement;\n passwordInput.value = state.credentials.password;\n passwordInput.addEventListener(\"input\", () =>\n control.setCredentials({ password: passwordInput.value }),\n );\n section.appendChild(\n fieldRow(\n {\n key: \"account-password\",\n type: \"text\",\n label: \"Password (12+ characters)\",\n required: true,\n },\n passwordInput,\n \"nodii-account-password\", // label for + error id match the real input id\n ),\n );\n\n const tosCheckbox = el(\"input\", {\n type: \"checkbox\",\n id: \"nodii-consent-tos\",\n }) as HTMLInputElement;\n tosCheckbox.checked = state.consent.tosAccepted;\n tosCheckbox.addEventListener(\"change\", () =>\n control.setConsent({ tosAccepted: tosCheckbox.checked }),\n );\n const tosLabelChildren: Array<HTMLElement | string> = [\"I accept the \"];\n if (options.tosUrl) {\n tosLabelChildren.push(\n el(\n \"a\",\n {\n href: options.tosUrl,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n [\"Terms of Service\"],\n ),\n );\n } else {\n tosLabelChildren.push(\"Terms of Service\");\n }\n section.appendChild(\n el(\"div\", { class: \"nodii-onboarding-consent-row\" }, [\n tosCheckbox,\n el(\"label\", { for: \"nodii-consent-tos\" }, tosLabelChildren),\n ]),\n );\n section.appendChild(\n el(\"div\", {\n class: \"nodii-onboarding-field-error\",\n id: \"nodii-consent-tos-error\",\n role: \"alert\",\n }),\n );\n\n const privacyCheckbox = el(\"input\", {\n type: \"checkbox\",\n id: \"nodii-consent-privacy\",\n }) as HTMLInputElement;\n privacyCheckbox.checked = state.consent.privacyAccepted;\n privacyCheckbox.addEventListener(\"change\", () =>\n control.setConsent({ privacyAccepted: privacyCheckbox.checked }),\n );\n const privacyLabelChildren: Array<HTMLElement | string> = [\"I accept the \"];\n if (options.privacyUrl) {\n privacyLabelChildren.push(\n el(\n \"a\",\n {\n href: options.privacyUrl,\n target: \"_blank\",\n rel: \"noopener noreferrer\",\n },\n [\"Privacy Policy\"],\n ),\n );\n } else {\n privacyLabelChildren.push(\"Privacy Policy\");\n }\n section.appendChild(\n el(\"div\", { class: \"nodii-onboarding-consent-row\" }, [\n privacyCheckbox,\n el(\"label\", { for: \"nodii-consent-privacy\" }, privacyLabelChildren),\n ]),\n );\n section.appendChild(\n el(\"div\", {\n class: \"nodii-onboarding-field-error\",\n id: \"nodii-consent-privacy-error\",\n role: \"alert\",\n }),\n );\n\n return section;\n }\n\n function renderStep(\n control: SignupStepperControl,\n state: SignupStepperState,\n ): void {\n while (stepArea.firstChild) stepArea.removeChild(stepArea.firstChild);\n\n const step = state.currentStep;\n if (step) {\n stepArea.appendChild(\n el(\"h3\", { class: \"nodii-onboarding-stage-title\" }, [\n STAGE_TITLES[step.stage] ?? step.stage,\n ]),\n );\n for (const field of step.fields) {\n const input = buildFieldInput(\n field,\n state.answers[field.key],\n (value) => control.setAnswer(field.key, value),\n );\n stepArea.appendChild(fieldRow(field, input));\n }\n }\n\n const isLast = control.isLastStep();\n if (isLast) {\n stepArea.appendChild(renderAccountSection(control, state));\n }\n\n const nav = el(\"div\", { class: \"nodii-onboarding-nav\" });\n if (!control.isFirstStep()) {\n const backBtn = el(\n \"button\",\n { type: \"button\", class: \"nodii-onboarding-back-btn\" },\n [\"Back\"],\n );\n backBtn.addEventListener(\"click\", () => control.back());\n nav.appendChild(backBtn);\n }\n const forwardBtn = el(\n \"button\",\n {\n type: isLast ? \"submit\" : \"button\",\n class: \"nodii-onboarding-submit-btn\",\n id: \"nodii-signup-forward\",\n },\n [isLast ? (options.submitLabel ?? \"Create account\") : \"Next\"],\n );\n if (!isLast) {\n forwardBtn.addEventListener(\"click\", () => control.next());\n }\n nav.appendChild(forwardBtn);\n stepArea.appendChild(nav);\n }\n\n async function handleSpecStale(control: SignupStepperControl): Promise<void> {\n // READ the previously-served version back out of the cache (populated on\n // boot under (onboarder, specVersion)) so we can diff it against the\n // refetched spec and tell the user exactly what changed.\n const prior =\n currentSpecVersion !== null\n ? cache.get(options.onboarder, currentSpecVersion)\n : undefined;\n\n const fresh = await fetchOnboardingSpec({\n baseUrl: options.baseUrl,\n onboarder: options.onboarder,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n cache,\n });\n if (unmounted) return;\n\n if (prior) {\n const diff = diffSpecFields(prior, fresh);\n const parts: string[] = [];\n if (diff.added.length) parts.push(`added: ${diff.added.join(\", \")}`);\n if (diff.removed.length)\n parts.push(`removed: ${diff.removed.join(\", \")}`);\n if (diff.changed.length)\n parts.push(`changed: ${diff.changed.join(\", \")}`);\n staleDiffSummary = parts.length ? ` (${parts.join(\"; \")})` : \"\";\n } else {\n staleDiffSummary = \"\";\n }\n\n siteKey = options.siteKey ?? fresh.botChallenge.siteKey;\n currentSpecVersion = fresh.specVersion;\n control.applyNewSpec(fresh);\n // A stale submission's payload is dead; the next submit is a NEW\n // logical submission against the new specVersion.\n idempotencyKey = null;\n lastFingerprint = null;\n }\n\n async function handleSubmit(control: SignupStepperControl): Promise<void> {\n if (!control.validateAll()) return;\n control.acknowledgeSpecStale();\n control.setSubmitting();\n\n const body = control.buildSubmitPayload();\n const fingerprint = computeSignupFingerprint(body);\n if (idempotencyKey === null || fingerprint !== lastFingerprint) {\n idempotencyKey = generateIdempotencyKey();\n lastFingerprint = fingerprint;\n }\n\n // First token up front (clear pre-HTTP failure); fresh token per retry\n // attempt via the provider (single-use tokens).\n let firstToken: string;\n try {\n firstToken = await executeRecaptcha(siteKey, \"signup_submit\", {\n timeoutMs: options.timeoutMs,\n });\n } catch (recaptchaErr) {\n control.setError(\"Could not load bot protection. Please try again.\");\n options.onError?.(recaptchaErr);\n return;\n }\n let usedFirst = false;\n const tokenProvider = async (): Promise<string> => {\n if (!usedFirst) {\n usedFirst = true;\n return firstToken;\n }\n return executeRecaptcha(siteKey, \"signup_submit\", {\n timeoutMs: options.timeoutMs,\n });\n };\n\n try {\n const result = await submitSignup(body, {\n baseUrl: options.baseUrl,\n botToken: tokenProvider,\n idempotencyKey,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n });\n idempotencyKey = null;\n lastFingerprint = null;\n control.setSuccess(result.terminalStage);\n options.onSuccess?.(result);\n } catch (err) {\n if (err instanceof OnboardingSpecStaleError) {\n try {\n await handleSpecStale(control);\n } catch (refetchErr) {\n control.setError(\n \"The signup form changed and could not be reloaded. Please refresh the page.\",\n );\n options.onError?.(refetchErr);\n return;\n }\n options.onError?.(err);\n } else if (err instanceof OnboardingBotChallengeError) {\n control.setError(\n \"Bot protection check failed. Please refresh the page and try again.\",\n );\n options.onError?.(err);\n } else if (err instanceof OnboardingRateLimitError) {\n control.setError(\n err.retryAfterSeconds !== null\n ? `Too many requests. Please wait ${err.retryAfterSeconds}s.`\n : \"Too many requests. Please wait a moment.\",\n );\n options.onError?.(err);\n } else {\n control.setError(\"Something went wrong. Please try again in a moment.\");\n options.onError?.(err);\n }\n }\n }\n\n function onStateChange(\n control: SignupStepperControl,\n state: SignupStepperState,\n ): void {\n // Full step re-render only when the step (or staleness) changed —\n // in-place updates otherwise so typing never loses focus.\n if (\n state.stepIndex !== renderedStepIndex ||\n state.specStale !== renderedStale\n ) {\n renderedStepIndex = state.stepIndex;\n renderedStale = state.specStale;\n renderStep(control, state);\n renderStepsIndicator(state);\n }\n\n staleBanner.style.display = state.specStale ? \"\" : \"none\";\n staleBanner.textContent = state.specStale\n ? `This form was just updated by the provider${staleDiffSummary}. Please review your answers below and submit again.`\n : \"\";\n\n setFieldErrorsInPlace(\n stepArea,\n state.errors,\n (path) => `nodii-f-${path.split(\".\")[0] ?? path}`,\n );\n // Account errors overlay (only present on the last step's DOM)\n for (const err of state.accountErrors) {\n const id = accountIdOf(err.path.split(\".\")[0] ?? err.path);\n const errorNode = stepArea.querySelector(idSelector(`${id}-error`));\n if (errorNode) errorNode.textContent = err.message;\n const inputNode = stepArea.querySelector(idSelector(id));\n if (inputNode) inputNode.classList.add(\"has-error\");\n }\n\n if (state.serverError) {\n serverErrorEl.textContent = state.serverError;\n serverErrorEl.style.display = \"\";\n } else {\n serverErrorEl.style.display = \"none\";\n }\n\n const forwardBtn = stepArea.querySelector(\n \"#nodii-signup-forward\",\n ) as HTMLButtonElement | null;\n if (forwardBtn) {\n forwardBtn.disabled = state.status === \"submitting\";\n }\n\n if (state.status === \"success\") {\n const message =\n state.terminalStage === \"active\"\n ? \"Your account is ready — you're all set!\"\n : state.terminalStage === \"inactive\"\n ? \"Your account was created. Complete verification to activate it.\"\n : \"Thanks for signing up! Check your email to verify your account.\";\n successEl.textContent = message;\n successEl.style.display = \"\";\n form.style.display = \"none\";\n } else {\n // Any non-success status (editing/submitting/error) shows the form and\n // hides the success panel. Without this, a reset()→\"editing\" re-emit\n // would leave the success panel up and the form hidden until reload.\n successEl.style.display = \"none\";\n form.style.display = \"\";\n }\n }\n\n // ── Boot: fetch spec, then build the interactive form ──\n void (async () => {\n let spec: OnboardingSpec;\n try {\n spec = await fetchOnboardingSpec({\n baseUrl: options.baseUrl,\n onboarder: options.onboarder,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs,\n cache,\n // Reuse a spec already loaded for this onboarder this session (a\n // remount into the same page shouldn't re-hit the network). A 409 on\n // submit is the authoritative staleness signal that triggers refetch.\n preferCached: true,\n });\n } catch (err) {\n if (unmounted) return;\n loadingEl.textContent =\n \"The signup form could not be loaded. Please refresh the page.\";\n options.onError?.(err);\n return;\n }\n if (unmounted) return;\n\n siteKey = options.siteKey ?? spec.botChallenge.siteKey;\n currentSpecVersion = spec.specVersion;\n\n const control = createSignupStepper(spec);\n stepper = control;\n\n form.addEventListener(\"submit\", (event: Event) => {\n event.preventDefault();\n void handleSubmit(control);\n });\n\n form.appendChild(stepsIndicator);\n form.appendChild(staleBanner);\n form.appendChild(stepArea);\n form.appendChild(serverErrorEl);\n\n wrapper.removeChild(loadingEl);\n wrapper.appendChild(successEl);\n wrapper.appendChild(form);\n\n unsubscribe = control.subscribe((state) => onStateChange(control, state));\n // Initial render\n onStateChange(control, control.getState());\n options.onReady?.(spec);\n })();\n\n return {\n unmount() {\n unmounted = true;\n unsubscribe?.();\n if (wrapper.parentNode === host) host.removeChild(wrapper);\n },\n reset() {\n idempotencyKey = null;\n lastFingerprint = null;\n // Force a full re-render on the next state emit so cleared answers\n // actually re-render as empty inputs.\n renderedStepIndex = -1;\n renderedStale = false;\n if (stepper) {\n // stepper.reset() clears answers/credentials/consent and transitions\n // status back to \"editing\"; the emitted state re-renders the form,\n // hides the success panel (via onStateChange's else branch), and\n // repositions to step 0.\n stepper.reset();\n } else {\n form.style.display = \"\";\n successEl.style.display = \"none\";\n }\n },\n };\n}\n","/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\nexport {\n mountContactForm,\n type ContactFormMountOptions,\n type MountedWidget,\n} from \"./contact-form.js\";\n\nexport {\n mountSignupForm,\n type SignupFormMountOptions,\n} from \"./signup-form.js\";\n\nexport { injectWidgetStyles, DEFAULT_WIDGET_CSS } from \"./styles.js\";\n\nexport { cssEscape, idSelector } from \"./dom-utils.js\";\n\n/**\n * Namespace entrypoint mirroring the plan's mount API:\n * OnboardingWidget.mount(el, { onboarder, form: 'contact'|'signup', baseUrl, ... })\n */\nimport { mountContactForm } from \"./contact-form.js\";\nimport type { ContactFormMountOptions, MountedWidget } from \"./contact-form.js\";\nimport { mountSignupForm } from \"./signup-form.js\";\nimport type { SignupFormMountOptions } from \"./signup-form.js\";\n\nexport type WidgetMountOptions =\n | ContactFormMountOptions\n | SignupFormMountOptions;\n\nexport const OnboardingWidget = {\n /**\n * Mount the onboarding widget into a host element.\n *\n * @param el - The DOM element to render into.\n * @param options - Widget configuration. `form: \"contact\"` renders the\n * fixed contact form (Phase 1); `form: \"signup\"` fetches the D540 spec\n * and renders the dynamic stepper (Phase 2 — siteKey comes from the\n * spec's botChallenge unless overridden).\n * @returns A mounted widget control (unmount / reset).\n *\n * @example\n * ```ts\n * import { OnboardingWidget } from \"@nodii/onboarding/widget\";\n *\n * OnboardingWidget.mount(document.getElementById(\"signup-form\")!, {\n * onboarder: \"acme-corp\",\n * form: \"signup\",\n * baseUrl: \"https://api.acme.nucleus-cloud.in\",\n * onSuccess: (r) => console.log(\"landed at\", r.terminalStage),\n * });\n * ```\n */\n mount(el: HTMLElement, options: WidgetMountOptions): MountedWidget {\n if (options.form === \"contact\") {\n return mountContactForm(el, options);\n }\n if (options.form === \"signup\") {\n return mountSignupForm(el, options);\n }\n throw new Error(\n `OnboardingWidget.mount: unknown form \"${(options as { form: string }).form}\". Supported: \"contact\", \"signup\".`,\n );\n },\n} as const;\n"]}
|
package/dist/chunk-ZDY2I6KY.js
DELETED