@matterfact/embed 0.11.3 → 0.13.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 (44) hide show
  1. package/README.md +41 -0
  2. package/dist/chunk-C7DXO37G.js +2 -0
  3. package/dist/{chunk-CTZEDOH7.js → chunk-JLJG3MDX.js} +101 -51
  4. package/dist/chunk-JLJG3MDX.js.map +1 -0
  5. package/dist/chunk-QZCUQZJK.js +3 -0
  6. package/dist/chunk-QZCUQZJK.js.map +7 -0
  7. package/dist/{chunk-AANODHBV.js → chunk-S6OT47DL.js} +100 -49
  8. package/dist/chunk-S6OT47DL.js.map +1 -0
  9. package/dist/{chunk-JO3GWFMJ.js → chunk-UA4Y2O64.js} +2 -2
  10. package/dist/{context-FR7VFENN.js → context-DAXACLSP.js} +3 -3
  11. package/dist/{context-FR7VFENN.js.map → context-DAXACLSP.js.map} +1 -1
  12. package/dist/{context-IK5MECUW.js → context-IJK345PN.js} +4 -2
  13. package/dist/embed.js +1 -1
  14. package/dist/embed.js.map +3 -3
  15. package/dist/index.cjs +167 -53
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +83 -10
  18. package/dist/index.d.ts +83 -10
  19. package/dist/index.js +63 -6
  20. package/dist/index.js.map +1 -1
  21. package/dist/react.cjs +159 -52
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.cts +29 -2
  24. package/dist/react.d.ts +29 -2
  25. package/dist/react.js +54 -5
  26. package/dist/react.js.map +1 -1
  27. package/dist/{snapshot-2V5SDSH2.js → snapshot-EVBNVVCT.js} +2 -2
  28. package/dist/{snapshot-Y5BF2UJR.js → snapshot-P5SVKSPB.js} +3 -3
  29. package/dist/{snapshot-Y5BF2UJR.js.map → snapshot-P5SVKSPB.js.map} +1 -1
  30. package/examples/embed-demo/.env.example +7 -3
  31. package/examples/embed-demo/README.md +25 -4
  32. package/examples/embed-demo/src/App.tsx +67 -7
  33. package/examples/embed-demo/src/styles.css +52 -0
  34. package/examples/embed-demo/vite.config.ts +3 -2
  35. package/package.json +1 -1
  36. package/dist/chunk-AANODHBV.js.map +0 -1
  37. package/dist/chunk-CTZEDOH7.js.map +0 -1
  38. package/dist/chunk-SKJFF7RD.js +0 -2
  39. package/dist/chunk-Y7I25VHL.js +0 -3
  40. package/dist/chunk-Y7I25VHL.js.map +0 -7
  41. /package/dist/{chunk-SKJFF7RD.js.map → chunk-C7DXO37G.js.map} +0 -0
  42. /package/dist/{chunk-JO3GWFMJ.js.map → chunk-UA4Y2O64.js.map} +0 -0
  43. /package/dist/{context-IK5MECUW.js.map → context-IJK345PN.js.map} +0 -0
  44. /package/dist/{snapshot-2V5SDSH2.js.map → snapshot-EVBNVVCT.js.map} +0 -0
package/dist/react.cjs CHANGED
@@ -22,6 +22,37 @@ var __copyProps = (to, from, except, desc) => {
22
22
  };
23
23
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
24
 
25
+ // src/pageContextMode.ts
26
+ function parsePageContextMode(value) {
27
+ if (typeof value === "boolean") return value ? "full" : "off";
28
+ if (value == null) return "full";
29
+ const s = String(value).trim().toLowerCase();
30
+ if (s === "full" || s === "declared" || s === "off") return s;
31
+ if (s === "true" || s === "on" || s === "1" || s === "yes") return "full";
32
+ if (s === "false" || s === "0" || s === "no") return "off";
33
+ return "full";
34
+ }
35
+ function clampPageContextMode(adminMax, hostRequest) {
36
+ return RANK[adminMax] <= RANK[hostRequest] ? adminMax : hostRequest;
37
+ }
38
+ function allowsDeclared(mode) {
39
+ return mode !== "off";
40
+ }
41
+ function allowsAuto(mode) {
42
+ return mode === "full";
43
+ }
44
+ var RANK;
45
+ var init_pageContextMode = __esm({
46
+ "src/pageContextMode.ts"() {
47
+ "use strict";
48
+ RANK = {
49
+ off: 0,
50
+ declared: 1,
51
+ full: 2
52
+ };
53
+ }
54
+ });
55
+
25
56
  // src/redact.ts
26
57
  function redact(text) {
27
58
  let out = text;
@@ -449,7 +480,7 @@ function mfTools(win) {
449
480
  if (typeof document2 === "function") {
450
481
  out.push({
451
482
  name: "mf.resolveDocument",
452
- description: 'Resolve a matterfact document (dossier, report, briefing) that is NOT on the current page to a concrete id. Call it with the document type and a key (e.g. a ticker) when the site map shows the document lives on another route. Returns {id, label, href}. Cite the result inline as <MFRef kind="document" id="<id>" label="<label>" /> \u2014 it renders as a chip that opens the document in the side panel; href is its "open on page" deeplink.',
483
+ description: `Resolve a matterfact document (dossier, report, briefing) that is NOT on the current page to a concrete id. Call it with the document type and the subject's key, when the site map shows the document lives on another route. For the key, use the current route parameter VERBATIM when the page context states one (e.g. ticker = BP~+LN+Equity \u2192 key "BP~+LN+Equity"): it is the host's own identifier and often differs from the ticker or name a person would write. Do not normalise, decode or re-spell it, and do not substitute what the user typed. Returns {id, label, href}. Cite the result inline as <MFRef kind="document" id="<id>" label="<label>" /> \u2014 it renders as a chip that opens the document in the side panel; href is its "open on page" deeplink.`,
453
484
  inputSchema: {
454
485
  type: "object",
455
486
  properties: {
@@ -1064,9 +1095,16 @@ __export(context_exports, {
1064
1095
  redact: () => redact,
1065
1096
  sendRegion: () => sendRegion,
1066
1097
  sendSnapshot: () => sendSnapshot,
1098
+ setPageContextMax: () => setPageContextMax,
1067
1099
  start: () => start,
1068
1100
  stop: () => stop
1069
1101
  });
1102
+ function effectivePageContextMode() {
1103
+ return clampPageContextMode(adminPageContextMax, hostPageContextMode);
1104
+ }
1105
+ function pageContextOn() {
1106
+ return allowsDeclared(effectivePageContextMode());
1107
+ }
1070
1108
  function isPrivate(el) {
1071
1109
  if (el.closest("[data-mf-private]")) return true;
1072
1110
  const tag = el.tagName;
@@ -1153,8 +1191,9 @@ async function resolveDeclaredContext() {
1153
1191
  return mf?.context ?? {};
1154
1192
  }
1155
1193
  async function publishContext() {
1156
- if (!pageContextOn) return;
1194
+ if (!pageContextOn()) return;
1157
1195
  const declared = await resolveDeclaredContext();
1196
+ if (!pageContextOn()) return;
1158
1197
  send?.({ type: "host.context", context: buildPageContext(declared) });
1159
1198
  }
1160
1199
  function provideContext() {
@@ -1215,7 +1254,7 @@ function readSitemap2() {
1215
1254
  return Array.isArray(s) ? s : [];
1216
1255
  }
1217
1256
  function publishSitemap() {
1218
- if (!pageContextOn) return;
1257
+ if (!pageContextOn()) return;
1219
1258
  const sitemap = readSitemap2();
1220
1259
  if (sitemap.length) send?.({ type: "host.sitemap", sitemap });
1221
1260
  }
@@ -1232,6 +1271,7 @@ function navigateHost(href) {
1232
1271
  location.assign(target.href);
1233
1272
  }
1234
1273
  function pushActivity(e) {
1274
+ if (!allowsAuto(effectivePageContextMode())) return;
1235
1275
  activity.push({ ...e, seq: ++activitySeq, ts: Date.now() });
1236
1276
  if (activity.length > MAX_ACTIVITY) activity.shift();
1237
1277
  send?.({ type: "host.activity", events: [activity[activity.length - 1]] });
@@ -1296,6 +1336,7 @@ function watchNavigation() {
1296
1336
  publishSitemap();
1297
1337
  publishTools();
1298
1338
  };
1339
+ if (navFire) return;
1299
1340
  navFire = fire;
1300
1341
  for (const name of ["pushState", "replaceState"]) {
1301
1342
  const orig = history[name];
@@ -1350,7 +1391,7 @@ function scheduleFocus() {
1350
1391
  }, 250);
1351
1392
  }
1352
1393
  async function sendSnapshot(emit) {
1353
- if (!pageContextOn) return;
1394
+ if (!allowsAuto(effectivePageContextMode())) return;
1354
1395
  const hoist = detectHoist(() => readHoistRuntime());
1355
1396
  if (hoist) {
1356
1397
  const { rows } = readHoistConfig(
@@ -1366,6 +1407,7 @@ async function sendSnapshot(emit) {
1366
1407
  return;
1367
1408
  }
1368
1409
  const { snapshot: snapshot2 } = await loadSnapshotModule();
1410
+ if (!allowsAuto(effectivePageContextMode())) return;
1369
1411
  const { yaml, truncated, visibleRefs } = snapshot2();
1370
1412
  emit({
1371
1413
  type: "host.snapshot",
@@ -1375,8 +1417,9 @@ async function sendSnapshot(emit) {
1375
1417
  emit({ type: "host.focus", focus: lastFocus });
1376
1418
  }
1377
1419
  async function sendRegion(ref, emit) {
1378
- if (!pageContextOn) return;
1420
+ if (!allowsAuto(effectivePageContextMode())) return;
1379
1421
  const { snapshotRegion: snapshotRegion2, resolveRef: resolveRef2 } = await loadSnapshotModule();
1422
+ if (!allowsAuto(effectivePageContextMode())) return;
1380
1423
  const el = resolveRef2(ref);
1381
1424
  if (!el) {
1382
1425
  emit({
@@ -1390,15 +1433,6 @@ async function sendRegion(ref, emit) {
1390
1433
  emit({ type: "host.region", ref, yaml: redact(yaml) });
1391
1434
  }
1392
1435
  async function callTool(call, emit) {
1393
- if (!pageContextOn) {
1394
- emit({
1395
- type: "host.toolResult",
1396
- callId: call.callId,
1397
- ok: false,
1398
- error: "host tools are disabled"
1399
- });
1400
- return;
1401
- }
1402
1436
  const win = typeof window !== "undefined" ? window : void 0;
1403
1437
  const cls = toolClass(call.name);
1404
1438
  const startedAt = Date.now();
@@ -1425,13 +1459,39 @@ async function callTool(call, emit) {
1425
1459
  error: r.error
1426
1460
  });
1427
1461
  }
1428
- function stop() {
1462
+ function installAutoObservers() {
1463
+ document.addEventListener("click", onClick, { capture: true, passive: true });
1464
+ document.addEventListener("submit", onSubmit, {
1465
+ capture: true,
1466
+ passive: true
1467
+ });
1468
+ document.addEventListener("change", onChange, {
1469
+ capture: true,
1470
+ passive: true
1471
+ });
1472
+ document.addEventListener("selectionchange", scheduleFocus, { passive: true });
1473
+ document.addEventListener("focusin", scheduleFocus, {
1474
+ capture: true,
1475
+ passive: true
1476
+ });
1477
+ window.addEventListener("scroll", scheduleFocus, {
1478
+ capture: true,
1479
+ passive: true
1480
+ });
1481
+ }
1482
+ function removeAutoObservers() {
1429
1483
  document.removeEventListener("click", onClick, { capture: true });
1430
1484
  document.removeEventListener("submit", onSubmit, { capture: true });
1431
1485
  document.removeEventListener("change", onChange, { capture: true });
1432
1486
  document.removeEventListener("selectionchange", scheduleFocus);
1433
1487
  document.removeEventListener("focusin", scheduleFocus, { capture: true });
1434
1488
  window.removeEventListener("scroll", scheduleFocus, { capture: true });
1489
+ if (focusTimer) {
1490
+ clearTimeout(focusTimer);
1491
+ focusTimer = null;
1492
+ }
1493
+ }
1494
+ function unwatchNavigation() {
1435
1495
  if (navFire) {
1436
1496
  window.removeEventListener("popstate", navFire);
1437
1497
  navFire = null;
@@ -1444,10 +1504,10 @@ function stop() {
1444
1504
  history.replaceState = origReplaceState;
1445
1505
  origReplaceState = null;
1446
1506
  }
1447
- if (focusTimer) {
1448
- clearTimeout(focusTimer);
1449
- focusTimer = null;
1450
- }
1507
+ }
1508
+ function stop() {
1509
+ removeAutoObservers();
1510
+ unwatchNavigation();
1451
1511
  send = null;
1452
1512
  contextProvider = void 0;
1453
1513
  activity.length = 0;
@@ -1455,45 +1515,41 @@ function stop() {
1455
1515
  widgetOrigin = "";
1456
1516
  snapshotModule?.clearRefs();
1457
1517
  }
1518
+ function setPageContextMax(max) {
1519
+ adminPageContextMax = parsePageContextMode(max);
1520
+ applyObservation();
1521
+ }
1522
+ function applyObservation() {
1523
+ const mode = effectivePageContextMode();
1524
+ if (allowsAuto(mode)) {
1525
+ installAutoObservers();
1526
+ } else {
1527
+ removeAutoObservers();
1528
+ activity.length = 0;
1529
+ lastFocus = {};
1530
+ }
1531
+ if (allowsDeclared(mode)) {
1532
+ watchNavigation();
1533
+ } else {
1534
+ unwatchNavigation();
1535
+ }
1536
+ }
1458
1537
  function start(emit, origin, pageContext = true, provider) {
1459
1538
  stop();
1460
1539
  send = emit;
1461
1540
  widgetOrigin = origin || "";
1462
1541
  lastUrl = location.pathname;
1463
- pageContextOn = pageContext;
1542
+ hostPageContextMode = parsePageContextMode(pageContext);
1464
1543
  contextProvider = provider;
1465
- if (pageContextOn) {
1544
+ if (allowsDeclared(effectivePageContextMode())) {
1466
1545
  void publishContext();
1467
1546
  publishArtifactGrants();
1468
1547
  publishSitemap();
1469
- watchNavigation();
1470
- document.addEventListener("click", onClick, {
1471
- capture: true,
1472
- passive: true
1473
- });
1474
- document.addEventListener("submit", onSubmit, {
1475
- capture: true,
1476
- passive: true
1477
- });
1478
- document.addEventListener("change", onChange, {
1479
- capture: true,
1480
- passive: true
1481
- });
1482
- document.addEventListener("selectionchange", scheduleFocus, {
1483
- passive: true
1484
- });
1485
- document.addEventListener("focusin", scheduleFocus, {
1486
- capture: true,
1487
- passive: true
1488
- });
1489
- window.addEventListener("scroll", scheduleFocus, {
1490
- capture: true,
1491
- passive: true
1492
- });
1493
1548
  }
1549
+ applyObservation();
1494
1550
  const theme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1495
1551
  emit({ type: "host.theme", mode: theme });
1496
- if (pageContextOn) {
1552
+ {
1497
1553
  const w = typeof window !== "undefined" ? window : void 0;
1498
1554
  const tools = advertise(w);
1499
1555
  if (tools.length) {
@@ -1520,10 +1576,11 @@ function publishTools() {
1520
1576
  });
1521
1577
  }
1522
1578
  }
1523
- var widgetOrigin, MAX_ACTIVITY, send, activitySeq, activity, lastUrl, pageContextOn, contextProvider, navFire, origPushState, origReplaceState, snapshotModule, FORM_CONTROLS, ACTIONABLE, lastFocus, focusTimer, snapshotSeq;
1579
+ var widgetOrigin, MAX_ACTIVITY, send, activitySeq, activity, lastUrl, hostPageContextMode, adminPageContextMax, contextProvider, navFire, origPushState, origReplaceState, snapshotModule, FORM_CONTROLS, ACTIONABLE, lastFocus, focusTimer, snapshotSeq;
1524
1580
  var init_context = __esm({
1525
1581
  "src/context.ts"() {
1526
1582
  "use strict";
1583
+ init_pageContextMode();
1527
1584
  init_redact();
1528
1585
  init_hoist();
1529
1586
  init_hoist_runtime();
@@ -1535,7 +1592,8 @@ var init_context = __esm({
1535
1592
  activitySeq = 0;
1536
1593
  activity = [];
1537
1594
  lastUrl = "";
1538
- pageContextOn = true;
1595
+ hostPageContextMode = "full";
1596
+ adminPageContextMax = "full";
1539
1597
  navFire = null;
1540
1598
  origPushState = null;
1541
1599
  origReplaceState = null;
@@ -1782,11 +1840,19 @@ function dockBox(g, vw, _vh) {
1782
1840
  // src/loader.ts
1783
1841
  function devRequested() {
1784
1842
  try {
1785
- return new URLSearchParams(location.search).get("mfdev") === "1";
1843
+ if (new URLSearchParams(location.search).get("mfdev") === "1") return true;
1844
+ try {
1845
+ return localStorage.getItem("mfdev") === "1";
1846
+ } catch {
1847
+ return false;
1848
+ }
1786
1849
  } catch {
1787
1850
  return false;
1788
1851
  }
1789
1852
  }
1853
+ function alog(m, x) {
1854
+ if (devRequested()) console.info("[embed auth] host: " + m, x ?? "");
1855
+ }
1790
1856
  var POS_KEY = "mf.embed.pos";
1791
1857
  var EmbedHost = class {
1792
1858
  constructor(config) {
@@ -2048,6 +2114,11 @@ var EmbedHost = class {
2048
2114
  case "widget.requestContext":
2049
2115
  void this.loadContext().then((m) => m.provideContext());
2050
2116
  break;
2117
+ case "widget.pageContextMax":
2118
+ void this.loadContext().then((m) => {
2119
+ m.setPageContextMax(msg.mode);
2120
+ });
2121
+ break;
2051
2122
  case "widget.requestSnapshot":
2052
2123
  void this.loadContext().then((m) => m.sendSnapshot(this.send));
2053
2124
  break;
@@ -2153,6 +2224,13 @@ var EmbedHost = class {
2153
2224
  case "widget.chat":
2154
2225
  this.emit({ type: "chat", phase: msg.phase, chatId: msg.chatId });
2155
2226
  break;
2227
+ case "widget.artifactParams":
2228
+ this.emit({
2229
+ type: "artifactParams",
2230
+ params: msg.params,
2231
+ source: msg.source
2232
+ });
2233
+ break;
2156
2234
  }
2157
2235
  }
2158
2236
  /**
@@ -2260,14 +2338,22 @@ var EmbedHost = class {
2260
2338
  */
2261
2339
  async provideAuth() {
2262
2340
  const provider = this.config.authTokenProvider ?? globalThis.matterfact?.getEmbedAuthToken;
2263
- if (!provider) return;
2264
- if (++this.ac > 5) return;
2341
+ if (!provider) {
2342
+ alog("no provider");
2343
+ return;
2344
+ }
2345
+ if (++this.ac > 5) {
2346
+ alog("storm cap");
2347
+ return;
2348
+ }
2265
2349
  try {
2266
2350
  const token = await provider();
2267
2351
  if (token) this.send({ type: "host.auth", token, expiresAt: 0 });
2268
2352
  this.emit({ type: "auth", phase: token ? "granted" : "failed" });
2269
- } catch {
2353
+ alog(token ? "token" : "empty");
2354
+ } catch (e) {
2270
2355
  this.emit({ type: "auth", phase: "failed" });
2356
+ alog("threw", e);
2271
2357
  }
2272
2358
  }
2273
2359
  loadContext() {
@@ -2290,6 +2376,23 @@ var EmbedHost = class {
2290
2376
  this.queue = [];
2291
2377
  for (const m of pending) this.send(m);
2292
2378
  }
2379
+ /**
2380
+ * Push artifact param values into the widget — a PARTIAL patch; only the named
2381
+ * params change. Buffered like every other host→widget message until the widget
2382
+ * says it's listening.
2383
+ *
2384
+ * Explicit and deliberate, so it applies even to a param whose page-context binding
2385
+ * the viewer has overridden (spec §7.3).
2386
+ */
2387
+ setArtifactParams(params) {
2388
+ if (params == null || typeof params !== "object" || Array.isArray(params)) {
2389
+ console.error(
2390
+ "[matterfact] setArtifactParams expects an object of param values"
2391
+ );
2392
+ return;
2393
+ }
2394
+ this.send({ type: "host.artifactParams", params });
2395
+ }
2293
2396
  /** Tear down: stop listening and remove the host element. For the React wrapper's
2294
2397
  * unmount — the vanilla `<script>` loader lives for the page's lifetime and never
2295
2398
  * calls this. */
@@ -2307,6 +2410,10 @@ var EmbedHost = class {
2307
2410
  function mount(config) {
2308
2411
  const host = new EmbedHost(config);
2309
2412
  host.mount();
2413
+ window.matterfact = {
2414
+ ...window.matterfact ?? {},
2415
+ setArtifactParams: (params) => host.setArtifactParams(params)
2416
+ };
2310
2417
  return host;
2311
2418
  }
2312
2419