@matterfact/embed 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +171 -1
  2. package/dist/chunk-6EM7T2JV.js +816 -0
  3. package/dist/chunk-6EM7T2JV.js.map +1 -0
  4. package/dist/{chunk-4Q2ROXLR.js → chunk-BKKXHSYU.js} +2 -2
  5. package/dist/chunk-FEXG4LQJ.js +3 -0
  6. package/dist/chunk-FEXG4LQJ.js.map +7 -0
  7. package/dist/chunk-NWNMS34P.js +2 -0
  8. package/dist/chunk-URGQBG4I.js +800 -0
  9. package/dist/chunk-URGQBG4I.js.map +1 -0
  10. package/dist/context-ACFBWIFH.js +3 -0
  11. package/dist/{context-YX2KXFLI.js.map → context-ACFBWIFH.js.map} +1 -1
  12. package/dist/{context-WU2F5CBC.js → context-U2HJJN2S.js} +4 -2
  13. package/dist/embed.js +1 -1
  14. package/dist/embed.js.map +4 -4
  15. package/dist/index.cjs +1006 -159
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +192 -32
  18. package/dist/index.d.ts +192 -32
  19. package/dist/index.js +537 -130
  20. package/dist/index.js.map +1 -1
  21. package/dist/react.cjs +1042 -165
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.cts +81 -1
  24. package/dist/react.d.ts +81 -1
  25. package/dist/react.js +566 -132
  26. package/dist/react.js.map +1 -1
  27. package/dist/{snapshot-JOGZWESK.js → snapshot-4GXT6PKZ.js} +2 -2
  28. package/dist/{snapshot-MUXE7KXX.js → snapshot-Y75SCGCM.js} +3 -3
  29. package/dist/{snapshot-MUXE7KXX.js.map → snapshot-Y75SCGCM.js.map} +1 -1
  30. package/examples/embed-demo/README.md +37 -0
  31. package/examples/embed-demo/src/App.tsx +55 -21
  32. package/examples/embed-demo/src/HoistDemo.tsx +390 -0
  33. package/examples/embed-demo/src/main.tsx +7 -0
  34. package/examples/embed-demo/src/mockXH.ts +492 -0
  35. package/examples/embed-demo/src/placement.tsx +43 -0
  36. package/examples/embed-demo/src/styles.css +147 -2
  37. package/examples/embed-demo/vite.config.ts +2 -2
  38. package/package.json +1 -1
  39. package/dist/chunk-7I37ZFAJ.js +0 -2
  40. package/dist/chunk-AXKXNYRT.js +0 -381
  41. package/dist/chunk-AXKXNYRT.js.map +0 -1
  42. package/dist/chunk-D7R6WVHG.js +0 -2
  43. package/dist/chunk-D7R6WVHG.js.map +0 -7
  44. package/dist/chunk-RS6RMZ77.js +0 -396
  45. package/dist/chunk-RS6RMZ77.js.map +0 -1
  46. package/dist/context-YX2KXFLI.js +0 -3
  47. /package/dist/{chunk-4Q2ROXLR.js.map → chunk-BKKXHSYU.js.map} +0 -0
  48. /package/dist/{chunk-7I37ZFAJ.js.map → chunk-NWNMS34P.js.map} +0 -0
  49. /package/dist/{context-WU2F5CBC.js.map → context-U2HJJN2S.js.map} +0 -0
  50. /package/dist/{snapshot-JOGZWESK.js.map → snapshot-4GXT6PKZ.js.map} +0 -0
package/README.md CHANGED
@@ -92,6 +92,78 @@ Script-tag / non-React hosts can use the iframe directly (the Share dialog shows
92
92
  ></iframe>
93
93
  ```
94
94
 
95
+ ## Linking your app's matterfact content
96
+
97
+ A co-embedded `<MatterfactArtifact>` (above) is found automatically. But your app may
98
+ render matterfact content another way — a report/dossier you pulled from matterfact and
99
+ render yourself, or artifacts spread across many routes. Tell the agent where that content
100
+ lives with a **site map**: your routes, each tagged with what kind of matterfact content
101
+ it carries. The agent uses it to reason about — and navigate toward — content the user
102
+ isn't currently looking at.
103
+
104
+ ```tsx
105
+ <MatterfactAgent
106
+ sitemap={[
107
+ {
108
+ path: '/company/:ticker/dossier',
109
+ label: 'Company Dossier',
110
+ content: { kind: 'mf-document', doctype: 'company_dossier' },
111
+ },
112
+ {
113
+ path: '/talent/exec-departures',
114
+ label: 'Exec Departures',
115
+ content: { kind: 'mf-artifact', slug: 'exec-departure-tracker' },
116
+ },
117
+ { path: '/screener', label: 'Screener', content: { kind: 'host-data' } },
118
+ ]}
119
+ />
120
+ ```
121
+
122
+ ```js
123
+ // script tag — same shape
124
+ window.matterfact = {
125
+ sitemap: [
126
+ /* … */
127
+ ],
128
+ };
129
+ ```
130
+
131
+ Each entry is **classification only** — a route pattern, a label, and a `content` tag:
132
+
133
+ - `{ kind: 'mf-artifact', slug }` — a matterfact artifact rendered on that route.
134
+ - `{ kind: 'mf-document', doctype }` — a matterfact document/report (dossier, etc.).
135
+ - `{ kind: 'host-data' }` — your own data; not matterfact content.
136
+
137
+ **Never put a capability token in the site map.** It is app-wide and rides on every turn;
138
+ the concrete artifact/document on the _current_ page arrives separately (the live artifact
139
+ iframe, or per-page context — see below), where the token belongs.
140
+
141
+ ### Documents on the current page
142
+
143
+ For a matterfact **document** the user is looking at, hand the agent its id via page
144
+ context (the same `context.entities` you already declare — see _What the agent can see_):
145
+
146
+ ```tsx
147
+ <MatterfactAgent
148
+ getPageContext={() => ({
149
+ route: '/company/:ticker/dossier',
150
+ entities: [
151
+ {
152
+ kind: 'document',
153
+ id: currentDoc.mfDocId, // the matterfact MF_DOC_ID
154
+ label: currentDoc.title,
155
+ data: { href: location.href }, // optional: enables the panel's "open on page" deeplink
156
+ },
157
+ ],
158
+ })}
159
+ />
160
+ ```
161
+
162
+ The agent can then cite the document inline as a chip; clicking it opens a read-only viewer
163
+ in the widget (authorized by the signed-in user's own matterfact access — no token), with an
164
+ optional **Open on page** deeplink back to your route. matterfact resolves the document from
165
+ its own systems by `MF_DOC_ID`; it never reads your database.
166
+
95
167
  ## Signing users in
96
168
 
97
169
  By default the widget runs its own sign-in in a popup (the only way an embedded frame can
@@ -214,6 +286,102 @@ gets nothing back. Default is on: seeing the page is the point of the widget.
214
286
  <MatterfactAgent publishableKey="pk_live_…" pageContext={false} />
215
287
  ```
216
288
 
289
+ ## Hoist apps
290
+
291
+ If the host page is an [XH Hoist](https://xh.io/) SPA — `window.XH` is present — the widget
292
+ automatically extracts rich page context and a snapshot from it. No `window.matterfact.context`,
293
+ no `getPageContext`, no host code at all: the grids, charts, and navigation already mounted in
294
+ the page are the source of truth. On any other page this is skipped entirely and the widget falls
295
+ back to the generic DOM snapshot described above.
296
+
297
+ This affects two different messages the widget sends, independently:
298
+
299
+ - The per-turn **context** (route + one-line description) still prefers an explicit
300
+ `getPageContext` / `window.matterfact.context` when the host declares one — Hoist is only the
301
+ fallback when neither is set.
302
+ - The on-demand **snapshot** (what the agent sees when it looks at the page) is Hoist-first,
303
+ unconditionally, ahead of the generic DOM walk — whether or not the host also declares context.
304
+
305
+ What gets extracted:
306
+
307
+ - **Route + description** — `XH.routerState`, turned into a one-line summary, e.g. `"Viewing
308
+ default.company.tsr, 1 selected, 1 grid(s)."`
309
+ - **Grids** — each mounted `GridModel` that has rows or a selection (an empty, not-yet-loaded
310
+ grid — e.g. an off-view tab — is skipped), as a table: columns (a grouped column is flattened
311
+ to its visible leaves and prefixed with its group, e.g. `"5Y Value"`), the current selection,
312
+ and up to `rows` data rows with a total count.
313
+ - **Charts** — each mounted `ChartModel` with at least one series, summarised per series (point
314
+ count, min, max, last) — never the raw series.
315
+ - **Site map** — each mounted `TabContainerModel`, joined to the router's routes: the app's
316
+ navigable destinations, grouped by nav level (top tabs, a per-record sidebar, …), with the
317
+ current one marked. This leads the snapshot, since it barely changes turn to turn.
318
+
319
+ It reads roughly like the ARIA snapshot above, with its own block types:
320
+
321
+ ```
322
+ - navigation "Site":
323
+ - link "Companies" → /app/companies
324
+ - link "Company Analysis" [current] → /app/company
325
+ - table "Peer TSR":
326
+ - rowgroup "columns":
327
+ - columnheader "Ticker"
328
+ - columnheader "1Y TSR"
329
+ - rowgroup "rows":
330
+ - row:
331
+ - cell "SITE"
332
+ - cell "12.3%"
333
+ - text: "showing 1 of 412 rows"
334
+ - figure "TSR vs Index":
335
+ - text: "series SITE: 4 points, min 1, max 10, last 10"
336
+ ```
337
+
338
+ ### Configuring it
339
+
340
+ ```js
341
+ window.matterfact = {
342
+ hoist: {
343
+ rows: 50, // rows sent per grid before truncating (default 50)
344
+ excludeModels: [], // class names ('ChartModel') or specific model ids to omit
345
+ actions: { navigate: 'off' }, // see "Letting the agent navigate" below
346
+ },
347
+ };
348
+ ```
349
+
350
+ | Key | Type | Default | What |
351
+ | ------------------ | ------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
352
+ | `rows` | `number` | `50` | Rows sent per grid before truncating. The full row count still rides along. |
353
+ | `excludeModels` | `string[]` | `[]` | Model class names (drops every instance) or specific model ids to omit — applies to grids, charts, and nav tab containers alike. |
354
+ | `actions.navigate` | `'off' \| 'confirm' \| 'auto'` | `'off'` | Whether the agent can drive navigation — see below. |
355
+
356
+ ### Letting the agent navigate
357
+
358
+ Set `actions.navigate` and the widget advertises a `hoist.navigate` tool bounded to exactly the
359
+ destinations in the CURRENT site map — the agent can't ask for somewhere that isn't reachable
360
+ from where the user actually is, and every call is re-validated against the live site map (and
361
+ the live policy), never whatever the widget last cached, before it runs:
362
+
363
+ - `'off'` (default) — the tool isn't advertised at all.
364
+ - `'confirm'` — advertised, and the widget shows an approval card the user must accept before
365
+ each call.
366
+ - `'auto'` — advertised and runs without asking.
367
+
368
+ ```tsx
369
+ <MatterfactAgent publishableKey="pk_live_…" actions={{ navigate: 'confirm' }} />
370
+ ```
371
+
372
+ ```js
373
+ // script tag — same idea, the global the React prop above is sugar for
374
+ window.matterfact = { hoist: { actions: { navigate: 'confirm' } } };
375
+ ```
376
+
377
+ Changing `actions` on `<MatterfactAgent>` remounts the widget (a fresh chat session) so the new
378
+ policy is advertised immediately — it's identity-defining config, not a live callback like
379
+ `getPageContext`.
380
+
381
+ Everything else about page observation still applies here: values are redacted before anything
382
+ leaves the page, row counts are capped, and `pageContext={false}` turns this off along with
383
+ everything else (see above).
384
+
217
385
  ## Microphone / dictation
218
386
 
219
387
  The composer supports voice dictation; the loader grants the iframe `allow="microphone"`.
@@ -253,7 +421,9 @@ Runnable examples ship inside this package (under `examples/`) and are browsable
253
421
  cloning anything:
254
422
 
255
423
  - **`examples/embed-demo/`** — a tiny Vite + React app that mounts `<MatterfactAgent inline>`
256
- in a side panel next to an embedded `<MatterfactArtifact>`, configured entirely via `.env`.
424
+ in a side panel next to an embedded `<MatterfactArtifact>`, configured entirely via `.env`. Also
425
+ ships an opt-in mock Hoist app (`?hoist=1`) to try the automatic Hoist-app path above with no
426
+ real Hoist deployment — see its own README.
257
427
  Browse it on [unpkg](https://unpkg.com/browse/@matterfact/embed/examples/embed-demo/), or
258
428
  after `npm install @matterfact/embed` find it at
259
429
  `node_modules/@matterfact/embed/examples/embed-demo/` — copy it out, `npm install`, `npm run dev`.