@formio/uag-js 2.0.0-rc.6 → 2.0.0-rc.8

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
@@ -13,8 +13,34 @@ Formio.use(UAG('https://uag.example.com'));
13
13
  Formio.createForm(document.getElementById('claim'), 'https://forms.example.com/myproject/claim');
14
14
  ```
15
15
 
16
+ Without a bundler, load the UAG's own `https://uag.example.com/uag-js/uag.use.js` (and `uag-js.css`) after formio.js: it registers itself with that UAG and its modules' components. See [Or load it from the UAG](https://ai.form.io/developers/renderer#or-load-it-from-the-uag).
17
+
16
18
  Requests to the UAG carry the user's Form.io token (`x-jwt-token`), as formio.js sends it to Form.io; no other token is needed. Routing in the browser is not a security boundary: protect the fields an agent owns on the server, with an agent role, form permissions and `uagAuthoritative`.
17
19
 
20
+ ## AI Document
21
+
22
+ The **AI Document** component (`uagdocument`) is a UAG module from [`@formio/uag-extras`](https://github.com/formio/uag-extras) (`npm install @formio/uag-extras@^1`), not from this package. A UAG that uses the module adds the component to its `/uag-js/uag.use.js`; an application with a bundler registers it after this package:
23
+
24
+ ```js
25
+ import aiDocument from '@formio/uag-extras/modules/ai-document/client';
26
+ Formio.use(UAG('https://uag.example.com'));
27
+ Formio.use(aiDocument);
28
+ ```
29
+
30
+ See [AI Document](https://ai.form.io/developers/ai-document).
31
+
32
+ ## For components: `client`
33
+
34
+ Once the UAG is registered, `client` (also `Formio.uagClient`, `FormioUAG.client` and `UAG.client`) is the browser API that components of UAG modules build on, stable within a major version: the UAG's URL, the user's token and headers, a form's URL on the UAG, the installed plugins, `stream()` for module routes, and Markdown rendering.
35
+
36
+ ```js
37
+ import { client } from '@formio/uag-js';
38
+ await client.ready;
39
+ const done = await client.stream(client.formUrl(form) + '/document/process', { path, files }, { onEvent: (name, data) => {} });
40
+ ```
41
+
42
+ Every member, and how `stream()` resolves and rejects: [For module components: `client`](https://ai.form.io/developers/renderer#for-module-components-client).
43
+
18
44
  ## Chat
19
45
 
20
46
  Any form tagged `uag` can also be rendered as a chat, the way `Formio.createForm` renders it as a form. A person describes what they need; the chat asks for what is still missing and fills the form behind it, which validates and submits through the UAG once they confirm. Each turn is the form's `{form}/agent/chat` on the UAG, so there is no model code and no server of your own, and it needs no Agentic Formflow license (the UAG needs an agent engine).
@@ -22,7 +48,7 @@ Any form tagged `uag` can also be rendered as a chat, the way `Formio.createForm
22
48
  ```js
23
49
  Formio.use(UAG('https://uag.example.com'));
24
50
 
25
- const chat = await Formio.createChat(document.getElementById('help'), 'https://forms.example.com/myproject/servicerequest', {
51
+ const chat = await Formio.createChat(document.getElementById('help'), 'https://forms.example.com/myproject/service-request', {
26
52
  suggestions: ['My internet is down'],
27
53
  markdown: (text) => marked.parse(text) // optional; the output is sanitized
28
54
  });
package/index.d.ts CHANGED
@@ -189,11 +189,111 @@ export interface ChatForm {
189
189
  export interface UAGOptions extends Omit<AttachOptions, 'uagUrl' | 'formUrl'> {
190
190
  /** `false` attaches no Agent Input anywhere; submissions of `uag` forms still go to the UAG. */
191
191
  agentInput?: boolean;
192
+ /**
193
+ * Portal mode, used by the UAG's portal script: registers only the client
194
+ * and the manifest, for the modules' components. Saves are not routed, and
195
+ * neither Agent Input nor the chat is registered.
196
+ */
197
+ portal?: boolean;
198
+ /** The installed plugins, as `GET {project}/plugins` describes them. Fetched at registration when not given. */
199
+ manifest?: PluginManifestEntry[];
200
+ }
201
+
202
+ /** One installed plugin, as the UAG's manifest describes it. */
203
+ export interface PluginManifestEntry {
204
+ type: string;
205
+ name: string;
206
+ title: string;
207
+ description?: string;
208
+ version: string;
209
+ stability: 'stable' | 'experimental';
210
+ editForm?: any[];
211
+ /** Document plugins: the file types the installed converters can bring to it. */
212
+ accept?: Array<{ type: string; ext: string[]; routes: Record<string, any>; converters: string[] }>;
213
+ inputs?: Array<Array<'pdf' | 'text'>>;
214
+ editable?: boolean;
215
+ output?: 'markdown' | 'text';
216
+ defaults?: Record<string, any>;
217
+ [field: string]: any;
192
218
  }
193
219
 
220
+ /** An AI Document's stored `result`. */
221
+ export interface AIDocumentResult {
222
+ content: string;
223
+ format: 'markdown' | 'text';
224
+ status: 'ok' | 'flagged';
225
+ issues: Array<{ kind: string; message: string; output?: string; document?: string; page?: number; file?: string }>;
226
+ summary: string;
227
+ edited: boolean;
228
+ meta: { plugin: string; engine: string; model: string; files: Array<{ name: string; route: string[]; pages?: number }> };
229
+ }
230
+
231
+ /**
232
+ * Events an AI Document emits on its form: `uagDocumentStart` ({ component, path, files }),
233
+ * `uagDocumentProgress` ({ component, path, progress, message? }), `uagDocumentResult`
234
+ * ({ component, path, result }), `uagDocumentError` ({ component, path, error }).
235
+ */
236
+ export type AIDocumentEvent = 'uagDocumentStart' | 'uagDocumentProgress' | 'uagDocumentResult' | 'uagDocumentError';
237
+
238
+ /** Render Markdown as the AI Document does: headings, paragraphs, lists, tables, emphasis, code and safe links, all text escaped. */
239
+ export declare function renderMarkdown(markdown: string): string;
240
+
241
+ /** Options for `client.stream`. */
242
+ export interface ClientStreamOptions {
243
+ /** Called with every server-sent event, by name. */
244
+ onEvent?(name: string, data: any): void;
245
+ signal?: AbortSignal;
246
+ /** The rendered form, whose Form.io token identifies the user. */
247
+ form?: any;
248
+ headers?: Record<string, string>;
249
+ fetch?: typeof fetch;
250
+ }
251
+
252
+ /** An error the UAG answered with. */
253
+ export interface UAGClientError extends Error {
254
+ status?: number;
255
+ code?: string;
256
+ }
257
+
258
+ /**
259
+ * The public browser API that components of UAG modules build on, once
260
+ * `Formio.use(UAG(url))` has run. Stable within a major version.
261
+ */
262
+ export interface UAGClient {
263
+ /** The UAG's URL. */
264
+ url(): string;
265
+ /** The user's Form.io token, from the form's own formio or the SDK. */
266
+ token(form?: any): string | null;
267
+ /** The headers that identify the user to the UAG. */
268
+ headers(form?: any): Record<string, string>;
269
+ /** A form's URL on the UAG, from its definition (or a rendered form). */
270
+ formUrl(definition: any): string;
271
+ /** Resolves once the installed plugins are known. */
272
+ ready: Promise<void>;
273
+ /** Whether the installed plugins are known yet. */
274
+ readonly loaded: boolean;
275
+ /** The installed plugins, of one type or all. */
276
+ plugins(type?: string): PluginManifestEntry[];
277
+ plugin(type: string, name: string): PluginManifestEntry | null;
278
+ /** POST JSON, accepting server-sent events: resolves with the `done` event's data, or the JSON answer. */
279
+ stream(url: string, body: any, options?: ClientStreamOptions): Promise<any>;
280
+ renderMarkdown(markdown: string): string;
281
+ escapeHtml(value: unknown): string;
282
+ /** The formio.js the UAG was registered with. */
283
+ readonly Formio: any;
284
+ }
285
+
286
+ export declare const client: UAGClient;
287
+
194
288
  /** The formio.js module: `Formio.use(UAG('https://uag.example.com'))`. It also registers the `chat` display and `Formio.createChat`. */
195
289
  export declare function UAG(uagUrl: string, options?: UAGOptions): (Formio: any) => { fetch: Record<string, any>; displays?: Record<string, any> };
196
290
  export declare namespace UAG {
291
+ /** Resolves once the installed document plugins are known (embedded by the UAG's scripts, or fetched at registration). */
292
+ const ready: Promise<void>;
293
+ /** The same as `renderMarkdown`. */
294
+ function renderMarkdown(markdown: string): string;
295
+ /** The same as `client`. */
296
+ const client: UAGClient;
197
297
  /** The same as `attach`. */
198
298
  function attach(form: any, options?: AttachOptions): AgentInput;
199
299
  /** The same as `createChat`. */
@@ -227,5 +327,7 @@ declare const uag: {
227
327
  SSEParser: typeof SSEParser;
228
328
  isEmpty: typeof isEmpty;
229
329
  CHAT_TEMPLATES: typeof CHAT_TEMPLATES;
330
+ renderMarkdown: typeof renderMarkdown;
331
+ client: typeof client;
230
332
  };
231
333
  export default uag;
package/index.js CHANGED
@@ -734,7 +734,7 @@
734
734
  * The chat: a formio.js display that renders a form as a conversation.
735
735
  *
736
736
  * Formio.use(UAG('https://uag.example.com'));
737
- * Formio.createChat(element, 'https://forms.example.com/myproject/servicerequest');
737
+ * Formio.createChat(element, 'https://forms.example.com/myproject/service-request');
738
738
  *
739
739
  * Each message the person sends goes to the form's chat on the UAG
740
740
  * (`{form}/agent/chat`) with the conversation and the form's data; the
@@ -1424,6 +1424,227 @@
1424
1424
  return wrapper.setForm(src);
1425
1425
  }
1426
1426
 
1427
+
1428
+ // ---------------------------------------------------------------------
1429
+ // The installed plugins (the UAG's manifest), for the modules' components.
1430
+ // ---------------------------------------------------------------------
1431
+
1432
+ /** The installed plugins, as the UAG's manifest describes them. */
1433
+ var manifestState = { manifest: null, resolve: null, promise: null };
1434
+ manifestState.promise = new Promise(function (resolve) { manifestState.resolve = resolve; });
1435
+
1436
+ function setManifest(manifest) {
1437
+ manifestState.manifest = Array.isArray(manifest) ? manifest : [];
1438
+ manifestState.resolve();
1439
+ }
1440
+
1441
+ /** Fetch the manifest from the UAG, with the user's token. Resolves with [] when it cannot. */
1442
+ function fetchManifest(uagUrl, sdk) {
1443
+ var fetchImpl = (registered.options && registered.options.fetch) || (typeof fetch === 'function' ? fetch : null);
1444
+ if (!fetchImpl) return Promise.resolve([]);
1445
+ var headers = { Accept: 'application/json' };
1446
+ try {
1447
+ var token = sdk && typeof sdk.getToken === 'function' ? sdk.getToken() : null;
1448
+ if (token) headers['x-jwt-token'] = token;
1449
+ }
1450
+ catch (err) { /* no token */ }
1451
+ return Promise.resolve().then(function () {
1452
+ return fetchImpl(trimSlash(uagUrl) + '/plugins', { headers: headers });
1453
+ }).then(function (response) {
1454
+ return response && response.ok ? response.json() : [];
1455
+ }).catch(function () { return []; });
1456
+ }
1457
+
1458
+ // --- Markdown, as sanitizeMarkdown keeps it, rendered with every text escaped ---
1459
+
1460
+ function safeHref(href) {
1461
+ return /^(https?:|mailto:)/i.test(String(href || '').trim()) ? String(href).trim() : '';
1462
+ }
1463
+
1464
+ /** Inline Markdown: backslash escapes, code, links (safe targets only), strong, emphasis. Everything else is escaped text. */
1465
+ function inlineMarkdown(text) {
1466
+ var out = '';
1467
+ var rest = String(text || '');
1468
+ var pattern = /(`+)([^`]*?)\1|\[([^\]]*)\]\(\s*<?([^)\s>]*)>?(?:\s+"[^"]*")?\s*\)|<((?:https?:|mailto:)[^>\s]+)>|\*\*([^*]+)\*\*|__([^_]+)__|\*([^*\s][^*]*?)\*|_([^_\s][^_]*?)_|\\([!-\/:-@[-`{-~])/;
1469
+ var match;
1470
+ while ((match = pattern.exec(rest))) {
1471
+ out += escapeHtml(rest.slice(0, match.index));
1472
+ // A backslash escape (sanitizeMarkdown escapes what it shows as text): the character itself.
1473
+ if (match[10]) out += escapeHtml(match[10]);
1474
+ else if (match[1]) out += '<code>' + escapeHtml(match[2]) + '</code>';
1475
+ else if (match[3] !== undefined) {
1476
+ var href = safeHref(match[4]);
1477
+ out += href ? '<a href="' + escapeHtml(href) + '" target="_blank" rel="noopener noreferrer">' + inlineMarkdown(match[3]) + '</a>' : inlineMarkdown(match[3]);
1478
+ }
1479
+ else if (match[5]) out += '<a href="' + escapeHtml(match[5]) + '" target="_blank" rel="noopener noreferrer">' + escapeHtml(match[5]) + '</a>';
1480
+ else if (match[6] || match[7]) out += '<strong>' + inlineMarkdown(match[6] || match[7]) + '</strong>';
1481
+ else out += '<em>' + inlineMarkdown(match[8] || match[9]) + '</em>';
1482
+ rest = rest.slice(match.index + match[0].length);
1483
+ }
1484
+ return out + escapeHtml(rest);
1485
+ }
1486
+
1487
+ function tableRow(line) {
1488
+ return line.trim().replace(/^\|/, '').replace(/\|$/, '').split('|').map(function (cell) { return cell.trim(); });
1489
+ }
1490
+
1491
+ /**
1492
+ * Render Markdown to HTML: headings, paragraphs, lists, tables, emphasis,
1493
+ * code and http/https/mailto links, nothing else. All text is escaped.
1494
+ */
1495
+ function renderMarkdown(markdown) {
1496
+ var lines = String(markdown || '').replace(/\r\n?/g, '\n').split('\n');
1497
+ var html = [];
1498
+ var i = 0;
1499
+ while (i < lines.length) {
1500
+ var line = lines[i];
1501
+ var fence = /^\s{0,3}(`{3,}|~{3,})/.exec(line);
1502
+ if (fence) {
1503
+ var code = [];
1504
+ i++;
1505
+ while (i < lines.length && !(new RegExp('^\\s{0,3}' + fence[1][0] + '{' + fence[1].length + ',}\\s*$')).test(lines[i])) code.push(lines[i++]);
1506
+ i++;
1507
+ html.push('<pre><code>' + escapeHtml(code.join('\n')) + '</code></pre>');
1508
+ continue;
1509
+ }
1510
+ if (!line.trim()) { i++; continue; }
1511
+ var heading = /^\s{0,3}(#{1,6})\s+(.*?)\s*#*\s*$/.exec(line);
1512
+ if (heading) {
1513
+ html.push('<h' + heading[1].length + '>' + inlineMarkdown(heading[2]) + '</h' + heading[1].length + '>');
1514
+ i++;
1515
+ continue;
1516
+ }
1517
+ if (/^\s*\|/.test(line) && i + 1 < lines.length && /^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(lines[i + 1])) {
1518
+ var head = tableRow(line);
1519
+ i += 2;
1520
+ var rows = [];
1521
+ while (i < lines.length && /^\s*\|/.test(lines[i])) rows.push(tableRow(lines[i++]));
1522
+ html.push('<table class="table table-sm"><thead><tr>' + head.map(function (cell) { return '<th>' + inlineMarkdown(cell) + '</th>'; }).join('') + '</tr></thead><tbody>' +
1523
+ rows.map(function (row) { return '<tr>' + row.map(function (cell) { return '<td>' + inlineMarkdown(cell) + '</td>'; }).join('') + '</tr>'; }).join('') + '</tbody></table>');
1524
+ continue;
1525
+ }
1526
+ var item = /^\s*([-*+]|\d+[.)])\s+(.*)$/.exec(line);
1527
+ if (item) {
1528
+ var ordered = /\d/.test(item[1]);
1529
+ var items = [];
1530
+ while (i < lines.length) {
1531
+ var next = /^\s*([-*+]|\d+[.)])\s+(.*)$/.exec(lines[i]);
1532
+ if (!next || /\d/.test(next[1]) !== ordered) break;
1533
+ items.push('<li>' + inlineMarkdown(next[2]) + '</li>');
1534
+ i++;
1535
+ }
1536
+ html.push((ordered ? '<ol>' : '<ul>') + items.join('') + (ordered ? '</ol>' : '</ul>'));
1537
+ continue;
1538
+ }
1539
+ var paragraph = [];
1540
+ while (i < lines.length && lines[i].trim() && !/^\s{0,3}(#{1,6}\s|`{3,}|~{3,})/.test(lines[i]) && !/^\s*([-*+]|\d+[.)])\s+/.test(lines[i]) && !/^\s*\|/.test(lines[i])) {
1541
+ paragraph.push(lines[i++].trim());
1542
+ }
1543
+ if (!paragraph.length) { html.push('<p>' + inlineMarkdown(lines[i++]) + '</p>'); continue; }
1544
+ html.push('<p>' + paragraph.map(inlineMarkdown).join('<br>') + '</p>');
1545
+ }
1546
+ return html.join('');
1547
+ }
1548
+
1549
+ // ---------------------------------------------------------------------
1550
+ // client: the public browser API that components of UAG modules build on.
1551
+ // ---------------------------------------------------------------------
1552
+
1553
+ /** The headers that identify the user to the UAG: their Form.io token, and a portal team member's remote token. */
1554
+ function authHeaders(form) {
1555
+ var headers = {};
1556
+ var token = formioToken(form);
1557
+ if (token) headers['x-jwt-token'] = token;
1558
+ try {
1559
+ var sdk = registered.Formio;
1560
+ var remote = sdk && typeof sdk.getRemoteToken === 'function' ? sdk.getRemoteToken() : null;
1561
+ if (remote) headers['x-remote-token'] = remote;
1562
+ }
1563
+ catch (err) { /* no remote token */ }
1564
+ return headers;
1565
+ }
1566
+
1567
+ /** An Error with the UAG's status and code. */
1568
+ function uagError(message, status, code) {
1569
+ var err = new Error(message);
1570
+ if (status) err.status = status;
1571
+ if (code) err.code = code;
1572
+ return err;
1573
+ }
1574
+
1575
+ /**
1576
+ * POST JSON to the UAG, accepting server-sent events. Resolves with the
1577
+ * `done` event's data, or with the JSON answer; rejects with the UAG's
1578
+ * message (and `status`, `code`) for an error answer or a `failed` event.
1579
+ * Every event is passed to `options.onEvent(name, data)`.
1580
+ */
1581
+ function stream(url, body, options) {
1582
+ options = options || {};
1583
+ var fetchImpl = options.fetch || (registered.options && registered.options.fetch) || (typeof fetch === 'function' ? fetch : null);
1584
+ if (!fetchImpl) return Promise.reject(uagError('fetch is not available.'));
1585
+ var headers = Object.assign({ 'Content-Type': 'application/json', Accept: 'text/event-stream' }, authHeaders(options.form), options.headers || {});
1586
+ var done = null;
1587
+ var failure = null;
1588
+ return Promise.resolve().then(function () {
1589
+ return fetchImpl(url, { method: 'POST', headers: headers, body: JSON.stringify(body || {}), signal: options.signal });
1590
+ }).then(function (response) {
1591
+ var type = (response.headers && response.headers.get && response.headers.get('content-type')) || '';
1592
+ if (!response.ok || type.indexOf('text/event-stream') === -1) {
1593
+ return response.json().catch(function () { return {}; }).then(function (answer) {
1594
+ if (!response.ok) throw uagError((answer && answer.error) || ('The request failed (' + response.status + ').'), response.status, answer && answer.code);
1595
+ done = answer;
1596
+ });
1597
+ }
1598
+ var parser = new SSEParser(function (name, data) {
1599
+ if (typeof options.onEvent === 'function') options.onEvent(name, data);
1600
+ if (name === 'done') done = data;
1601
+ else if (name === 'failed' || name === 'error') failure = uagError((data && data.error) || 'The request failed.', data && data.status, data && data.code);
1602
+ });
1603
+ if (response.body && response.body.getReader) {
1604
+ var reader = response.body.getReader();
1605
+ var decoder = new TextDecoder();
1606
+ var pump = function () {
1607
+ return reader.read().then(function (chunk) {
1608
+ if (chunk.done) return;
1609
+ parser.push(decoder.decode(chunk.value, { stream: true }));
1610
+ return pump();
1611
+ });
1612
+ };
1613
+ return pump();
1614
+ }
1615
+ return response.text().then(function (text) { parser.push(text + '\n\n'); });
1616
+ }).then(function () {
1617
+ if (failure) throw failure;
1618
+ if (done === null) throw uagError('The request ended without an answer.');
1619
+ return done;
1620
+ });
1621
+ }
1622
+
1623
+ /**
1624
+ * The public browser API for components: the UAG's URL, the user's token,
1625
+ * a form's URL on the UAG, the installed plugins, streamed requests, and
1626
+ * Markdown rendering. Stable within a major version of @formio/uag-js.
1627
+ */
1628
+ var client = {
1629
+ url: function () { return registered.uagUrl; },
1630
+ token: function (form) { return formioToken(form); },
1631
+ headers: function (form) { return authHeaders(form); },
1632
+ formUrl: function (definition) { return uagFormUrl(registered.uagUrl, definition && definition.form && definition.form._id ? definition.form : definition); },
1633
+ ready: manifestState.promise,
1634
+ /** Whether the installed plugins are known yet (`ready` has resolved). */
1635
+ get loaded() { return manifestState.manifest !== null; },
1636
+ plugins: function (type) {
1637
+ return (manifestState.manifest || []).filter(function (plugin) { return plugin && (!type || plugin.type === type); });
1638
+ },
1639
+ plugin: function (type, name) {
1640
+ return client.plugins(type).filter(function (plugin) { return plugin.name === name; })[0] || null;
1641
+ },
1642
+ stream: stream,
1643
+ renderMarkdown: function (markdown) { return renderMarkdown(markdown); },
1644
+ escapeHtml: function (value) { return escapeHtml(value); },
1645
+ get Formio() { return registered.Formio; }
1646
+ };
1647
+
1427
1648
  /**
1428
1649
  * The formio.js module: `Formio.use(UAG('https://uag.example.com', options))`.
1429
1650
  * Options: `agentInput` (`false` turns Agent Input off), and Agent Input's
@@ -1432,8 +1653,19 @@
1432
1653
  */
1433
1654
  function UAG(uagUrl, options) {
1434
1655
  if (!uagUrl) throw new Error('UAG(): give the UAG\'s URL, e.g. UAG(\'https://uag.example.com\').');
1656
+ options = options || {};
1435
1657
  return function (Formio) {
1436
- registered = { uagUrl: trimSlash(uagUrl), Formio: Formio || null, options: options || {} };
1658
+ registered = { uagUrl: trimSlash(uagUrl), Formio: Formio || null, options: options };
1659
+ // Components of UAG modules find the client on the formio.js they are given.
1660
+ if (Formio && (typeof Formio === 'object' || typeof Formio === 'function')) {
1661
+ try { Object.defineProperty(Formio, 'uagClient', { value: client, configurable: true }); }
1662
+ catch (err) { /* a frozen Formio: components use FormioUAG.client */ }
1663
+ }
1664
+ // The installed plugins (the manifest), which components of UAG modules read through `client`.
1665
+ if (options.manifest) setManifest(options.manifest);
1666
+ else if (!manifestState.manifest) fetchManifest(registered.uagUrl, Formio).then(setManifest);
1667
+ // Portal mode: only the manifest and the client, for the modules' components; saves and Agent Input are left alone.
1668
+ if (options.portal) return {};
1437
1669
  var mod = { fetch: { uag: routingPlugin(registered.uagUrl) } };
1438
1670
  var displays = (Formio && Formio.Displays && Formio.Displays.displays) || {};
1439
1671
  mod.displays = {};
@@ -1452,6 +1684,10 @@
1452
1684
  }
1453
1685
  UAG.attach = attach;
1454
1686
  UAG.createChat = createChat;
1687
+ /** Resolves once the installed document plugins are known (embedded, or fetched at registration). */
1688
+ UAG.ready = manifestState.promise;
1689
+ UAG.renderMarkdown = renderMarkdown;
1690
+ UAG.client = client;
1455
1691
 
1456
1692
  return {
1457
1693
  UAG: UAG,
@@ -1462,6 +1698,8 @@
1462
1698
  ExtractionState: ExtractionState,
1463
1699
  SSEParser: SSEParser,
1464
1700
  isEmpty: isEmpty,
1465
- CHAT_TEMPLATES: CHAT_TEMPLATES
1701
+ CHAT_TEMPLATES: CHAT_TEMPLATES,
1702
+ renderMarkdown: renderMarkdown,
1703
+ client: client
1466
1704
  };
1467
1705
  }));
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // The ES module entry: the same module as index.js, which is CommonJS (and a browser global).
2
2
  import uag from './index.js';
3
3
 
4
- export const { UAG, attach, createChat, uagFormUrl, routingPlugin, ExtractionState, SSEParser, isEmpty, CHAT_TEMPLATES } = uag;
4
+ export const { UAG, attach, createChat, uagFormUrl, routingPlugin, ExtractionState, SSEParser, isEmpty, CHAT_TEMPLATES, renderMarkdown, client } = uag;
5
5
  export default uag;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formio/uag-js",
3
- "version": "2.0.0-rc.6",
3
+ "version": "2.0.0-rc.8",
4
4
  "description": "The Form.io UAG for formio.js applications: register it once, and forms tagged \"uag\" save through the UAG and get Agent Input, without overwriting what the user entered.",
5
5
  "keywords": [
6
6
  "formio",