@nodii/onboarding 0.1.0 → 0.2.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.
Files changed (56) hide show
  1. package/README.md +46 -0
  2. package/dist/{chunk-KQTS47FC.js → chunk-A3DE2IAH.js} +30 -5
  3. package/dist/chunk-A3DE2IAH.js.map +1 -0
  4. package/dist/{chunk-U6AXKGYQ.js → chunk-DWFZA5T6.js} +10 -8
  5. package/dist/chunk-DWFZA5T6.js.map +1 -0
  6. package/dist/{chunk-F75ZJERM.js → chunk-KFHVZGX6.js} +34 -14
  7. package/dist/chunk-KFHVZGX6.js.map +1 -0
  8. package/dist/{chunk-U56GQITG.js → chunk-NDSBIB3N.js} +25 -5
  9. package/dist/chunk-NDSBIB3N.js.map +1 -0
  10. package/dist/chunk-OLWR5COK.js +10 -0
  11. package/dist/chunk-OLWR5COK.js.map +1 -0
  12. package/dist/{chunk-IPAKPLIF.js → chunk-OVULPWNZ.js} +341 -80
  13. package/dist/chunk-OVULPWNZ.js.map +1 -0
  14. package/dist/{chunk-LVJM4CTG.js → chunk-T7EWURTF.js} +34 -19
  15. package/dist/chunk-T7EWURTF.js.map +1 -0
  16. package/dist/{chunk-BMQINH6O.js → chunk-UHOFGWI7.js} +5 -4
  17. package/dist/chunk-UHOFGWI7.js.map +1 -0
  18. package/dist/{chunk-SIMLMQPT.js → chunk-WKN4U7QF.js} +3 -5
  19. package/dist/chunk-WKN4U7QF.js.map +1 -0
  20. package/dist/{chunk-AZE3NPSY.js → chunk-ZR6X3GSM.js} +3 -3
  21. package/dist/{chunk-AZE3NPSY.js.map → chunk-ZR6X3GSM.js.map} +1 -1
  22. package/dist/{client-CqE2dF9A.d.ts → client-NvqPpfQP.d.ts} +1 -1
  23. package/dist/consent/index.d.ts +3 -3
  24. package/dist/consent/index.js +2 -2
  25. package/dist/{controller-BQb62D0N.d.ts → controller-BLH3wnxl.d.ts} +1 -1
  26. package/dist/dynamic/index.d.ts +13 -5
  27. package/dist/dynamic/index.js +4 -3
  28. package/dist/form/index.d.ts +12 -4
  29. package/dist/form/index.js +2 -2
  30. package/dist/{index-Dqfa890U.d.ts → index-BMSbQGWP.d.ts} +23 -3
  31. package/dist/index.d.ts +8 -8
  32. package/dist/index.js +9 -8
  33. package/dist/{model-mnjAEtKe.d.ts → model-BI_I-D_V.d.ts} +16 -2
  34. package/dist/{model-ESLSEbi0.d.ts → model-CEwvHlWA.d.ts} +14 -1
  35. package/dist/render-EWQXF73I.js +5 -0
  36. package/dist/{render-DC7P2BGQ.js.map → render-EWQXF73I.js.map} +1 -1
  37. package/dist/{schema-BrXb9gnh.d.ts → schema-BrtjpXfL.d.ts} +0 -10
  38. package/dist/{signup-client-BL5DfarJ.d.ts → signup-client-CS95nkVO.d.ts} +4 -4
  39. package/dist/spec/index.d.ts +3 -3
  40. package/dist/spec/index.js +2 -2
  41. package/dist/submit/index.d.ts +5 -5
  42. package/dist/submit/index.js +3 -2
  43. package/dist/viewer/index.d.ts +3 -3
  44. package/dist/viewer/index.js +1 -1
  45. package/dist/widget/index.d.ts +61 -22
  46. package/dist/widget/index.js +9 -8
  47. package/package.json +1 -1
  48. package/dist/chunk-BMQINH6O.js.map +0 -1
  49. package/dist/chunk-F75ZJERM.js.map +0 -1
  50. package/dist/chunk-IPAKPLIF.js.map +0 -1
  51. package/dist/chunk-KQTS47FC.js.map +0 -1
  52. package/dist/chunk-LVJM4CTG.js.map +0 -1
  53. package/dist/chunk-SIMLMQPT.js.map +0 -1
  54. package/dist/chunk-U56GQITG.js.map +0 -1
  55. package/dist/chunk-U6AXKGYQ.js.map +0 -1
  56. package/dist/render-DC7P2BGQ.js +0 -5
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/consent/model.ts"],"names":[],"mappings":"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","file":"chunk-U56GQITG.js","sourcesContent":["/**\n * D543 §4 ConsentPack spec model — the `consentPack` block that GET\n * /api/v1/public/onboarding/spec grows on top of the D540 shape:\n *\n * consentPack: {\n * documents: [\n * { doc_type, custom_key?, title, version_no, content_hash,\n * download_url, acceptance_level, required }\n * ]\n * }\n *\n * The intake projects ONLY `live` versions into this block (D543 §4);\n * `download_url` is a short-TTL presigned GET the SDK renders/opens.\n *\n * `acceptance_level` (D543 §2) is a per-document GATE:\n * - \"checkbox\" — a single accept checkbox (basic clickwrap).\n * - \"scroll_then_accept\" — accept disabled until the doc is scrolled to\n * the end (client asserts evidence.scrolled_to_end).\n * - \"open_then_accept\" — accept disabled until the doc is opened/viewed\n * (client asserts evidence.opened).\n * (E-signature is a deferred future level, D543 §2 — NOT modeled here.)\n *\n * FAIL-CLOSED (R1 + D543 §5 / D540 §1): a malformed consentPack throws\n * OnboardingSpecInvalidError at parse time — never rendered half-parsed\n * (a dropped `required` doc would let a user submit without consent, and a\n * missing `content_hash`/`version_no` would break the server's re-validation\n * match). The SDK refuses to render a consent step it cannot trust.\n *\n * DOM-ID HARDENING: a document's DOM-id token is derived from `doc_type`\n * (a fixed enum — safe) or, for custom docs, from `custom_key` (free-form\n * from the served spec). Custom keys are interpolated into element ids and\n * (historically) selectors by the widget layer, so they are constrained to\n * the SAME strict identifier alphabet as field keys (CUSTOM_KEY_PATTERN,\n * identical to the spec model's FIELD_KEY_PATTERN) and REJECTED at parse time\n * if they carry CSS/selector metacharacters. This is layer 1; the widget also\n * CSS.escapes every id token as defense-in-depth.\n *\n * SUBMIT PIN (P4): the submit array carries {legalDocumentId, versionNo,\n * accepted, evidence} — the server matches on legalDocumentId + versionNo\n * (contentHash is spec-side integrity metadata, NOT echoed on submit; a\n * content change publishes a new versionNo, so versionNo is a complete pin).\n *\n * DRIFT 5e3df7a3 (2026-07-14, consumer-visible) — RESOLVED by the canonical\n * shape: D543 §4 as literally written omitted `legal_document_id` from the\n * spec block, yet the submit array is KEYED on it (the server matches\n * legalDocumentId + versionNo against the live version). The\n * canonical alignment (both tiers, camelCase) INCLUDES `legalDocumentId` in\n * the spec `consentPack.documents[]`, exactly as the drift proposed. This\n * model REQUIRES it (fail-closed OnboardingSpecInvalidError if missing).\n */\n\nimport { z } from \"zod/v3\";\n\n/**\n * DOM-id-safe custom-key alphabet. INTENTIONALLY identical to the spec\n * model's FIELD_KEY_PATTERN (`/^[A-Za-z0-9_-]+$/`), duplicated here rather\n * than imported to avoid a spec↔consent import cycle (spec/model.ts imports\n * consentPackSchema from this file). Any change to one must mirror the other.\n */\nconst CUSTOM_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;\n\n/** D543 §2 acceptance-level enum. Extensible (adding a level is additive). */\nexport const ACCEPTANCE_LEVELS = [\n \"checkbox\",\n \"scroll_then_accept\",\n \"open_then_accept\",\n] as const;\n\nexport type AcceptanceLevel = (typeof ACCEPTANCE_LEVELS)[number];\n\nexport const acceptanceLevelSchema = z.enum(ACCEPTANCE_LEVELS);\n\n/** D543 §3 docType enum. */\nexport const DOC_TYPES = [\"tos\", \"privacy\", \"dpa\", \"custom\"] as const;\nexport type ConsentDocType = (typeof DOC_TYPES)[number];\n\n/**\n * One live legal document projected into the consent step. Mirrors the D543\n * §4 `consentPack.documents[]` element — CANONICAL camelCase wire shape (both\n * tenant + platform tiers aligned to this): { legalDocumentId, docType,\n * customKey (nullable), title, versionNo, contentHash, downloadUrl,\n * acceptanceLevel, required }. The `acceptanceLevel` enum VALUES stay snake\n * (checkbox | scroll_then_accept | open_then_accept).\n *\n * Cross-field invariant (D543 §3): `customKey` is a non-null identifier when\n * `docType === \"custom\"` and MUST be null otherwise (a canonical tos/privacy/\n * dpa doc is keyed by docType; only custom docs carry a key). The custom-key\n * alphabet is DOM-id safe.\n */\nexport const consentDocumentSchema = z\n .object({\n // Server-side opaque registry id (D543 §3 legal_documents.id). Echoed\n // verbatim on submit as consent.documents[].legalDocumentId (D543 §4);\n // the SDK never synthesizes it. See DRIFT 5e3df7a3 (module doc).\n legalDocumentId: z.string().min(1),\n docType: z.enum(DOC_TYPES),\n // Nullable (NOT omitted): non-custom docs send customKey:null.\n customKey: z\n .string()\n .min(1)\n .regex(\n CUSTOM_KEY_PATTERN,\n \"customKey must contain only letters, digits, underscore, or hyphen\",\n )\n .nullable(),\n title: z.string().min(1),\n // Monotonic version of the live document. This is the SUBMIT PIN: it is\n // echoed on submit (consent.documents[].versionNo) and the server matches\n // it against the current live version (mismatch ⇒ 409 consent_stale). Any\n // content change publishes a NEW version, so versionNo is a complete pin.\n versionNo: z.number().int().nonnegative(),\n // sha256 of the live artifact — spec-side integrity metadata (P4). NOT\n // echoed on submit: versionNo is the pin (a content change = new version),\n // so the submit array carries versionNo only, per the canonical wire shape.\n // The SDK exposes contentHash so a consumer can display/verify integrity;\n // the server does NOT require it on the submit array.\n contentHash: z.string().min(1),\n // Short-TTL presigned GET for the artifact bytes (D543 §4 / 04-pii).\n downloadUrl: z.string().min(1),\n acceptanceLevel: acceptanceLevelSchema,\n required: z.boolean(),\n })\n .strict()\n .superRefine((doc, ctx) => {\n if (doc.docType === \"custom\" && doc.customKey === null) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"customKey\"],\n message: \"customKey is required (non-null) when docType is 'custom'\",\n });\n }\n if (doc.docType !== \"custom\" && doc.customKey !== null) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"customKey\"],\n message: \"customKey must be null when docType is not 'custom'\",\n });\n }\n });\n\nexport type ConsentDocument = z.infer<typeof consentDocumentSchema>;\n\n/**\n * The `consentPack` block. `documents` may be empty (an onboarder with no\n * required legal docs) — the consent stage is then omitted from the flow.\n *\n * Uniqueness: no two documents may share the same STABLE key (docType, or\n * custom:<customKey> for custom docs). A duplicate would collide their DOM\n * ids AND their consent records — fail-closed at parse (the server keys the\n * registry on (scope, docType) / (scope, customKey) per D543 §3, so a\n * duplicate here is a projection bug, not a renderable spec).\n */\nexport const consentPackSchema = z\n .object({\n documents: z.array(consentDocumentSchema),\n })\n .strict()\n .superRefine((pack, ctx) => {\n const seen = new Set<string>();\n for (let i = 0; i < pack.documents.length; i++) {\n const doc = pack.documents[i];\n if (!doc) continue;\n const key = consentDocKey(doc);\n if (seen.has(key)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"documents\", i],\n message: `duplicate consent document key \"${key}\"`,\n });\n }\n seen.add(key);\n }\n });\n\nexport type ConsentPack = z.infer<typeof consentPackSchema>;\n\n/**\n * Stable, collision-proof identity for a consent document, used as the map\n * key in the controller and the DOM-id token in the widget. `docType` is a\n * fixed enum; `custom:` is prefixed for custom docs so a customKey of\n * \"tos\" can never alias the canonical tos doc.\n *\n * Note: this is NOT the submit key — the submit array keys on the server's\n * opaque `legalDocumentId` (D543 §4), which the SDK does not synthesize.\n * This is a purely CLIENT-side identity for state + DOM.\n */\nexport function consentDocKey(doc: {\n docType: ConsentDocType;\n customKey?: string | null | undefined;\n}): string {\n return doc.docType === \"custom\"\n ? `custom:${doc.customKey ?? \"\"}`\n : doc.docType;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/form/state.ts"],"names":[],"mappings":"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","file":"chunk-U6AXKGYQ.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: undefined,\n companyName: \"\",\n contactName: \"\",\n email: \"\",\n phone: undefined,\n message: undefined,\n interestModules: [],\n sizeBand: undefined,\n attribution: undefined,\n privacyNoticeAcknowledged: false,\n marketingOptIn: false,\n intakeKind: \"enquiry\",\n website: 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,5 +0,0 @@
1
- export { _resetPdfWorkerState, renderConsentDocument } from './chunk-LVJM4CTG.js';
2
- import './chunk-SEKNVHD3.js';
3
- import './chunk-XJTJPBJB.js';
4
- //# sourceMappingURL=render-DC7P2BGQ.js.map
5
- //# sourceMappingURL=render-DC7P2BGQ.js.map