@lorikeetai/react-native-sdk 2.0.0-alpha.3 → 2.0.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/dist/index.d.cts CHANGED
@@ -13,13 +13,21 @@ type ConversationMetadata = Record<string, unknown>;
13
13
  * have: `Customisations` then degraded to `any` and typed nothing.
14
14
  * `ConversationMetadata` is duplicated here for the same reason.
15
15
  *
16
- * `src/customisations.web-sdk-parity.ts` fails the build if the two drift.
16
+ * `src/customisations.web-sdk-parity.ts` fails `typecheck` if the two drift. Not
17
+ * the build: that file is unreachable from `index.ts`, so the declaration build
18
+ * never sees it.
17
19
  *
18
- * Fields that only mean something on a web page, the viewport sizes and the
19
- * launcher button, are kept so the page's behaviour is unchanged and so a host
20
- * sharing one configuration object with its web widget still type-checks.
20
+ * Fields that only mean something on a web page are kept so the page's behaviour
21
+ * is unchanged and so a host sharing one configuration object with its web
22
+ * widget still type-checks. The viewport sizes, the launcher button and `mode`
23
+ * are all read by the web SDK rather than by the page, so none of them reaches
24
+ * anything this SDK renders.
25
+ */
26
+ /**
27
+ * Sizing for one viewport. Mostly desktop: the page is full-screen on mobile, so
28
+ * `height`, `width` and `borderRadius` are read for `desktop` alone, while
29
+ * `topClearance` and `default_open` are read for whichever viewport applies.
21
30
  */
22
- /** Sizing for one viewport. Desktop only: the page is full-screen on mobile. */
23
31
  interface ViewportCustomisations {
24
32
  /** Clamped to a 2rem maximum. */
25
33
  borderRadius?: string;
@@ -37,7 +45,10 @@ interface Customisations {
37
45
  desktop?: ViewportCustomisations;
38
46
  /**
39
47
  * Which header the customer gets, not whether there is one. `true` hides the
40
- * page's own; `false` keeps it, and it carries Close and End chat.
48
+ * page's own; `false` keeps it, and with it the page's way out of a
49
+ * conversation. Ending and minimising are what that header is for, and which
50
+ * controls it offers depends on the subscriber's configuration, so hiding it
51
+ * leaves the customer no way to end or minimise unless the host supplies one.
41
52
  *
42
53
  * What replaces a hidden one is the host's business, so there is no one
43
54
  * default to quote. `LorikeetWidgetView` substitutes its own header, a title
@@ -53,12 +64,17 @@ interface Customisations {
53
64
  messages?: {
54
65
  /** Shown when the widget is in an unexpectedly failed state. */
55
66
  failOver?: string;
56
- /** Shown when live chat has been switched off deliberately. */
67
+ /**
68
+ * Shown when live chat has been switched off deliberately. Reachable only
69
+ * where the live agent bridge is on for the subscriber; without it the widget
70
+ * has no unavailable state for this to label.
71
+ */
57
72
  unavailable?: string;
58
73
  /**
59
74
  * Replaces the line under "Someone is taking a look", for a conversation
60
75
  * handed to a person. Say where the reply will come from when the default
61
- * should not promise it.
76
+ * should not promise it. Shown only where the live chat experience is on,
77
+ * which is what puts the notice on screen in the first place.
62
78
  */
63
79
  escalated?: string;
64
80
  };
@@ -103,9 +119,10 @@ interface CustomisationTheme {
103
119
  /**
104
120
  * Google Fonts CSS URL declaring the `@font-face` rules for `fontFamily`.
105
121
  * The page ships Inter only, so a brand font the device lacks falls back
106
- * unless its files are loaded. Host must be `fonts.googleapis.com`, path
107
- * `/css` or `/css2`, and only `family` and `display` params; anything else is
108
- * ignored.
122
+ * unless its files are loaded. Must be https, host `fonts.googleapis.com`,
123
+ * path `/css` or `/css2`, and carry `family` plus at most a standard
124
+ * `display`. A URL failing any of that is dropped whole rather than trimmed,
125
+ * so one stray query param means no font loads at all.
109
126
  */
110
127
  fontUrl?: string;
111
128
  /**
@@ -130,14 +147,15 @@ interface CustomisationTheme {
130
147
  * Names follow the web SDK's (`LorikeetEvent` in `@lorikeetai/web-sdk/types`)
131
148
  * wherever it has one, because a host that integrates both should not have to
132
149
  * learn two vocabularies. The rest cover what the page tells a host that owns
133
- * its own layout and storage, which on web the SDK handles internally and never
134
- * surfaces: the close handshake, the persistence messages, the logout
135
- * confirmation, and error codes. `logout_failed` is the one the SDK reports
136
- * itself, for a page that said nothing when it had to.
150
+ * its own layout and storage, which the web SDK largely handles for itself: it
151
+ * surfaces a close without its reason, a created ticket without the stored pair
152
+ * behind it, and `EXPIRED_TOKEN` alone of the error codes. `logout_failed` is
153
+ * the one the SDK reports itself, for a page that said nothing when it had to.
137
154
  *
138
- * `token_expiry` is deliberately absent. The credential model it belongs to is
139
- * being rewritten, and an event is the hardest thing to take back. Nothing
140
- * carrying a credential is translated at all, for the same reason.
155
+ * `token_expiry` is deliberately absent, and the anonymous session token with
156
+ * it. The credential model they belong to is being rewritten, and an event is
157
+ * the hardest thing to take back. `persist_session` is translated despite
158
+ * carrying a credential, because a resume cannot be rebuilt without it.
141
159
  */
142
160
  type LorikeetWidgetEvent =
143
161
  /** The page is up and the conversation is usable. */
@@ -146,7 +164,8 @@ type LorikeetWidgetEvent =
146
164
  } |
147
165
  /**
148
166
  * A ticket that did not exist before this page loaded. Once per ticket, and
149
- * never for a resume, matching the web SDK.
167
+ * never for a resume. The web SDK suppresses a resume too, but counts once
168
+ * per session rather than per ticket, so this is the stricter of the two.
150
169
  */
151
170
  {
152
171
  type: 'ticket_created';
@@ -170,12 +189,18 @@ type LorikeetWidgetEvent =
170
189
  markUnread?: boolean;
171
190
  } |
172
191
  /**
173
- * The page closed itself, and why. `ended_by_customer` is followed by a
174
- * `new_chat`, seconds later, so a host that tears down here never sees the
175
- * rest of the handshake. `minimised` has nothing behind it: the conversation
176
- * is intact and hiding it is enough.
192
+ * The page closed itself, and why. `ended_by_customer` is usually followed by
193
+ * a `new_chat`, once the end and any CSAT have settled, so a host that tears
194
+ * down here never sees the rest of the handshake. Usually rather than always:
195
+ * a CSAT rating that fails holds the replacement back, and nothing but another
196
+ * close releases it. `minimised` has nothing behind it: the conversation is
197
+ * intact and hiding it is enough.
177
198
  *
178
- * `reason` is absent from a page older than the release that added it.
199
+ * `reason` is absent from a page older than the release that added it, from one
200
+ * whose host lifecycle events are switched off, and from the closes the page
201
+ * makes on its own behalf, its error boundary among them. An absent reason
202
+ * reads as an end, so a minimise is only distinguishable when the page names
203
+ * it.
179
204
  */
180
205
  {
181
206
  type: 'close';
@@ -186,6 +211,9 @@ type LorikeetWidgetEvent =
186
211
  * or it timed out. Nothing follows, and nothing is asking the host to hide
187
212
  * anything. Left unhandled, this is the customer stranded on a conversation
188
213
  * that can no longer be used.
214
+ *
215
+ * Reported only by a page whose host lifecycle events are on, so it is not
216
+ * the only way an ended conversation can reach a host.
189
217
  */
190
218
  {
191
219
  type: 'conversation_ended';
@@ -199,13 +227,16 @@ type LorikeetWidgetEvent =
199
227
  } |
200
228
  /**
201
229
  * Store this against the customer, alongside the session. A resume needs both:
202
- * the ticket alone fails with `CUSTOMER_ID_MISSING`.
230
+ * the ticket alone is refused, usually as `CUSTOMER_ID_MISSING`.
203
231
  */
204
232
  {
205
233
  type: 'persist_ticket_id';
206
234
  ticketId: string;
207
235
  } |
208
- /** The other half of the stored pair. Arrives separately and in no order. */
236
+ /**
237
+ * The other half of the stored pair, as its own message. The SDK does not rely
238
+ * on which half arrives first, and neither should a host.
239
+ */
209
240
  {
210
241
  type: 'persist_session';
211
242
  session: string;
@@ -297,10 +328,16 @@ type LorikeetWidgetWebViewProps = {
297
328
  /**
298
329
  * What the page reported, as typed events rather than raw bridge messages.
299
330
  *
300
- * This component reports; it does not act. A host composing it owns its own
301
- * URL, layout and storage, so hiding on a close, rebuilding a resume URL or
302
- * recovering from process loss are all theirs to do. `LorikeetWidgetView`
303
- * consumes this same path and acts on top of it, because it owns the URL.
331
+ * This component acts on navigation alone; about the conversation it does
332
+ * nothing. A top-level navigation leaving the widget's origin goes to the OS,
333
+ * unless your own `webviewProps.onShouldStartLoadWithRequest` returns `false`
334
+ * for it, which is taken as a decision and not second-guessed. A navigation
335
+ * the WebView reports as a subframe stays in the page, since a frame the page
336
+ * embedded is not a link the customer followed. A host
337
+ * composing it owns its own URL, layout and storage, so hiding on a close,
338
+ * rebuilding a resume URL or recovering from process loss are all theirs to
339
+ * do. `LorikeetWidgetView` consumes this same path and acts on top of it,
340
+ * because it owns the URL.
304
341
  */
305
342
  onEvent?: (event: LorikeetWidgetEvent) => void;
306
343
  };
@@ -339,17 +376,27 @@ type LorikeetWidgetHandle = {
339
376
  * host holding what it passed at mount can be holding a conversation that no
340
377
  * longer exists.
341
378
  *
342
- * `null` means exactly that the widget has nothing to resume: no conversation
343
- * reported yet, only half of one, the credentials have moved on, or the
344
- * customer has been logged out. It does not mean the conversation is over. A
345
- * conversation the customer ended is still reported, because that is still
346
- * what the widget is on and what its own recovery would resume; `close` and
347
- * its `reason` are how you hear that it ended.
379
+ * The ticket is the half that decides. `null` means no ticket has been
380
+ * reported for these credentials: none yet, a session on its own, the
381
+ * credentials have moved on, or the customer has been logged out. It does not
382
+ * mean the conversation is over. A conversation the customer ended is still
383
+ * reported, because that is still what the widget is on and what its own
384
+ * recovery would resume; `close` and its `reason` are how you hear that it
385
+ * ended.
386
+ *
387
+ * A reported ticket with no `session` yet is not `null`, and is also not
388
+ * resumable on its own: the ticket route needs both. Treat `session` as
389
+ * outstanding rather than absent until it arrives.
348
390
  *
349
- * Reports what is on screen, so inside an `onEvent` handler it is still what
350
- * was on screen before that event: read `reason` on the `close` rather than
351
- * calling this from the handler. Read it again after a change rather than
352
- * caching what it said.
391
+ * Reads live, so inside an `onEvent` handler for `persist_ticket_id` or
392
+ * `persist_session` it has already taken that event into account. What it will
393
+ * not do is answer before a ticket exists, and the page normally sends the
394
+ * session first, so the `persist_session` handler sees `null`. Store each half
395
+ * from its own event rather than asking here.
396
+ *
397
+ * `minimised` moves with a render instead, so inside a `close` handler it
398
+ * describes what was on screen before: read `reason` on the `close` rather
399
+ * than this. Read it again after a change rather than caching what it said.
353
400
  */
354
401
  getConversation: () => {
355
402
  minimised: boolean;
@@ -442,14 +489,15 @@ type LorikeetWidgetViewProps = {
442
489
  * Resume this conversation instead of starting a new one. Without it the
443
490
  * widget boots `/widget`, which mints a fresh ticket on every mount.
444
491
  *
445
- * Take it from the `persistLorikeetTicketId` message and store it yourself;
446
- * the SDK has no storage of its own.
492
+ * Take it from the `persist_ticket_id` event, or from `getConversation()`, and
493
+ * store it yourself; the SDK has no storage of its own.
447
494
  */
448
495
  ticketId?: string;
449
496
  /**
450
- * The session token last reported by `persistLorikeetSession`, stored
451
- * alongside `ticketId`. The ticket route needs it to authorise a WebView that
452
- * has no cookie yet, so a resume without it fails with CUSTOMER_ID_MISSING.
497
+ * The session token last reported by `persist_session`, stored alongside
498
+ * `ticketId`. The ticket route needs it to authorise a WebView that has no
499
+ * cookie yet, so a resume without it is refused, usually as
500
+ * CUSTOMER_ID_MISSING.
453
501
  */
454
502
  session?: string;
455
503
  /**
@@ -501,9 +549,14 @@ declare class LorikeetClient {
501
549
  //#endregion
502
550
  //#region src/errors.d.ts
503
551
  /**
504
- * Codes the chat page posts to the host as `{ type: 'error', error: CODE }`.
505
- * Mirrored here because the page publishes them nowhere else, so a host would
506
- * otherwise be matching on strings it discovered by observation.
552
+ * The chat page's error vocabulary, as it reaches a host in
553
+ * `{ type: 'error', error: CODE }`. Mirrored here because the page publishes it
554
+ * nowhere else, so a host would otherwise be matching on strings it discovered
555
+ * by observation.
556
+ *
557
+ * The page's own list rather than a list of codes seen in the wild:
558
+ * `MISSING_PUBLIC_KEY` has no producer today, and is kept because narrowing this
559
+ * would be a breaking change.
507
560
  */
508
561
  declare const LORIKEET_ERROR_CODES: readonly ["MISSING_TOKEN", "CORRUPT_TOKEN_DATA", "DECRYPT_FAILED", "EXPIRED_TOKEN", "MALFORMED_TOKEN", "MISSING_PUBLIC_KEY", "UNKNOWN_PUBLIC_KEY", "CUSTOMER_ID_CONFLICT", "CUSTOMER_ID_MISSING", "FATAL_ERROR", "INVALID_SESSION", "DOMAIN_NOT_ALLOWED", "TICKET_NOT_FOUND"];
509
562
  type LorikeetErrorCode = (typeof LORIKEET_ERROR_CODES)[number];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/conversation-metadata.ts","../src/customisations.ts","../src/events.ts","../src/types.ts","../src/widget.tsx","../src/client.ts","../src/errors.ts","../src/lifecycle.ts"],"mappings":";;;KAEY,uBAAuB;;;;;;;;;;;;;;;;;;;UCezB;;EAER;EACA;;EAEA;;EAEA;EACA;;UAGe;;EAEf;EACA;EACA,UAAU;;;;;;;;;;;;EAYV;;EAEA;EACA;EACA;;IAEE;;IAEA;;;;;;IAMA;;EAEF,SAAS;EACT;;;;;;;EAOA;IACE;IACA;IACA;IACA;IACA;;IAEA;;;EAGF;EACA,QAAQ;EACR;;EAEA;;UAGe;;;;;;EAMf;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;;;EAQA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;KCxGU;;;EAEN;;;;;;;EAKA;EAAwB;;;;EAExB;;;;;;;;;;;;EAUA;EAAuB;;;;;;;;;;;EASvB;EAAe;;;;;;;;;EAOf;;;;;;;EAKA;;;;;;;EAKA;EAA2B;;;;EAE3B;EAAyB;;;;;;;;;;;;;;;;EAczB;;;;;;;;;;;;EAUA;;;;EAEA;EAAe;;;;;;;;;;;;;EAYf;EACA;EACA;;;KAIM;;;UCnGK;;;;EAIf;;;;EAIA,iBAAiB;;;;;EAKjB,WAAW;;;;EAIX;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA,eAAe;;;;;;;;;EASf,WAAW,OAAO;;KAGR;;;;EAIV;;;;EAIA,QAAQ,UAAU;;;;EAIlB,OAAO,MAAM;;;;EAIb;;;;;;;KAQU;;;;;;;;;;;;;;;;;;;;;;;;EAwBV;IACE;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BF;;;;;;;;;;;;;EAaA;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA;;;;;;;;;;;;;EAaA,oBAAoB,OAAO;;;;;EAK3B,WAAW,OAAO;;;;EAIlB,iBAAiB;;;;EAIjB;IACE,SAAS,UAAU;;;;;;;;;EASrB;;;;;;EAMA;;;;;;EAMA,WAAW;;;;;;;EAOX,eAAe;;;;cC3HJ,uCAAqB,0BAAA,6CAAA,cAAA;cA2HrB,yBAAwB,OAAA,OAAA,MAAA,eAKlC,8CAAyB,IAAA;cAYf,oCAAkB,0BAAA,0CAAA,cAAA;;;cCjOlB;EACX;EACA,gBAAgB;EAChB,UAAU;EACV;EAEY,cACV,gBACA,UACA,UACA,cACC;EAeH,kBAAiB,gBAAA,eAAA,OAAA,WAAA;IAOf;IACA;IACA;IACA;IACA;;;;;;;;;;;;EAmDF;;;;;;;;;cCxFW;KAgBD,4BAA4B;;iBAexB,2BAA2B;iBAK3B,uBAAuB;;;;;;;;;;;;;;cCjB1B"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/conversation-metadata.ts","../src/customisations.ts","../src/events.ts","../src/types.ts","../src/widget.tsx","../src/client.ts","../src/errors.ts","../src/lifecycle.ts"],"mappings":";;;KAEY,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;UCuBzB;;EAER;EACA;;EAEA;;EAEA;EACA;;UAGe;;EAEf;EACA;EACA,UAAU;;;;;;;;;;;;;;;EAeV;;EAEA;EACA;EACA;;IAEE;;;;;;IAMA;;;;;;;IAOA;;EAEF,SAAS;EACT;;;;;;;EAOA;IACE;IACA;IACA;IACA;IACA;;IAEA;;;EAGF;EACA,QAAQ;EACR;;EAEA;;UAGe;;;;;;EAMf;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;;;;EASA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;;KCxHU;;;EAEN;;;;;;;;EAMA;EAAwB;;;;EAExB;;;;;;;;;;;;EAUA;EAAuB;;;;;;;;;;;;;;;;;EAevB;EAAe;;;;;;;;;;;;EAUf;;;;;;;EAKA;;;;;;;EAKA;EAA2B;;;;;;;EAK3B;EAAyB;;;;;;;;;;;;;;;;EAczB;;;;;;;;;;;;EAUA;;;;EAEA;EAAe;;;;;;;;;;;;;EAYf;EACA;EACA;;;KAIM;;;UCjHK;;;;EAIf;;;;EAIA,iBAAiB;;;;;EAKjB,WAAW;;;;EAIX;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA,eAAe;;;;;;;;;;;;;;;EAef,WAAW,OAAO;;KAGR;;;;EAIV;;;;EAIA,QAAQ,UAAU;;;;EAIlB,OAAO,MAAM;;;;EAIb;;;;;;;KAQU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCV;IACE;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BF;;;;;;;;;;;;;EAaA;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA;;;;;;;;;;;;;EAaA,oBAAoB,OAAO;;;;;EAK3B,WAAW,OAAO;;;;EAIlB,iBAAiB;;;;EAIjB;IACE,SAAS,UAAU;;;;;;;;;EASrB;;;;;;;EAOA;;;;;;EAMA,WAAW;;;;;;;EAOX,eAAe;;;;cC5IJ,uCAAqB,0BAAA,6CAAA,cAAA;cA2HrB,yBAAwB,OAAA,OAAA,MAAA,eAKlC,8CAAyB,IAAA;cAYf,oCAAkB,0BAAA,0CAAA,cAAA;;;cCjOlB;EACX;EACA,gBAAgB;EAChB,UAAU;EACV;EAEY,cACV,gBACA,UACA,UACA,cACC;EAeH,kBAAiB,gBAAA,eAAA,OAAA,WAAA;IAOf;IACA;IACA;IACA;IACA;;;;;;;;;;;;EAmDF;;;;;;;;;;;;;;cCnFW;KAgBD,4BAA4B;;iBAexB,2BAA2B;iBAK3B,uBAAuB;;;;;;;;;;;;;;cCtB1B"}
package/dist/index.d.ts CHANGED
@@ -13,13 +13,21 @@ type ConversationMetadata = Record<string, unknown>;
13
13
  * have: `Customisations` then degraded to `any` and typed nothing.
14
14
  * `ConversationMetadata` is duplicated here for the same reason.
15
15
  *
16
- * `src/customisations.web-sdk-parity.ts` fails the build if the two drift.
16
+ * `src/customisations.web-sdk-parity.ts` fails `typecheck` if the two drift. Not
17
+ * the build: that file is unreachable from `index.ts`, so the declaration build
18
+ * never sees it.
17
19
  *
18
- * Fields that only mean something on a web page, the viewport sizes and the
19
- * launcher button, are kept so the page's behaviour is unchanged and so a host
20
- * sharing one configuration object with its web widget still type-checks.
20
+ * Fields that only mean something on a web page are kept so the page's behaviour
21
+ * is unchanged and so a host sharing one configuration object with its web
22
+ * widget still type-checks. The viewport sizes, the launcher button and `mode`
23
+ * are all read by the web SDK rather than by the page, so none of them reaches
24
+ * anything this SDK renders.
25
+ */
26
+ /**
27
+ * Sizing for one viewport. Mostly desktop: the page is full-screen on mobile, so
28
+ * `height`, `width` and `borderRadius` are read for `desktop` alone, while
29
+ * `topClearance` and `default_open` are read for whichever viewport applies.
21
30
  */
22
- /** Sizing for one viewport. Desktop only: the page is full-screen on mobile. */
23
31
  interface ViewportCustomisations {
24
32
  /** Clamped to a 2rem maximum. */
25
33
  borderRadius?: string;
@@ -37,7 +45,10 @@ interface Customisations {
37
45
  desktop?: ViewportCustomisations;
38
46
  /**
39
47
  * Which header the customer gets, not whether there is one. `true` hides the
40
- * page's own; `false` keeps it, and it carries Close and End chat.
48
+ * page's own; `false` keeps it, and with it the page's way out of a
49
+ * conversation. Ending and minimising are what that header is for, and which
50
+ * controls it offers depends on the subscriber's configuration, so hiding it
51
+ * leaves the customer no way to end or minimise unless the host supplies one.
41
52
  *
42
53
  * What replaces a hidden one is the host's business, so there is no one
43
54
  * default to quote. `LorikeetWidgetView` substitutes its own header, a title
@@ -53,12 +64,17 @@ interface Customisations {
53
64
  messages?: {
54
65
  /** Shown when the widget is in an unexpectedly failed state. */
55
66
  failOver?: string;
56
- /** Shown when live chat has been switched off deliberately. */
67
+ /**
68
+ * Shown when live chat has been switched off deliberately. Reachable only
69
+ * where the live agent bridge is on for the subscriber; without it the widget
70
+ * has no unavailable state for this to label.
71
+ */
57
72
  unavailable?: string;
58
73
  /**
59
74
  * Replaces the line under "Someone is taking a look", for a conversation
60
75
  * handed to a person. Say where the reply will come from when the default
61
- * should not promise it.
76
+ * should not promise it. Shown only where the live chat experience is on,
77
+ * which is what puts the notice on screen in the first place.
62
78
  */
63
79
  escalated?: string;
64
80
  };
@@ -103,9 +119,10 @@ interface CustomisationTheme {
103
119
  /**
104
120
  * Google Fonts CSS URL declaring the `@font-face` rules for `fontFamily`.
105
121
  * The page ships Inter only, so a brand font the device lacks falls back
106
- * unless its files are loaded. Host must be `fonts.googleapis.com`, path
107
- * `/css` or `/css2`, and only `family` and `display` params; anything else is
108
- * ignored.
122
+ * unless its files are loaded. Must be https, host `fonts.googleapis.com`,
123
+ * path `/css` or `/css2`, and carry `family` plus at most a standard
124
+ * `display`. A URL failing any of that is dropped whole rather than trimmed,
125
+ * so one stray query param means no font loads at all.
109
126
  */
110
127
  fontUrl?: string;
111
128
  /**
@@ -130,14 +147,15 @@ interface CustomisationTheme {
130
147
  * Names follow the web SDK's (`LorikeetEvent` in `@lorikeetai/web-sdk/types`)
131
148
  * wherever it has one, because a host that integrates both should not have to
132
149
  * learn two vocabularies. The rest cover what the page tells a host that owns
133
- * its own layout and storage, which on web the SDK handles internally and never
134
- * surfaces: the close handshake, the persistence messages, the logout
135
- * confirmation, and error codes. `logout_failed` is the one the SDK reports
136
- * itself, for a page that said nothing when it had to.
150
+ * its own layout and storage, which the web SDK largely handles for itself: it
151
+ * surfaces a close without its reason, a created ticket without the stored pair
152
+ * behind it, and `EXPIRED_TOKEN` alone of the error codes. `logout_failed` is
153
+ * the one the SDK reports itself, for a page that said nothing when it had to.
137
154
  *
138
- * `token_expiry` is deliberately absent. The credential model it belongs to is
139
- * being rewritten, and an event is the hardest thing to take back. Nothing
140
- * carrying a credential is translated at all, for the same reason.
155
+ * `token_expiry` is deliberately absent, and the anonymous session token with
156
+ * it. The credential model they belong to is being rewritten, and an event is
157
+ * the hardest thing to take back. `persist_session` is translated despite
158
+ * carrying a credential, because a resume cannot be rebuilt without it.
141
159
  */
142
160
  type LorikeetWidgetEvent =
143
161
  /** The page is up and the conversation is usable. */
@@ -146,7 +164,8 @@ type LorikeetWidgetEvent =
146
164
  } |
147
165
  /**
148
166
  * A ticket that did not exist before this page loaded. Once per ticket, and
149
- * never for a resume, matching the web SDK.
167
+ * never for a resume. The web SDK suppresses a resume too, but counts once
168
+ * per session rather than per ticket, so this is the stricter of the two.
150
169
  */
151
170
  {
152
171
  type: 'ticket_created';
@@ -170,12 +189,18 @@ type LorikeetWidgetEvent =
170
189
  markUnread?: boolean;
171
190
  } |
172
191
  /**
173
- * The page closed itself, and why. `ended_by_customer` is followed by a
174
- * `new_chat`, seconds later, so a host that tears down here never sees the
175
- * rest of the handshake. `minimised` has nothing behind it: the conversation
176
- * is intact and hiding it is enough.
192
+ * The page closed itself, and why. `ended_by_customer` is usually followed by
193
+ * a `new_chat`, once the end and any CSAT have settled, so a host that tears
194
+ * down here never sees the rest of the handshake. Usually rather than always:
195
+ * a CSAT rating that fails holds the replacement back, and nothing but another
196
+ * close releases it. `minimised` has nothing behind it: the conversation is
197
+ * intact and hiding it is enough.
177
198
  *
178
- * `reason` is absent from a page older than the release that added it.
199
+ * `reason` is absent from a page older than the release that added it, from one
200
+ * whose host lifecycle events are switched off, and from the closes the page
201
+ * makes on its own behalf, its error boundary among them. An absent reason
202
+ * reads as an end, so a minimise is only distinguishable when the page names
203
+ * it.
179
204
  */
180
205
  {
181
206
  type: 'close';
@@ -186,6 +211,9 @@ type LorikeetWidgetEvent =
186
211
  * or it timed out. Nothing follows, and nothing is asking the host to hide
187
212
  * anything. Left unhandled, this is the customer stranded on a conversation
188
213
  * that can no longer be used.
214
+ *
215
+ * Reported only by a page whose host lifecycle events are on, so it is not
216
+ * the only way an ended conversation can reach a host.
189
217
  */
190
218
  {
191
219
  type: 'conversation_ended';
@@ -199,13 +227,16 @@ type LorikeetWidgetEvent =
199
227
  } |
200
228
  /**
201
229
  * Store this against the customer, alongside the session. A resume needs both:
202
- * the ticket alone fails with `CUSTOMER_ID_MISSING`.
230
+ * the ticket alone is refused, usually as `CUSTOMER_ID_MISSING`.
203
231
  */
204
232
  {
205
233
  type: 'persist_ticket_id';
206
234
  ticketId: string;
207
235
  } |
208
- /** The other half of the stored pair. Arrives separately and in no order. */
236
+ /**
237
+ * The other half of the stored pair, as its own message. The SDK does not rely
238
+ * on which half arrives first, and neither should a host.
239
+ */
209
240
  {
210
241
  type: 'persist_session';
211
242
  session: string;
@@ -297,10 +328,16 @@ type LorikeetWidgetWebViewProps = {
297
328
  /**
298
329
  * What the page reported, as typed events rather than raw bridge messages.
299
330
  *
300
- * This component reports; it does not act. A host composing it owns its own
301
- * URL, layout and storage, so hiding on a close, rebuilding a resume URL or
302
- * recovering from process loss are all theirs to do. `LorikeetWidgetView`
303
- * consumes this same path and acts on top of it, because it owns the URL.
331
+ * This component acts on navigation alone; about the conversation it does
332
+ * nothing. A top-level navigation leaving the widget's origin goes to the OS,
333
+ * unless your own `webviewProps.onShouldStartLoadWithRequest` returns `false`
334
+ * for it, which is taken as a decision and not second-guessed. A navigation
335
+ * the WebView reports as a subframe stays in the page, since a frame the page
336
+ * embedded is not a link the customer followed. A host
337
+ * composing it owns its own URL, layout and storage, so hiding on a close,
338
+ * rebuilding a resume URL or recovering from process loss are all theirs to
339
+ * do. `LorikeetWidgetView` consumes this same path and acts on top of it,
340
+ * because it owns the URL.
304
341
  */
305
342
  onEvent?: (event: LorikeetWidgetEvent) => void;
306
343
  };
@@ -339,17 +376,27 @@ type LorikeetWidgetHandle = {
339
376
  * host holding what it passed at mount can be holding a conversation that no
340
377
  * longer exists.
341
378
  *
342
- * `null` means exactly that the widget has nothing to resume: no conversation
343
- * reported yet, only half of one, the credentials have moved on, or the
344
- * customer has been logged out. It does not mean the conversation is over. A
345
- * conversation the customer ended is still reported, because that is still
346
- * what the widget is on and what its own recovery would resume; `close` and
347
- * its `reason` are how you hear that it ended.
379
+ * The ticket is the half that decides. `null` means no ticket has been
380
+ * reported for these credentials: none yet, a session on its own, the
381
+ * credentials have moved on, or the customer has been logged out. It does not
382
+ * mean the conversation is over. A conversation the customer ended is still
383
+ * reported, because that is still what the widget is on and what its own
384
+ * recovery would resume; `close` and its `reason` are how you hear that it
385
+ * ended.
386
+ *
387
+ * A reported ticket with no `session` yet is not `null`, and is also not
388
+ * resumable on its own: the ticket route needs both. Treat `session` as
389
+ * outstanding rather than absent until it arrives.
348
390
  *
349
- * Reports what is on screen, so inside an `onEvent` handler it is still what
350
- * was on screen before that event: read `reason` on the `close` rather than
351
- * calling this from the handler. Read it again after a change rather than
352
- * caching what it said.
391
+ * Reads live, so inside an `onEvent` handler for `persist_ticket_id` or
392
+ * `persist_session` it has already taken that event into account. What it will
393
+ * not do is answer before a ticket exists, and the page normally sends the
394
+ * session first, so the `persist_session` handler sees `null`. Store each half
395
+ * from its own event rather than asking here.
396
+ *
397
+ * `minimised` moves with a render instead, so inside a `close` handler it
398
+ * describes what was on screen before: read `reason` on the `close` rather
399
+ * than this. Read it again after a change rather than caching what it said.
353
400
  */
354
401
  getConversation: () => {
355
402
  minimised: boolean;
@@ -442,14 +489,15 @@ type LorikeetWidgetViewProps = {
442
489
  * Resume this conversation instead of starting a new one. Without it the
443
490
  * widget boots `/widget`, which mints a fresh ticket on every mount.
444
491
  *
445
- * Take it from the `persistLorikeetTicketId` message and store it yourself;
446
- * the SDK has no storage of its own.
492
+ * Take it from the `persist_ticket_id` event, or from `getConversation()`, and
493
+ * store it yourself; the SDK has no storage of its own.
447
494
  */
448
495
  ticketId?: string;
449
496
  /**
450
- * The session token last reported by `persistLorikeetSession`, stored
451
- * alongside `ticketId`. The ticket route needs it to authorise a WebView that
452
- * has no cookie yet, so a resume without it fails with CUSTOMER_ID_MISSING.
497
+ * The session token last reported by `persist_session`, stored alongside
498
+ * `ticketId`. The ticket route needs it to authorise a WebView that has no
499
+ * cookie yet, so a resume without it is refused, usually as
500
+ * CUSTOMER_ID_MISSING.
453
501
  */
454
502
  session?: string;
455
503
  /**
@@ -501,9 +549,14 @@ declare class LorikeetClient {
501
549
  //#endregion
502
550
  //#region src/errors.d.ts
503
551
  /**
504
- * Codes the chat page posts to the host as `{ type: 'error', error: CODE }`.
505
- * Mirrored here because the page publishes them nowhere else, so a host would
506
- * otherwise be matching on strings it discovered by observation.
552
+ * The chat page's error vocabulary, as it reaches a host in
553
+ * `{ type: 'error', error: CODE }`. Mirrored here because the page publishes it
554
+ * nowhere else, so a host would otherwise be matching on strings it discovered
555
+ * by observation.
556
+ *
557
+ * The page's own list rather than a list of codes seen in the wild:
558
+ * `MISSING_PUBLIC_KEY` has no producer today, and is kept because narrowing this
559
+ * would be a breaking change.
507
560
  */
508
561
  declare const LORIKEET_ERROR_CODES: readonly ["MISSING_TOKEN", "CORRUPT_TOKEN_DATA", "DECRYPT_FAILED", "EXPIRED_TOKEN", "MALFORMED_TOKEN", "MISSING_PUBLIC_KEY", "UNKNOWN_PUBLIC_KEY", "CUSTOMER_ID_CONFLICT", "CUSTOMER_ID_MISSING", "FATAL_ERROR", "INVALID_SESSION", "DOMAIN_NOT_ALLOWED", "TICKET_NOT_FOUND"];
509
562
  type LorikeetErrorCode = (typeof LORIKEET_ERROR_CODES)[number];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/conversation-metadata.ts","../src/customisations.ts","../src/events.ts","../src/types.ts","../src/widget.tsx","../src/client.ts","../src/errors.ts","../src/lifecycle.ts"],"mappings":";;;KAEY,uBAAuB;;;;;;;;;;;;;;;;;;;UCezB;;EAER;EACA;;EAEA;;EAEA;EACA;;UAGe;;EAEf;EACA;EACA,UAAU;;;;;;;;;;;;EAYV;;EAEA;EACA;EACA;;IAEE;;IAEA;;;;;;IAMA;;EAEF,SAAS;EACT;;;;;;;EAOA;IACE;IACA;IACA;IACA;IACA;;IAEA;;;EAGF;EACA,QAAQ;EACR;;EAEA;;UAGe;;;;;;EAMf;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;;;EAQA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;KCxGU;;;EAEN;;;;;;;EAKA;EAAwB;;;;EAExB;;;;;;;;;;;;EAUA;EAAuB;;;;;;;;;;;EASvB;EAAe;;;;;;;;;EAOf;;;;;;;EAKA;;;;;;;EAKA;EAA2B;;;;EAE3B;EAAyB;;;;;;;;;;;;;;;;EAczB;;;;;;;;;;;;EAUA;;;;EAEA;EAAe;;;;;;;;;;;;;EAYf;EACA;EACA;;;KAIM;;;UCnGK;;;;EAIf;;;;EAIA,iBAAiB;;;;;EAKjB,WAAW;;;;EAIX;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA,eAAe;;;;;;;;;EASf,WAAW,OAAO;;KAGR;;;;EAIV;;;;EAIA,QAAQ,UAAU;;;;EAIlB,OAAO,MAAM;;;;EAIb;;;;;;;KAQU;;;;;;;;;;;;;;;;;;;;;;;;EAwBV;IACE;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BF;;;;;;;;;;;;;EAaA;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA;;;;;;;;;;;;;EAaA,oBAAoB,OAAO;;;;;EAK3B,WAAW,OAAO;;;;EAIlB,iBAAiB;;;;EAIjB;IACE,SAAS,UAAU;;;;;;;;;EASrB;;;;;;EAMA;;;;;;EAMA,WAAW;;;;;;;EAOX,eAAe;;;;cC3HJ,uCAAqB,0BAAA,6CAAA,cAAA;cA2HrB,yBAAwB,OAAA,OAAA,MAAA,eAKlC,8CAAyB,IAAA;cAYf,oCAAkB,0BAAA,0CAAA,cAAA;;;cCjOlB;EACX;EACA,gBAAgB;EAChB,UAAU;EACV;EAEY,cACV,gBACA,UACA,UACA,cACC;EAeH,kBAAiB,gBAAA,eAAA,OAAA,WAAA;IAOf;IACA;IACA;IACA;IACA;;;;;;;;;;;;EAmDF;;;;;;;;;cCxFW;KAgBD,4BAA4B;;iBAexB,2BAA2B;iBAK3B,uBAAuB;;;;;;;;;;;;;;cCjB1B"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/conversation-metadata.ts","../src/customisations.ts","../src/events.ts","../src/types.ts","../src/widget.tsx","../src/client.ts","../src/errors.ts","../src/lifecycle.ts"],"mappings":";;;KAEY,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;UCuBzB;;EAER;EACA;;EAEA;;EAEA;EACA;;UAGe;;EAEf;EACA;EACA,UAAU;;;;;;;;;;;;;;;EAeV;;EAEA;EACA;EACA;;IAEE;;;;;;IAMA;;;;;;;IAOA;;EAEF,SAAS;EACT;;;;;;;EAOA;IACE;IACA;IACA;IACA;IACA;;IAEA;;;EAGF;EACA,QAAQ;EACR;;EAEA;;UAGe;;;;;;EAMf;EACA;;EAEA;EACA;;EAEA;EACA;;;;;;;;;EASA;;;;;EAKA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;;KCxHU;;;EAEN;;;;;;;;EAMA;EAAwB;;;;EAExB;;;;;;;;;;;;EAUA;EAAuB;;;;;;;;;;;;;;;;;EAevB;EAAe;;;;;;;;;;;;EAUf;;;;;;;EAKA;;;;;;;EAKA;EAA2B;;;;;;;EAK3B;EAAyB;;;;;;;;;;;;;;;;EAczB;;;;;;;;;;;;EAUA;;;;EAEA;EAAe;;;;;;;;;;;;;EAYf;EACA;EACA;;;KAIM;;;UCjHK;;;;EAIf;;;;EAIA,iBAAiB;;;;;EAKjB,WAAW;;;;EAIX;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA,eAAe;;;;;;;;;;;;;;;EAef,WAAW,OAAO;;KAGR;;;;EAIV;;;;EAIA,QAAQ,UAAU;;;;EAIlB,OAAO,MAAM;;;;EAIb;;;;;;;KAQU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCV;IACE;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BF;;;;;;;;;;;;;EAaA;;KAGU;;;;EAIV;;;;EAIA;;;;EAIA;;;;;;;;;;;;;EAaA,oBAAoB,OAAO;;;;;EAK3B,WAAW,OAAO;;;;EAIlB,iBAAiB;;;;EAIjB;IACE,SAAS,UAAU;;;;;;;;;EASrB;;;;;;;EAOA;;;;;;EAMA,WAAW;;;;;;;EAOX,eAAe;;;;cC5IJ,uCAAqB,0BAAA,6CAAA,cAAA;cA2HrB,yBAAwB,OAAA,OAAA,MAAA,eAKlC,8CAAyB,IAAA;cAYf,oCAAkB,0BAAA,0CAAA,cAAA;;;cCjOlB;EACX;EACA,gBAAgB;EAChB,UAAU;EACV;EAEY,cACV,gBACA,UACA,UACA,cACC;EAeH,kBAAiB,gBAAA,eAAA,OAAA,WAAA;IAOf;IACA;IACA;IACA;IACA;;;;;;;;;;;;EAmDF;;;;;;;;;;;;;;cCnFW;KAgBD,4BAA4B;;iBAexB,2BAA2B;iBAK3B,uBAAuB;;;;;;;;;;;;;;cCtB1B"}
package/dist/index.js CHANGED
@@ -145,9 +145,14 @@ var LorikeetClient = class {
145
145
  //#endregion
146
146
  //#region src/errors.ts
147
147
  /**
148
- * Codes the chat page posts to the host as `{ type: 'error', error: CODE }`.
149
- * Mirrored here because the page publishes them nowhere else, so a host would
150
- * otherwise be matching on strings it discovered by observation.
148
+ * The chat page's error vocabulary, as it reaches a host in
149
+ * `{ type: 'error', error: CODE }`. Mirrored here because the page publishes it
150
+ * nowhere else, so a host would otherwise be matching on strings it discovered
151
+ * by observation.
152
+ *
153
+ * The page's own list rather than a list of codes seen in the wild:
154
+ * `MISSING_PUBLIC_KEY` has no producer today, and is kept because narrowing this
155
+ * would be a breaking change.
151
156
  */
152
157
  const LORIKEET_ERROR_CODES = [
153
158
  "MISSING_TOKEN",