@captello/ulc-webview-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +424 -0
- package/dist/chunk-ETF52K7K.js +91 -0
- package/dist/chunk-ETF52K7K.js.map +1 -0
- package/dist/chunk-ZMYMZK2A.js +328 -0
- package/dist/chunk-ZMYMZK2A.js.map +1 -0
- package/dist/client-3IBxKbIE.d.cts +561 -0
- package/dist/client-3IBxKbIE.d.ts +561 -0
- package/dist/index.cjs +594 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/dist/promises.cjs +366 -0
- package/dist/promises.cjs.map +1 -0
- package/dist/promises.d.cts +72 -0
- package/dist/promises.d.ts +72 -0
- package/dist/promises.js +51 -0
- package/dist/promises.js.map +1 -0
- package/dist/react.cjs +476 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +108 -0
- package/dist/react.d.ts +108 -0
- package/dist/react.js +112 -0
- package/dist/react.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed access to a submission's **visible** data — the list a host renders as
|
|
3
|
+
* key/value pairs (one row per filled, visible form element).
|
|
4
|
+
*
|
|
5
|
+
* The webview emits this as `visible_submissions_data` inside the `submission_body`
|
|
6
|
+
* payload: an array of items discriminated by `element_type`, where `element_value`'s
|
|
7
|
+
* shape depends on the type. This module mirrors that contract and provides:
|
|
8
|
+
*
|
|
9
|
+
* - {@link parseVisibleSubmissionsData} — narrow `unknown` to typed items, dropping
|
|
10
|
+
* anything that doesn't match the contract.
|
|
11
|
+
* - {@link toDisplayValue} / {@link toDisplayPairs} — flatten each item to a string
|
|
12
|
+
* (and `{ id, label, value }` rows) for direct rendering.
|
|
13
|
+
*
|
|
14
|
+
* For custom rendering, narrow on `element_type` and read the precisely-typed
|
|
15
|
+
* `element_value` yourself.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Every form element type, mirroring the webview's `FormElementType`. The string
|
|
19
|
+
* values are the wire values. Structural types (sections, separators, …) never carry
|
|
20
|
+
* a value and never appear in visible submission data.
|
|
21
|
+
*/
|
|
22
|
+
declare enum FormElementType {
|
|
23
|
+
email = "email",
|
|
24
|
+
section = "section_block",
|
|
25
|
+
html_block = "section",
|
|
26
|
+
url = "url",
|
|
27
|
+
text = "text",
|
|
28
|
+
select = "select",
|
|
29
|
+
radio = "radio",
|
|
30
|
+
simple_name = "simple_name",
|
|
31
|
+
textarea = "textarea",
|
|
32
|
+
time = "time",
|
|
33
|
+
address = "address",
|
|
34
|
+
money = "money",
|
|
35
|
+
number = "number",
|
|
36
|
+
date = "date",
|
|
37
|
+
phone = "phone",
|
|
38
|
+
simple_phone = "simple_phone",
|
|
39
|
+
checkbox = "checkbox",
|
|
40
|
+
image = "image",
|
|
41
|
+
business_card = "business_card",
|
|
42
|
+
signature = "signature",
|
|
43
|
+
barcode = "barcode",
|
|
44
|
+
separator = "column_separator",
|
|
45
|
+
activation = "activation",
|
|
46
|
+
document = "documents",
|
|
47
|
+
datetime = "datetime",
|
|
48
|
+
meeting = "meeting",
|
|
49
|
+
audio = "audio",
|
|
50
|
+
rating = "rating",
|
|
51
|
+
assign_owner = "assign_owner",
|
|
52
|
+
boolean = "boolean",
|
|
53
|
+
engagem_feeder = "engagem_feeder",
|
|
54
|
+
speaker_section = "speaker_section_block",
|
|
55
|
+
session_section = "session_section_block",
|
|
56
|
+
image_placeholder = "image_placeholder",
|
|
57
|
+
star_rating = "star_survey",
|
|
58
|
+
attachments = "attachments"
|
|
59
|
+
}
|
|
60
|
+
/** Composite element value (simple_name / address): sub-field values keyed by sub-element id. */
|
|
61
|
+
type CompositeSubmissionValue = {
|
|
62
|
+
[subElementId: string]: string;
|
|
63
|
+
};
|
|
64
|
+
/** Checkbox value when the element is an "order" checkbox (quantities + note). */
|
|
65
|
+
type OrderCheckboxSubmissionData = {
|
|
66
|
+
values: {
|
|
67
|
+
value: string;
|
|
68
|
+
quantity: number;
|
|
69
|
+
}[];
|
|
70
|
+
note: string;
|
|
71
|
+
};
|
|
72
|
+
/** Radio/select value when the element is an "order" radio/select (quantity + note). */
|
|
73
|
+
type OrderRadioSubmissionData = {
|
|
74
|
+
value: string;
|
|
75
|
+
quantity: number;
|
|
76
|
+
note: string;
|
|
77
|
+
};
|
|
78
|
+
/** An uploaded attachment. `blob` is not present on the wire (postMessage JSON drops it). */
|
|
79
|
+
type AttachmentValue = {
|
|
80
|
+
token: string;
|
|
81
|
+
url: string;
|
|
82
|
+
name: string;
|
|
83
|
+
size: number;
|
|
84
|
+
};
|
|
85
|
+
/** A business-card capture: front/back image references (either may be absent). */
|
|
86
|
+
type BusinessCardValue = {
|
|
87
|
+
front: string;
|
|
88
|
+
back: string;
|
|
89
|
+
};
|
|
90
|
+
/** One engagement-feeder question/answer entry. */
|
|
91
|
+
type SubmissionQuestionData = {
|
|
92
|
+
question: string;
|
|
93
|
+
answers: string[];
|
|
94
|
+
/** `""` when the element is hidden. */
|
|
95
|
+
correct_answer: number | "";
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Maps each value-carrying element type to its `element_value` shape. Structural
|
|
99
|
+
* types are intentionally absent, so they can never appear in a visible item.
|
|
100
|
+
*/
|
|
101
|
+
type VisibleSubmissionElementValueMap = {
|
|
102
|
+
[FormElementType.email]: string;
|
|
103
|
+
[FormElementType.url]: string;
|
|
104
|
+
[FormElementType.text]: string;
|
|
105
|
+
[FormElementType.textarea]: string;
|
|
106
|
+
[FormElementType.money]: string;
|
|
107
|
+
[FormElementType.number]: string;
|
|
108
|
+
[FormElementType.phone]: string;
|
|
109
|
+
[FormElementType.simple_phone]: string;
|
|
110
|
+
[FormElementType.date]: string;
|
|
111
|
+
[FormElementType.time]: string;
|
|
112
|
+
[FormElementType.datetime]: string;
|
|
113
|
+
[FormElementType.audio]: string;
|
|
114
|
+
[FormElementType.rating]: string;
|
|
115
|
+
[FormElementType.star_rating]: string;
|
|
116
|
+
[FormElementType.assign_owner]: string;
|
|
117
|
+
[FormElementType.signature]: string;
|
|
118
|
+
[FormElementType.barcode]: string;
|
|
119
|
+
[FormElementType.meeting]: string;
|
|
120
|
+
[FormElementType.activation]: string;
|
|
121
|
+
[FormElementType.checkbox]: string[] | OrderCheckboxSubmissionData;
|
|
122
|
+
[FormElementType.radio]: string | OrderRadioSubmissionData;
|
|
123
|
+
[FormElementType.select]: string | OrderRadioSubmissionData;
|
|
124
|
+
[FormElementType.image]: string[];
|
|
125
|
+
[FormElementType.document]: number[];
|
|
126
|
+
[FormElementType.engagem_feeder]: SubmissionQuestionData[];
|
|
127
|
+
[FormElementType.business_card]: Partial<BusinessCardValue>;
|
|
128
|
+
[FormElementType.boolean]: boolean;
|
|
129
|
+
[FormElementType.attachments]: AttachmentValue[];
|
|
130
|
+
[FormElementType.simple_name]: CompositeSubmissionValue;
|
|
131
|
+
[FormElementType.address]: CompositeSubmissionValue;
|
|
132
|
+
};
|
|
133
|
+
/** Element types that carry a user-facing value (i.e. can appear in visible data). */
|
|
134
|
+
type VisibleSubmissionElementType = keyof VisibleSubmissionElementValueMap;
|
|
135
|
+
/**
|
|
136
|
+
* One entry in `visible_submissions_data`, discriminated by `element_type`. Narrowing
|
|
137
|
+
* on `element_type` gives a precisely-typed `element_value`.
|
|
138
|
+
*/
|
|
139
|
+
type VisibleSubmissionDataItem = {
|
|
140
|
+
[T in VisibleSubmissionElementType]: {
|
|
141
|
+
element_id: string;
|
|
142
|
+
element_title: string;
|
|
143
|
+
element_type: T;
|
|
144
|
+
element_value: VisibleSubmissionElementValueMap[T];
|
|
145
|
+
};
|
|
146
|
+
}[VisibleSubmissionElementType];
|
|
147
|
+
/**
|
|
148
|
+
* Narrows `unknown` to a typed `VisibleSubmissionDataItem[]`, ready for rendering.
|
|
149
|
+
*
|
|
150
|
+
* Accepts, in order of convenience:
|
|
151
|
+
* - the `visible_submissions_data` array itself,
|
|
152
|
+
* - a `submission_body` payload object (the `data` of a `SubmissionBody` message) —
|
|
153
|
+
* its `visible_submissions_data` is extracted,
|
|
154
|
+
* - anything else → `[]`.
|
|
155
|
+
*
|
|
156
|
+
* Items that don't match the contract (missing fields, structural/unknown
|
|
157
|
+
* `element_type`) are dropped, so the result is always safe to map over.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* webview.on(OutboundMessageType.SubmissionBody, (msg) => {
|
|
161
|
+
* const rows = toDisplayPairs(msg.data); // [{ elementId, label, value }, ...]
|
|
162
|
+
* render(rows);
|
|
163
|
+
* });
|
|
164
|
+
*/
|
|
165
|
+
declare function parseVisibleSubmissionsData(data: unknown): VisibleSubmissionDataItem[];
|
|
166
|
+
/** Options for {@link toDisplayValue} / {@link toDisplayPairs}. */
|
|
167
|
+
interface DisplayValueOptions {
|
|
168
|
+
/** Separator for list-like values (checkbox, image, …). Default `", "`. */
|
|
169
|
+
listSeparator?: string;
|
|
170
|
+
/** Labels for boolean values. Default `{ true: "Yes", false: "No" }`. */
|
|
171
|
+
booleanLabels?: {
|
|
172
|
+
true: string;
|
|
173
|
+
false: string;
|
|
174
|
+
};
|
|
175
|
+
/** Text used when a value is empty/blank. Default `""`. */
|
|
176
|
+
emptyText?: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Flattens a single visible item's `element_value` to a human-readable string for
|
|
180
|
+
* rendering — composites are joined, list/order values are summarized, booleans use
|
|
181
|
+
* the configured labels. For full control, read `element_value` directly instead.
|
|
182
|
+
*/
|
|
183
|
+
declare function toDisplayValue(item: VisibleSubmissionDataItem, options?: DisplayValueOptions): string;
|
|
184
|
+
/** A render-ready key/value row. */
|
|
185
|
+
interface SubmissionDisplayPair {
|
|
186
|
+
elementId: string;
|
|
187
|
+
label: string;
|
|
188
|
+
value: string;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* One-shot helper: parse `unknown` and map each visible item to a
|
|
192
|
+
* `{ elementId, label, value }` row, where `value` is {@link toDisplayValue}'s output.
|
|
193
|
+
* Ideal for rendering a submission as a key/value list.
|
|
194
|
+
*/
|
|
195
|
+
declare function toDisplayPairs(data: unknown, options?: DisplayValueOptions): SubmissionDisplayPair[];
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The message protocol exchanged between the Captello capture webview (the iframe)
|
|
199
|
+
* and its host page.
|
|
200
|
+
*
|
|
201
|
+
* Wire format (this is the contract — match it exactly):
|
|
202
|
+
* - Every message is a JSON **string**. The webview sends outbound messages with
|
|
203
|
+
* `JSON.stringify(message)` and reads inbound messages with `JSON.parse(event.data)`.
|
|
204
|
+
* A host that posts a raw object instead of a string will be ignored, because the
|
|
205
|
+
* webview's parser produces a non-object and bails.
|
|
206
|
+
* - Every message is an object with a `type` discriminator. Inbound and outbound
|
|
207
|
+
* types are disjoint string enums.
|
|
208
|
+
*
|
|
209
|
+
* Direction is named from the **webview's** point of view:
|
|
210
|
+
* - {@link OutboundMessageType}: webview → host (the host listens for these).
|
|
211
|
+
* - {@link InboundMessageType}: host → webview (the host sends these).
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
/** Message `type` values the webview emits to its host. */
|
|
215
|
+
declare enum OutboundMessageType {
|
|
216
|
+
/** The form finished loading and rendering. Safe to interact with it after this. */
|
|
217
|
+
FormLoadComplete = "form_load_complete",
|
|
218
|
+
/** A user-facing error occurred; `data` is the translated, display-ready message. */
|
|
219
|
+
FormErrorMessage = "form_error_message",
|
|
220
|
+
/**
|
|
221
|
+
* Emitted for embedded forms instead of submitting directly: `data` is the full
|
|
222
|
+
* submission body for the host to persist/forward.
|
|
223
|
+
*/
|
|
224
|
+
SubmissionBody = "submission_body",
|
|
225
|
+
/** The form was submitted successfully (used in kiosk / quick-capture flows). */
|
|
226
|
+
FormSubmitSuccess = "form_submit_success",
|
|
227
|
+
/** Connexions: the host should perform the profile redirect (embed mode). */
|
|
228
|
+
ConnexionsProfileRedirect = "connexions_profile_redirect",
|
|
229
|
+
/** Connexions: the host should trigger the vCard download (embed mode). */
|
|
230
|
+
ConnexionsDownloadVcard = "connexions_download_vcard"
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Opaque submission payload carried by {@link OutboundMessageType.SubmissionBody}.
|
|
234
|
+
*
|
|
235
|
+
* This mirrors the webview's internal `FormSubmission` model. It is intentionally
|
|
236
|
+
* typed as an open record here so the SDK stays decoupled from the app's full model
|
|
237
|
+
* graph; the documented fields below are stable, the rest are passed through as-is.
|
|
238
|
+
* Host code that needs the deep element-value types should treat `data` as untyped
|
|
239
|
+
* and key it by element id (e.g. `"element_12"`, `"element_12_3"`).
|
|
240
|
+
*/
|
|
241
|
+
interface SubmissionBody {
|
|
242
|
+
id: number;
|
|
243
|
+
form_id: number;
|
|
244
|
+
prospect_id: number;
|
|
245
|
+
email: string;
|
|
246
|
+
first_name: string;
|
|
247
|
+
last_name: string;
|
|
248
|
+
full_name: string;
|
|
249
|
+
company: string;
|
|
250
|
+
phone: string;
|
|
251
|
+
/** Submitted values keyed by element id / sub-element id. */
|
|
252
|
+
data: Record<string, unknown>;
|
|
253
|
+
/**
|
|
254
|
+
* Visible, filled elements ready to render as key/value rows — one item per
|
|
255
|
+
* element, discriminated by `element_type`. Use {@link parseVisibleSubmissionsData}
|
|
256
|
+
* or {@link toDisplayPairs} to consume it. May be absent on older webview builds.
|
|
257
|
+
*/
|
|
258
|
+
visible_submissions_data?: VisibleSubmissionDataItem[];
|
|
259
|
+
submission_date: string;
|
|
260
|
+
/** Query-string params the webview was loaded with, echoed back on submit. */
|
|
261
|
+
query_parameters?: Record<string, string>;
|
|
262
|
+
/** Additional fields from the webview's submission model are passed through verbatim. */
|
|
263
|
+
[key: string]: unknown;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Loose submission shape accepted when **pre-filling** the form (host → webview).
|
|
267
|
+
*
|
|
268
|
+
* Distinct from {@link SubmissionBody}: a received `submission_body` is always fully
|
|
269
|
+
* populated, but when pre-filling you typically either round-trip a previously-received
|
|
270
|
+
* body or pass a partial object assembled from your own data. A {@link SubmissionBody}
|
|
271
|
+
* is assignable to this, so round-tripping just works.
|
|
272
|
+
*/
|
|
273
|
+
interface SubmissionPrefill {
|
|
274
|
+
/** Submitted values keyed by element id / sub-element id. */
|
|
275
|
+
data?: Record<string, unknown>;
|
|
276
|
+
[key: string]: unknown;
|
|
277
|
+
}
|
|
278
|
+
interface FormLoadCompleteMessage {
|
|
279
|
+
type: OutboundMessageType.FormLoadComplete;
|
|
280
|
+
}
|
|
281
|
+
interface FormSubmitSuccessMessage {
|
|
282
|
+
type: OutboundMessageType.FormSubmitSuccess;
|
|
283
|
+
}
|
|
284
|
+
interface FormErrorMessageMessage {
|
|
285
|
+
type: OutboundMessageType.FormErrorMessage;
|
|
286
|
+
/** Translated, display-ready error text. */
|
|
287
|
+
data: string;
|
|
288
|
+
}
|
|
289
|
+
interface SubmissionBodyMessage {
|
|
290
|
+
type: OutboundMessageType.SubmissionBody;
|
|
291
|
+
data: SubmissionBody;
|
|
292
|
+
}
|
|
293
|
+
interface ConnexionsProfileRedirectMessage {
|
|
294
|
+
type: OutboundMessageType.ConnexionsProfileRedirect;
|
|
295
|
+
}
|
|
296
|
+
interface ConnexionsDownloadVcardMessage {
|
|
297
|
+
type: OutboundMessageType.ConnexionsDownloadVcard;
|
|
298
|
+
}
|
|
299
|
+
/** Discriminated union of every message the webview can emit to its host. */
|
|
300
|
+
type OutboundMessage = FormLoadCompleteMessage | FormSubmitSuccessMessage | FormErrorMessageMessage | SubmissionBodyMessage | ConnexionsProfileRedirectMessage | ConnexionsDownloadVcardMessage;
|
|
301
|
+
/** Maps each outbound `type` to its full message shape (used by the client's `.on`). */
|
|
302
|
+
type OutboundMessageMap = {
|
|
303
|
+
[M in OutboundMessage as M["type"]]: M;
|
|
304
|
+
};
|
|
305
|
+
/** Message `type` values the host sends into the webview. */
|
|
306
|
+
declare enum InboundMessageType {
|
|
307
|
+
/** Programmatically trigger form submission (as if the user pressed submit). */
|
|
308
|
+
Submit = "submit_form",
|
|
309
|
+
/** Reset the form, clearing all entered values. */
|
|
310
|
+
Reset = "reset_form",
|
|
311
|
+
/** Pre-fill the form with existing data. See {@link PrefillDataType}. */
|
|
312
|
+
FormPrefill = "form_prefill",
|
|
313
|
+
/** Switch the current submission into draft-update mode. */
|
|
314
|
+
UpdateDraft = "update_draft",
|
|
315
|
+
/** Run validation against a target field (or the whole form). */
|
|
316
|
+
TriggerValidation = "trigger_validation"
|
|
317
|
+
}
|
|
318
|
+
/** Shape selector for {@link InboundMessageType.FormPrefill} payloads. */
|
|
319
|
+
declare enum PrefillDataType {
|
|
320
|
+
/** `data` is a full ULC submission (the webview's submission model). */
|
|
321
|
+
UlcSubmission = "ulc_submission",
|
|
322
|
+
/** `data` is a list of transcription field/value items. */
|
|
323
|
+
Info = "info",
|
|
324
|
+
/** `data` is `{ submission, info }` — a submission plus transcription items. */
|
|
325
|
+
UlcSubmissionAndInfo = "ulc_submission_and_info"
|
|
326
|
+
}
|
|
327
|
+
/** Targets for {@link InboundMessageType.TriggerValidation}. */
|
|
328
|
+
type ValidationTarget = "invitation_code" | "email" | "all";
|
|
329
|
+
/**
|
|
330
|
+
* A single transcription field/value item used by {@link PrefillDataType.Info}.
|
|
331
|
+
*
|
|
332
|
+
* The webview matches each item to a form element by `ll_field_unique_identifier`
|
|
333
|
+
* alone (e.g. `"FirstName"`, `"Email"`); `ll_field_id` is catalog metadata and is not
|
|
334
|
+
* used for matching, so it is accepted as either a number or a string. `value` is
|
|
335
|
+
* typically a string but may be a boolean (e.g. the PII opt-out field).
|
|
336
|
+
*/
|
|
337
|
+
interface PrefillInfoItem {
|
|
338
|
+
ll_field_unique_identifier: string;
|
|
339
|
+
ll_field_id?: string | number;
|
|
340
|
+
value: string | boolean;
|
|
341
|
+
}
|
|
342
|
+
interface SubmitMessage {
|
|
343
|
+
type: InboundMessageType.Submit;
|
|
344
|
+
}
|
|
345
|
+
interface ResetMessage {
|
|
346
|
+
type: InboundMessageType.Reset;
|
|
347
|
+
}
|
|
348
|
+
interface UpdateDraftMessage {
|
|
349
|
+
type: InboundMessageType.UpdateDraft;
|
|
350
|
+
}
|
|
351
|
+
interface TriggerValidationMessage {
|
|
352
|
+
type: InboundMessageType.TriggerValidation;
|
|
353
|
+
target: ValidationTarget;
|
|
354
|
+
}
|
|
355
|
+
interface PrefillSubmissionMessage {
|
|
356
|
+
type: InboundMessageType.FormPrefill;
|
|
357
|
+
data_type: PrefillDataType.UlcSubmission;
|
|
358
|
+
/** A submission body to pre-fill from (a received {@link SubmissionBody} or a partial). */
|
|
359
|
+
data: SubmissionPrefill;
|
|
360
|
+
}
|
|
361
|
+
interface PrefillInfoMessage {
|
|
362
|
+
type: InboundMessageType.FormPrefill;
|
|
363
|
+
data_type: PrefillDataType.Info;
|
|
364
|
+
data: PrefillInfoItem[];
|
|
365
|
+
}
|
|
366
|
+
interface PrefillSubmissionAndInfoMessage {
|
|
367
|
+
type: InboundMessageType.FormPrefill;
|
|
368
|
+
data_type: PrefillDataType.UlcSubmissionAndInfo;
|
|
369
|
+
data: {
|
|
370
|
+
submission?: SubmissionPrefill;
|
|
371
|
+
info?: PrefillInfoItem[];
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
/** Discriminated union of every message the host can send into the webview. */
|
|
375
|
+
type InboundMessage = SubmitMessage | ResetMessage | UpdateDraftMessage | TriggerValidationMessage | PrefillSubmissionMessage | PrefillInfoMessage | PrefillSubmissionAndInfoMessage;
|
|
376
|
+
/**
|
|
377
|
+
* Parses a raw `MessageEvent.data` value into a typed {@link OutboundMessage}, or
|
|
378
|
+
* returns `null` if it is not a recognized Captello webview message.
|
|
379
|
+
*
|
|
380
|
+
* Accepts either a JSON string (the webview always sends strings) or an
|
|
381
|
+
* already-parsed object, so it is robust to hosts/proxies that pre-parse.
|
|
382
|
+
*/
|
|
383
|
+
declare function parseOutboundMessage(data: unknown): OutboundMessage | null;
|
|
384
|
+
|
|
385
|
+
/** Listener for a specific outbound message type. */
|
|
386
|
+
type OutboundListener<T extends OutboundMessageType> = (message: OutboundMessageMap[T]) => void;
|
|
387
|
+
/** Listener for every outbound message (used by {@link CaptelloWebview.onAny}). */
|
|
388
|
+
type AnyOutboundListener = (message: OutboundMessage) => void;
|
|
389
|
+
/** Unsubscribe handle returned by every `on*` method. Calling it removes the listener. */
|
|
390
|
+
type Unsubscribe = () => void;
|
|
391
|
+
/**
|
|
392
|
+
* Rejection reason from {@link CaptelloWebview.submitAndWait} when the webview reports
|
|
393
|
+
* a `form_error_message`. `message` is the translated, display-ready text.
|
|
394
|
+
*/
|
|
395
|
+
declare class SubmissionError extends Error {
|
|
396
|
+
constructor(message: string);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Rejection reason from {@link CaptelloWebview.submitAndWait} when no `submission_body`
|
|
400
|
+
* or `form_error_message` arrives within the timeout.
|
|
401
|
+
*/
|
|
402
|
+
declare class SubmissionTimeoutError extends Error {
|
|
403
|
+
readonly timeoutMs: number;
|
|
404
|
+
constructor(timeoutMs: number);
|
|
405
|
+
}
|
|
406
|
+
interface CaptelloWebviewOptions {
|
|
407
|
+
/**
|
|
408
|
+
* Origin to validate incoming messages against and to target outgoing messages.
|
|
409
|
+
* Strongly recommended — set it to the webview's origin (e.g.
|
|
410
|
+
* `"https://capture.captello.com"`). Use {@link targetOriginFromUrl} to derive it
|
|
411
|
+
* from the embed URL.
|
|
412
|
+
*
|
|
413
|
+
* Defaults to `"*"`, which accepts messages from any origin and posts without an
|
|
414
|
+
* origin check. Only acceptable for trusted/local development.
|
|
415
|
+
*/
|
|
416
|
+
targetOrigin?: string;
|
|
417
|
+
/**
|
|
418
|
+
* The window to attach the `message` listener to. Defaults to the global `window`.
|
|
419
|
+
* Override for testing or non-standard host environments.
|
|
420
|
+
*/
|
|
421
|
+
hostWindow?: Window;
|
|
422
|
+
/**
|
|
423
|
+
* If `true` (default), incoming messages are accepted only when they originate
|
|
424
|
+
* from the bound iframe's `contentWindow`. Set `false` only if the webview relays
|
|
425
|
+
* messages through an intermediate window and source matching is impossible.
|
|
426
|
+
*/
|
|
427
|
+
matchSource?: boolean;
|
|
428
|
+
/**
|
|
429
|
+
* If `true` (default), messages sent before the webview reports
|
|
430
|
+
* `form_load_complete` are buffered and flushed, in order, once it's ready. This
|
|
431
|
+
* removes a common footgun: calling `prefillInfo(...)` right after mount would
|
|
432
|
+
* otherwise post to a form that isn't listening yet and be silently dropped.
|
|
433
|
+
*
|
|
434
|
+
* Set `false` to send immediately (the legacy behavior). Note: a client that
|
|
435
|
+
* attaches *after* the form already loaded will not have seen `form_load_complete`,
|
|
436
|
+
* so its queued messages won't flush — create the client with the iframe.
|
|
437
|
+
*/
|
|
438
|
+
queueUntilReady?: boolean;
|
|
439
|
+
}
|
|
440
|
+
type ElementOrFrame = HTMLIFrameElement | {
|
|
441
|
+
contentWindow: Window | null;
|
|
442
|
+
};
|
|
443
|
+
/**
|
|
444
|
+
* Host-side controller for an embedded Captello capture webview.
|
|
445
|
+
*
|
|
446
|
+
* Wraps a single `<iframe>` and encodes the full message protocol:
|
|
447
|
+
* - **Receiving** (webview → host): subscribe with {@link on} / {@link onAny}.
|
|
448
|
+
* - **Sending** (host → webview): use {@link submit}, {@link reset}, {@link prefill},
|
|
449
|
+
* {@link triggerValidation}, {@link updateDraft}, or the lower-level {@link send}.
|
|
450
|
+
*
|
|
451
|
+
* Wire details handled for you: outgoing messages are `JSON.stringify`'d (the webview
|
|
452
|
+
* parses inbound data with `JSON.parse`, so a raw object would be ignored), and
|
|
453
|
+
* incoming messages are validated by origin + source before being parsed.
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```ts
|
|
457
|
+
* const iframe = document.querySelector("iframe")!;
|
|
458
|
+
* const webview = new CaptelloWebview(iframe, {
|
|
459
|
+
* targetOrigin: "https://capture.captello.com",
|
|
460
|
+
* });
|
|
461
|
+
*
|
|
462
|
+
* webview.on(OutboundMessageType.FormLoadComplete, () => console.log("ready"));
|
|
463
|
+
* webview.on(OutboundMessageType.SubmissionBody, (msg) => save(msg.data));
|
|
464
|
+
*
|
|
465
|
+
* // later, drive the form:
|
|
466
|
+
* webview.submit();
|
|
467
|
+
*
|
|
468
|
+
* // on teardown:
|
|
469
|
+
* webview.destroy();
|
|
470
|
+
* ```
|
|
471
|
+
*/
|
|
472
|
+
declare class CaptelloWebview {
|
|
473
|
+
private readonly frame;
|
|
474
|
+
private readonly targetOrigin;
|
|
475
|
+
private readonly hostWindow;
|
|
476
|
+
private readonly matchSource;
|
|
477
|
+
private readonly listeners;
|
|
478
|
+
private readonly anyListeners;
|
|
479
|
+
private readonly boundHandler;
|
|
480
|
+
private destroyed;
|
|
481
|
+
private readonly queueUntilReady;
|
|
482
|
+
/** True once `form_load_complete` has been observed. */
|
|
483
|
+
private ready;
|
|
484
|
+
/** Messages sent before ready, flushed in order on load. */
|
|
485
|
+
private readonly outbox;
|
|
486
|
+
constructor(frame: ElementOrFrame, options?: CaptelloWebviewOptions);
|
|
487
|
+
/** `true` once the webview has reported `form_load_complete`. */
|
|
488
|
+
get isReady(): boolean;
|
|
489
|
+
/**
|
|
490
|
+
* Subscribe to a single outbound message type. Returns an unsubscribe function.
|
|
491
|
+
*
|
|
492
|
+
* @example webview.on(OutboundMessageType.FormErrorMessage, (m) => toast(m.data));
|
|
493
|
+
*/
|
|
494
|
+
on<T extends OutboundMessageType>(type: T, listener: OutboundListener<T>): Unsubscribe;
|
|
495
|
+
/**
|
|
496
|
+
* Subscribe once: the listener is removed automatically after it fires the first
|
|
497
|
+
* time for `type`. Returns an unsubscribe function for cancelling early.
|
|
498
|
+
*/
|
|
499
|
+
once<T extends OutboundMessageType>(type: T, listener: OutboundListener<T>): Unsubscribe;
|
|
500
|
+
/** Subscribe to every outbound message regardless of type. Returns an unsubscribe function. */
|
|
501
|
+
onAny(listener: AnyOutboundListener): Unsubscribe;
|
|
502
|
+
/**
|
|
503
|
+
* Low-level send: posts any inbound message to the webview as a JSON string.
|
|
504
|
+
* Prefer the typed helpers below; use this only for forward-compatibility.
|
|
505
|
+
*
|
|
506
|
+
* When `queueUntilReady` is enabled (the default) and the form hasn't reported
|
|
507
|
+
* `form_load_complete` yet, the message is buffered and flushed on load instead of
|
|
508
|
+
* posted immediately.
|
|
509
|
+
*
|
|
510
|
+
* @throws if the iframe's `contentWindow` is not available (not yet loaded /
|
|
511
|
+
* detached) and the message can't be queued.
|
|
512
|
+
*/
|
|
513
|
+
send(message: InboundMessage): void;
|
|
514
|
+
/** Posts a message immediately, bypassing the ready-queue. */
|
|
515
|
+
private postNow;
|
|
516
|
+
/** Marks the client ready and flushes any queued messages, in order. */
|
|
517
|
+
private markReadyAndFlush;
|
|
518
|
+
/** Programmatically submit the form (fire-and-forget). */
|
|
519
|
+
submit(): void;
|
|
520
|
+
/**
|
|
521
|
+
* Submit the form and await the outcome.
|
|
522
|
+
*
|
|
523
|
+
* Sends `submit_form`, then resolves with the {@link SubmissionBody} when the
|
|
524
|
+
* webview emits `submission_body`, or rejects with a {@link SubmissionError}
|
|
525
|
+
* (carrying the translated message) when it emits `form_error_message`. Rejects
|
|
526
|
+
* with a {@link SubmissionTimeoutError} if neither arrives within `timeoutMs`.
|
|
527
|
+
*
|
|
528
|
+
* This is the typed, leak-free version of the common "click submit, wait for the
|
|
529
|
+
* result" flow — listeners are always cleaned up, including on timeout.
|
|
530
|
+
*
|
|
531
|
+
* @param timeoutMs how long to wait before giving up. Defaults to 60_000.
|
|
532
|
+
* @example
|
|
533
|
+
* try {
|
|
534
|
+
* const body = await webview.submitAndWait();
|
|
535
|
+
* await persist(body);
|
|
536
|
+
* } catch (err) {
|
|
537
|
+
* if (err instanceof SubmissionError) showToast(err.message);
|
|
538
|
+
* }
|
|
539
|
+
*/
|
|
540
|
+
submitAndWait(timeoutMs?: number): Promise<SubmissionBody>;
|
|
541
|
+
/** Reset the form, clearing all entered values. */
|
|
542
|
+
reset(): void;
|
|
543
|
+
/** Switch the current submission into draft-update mode. */
|
|
544
|
+
updateDraft(): void;
|
|
545
|
+
/** Run validation against a target field, or `"all"` for the whole form. */
|
|
546
|
+
triggerValidation(target: ValidationTarget): void;
|
|
547
|
+
/** Pre-fill the form from a submission body (a received body or a partial). */
|
|
548
|
+
prefillSubmission(submission: SubmissionPrefill): void;
|
|
549
|
+
/** Pre-fill the form from a list of transcription field/value items. */
|
|
550
|
+
prefillInfo(info: PrefillInfoItem[]): void;
|
|
551
|
+
/** Pre-fill the form from a submission plus transcription items. */
|
|
552
|
+
prefillSubmissionAndInfo(data: {
|
|
553
|
+
submission?: SubmissionPrefill;
|
|
554
|
+
info?: PrefillInfoItem[];
|
|
555
|
+
}): void;
|
|
556
|
+
/** Remove the `message` listener and drop all subscriptions. Idempotent. */
|
|
557
|
+
destroy(): void;
|
|
558
|
+
private handleMessage;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
export { type AnyOutboundListener as A, type BusinessCardValue as B, type CaptelloWebviewOptions as C, type DisplayValueOptions as D, 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 SubmissionDisplayPair as n, type SubmissionQuestionData as o, type VisibleSubmissionDataItem as p, type VisibleSubmissionElementType as q, type VisibleSubmissionElementValueMap as r, parseOutboundMessage as s, parseVisibleSubmissionsData as t, toDisplayPairs as u, toDisplayValue as v };
|