@anubhav-choubey/web-for-agents 0.1.0 → 0.3.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 +77 -512
- package/dist/bin.js +6 -6
- package/dist/{chunk-AZG5MLNG.js → chunk-2Y3LLYEC.js} +5 -1
- package/dist/{chunk-IF32TPGR.js → chunk-357ATBMS.js} +369 -130
- package/dist/chunk-4STTPCBR.js +25 -0
- package/dist/chunk-CGIIB6AF.js +127 -0
- package/dist/{chunk-HONWT6GK.js → chunk-K3B53RIO.js} +66 -34
- package/dist/chunk-L3AYWCSX.js +33 -0
- package/dist/chunk-MIVGE5TM.js +34 -0
- package/dist/chunk-OKCYZE6C.js +245 -0
- package/dist/{chunk-5TNG4QMP.js → chunk-PGZH33B5.js} +20 -2
- package/dist/{chunk-ZYMNO5AO.js → chunk-T42S3WRV.js} +161 -62
- package/dist/cli.js +6 -6
- package/dist/{happyDom-XVDHYJDM.js → happyDom-ZEFNMD7B.js} +3 -3
- package/dist/index.d.ts +89 -11
- package/dist/index.js +113 -246
- package/dist/overlay.js +22 -42
- package/dist/{renderChild-Y2RFSYY4.js → renderChild-PSQLAIUW.js} +27 -4
- package/dist/vite.d.ts +116 -3
- package/dist/vite.js +867 -192
- package/package.json +1 -1
- package/dist/chunk-CKXHTGGT.js +0 -25
- package/dist/chunk-FEAKVNMG.js +0 -12
- package/dist/chunk-LCLDQ3A3.js +0 -26
- package/dist/chunk-LCVI2PRP.js +0 -13
package/dist/index.js
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
EMPTY_OBJECT_SCHEMA,
|
|
3
|
+
agentFields,
|
|
4
|
+
hasOwn,
|
|
5
|
+
inDisabledFieldset,
|
|
6
|
+
isConcealed,
|
|
7
|
+
isDisabled,
|
|
8
|
+
schemaFromForm,
|
|
9
|
+
validateFormInput,
|
|
10
|
+
validateInput
|
|
11
|
+
} from "./chunk-OKCYZE6C.js";
|
|
12
|
+
import {
|
|
13
|
+
DESCRIPTION_MAX_CHARS,
|
|
14
|
+
DESCRIPTION_MIN_CHARS,
|
|
15
|
+
TITLE_MAX_CHARS
|
|
16
|
+
} from "./chunk-L3AYWCSX.js";
|
|
5
17
|
import {
|
|
6
18
|
compareStrings
|
|
7
19
|
} from "./chunk-AAIYCJD3.js";
|
|
8
20
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
21
|
+
ACTION_NAME_RULE,
|
|
22
|
+
AGENT_GLOBAL_VERSION,
|
|
23
|
+
isValidActionName
|
|
24
|
+
} from "./chunk-4STTPCBR.js";
|
|
11
25
|
import {
|
|
12
26
|
ACTION_ATTR,
|
|
13
27
|
ACTION_DESCRIPTION_ATTR,
|
|
@@ -17,15 +31,13 @@ import {
|
|
|
17
31
|
CONTENT_ATTR,
|
|
18
32
|
EXCLUDE_ATTR,
|
|
19
33
|
HEAD_OWNED_ATTR,
|
|
20
|
-
HIDDEN_SELECTOR,
|
|
21
34
|
PRERENDERED_ATTR,
|
|
22
35
|
READY_GLOBAL,
|
|
23
|
-
WEBMCP_TOOLPARAMDESCRIPTION_ATTR,
|
|
24
36
|
hasScheme,
|
|
25
37
|
publicUrl,
|
|
26
38
|
resolveUrl,
|
|
27
39
|
routeOf
|
|
28
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-2Y3LLYEC.js";
|
|
29
41
|
import {
|
|
30
42
|
errorMessage,
|
|
31
43
|
withPrefix
|
|
@@ -185,6 +197,7 @@ function flush(doc) {
|
|
|
185
197
|
else merged.set(tag.key, tag);
|
|
186
198
|
}
|
|
187
199
|
}
|
|
200
|
+
if (process.env.NODE_ENV !== "production") warnLengths(merged);
|
|
188
201
|
for (const key of store.applied) if (!merged.has(key)) removeHeadTag(key, doc);
|
|
189
202
|
applyHeadTags([...merged.values()], doc);
|
|
190
203
|
store.applied = new Set(merged.keys());
|
|
@@ -240,6 +253,26 @@ function release() {
|
|
|
240
253
|
}
|
|
241
254
|
}
|
|
242
255
|
var useIsoLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
256
|
+
var warnedLengths = /* @__PURE__ */ new Set();
|
|
257
|
+
function warnLengths(merged) {
|
|
258
|
+
if (process.env.NODE_ENV !== "production") {
|
|
259
|
+
const t = merged.get("title");
|
|
260
|
+
const d = merged.get("name:description");
|
|
261
|
+
const title = t?.kind === "title" ? t.text : void 0;
|
|
262
|
+
const description = d?.kind === "meta" ? d.attrs.content : void 0;
|
|
263
|
+
const once = (value, message) => {
|
|
264
|
+
if (warnedLengths.has(message + value)) return;
|
|
265
|
+
warnedLengths.add(message + value);
|
|
266
|
+
console.warn(`[web-for-agents] ${message}: "${value}"`);
|
|
267
|
+
};
|
|
268
|
+
if (title && title.length > TITLE_MAX_CHARS) {
|
|
269
|
+
once(title, `<Seo> title is ${title.length} characters (over ${TITLE_MAX_CHARS})`);
|
|
270
|
+
}
|
|
271
|
+
if (description && (description.length < DESCRIPTION_MIN_CHARS || description.length > DESCRIPTION_MAX_CHARS)) {
|
|
272
|
+
once(description, `<Seo> description is ${description.length} characters (aim for ${DESCRIPTION_MIN_CHARS}-${DESCRIPTION_MAX_CHARS})`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
243
276
|
var DefaultsContext = createContext({});
|
|
244
277
|
function SeoProvider(props) {
|
|
245
278
|
const { defaults, children } = props;
|
|
@@ -307,6 +340,23 @@ function node(type, fields) {
|
|
|
307
340
|
for (const [k, v] of Object.entries(fields)) if (v !== void 0) out[k] = v;
|
|
308
341
|
return out;
|
|
309
342
|
}
|
|
343
|
+
function definedOnly(o) {
|
|
344
|
+
return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
345
|
+
}
|
|
346
|
+
function nested(n) {
|
|
347
|
+
const { "@context": _context, ...rest } = n;
|
|
348
|
+
return rest;
|
|
349
|
+
}
|
|
350
|
+
function offer(o) {
|
|
351
|
+
if (o === void 0) return void 0;
|
|
352
|
+
return {
|
|
353
|
+
"@type": "Offer",
|
|
354
|
+
price: o.price,
|
|
355
|
+
priceCurrency: o.priceCurrency,
|
|
356
|
+
availability: o.availability && `https://schema.org/${o.availability}`,
|
|
357
|
+
url: o.url
|
|
358
|
+
};
|
|
359
|
+
}
|
|
310
360
|
var schema = {
|
|
311
361
|
article(i) {
|
|
312
362
|
const { author, ...rest } = i;
|
|
@@ -320,13 +370,7 @@ var schema = {
|
|
|
320
370
|
return node("Product", {
|
|
321
371
|
...rest,
|
|
322
372
|
brand: brand === void 0 ? void 0 : { "@type": "Brand", name: brand },
|
|
323
|
-
offers: offers
|
|
324
|
-
"@type": "Offer",
|
|
325
|
-
price: offers.price,
|
|
326
|
-
priceCurrency: offers.priceCurrency,
|
|
327
|
-
availability: offers.availability && `https://schema.org/${offers.availability}`,
|
|
328
|
-
url: offers.url
|
|
329
|
-
}
|
|
373
|
+
offers: offer(offers)
|
|
330
374
|
});
|
|
331
375
|
},
|
|
332
376
|
faqPage(items) {
|
|
@@ -361,6 +405,41 @@ var schema = {
|
|
|
361
405
|
"query-input": "required name=search_term_string"
|
|
362
406
|
} : void 0
|
|
363
407
|
});
|
|
408
|
+
},
|
|
409
|
+
person(i) {
|
|
410
|
+
const { worksFor, ...rest } = i;
|
|
411
|
+
return node("Person", {
|
|
412
|
+
...rest,
|
|
413
|
+
worksFor: worksFor === void 0 ? void 0 : typeof worksFor === "string" ? { "@type": "Organization", name: worksFor } : definedOnly({ "@type": "Organization", name: worksFor.name, url: worksFor.url })
|
|
414
|
+
});
|
|
415
|
+
},
|
|
416
|
+
softwareApplication(i) {
|
|
417
|
+
const { offers, aggregateRating, author, ...rest } = i;
|
|
418
|
+
return node("SoftwareApplication", {
|
|
419
|
+
...rest,
|
|
420
|
+
offers: offer(offers),
|
|
421
|
+
aggregateRating: aggregateRating === void 0 ? void 0 : { "@type": "AggregateRating", ...definedOnly(aggregateRating) },
|
|
422
|
+
author: author === void 0 ? void 0 : person(author)
|
|
423
|
+
});
|
|
424
|
+
},
|
|
425
|
+
profilePage(i) {
|
|
426
|
+
return node("ProfilePage", { ...i, mainEntity: nested(i.mainEntity) });
|
|
427
|
+
},
|
|
428
|
+
creativeWork(i) {
|
|
429
|
+
const { author, keywords, ...rest } = i;
|
|
430
|
+
return node("CreativeWork", {
|
|
431
|
+
...rest,
|
|
432
|
+
author: author === void 0 ? void 0 : person(author),
|
|
433
|
+
keywords: Array.isArray(keywords) ? keywords.join(", ") : keywords
|
|
434
|
+
});
|
|
435
|
+
},
|
|
436
|
+
webPage(i) {
|
|
437
|
+
const { breadcrumb, ...rest } = i;
|
|
438
|
+
return node("WebPage", { ...rest, breadcrumb: breadcrumb && nested(breadcrumb) });
|
|
439
|
+
},
|
|
440
|
+
/** One `@graph` document from several nodes; each node's own `@context` is dropped in favour of a single top-level one. */
|
|
441
|
+
graph(nodes) {
|
|
442
|
+
return { "@context": "https://schema.org", "@graph": nodes.map(nested) };
|
|
364
443
|
}
|
|
365
444
|
};
|
|
366
445
|
|
|
@@ -416,229 +495,9 @@ function hydrateApp(container, app, options) {
|
|
|
416
495
|
// src/runtime/agent/react.tsx
|
|
417
496
|
import { useCallback, useEffect as useEffect2, useLayoutEffect as useLayoutEffect2, useRef as useRef2 } from "react";
|
|
418
497
|
|
|
419
|
-
// src/shared/
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
// src/runtime/agent/dom.ts
|
|
423
|
-
var INERT_OR_CLOSED = "[inert], dialog:not([open]), details:not([open]) > :not(summary)";
|
|
424
|
-
var CONCEALED = `${HIDDEN_SELECTOR}, ${INERT_OR_CLOSED}`;
|
|
425
|
-
function inDisabledFieldset(el) {
|
|
426
|
-
for (let child = el, p = el.parentElement; p; child = p, p = p.parentElement) {
|
|
427
|
-
if (p.matches("fieldset[disabled]") && child !== p.querySelector(":scope > legend")) return true;
|
|
428
|
-
}
|
|
429
|
-
return false;
|
|
430
|
-
}
|
|
431
|
-
function isDisabled(el) {
|
|
432
|
-
return el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true" || inDisabledFieldset(el);
|
|
433
|
-
}
|
|
434
|
-
function isConcealed(el) {
|
|
435
|
-
if (!el.closest(CONCEALED)) return false;
|
|
436
|
-
const labels = el.tagName === "INPUT" && /^(checkbox|radio)$/.test(el.type) ? el.labels : null;
|
|
437
|
-
return !(labels && el.getAttribute("aria-hidden") !== "true" && !el.matches(INERT_OR_CLOSED) && !el.parentElement?.closest(CONCEALED) && Array.from(labels).some((l) => !isConcealed(l) && !isDisabled(l)));
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// src/runtime/agent/formSchema.ts
|
|
441
|
-
var EMPTY_OBJECT_SCHEMA = Object.freeze({
|
|
442
|
-
type: "object",
|
|
443
|
-
properties: Object.freeze({}),
|
|
444
|
-
additionalProperties: false
|
|
445
|
-
});
|
|
446
|
-
var EXCLUDED_TYPES = /* @__PURE__ */ new Set(["hidden", "password", "file", "submit", "button", "reset", "image"]);
|
|
447
|
-
function isAgentField(e) {
|
|
448
|
-
const tag = e.tagName;
|
|
449
|
-
if (tag !== "INPUT" && tag !== "SELECT" && tag !== "TEXTAREA") return false;
|
|
450
|
-
if (!e.getAttribute("name")) return false;
|
|
451
|
-
if (e.hasAttribute("disabled") || e.hasAttribute("readonly") || inDisabledFieldset(e)) return false;
|
|
452
|
-
if (tag === "INPUT" && EXCLUDED_TYPES.has((e.getAttribute("type") ?? "text").toLowerCase())) return false;
|
|
453
|
-
return !isConcealed(e);
|
|
454
|
-
}
|
|
455
|
-
function agentFields(form) {
|
|
456
|
-
const groups = /* @__PURE__ */ new Map();
|
|
457
|
-
for (const el of Array.from(form.elements)) {
|
|
458
|
-
if (!isAgentField(el)) continue;
|
|
459
|
-
const name = el.getAttribute("name");
|
|
460
|
-
const list = groups.get(name);
|
|
461
|
-
if (list) list.push(el);
|
|
462
|
-
else groups.set(name, [el]);
|
|
463
|
-
}
|
|
464
|
-
return groups;
|
|
465
|
-
}
|
|
466
|
-
function labelText(el) {
|
|
467
|
-
const labels = el.labels ? Array.from(el.labels) : [];
|
|
468
|
-
if (labels.length === 0) {
|
|
469
|
-
const wrap = el.closest("label");
|
|
470
|
-
if (wrap) labels.push(wrap);
|
|
471
|
-
}
|
|
472
|
-
return collapseWhitespace(
|
|
473
|
-
labels.map((l) => {
|
|
474
|
-
const c = l.cloneNode(true);
|
|
475
|
-
c.querySelectorAll("input,select,textarea,button").forEach((n) => n.remove());
|
|
476
|
-
return c.textContent;
|
|
477
|
-
}).join(" ")
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
function describe(el) {
|
|
481
|
-
return collapseWhitespace(el.getAttribute(ACTION_PARAM_ATTR)) || collapseWhitespace(el.getAttribute(WEBMCP_TOOLPARAMDESCRIPTION_ATTR)) || labelText(el) || collapseWhitespace(el.getAttribute("aria-label")) || collapseWhitespace(el.getAttribute("placeholder"));
|
|
482
|
-
}
|
|
483
|
-
function num(el, attr) {
|
|
484
|
-
const v = el.getAttribute(attr);
|
|
485
|
-
if (v === null || v.trim() === "") return void 0;
|
|
486
|
-
const n = Number(v);
|
|
487
|
-
return Number.isFinite(n) ? n : void 0;
|
|
488
|
-
}
|
|
489
|
-
function inputSchema(el) {
|
|
490
|
-
const type = el instanceof HTMLTextAreaElement ? "textarea" : (el.getAttribute("type") ?? "text").toLowerCase();
|
|
491
|
-
const s = {};
|
|
492
|
-
if (type === "checkbox") {
|
|
493
|
-
s.type = "boolean";
|
|
494
|
-
return s;
|
|
495
|
-
}
|
|
496
|
-
if (type === "number" || type === "range") {
|
|
497
|
-
const step = el.getAttribute("step");
|
|
498
|
-
s.type = step === null || /^\d+$/.test(step.trim()) ? "integer" : "number";
|
|
499
|
-
const min = num(el, "min");
|
|
500
|
-
const max = num(el, "max");
|
|
501
|
-
if (min !== void 0) s.minimum = min;
|
|
502
|
-
if (max !== void 0) s.maximum = max;
|
|
503
|
-
return s;
|
|
504
|
-
}
|
|
505
|
-
s.type = "string";
|
|
506
|
-
if (type === "email") s.format = "email";
|
|
507
|
-
else if (type === "url") s.format = "uri";
|
|
508
|
-
else if (type === "date") s.format = "date";
|
|
509
|
-
else if (type === "time") s.format = "time";
|
|
510
|
-
const minLength = num(el, "minlength");
|
|
511
|
-
const maxLength = num(el, "maxlength");
|
|
512
|
-
if (minLength !== void 0) s.minLength = minLength;
|
|
513
|
-
if (maxLength !== void 0) s.maxLength = maxLength;
|
|
514
|
-
const pattern = el.getAttribute("pattern");
|
|
515
|
-
if (pattern) s.pattern = `^(?:${pattern})$`;
|
|
516
|
-
return s;
|
|
517
|
-
}
|
|
518
|
-
function withDescription(s, desc) {
|
|
519
|
-
if (desc) s.description = desc;
|
|
520
|
-
return s;
|
|
521
|
-
}
|
|
522
|
-
function selectSchema(sel, desc) {
|
|
523
|
-
const opts = Array.from(sel.querySelectorAll("option")).filter((o) => !o.hasAttribute("disabled") && !o.hasAttribute("hidden") && !o.closest("optgroup[disabled]")).map((o) => ({ value: o.getAttribute("value") ?? collapseWhitespace(o.textContent), label: collapseWhitespace(o.textContent) })).filter((o) => o.value !== "");
|
|
524
|
-
const values = opts.map((o) => o.value);
|
|
525
|
-
const list = opts.map((o) => o.label && o.label !== o.value ? `${o.value} (${o.label})` : o.value).join(", ");
|
|
526
|
-
const schema2 = sel.hasAttribute("multiple") ? { type: "array", items: { type: "string", enum: values } } : { type: "string", enum: values };
|
|
527
|
-
return withDescription(schema2, [desc, `Options: ${list}`].filter(Boolean).join(". "));
|
|
528
|
-
}
|
|
529
|
-
var isType = (e, t) => e.tagName === "INPUT" && (e.getAttribute("type") ?? "").toLowerCase() === t;
|
|
530
|
-
function groupSchema(els) {
|
|
531
|
-
const first = els[0];
|
|
532
|
-
const desc = els.map(describe).find(Boolean) ?? "";
|
|
533
|
-
if (first.tagName === "SELECT") return selectSchema(first, desc);
|
|
534
|
-
const values = () => els.map((e) => e.getAttribute("value") ?? "on");
|
|
535
|
-
if (els.every((e) => isType(e, "radio"))) return withDescription({ type: "string", enum: values() }, desc);
|
|
536
|
-
if (els.length > 1 && els.every((e) => isType(e, "checkbox"))) {
|
|
537
|
-
return withDescription({ type: "array", items: { type: "string", enum: values() } }, desc);
|
|
538
|
-
}
|
|
539
|
-
return withDescription(inputSchema(first), desc);
|
|
540
|
-
}
|
|
541
|
-
function schemaFromForm(form) {
|
|
542
|
-
const properties = /* @__PURE__ */ Object.create(null);
|
|
543
|
-
const required = [];
|
|
544
|
-
for (const [name, els] of agentFields(form)) {
|
|
545
|
-
properties[name] = groupSchema(els);
|
|
546
|
-
if (els.some((e) => e.hasAttribute("required"))) required.push(name);
|
|
547
|
-
}
|
|
548
|
-
const out = { type: "object", properties, additionalProperties: false };
|
|
549
|
-
if (required.length) out.required = required;
|
|
550
|
-
return out;
|
|
551
|
-
}
|
|
552
|
-
var MAX_REGEX_INPUT = 1e4;
|
|
553
|
-
function checkValue(s, v, field, errors) {
|
|
554
|
-
const bad = (message) => {
|
|
555
|
-
errors.push({ field, message });
|
|
556
|
-
};
|
|
557
|
-
switch (s.type) {
|
|
558
|
-
case "string":
|
|
559
|
-
if (typeof v !== "string") return bad("must be string");
|
|
560
|
-
break;
|
|
561
|
-
case "number":
|
|
562
|
-
if (typeof v !== "number" || !Number.isFinite(v)) return bad("must be number");
|
|
563
|
-
break;
|
|
564
|
-
case "integer":
|
|
565
|
-
if (typeof v !== "number" || !Number.isInteger(v)) return bad("must be integer");
|
|
566
|
-
break;
|
|
567
|
-
case "boolean":
|
|
568
|
-
if (typeof v !== "boolean") return bad("must be boolean");
|
|
569
|
-
break;
|
|
570
|
-
case "array":
|
|
571
|
-
if (!Array.isArray(v)) return bad("must be array");
|
|
572
|
-
break;
|
|
573
|
-
case "object":
|
|
574
|
-
if (!isPlainObject(v)) return bad("must be object");
|
|
575
|
-
checkObject(s, v, `${field}.`, errors);
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (s.enum && !s.enum.includes(v)) {
|
|
579
|
-
return bad(`must be one of: ${s.enum.join(", ")}`);
|
|
580
|
-
}
|
|
581
|
-
if (typeof v === "string") {
|
|
582
|
-
if (s.minLength !== void 0 && v.length < s.minLength) bad(`must be at least ${s.minLength} characters`);
|
|
583
|
-
if (s.maxLength !== void 0 && v.length > s.maxLength) bad(`must be at most ${s.maxLength} characters`);
|
|
584
|
-
if ((s.pattern !== void 0 || s.format === "email") && v.length > MAX_REGEX_INPUT) {
|
|
585
|
-
return bad(`must be at most ${MAX_REGEX_INPUT} characters to be checked`);
|
|
586
|
-
}
|
|
587
|
-
if (s.pattern !== void 0) {
|
|
588
|
-
let ok = false;
|
|
589
|
-
try {
|
|
590
|
-
ok = new RegExp(s.pattern).test(v);
|
|
591
|
-
} catch {
|
|
592
|
-
ok = false;
|
|
593
|
-
}
|
|
594
|
-
if (!ok) bad(`must match pattern ${s.pattern}`);
|
|
595
|
-
}
|
|
596
|
-
if (s.format === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)) bad("must be a valid email");
|
|
597
|
-
if (s.format === "uri") {
|
|
598
|
-
try {
|
|
599
|
-
new URL(v);
|
|
600
|
-
} catch {
|
|
601
|
-
bad("must be a valid URI");
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
if (typeof v === "number") {
|
|
606
|
-
if (s.minimum !== void 0 && v < s.minimum) bad(`must be >= ${s.minimum}`);
|
|
607
|
-
if (s.maximum !== void 0 && v > s.maximum) bad(`must be <= ${s.maximum}`);
|
|
608
|
-
}
|
|
609
|
-
if (Array.isArray(v) && s.items) {
|
|
610
|
-
v.forEach((item, i) => checkValue(s.items, item, `${field}[${i}]`, errors));
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
function isPlainObject(v) {
|
|
614
|
-
if (typeof v !== "object" || v === null) return false;
|
|
615
|
-
const proto = Object.getPrototypeOf(v);
|
|
616
|
-
return proto === Object.prototype || proto === null;
|
|
617
|
-
}
|
|
618
|
-
function checkObject(schema2, obj, prefix, errors) {
|
|
619
|
-
const props = schema2.properties ?? {};
|
|
620
|
-
for (const name of schema2.required ?? []) {
|
|
621
|
-
if (!hasOwn(obj, name) || obj[name] === void 0) errors.push({ field: prefix + name, message: "is required" });
|
|
622
|
-
}
|
|
623
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
624
|
-
const prop = props[key];
|
|
625
|
-
if (!hasOwn(props, key) || !prop) {
|
|
626
|
-
if (schema2.additionalProperties !== true) errors.push({ field: prefix + key, message: "is not an allowed field" });
|
|
627
|
-
continue;
|
|
628
|
-
}
|
|
629
|
-
if (value === void 0) continue;
|
|
630
|
-
checkValue(prop, value, prefix + key, errors);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
function validateInput(schema2, input) {
|
|
634
|
-
if (!isPlainObject(input)) return { ok: false, errors: [{ field: "", message: "input must be an object" }] };
|
|
635
|
-
const errors = [];
|
|
636
|
-
checkObject(schema2, input, "", errors);
|
|
637
|
-
return errors.length ? { ok: false, errors } : { ok: true, value: input };
|
|
638
|
-
}
|
|
639
|
-
function validateFormInput(schema2, input) {
|
|
640
|
-
const r = validateInput({ ...schema2, additionalProperties: true }, input);
|
|
641
|
-
return r.ok ? r : validateInput(schema2, input);
|
|
498
|
+
// src/shared/actionName.ts
|
|
499
|
+
function assertValidActionName(name) {
|
|
500
|
+
if (!isValidActionName(name)) throw new Error(withPrefix(`invalid action name "${name}": ${ACTION_NAME_RULE}`));
|
|
642
501
|
}
|
|
643
502
|
|
|
644
503
|
// src/runtime/agent/formAutomation.ts
|
|
@@ -794,11 +653,6 @@ var nextId = 1;
|
|
|
794
653
|
var syncScheduled = false;
|
|
795
654
|
var forceScheduled = false;
|
|
796
655
|
var CONFIRM_BUDGET = 1e3;
|
|
797
|
-
function assertValidActionName(name) {
|
|
798
|
-
if (!isValidActionName(name)) {
|
|
799
|
-
throw new Error(withPrefix(`invalid action name "${name}": use 1-128 chars of A-Z a-z 0-9 _ - .`));
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
656
|
function installGlobal() {
|
|
803
657
|
if (typeof window === "undefined") return;
|
|
804
658
|
const w = window;
|
|
@@ -850,7 +704,7 @@ function schemaOf(r) {
|
|
|
850
704
|
}
|
|
851
705
|
return r.spec.inputSchema ?? EMPTY_OBJECT_SCHEMA;
|
|
852
706
|
}
|
|
853
|
-
function
|
|
707
|
+
function describe(name, entry) {
|
|
854
708
|
const r = resolve(entry);
|
|
855
709
|
if (r.kind === null) return null;
|
|
856
710
|
const d = {
|
|
@@ -865,7 +719,7 @@ function describe2(name, entry) {
|
|
|
865
719
|
return d;
|
|
866
720
|
}
|
|
867
721
|
function listAgentActions() {
|
|
868
|
-
return Array.from(activeEntries(), ([name, [, entry]]) =>
|
|
722
|
+
return Array.from(activeEntries(), ([name, [, entry]]) => describe(name, entry)).filter((d) => d !== null).sort((a, b) => compareStrings(a.name, b.name));
|
|
869
723
|
}
|
|
870
724
|
var UNSAFE = /[\0-\t\v-\x1F\x7F-\x9F\xAD\u061C\u200B\u200E\u200F\u2028-\u202E\u2060\u2066-\u2069\uFEFF]/g;
|
|
871
725
|
var UNIT = /\\u[\da-f]{4}|\\[^]|[^]/giu;
|
|
@@ -981,7 +835,7 @@ function warnUndescribable(name, err) {
|
|
|
981
835
|
function buildTool(name, entry) {
|
|
982
836
|
let d;
|
|
983
837
|
try {
|
|
984
|
-
d =
|
|
838
|
+
d = describe(name, entry);
|
|
985
839
|
} catch (err) {
|
|
986
840
|
warnUndescribable(name, err);
|
|
987
841
|
return null;
|
|
@@ -1113,6 +967,18 @@ function AgentForm(props) {
|
|
|
1113
967
|
function agentParam(description) {
|
|
1114
968
|
return { [ACTION_PARAM_ATTR]: description };
|
|
1115
969
|
}
|
|
970
|
+
|
|
971
|
+
// src/runtime/agent/link.ts
|
|
972
|
+
function agentLinkProps(spec) {
|
|
973
|
+
assertValidActionName(spec.name);
|
|
974
|
+
const props = {
|
|
975
|
+
[ACTION_ATTR]: spec.name,
|
|
976
|
+
[ACTION_DESCRIPTION_ATTR]: spec.description,
|
|
977
|
+
"aria-description": spec.description
|
|
978
|
+
};
|
|
979
|
+
if (spec.destructive) props[ACTION_DESTRUCTIVE_ATTR] = "true";
|
|
980
|
+
return props;
|
|
981
|
+
}
|
|
1116
982
|
export {
|
|
1117
983
|
AgentForm,
|
|
1118
984
|
CONTENT_ATTR,
|
|
@@ -1124,6 +990,7 @@ export {
|
|
|
1124
990
|
READY_GLOBAL,
|
|
1125
991
|
Seo,
|
|
1126
992
|
SeoProvider,
|
|
993
|
+
agentLinkProps,
|
|
1127
994
|
agentParam,
|
|
1128
995
|
executeAgentAction,
|
|
1129
996
|
holdPrerender,
|
package/dist/overlay.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CONTENT_SELECTOR,
|
|
3
3
|
DEFAULT_SHORTCUT,
|
|
4
|
+
INVALID_NAME_REASON,
|
|
5
|
+
actionGroups,
|
|
4
6
|
buildPageMarkdown,
|
|
7
|
+
firstPerName,
|
|
8
|
+
markupActions,
|
|
5
9
|
matchesShortcut,
|
|
6
10
|
parseShortcut,
|
|
7
11
|
readPageMeta,
|
|
12
|
+
resolveLinkHref,
|
|
8
13
|
selectContentRegion
|
|
9
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-T42S3WRV.js";
|
|
10
15
|
import {
|
|
11
16
|
compareStrings
|
|
12
17
|
} from "./chunk-AAIYCJD3.js";
|
|
13
18
|
import {
|
|
14
19
|
jsonLdTypes
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import
|
|
20
|
+
} from "./chunk-MIVGE5TM.js";
|
|
21
|
+
import {
|
|
22
|
+
isValidActionName
|
|
23
|
+
} from "./chunk-4STTPCBR.js";
|
|
17
24
|
import {
|
|
18
|
-
ACTION_ATTR,
|
|
19
|
-
ACTION_DESCRIPTION_ATTR,
|
|
20
|
-
ACTION_DESTRUCTIVE_ATTR,
|
|
21
25
|
AGENT_GLOBAL,
|
|
22
|
-
WEBMCP_TOOLDESCRIPTION_ATTR,
|
|
23
|
-
WEBMCP_TOOLNAME_ATTR,
|
|
24
26
|
routeOf,
|
|
25
27
|
trimTrailingSlash
|
|
26
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-2Y3LLYEC.js";
|
|
27
29
|
import {
|
|
28
30
|
errorMessage
|
|
29
31
|
} from "./chunk-JJN6FNJD.js";
|
|
@@ -67,39 +69,15 @@ function registryActions(doc) {
|
|
|
67
69
|
return [];
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
|
-
function collectActions(doc) {
|
|
71
|
-
const markup =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
description: el2.getAttribute(ACTION_DESCRIPTION_ATTR) || null,
|
|
78
|
-
kind: el2.tagName === "FORM" ? "form" : "click",
|
|
79
|
-
destructive: el2.getAttribute(ACTION_DESTRUCTIVE_ATTR) === "true",
|
|
80
|
-
source: "markup"
|
|
81
|
-
});
|
|
72
|
+
function collectActions(doc, pageUrl) {
|
|
73
|
+
const markup = markupActions(doc).map(({ name, description, kind, destructive, source, href }) => {
|
|
74
|
+
const a = { name, description, kind, destructive, source };
|
|
75
|
+
if (!isValidActionName(name)) return { ...a, warning: `Not listed in agents.json: ${INVALID_NAME_REASON}` };
|
|
76
|
+
if (kind !== "link") return a;
|
|
77
|
+
const r = resolveLinkHref(href ?? "", pageUrl);
|
|
78
|
+
return r.ok ? { ...a, href: r.href } : { ...a, warning: `Not listed in agents.json: ${r.reason}` };
|
|
82
79
|
});
|
|
83
|
-
|
|
84
|
-
doc.querySelectorAll(`form[${WEBMCP_TOOLNAME_ATTR}]`).forEach((el2) => {
|
|
85
|
-
const name = el2.getAttribute(WEBMCP_TOOLNAME_ATTR)?.trim();
|
|
86
|
-
if (!name) return;
|
|
87
|
-
declarative.push({
|
|
88
|
-
name,
|
|
89
|
-
description: el2.getAttribute(WEBMCP_TOOLDESCRIPTION_ATTR) || null,
|
|
90
|
-
kind: "form",
|
|
91
|
-
destructive: false,
|
|
92
|
-
source: "webmcp-declarative"
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
const seen = /* @__PURE__ */ new Set();
|
|
96
|
-
const out = [];
|
|
97
|
-
for (const a of [...registryActions(doc), ...markup, ...declarative]) {
|
|
98
|
-
if (seen.has(a.name)) continue;
|
|
99
|
-
seen.add(a.name);
|
|
100
|
-
out.push(a);
|
|
101
|
-
}
|
|
102
|
-
return out.sort((a, b) => compareStrings(a.name, b.name));
|
|
80
|
+
return firstPerName(registryActions(doc), ...actionGroups(markup)).sort((a, b) => compareStrings(a.name, b.name));
|
|
103
81
|
}
|
|
104
82
|
function collectPageReport(doc = document, opts = {}) {
|
|
105
83
|
const url = doc.location?.href ?? "";
|
|
@@ -135,7 +113,7 @@ function collectPageReport(doc = document, opts = {}) {
|
|
|
135
113
|
} catch {
|
|
136
114
|
}
|
|
137
115
|
try {
|
|
138
|
-
actions = collectActions(doc);
|
|
116
|
+
actions = collectActions(doc, pageUrl);
|
|
139
117
|
} catch {
|
|
140
118
|
}
|
|
141
119
|
return { url, meta, jsonLd, content, actions };
|
|
@@ -206,6 +184,8 @@ function renderPanel(root, report) {
|
|
|
206
184
|
const line = [a.name, a.kind, a.source, a.destructive ? "destructive" : ""].filter(Boolean).join(" \xB7 ");
|
|
207
185
|
actions.append(el(doc, "div", "action", el(doc, "strong", void 0, a.name), line.slice(a.name.length)));
|
|
208
186
|
if (a.description) actions.append(el(doc, "div", "note", a.description));
|
|
187
|
+
if (a.href) actions.append(el(doc, "div", "note", a.href));
|
|
188
|
+
if (a.warning) actions.append(el(doc, "p", "warn", a.warning));
|
|
209
189
|
}
|
|
210
190
|
const refresh = el(doc, "button", "btn", "Refresh");
|
|
211
191
|
refresh.setAttribute("type", "button");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-PGZH33B5.js";
|
|
2
2
|
import {
|
|
3
3
|
errorMessage
|
|
4
4
|
} from "./chunk-JJN6FNJD.js";
|
|
@@ -196,13 +196,35 @@ function isSyncResources(v) {
|
|
|
196
196
|
(r) => r !== null && typeof r === "object" && typeof r.body === "string" && typeof r.contentType === "string"
|
|
197
197
|
);
|
|
198
198
|
}
|
|
199
|
+
function parseChildOptions(json) {
|
|
200
|
+
const o = JSON.parse(json);
|
|
201
|
+
if (o === null || typeof o !== "object" || Array.isArray(o)) throw new Error("render options are not an object");
|
|
202
|
+
const v = o;
|
|
203
|
+
const bad = (field, want) => {
|
|
204
|
+
throw new Error(`render option ${field} must be ${want}, got ${JSON.stringify(v[field])}`);
|
|
205
|
+
};
|
|
206
|
+
const strings = (x) => Array.isArray(x) && x.every((s) => typeof s === "string");
|
|
207
|
+
if (!strings(v.localOrigins)) bad("localOrigins", "an array of strings");
|
|
208
|
+
if (v.allowOrigins !== void 0 && !strings(v.allowOrigins)) bad("allowOrigins", "an array of strings");
|
|
209
|
+
if (v.idleMs !== void 0 && !(typeof v.idleMs === "number" && Number.isInteger(v.idleMs) && v.idleMs >= 0)) {
|
|
210
|
+
bad("idleMs", "a non-negative integer");
|
|
211
|
+
}
|
|
212
|
+
if (v.readySelector !== void 0 && !(typeof v.readySelector === "string" && v.readySelector.trim() !== "")) {
|
|
213
|
+
bad("readySelector", "a non-empty string");
|
|
214
|
+
}
|
|
215
|
+
if (v.onTimeout !== void 0 && v.onTimeout !== "fail" && v.onTimeout !== "snapshot") {
|
|
216
|
+
bad("onTimeout", '"fail" or "snapshot"');
|
|
217
|
+
}
|
|
218
|
+
if (v.syncResources !== void 0 && !isSyncResources(v.syncResources)) bad("syncResources", "a resources object");
|
|
219
|
+
return o;
|
|
220
|
+
}
|
|
199
221
|
async function runRenderChild() {
|
|
200
222
|
const send = (m) => process.send(m);
|
|
201
|
-
const options =
|
|
223
|
+
const options = parseChildOptions(process.env[CHILD_OPTIONS_ENV] ?? "{}");
|
|
202
224
|
const allow = createAllowList();
|
|
203
225
|
for (const o of [...options.localOrigins ?? [], ...options.allowOrigins ?? []]) allowOrigin(allow, o);
|
|
204
226
|
containNetwork(allow);
|
|
205
|
-
const { createHappyDomRenderer } = await import("./happyDom-
|
|
227
|
+
const { createHappyDomRenderer } = await import("./happyDom-ZEFNMD7B.js");
|
|
206
228
|
const renderer = createHappyDomRenderer(options);
|
|
207
229
|
process.on("message", (m) => {
|
|
208
230
|
if (m.type === "resources") {
|
|
@@ -241,5 +263,6 @@ export {
|
|
|
241
263
|
CHILD_ENTRY,
|
|
242
264
|
CHILD_ENV,
|
|
243
265
|
CHILD_OPTIONS_ENV,
|
|
244
|
-
isSyncResources
|
|
266
|
+
isSyncResources,
|
|
267
|
+
parseChildOptions
|
|
245
268
|
};
|