@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.
- package/README.md +171 -1
- package/dist/chunk-6EM7T2JV.js +816 -0
- package/dist/chunk-6EM7T2JV.js.map +1 -0
- package/dist/{chunk-4Q2ROXLR.js → chunk-BKKXHSYU.js} +2 -2
- package/dist/chunk-FEXG4LQJ.js +3 -0
- package/dist/chunk-FEXG4LQJ.js.map +7 -0
- package/dist/chunk-NWNMS34P.js +2 -0
- package/dist/chunk-URGQBG4I.js +800 -0
- package/dist/chunk-URGQBG4I.js.map +1 -0
- package/dist/context-ACFBWIFH.js +3 -0
- package/dist/{context-YX2KXFLI.js.map → context-ACFBWIFH.js.map} +1 -1
- package/dist/{context-WU2F5CBC.js → context-U2HJJN2S.js} +4 -2
- package/dist/embed.js +1 -1
- package/dist/embed.js.map +4 -4
- package/dist/index.cjs +1006 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +192 -32
- package/dist/index.d.ts +192 -32
- package/dist/index.js +537 -130
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1042 -165
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +81 -1
- package/dist/react.d.ts +81 -1
- package/dist/react.js +566 -132
- package/dist/react.js.map +1 -1
- package/dist/{snapshot-JOGZWESK.js → snapshot-4GXT6PKZ.js} +2 -2
- package/dist/{snapshot-MUXE7KXX.js → snapshot-Y75SCGCM.js} +3 -3
- package/dist/{snapshot-MUXE7KXX.js.map → snapshot-Y75SCGCM.js.map} +1 -1
- package/examples/embed-demo/README.md +37 -0
- package/examples/embed-demo/src/App.tsx +55 -21
- package/examples/embed-demo/src/HoistDemo.tsx +390 -0
- package/examples/embed-demo/src/main.tsx +7 -0
- package/examples/embed-demo/src/mockXH.ts +492 -0
- package/examples/embed-demo/src/placement.tsx +43 -0
- package/examples/embed-demo/src/styles.css +147 -2
- package/examples/embed-demo/vite.config.ts +2 -2
- package/package.json +1 -1
- package/dist/chunk-7I37ZFAJ.js +0 -2
- package/dist/chunk-AXKXNYRT.js +0 -381
- package/dist/chunk-AXKXNYRT.js.map +0 -1
- package/dist/chunk-D7R6WVHG.js +0 -2
- package/dist/chunk-D7R6WVHG.js.map +0 -7
- package/dist/chunk-RS6RMZ77.js +0 -396
- package/dist/chunk-RS6RMZ77.js.map +0 -1
- package/dist/context-YX2KXFLI.js +0 -3
- /package/dist/{chunk-4Q2ROXLR.js.map → chunk-BKKXHSYU.js.map} +0 -0
- /package/dist/{chunk-7I37ZFAJ.js.map → chunk-NWNMS34P.js.map} +0 -0
- /package/dist/{context-WU2F5CBC.js.map → context-U2HJJN2S.js.map} +0 -0
- /package/dist/{snapshot-JOGZWESK.js.map → snapshot-4GXT6PKZ.js.map} +0 -0
|
@@ -86,15 +86,21 @@ nav {
|
|
|
86
86
|
gap: 4px;
|
|
87
87
|
margin-left: 12px;
|
|
88
88
|
}
|
|
89
|
-
nav a
|
|
89
|
+
nav a,
|
|
90
|
+
nav button {
|
|
90
91
|
color: var(--muted);
|
|
91
92
|
text-decoration: none;
|
|
92
93
|
font-size: 13.5px;
|
|
93
94
|
font-weight: 500;
|
|
94
95
|
padding: 6px 11px;
|
|
95
96
|
border-radius: 7px;
|
|
97
|
+
background: none;
|
|
98
|
+
border: 0;
|
|
99
|
+
font-family: inherit;
|
|
100
|
+
cursor: pointer;
|
|
96
101
|
}
|
|
97
|
-
nav a.active
|
|
102
|
+
nav a.active,
|
|
103
|
+
nav button.active {
|
|
98
104
|
color: var(--ink);
|
|
99
105
|
background: var(--surface-2);
|
|
100
106
|
}
|
|
@@ -133,6 +139,33 @@ nav a.active {
|
|
|
133
139
|
background: var(--pos);
|
|
134
140
|
}
|
|
135
141
|
|
|
142
|
+
/* Placement switch (Corner | Panel) — a small segmented control in the header. */
|
|
143
|
+
.placement {
|
|
144
|
+
display: flex;
|
|
145
|
+
border: 1px solid var(--line);
|
|
146
|
+
border-radius: 8px;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
}
|
|
149
|
+
.placement .seg {
|
|
150
|
+
cursor: pointer;
|
|
151
|
+
background: var(--surface-2);
|
|
152
|
+
color: var(--muted);
|
|
153
|
+
border: 0;
|
|
154
|
+
padding: 6px 12px;
|
|
155
|
+
font: inherit;
|
|
156
|
+
font-size: 13px;
|
|
157
|
+
}
|
|
158
|
+
.placement .seg + .seg {
|
|
159
|
+
border-left: 1px solid var(--line);
|
|
160
|
+
}
|
|
161
|
+
.placement .seg:hover {
|
|
162
|
+
color: var(--ink);
|
|
163
|
+
}
|
|
164
|
+
.placement .seg.on {
|
|
165
|
+
background: var(--accent);
|
|
166
|
+
color: #fff;
|
|
167
|
+
}
|
|
168
|
+
|
|
136
169
|
.layout {
|
|
137
170
|
display: grid;
|
|
138
171
|
grid-template-columns: 1fr var(--panel-w);
|
|
@@ -141,6 +174,11 @@ nav a.active {
|
|
|
141
174
|
.app[data-panel='closed'] .layout {
|
|
142
175
|
grid-template-columns: 1fr 0;
|
|
143
176
|
}
|
|
177
|
+
/* Corner placement draws no aside, so the page is all content — the widget
|
|
178
|
+
positions itself over it. */
|
|
179
|
+
.app[data-placement='corner'] .layout {
|
|
180
|
+
grid-template-columns: 1fr;
|
|
181
|
+
}
|
|
144
182
|
|
|
145
183
|
main {
|
|
146
184
|
overflow-y: auto;
|
|
@@ -352,3 +390,110 @@ aside {
|
|
|
352
390
|
.setup li.bad {
|
|
353
391
|
color: var(--neg);
|
|
354
392
|
}
|
|
393
|
+
|
|
394
|
+
/* Hoist mock demo (?hoist=1) — see mockXH.ts / HoistDemo.tsx. Reuses everything
|
|
395
|
+
above (header/layout/table/aside); these are the few bits unique to it. */
|
|
396
|
+
.mode-link {
|
|
397
|
+
color: var(--muted);
|
|
398
|
+
text-decoration: none;
|
|
399
|
+
font-size: 12px;
|
|
400
|
+
border: 1px solid var(--line);
|
|
401
|
+
border-radius: 999px;
|
|
402
|
+
padding: 5px 11px;
|
|
403
|
+
white-space: nowrap;
|
|
404
|
+
}
|
|
405
|
+
.mode-link:hover {
|
|
406
|
+
color: var(--ink);
|
|
407
|
+
border-color: var(--accent);
|
|
408
|
+
}
|
|
409
|
+
.nav-sep {
|
|
410
|
+
color: var(--line);
|
|
411
|
+
padding: 0 2px;
|
|
412
|
+
}
|
|
413
|
+
.hint {
|
|
414
|
+
color: var(--muted);
|
|
415
|
+
font-weight: 500;
|
|
416
|
+
text-transform: none;
|
|
417
|
+
letter-spacing: 0;
|
|
418
|
+
}
|
|
419
|
+
.ticker-link {
|
|
420
|
+
font: inherit;
|
|
421
|
+
font-weight: 700;
|
|
422
|
+
background: none;
|
|
423
|
+
border: 0;
|
|
424
|
+
padding: 0;
|
|
425
|
+
color: var(--ink);
|
|
426
|
+
cursor: pointer;
|
|
427
|
+
}
|
|
428
|
+
.ticker-link:hover {
|
|
429
|
+
color: var(--accent);
|
|
430
|
+
text-decoration: underline;
|
|
431
|
+
}
|
|
432
|
+
.company-subnav {
|
|
433
|
+
display: flex;
|
|
434
|
+
gap: 6px;
|
|
435
|
+
margin-bottom: 20px;
|
|
436
|
+
}
|
|
437
|
+
.subtab {
|
|
438
|
+
font: inherit;
|
|
439
|
+
font-size: 13px;
|
|
440
|
+
font-weight: 600;
|
|
441
|
+
background: var(--surface);
|
|
442
|
+
border: 1px solid var(--line);
|
|
443
|
+
border-radius: 8px;
|
|
444
|
+
padding: 7px 12px;
|
|
445
|
+
cursor: pointer;
|
|
446
|
+
color: var(--muted);
|
|
447
|
+
}
|
|
448
|
+
.subtab.active {
|
|
449
|
+
color: var(--ink);
|
|
450
|
+
border-color: var(--accent);
|
|
451
|
+
background: var(--surface-2);
|
|
452
|
+
}
|
|
453
|
+
.hoist-chart {
|
|
454
|
+
display: block;
|
|
455
|
+
background: var(--surface);
|
|
456
|
+
border: 1px solid var(--line);
|
|
457
|
+
border-radius: 12px;
|
|
458
|
+
margin-bottom: 16px;
|
|
459
|
+
}
|
|
460
|
+
.hoist-actions {
|
|
461
|
+
padding: 10px 14px;
|
|
462
|
+
border-bottom: 1px solid var(--line);
|
|
463
|
+
font-size: 12.5px;
|
|
464
|
+
}
|
|
465
|
+
.hoist-actions label {
|
|
466
|
+
display: flex;
|
|
467
|
+
align-items: center;
|
|
468
|
+
justify-content: space-between;
|
|
469
|
+
gap: 8px;
|
|
470
|
+
color: var(--muted);
|
|
471
|
+
}
|
|
472
|
+
.hoist-actions select {
|
|
473
|
+
font: inherit;
|
|
474
|
+
font-size: 12.5px;
|
|
475
|
+
background: var(--surface-2);
|
|
476
|
+
color: var(--ink);
|
|
477
|
+
border: 1px solid var(--line);
|
|
478
|
+
border-radius: 6px;
|
|
479
|
+
padding: 4px 6px;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* The Hoist demo's nav-policy control, in the header so it survives the corner
|
|
483
|
+
placement (where there is no aside to hold it). */
|
|
484
|
+
.hoist-policy {
|
|
485
|
+
display: flex;
|
|
486
|
+
align-items: center;
|
|
487
|
+
gap: 7px;
|
|
488
|
+
font-size: 12px;
|
|
489
|
+
color: var(--muted);
|
|
490
|
+
}
|
|
491
|
+
.hoist-policy select {
|
|
492
|
+
font: inherit;
|
|
493
|
+
font-size: 12px;
|
|
494
|
+
color: var(--ink);
|
|
495
|
+
background: var(--surface-2);
|
|
496
|
+
border: 1px solid var(--line);
|
|
497
|
+
border-radius: 7px;
|
|
498
|
+
padding: 4px 6px;
|
|
499
|
+
}
|
|
@@ -6,6 +6,6 @@ import react from '@vitejs/plugin-react';
|
|
|
6
6
|
// drifts to a different (unregistered) port.
|
|
7
7
|
export default defineConfig({
|
|
8
8
|
plugins: [react()],
|
|
9
|
-
server: { host: 'localhost', port:
|
|
10
|
-
preview: { host: 'localhost', port:
|
|
9
|
+
server: { host: 'localhost', port: 3010, strictPort: true },
|
|
10
|
+
preview: { host: 'localhost', port: 3010, strictPort: true },
|
|
11
11
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matterfact/embed",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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,
|
package/dist/chunk-7I37ZFAJ.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a,b,c,d,e,f,g,h,i,j,k,l}from"./chunk-D7R6WVHG.js";export{c as artifactIdFromPath,d as buildPageContext,j as callTool,g as grantsFromIframeSrcs,b as isPrivate,f as provideContext,e as readPageContext,a as redact,i as sendRegion,h as sendSnapshot,l as start,k as stop};
|
|
2
|
-
//# sourceMappingURL=chunk-7I37ZFAJ.js.map
|
package/dist/chunk-AXKXNYRT.js
DELETED
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
// src/context.ts
|
|
2
|
-
var widgetOrigin = "";
|
|
3
|
-
var MAX_ACTIVITY = 40;
|
|
4
|
-
var send = null;
|
|
5
|
-
var activitySeq = 0;
|
|
6
|
-
var activity = [];
|
|
7
|
-
var lastUrl = "";
|
|
8
|
-
var pageContextOn = true;
|
|
9
|
-
var contextProvider;
|
|
10
|
-
var navFire = null;
|
|
11
|
-
var origPushState = null;
|
|
12
|
-
var origReplaceState = null;
|
|
13
|
-
var snapshotModule = null;
|
|
14
|
-
var PII = [
|
|
15
|
-
/\b[\w.+-]+@[\w-]+\.[\w.]{2,}\b/g,
|
|
16
|
-
// email
|
|
17
|
-
/\b(?:\d[ -]?){13,19}\b/g,
|
|
18
|
-
// card-ish
|
|
19
|
-
/\b\d{3}[- ]?\d{2}[- ]?\d{4}\b/g,
|
|
20
|
-
// ssn — dashed, spaced, OR bare 9 digits
|
|
21
|
-
/\b\d{9,}\b/g,
|
|
22
|
-
// long bare digit runs: account / MRN / routing numbers
|
|
23
|
-
/(?:\+?\d{1,2}[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b/g,
|
|
24
|
-
// us phone
|
|
25
|
-
/\b(?:sk|pk|rk|ak)_(?:live|test)_[A-Za-z0-9]{8,}\b/g,
|
|
26
|
-
// stripe-style api keys
|
|
27
|
-
/\beyJ[\w-]+\.[\w-]+\.[\w-]+\b/g
|
|
28
|
-
// jwt
|
|
29
|
-
];
|
|
30
|
-
function redact(text) {
|
|
31
|
-
let out = text;
|
|
32
|
-
for (const re of PII) out = out.replace(re, "[redacted]");
|
|
33
|
-
return out;
|
|
34
|
-
}
|
|
35
|
-
function isPrivate(el) {
|
|
36
|
-
if (el.closest("[data-mf-private]")) return true;
|
|
37
|
-
const tag = el.tagName;
|
|
38
|
-
if (tag === "INPUT") {
|
|
39
|
-
const t = el.type;
|
|
40
|
-
if (t === "password" || t === "hidden") return true;
|
|
41
|
-
}
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
function artifactIdFromPath(pathname) {
|
|
45
|
-
const m = pathname.match(/^\/(?:embed\/)?artifacts\/(.+?)\/?$/);
|
|
46
|
-
return m ? decodeURIComponent(m[1]) : null;
|
|
47
|
-
}
|
|
48
|
-
function embeddedMatterfactEntities() {
|
|
49
|
-
if (!widgetOrigin) return [];
|
|
50
|
-
const out = [];
|
|
51
|
-
for (const frame of Array.from(document.querySelectorAll("iframe"))) {
|
|
52
|
-
let u;
|
|
53
|
-
try {
|
|
54
|
-
u = new URL(frame.getAttribute("src") || "", location.href);
|
|
55
|
-
} catch {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
if (u.origin !== widgetOrigin) continue;
|
|
59
|
-
const id = artifactIdFromPath(u.pathname);
|
|
60
|
-
if (!id) continue;
|
|
61
|
-
if (out.some((e) => e.id === id)) continue;
|
|
62
|
-
out.push({
|
|
63
|
-
kind: "artifact",
|
|
64
|
-
id,
|
|
65
|
-
label: redact(frame.getAttribute("title") || "") || id
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
return out;
|
|
69
|
-
}
|
|
70
|
-
function opaqueFrameCount() {
|
|
71
|
-
return Array.from(document.querySelectorAll("iframe")).filter((f) => {
|
|
72
|
-
try {
|
|
73
|
-
const u = new URL(f.getAttribute("src") || "", location.href);
|
|
74
|
-
return u.origin !== location.origin && u.origin !== widgetOrigin;
|
|
75
|
-
} catch {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
}).length;
|
|
79
|
-
}
|
|
80
|
-
function buildPageContext(declared) {
|
|
81
|
-
const found = embeddedMatterfactEntities();
|
|
82
|
-
const opaque = opaqueFrameCount();
|
|
83
|
-
return {
|
|
84
|
-
// Path only. A query string is where session ids, tokens and email addresses
|
|
85
|
-
// live; it is not ours to take.
|
|
86
|
-
url: location.origin + location.pathname,
|
|
87
|
-
path: location.pathname,
|
|
88
|
-
title: redact(document.title),
|
|
89
|
-
locale: document.documentElement.lang || void 0,
|
|
90
|
-
...declared,
|
|
91
|
-
// After the spread: what we FOUND is additive to what the host DECLARED, never a
|
|
92
|
-
// replacement. A host that declares its own entities still gets the artifacts we
|
|
93
|
-
// spotted, and vice versa.
|
|
94
|
-
entities: [...declared.entities ?? [], ...found],
|
|
95
|
-
data: {
|
|
96
|
-
...declared.data ?? {},
|
|
97
|
-
...opaque ? { opaque_frames: opaque } : {}
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
function readPageContext() {
|
|
102
|
-
return buildPageContext(
|
|
103
|
-
window.matterfact?.context ?? {}
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
async function resolveDeclaredContext() {
|
|
107
|
-
const mf = window.matterfact;
|
|
108
|
-
if (contextProvider) {
|
|
109
|
-
const c = await contextProvider();
|
|
110
|
-
if (c) return c;
|
|
111
|
-
}
|
|
112
|
-
if (mf?.getPageContext) {
|
|
113
|
-
const c = await mf.getPageContext();
|
|
114
|
-
if (c) return c;
|
|
115
|
-
}
|
|
116
|
-
return mf?.context ?? {};
|
|
117
|
-
}
|
|
118
|
-
async function publishContext() {
|
|
119
|
-
if (!pageContextOn) return;
|
|
120
|
-
const declared = await resolveDeclaredContext();
|
|
121
|
-
send?.({ type: "host.context", context: buildPageContext(declared) });
|
|
122
|
-
}
|
|
123
|
-
function provideContext() {
|
|
124
|
-
void publishContext();
|
|
125
|
-
}
|
|
126
|
-
function grantsFromIframeSrcs(srcs, origin) {
|
|
127
|
-
const out = [];
|
|
128
|
-
for (const raw of srcs) {
|
|
129
|
-
let u;
|
|
130
|
-
try {
|
|
131
|
-
u = new URL(raw || "", location.href);
|
|
132
|
-
} catch {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
if (u.origin !== origin) continue;
|
|
136
|
-
const id = artifactIdFromPath(u.pathname);
|
|
137
|
-
if (!id) continue;
|
|
138
|
-
const owner = u.searchParams.get("owner") || "";
|
|
139
|
-
const token = u.searchParams.get("t") || "";
|
|
140
|
-
if (!owner || !token) continue;
|
|
141
|
-
if (out.some((g) => g.id === id)) continue;
|
|
142
|
-
out.push({ id, owner, token });
|
|
143
|
-
}
|
|
144
|
-
return out;
|
|
145
|
-
}
|
|
146
|
-
function readArtifactGrants() {
|
|
147
|
-
if (!widgetOrigin) return [];
|
|
148
|
-
const srcs = Array.from(document.querySelectorAll("iframe")).map(
|
|
149
|
-
(f) => f.getAttribute("src") || ""
|
|
150
|
-
);
|
|
151
|
-
return grantsFromIframeSrcs(srcs, widgetOrigin);
|
|
152
|
-
}
|
|
153
|
-
function publishArtifactGrants() {
|
|
154
|
-
send?.({ type: "host.artifactGrants", grants: readArtifactGrants() });
|
|
155
|
-
}
|
|
156
|
-
function pushActivity(e) {
|
|
157
|
-
activity.push({ ...e, seq: ++activitySeq, ts: Date.now() });
|
|
158
|
-
if (activity.length > MAX_ACTIVITY) activity.shift();
|
|
159
|
-
send?.({ type: "host.activity", events: [activity[activity.length - 1]] });
|
|
160
|
-
}
|
|
161
|
-
function controlLabel(el) {
|
|
162
|
-
const aria = el.getAttribute("aria-label");
|
|
163
|
-
if (aria) return aria;
|
|
164
|
-
const id = el.id;
|
|
165
|
-
if (id) {
|
|
166
|
-
const forLabel = document.querySelector(`label[for="${CSS.escape(id)}"]`);
|
|
167
|
-
const t = forLabel?.textContent?.trim();
|
|
168
|
-
if (t) return t;
|
|
169
|
-
}
|
|
170
|
-
const wrapping = el.closest("label")?.textContent?.trim();
|
|
171
|
-
if (wrapping) return wrapping;
|
|
172
|
-
const placeholder = el.getAttribute("placeholder");
|
|
173
|
-
if (placeholder) return placeholder;
|
|
174
|
-
return "";
|
|
175
|
-
}
|
|
176
|
-
var FORM_CONTROLS = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA"]);
|
|
177
|
-
function describe(el) {
|
|
178
|
-
const role = el.getAttribute("role") || el.tagName.toLowerCase();
|
|
179
|
-
const label = el.getAttribute("aria-label") || (FORM_CONTROLS.has(el.tagName) ? controlLabel(el) : el.innerText?.trim().slice(0, 60)) || el.getAttribute("title") || "";
|
|
180
|
-
return label ? `${role} "${redact(label)}"` : role;
|
|
181
|
-
}
|
|
182
|
-
var ACTIONABLE = 'a[href],button,input,select,textarea,summary,[role="button"],[role="link"],[role="menuitem"],[role="tab"],[role="option"],[role="checkbox"],[role="switch"],[role="radio"],[onclick],[tabindex]';
|
|
183
|
-
function onClick(ev) {
|
|
184
|
-
const target = ev.target;
|
|
185
|
-
if (!target || !(target instanceof Element)) return;
|
|
186
|
-
const label = target.closest("label");
|
|
187
|
-
const labelled = label ? label.getAttribute("for") && document.getElementById(label.getAttribute("for")) || label.querySelector("input,select,textarea") : null;
|
|
188
|
-
const actionable = labelled ?? target.closest(ACTIONABLE);
|
|
189
|
-
if (!actionable || isPrivate(actionable)) return;
|
|
190
|
-
pushActivity({ type: "click", summary: `clicked ${describe(actionable)}` });
|
|
191
|
-
}
|
|
192
|
-
function onSubmit(ev) {
|
|
193
|
-
const el = ev.target;
|
|
194
|
-
if (!el || isPrivate(el)) return;
|
|
195
|
-
pushActivity({ type: "submit", summary: `submitted ${describe(el)}` });
|
|
196
|
-
}
|
|
197
|
-
function onChange(ev) {
|
|
198
|
-
const el = ev.target;
|
|
199
|
-
if (!el || !(el instanceof Element) || isPrivate(el)) return;
|
|
200
|
-
const tag = el.tagName;
|
|
201
|
-
const type = el.type;
|
|
202
|
-
if (tag === "INPUT" && (type === "password" || type === "hidden")) return;
|
|
203
|
-
let summary = `changed ${describe(el)}`;
|
|
204
|
-
if (tag === "SELECT") {
|
|
205
|
-
const opt = el.selectedOptions[0]?.text;
|
|
206
|
-
if (opt) summary = `${describe(el)} \u2192 "${redact(opt)}"`;
|
|
207
|
-
} else if (type === "checkbox" || type === "radio") {
|
|
208
|
-
summary = `${el.checked ? "checked" : "unchecked"} ${describe(el)}`;
|
|
209
|
-
}
|
|
210
|
-
pushActivity({ type: "input", summary });
|
|
211
|
-
}
|
|
212
|
-
function watchNavigation() {
|
|
213
|
-
const fire = () => {
|
|
214
|
-
const url = location.pathname;
|
|
215
|
-
if (url === lastUrl) return;
|
|
216
|
-
lastUrl = url;
|
|
217
|
-
pushActivity({ type: "nav", summary: `navigated to ${url}` });
|
|
218
|
-
void publishContext();
|
|
219
|
-
publishArtifactGrants();
|
|
220
|
-
};
|
|
221
|
-
navFire = fire;
|
|
222
|
-
for (const name of ["pushState", "replaceState"]) {
|
|
223
|
-
const orig = history[name];
|
|
224
|
-
if (name === "pushState") origPushState = orig;
|
|
225
|
-
else origReplaceState = orig;
|
|
226
|
-
history[name] = function(...args) {
|
|
227
|
-
const r = orig.apply(this, args);
|
|
228
|
-
fire();
|
|
229
|
-
return r;
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
window.addEventListener("popstate", fire);
|
|
233
|
-
}
|
|
234
|
-
var lastFocus = {};
|
|
235
|
-
async function readFocus() {
|
|
236
|
-
const focus = {};
|
|
237
|
-
const sel = window.getSelection?.();
|
|
238
|
-
if (sel && !sel.isCollapsed) {
|
|
239
|
-
const anchor = sel.anchorNode?.parentElement ?? null;
|
|
240
|
-
if (!anchor || !anchor.closest("[data-mf-private]")) {
|
|
241
|
-
const text = sel.toString().trim().slice(0, 500);
|
|
242
|
-
if (text) focus.selection = redact(text);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const active = document.activeElement;
|
|
246
|
-
if (active && active !== document.body && !isPrivate(active) && !active.closest("[data-mf-private]")) {
|
|
247
|
-
const { snapshot } = await loadSnapshotModule();
|
|
248
|
-
focus.focused = {
|
|
249
|
-
label: redact(describeControl(active)),
|
|
250
|
-
role: active.getAttribute("role") || active.tagName.toLowerCase()
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
const doc = document.documentElement;
|
|
254
|
-
const scrollable = doc.scrollHeight - doc.clientHeight;
|
|
255
|
-
focus.scroll = scrollable > 0 ? Math.round(doc.scrollTop / scrollable * 100) / 100 : 0;
|
|
256
|
-
return focus;
|
|
257
|
-
}
|
|
258
|
-
function describeControl(el) {
|
|
259
|
-
return describe(el);
|
|
260
|
-
}
|
|
261
|
-
async function loadSnapshotModule() {
|
|
262
|
-
const m = await import('./snapshot-MUXE7KXX.js');
|
|
263
|
-
snapshotModule = m;
|
|
264
|
-
return m;
|
|
265
|
-
}
|
|
266
|
-
var focusTimer = null;
|
|
267
|
-
function scheduleFocus() {
|
|
268
|
-
if (focusTimer) return;
|
|
269
|
-
focusTimer = setTimeout(async () => {
|
|
270
|
-
focusTimer = null;
|
|
271
|
-
lastFocus = await readFocus();
|
|
272
|
-
send?.({ type: "host.focus", focus: lastFocus });
|
|
273
|
-
}, 250);
|
|
274
|
-
}
|
|
275
|
-
var snapshotSeq = 0;
|
|
276
|
-
async function sendSnapshot(emit) {
|
|
277
|
-
if (!pageContextOn) return;
|
|
278
|
-
const { snapshot } = await loadSnapshotModule();
|
|
279
|
-
const { yaml, truncated, visibleRefs } = snapshot();
|
|
280
|
-
emit({
|
|
281
|
-
type: "host.snapshot",
|
|
282
|
-
snapshot: { yaml: redact(yaml), seq: ++snapshotSeq, truncated }
|
|
283
|
-
});
|
|
284
|
-
lastFocus = { ...lastFocus, visibleRefs };
|
|
285
|
-
emit({ type: "host.focus", focus: lastFocus });
|
|
286
|
-
}
|
|
287
|
-
async function sendRegion(ref, emit) {
|
|
288
|
-
if (!pageContextOn) return;
|
|
289
|
-
const { snapshotRegion, resolveRef } = await loadSnapshotModule();
|
|
290
|
-
const el = resolveRef(ref);
|
|
291
|
-
if (!el) {
|
|
292
|
-
emit({
|
|
293
|
-
type: "host.region",
|
|
294
|
-
ref,
|
|
295
|
-
yaml: "(this element is no longer on the page)"
|
|
296
|
-
});
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
const { yaml } = snapshotRegion(el);
|
|
300
|
-
emit({ type: "host.region", ref, yaml: redact(yaml) });
|
|
301
|
-
}
|
|
302
|
-
async function callTool(call, emit) {
|
|
303
|
-
emit({
|
|
304
|
-
type: "host.toolResult",
|
|
305
|
-
callId: call.callId,
|
|
306
|
-
ok: false,
|
|
307
|
-
error: "Host tools are read-only in this version; no action was taken."
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
function stop() {
|
|
311
|
-
document.removeEventListener("click", onClick, { capture: true });
|
|
312
|
-
document.removeEventListener("submit", onSubmit, { capture: true });
|
|
313
|
-
document.removeEventListener("change", onChange, { capture: true });
|
|
314
|
-
document.removeEventListener("selectionchange", scheduleFocus);
|
|
315
|
-
document.removeEventListener("focusin", scheduleFocus, { capture: true });
|
|
316
|
-
window.removeEventListener("scroll", scheduleFocus, { capture: true });
|
|
317
|
-
if (navFire) {
|
|
318
|
-
window.removeEventListener("popstate", navFire);
|
|
319
|
-
navFire = null;
|
|
320
|
-
}
|
|
321
|
-
if (origPushState) {
|
|
322
|
-
history.pushState = origPushState;
|
|
323
|
-
origPushState = null;
|
|
324
|
-
}
|
|
325
|
-
if (origReplaceState) {
|
|
326
|
-
history.replaceState = origReplaceState;
|
|
327
|
-
origReplaceState = null;
|
|
328
|
-
}
|
|
329
|
-
if (focusTimer) {
|
|
330
|
-
clearTimeout(focusTimer);
|
|
331
|
-
focusTimer = null;
|
|
332
|
-
}
|
|
333
|
-
send = null;
|
|
334
|
-
contextProvider = void 0;
|
|
335
|
-
activity.length = 0;
|
|
336
|
-
lastFocus = {};
|
|
337
|
-
widgetOrigin = "";
|
|
338
|
-
snapshotModule?.clearRefs();
|
|
339
|
-
}
|
|
340
|
-
function start(emit, origin, pageContext = true, provider) {
|
|
341
|
-
stop();
|
|
342
|
-
send = emit;
|
|
343
|
-
widgetOrigin = origin || "";
|
|
344
|
-
lastUrl = location.pathname;
|
|
345
|
-
pageContextOn = pageContext;
|
|
346
|
-
contextProvider = provider;
|
|
347
|
-
if (pageContextOn) {
|
|
348
|
-
void publishContext();
|
|
349
|
-
publishArtifactGrants();
|
|
350
|
-
watchNavigation();
|
|
351
|
-
document.addEventListener("click", onClick, {
|
|
352
|
-
capture: true,
|
|
353
|
-
passive: true
|
|
354
|
-
});
|
|
355
|
-
document.addEventListener("submit", onSubmit, {
|
|
356
|
-
capture: true,
|
|
357
|
-
passive: true
|
|
358
|
-
});
|
|
359
|
-
document.addEventListener("change", onChange, {
|
|
360
|
-
capture: true,
|
|
361
|
-
passive: true
|
|
362
|
-
});
|
|
363
|
-
document.addEventListener("selectionchange", scheduleFocus, {
|
|
364
|
-
passive: true
|
|
365
|
-
});
|
|
366
|
-
document.addEventListener("focusin", scheduleFocus, {
|
|
367
|
-
capture: true,
|
|
368
|
-
passive: true
|
|
369
|
-
});
|
|
370
|
-
window.addEventListener("scroll", scheduleFocus, {
|
|
371
|
-
capture: true,
|
|
372
|
-
passive: true
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
const theme = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
376
|
-
emit({ type: "host.theme", mode: theme });
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
export { artifactIdFromPath, buildPageContext, callTool, grantsFromIframeSrcs, isPrivate, provideContext, readPageContext, redact, sendRegion, sendSnapshot, start, stop };
|
|
380
|
-
//# sourceMappingURL=chunk-AXKXNYRT.js.map
|
|
381
|
-
//# sourceMappingURL=chunk-AXKXNYRT.js.map
|