@captello/ulc-webview-sdk 0.2.0 → 0.4.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 CHANGED
@@ -31,7 +31,14 @@ pnpm add @captello/ulc-webview-sdk
31
31
  ## Quick start
32
32
 
33
33
  ```ts
34
- import { CaptelloWebview, buildEmbedUrl, FormMode, LauncherType, OutboundMessageType } from "@captello/ulc-webview-sdk";
34
+ import {
35
+ CaptelloWebview,
36
+ buildEmbedUrl,
37
+ FormMode,
38
+ Language,
39
+ LauncherType,
40
+ OutboundMessageType,
41
+ } from "@captello/ulc-webview-sdk";
35
42
 
36
43
  // 1. Build the embed URL. Pass just the capture origin — the SDK appends the
37
44
  // capture path for you (passing the full ".../capture/submission" URL also works).
@@ -39,7 +46,7 @@ const src = buildEmbedUrl("https://capture.captello.com", {
39
46
  formId: 1234,
40
47
  mode: FormMode.Submit,
41
48
  launcher: LauncherType.EventGenWeb,
42
- language: "en",
49
+ language: Language.English,
43
50
  });
44
51
 
45
52
  // 2. Point an iframe at it.
@@ -383,7 +390,7 @@ const src = buildEmbedUrl(base, {
383
390
  actionButtonPosition: ActionButtonPosition.Hidden,
384
391
  mode: FormMode.Submit,
385
392
  launcher: LauncherType.EventGenWeb,
386
- language: code || undefined,
393
+ language: code as Language | undefined,
387
394
  });
388
395
  ```
389
396
 
@@ -39,6 +39,20 @@ var ActionButtonPosition = /* @__PURE__ */ ((ActionButtonPosition2) => {
39
39
  ActionButtonPosition2["Hidden"] = "2";
40
40
  return ActionButtonPosition2;
41
41
  })(ActionButtonPosition || {});
42
+ var Language = /* @__PURE__ */ ((Language2) => {
43
+ Language2["Arabic"] = "ar";
44
+ Language2["German"] = "de";
45
+ Language2["English"] = "en";
46
+ Language2["Spanish"] = "es";
47
+ Language2["French"] = "fr";
48
+ Language2["Italian"] = "it";
49
+ Language2["Japanese"] = "ja";
50
+ Language2["Korean"] = "ko";
51
+ Language2["Dutch"] = "nl";
52
+ Language2["Portuguese"] = "pt";
53
+ Language2["Chinese"] = "zh";
54
+ return Language2;
55
+ })(Language || {});
42
56
  var OPTION_TO_PARAM = [
43
57
  ["formId", "f" /* FormId */],
44
58
  ["submissionToken", "s" /* SubmissionToken */],
@@ -95,6 +109,6 @@ function buildEmbedUrl(baseUrl, options = {}) {
95
109
  return url.toString();
96
110
  }
97
111
 
98
- export { ActionButtonPosition, EmbedParam, FormMode, LauncherType, buildEmbedUrl };
99
- //# sourceMappingURL=chunk-RKAY66VV.js.map
100
- //# sourceMappingURL=chunk-RKAY66VV.js.map
112
+ export { ActionButtonPosition, EmbedParam, FormMode, Language, LauncherType, buildEmbedUrl };
113
+ //# sourceMappingURL=chunk-4E7OW4RJ.js.map
114
+ //# sourceMappingURL=chunk-4E7OW4RJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/embed-url.ts"],"names":["EmbedParam","FormMode","LauncherType","ActionButtonPosition","Language"],"mappings":"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","file":"chunk-4E7OW4RJ.js","sourcesContent":["/**\n * Builder for the Captello capture webview embed URL.\n *\n * The webview reads its configuration from query-string params. The short keys\n * below are the contract the webview expects (see the webview's `PARAMS` enum);\n * this builder maps friendly option names onto those keys so hosts never have to\n * hard-code `\"f\"`, `\"m\"`, etc.\n */\n\n/** Query-param keys understood by the webview. */\nexport enum EmbedParam {\n FormId = \"f\",\n SubmissionToken = \"s\",\n StationId = \"st\",\n Mode = \"m\",\n EventWebAccessToken = \"e\",\n ActivationId = \"a\",\n Language = \"l\",\n ActionButtonPosition = \"b\",\n FormType = \"form_type\",\n Launcher = \"launcher\",\n SubmissionType = \"t\",\n SubmitButtonBottomPadding = \"sbbp\",\n Platform = \"platform\",\n HideEmail = \"he\",\n ConnexionsEmbedMode = \"cem\",\n /** Edit mode read-only: locks email-mapped and invitation-code elements. */\n Emro = \"emro\",\n /** Context for filtering form-fill actions (e.g. MMP outbound/inbound/notes). */\n UseIn = \"useIn\",\n}\n\n/** Form render mode (the webview's `FormMode`). */\nexport enum FormMode {\n Preview = \"preview\",\n Submit = \"submit\",\n Edit = \"edit\",\n View = \"view\",\n}\n\n/** Identifies the host embedding the webview (the webview's `LAUNCHER_TYPES`). */\nexport enum LauncherType {\n EventGenMobile = \"event_gen_mobile\",\n EventGenWeb = \"event_gen_web\",\n WebApp = \"webapp\",\n Mmp = \"MMP\",\n}\n\n/** `form_type` discriminator. */\nexport type FormType = \"template\" | \"device\";\n\n/** `t` (submission type) discriminator. */\nexport type SubmissionType = \"normal\" | \"drafted\";\n\n/**\n * Action-button position param (`b`), mirroring the webview's `CTABtnPosition`.\n * The wire values are numeric strings; use {@link ActionButtonPosition} for the\n * readable names.\n */\nexport enum ActionButtonPosition {\n Fixed = \"0\",\n Bottom = \"1\",\n Hidden = \"2\",\n}\n\n/** Supported webview languages. The wire value is the two-letter code. */\nexport enum Language {\n Arabic = \"ar\",\n German = \"de\",\n English = \"en\",\n Spanish = \"es\",\n French = \"fr\",\n Italian = \"it\",\n Japanese = \"ja\",\n Korean = \"ko\",\n Dutch = \"nl\",\n Portuguese = \"pt\",\n Chinese = \"zh\",\n}\n\n/** Context for filtering form-fill actions, sent as the `useIn` param. */\nexport type UseInContext = \"outbound\" | \"inbound\" | \"notes\";\n\n/**\n * Options for {@link buildEmbedUrl}. Every field is optional; only the ones you set\n * are written to the URL. `formId` is effectively required for a real embed but is\n * left optional so callers can build preview/partial URLs.\n */\nexport interface EmbedUrlOptions {\n formId?: string | number;\n submissionToken?: string;\n stationId?: string | number;\n mode?: FormMode;\n eventWebAccessToken?: string;\n activationId?: string | number;\n language?: Language;\n actionButtonPosition?: ActionButtonPosition;\n formType?: FormType;\n launcher?: LauncherType;\n submissionType?: SubmissionType;\n submitButtonBottomPadding?: string | number;\n /** Context for filtering form-fill actions (the `useIn` param). */\n useIn?: UseInContext;\n platform?: \"web\" | \"mobile\";\n hideEmail?: boolean;\n /** Connexions embed mode: suppress in-webview redirect/vCard download. */\n connexionsEmbedMode?: boolean;\n /** Edit mode read-only. */\n emro?: boolean;\n /**\n * Extra query params to append verbatim (e.g. prospect tracking params the\n * webview forwards on submit). Values are stringified; `undefined`/`null` skipped.\n */\n extraParams?: Record<string, string | number | boolean | undefined | null>;\n}\n\n// Maps each option onto its query key. Order here defines the order params are\n// written, which keeps generated URLs stable and diffable.\nconst OPTION_TO_PARAM: ReadonlyArray<[keyof EmbedUrlOptions, EmbedParam]> = [\n [\"formId\", EmbedParam.FormId],\n [\"submissionToken\", EmbedParam.SubmissionToken],\n [\"stationId\", EmbedParam.StationId],\n [\"mode\", EmbedParam.Mode],\n [\"eventWebAccessToken\", EmbedParam.EventWebAccessToken],\n [\"activationId\", EmbedParam.ActivationId],\n [\"language\", EmbedParam.Language],\n [\"actionButtonPosition\", EmbedParam.ActionButtonPosition],\n [\"formType\", EmbedParam.FormType],\n [\"launcher\", EmbedParam.Launcher],\n [\"submissionType\", EmbedParam.SubmissionType],\n [\"submitButtonBottomPadding\", EmbedParam.SubmitButtonBottomPadding],\n [\"useIn\", EmbedParam.UseIn],\n [\"platform\", EmbedParam.Platform],\n];\n\n// Boolean flags are encoded as \"1\" when true and omitted when false/unset, matching\n// how the webview reads them (`Boolean(queryParams[key])` / presence checks).\nconst BOOLEAN_OPTION_TO_PARAM: ReadonlyArray<[keyof EmbedUrlOptions, EmbedParam]> = [\n [\"hideEmail\", EmbedParam.HideEmail],\n [\"connexionsEmbedMode\", EmbedParam.ConnexionsEmbedMode],\n [\"emro\", EmbedParam.Emro],\n];\n\n/** The path the capture webview is served at. The SDK owns this so callers don't. */\nexport const CAPTURE_SUBMISSION_PATH = \"/capture/submission\";\n\n// Recognized capture routes — if the base URL already targets one of these, it is kept\n// as-is; otherwise the canonical submission path is appended. `capture/activation` is\n// preserved so activation embeds aren't rewritten to a submission URL.\nconst CAPTURE_PATH_PATTERN = /\\/capture\\/(submission|activation)\\/?$/;\n\n/**\n * Normalizes a base capture URL so the path is always a valid capture route, no matter\n * what the caller passed. This is the fix for the \"do I include `/capture/submission`?\"\n * footgun: the origin, the origin with a trailing slash, and the full path all converge\n * to the same correct URL.\n *\n * - Origin only (`https://capture.captello.com`) → path set to `/capture/submission`.\n * - Already a capture route (`…/capture/submission`, `…/capture/activation`, with or\n * without a trailing slash) → kept (trailing slash trimmed).\n * - A base path (`https://host/webview`) → `/capture/submission` appended to it, so\n * sub-path deployments still work.\n *\n * Existing query params and the origin are always preserved.\n */\nfunction normalizeCaptureUrl(baseUrl: string): URL {\n const url = new URL(baseUrl);\n\n if (CAPTURE_PATH_PATTERN.test(url.pathname)) {\n url.pathname = url.pathname.replace(/\\/+$/, \"\"); // drop any trailing slash\n return url;\n }\n\n const base = url.pathname.replace(/\\/+$/, \"\"); // \"\" for origin/\"/\", \"/webview\" for a sub-path\n url.pathname = `${base}${CAPTURE_SUBMISSION_PATH}`;\n return url;\n}\n\n/**\n * Builds an absolute embed URL from a capture base URL and typed options.\n *\n * You only need to pass the **capture origin** — the SDK appends the capture path for\n * you. Passing the origin, the origin with a trailing slash, or the full\n * `…/capture/submission` URL all produce the same correct result, so there's nothing to\n * get wrong. Existing query params on `baseUrl` are preserved; options override params\n * with the same key.\n *\n * @example\n * // All three are equivalent:\n * buildEmbedUrl(\"https://capture.captello.com\", { formId: 1234, mode: FormMode.Submit });\n * buildEmbedUrl(\"https://capture.captello.com/\", { formId: 1234, mode: FormMode.Submit });\n * buildEmbedUrl(\"https://capture.captello.com/capture/submission\", { formId: 1234, mode: FormMode.Submit });\n * // → \"https://capture.captello.com/capture/submission?f=1234&m=submit\"\n */\nexport function buildEmbedUrl(baseUrl: string, options: EmbedUrlOptions = {}): string {\n const url = normalizeCaptureUrl(baseUrl);\n\n for (const [optionKey, paramKey] of OPTION_TO_PARAM) {\n const value = options[optionKey];\n if (value !== undefined && value !== null && value !== \"\") {\n url.searchParams.set(paramKey, String(value));\n }\n }\n\n for (const [optionKey, paramKey] of BOOLEAN_OPTION_TO_PARAM) {\n if (options[optionKey]) {\n url.searchParams.set(paramKey, \"1\");\n }\n }\n\n if (options.extraParams) {\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n}\n"]}
@@ -16,12 +16,6 @@ var InboundMessageType = /* @__PURE__ */ ((InboundMessageType2) => {
16
16
  InboundMessageType2["TriggerValidation"] = "trigger_validation";
17
17
  return InboundMessageType2;
18
18
  })(InboundMessageType || {});
19
- var PrefillDataType = /* @__PURE__ */ ((PrefillDataType2) => {
20
- PrefillDataType2["UlcSubmission"] = "ulc_submission";
21
- PrefillDataType2["Info"] = "info";
22
- PrefillDataType2["UlcSubmissionAndInfo"] = "ulc_submission_and_info";
23
- return PrefillDataType2;
24
- })(PrefillDataType || {});
25
19
  var OUTBOUND_TYPES = new Set(Object.values(OutboundMessageType));
26
20
  function isPlainObject(value) {
27
21
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -253,24 +247,8 @@ var CaptelloWebview = class {
253
247
  triggerValidation(target) {
254
248
  this.send({ type: "trigger_validation" /* TriggerValidation */, target });
255
249
  }
256
- /** Pre-fill the form from a submission body (a received body or a partial). */
257
- prefillSubmission(submission) {
258
- this.send({
259
- type: "form_prefill" /* FormPrefill */,
260
- data_type: "ulc_submission" /* UlcSubmission */,
261
- data: submission
262
- });
263
- }
264
- /** Pre-fill the form from a list of transcription field/value items. */
265
- prefillInfo(info) {
266
- this.send({
267
- type: "form_prefill" /* FormPrefill */,
268
- data_type: "info" /* Info */,
269
- data: info
270
- });
271
- }
272
- /** Pre-fill the form from a submission plus transcription items. */
273
- prefillSubmissionAndInfo(data) {
250
+ /** Pre-fill form fields from a submission body, transcription items, or both. */
251
+ prefill(data) {
274
252
  this.send({
275
253
  type: "form_prefill" /* FormPrefill */,
276
254
  data_type: "ulc_submission_and_info" /* UlcSubmissionAndInfo */,
@@ -328,6 +306,6 @@ var CaptelloWebview = class {
328
306
  }
329
307
  };
330
308
 
331
- export { CaptelloWebview, InboundMessageType, OutboundMessageType, PrefillDataType, SubmissionError, SubmissionTimeoutError, parseOutboundMessage };
332
- //# sourceMappingURL=chunk-IMJYXGWK.js.map
333
- //# sourceMappingURL=chunk-IMJYXGWK.js.map
309
+ export { CaptelloWebview, InboundMessageType, OutboundMessageType, SubmissionError, SubmissionTimeoutError, parseOutboundMessage };
310
+ //# sourceMappingURL=chunk-PFFBCSJ2.js.map
311
+ //# sourceMappingURL=chunk-PFFBCSJ2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/messages.ts","../src/client.ts"],"names":["OutboundMessageType","InboundMessageType"],"mappings":"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","file":"chunk-PFFBCSJ2.js","sourcesContent":["/**\n * The message protocol exchanged between the Captello capture webview (the iframe)\n * and its host page.\n *\n * Wire format (this is the contract — match it exactly):\n * - Every message is a JSON **string**. The webview sends outbound messages with\n * `JSON.stringify(message)` and reads inbound messages with `JSON.parse(event.data)`.\n * A host that posts a raw object instead of a string will be ignored, because the\n * webview's parser produces a non-object and bails.\n * - Every message is an object with a `type` discriminator. Inbound and outbound\n * types are disjoint string enums.\n *\n * Direction is named from the **webview's** point of view:\n * - {@link OutboundMessageType}: webview → host (the host listens for these).\n * - {@link InboundMessageType}: host → webview (the host sends these).\n */\n\nimport type { VisibleSubmissionDataItem } from \"./submission-data\";\n\n/* ------------------------------------------------------------------ *\n * Outbound: webview → host\n * ------------------------------------------------------------------ */\n\n/** Message `type` values the webview emits to its host. */\nexport enum OutboundMessageType {\n /** The form finished loading and rendering. Safe to interact with it after this. */\n FormLoadComplete = \"form_load_complete\",\n /** A user-facing error occurred; `data` is the translated, display-ready message. */\n FormErrorMessage = \"form_error_message\",\n /**\n * Emitted for embedded forms instead of submitting directly: `data` is the full\n * submission body for the host to persist/forward.\n */\n SubmissionBody = \"submission_body\",\n /** The form was submitted successfully. `action` indicates whether it was a new submission or an update. */\n FormSubmitSuccess = \"form_submit_success\",\n /** Connexions: the host should perform the profile redirect (embed mode). */\n ConnexionsProfileRedirect = \"connexions_profile_redirect\",\n /** Connexions: the host should trigger the vCard download (embed mode). */\n ConnexionsDownloadVcard = \"connexions_download_vcard\",\n}\n\n/**\n * Opaque submission payload carried by {@link OutboundMessageType.SubmissionBody}.\n *\n * This mirrors the webview's internal `FormSubmission` model. It is intentionally\n * typed as an open record here so the SDK stays decoupled from the app's full model\n * graph; the documented fields below are stable, the rest are passed through as-is.\n * Host code that needs the deep element-value types should treat `data` as untyped\n * and key it by element id (e.g. `\"element_12\"`, `\"element_12_3\"`).\n */\nexport interface SubmissionBody {\n id: number;\n form_id: number;\n prospect_id: number;\n email: string;\n first_name: string;\n last_name: string;\n full_name: string;\n company: string;\n phone: string;\n /** Submitted values keyed by element id / sub-element id. */\n data: Record<string, unknown>;\n /**\n * Visible, filled elements ready to render as key/value rows — one item per\n * element, discriminated by `element_type` (narrow on it for a precisely-typed\n * `element_value`). See {@link VisibleSubmissionDataItem}. May be absent on older\n * webview builds.\n */\n visible_submissions_data?: VisibleSubmissionDataItem[];\n submission_date: string;\n /** Query-string params the webview was loaded with, echoed back on submit. */\n query_parameters?: Record<string, string>;\n /** Additional fields from the webview's submission model are passed through verbatim. */\n [key: string]: unknown;\n}\n\n/**\n * Loose submission shape accepted when **pre-filling** the form (host → webview).\n *\n * Distinct from {@link SubmissionBody}: a received `submission_body` is always fully\n * populated, but when pre-filling you typically either round-trip a previously-received\n * body or pass a partial object assembled from your own data. A {@link SubmissionBody}\n * is assignable to this, so round-tripping just works.\n */\nexport interface SubmissionPrefill {\n /** Submitted values keyed by element id / sub-element id. */\n data?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface FormLoadCompleteMessage {\n type: OutboundMessageType.FormLoadComplete;\n}\ninterface FormSubmitSuccessMessage {\n type: OutboundMessageType.FormSubmitSuccess;\n action: \"create\" | \"update\";\n}\ninterface FormErrorMessageMessage {\n type: OutboundMessageType.FormErrorMessage;\n /** Translated, display-ready error text. */\n data: string;\n}\ninterface SubmissionBodyMessage {\n type: OutboundMessageType.SubmissionBody;\n data: SubmissionBody;\n}\ninterface ConnexionsProfileRedirectMessage {\n type: OutboundMessageType.ConnexionsProfileRedirect;\n}\ninterface ConnexionsDownloadVcardMessage {\n type: OutboundMessageType.ConnexionsDownloadVcard;\n}\n\n/** Discriminated union of every message the webview can emit to its host. */\nexport type OutboundMessage =\n | FormLoadCompleteMessage\n | FormSubmitSuccessMessage\n | FormErrorMessageMessage\n | SubmissionBodyMessage\n | ConnexionsProfileRedirectMessage\n | ConnexionsDownloadVcardMessage;\n\n/** Maps each outbound `type` to its full message shape (used by the client's `.on`). */\nexport type OutboundMessageMap = {\n [M in OutboundMessage as M[\"type\"]]: M;\n};\n\n/* ------------------------------------------------------------------ *\n * Inbound: host → webview\n * ------------------------------------------------------------------ */\n\n/** Message `type` values the host sends into the webview. */\nexport enum InboundMessageType {\n /** Programmatically trigger form submission (as if the user pressed submit). */\n Submit = \"submit_form\",\n /** Reset the form, clearing all entered values. */\n Reset = \"reset_form\",\n /** Pre-fill the form with existing data. */\n FormPrefill = \"form_prefill\",\n /** Switch the current submission into draft-update mode. */\n UpdateDraft = \"update_draft\",\n /** Run validation against a target field (or the whole form). */\n TriggerValidation = \"trigger_validation\",\n}\n\n/** Shape selector for {@link InboundMessageType.FormPrefill} payloads. */\nexport enum PrefillDataType {\n UlcSubmissionAndInfo = \"ulc_submission_and_info\",\n}\n\n/** Targets for {@link InboundMessageType.TriggerValidation}. */\nexport type ValidationTarget = \"invitation_code\" | \"email\" | \"all\";\n\n/**\n * A single transcription field/value item for the `info` prefill array.\n *\n * The webview matches each item to a form element by `ll_field_unique_identifier`\n * alone (e.g. `\"FirstName\"`, `\"Email\"`); `ll_field_id` is catalog metadata and is not\n * used for matching, so it is accepted as either a number or a string. `value` is\n * typically a string but may be a boolean (e.g. the PII opt-out field).\n */\nexport interface PrefillInfoItem {\n ll_field_unique_identifier: string;\n ll_field_id?: string | number;\n value: string | boolean;\n}\n\ninterface SubmitMessage {\n type: InboundMessageType.Submit;\n}\ninterface ResetMessage {\n type: InboundMessageType.Reset;\n}\ninterface UpdateDraftMessage {\n type: InboundMessageType.UpdateDraft;\n}\ninterface TriggerValidationMessage {\n type: InboundMessageType.TriggerValidation;\n target: ValidationTarget;\n}\ninterface PrefillMessage {\n type: InboundMessageType.FormPrefill;\n data_type: PrefillDataType.UlcSubmissionAndInfo;\n data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] };\n}\n\n/** Discriminated union of every message the host can send into the webview. */\nexport type InboundMessage =\n | SubmitMessage\n | ResetMessage\n | UpdateDraftMessage\n | TriggerValidationMessage\n | PrefillMessage;\n\n/* ------------------------------------------------------------------ *\n * Runtime guards / parsing\n * ------------------------------------------------------------------ */\n\nconst OUTBOUND_TYPES: ReadonlySet<string> = new Set(Object.values(OutboundMessageType));\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Parses a raw `MessageEvent.data` value into a typed {@link OutboundMessage}, or\n * returns `null` if it is not a recognized Captello webview message.\n *\n * Accepts either a JSON string (the webview always sends strings) or an\n * already-parsed object, so it is robust to hosts/proxies that pre-parse.\n */\nexport function parseOutboundMessage(data: unknown): OutboundMessage | null {\n let value: unknown = data;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n if (!isPlainObject(value)) return null;\n if (typeof value[\"type\"] !== \"string\" || !OUTBOUND_TYPES.has(value[\"type\"])) return null;\n return value as unknown as OutboundMessage;\n}\n","import { InboundMessageType, OutboundMessageType, parseOutboundMessage, PrefillDataType } from \"./messages\";\nimport type {\n InboundMessage,\n OutboundMessage,\n OutboundMessageMap,\n PrefillInfoItem,\n SubmissionBody,\n SubmissionPrefill,\n ValidationTarget,\n} from \"./messages\";\n\n/** Listener for a specific outbound message type. */\nexport type OutboundListener<T extends OutboundMessageType> = (message: OutboundMessageMap[T]) => void;\n\n/** Listener for every outbound message (used by {@link CaptelloWebview.onAny}). */\nexport type AnyOutboundListener = (message: OutboundMessage) => void;\n\n/** Unsubscribe handle returned by every `on*` method. Calling it removes the listener. */\nexport type Unsubscribe = () => void;\n\n/**\n * Rejection reason from {@link CaptelloWebview.submitAndWait} when the webview reports\n * a `form_error_message`. `message` is the translated, display-ready text.\n */\nexport class SubmissionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SubmissionError\";\n }\n}\n\n/**\n * Rejection reason from {@link CaptelloWebview.submitAndWait} when no `submission_body`\n * or `form_error_message` arrives within the timeout.\n */\nexport class SubmissionTimeoutError extends Error {\n constructor(public readonly timeoutMs: number) {\n super(`Captello webview did not respond to submit within ${timeoutMs}ms.`);\n this.name = \"SubmissionTimeoutError\";\n }\n}\n\nexport interface CaptelloWebviewOptions {\n /**\n * Origin to validate incoming messages against and to target outgoing messages.\n * Strongly recommended — set it to the webview's origin (e.g.\n * `\"https://capture.captello.com\"`), e.g. `new URL(embedUrl).origin`.\n *\n * Defaults to `\"*\"`, which accepts messages from any origin and posts without an\n * origin check. Only acceptable for trusted/local development.\n */\n targetOrigin?: string;\n /**\n * The window to attach the `message` listener to. Defaults to the global `window`.\n * Override for testing or non-standard host environments.\n */\n hostWindow?: Window;\n /**\n * If `true` (default), incoming messages are accepted only when they originate\n * from the bound iframe's `contentWindow`. Set `false` only if the webview relays\n * messages through an intermediate window and source matching is impossible.\n */\n matchSource?: boolean;\n /**\n * If `true` (default), messages sent before the webview reports\n * `form_load_complete` are buffered and flushed, in order, once it's ready. This\n * removes a common footgun: calling `prefill(...)` right after mount would\n * otherwise post to a form that isn't listening yet and be silently dropped.\n *\n * Set `false` to send immediately (the legacy behavior). Note: a client that\n * attaches *after* the form already loaded will not have seen `form_load_complete`,\n * so its queued messages won't flush — create the client with the iframe.\n */\n queueUntilReady?: boolean;\n}\n\n/** Emits a console warning in development builds only. No-op in production / no bundler. */\nfunction devWarn(message: string): void {\n try {\n if (typeof process !== \"undefined\" && process.env && process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(message);\n }\n } catch {\n /* `process` not defined (pure browser, no bundler define) → stay silent */\n }\n}\n\ntype ElementOrFrame = HTMLIFrameElement | { contentWindow: Window | null };\n\n/**\n * Host-side controller for an embedded Captello capture webview.\n *\n * Wraps a single `<iframe>` and encodes the full message protocol:\n * - **Receiving** (webview → host): subscribe with {@link on} / {@link onAny}.\n * - **Sending** (host → webview): use {@link submit}, {@link reset}, {@link prefill},\n * {@link triggerValidation}, {@link updateDraft}, or the lower-level {@link send}.\n *\n * Wire details handled for you: outgoing messages are `JSON.stringify`'d (the webview\n * parses inbound data with `JSON.parse`, so a raw object would be ignored), and\n * incoming messages are validated by origin + source before being parsed.\n *\n * @example\n * ```ts\n * const iframe = document.querySelector(\"iframe\")!;\n * const webview = new CaptelloWebview(iframe, {\n * targetOrigin: \"https://capture.captello.com\",\n * });\n *\n * webview.on(OutboundMessageType.FormLoadComplete, () => console.log(\"ready\"));\n * webview.on(OutboundMessageType.SubmissionBody, (msg) => save(msg.data));\n *\n * // later, drive the form:\n * webview.submit();\n *\n * // on teardown:\n * webview.destroy();\n * ```\n */\nexport class CaptelloWebview {\n private readonly frame: ElementOrFrame;\n private readonly targetOrigin: string;\n private readonly hostWindow: Window;\n private readonly matchSource: boolean;\n\n private readonly listeners = new Map<OutboundMessageType, Set<OutboundListener<OutboundMessageType>>>();\n private readonly anyListeners = new Set<AnyOutboundListener>();\n private readonly boundHandler: (event: MessageEvent) => void;\n private destroyed = false;\n\n private readonly queueUntilReady: boolean;\n /** True once `form_load_complete` has been observed. */\n private ready = false;\n /** Messages sent before ready, flushed in order on load. */\n private readonly outbox: InboundMessage[] = [];\n\n constructor(frame: ElementOrFrame, options: CaptelloWebviewOptions = {}) {\n if (!frame) {\n throw new Error(\"CaptelloWebview: an iframe element (or { contentWindow }) is required.\");\n }\n this.frame = frame;\n this.targetOrigin = options.targetOrigin ?? \"*\";\n this.matchSource = options.matchSource ?? true;\n this.queueUntilReady = options.queueUntilReady ?? true;\n\n // Nudge (dev only) when running without origin scoping. \"*\" accepts inbound\n // messages from any origin and posts outbound without an origin check — fine\n // for local/trusted dev, unsafe in production. Set targetOrigin to the\n // webview's origin, e.g. `new URL(embedUrl).origin`.\n if (this.targetOrigin === \"*\") {\n devWarn(\n '[captello-sdk] No targetOrigin set — defaulting to \"*\", which accepts messages ' +\n \"from any origin and posts without an origin check. Set targetOrigin to the webview's \" +\n \"origin (e.g. new URL(embedUrl).origin) in production.\",\n );\n }\n\n const hostWindow = options.hostWindow ?? (typeof window !== \"undefined\" ? window : undefined);\n if (!hostWindow) {\n throw new Error(\n \"CaptelloWebview: no host window available. Pass `hostWindow` when constructing outside a browser.\",\n );\n }\n this.hostWindow = hostWindow;\n\n this.boundHandler = (event: MessageEvent) => this.handleMessage(event);\n this.hostWindow.addEventListener(\"message\", this.boundHandler);\n }\n\n /** `true` once the webview has reported `form_load_complete`. */\n get isReady(): boolean {\n return this.ready;\n }\n\n /* -------------------------------------------------------------- *\n * Receiving (webview → host)\n * -------------------------------------------------------------- */\n\n /**\n * Subscribe to a single outbound message type. Returns an unsubscribe function.\n *\n * @example webview.on(OutboundMessageType.FormErrorMessage, (m) => toast(m.data));\n */\n on<T extends OutboundMessageType>(type: T, listener: OutboundListener<T>): Unsubscribe {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(listener as OutboundListener<OutboundMessageType>);\n return () => {\n set?.delete(listener as OutboundListener<OutboundMessageType>);\n };\n }\n\n /**\n * Subscribe once: the listener is removed automatically after it fires the first\n * time for `type`. Returns an unsubscribe function for cancelling early.\n */\n once<T extends OutboundMessageType>(type: T, listener: OutboundListener<T>): Unsubscribe {\n const off = this.on(type, (message) => {\n off();\n listener(message);\n });\n return off;\n }\n\n /** Subscribe to every outbound message regardless of type. Returns an unsubscribe function. */\n onAny(listener: AnyOutboundListener): Unsubscribe {\n this.anyListeners.add(listener);\n return () => {\n this.anyListeners.delete(listener);\n };\n }\n\n /* -------------------------------------------------------------- *\n * Sending (host → webview)\n * -------------------------------------------------------------- */\n\n /**\n * Low-level send: posts any inbound message to the webview as a JSON string.\n * Prefer the typed helpers below; use this only for forward-compatibility.\n *\n * When `queueUntilReady` is enabled (the default) and the form hasn't reported\n * `form_load_complete` yet, the message is buffered and flushed on load instead of\n * posted immediately.\n *\n * @throws if the iframe's `contentWindow` is not available (not yet loaded /\n * detached) and the message can't be queued.\n */\n send(message: InboundMessage): void {\n if (this.destroyed) {\n throw new Error(\"CaptelloWebview: cannot send after destroy().\");\n }\n if (this.queueUntilReady && !this.ready) {\n this.outbox.push(message);\n return;\n }\n this.postNow(message);\n }\n\n /** Posts a message immediately, bypassing the ready-queue. */\n private postNow(message: InboundMessage): void {\n const target = this.frame.contentWindow;\n if (!target) {\n throw new Error(\n \"CaptelloWebview: iframe.contentWindow is null. Wait for the iframe to load before sending.\",\n );\n }\n // The webview reads inbound data with JSON.parse(event.data), so it must be a string.\n target.postMessage(JSON.stringify(message), this.targetOrigin);\n }\n\n /** Marks the client ready and flushes any queued messages, in order. */\n private markReadyAndFlush(): void {\n if (this.ready) return;\n this.ready = true;\n const queued = this.outbox.splice(0);\n for (const message of queued) {\n try {\n this.postNow(message);\n } catch {\n /* iframe detached between load and flush — drop silently */\n }\n }\n }\n\n /** Programmatically submit the form (fire-and-forget). */\n submit(): void {\n this.send({ type: InboundMessageType.Submit });\n }\n\n /**\n * Submit the form and await the outcome.\n *\n * Sends `submit_form`, then resolves with the {@link SubmissionBody} when the\n * webview emits `submission_body`, or rejects with a {@link SubmissionError}\n * (carrying the translated message) when it emits `form_error_message`. Rejects\n * with a {@link SubmissionTimeoutError} if neither arrives within `timeoutMs`.\n *\n * This is the typed, leak-free version of the common \"click submit, wait for the\n * result\" flow — listeners are always cleaned up, including on timeout.\n *\n * @param timeoutMs how long to wait before giving up. Defaults to 60_000.\n * @example\n * try {\n * const body = await webview.submitAndWait();\n * await persist(body);\n * } catch (err) {\n * if (err instanceof SubmissionError) showToast(err.message);\n * }\n */\n submitAndWait(timeoutMs = 60_000): Promise<SubmissionBody> {\n return new Promise<SubmissionBody>((resolve, reject) => {\n let settled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const cleanup = () => {\n settled = true;\n offSuccess();\n offError();\n if (timer !== undefined) clearTimeout(timer);\n };\n\n const offSuccess = this.on(OutboundMessageType.SubmissionBody, (message) => {\n if (settled) return;\n cleanup();\n resolve(message.data);\n });\n const offError = this.on(OutboundMessageType.FormErrorMessage, (message) => {\n if (settled) return;\n cleanup();\n reject(new SubmissionError(message.data));\n });\n\n if (timeoutMs > 0 && timeoutMs !== Infinity) {\n timer = setTimeout(() => {\n if (settled) return;\n cleanup();\n reject(new SubmissionTimeoutError(timeoutMs));\n }, timeoutMs);\n }\n\n try {\n this.send({ type: InboundMessageType.Submit });\n } catch (err) {\n if (!settled) {\n cleanup();\n reject(err);\n }\n }\n });\n }\n\n /** Reset the form, clearing all entered values. */\n reset(): void {\n this.send({ type: InboundMessageType.Reset });\n }\n\n /** Switch the current submission into draft-update mode. */\n updateDraft(): void {\n this.send({ type: InboundMessageType.UpdateDraft });\n }\n\n /** Run validation against a target field, or `\"all\"` for the whole form. */\n triggerValidation(target: ValidationTarget): void {\n this.send({ type: InboundMessageType.TriggerValidation, target });\n }\n\n /** Pre-fill form fields from a submission body, transcription items, or both. */\n prefill(data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] }): void {\n this.send({\n type: InboundMessageType.FormPrefill,\n data_type: PrefillDataType.UlcSubmissionAndInfo,\n data,\n });\n }\n\n /* -------------------------------------------------------------- *\n * Lifecycle\n * -------------------------------------------------------------- */\n\n /** Remove the `message` listener and drop all subscriptions. Idempotent. */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.hostWindow.removeEventListener(\"message\", this.boundHandler);\n this.listeners.clear();\n this.anyListeners.clear();\n this.outbox.length = 0;\n }\n\n /* -------------------------------------------------------------- *\n * Internals\n * -------------------------------------------------------------- */\n\n private handleMessage(event: MessageEvent): void {\n if (this.destroyed) return;\n\n // Origin check: skip when targetOrigin is the wildcard. Warn (dev only) if a\n // message that *looks* like ours is dropped on origin — a common \"why isn't my\n // listener firing?\" cause.\n if (this.targetOrigin !== \"*\" && event.origin !== this.targetOrigin) {\n if (parseOutboundMessage(event.data)) {\n devWarn(\n `[captello-sdk] Ignored a Captello message from origin \"${event.origin}\" ` +\n `(expected \"${this.targetOrigin}\"). Check the targetOrigin you passed.`,\n );\n }\n return;\n }\n\n // Source check: only accept messages from the bound iframe's window.\n if (this.matchSource) {\n const expected = this.frame.contentWindow;\n if (expected && event.source !== expected) {\n if (parseOutboundMessage(event.data)) {\n devWarn(\n \"[captello-sdk] Ignored a Captello message from an unexpected source window \" +\n \"(not the bound iframe). If the webview relays through another window, set matchSource: false.\",\n );\n }\n return;\n }\n }\n\n const message = parseOutboundMessage(event.data);\n if (!message) return;\n\n // Flip to ready (and flush queued sends) the moment the form loads, before\n // dispatching to listeners — so a listener can send and have it post immediately.\n if (message.type === OutboundMessageType.FormLoadComplete) {\n this.markReadyAndFlush();\n }\n\n const set = this.listeners.get(message.type);\n if (set) {\n // Copy to a snapshot so a listener that unsubscribes mid-dispatch is safe.\n for (const listener of [...set]) listener(message);\n }\n if (this.anyListeners.size) {\n for (const listener of [...this.anyListeners]) listener(message);\n }\n }\n}\n"]}
@@ -180,7 +180,7 @@ declare enum OutboundMessageType {
180
180
  * submission body for the host to persist/forward.
181
181
  */
182
182
  SubmissionBody = "submission_body",
183
- /** The form was submitted successfully (used in kiosk / quick-capture flows). */
183
+ /** The form was submitted successfully. `action` indicates whether it was a new submission or an update. */
184
184
  FormSubmitSuccess = "form_submit_success",
185
185
  /** Connexions: the host should perform the profile redirect (embed mode). */
186
186
  ConnexionsProfileRedirect = "connexions_profile_redirect",
@@ -239,6 +239,7 @@ interface FormLoadCompleteMessage {
239
239
  }
240
240
  interface FormSubmitSuccessMessage {
241
241
  type: OutboundMessageType.FormSubmitSuccess;
242
+ action: "create" | "update";
242
243
  }
243
244
  interface FormErrorMessageMessage {
244
245
  type: OutboundMessageType.FormErrorMessage;
@@ -267,7 +268,7 @@ declare enum InboundMessageType {
267
268
  Submit = "submit_form",
268
269
  /** Reset the form, clearing all entered values. */
269
270
  Reset = "reset_form",
270
- /** Pre-fill the form with existing data. See {@link PrefillDataType}. */
271
+ /** Pre-fill the form with existing data. */
271
272
  FormPrefill = "form_prefill",
272
273
  /** Switch the current submission into draft-update mode. */
273
274
  UpdateDraft = "update_draft",
@@ -276,17 +277,12 @@ declare enum InboundMessageType {
276
277
  }
277
278
  /** Shape selector for {@link InboundMessageType.FormPrefill} payloads. */
278
279
  declare enum PrefillDataType {
279
- /** `data` is a full ULC submission (the webview's submission model). */
280
- UlcSubmission = "ulc_submission",
281
- /** `data` is a list of transcription field/value items. */
282
- Info = "info",
283
- /** `data` is `{ submission, info }` — a submission plus transcription items. */
284
280
  UlcSubmissionAndInfo = "ulc_submission_and_info"
285
281
  }
286
282
  /** Targets for {@link InboundMessageType.TriggerValidation}. */
287
283
  type ValidationTarget = "invitation_code" | "email" | "all";
288
284
  /**
289
- * A single transcription field/value item used by {@link PrefillDataType.Info}.
285
+ * A single transcription field/value item for the `info` prefill array.
290
286
  *
291
287
  * The webview matches each item to a form element by `ll_field_unique_identifier`
292
288
  * alone (e.g. `"FirstName"`, `"Email"`); `ll_field_id` is catalog metadata and is not
@@ -311,18 +307,7 @@ interface TriggerValidationMessage {
311
307
  type: InboundMessageType.TriggerValidation;
312
308
  target: ValidationTarget;
313
309
  }
314
- interface PrefillSubmissionMessage {
315
- type: InboundMessageType.FormPrefill;
316
- data_type: PrefillDataType.UlcSubmission;
317
- /** A submission body to pre-fill from (a received {@link SubmissionBody} or a partial). */
318
- data: SubmissionPrefill;
319
- }
320
- interface PrefillInfoMessage {
321
- type: InboundMessageType.FormPrefill;
322
- data_type: PrefillDataType.Info;
323
- data: PrefillInfoItem[];
324
- }
325
- interface PrefillSubmissionAndInfoMessage {
310
+ interface PrefillMessage {
326
311
  type: InboundMessageType.FormPrefill;
327
312
  data_type: PrefillDataType.UlcSubmissionAndInfo;
328
313
  data: {
@@ -331,7 +316,7 @@ interface PrefillSubmissionAndInfoMessage {
331
316
  };
332
317
  }
333
318
  /** Discriminated union of every message the host can send into the webview. */
334
- type InboundMessage = SubmitMessage | ResetMessage | UpdateDraftMessage | TriggerValidationMessage | PrefillSubmissionMessage | PrefillInfoMessage | PrefillSubmissionAndInfoMessage;
319
+ type InboundMessage = SubmitMessage | ResetMessage | UpdateDraftMessage | TriggerValidationMessage | PrefillMessage;
335
320
  /**
336
321
  * Parses a raw `MessageEvent.data` value into a typed {@link OutboundMessage}, or
337
322
  * returns `null` if it is not a recognized Captello webview message.
@@ -386,7 +371,7 @@ interface CaptelloWebviewOptions {
386
371
  /**
387
372
  * If `true` (default), messages sent before the webview reports
388
373
  * `form_load_complete` are buffered and flushed, in order, once it's ready. This
389
- * removes a common footgun: calling `prefillInfo(...)` right after mount would
374
+ * removes a common footgun: calling `prefill(...)` right after mount would
390
375
  * otherwise post to a form that isn't listening yet and be silently dropped.
391
376
  *
392
377
  * Set `false` to send immediately (the legacy behavior). Note: a client that
@@ -502,12 +487,8 @@ declare class CaptelloWebview {
502
487
  updateDraft(): void;
503
488
  /** Run validation against a target field, or `"all"` for the whole form. */
504
489
  triggerValidation(target: ValidationTarget): void;
505
- /** Pre-fill the form from a submission body (a received body or a partial). */
506
- prefillSubmission(submission: SubmissionPrefill): void;
507
- /** Pre-fill the form from a list of transcription field/value items. */
508
- prefillInfo(info: PrefillInfoItem[]): void;
509
- /** Pre-fill the form from a submission plus transcription items. */
510
- prefillSubmissionAndInfo(data: {
490
+ /** Pre-fill form fields from a submission body, transcription items, or both. */
491
+ prefill(data: {
511
492
  submission?: SubmissionPrefill;
512
493
  info?: PrefillInfoItem[];
513
494
  }): void;
@@ -516,4 +497,4 @@ declare class CaptelloWebview {
516
497
  private handleMessage;
517
498
  }
518
499
 
519
- export { type AnyOutboundListener as A, type BusinessCardValue as B, type CaptelloWebviewOptions as C, FormElementType as F, type InboundMessage as I, OutboundMessageType as O, type PrefillInfoItem as P, type SubmissionBody as S, type Unsubscribe as U, type ValidationTarget as V, type OutboundMessageMap as a, SubmissionError as b, SubmissionTimeoutError as c, type OutboundMessage as d, CaptelloWebview as e, type SubmissionPrefill as f, type AttachmentValue as g, type CompositeSubmissionValue as h, InboundMessageType as i, type OrderCheckboxSubmissionData as j, type OrderRadioSubmissionData as k, type OutboundListener as l, PrefillDataType as m, type SubmissionQuestionData as n, type VisibleSubmissionDataItem as o, type VisibleSubmissionElementType as p, type VisibleSubmissionElementValueMap as q, parseOutboundMessage as r };
500
+ export { type AnyOutboundListener as A, type BusinessCardValue as B, type CaptelloWebviewOptions as C, FormElementType as F, type InboundMessage as I, OutboundMessageType as O, type PrefillInfoItem as P, type SubmissionBody as S, type Unsubscribe as U, type ValidationTarget as V, type OutboundMessageMap as a, SubmissionError as b, SubmissionTimeoutError as c, type OutboundMessage as d, CaptelloWebview as e, type SubmissionPrefill as f, type AttachmentValue as g, type CompositeSubmissionValue as h, InboundMessageType as i, type OrderCheckboxSubmissionData as j, type OrderRadioSubmissionData as k, type OutboundListener as l, type SubmissionQuestionData as m, type VisibleSubmissionDataItem as n, type VisibleSubmissionElementType as o, type VisibleSubmissionElementValueMap as p, parseOutboundMessage as q };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AnyOutboundListener, g as AttachmentValue, B as BusinessCardValue, e as CaptelloWebview, C as CaptelloWebviewOptions, h as CompositeSubmissionValue, F as FormElementType, I as InboundMessage, i as InboundMessageType, j as OrderCheckboxSubmissionData, k as OrderRadioSubmissionData, l as OutboundListener, d as OutboundMessage, a as OutboundMessageMap, O as OutboundMessageType, m as PrefillDataType, P as PrefillInfoItem, S as SubmissionBody, b as SubmissionError, f as SubmissionPrefill, n as SubmissionQuestionData, c as SubmissionTimeoutError, U as Unsubscribe, V as ValidationTarget, o as VisibleSubmissionDataItem, p as VisibleSubmissionElementType, q as VisibleSubmissionElementValueMap, r as parseOutboundMessage } from './client-BRIlJHCg.js';
1
+ export { A as AnyOutboundListener, g as AttachmentValue, B as BusinessCardValue, e as CaptelloWebview, C as CaptelloWebviewOptions, h as CompositeSubmissionValue, F as FormElementType, I as InboundMessage, i as InboundMessageType, j as OrderCheckboxSubmissionData, k as OrderRadioSubmissionData, l as OutboundListener, d as OutboundMessage, a as OutboundMessageMap, O as OutboundMessageType, P as PrefillInfoItem, S as SubmissionBody, b as SubmissionError, f as SubmissionPrefill, m as SubmissionQuestionData, c as SubmissionTimeoutError, U as Unsubscribe, V as ValidationTarget, n as VisibleSubmissionDataItem, o as VisibleSubmissionElementType, p as VisibleSubmissionElementValueMap, q as parseOutboundMessage } from './client-Dik-Mjid.js';
2
2
 
3
3
  /**
4
4
  * Builder for the Captello capture webview embed URL.
@@ -58,6 +58,20 @@ declare enum ActionButtonPosition {
58
58
  Bottom = "1",
59
59
  Hidden = "2"
60
60
  }
61
+ /** Supported webview languages. The wire value is the two-letter code. */
62
+ declare enum Language {
63
+ Arabic = "ar",
64
+ German = "de",
65
+ English = "en",
66
+ Spanish = "es",
67
+ French = "fr",
68
+ Italian = "it",
69
+ Japanese = "ja",
70
+ Korean = "ko",
71
+ Dutch = "nl",
72
+ Portuguese = "pt",
73
+ Chinese = "zh"
74
+ }
61
75
  /** Context for filtering form-fill actions, sent as the `useIn` param. */
62
76
  type UseInContext = "outbound" | "inbound" | "notes";
63
77
  /**
@@ -72,8 +86,7 @@ interface EmbedUrlOptions {
72
86
  mode?: FormMode;
73
87
  eventWebAccessToken?: string;
74
88
  activationId?: string | number;
75
- /** Two-letter language code, e.g. `"en"`, `"de"`. */
76
- language?: string;
89
+ language?: Language;
77
90
  actionButtonPosition?: ActionButtonPosition;
78
91
  formType?: FormType;
79
92
  launcher?: LauncherType;
@@ -111,4 +124,4 @@ interface EmbedUrlOptions {
111
124
  */
112
125
  declare function buildEmbedUrl(baseUrl: string, options?: EmbedUrlOptions): string;
113
126
 
114
- export { ActionButtonPosition, EmbedParam, type EmbedUrlOptions, FormMode, type FormType, LauncherType, type SubmissionType, type UseInContext, buildEmbedUrl };
127
+ export { ActionButtonPosition, EmbedParam, type EmbedUrlOptions, FormMode, type FormType, Language, LauncherType, type SubmissionType, type UseInContext, buildEmbedUrl };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { ActionButtonPosition, EmbedParam, FormMode, LauncherType, buildEmbedUrl } from './chunk-RKAY66VV.js';
2
- export { CaptelloWebview, InboundMessageType, OutboundMessageType, PrefillDataType, SubmissionError, SubmissionTimeoutError, parseOutboundMessage } from './chunk-IMJYXGWK.js';
1
+ export { ActionButtonPosition, EmbedParam, FormMode, Language, LauncherType, buildEmbedUrl } from './chunk-4E7OW4RJ.js';
2
+ export { CaptelloWebview, InboundMessageType, OutboundMessageType, SubmissionError, SubmissionTimeoutError, parseOutboundMessage } from './chunk-PFFBCSJ2.js';
3
3
 
4
4
  // src/submission-data.ts
5
5
  var FormElementType = /* @__PURE__ */ ((FormElementType2) => {
@@ -1,5 +1,5 @@
1
- import { C as CaptelloWebviewOptions, S as SubmissionBody, O as OutboundMessageType, a as OutboundMessageMap } from './client-BRIlJHCg.js';
2
- export { b as SubmissionError, c as SubmissionTimeoutError } from './client-BRIlJHCg.js';
1
+ import { C as CaptelloWebviewOptions, S as SubmissionBody, O as OutboundMessageType, a as OutboundMessageMap } from './client-Dik-Mjid.js';
2
+ export { b as SubmissionError, c as SubmissionTimeoutError } from './client-Dik-Mjid.js';
3
3
 
4
4
  /**
5
5
  * Promise-based, one-shot helpers for imperative flows — `@captello/ulc-webview-sdk/promises`.
package/dist/promises.js CHANGED
@@ -1,5 +1,5 @@
1
- import { CaptelloWebview } from './chunk-IMJYXGWK.js';
2
- export { SubmissionError, SubmissionTimeoutError } from './chunk-IMJYXGWK.js';
1
+ import { CaptelloWebview } from './chunk-PFFBCSJ2.js';
2
+ export { SubmissionError, SubmissionTimeoutError } from './chunk-PFFBCSJ2.js';
3
3
 
4
4
  // src/promises.ts
5
5
  var DEFAULT_TIMEOUT_MS = 6e4;
package/dist/react.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { RefCallback } from 'react';
2
- import { a as OutboundMessageMap, O as OutboundMessageType, d as OutboundMessage, C as CaptelloWebviewOptions, e as CaptelloWebview, V as ValidationTarget, P as PrefillInfoItem, f as SubmissionPrefill, S as SubmissionBody } from './client-BRIlJHCg.js';
3
- export { b as SubmissionError, c as SubmissionTimeoutError, U as Unsubscribe } from './client-BRIlJHCg.js';
2
+ import { a as OutboundMessageMap, O as OutboundMessageType, d as OutboundMessage, C as CaptelloWebviewOptions, e as CaptelloWebview, V as ValidationTarget, f as SubmissionPrefill, P as PrefillInfoItem, S as SubmissionBody } from './client-Dik-Mjid.js';
3
+ export { b as SubmissionError, c as SubmissionTimeoutError, U as Unsubscribe } from './client-Dik-Mjid.js';
4
4
  import { EmbedUrlOptions } from './index.js';
5
5
 
6
6
  /**
@@ -10,10 +10,10 @@ import { EmbedUrlOptions } from './index.js';
10
10
  * iframe: it creates the client once the iframe mounts, wires the outbound messages
11
11
  * you care about to typed callbacks, tracks readiness, and destroys the client on
12
12
  * unmount. You get back `iframeProps` to spread onto your `<iframe>` (or a bare `ref`),
13
- * an `isReady` flag, and stable senders (`submit`, `reset`, `prefillInfo`, …).
13
+ * an `isReady` flag, and stable senders (`submit`, `reset`, `prefill`, …).
14
14
  *
15
15
  * Sends made before the form loads are queued by the client and flushed on
16
- * `form_load_complete`, so you can call `prefillInfo(...)` as soon as you have data —
16
+ * `form_load_complete`, so you can call `prefill(...)` as soon as you have data —
17
17
  * no need to gate on readiness yourself.
18
18
  *
19
19
  * Callbacks are held in a ref and always called fresh, so you do NOT need to memoize
@@ -96,9 +96,7 @@ interface UseCaptelloWebviewResult {
96
96
  reset: () => void;
97
97
  updateDraft: () => void;
98
98
  triggerValidation: (target: ValidationTarget) => void;
99
- prefillInfo: (info: PrefillInfoItem[]) => void;
100
- prefillSubmission: (submission: SubmissionPrefill) => void;
101
- prefillSubmissionAndInfo: (data: {
99
+ prefill: (data: {
102
100
  submission?: SubmissionPrefill;
103
101
  info?: PrefillInfoItem[];
104
102
  }) => void;
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
- import { buildEmbedUrl } from './chunk-RKAY66VV.js';
2
- import { CaptelloWebview, OutboundMessageType } from './chunk-IMJYXGWK.js';
3
- export { CaptelloWebview, SubmissionError, SubmissionTimeoutError } from './chunk-IMJYXGWK.js';
1
+ import { buildEmbedUrl } from './chunk-4E7OW4RJ.js';
2
+ import { CaptelloWebview, OutboundMessageType } from './chunk-PFFBCSJ2.js';
3
+ export { CaptelloWebview, SubmissionError, SubmissionTimeoutError } from './chunk-PFFBCSJ2.js';
4
4
  import { useRef, useState, useCallback, useEffect } from 'react';
5
5
 
6
6
  var CALLBACK_BY_TYPE = {
@@ -73,13 +73,8 @@ function useCaptelloWebview(options) {
73
73
  (target) => clientRef.current?.triggerValidation(target),
74
74
  []
75
75
  );
76
- const prefillInfo = useCallback((info) => clientRef.current?.prefillInfo(info), []);
77
- const prefillSubmission = useCallback(
78
- (submission) => clientRef.current?.prefillSubmission(submission),
79
- []
80
- );
81
- const prefillSubmissionAndInfo = useCallback(
82
- (data) => clientRef.current?.prefillSubmissionAndInfo(data),
76
+ const prefill = useCallback(
77
+ (data) => clientRef.current?.prefill(data),
83
78
  []
84
79
  );
85
80
  const submitAndWait = useCallback((timeoutMs) => {
@@ -100,9 +95,7 @@ function useCaptelloWebview(options) {
100
95
  reset,
101
96
  updateDraft,
102
97
  triggerValidation,
103
- prefillInfo,
104
- prefillSubmission,
105
- prefillSubmissionAndInfo,
98
+ prefill,
106
99
  submitAndWait
107
100
  };
108
101
  }
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.ts"],"names":[],"mappings":"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","file":"react.js","sourcesContent":["/**\n * React adapter for the Captello webview SDK — `@captello/ulc-webview-sdk/react`.\n *\n * {@link useCaptelloWebview} owns a {@link CaptelloWebview} for the lifetime of an\n * iframe: it creates the client once the iframe mounts, wires the outbound messages\n * you care about to typed callbacks, tracks readiness, and destroys the client on\n * unmount. You get back `iframeProps` to spread onto your `<iframe>` (or a bare `ref`),\n * an `isReady` flag, and stable senders (`submit`, `reset`, `prefillInfo`, …).\n *\n * Sends made before the form loads are queued by the client and flushed on\n * `form_load_complete`, so you can call `prefillInfo(...)` as soon as you have data —\n * no need to gate on readiness yourself.\n *\n * Callbacks are held in a ref and always called fresh, so you do NOT need to memoize\n * them — passing inline arrow functions will not re-subscribe or re-create the client.\n *\n * `react` is an optional peer dependency; importing this entry point requires React 18+.\n *\n * @example\n * function UlcForm({ token, onSubmitted }: { token: string; onSubmitted: (b: SubmissionBody) => void }) {\n * const { iframeProps, isReady, submit } = useCaptelloWebview({\n * embedUrl: {\n * baseUrl: \"https://capture.captello.com\",\n * eventWebAccessToken: token,\n * mode: FormMode.Submit,\n * launcher: LauncherType.EventGenWeb,\n * },\n * onSubmissionBody: (m) => onSubmitted(m.data),\n * });\n * return (\n * <>\n * {!isReady && <Spinner />}\n * <iframe {...iframeProps} title=\"UlcForm\" allow=\"camera; microphone\" />\n * <button onClick={submit}>Submit</button>\n * </>\n * );\n * }\n */\n\nimport { useCallback, useEffect, useRef, useState, type RefCallback } from \"react\";\n\nimport { CaptelloWebview } from \"./client\";\nimport type { CaptelloWebviewOptions, Unsubscribe } from \"./client\";\nimport { buildEmbedUrl } from \"./embed-url\";\nimport type { EmbedUrlOptions } from \"./embed-url\";\nimport { OutboundMessageType } from \"./messages\";\nimport type {\n OutboundMessage,\n OutboundMessageMap,\n PrefillInfoItem,\n SubmissionBody,\n SubmissionPrefill,\n ValidationTarget,\n} from \"./messages\";\n\n/** Per-message-type callback props accepted by {@link useCaptelloWebview}. */\nexport interface CaptelloWebviewCallbacks {\n onFormLoadComplete?: (message: OutboundMessageMap[OutboundMessageType.FormLoadComplete]) => void;\n onFormErrorMessage?: (message: OutboundMessageMap[OutboundMessageType.FormErrorMessage]) => void;\n onSubmissionBody?: (message: OutboundMessageMap[OutboundMessageType.SubmissionBody]) => void;\n onFormSubmitSuccess?: (message: OutboundMessageMap[OutboundMessageType.FormSubmitSuccess]) => void;\n onConnexionsProfileRedirect?: (message: OutboundMessageMap[OutboundMessageType.ConnexionsProfileRedirect]) => void;\n onConnexionsDownloadVcard?: (message: OutboundMessageMap[OutboundMessageType.ConnexionsDownloadVcard]) => void;\n /** Catch-all: called for every outbound message, after the specific handler above. */\n onAnyMessage?: (message: OutboundMessage) => void;\n}\n\n/** Embed-URL config: a base URL plus {@link EmbedUrlOptions}. */\nexport interface EmbedUrlConfig extends EmbedUrlOptions {\n /**\n * The capture **origin**, e.g. `\"https://capture.captello.com\"`. The SDK appends the\n * capture path for you, so the origin, a trailing slash, or the full\n * `…/capture/submission` URL all work — see {@link buildEmbedUrl}.\n */\n baseUrl: string;\n}\n\n/**\n * Options for {@link useCaptelloWebview}.\n *\n * Provide **either** `embedUrl` (the hook builds the URL and derives `targetOrigin`,\n * returning `iframeProps.src`) **or** your own `targetOrigin` (you set the iframe `src`\n * yourself). Plus message callbacks and the usual client options.\n */\nexport interface UseCaptelloWebviewOptions extends CaptelloWebviewOptions, CaptelloWebviewCallbacks {\n /** Build the iframe URL and derive `targetOrigin` from it. Sets `iframeProps.src`. */\n embedUrl?: EmbedUrlConfig;\n}\n\n/** Readiness of the embedded form. */\nexport type CaptelloWebviewStatus = \"loading\" | \"ready\" | \"error\";\n\n/** Props to spread onto the `<iframe>`. `src` is present only when `embedUrl` is given. */\nexport interface CaptelloIframeProps {\n ref: RefCallback<HTMLIFrameElement | null>;\n src?: string;\n}\n\n/** What {@link useCaptelloWebview} returns. */\nexport interface UseCaptelloWebviewResult {\n /** Spread onto your iframe: `<iframe {...iframeProps} />`. Includes `src` if `embedUrl` was given. */\n iframeProps: CaptelloIframeProps;\n /** The iframe ref callback (same as `iframeProps.ref`), if you'd rather set `src` yourself. */\n ref: RefCallback<HTMLIFrameElement | null>;\n /** `true` once the form has reported `form_load_complete`. */\n isReady: boolean;\n /** `\"loading\"` → `\"ready\"`; flips to `\"error\"` if a `form_error_message` arrives. */\n status: CaptelloWebviewStatus;\n /** The live client, or `null` before the iframe mounts. For escape-hatch use. */\n getClient: () => CaptelloWebview | null;\n submit: () => void;\n reset: () => void;\n updateDraft: () => void;\n triggerValidation: (target: ValidationTarget) => void;\n prefillInfo: (info: PrefillInfoItem[]) => void;\n prefillSubmission: (submission: SubmissionPrefill) => void;\n prefillSubmissionAndInfo: (data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] }) => void;\n submitAndWait: (timeoutMs?: number) => Promise<SubmissionBody>;\n}\n\nconst CALLBACK_BY_TYPE: Record<OutboundMessageType, keyof CaptelloWebviewCallbacks> = {\n [OutboundMessageType.FormLoadComplete]: \"onFormLoadComplete\",\n [OutboundMessageType.FormErrorMessage]: \"onFormErrorMessage\",\n [OutboundMessageType.SubmissionBody]: \"onSubmissionBody\",\n [OutboundMessageType.FormSubmitSuccess]: \"onFormSubmitSuccess\",\n [OutboundMessageType.ConnexionsProfileRedirect]: \"onConnexionsProfileRedirect\",\n [OutboundMessageType.ConnexionsDownloadVcard]: \"onConnexionsDownloadVcard\",\n};\n\n/**\n * Binds a {@link CaptelloWebview} to an iframe's lifecycle. See the module doc for usage.\n */\nexport function useCaptelloWebview(options: UseCaptelloWebviewOptions): UseCaptelloWebviewResult {\n const { embedUrl, matchSource, queueUntilReady, hostWindow } = options;\n\n // Resolve the URL + the targetOrigin to use. embedUrl wins; otherwise use the\n // explicit targetOrigin. Recompute only when the URL-affecting inputs change.\n const src = embedUrl ? buildEmbedUrl(embedUrl.baseUrl, embedUrl) : undefined;\n const targetOrigin = src ? new URL(src).origin : options.targetOrigin;\n\n // Latest options/callbacks, read fresh inside listeners so callers needn't memoize.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const clientRef = useRef<CaptelloWebview | null>(null);\n const frameRef = useRef<HTMLIFrameElement | null>(null);\n const teardown = useRef<(() => void) | null>(null);\n\n const [status, setStatus] = useState<CaptelloWebviewStatus>(\"loading\");\n\n const attach = useCallback(\n (frame: HTMLIFrameElement | null) => {\n // Tear down any previous client (ref changed or unmounting).\n teardown.current?.();\n teardown.current = null;\n clientRef.current = null;\n frameRef.current = frame;\n setStatus(\"loading\");\n\n if (!frame) return;\n\n const client = new CaptelloWebview(frame, {\n targetOrigin,\n hostWindow: optionsRef.current.hostWindow,\n matchSource: optionsRef.current.matchSource,\n queueUntilReady: optionsRef.current.queueUntilReady,\n });\n clientRef.current = client;\n\n const offs: Unsubscribe[] = [];\n for (const type of Object.values(OutboundMessageType)) {\n offs.push(\n client.on(type, (message) => {\n if (type === OutboundMessageType.FormLoadComplete) setStatus(\"ready\");\n else if (type === OutboundMessageType.FormErrorMessage) setStatus(\"error\");\n\n const handler = optionsRef.current[CALLBACK_BY_TYPE[type]] as\n | ((m: typeof message) => void)\n | undefined;\n handler?.(message);\n optionsRef.current.onAnyMessage?.(message);\n }),\n );\n }\n\n teardown.current = () => {\n for (const off of offs) off();\n client.destroy();\n };\n },\n // Re-create the client only when connection-level inputs change.\n // Callbacks are read via optionsRef, so they intentionally aren't deps.\n [targetOrigin, matchSource, queueUntilReady, hostWindow],\n );\n\n useEffect(() => {\n if (frameRef.current) attach(frameRef.current);\n return () => {\n teardown.current?.();\n teardown.current = null;\n clientRef.current = null;\n };\n }, [attach]);\n\n const getClient = useCallback(() => clientRef.current, []);\n\n const submit = useCallback(() => clientRef.current?.submit(), []);\n const reset = useCallback(() => clientRef.current?.reset(), []);\n const updateDraft = useCallback(() => clientRef.current?.updateDraft(), []);\n const triggerValidation = useCallback(\n (target: ValidationTarget) => clientRef.current?.triggerValidation(target),\n [],\n );\n const prefillInfo = useCallback((info: PrefillInfoItem[]) => clientRef.current?.prefillInfo(info), []);\n const prefillSubmission = useCallback(\n (submission: SubmissionPrefill) => clientRef.current?.prefillSubmission(submission),\n [],\n );\n const prefillSubmissionAndInfo = useCallback(\n (data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] }) =>\n clientRef.current?.prefillSubmissionAndInfo(data),\n [],\n );\n const submitAndWait = useCallback((timeoutMs?: number) => {\n const client = clientRef.current;\n if (!client) {\n return Promise.reject(new Error(\"CaptelloWebview: iframe is not mounted yet.\"));\n }\n return client.submitAndWait(timeoutMs);\n }, []);\n\n const iframeProps: CaptelloIframeProps = src ? { ref: attach, src } : { ref: attach };\n\n return {\n iframeProps,\n ref: attach,\n isReady: status === \"ready\",\n status,\n getClient,\n submit,\n reset,\n updateDraft,\n triggerValidation,\n prefillInfo,\n prefillSubmission,\n prefillSubmissionAndInfo,\n submitAndWait,\n };\n}\n\nexport { CaptelloWebview, SubmissionError, SubmissionTimeoutError } from \"./client\";\nexport type { Unsubscribe } from \"./client\";\n"]}
1
+ {"version":3,"sources":["../src/react.ts"],"names":[],"mappings":";;;;;AAsHA,IAAM,gBAAA,GAAgF;AAAA,EAClF,+CAAwC,oBAAA;AAAA,EACxC,+CAAwC,oBAAA;AAAA,EACxC,0CAAsC,kBAAA;AAAA,EACtC,iDAAyC,qBAAA;AAAA,EACzC,iEAAiD,6BAAA;AAAA,EACjD,6DAA+C;AACnD,CAAA;AAKO,SAAS,mBAAmB,OAAA,EAA8D;AAC7F,EAAA,MAAM,EAAE,QAAA,EAAU,WAAA,EAAa,eAAA,EAAiB,YAAW,GAAI,OAAA;AAI/D,EAAA,MAAM,MAAM,QAAA,GAAW,aAAA,CAAc,QAAA,CAAS,OAAA,EAAS,QAAQ,CAAA,GAAI,MAAA;AACnE,EAAA,MAAM,eAAe,GAAA,GAAM,IAAI,IAAI,GAAG,CAAA,CAAE,SAAS,OAAA,CAAQ,YAAA;AAGzD,EAAA,MAAM,UAAA,GAAa,OAAO,OAAO,CAAA;AACjC,EAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAErB,EAAA,MAAM,SAAA,GAAY,OAA+B,IAAI,CAAA;AACrD,EAAA,MAAM,QAAA,GAAW,OAAiC,IAAI,CAAA;AACtD,EAAA,MAAM,QAAA,GAAW,OAA4B,IAAI,CAAA;AAEjD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAgC,SAAS,CAAA;AAErE,EAAA,MAAM,MAAA,GAAS,WAAA;AAAA,IACX,CAAC,KAAA,KAAoC;AAEjC,MAAA,QAAA,CAAS,OAAA,IAAU;AACnB,MAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,MAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AACpB,MAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AACnB,MAAA,SAAA,CAAU,SAAS,CAAA;AAEnB,MAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,MAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB,KAAA,EAAO;AAAA,QACtC,YAAA;AAAA,QACA,UAAA,EAAY,WAAW,OAAA,CAAQ,UAAA;AAAA,QAC/B,WAAA,EAAa,WAAW,OAAA,CAAQ,WAAA;AAAA,QAChC,eAAA,EAAiB,WAAW,OAAA,CAAQ;AAAA,OACvC,CAAA;AACD,MAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAEpB,MAAA,MAAM,OAAsB,EAAC;AAC7B,MAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,MAAA,CAAO,mBAAmB,CAAA,EAAG;AACnD,QAAA,IAAA,CAAK,IAAA;AAAA,UACD,MAAA,CAAO,EAAA,CAAG,IAAA,EAAM,CAAC,OAAA,KAAY;AACzB,YAAA,IAAI,IAAA,KAAA,oBAAA,mCAAyD,OAAO,CAAA;AAAA,iBAAA,IAC3D,IAAA,KAAA,oBAAA,mCAAyD,OAAO,CAAA;AAEzE,YAAA,MAAM,OAAA,GAAU,UAAA,CAAW,OAAA,CAAQ,gBAAA,CAAiB,IAAI,CAAC,CAAA;AAGzD,YAAA,OAAA,GAAU,OAAO,CAAA;AACjB,YAAA,UAAA,CAAW,OAAA,CAAQ,eAAe,OAAO,CAAA;AAAA,UAC7C,CAAC;AAAA,SACL;AAAA,MACJ;AAEA,MAAA,QAAA,CAAS,UAAU,MAAM;AACrB,QAAA,KAAA,MAAW,GAAA,IAAO,MAAM,GAAA,EAAI;AAC5B,QAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,MACnB,CAAA;AAAA,IACJ,CAAA;AAAA;AAAA;AAAA,IAGA,CAAC,YAAA,EAAc,WAAA,EAAa,eAAA,EAAiB,UAAU;AAAA,GAC3D;AAEA,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,QAAA,CAAS,OAAA,EAAS,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA;AAC7C,IAAA,OAAO,MAAM;AACT,MAAA,QAAA,CAAS,OAAA,IAAU;AACnB,MAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,MAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AAAA,IACxB,CAAA;AAAA,EACJ,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,YAAY,WAAA,CAAY,MAAM,SAAA,CAAU,OAAA,EAAS,EAAE,CAAA;AAEzD,EAAA,MAAM,MAAA,GAAS,YAAY,MAAM,SAAA,CAAU,SAAS,MAAA,EAAO,EAAG,EAAE,CAAA;AAChE,EAAA,MAAM,KAAA,GAAQ,YAAY,MAAM,SAAA,CAAU,SAAS,KAAA,EAAM,EAAG,EAAE,CAAA;AAC9D,EAAA,MAAM,WAAA,GAAc,YAAY,MAAM,SAAA,CAAU,SAAS,WAAA,EAAY,EAAG,EAAE,CAAA;AAC1E,EAAA,MAAM,iBAAA,GAAoB,WAAA;AAAA,IACtB,CAAC,MAAA,KAA6B,SAAA,CAAU,OAAA,EAAS,kBAAkB,MAAM,CAAA;AAAA,IACzE;AAAC,GACL;AACA,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACZ,CAAC,IAAA,KACG,SAAA,CAAU,OAAA,EAAS,QAAQ,IAAI,CAAA;AAAA,IACnC;AAAC,GACL;AACA,EAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,CAAC,SAAA,KAAuB;AACtD,IAAA,MAAM,SAAS,SAAA,CAAU,OAAA;AACzB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACT,MAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,6CAA6C,CAAC,CAAA;AAAA,IAClF;AACA,IAAA,OAAO,MAAA,CAAO,cAAc,SAAS,CAAA;AAAA,EACzC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,WAAA,GAAmC,MAAM,EAAE,GAAA,EAAK,QAAQ,GAAA,EAAI,GAAI,EAAE,GAAA,EAAK,MAAA,EAAO;AAEpF,EAAA,OAAO;AAAA,IACH,WAAA;AAAA,IACA,GAAA,EAAK,MAAA;AAAA,IACL,SAAS,MAAA,KAAW,OAAA;AAAA,IACpB,MAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACJ;AACJ","file":"react.js","sourcesContent":["/**\n * React adapter for the Captello webview SDK — `@captello/ulc-webview-sdk/react`.\n *\n * {@link useCaptelloWebview} owns a {@link CaptelloWebview} for the lifetime of an\n * iframe: it creates the client once the iframe mounts, wires the outbound messages\n * you care about to typed callbacks, tracks readiness, and destroys the client on\n * unmount. You get back `iframeProps` to spread onto your `<iframe>` (or a bare `ref`),\n * an `isReady` flag, and stable senders (`submit`, `reset`, `prefill`, …).\n *\n * Sends made before the form loads are queued by the client and flushed on\n * `form_load_complete`, so you can call `prefill(...)` as soon as you have data —\n * no need to gate on readiness yourself.\n *\n * Callbacks are held in a ref and always called fresh, so you do NOT need to memoize\n * them — passing inline arrow functions will not re-subscribe or re-create the client.\n *\n * `react` is an optional peer dependency; importing this entry point requires React 18+.\n *\n * @example\n * function UlcForm({ token, onSubmitted }: { token: string; onSubmitted: (b: SubmissionBody) => void }) {\n * const { iframeProps, isReady, submit } = useCaptelloWebview({\n * embedUrl: {\n * baseUrl: \"https://capture.captello.com\",\n * eventWebAccessToken: token,\n * mode: FormMode.Submit,\n * launcher: LauncherType.EventGenWeb,\n * },\n * onSubmissionBody: (m) => onSubmitted(m.data),\n * });\n * return (\n * <>\n * {!isReady && <Spinner />}\n * <iframe {...iframeProps} title=\"UlcForm\" allow=\"camera; microphone\" />\n * <button onClick={submit}>Submit</button>\n * </>\n * );\n * }\n */\n\nimport { useCallback, useEffect, useRef, useState, type RefCallback } from \"react\";\n\nimport { CaptelloWebview } from \"./client\";\nimport type { CaptelloWebviewOptions, Unsubscribe } from \"./client\";\nimport { buildEmbedUrl } from \"./embed-url\";\nimport type { EmbedUrlOptions } from \"./embed-url\";\nimport { OutboundMessageType } from \"./messages\";\nimport type {\n OutboundMessage,\n OutboundMessageMap,\n PrefillInfoItem,\n SubmissionBody,\n SubmissionPrefill,\n ValidationTarget,\n} from \"./messages\";\n\n/** Per-message-type callback props accepted by {@link useCaptelloWebview}. */\nexport interface CaptelloWebviewCallbacks {\n onFormLoadComplete?: (message: OutboundMessageMap[OutboundMessageType.FormLoadComplete]) => void;\n onFormErrorMessage?: (message: OutboundMessageMap[OutboundMessageType.FormErrorMessage]) => void;\n onSubmissionBody?: (message: OutboundMessageMap[OutboundMessageType.SubmissionBody]) => void;\n onFormSubmitSuccess?: (message: OutboundMessageMap[OutboundMessageType.FormSubmitSuccess]) => void;\n onConnexionsProfileRedirect?: (message: OutboundMessageMap[OutboundMessageType.ConnexionsProfileRedirect]) => void;\n onConnexionsDownloadVcard?: (message: OutboundMessageMap[OutboundMessageType.ConnexionsDownloadVcard]) => void;\n /** Catch-all: called for every outbound message, after the specific handler above. */\n onAnyMessage?: (message: OutboundMessage) => void;\n}\n\n/** Embed-URL config: a base URL plus {@link EmbedUrlOptions}. */\nexport interface EmbedUrlConfig extends EmbedUrlOptions {\n /**\n * The capture **origin**, e.g. `\"https://capture.captello.com\"`. The SDK appends the\n * capture path for you, so the origin, a trailing slash, or the full\n * `…/capture/submission` URL all work — see {@link buildEmbedUrl}.\n */\n baseUrl: string;\n}\n\n/**\n * Options for {@link useCaptelloWebview}.\n *\n * Provide **either** `embedUrl` (the hook builds the URL and derives `targetOrigin`,\n * returning `iframeProps.src`) **or** your own `targetOrigin` (you set the iframe `src`\n * yourself). Plus message callbacks and the usual client options.\n */\nexport interface UseCaptelloWebviewOptions extends CaptelloWebviewOptions, CaptelloWebviewCallbacks {\n /** Build the iframe URL and derive `targetOrigin` from it. Sets `iframeProps.src`. */\n embedUrl?: EmbedUrlConfig;\n}\n\n/** Readiness of the embedded form. */\nexport type CaptelloWebviewStatus = \"loading\" | \"ready\" | \"error\";\n\n/** Props to spread onto the `<iframe>`. `src` is present only when `embedUrl` is given. */\nexport interface CaptelloIframeProps {\n ref: RefCallback<HTMLIFrameElement | null>;\n src?: string;\n}\n\n/** What {@link useCaptelloWebview} returns. */\nexport interface UseCaptelloWebviewResult {\n /** Spread onto your iframe: `<iframe {...iframeProps} />`. Includes `src` if `embedUrl` was given. */\n iframeProps: CaptelloIframeProps;\n /** The iframe ref callback (same as `iframeProps.ref`), if you'd rather set `src` yourself. */\n ref: RefCallback<HTMLIFrameElement | null>;\n /** `true` once the form has reported `form_load_complete`. */\n isReady: boolean;\n /** `\"loading\"` → `\"ready\"`; flips to `\"error\"` if a `form_error_message` arrives. */\n status: CaptelloWebviewStatus;\n /** The live client, or `null` before the iframe mounts. For escape-hatch use. */\n getClient: () => CaptelloWebview | null;\n submit: () => void;\n reset: () => void;\n updateDraft: () => void;\n triggerValidation: (target: ValidationTarget) => void;\n prefill: (data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] }) => void;\n submitAndWait: (timeoutMs?: number) => Promise<SubmissionBody>;\n}\n\nconst CALLBACK_BY_TYPE: Record<OutboundMessageType, keyof CaptelloWebviewCallbacks> = {\n [OutboundMessageType.FormLoadComplete]: \"onFormLoadComplete\",\n [OutboundMessageType.FormErrorMessage]: \"onFormErrorMessage\",\n [OutboundMessageType.SubmissionBody]: \"onSubmissionBody\",\n [OutboundMessageType.FormSubmitSuccess]: \"onFormSubmitSuccess\",\n [OutboundMessageType.ConnexionsProfileRedirect]: \"onConnexionsProfileRedirect\",\n [OutboundMessageType.ConnexionsDownloadVcard]: \"onConnexionsDownloadVcard\",\n};\n\n/**\n * Binds a {@link CaptelloWebview} to an iframe's lifecycle. See the module doc for usage.\n */\nexport function useCaptelloWebview(options: UseCaptelloWebviewOptions): UseCaptelloWebviewResult {\n const { embedUrl, matchSource, queueUntilReady, hostWindow } = options;\n\n // Resolve the URL + the targetOrigin to use. embedUrl wins; otherwise use the\n // explicit targetOrigin. Recompute only when the URL-affecting inputs change.\n const src = embedUrl ? buildEmbedUrl(embedUrl.baseUrl, embedUrl) : undefined;\n const targetOrigin = src ? new URL(src).origin : options.targetOrigin;\n\n // Latest options/callbacks, read fresh inside listeners so callers needn't memoize.\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const clientRef = useRef<CaptelloWebview | null>(null);\n const frameRef = useRef<HTMLIFrameElement | null>(null);\n const teardown = useRef<(() => void) | null>(null);\n\n const [status, setStatus] = useState<CaptelloWebviewStatus>(\"loading\");\n\n const attach = useCallback(\n (frame: HTMLIFrameElement | null) => {\n // Tear down any previous client (ref changed or unmounting).\n teardown.current?.();\n teardown.current = null;\n clientRef.current = null;\n frameRef.current = frame;\n setStatus(\"loading\");\n\n if (!frame) return;\n\n const client = new CaptelloWebview(frame, {\n targetOrigin,\n hostWindow: optionsRef.current.hostWindow,\n matchSource: optionsRef.current.matchSource,\n queueUntilReady: optionsRef.current.queueUntilReady,\n });\n clientRef.current = client;\n\n const offs: Unsubscribe[] = [];\n for (const type of Object.values(OutboundMessageType)) {\n offs.push(\n client.on(type, (message) => {\n if (type === OutboundMessageType.FormLoadComplete) setStatus(\"ready\");\n else if (type === OutboundMessageType.FormErrorMessage) setStatus(\"error\");\n\n const handler = optionsRef.current[CALLBACK_BY_TYPE[type]] as\n | ((m: typeof message) => void)\n | undefined;\n handler?.(message);\n optionsRef.current.onAnyMessage?.(message);\n }),\n );\n }\n\n teardown.current = () => {\n for (const off of offs) off();\n client.destroy();\n };\n },\n // Re-create the client only when connection-level inputs change.\n // Callbacks are read via optionsRef, so they intentionally aren't deps.\n [targetOrigin, matchSource, queueUntilReady, hostWindow],\n );\n\n useEffect(() => {\n if (frameRef.current) attach(frameRef.current);\n return () => {\n teardown.current?.();\n teardown.current = null;\n clientRef.current = null;\n };\n }, [attach]);\n\n const getClient = useCallback(() => clientRef.current, []);\n\n const submit = useCallback(() => clientRef.current?.submit(), []);\n const reset = useCallback(() => clientRef.current?.reset(), []);\n const updateDraft = useCallback(() => clientRef.current?.updateDraft(), []);\n const triggerValidation = useCallback(\n (target: ValidationTarget) => clientRef.current?.triggerValidation(target),\n [],\n );\n const prefill = useCallback(\n (data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] }) =>\n clientRef.current?.prefill(data),\n [],\n );\n const submitAndWait = useCallback((timeoutMs?: number) => {\n const client = clientRef.current;\n if (!client) {\n return Promise.reject(new Error(\"CaptelloWebview: iframe is not mounted yet.\"));\n }\n return client.submitAndWait(timeoutMs);\n }, []);\n\n const iframeProps: CaptelloIframeProps = src ? { ref: attach, src } : { ref: attach };\n\n return {\n iframeProps,\n ref: attach,\n isReady: status === \"ready\",\n status,\n getClient,\n submit,\n reset,\n updateDraft,\n triggerValidation,\n prefill,\n submitAndWait,\n };\n}\n\nexport { CaptelloWebview, SubmissionError, SubmissionTimeoutError } from \"./client\";\nexport type { Unsubscribe } from \"./client\";\n"]}
package/package.json CHANGED
@@ -1,78 +1,78 @@
1
1
  {
2
- "name": "@captello/ulc-webview-sdk",
3
- "version": "0.2.0",
4
- "description": "Typed SDK for embedding the Captello capture webview: message protocol, host client, and embed-URL builder.",
5
- "author": "Lead Liaison",
6
- "license": "MIT",
7
- "type": "module",
8
- "sideEffects": false,
9
- "module": "./dist/index.js",
10
- "types": "./dist/index.d.ts",
11
- "typesVersions": {
12
- "*": {
13
- "promises": [
14
- "./dist/promises.d.ts"
15
- ],
16
- "react": [
17
- "./dist/react.d.ts"
18
- ]
19
- }
20
- },
21
- "exports": {
22
- ".": {
23
- "types": "./dist/index.d.ts",
24
- "import": "./dist/index.js"
25
- },
26
- "./promises": {
27
- "types": "./dist/promises.d.ts",
28
- "import": "./dist/promises.js"
29
- },
30
- "./react": {
31
- "types": "./dist/react.d.ts",
32
- "import": "./dist/react.js"
33
- },
34
- "./package.json": "./package.json"
35
- },
36
- "files": [
37
- "dist",
38
- "LICENSE"
39
- ],
40
- "scripts": {
41
- "build": "tsup",
42
- "dev": "tsup --watch",
43
- "typecheck": "tsc --noEmit",
44
- "typecheck:test": "tsc -p tsconfig.test.json",
45
- "test": "vitest run",
46
- "test:watch": "vitest",
47
- "clean": "rm -rf dist"
48
- },
49
- "keywords": [
50
- "captello",
51
- "webview",
52
- "iframe",
53
- "postmessage",
54
- "embed",
55
- "sdk"
56
- ],
57
- "peerDependencies": {
58
- "react": ">=18"
2
+ "name": "@captello/ulc-webview-sdk",
3
+ "version": "0.4.0",
4
+ "description": "Typed SDK for embedding the Captello capture webview: message protocol, host client, and embed-URL builder.",
5
+ "author": "Lead Liaison",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "typesVersions": {
12
+ "*": {
13
+ "promises": [
14
+ "./dist/promises.d.ts"
15
+ ],
16
+ "react": [
17
+ "./dist/react.d.ts"
18
+ ]
19
+ }
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
59
25
  },
60
- "peerDependenciesMeta": {
61
- "react": {
62
- "optional": true
63
- }
26
+ "./promises": {
27
+ "types": "./dist/promises.d.ts",
28
+ "import": "./dist/promises.js"
64
29
  },
65
- "devDependencies": {
66
- "@testing-library/react": "16.1.0",
67
- "@types/react": "19.2.2",
68
- "jsdom": "25.0.1",
69
- "react": "19.2.2",
70
- "react-dom": "19.2.2",
71
- "tsup": "8.3.5",
72
- "typescript": "5.9.3",
73
- "vitest": "2.1.9"
30
+ "./react": {
31
+ "types": "./dist/react.d.ts",
32
+ "import": "./dist/react.js"
74
33
  },
75
- "publishConfig": {
76
- "access": "public"
34
+ "./package.json": "./package.json"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "LICENSE"
39
+ ],
40
+ "keywords": [
41
+ "captello",
42
+ "webview",
43
+ "iframe",
44
+ "postmessage",
45
+ "embed",
46
+ "sdk"
47
+ ],
48
+ "peerDependencies": {
49
+ "react": ">=18"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "react": {
53
+ "optional": true
77
54
  }
78
- }
55
+ },
56
+ "devDependencies": {
57
+ "@testing-library/react": "16.1.0",
58
+ "@types/react": "19.2.2",
59
+ "jsdom": "25.0.1",
60
+ "react": "19.2.2",
61
+ "react-dom": "19.2.2",
62
+ "tsup": "8.3.5",
63
+ "typescript": "5.9.3",
64
+ "vitest": "2.1.9"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public"
68
+ },
69
+ "scripts": {
70
+ "build": "tsup",
71
+ "dev": "tsup --watch",
72
+ "typecheck": "tsc --noEmit",
73
+ "typecheck:test": "tsc -p tsconfig.test.json",
74
+ "test": "vitest run",
75
+ "test:watch": "vitest",
76
+ "clean": "rm -rf dist"
77
+ }
78
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/messages.ts","../src/client.ts"],"names":["OutboundMessageType","InboundMessageType","PrefillDataType"],"mappings":"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","file":"chunk-IMJYXGWK.js","sourcesContent":["/**\n * The message protocol exchanged between the Captello capture webview (the iframe)\n * and its host page.\n *\n * Wire format (this is the contract — match it exactly):\n * - Every message is a JSON **string**. The webview sends outbound messages with\n * `JSON.stringify(message)` and reads inbound messages with `JSON.parse(event.data)`.\n * A host that posts a raw object instead of a string will be ignored, because the\n * webview's parser produces a non-object and bails.\n * - Every message is an object with a `type` discriminator. Inbound and outbound\n * types are disjoint string enums.\n *\n * Direction is named from the **webview's** point of view:\n * - {@link OutboundMessageType}: webview → host (the host listens for these).\n * - {@link InboundMessageType}: host → webview (the host sends these).\n */\n\nimport type { VisibleSubmissionDataItem } from \"./submission-data\";\n\n/* ------------------------------------------------------------------ *\n * Outbound: webview → host\n * ------------------------------------------------------------------ */\n\n/** Message `type` values the webview emits to its host. */\nexport enum OutboundMessageType {\n /** The form finished loading and rendering. Safe to interact with it after this. */\n FormLoadComplete = \"form_load_complete\",\n /** A user-facing error occurred; `data` is the translated, display-ready message. */\n FormErrorMessage = \"form_error_message\",\n /**\n * Emitted for embedded forms instead of submitting directly: `data` is the full\n * submission body for the host to persist/forward.\n */\n SubmissionBody = \"submission_body\",\n /** The form was submitted successfully (used in kiosk / quick-capture flows). */\n FormSubmitSuccess = \"form_submit_success\",\n /** Connexions: the host should perform the profile redirect (embed mode). */\n ConnexionsProfileRedirect = \"connexions_profile_redirect\",\n /** Connexions: the host should trigger the vCard download (embed mode). */\n ConnexionsDownloadVcard = \"connexions_download_vcard\",\n}\n\n/**\n * Opaque submission payload carried by {@link OutboundMessageType.SubmissionBody}.\n *\n * This mirrors the webview's internal `FormSubmission` model. It is intentionally\n * typed as an open record here so the SDK stays decoupled from the app's full model\n * graph; the documented fields below are stable, the rest are passed through as-is.\n * Host code that needs the deep element-value types should treat `data` as untyped\n * and key it by element id (e.g. `\"element_12\"`, `\"element_12_3\"`).\n */\nexport interface SubmissionBody {\n id: number;\n form_id: number;\n prospect_id: number;\n email: string;\n first_name: string;\n last_name: string;\n full_name: string;\n company: string;\n phone: string;\n /** Submitted values keyed by element id / sub-element id. */\n data: Record<string, unknown>;\n /**\n * Visible, filled elements ready to render as key/value rows — one item per\n * element, discriminated by `element_type` (narrow on it for a precisely-typed\n * `element_value`). See {@link VisibleSubmissionDataItem}. May be absent on older\n * webview builds.\n */\n visible_submissions_data?: VisibleSubmissionDataItem[];\n submission_date: string;\n /** Query-string params the webview was loaded with, echoed back on submit. */\n query_parameters?: Record<string, string>;\n /** Additional fields from the webview's submission model are passed through verbatim. */\n [key: string]: unknown;\n}\n\n/**\n * Loose submission shape accepted when **pre-filling** the form (host → webview).\n *\n * Distinct from {@link SubmissionBody}: a received `submission_body` is always fully\n * populated, but when pre-filling you typically either round-trip a previously-received\n * body or pass a partial object assembled from your own data. A {@link SubmissionBody}\n * is assignable to this, so round-tripping just works.\n */\nexport interface SubmissionPrefill {\n /** Submitted values keyed by element id / sub-element id. */\n data?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface FormLoadCompleteMessage {\n type: OutboundMessageType.FormLoadComplete;\n}\ninterface FormSubmitSuccessMessage {\n type: OutboundMessageType.FormSubmitSuccess;\n}\ninterface FormErrorMessageMessage {\n type: OutboundMessageType.FormErrorMessage;\n /** Translated, display-ready error text. */\n data: string;\n}\ninterface SubmissionBodyMessage {\n type: OutboundMessageType.SubmissionBody;\n data: SubmissionBody;\n}\ninterface ConnexionsProfileRedirectMessage {\n type: OutboundMessageType.ConnexionsProfileRedirect;\n}\ninterface ConnexionsDownloadVcardMessage {\n type: OutboundMessageType.ConnexionsDownloadVcard;\n}\n\n/** Discriminated union of every message the webview can emit to its host. */\nexport type OutboundMessage =\n | FormLoadCompleteMessage\n | FormSubmitSuccessMessage\n | FormErrorMessageMessage\n | SubmissionBodyMessage\n | ConnexionsProfileRedirectMessage\n | ConnexionsDownloadVcardMessage;\n\n/** Maps each outbound `type` to its full message shape (used by the client's `.on`). */\nexport type OutboundMessageMap = {\n [M in OutboundMessage as M[\"type\"]]: M;\n};\n\n/* ------------------------------------------------------------------ *\n * Inbound: host → webview\n * ------------------------------------------------------------------ */\n\n/** Message `type` values the host sends into the webview. */\nexport enum InboundMessageType {\n /** Programmatically trigger form submission (as if the user pressed submit). */\n Submit = \"submit_form\",\n /** Reset the form, clearing all entered values. */\n Reset = \"reset_form\",\n /** Pre-fill the form with existing data. See {@link PrefillDataType}. */\n FormPrefill = \"form_prefill\",\n /** Switch the current submission into draft-update mode. */\n UpdateDraft = \"update_draft\",\n /** Run validation against a target field (or the whole form). */\n TriggerValidation = \"trigger_validation\",\n}\n\n/** Shape selector for {@link InboundMessageType.FormPrefill} payloads. */\nexport enum PrefillDataType {\n /** `data` is a full ULC submission (the webview's submission model). */\n UlcSubmission = \"ulc_submission\",\n /** `data` is a list of transcription field/value items. */\n Info = \"info\",\n /** `data` is `{ submission, info }` — a submission plus transcription items. */\n UlcSubmissionAndInfo = \"ulc_submission_and_info\",\n}\n\n/** Targets for {@link InboundMessageType.TriggerValidation}. */\nexport type ValidationTarget = \"invitation_code\" | \"email\" | \"all\";\n\n/**\n * A single transcription field/value item used by {@link PrefillDataType.Info}.\n *\n * The webview matches each item to a form element by `ll_field_unique_identifier`\n * alone (e.g. `\"FirstName\"`, `\"Email\"`); `ll_field_id` is catalog metadata and is not\n * used for matching, so it is accepted as either a number or a string. `value` is\n * typically a string but may be a boolean (e.g. the PII opt-out field).\n */\nexport interface PrefillInfoItem {\n ll_field_unique_identifier: string;\n ll_field_id?: string | number;\n value: string | boolean;\n}\n\ninterface SubmitMessage {\n type: InboundMessageType.Submit;\n}\ninterface ResetMessage {\n type: InboundMessageType.Reset;\n}\ninterface UpdateDraftMessage {\n type: InboundMessageType.UpdateDraft;\n}\ninterface TriggerValidationMessage {\n type: InboundMessageType.TriggerValidation;\n target: ValidationTarget;\n}\ninterface PrefillSubmissionMessage {\n type: InboundMessageType.FormPrefill;\n data_type: PrefillDataType.UlcSubmission;\n /** A submission body to pre-fill from (a received {@link SubmissionBody} or a partial). */\n data: SubmissionPrefill;\n}\ninterface PrefillInfoMessage {\n type: InboundMessageType.FormPrefill;\n data_type: PrefillDataType.Info;\n data: PrefillInfoItem[];\n}\ninterface PrefillSubmissionAndInfoMessage {\n type: InboundMessageType.FormPrefill;\n data_type: PrefillDataType.UlcSubmissionAndInfo;\n data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] };\n}\n\n/** Discriminated union of every message the host can send into the webview. */\nexport type InboundMessage =\n | SubmitMessage\n | ResetMessage\n | UpdateDraftMessage\n | TriggerValidationMessage\n | PrefillSubmissionMessage\n | PrefillInfoMessage\n | PrefillSubmissionAndInfoMessage;\n\n/* ------------------------------------------------------------------ *\n * Runtime guards / parsing\n * ------------------------------------------------------------------ */\n\nconst OUTBOUND_TYPES: ReadonlySet<string> = new Set(Object.values(OutboundMessageType));\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Parses a raw `MessageEvent.data` value into a typed {@link OutboundMessage}, or\n * returns `null` if it is not a recognized Captello webview message.\n *\n * Accepts either a JSON string (the webview always sends strings) or an\n * already-parsed object, so it is robust to hosts/proxies that pre-parse.\n */\nexport function parseOutboundMessage(data: unknown): OutboundMessage | null {\n let value: unknown = data;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n if (!isPlainObject(value)) return null;\n if (typeof value[\"type\"] !== \"string\" || !OUTBOUND_TYPES.has(value[\"type\"])) return null;\n return value as unknown as OutboundMessage;\n}\n","import { InboundMessageType, OutboundMessageType, parseOutboundMessage, PrefillDataType } from \"./messages\";\nimport type {\n InboundMessage,\n OutboundMessage,\n OutboundMessageMap,\n PrefillInfoItem,\n SubmissionBody,\n SubmissionPrefill,\n ValidationTarget,\n} from \"./messages\";\n\n/** Listener for a specific outbound message type. */\nexport type OutboundListener<T extends OutboundMessageType> = (message: OutboundMessageMap[T]) => void;\n\n/** Listener for every outbound message (used by {@link CaptelloWebview.onAny}). */\nexport type AnyOutboundListener = (message: OutboundMessage) => void;\n\n/** Unsubscribe handle returned by every `on*` method. Calling it removes the listener. */\nexport type Unsubscribe = () => void;\n\n/**\n * Rejection reason from {@link CaptelloWebview.submitAndWait} when the webview reports\n * a `form_error_message`. `message` is the translated, display-ready text.\n */\nexport class SubmissionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SubmissionError\";\n }\n}\n\n/**\n * Rejection reason from {@link CaptelloWebview.submitAndWait} when no `submission_body`\n * or `form_error_message` arrives within the timeout.\n */\nexport class SubmissionTimeoutError extends Error {\n constructor(public readonly timeoutMs: number) {\n super(`Captello webview did not respond to submit within ${timeoutMs}ms.`);\n this.name = \"SubmissionTimeoutError\";\n }\n}\n\nexport interface CaptelloWebviewOptions {\n /**\n * Origin to validate incoming messages against and to target outgoing messages.\n * Strongly recommended — set it to the webview's origin (e.g.\n * `\"https://capture.captello.com\"`), e.g. `new URL(embedUrl).origin`.\n *\n * Defaults to `\"*\"`, which accepts messages from any origin and posts without an\n * origin check. Only acceptable for trusted/local development.\n */\n targetOrigin?: string;\n /**\n * The window to attach the `message` listener to. Defaults to the global `window`.\n * Override for testing or non-standard host environments.\n */\n hostWindow?: Window;\n /**\n * If `true` (default), incoming messages are accepted only when they originate\n * from the bound iframe's `contentWindow`. Set `false` only if the webview relays\n * messages through an intermediate window and source matching is impossible.\n */\n matchSource?: boolean;\n /**\n * If `true` (default), messages sent before the webview reports\n * `form_load_complete` are buffered and flushed, in order, once it's ready. This\n * removes a common footgun: calling `prefillInfo(...)` right after mount would\n * otherwise post to a form that isn't listening yet and be silently dropped.\n *\n * Set `false` to send immediately (the legacy behavior). Note: a client that\n * attaches *after* the form already loaded will not have seen `form_load_complete`,\n * so its queued messages won't flush — create the client with the iframe.\n */\n queueUntilReady?: boolean;\n}\n\n/** Emits a console warning in development builds only. No-op in production / no bundler. */\nfunction devWarn(message: string): void {\n try {\n if (typeof process !== \"undefined\" && process.env && process.env.NODE_ENV !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(message);\n }\n } catch {\n /* `process` not defined (pure browser, no bundler define) → stay silent */\n }\n}\n\ntype ElementOrFrame = HTMLIFrameElement | { contentWindow: Window | null };\n\n/**\n * Host-side controller for an embedded Captello capture webview.\n *\n * Wraps a single `<iframe>` and encodes the full message protocol:\n * - **Receiving** (webview → host): subscribe with {@link on} / {@link onAny}.\n * - **Sending** (host → webview): use {@link submit}, {@link reset}, {@link prefill},\n * {@link triggerValidation}, {@link updateDraft}, or the lower-level {@link send}.\n *\n * Wire details handled for you: outgoing messages are `JSON.stringify`'d (the webview\n * parses inbound data with `JSON.parse`, so a raw object would be ignored), and\n * incoming messages are validated by origin + source before being parsed.\n *\n * @example\n * ```ts\n * const iframe = document.querySelector(\"iframe\")!;\n * const webview = new CaptelloWebview(iframe, {\n * targetOrigin: \"https://capture.captello.com\",\n * });\n *\n * webview.on(OutboundMessageType.FormLoadComplete, () => console.log(\"ready\"));\n * webview.on(OutboundMessageType.SubmissionBody, (msg) => save(msg.data));\n *\n * // later, drive the form:\n * webview.submit();\n *\n * // on teardown:\n * webview.destroy();\n * ```\n */\nexport class CaptelloWebview {\n private readonly frame: ElementOrFrame;\n private readonly targetOrigin: string;\n private readonly hostWindow: Window;\n private readonly matchSource: boolean;\n\n private readonly listeners = new Map<OutboundMessageType, Set<OutboundListener<OutboundMessageType>>>();\n private readonly anyListeners = new Set<AnyOutboundListener>();\n private readonly boundHandler: (event: MessageEvent) => void;\n private destroyed = false;\n\n private readonly queueUntilReady: boolean;\n /** True once `form_load_complete` has been observed. */\n private ready = false;\n /** Messages sent before ready, flushed in order on load. */\n private readonly outbox: InboundMessage[] = [];\n\n constructor(frame: ElementOrFrame, options: CaptelloWebviewOptions = {}) {\n if (!frame) {\n throw new Error(\"CaptelloWebview: an iframe element (or { contentWindow }) is required.\");\n }\n this.frame = frame;\n this.targetOrigin = options.targetOrigin ?? \"*\";\n this.matchSource = options.matchSource ?? true;\n this.queueUntilReady = options.queueUntilReady ?? true;\n\n // Nudge (dev only) when running without origin scoping. \"*\" accepts inbound\n // messages from any origin and posts outbound without an origin check — fine\n // for local/trusted dev, unsafe in production. Set targetOrigin to the\n // webview's origin, e.g. `new URL(embedUrl).origin`.\n if (this.targetOrigin === \"*\") {\n devWarn(\n '[captello-sdk] No targetOrigin set — defaulting to \"*\", which accepts messages ' +\n \"from any origin and posts without an origin check. Set targetOrigin to the webview's \" +\n \"origin (e.g. new URL(embedUrl).origin) in production.\",\n );\n }\n\n const hostWindow = options.hostWindow ?? (typeof window !== \"undefined\" ? window : undefined);\n if (!hostWindow) {\n throw new Error(\n \"CaptelloWebview: no host window available. Pass `hostWindow` when constructing outside a browser.\",\n );\n }\n this.hostWindow = hostWindow;\n\n this.boundHandler = (event: MessageEvent) => this.handleMessage(event);\n this.hostWindow.addEventListener(\"message\", this.boundHandler);\n }\n\n /** `true` once the webview has reported `form_load_complete`. */\n get isReady(): boolean {\n return this.ready;\n }\n\n /* -------------------------------------------------------------- *\n * Receiving (webview → host)\n * -------------------------------------------------------------- */\n\n /**\n * Subscribe to a single outbound message type. Returns an unsubscribe function.\n *\n * @example webview.on(OutboundMessageType.FormErrorMessage, (m) => toast(m.data));\n */\n on<T extends OutboundMessageType>(type: T, listener: OutboundListener<T>): Unsubscribe {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(listener as OutboundListener<OutboundMessageType>);\n return () => {\n set?.delete(listener as OutboundListener<OutboundMessageType>);\n };\n }\n\n /**\n * Subscribe once: the listener is removed automatically after it fires the first\n * time for `type`. Returns an unsubscribe function for cancelling early.\n */\n once<T extends OutboundMessageType>(type: T, listener: OutboundListener<T>): Unsubscribe {\n const off = this.on(type, (message) => {\n off();\n listener(message);\n });\n return off;\n }\n\n /** Subscribe to every outbound message regardless of type. Returns an unsubscribe function. */\n onAny(listener: AnyOutboundListener): Unsubscribe {\n this.anyListeners.add(listener);\n return () => {\n this.anyListeners.delete(listener);\n };\n }\n\n /* -------------------------------------------------------------- *\n * Sending (host → webview)\n * -------------------------------------------------------------- */\n\n /**\n * Low-level send: posts any inbound message to the webview as a JSON string.\n * Prefer the typed helpers below; use this only for forward-compatibility.\n *\n * When `queueUntilReady` is enabled (the default) and the form hasn't reported\n * `form_load_complete` yet, the message is buffered and flushed on load instead of\n * posted immediately.\n *\n * @throws if the iframe's `contentWindow` is not available (not yet loaded /\n * detached) and the message can't be queued.\n */\n send(message: InboundMessage): void {\n if (this.destroyed) {\n throw new Error(\"CaptelloWebview: cannot send after destroy().\");\n }\n if (this.queueUntilReady && !this.ready) {\n this.outbox.push(message);\n return;\n }\n this.postNow(message);\n }\n\n /** Posts a message immediately, bypassing the ready-queue. */\n private postNow(message: InboundMessage): void {\n const target = this.frame.contentWindow;\n if (!target) {\n throw new Error(\n \"CaptelloWebview: iframe.contentWindow is null. Wait for the iframe to load before sending.\",\n );\n }\n // The webview reads inbound data with JSON.parse(event.data), so it must be a string.\n target.postMessage(JSON.stringify(message), this.targetOrigin);\n }\n\n /** Marks the client ready and flushes any queued messages, in order. */\n private markReadyAndFlush(): void {\n if (this.ready) return;\n this.ready = true;\n const queued = this.outbox.splice(0);\n for (const message of queued) {\n try {\n this.postNow(message);\n } catch {\n /* iframe detached between load and flush — drop silently */\n }\n }\n }\n\n /** Programmatically submit the form (fire-and-forget). */\n submit(): void {\n this.send({ type: InboundMessageType.Submit });\n }\n\n /**\n * Submit the form and await the outcome.\n *\n * Sends `submit_form`, then resolves with the {@link SubmissionBody} when the\n * webview emits `submission_body`, or rejects with a {@link SubmissionError}\n * (carrying the translated message) when it emits `form_error_message`. Rejects\n * with a {@link SubmissionTimeoutError} if neither arrives within `timeoutMs`.\n *\n * This is the typed, leak-free version of the common \"click submit, wait for the\n * result\" flow — listeners are always cleaned up, including on timeout.\n *\n * @param timeoutMs how long to wait before giving up. Defaults to 60_000.\n * @example\n * try {\n * const body = await webview.submitAndWait();\n * await persist(body);\n * } catch (err) {\n * if (err instanceof SubmissionError) showToast(err.message);\n * }\n */\n submitAndWait(timeoutMs = 60_000): Promise<SubmissionBody> {\n return new Promise<SubmissionBody>((resolve, reject) => {\n let settled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const cleanup = () => {\n settled = true;\n offSuccess();\n offError();\n if (timer !== undefined) clearTimeout(timer);\n };\n\n const offSuccess = this.on(OutboundMessageType.SubmissionBody, (message) => {\n if (settled) return;\n cleanup();\n resolve(message.data);\n });\n const offError = this.on(OutboundMessageType.FormErrorMessage, (message) => {\n if (settled) return;\n cleanup();\n reject(new SubmissionError(message.data));\n });\n\n if (timeoutMs > 0 && timeoutMs !== Infinity) {\n timer = setTimeout(() => {\n if (settled) return;\n cleanup();\n reject(new SubmissionTimeoutError(timeoutMs));\n }, timeoutMs);\n }\n\n try {\n this.send({ type: InboundMessageType.Submit });\n } catch (err) {\n if (!settled) {\n cleanup();\n reject(err);\n }\n }\n });\n }\n\n /** Reset the form, clearing all entered values. */\n reset(): void {\n this.send({ type: InboundMessageType.Reset });\n }\n\n /** Switch the current submission into draft-update mode. */\n updateDraft(): void {\n this.send({ type: InboundMessageType.UpdateDraft });\n }\n\n /** Run validation against a target field, or `\"all\"` for the whole form. */\n triggerValidation(target: ValidationTarget): void {\n this.send({ type: InboundMessageType.TriggerValidation, target });\n }\n\n /** Pre-fill the form from a submission body (a received body or a partial). */\n prefillSubmission(submission: SubmissionPrefill): void {\n this.send({\n type: InboundMessageType.FormPrefill,\n data_type: PrefillDataType.UlcSubmission,\n data: submission,\n });\n }\n\n /** Pre-fill the form from a list of transcription field/value items. */\n prefillInfo(info: PrefillInfoItem[]): void {\n this.send({\n type: InboundMessageType.FormPrefill,\n data_type: PrefillDataType.Info,\n data: info,\n });\n }\n\n /** Pre-fill the form from a submission plus transcription items. */\n prefillSubmissionAndInfo(data: { submission?: SubmissionPrefill; info?: PrefillInfoItem[] }): void {\n this.send({\n type: InboundMessageType.FormPrefill,\n data_type: PrefillDataType.UlcSubmissionAndInfo,\n data,\n });\n }\n\n /* -------------------------------------------------------------- *\n * Lifecycle\n * -------------------------------------------------------------- */\n\n /** Remove the `message` listener and drop all subscriptions. Idempotent. */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.hostWindow.removeEventListener(\"message\", this.boundHandler);\n this.listeners.clear();\n this.anyListeners.clear();\n this.outbox.length = 0;\n }\n\n /* -------------------------------------------------------------- *\n * Internals\n * -------------------------------------------------------------- */\n\n private handleMessage(event: MessageEvent): void {\n if (this.destroyed) return;\n\n // Origin check: skip when targetOrigin is the wildcard. Warn (dev only) if a\n // message that *looks* like ours is dropped on origin — a common \"why isn't my\n // listener firing?\" cause.\n if (this.targetOrigin !== \"*\" && event.origin !== this.targetOrigin) {\n if (parseOutboundMessage(event.data)) {\n devWarn(\n `[captello-sdk] Ignored a Captello message from origin \"${event.origin}\" ` +\n `(expected \"${this.targetOrigin}\"). Check the targetOrigin you passed.`,\n );\n }\n return;\n }\n\n // Source check: only accept messages from the bound iframe's window.\n if (this.matchSource) {\n const expected = this.frame.contentWindow;\n if (expected && event.source !== expected) {\n if (parseOutboundMessage(event.data)) {\n devWarn(\n \"[captello-sdk] Ignored a Captello message from an unexpected source window \" +\n \"(not the bound iframe). If the webview relays through another window, set matchSource: false.\",\n );\n }\n return;\n }\n }\n\n const message = parseOutboundMessage(event.data);\n if (!message) return;\n\n // Flip to ready (and flush queued sends) the moment the form loads, before\n // dispatching to listeners — so a listener can send and have it post immediately.\n if (message.type === OutboundMessageType.FormLoadComplete) {\n this.markReadyAndFlush();\n }\n\n const set = this.listeners.get(message.type);\n if (set) {\n // Copy to a snapshot so a listener that unsubscribes mid-dispatch is safe.\n for (const listener of [...set]) listener(message);\n }\n if (this.anyListeners.size) {\n for (const listener of [...this.anyListeners]) listener(message);\n }\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/embed-url.ts"],"names":["EmbedParam","FormMode","LauncherType","ActionButtonPosition"],"mappings":"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","file":"chunk-RKAY66VV.js","sourcesContent":["/**\n * Builder for the Captello capture webview embed URL.\n *\n * The webview reads its configuration from query-string params. The short keys\n * below are the contract the webview expects (see the webview's `PARAMS` enum);\n * this builder maps friendly option names onto those keys so hosts never have to\n * hard-code `\"f\"`, `\"m\"`, etc.\n */\n\n/** Query-param keys understood by the webview. */\nexport enum EmbedParam {\n FormId = \"f\",\n SubmissionToken = \"s\",\n StationId = \"st\",\n Mode = \"m\",\n EventWebAccessToken = \"e\",\n ActivationId = \"a\",\n Language = \"l\",\n ActionButtonPosition = \"b\",\n FormType = \"form_type\",\n Launcher = \"launcher\",\n SubmissionType = \"t\",\n SubmitButtonBottomPadding = \"sbbp\",\n Platform = \"platform\",\n HideEmail = \"he\",\n ConnexionsEmbedMode = \"cem\",\n /** Edit mode read-only: locks email-mapped and invitation-code elements. */\n Emro = \"emro\",\n /** Context for filtering form-fill actions (e.g. MMP outbound/inbound/notes). */\n UseIn = \"useIn\",\n}\n\n/** Form render mode (the webview's `FormMode`). */\nexport enum FormMode {\n Preview = \"preview\",\n Submit = \"submit\",\n Edit = \"edit\",\n View = \"view\",\n}\n\n/** Identifies the host embedding the webview (the webview's `LAUNCHER_TYPES`). */\nexport enum LauncherType {\n EventGenMobile = \"event_gen_mobile\",\n EventGenWeb = \"event_gen_web\",\n WebApp = \"webapp\",\n Mmp = \"MMP\",\n}\n\n/** `form_type` discriminator. */\nexport type FormType = \"template\" | \"device\";\n\n/** `t` (submission type) discriminator. */\nexport type SubmissionType = \"normal\" | \"drafted\";\n\n/**\n * Action-button position param (`b`), mirroring the webview's `CTABtnPosition`.\n * The wire values are numeric strings; use {@link ActionButtonPosition} for the\n * readable names.\n */\nexport enum ActionButtonPosition {\n Fixed = \"0\",\n Bottom = \"1\",\n Hidden = \"2\",\n}\n\n/** Context for filtering form-fill actions, sent as the `useIn` param. */\nexport type UseInContext = \"outbound\" | \"inbound\" | \"notes\";\n\n/**\n * Options for {@link buildEmbedUrl}. Every field is optional; only the ones you set\n * are written to the URL. `formId` is effectively required for a real embed but is\n * left optional so callers can build preview/partial URLs.\n */\nexport interface EmbedUrlOptions {\n formId?: string | number;\n submissionToken?: string;\n stationId?: string | number;\n mode?: FormMode;\n eventWebAccessToken?: string;\n activationId?: string | number;\n /** Two-letter language code, e.g. `\"en\"`, `\"de\"`. */\n language?: string;\n actionButtonPosition?: ActionButtonPosition;\n formType?: FormType;\n launcher?: LauncherType;\n submissionType?: SubmissionType;\n submitButtonBottomPadding?: string | number;\n /** Context for filtering form-fill actions (the `useIn` param). */\n useIn?: UseInContext;\n platform?: \"web\" | \"mobile\";\n hideEmail?: boolean;\n /** Connexions embed mode: suppress in-webview redirect/vCard download. */\n connexionsEmbedMode?: boolean;\n /** Edit mode read-only. */\n emro?: boolean;\n /**\n * Extra query params to append verbatim (e.g. prospect tracking params the\n * webview forwards on submit). Values are stringified; `undefined`/`null` skipped.\n */\n extraParams?: Record<string, string | number | boolean | undefined | null>;\n}\n\n// Maps each option onto its query key. Order here defines the order params are\n// written, which keeps generated URLs stable and diffable.\nconst OPTION_TO_PARAM: ReadonlyArray<[keyof EmbedUrlOptions, EmbedParam]> = [\n [\"formId\", EmbedParam.FormId],\n [\"submissionToken\", EmbedParam.SubmissionToken],\n [\"stationId\", EmbedParam.StationId],\n [\"mode\", EmbedParam.Mode],\n [\"eventWebAccessToken\", EmbedParam.EventWebAccessToken],\n [\"activationId\", EmbedParam.ActivationId],\n [\"language\", EmbedParam.Language],\n [\"actionButtonPosition\", EmbedParam.ActionButtonPosition],\n [\"formType\", EmbedParam.FormType],\n [\"launcher\", EmbedParam.Launcher],\n [\"submissionType\", EmbedParam.SubmissionType],\n [\"submitButtonBottomPadding\", EmbedParam.SubmitButtonBottomPadding],\n [\"useIn\", EmbedParam.UseIn],\n [\"platform\", EmbedParam.Platform],\n];\n\n// Boolean flags are encoded as \"1\" when true and omitted when false/unset, matching\n// how the webview reads them (`Boolean(queryParams[key])` / presence checks).\nconst BOOLEAN_OPTION_TO_PARAM: ReadonlyArray<[keyof EmbedUrlOptions, EmbedParam]> = [\n [\"hideEmail\", EmbedParam.HideEmail],\n [\"connexionsEmbedMode\", EmbedParam.ConnexionsEmbedMode],\n [\"emro\", EmbedParam.Emro],\n];\n\n/** The path the capture webview is served at. The SDK owns this so callers don't. */\nexport const CAPTURE_SUBMISSION_PATH = \"/capture/submission\";\n\n// Recognized capture routes — if the base URL already targets one of these, it is kept\n// as-is; otherwise the canonical submission path is appended. `capture/activation` is\n// preserved so activation embeds aren't rewritten to a submission URL.\nconst CAPTURE_PATH_PATTERN = /\\/capture\\/(submission|activation)\\/?$/;\n\n/**\n * Normalizes a base capture URL so the path is always a valid capture route, no matter\n * what the caller passed. This is the fix for the \"do I include `/capture/submission`?\"\n * footgun: the origin, the origin with a trailing slash, and the full path all converge\n * to the same correct URL.\n *\n * - Origin only (`https://capture.captello.com`) → path set to `/capture/submission`.\n * - Already a capture route (`…/capture/submission`, `…/capture/activation`, with or\n * without a trailing slash) → kept (trailing slash trimmed).\n * - A base path (`https://host/webview`) → `/capture/submission` appended to it, so\n * sub-path deployments still work.\n *\n * Existing query params and the origin are always preserved.\n */\nfunction normalizeCaptureUrl(baseUrl: string): URL {\n const url = new URL(baseUrl);\n\n if (CAPTURE_PATH_PATTERN.test(url.pathname)) {\n url.pathname = url.pathname.replace(/\\/+$/, \"\"); // drop any trailing slash\n return url;\n }\n\n const base = url.pathname.replace(/\\/+$/, \"\"); // \"\" for origin/\"/\", \"/webview\" for a sub-path\n url.pathname = `${base}${CAPTURE_SUBMISSION_PATH}`;\n return url;\n}\n\n/**\n * Builds an absolute embed URL from a capture base URL and typed options.\n *\n * You only need to pass the **capture origin** — the SDK appends the capture path for\n * you. Passing the origin, the origin with a trailing slash, or the full\n * `…/capture/submission` URL all produce the same correct result, so there's nothing to\n * get wrong. Existing query params on `baseUrl` are preserved; options override params\n * with the same key.\n *\n * @example\n * // All three are equivalent:\n * buildEmbedUrl(\"https://capture.captello.com\", { formId: 1234, mode: FormMode.Submit });\n * buildEmbedUrl(\"https://capture.captello.com/\", { formId: 1234, mode: FormMode.Submit });\n * buildEmbedUrl(\"https://capture.captello.com/capture/submission\", { formId: 1234, mode: FormMode.Submit });\n * // → \"https://capture.captello.com/capture/submission?f=1234&m=submit\"\n */\nexport function buildEmbedUrl(baseUrl: string, options: EmbedUrlOptions = {}): string {\n const url = normalizeCaptureUrl(baseUrl);\n\n for (const [optionKey, paramKey] of OPTION_TO_PARAM) {\n const value = options[optionKey];\n if (value !== undefined && value !== null && value !== \"\") {\n url.searchParams.set(paramKey, String(value));\n }\n }\n\n for (const [optionKey, paramKey] of BOOLEAN_OPTION_TO_PARAM) {\n if (options[optionKey]) {\n url.searchParams.set(paramKey, \"1\");\n }\n }\n\n if (options.extraParams) {\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n}\n"]}