@matterfact/embed 0.13.0 → 0.15.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.
@@ -27,6 +27,15 @@ VITE_MF_ARTIFACT_SLUG=
27
27
  VITE_MF_ARTIFACT_OWNER=
28
28
  VITE_MF_ARTIFACT_TOKEN=
29
29
 
30
+ # ── Document (the embedded matterfact catalog document) ───────────────────────
31
+ # The <MatterfactDoc> surface is session-authed through the MatterfactAuthProvider
32
+ # (no token of its own — it reuses the publishable key + origin above). docKey is
33
+ # the catalog document key; ticker seeds its initial view; version is pinned to
34
+ # `latest` in the demo. These ship with sensible placeholders so the doc renders
35
+ # out of the box — swap them for a real document in your deployment.
36
+ VITE_MF_DOC_KEY=company-dossier
37
+ VITE_MF_DOC_TICKER=NVDA
38
+
30
39
  # ── Optional ──────────────────────────────────────────────────────────────────
31
40
  VITE_MF_SURFACE=embed-demo
32
41
  VITE_MF_THEME=auto
@@ -1,14 +1,54 @@
1
1
  # matterfact embed demo
2
2
 
3
- A tiny React + Vite app that puts **both** matterfact embed surfaces on one page using
4
- `@matterfact/embed`:
3
+ A tiny React + Vite app that puts **three** matterfact embed surfaces on one page using
4
+ `@matterfact/embed`, all configured through a **single `<MatterfactAuthProvider>`**:
5
5
 
6
6
  - **`<MatterfactAgent inline>`** — the chat, mounted in the page's right rail;
7
- - **`<MatterfactArtifact>`** — a matterfact artifact embedded in the page.
7
+ - **`<MatterfactArtifact>`** — a matterfact artifact embedded in the page (tokenless);
8
+ - **`<MatterfactDoc>`** — a matterfact catalog document (dossier / report), embedded
9
+ in the page (tokenless).
8
10
 
9
- Both on the page means the agent auto-detects the artifact by origin and can answer
11
+ All three on the page means the agent auto-detects the artifact by origin and can answer
10
12
  questions about the data behind it — no wiring.
11
13
 
14
+ ## Configure once: `<MatterfactAuthProvider>`
15
+
16
+ The publishable key, widget origin, theme and host-auth hook are set **once** on a
17
+ provider that wraps every surface — the components underneath read them from context:
18
+
19
+ ```tsx
20
+ import {
21
+ MatterfactAuthProvider,
22
+ MatterfactAgent,
23
+ MatterfactArtifact,
24
+ MatterfactDoc,
25
+ } from '@matterfact/embed/react';
26
+
27
+ <MatterfactAuthProvider
28
+ publishableKey="pk_live_…"
29
+ widgetOrigin="https://emc.matterfact.com"
30
+ getAuthToken={getAuthToken} // silent host-auth; return null → popup sign-in
31
+ theme="auto"
32
+ >
33
+ <MatterfactAgent inline surface="…" />
34
+ <MatterfactArtifact name="…" owner="you@firm.com" /> {/* no token, no origin */}
35
+ <MatterfactDoc docKey="…" ticker="NVDA" version="latest" />
36
+ </MatterfactAuthProvider>
37
+ ```
38
+
39
+ **This is the migration from the pre-provider pattern.** Previously each
40
+ `<MatterfactAgent>` / `<MatterfactArtifact>` carried its own `publishableKey`,
41
+ `widgetOrigin`, `theme` — and the artifact carried a per-component share `token`. Now:
42
+
43
+ - lift `publishableKey` / `widgetOrigin` / `theme` / `getAuthToken` onto the provider;
44
+ - `<MatterfactArtifact>`: `slug=` → `name=`, and **drop** `token=` and `widgetOrigin=`
45
+ (inside a provider it authenticates with the session — publishable key + host origin —
46
+ the same way the agent does). Keep `owner=`;
47
+ - `<MatterfactDoc>` is **always** session-authed — it has no standalone token mode at
48
+ all, so it only works inside a provider.
49
+
50
+ `src/App.tsx` is that migration end-to-end — read it as the copy-this reference.
51
+
12
52
  ### Two agent surfaces: inline + full page
13
53
 
14
54
  The header has an **Inline / Full page** switch (deep-linkable via `?view=full`):
@@ -51,9 +91,10 @@ Vite exposes only `VITE_`-prefixed vars to the app.
51
91
  | `VITE_MF_ENV` | Deployment: `ecm` \| `prod` \| `staging` \| `local`. Picks the widget origin. |
52
92
  | `VITE_MF_WIDGET_ORIGIN` | Optional. Overrides the origin (required for `staging`). |
53
93
  | `VITE_MF_PUBLISHABLE_KEY` | The agent's publishable key (`pk_live_…` / `pk_test_…`). |
54
- | `VITE_MF_ARTIFACT_SLUG` / `_OWNER` / `_TOKEN` | The artifact — from its **Share → Embed** dialog. |
94
+ | `VITE_MF_ARTIFACT_SLUG` / `_OWNER` / `_TOKEN` | The artifact — from its **Share → Embed** dialog. Inside the provider only `_SLUG` (→ `name`) and `_OWNER` are used; `_TOKEN` is no longer needed. |
95
+ | `VITE_MF_DOC_KEY` / `VITE_MF_DOC_TICKER` | The catalog document (`<MatterfactDoc>`) — its catalog key and initial ticker. Ship with placeholders. |
55
96
  | `VITE_MF_SURFACE` | Free-form usage/history label. |
56
- | `VITE_MF_THEME` | `light` \| `dark` \| `auto`. |
97
+ | `VITE_MF_THEME` | `light` \| `dark` \| `auto`. Set once — the provider fans it out to every surface. |
57
98
 
58
99
  ### Env → origin
59
100
 
@@ -75,7 +116,10 @@ If it isn't, the agent iframe renders nothing — the key isn't wrong, the origi
75
116
  ## Signing in
76
117
 
77
118
  The widget runs its own sign-in in a popup — a cross-site iframe has no ambient session, so
78
- this is the honest production behaviour. Silent host-auth (`getAuthToken`) is out of scope here.
119
+ this is the honest production behaviour. The provider's `getAuthToken` hook (silent host-auth)
120
+ is wired in `src/App.tsx` to show where it goes, but returns `null` here — so the demo falls
121
+ back to that popup sign-in. A trusted first-party host returns a real token (its Firebase
122
+ idToken, an Entra token, …) and every surface under the provider signs in silently instead.
79
123
 
80
124
  ## Host tools & telemetry
81
125
 
@@ -140,13 +184,23 @@ detection takes over. It doubles as a reference for what a real Hoist app needs
140
184
  the same result: nothing — just the `GridModel` / `ChartModel` / `TabContainerModel` / router
141
185
  surface a real Hoist app already has mounted.
142
186
 
143
- ## The two lines that matter
187
+ ## The shape that matters
144
188
 
145
189
  ```tsx
146
- import { MatterfactAgent, MatterfactArtifact } from '@matterfact/embed/react';
147
-
148
- <MatterfactAgent inline publishableKey="pk_live_…" widgetOrigin="https://emc.matterfact.com" />
149
- <MatterfactArtifact slug="…" owner="you@firm.com" token="…" widgetOrigin="https://emc.matterfact.com" />
190
+ import {
191
+ MatterfactAuthProvider,
192
+ MatterfactAgent,
193
+ MatterfactArtifact,
194
+ MatterfactDoc,
195
+ } from '@matterfact/embed/react';
196
+
197
+ // Configure once on the provider…
198
+ <MatterfactAuthProvider publishableKey="pk_live_…" widgetOrigin="https://emc.matterfact.com" theme="auto">
199
+ {/* …and every surface underneath inherits it. */}
200
+ <MatterfactAgent inline />
201
+ <MatterfactArtifact name="…" owner="you@firm.com" />
202
+ <MatterfactDoc docKey="…" ticker="NVDA" version="latest" />
203
+ </MatterfactAuthProvider>
150
204
  ```
151
205
 
152
206
  See the package [README](../../README.md) for the full API.
@@ -1,7 +1,9 @@
1
1
  import { useCallback, useMemo, useState } from 'react';
2
2
  import {
3
+ MatterfactAuthProvider,
3
4
  MatterfactAgent,
4
5
  MatterfactArtifact,
6
+ MatterfactDoc,
5
7
  type HostToolDef,
6
8
  } from '@matterfact/embed/react';
7
9
  import type { MatterfactEvent } from '@matterfact/embed';
@@ -78,6 +80,14 @@ export function App() {
78
80
  setEvents((prev) => [...prev.slice(-19), { t: Date.now(), line }]);
79
81
  }, []);
80
82
 
83
+ // SILENT HOST-AUTH passthrough — set once on the provider, inherited by every
84
+ // surface below (agent, artifact, doc). Return a token this matterfact
85
+ // deployment already trusts (the host app's Firebase idToken, an Entra token,
86
+ // …) and the widgets sign in silently with it. This demo has no host session,
87
+ // so it returns null — which falls back to the widget's own popup sign-in. It's
88
+ // wired here purely to show WHERE a real integration would supply the token.
89
+ const getAuthToken = useCallback(() => null, []);
90
+
81
91
  // Host-defined `app.*` tools: the agent can call these, and you watch the page react.
82
92
  // `selectHolding` mutates real page state (the same `selected` the pull-context demo
83
93
  // uses) so a tool call is visible; `filterHoldings` is a read-only query.
@@ -157,7 +167,18 @@ export function App() {
157
167
  data: { selectedHolding: selected },
158
168
  });
159
169
 
170
+ // CONFIGURE ONCE. Everything that used to be repeated on each <MatterfactAgent>
171
+ // / <MatterfactArtifact> — the publishable key, the widget origin, the theme,
172
+ // and the host-auth hook — now lives on ONE provider that wraps every embed
173
+ // surface. The agent, artifact and doc below read it from context, so they only
174
+ // carry the props that are actually specific to them.
160
175
  return (
176
+ <MatterfactAuthProvider
177
+ publishableKey={config.publishableKey}
178
+ widgetOrigin={config.widgetOrigin}
179
+ getAuthToken={getAuthToken}
180
+ theme={config.theme}
181
+ >
161
182
  <div
162
183
  className="app"
163
184
  data-placement={placement}
@@ -239,14 +260,15 @@ export function App() {
239
260
  <span className="mf">✦</span> matterfact artifact ·{' '}
240
261
  <code>{config.artifact.slug}</code>
241
262
  </div>
242
- {/* The agent, mounted on the same page below, auto-detects this artifact
243
- by origin and can answer questions about the data behind it. */}
263
+ {/* Tokenless. Inside the provider the artifact authenticates with
264
+ the SAME session as the agent (publishable key + host origin)
265
+ no per-component share token. Only `name` and `owner` identify
266
+ it; widgetOrigin and theme are inherited from the provider. The
267
+ agent, mounted on the same page below, still auto-detects this
268
+ artifact by origin and can answer questions about its data. */}
244
269
  <MatterfactArtifact
245
- slug={config.artifact.slug}
270
+ name={config.artifact.slug}
246
271
  owner={config.artifact.owner}
247
- token={config.artifact.token}
248
- widgetOrigin={config.widgetOrigin}
249
- theme={config.theme}
250
272
  style={{ width: '100%', height: '100%' }}
251
273
  />
252
274
  </div>
@@ -258,6 +280,33 @@ export function App() {
258
280
  </>
259
281
  )}
260
282
 
283
+ <div className="section-title">Embedded matterfact document</div>
284
+ <div className="artifact-frame">
285
+ <div className="artifact-badge">
286
+ <span className="mf">✦</span> matterfact document ·{' '}
287
+ <code>{config.doc.docKey}</code>
288
+ </div>
289
+ {/* A catalog document (dossier / report). ALWAYS session-authed — there
290
+ is no standalone share-token mode — so it relies on the provider for
291
+ the publishable key + origin. `docKey` is fixed at mount; `ticker`
292
+ and `version` seed the initial view (and are live-drivable via a
293
+ `params` prop, not shown here). */}
294
+ <MatterfactDoc
295
+ docKey={config.doc.docKey}
296
+ ticker={config.doc.ticker}
297
+ version="latest"
298
+ style={{ width: '100%', height: '100%' }}
299
+ />
300
+ </div>
301
+ <p className="artifact-caption">
302
+ <strong>Tokenless, session-authed:</strong> like the artifact above,
303
+ this document has no token of its own — it inherits the session from
304
+ the provider. Swap the placeholder <code>docKey</code>/
305
+ <code>ticker</code> (<code>VITE_MF_DOC_KEY</code> /{' '}
306
+ <code>VITE_MF_DOC_TICKER</code>) for a real catalog document in your
307
+ deployment.
308
+ </p>
309
+
261
310
  <div className="section-title">Holdings</div>
262
311
  <table>
263
312
  <thead>
@@ -328,10 +377,7 @@ export function App() {
328
377
  <div className="agent-slot">
329
378
  <MatterfactAgent
330
379
  inline
331
- publishableKey={config.publishableKey}
332
- widgetOrigin={config.widgetOrigin}
333
380
  surface={config.surface}
334
- theme={config.theme}
335
381
  // Pulled fresh every turn — the whole point of this example.
336
382
  getPageContext={getPageContext}
337
383
  // Host-defined tools + the unified telemetry hook.
@@ -350,16 +396,14 @@ export function App() {
350
396
  right-click menu, and the float/dock panel. */}
351
397
  {placement === 'corner' && (
352
398
  <MatterfactAgent
353
- publishableKey={config.publishableKey}
354
- widgetOrigin={config.widgetOrigin}
355
399
  surface={config.surface}
356
- theme={config.theme}
357
400
  getPageContext={getPageContext}
358
401
  tools={tools}
359
402
  onEvent={logEvent}
360
403
  />
361
404
  )}
362
405
  </div>
406
+ </MatterfactAuthProvider>
363
407
  );
364
408
  }
365
409
 
@@ -41,6 +41,14 @@ export const config = {
41
41
  owner: decodeOwner(env.VITE_MF_ARTIFACT_OWNER),
42
42
  token: env.VITE_MF_ARTIFACT_TOKEN ?? '',
43
43
  },
44
+ // The embedded catalog document (MatterfactDoc). Session-authed through the
45
+ // provider — no per-component token — so it needs only a docKey + an initial
46
+ // ticker. Both ship with sensible placeholders so the demo renders out of the
47
+ // box; swap them for a real document in your deployment.
48
+ doc: {
49
+ docKey: env.VITE_MF_DOC_KEY ?? 'company-dossier',
50
+ ticker: env.VITE_MF_DOC_TICKER ?? 'NVDA',
51
+ },
44
52
  surface: env.VITE_MF_SURFACE ?? 'embed-demo',
45
53
  theme: (env.VITE_MF_THEME ?? 'light') as Theme,
46
54
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterfact/embed",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "The matterfact embeddable agent: mount the chat in a cross-origin iframe (a <script> loader for any site, or a <MatterfactAgent> React component), give the agent eyes on the host page, and embed matterfact artifacts inline with <MatterfactArtifact>.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,