auto-webmcp 0.2.5 → 0.2.7
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/dist/analyzer.d.ts.map +1 -1
- package/dist/auto-webmcp.cjs.js +87 -16
- package/dist/auto-webmcp.cjs.js.map +3 -3
- package/dist/auto-webmcp.esm.js +87 -16
- package/dist/auto-webmcp.esm.js.map +3 -3
- package/dist/auto-webmcp.iife.js +2 -2
- package/dist/auto-webmcp.iife.js.map +3 -3
- package/dist/interceptor.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/auto-webmcp.esm.js
CHANGED
|
@@ -173,7 +173,7 @@ function buildStringSchema(input) {
|
|
|
173
173
|
return prop;
|
|
174
174
|
}
|
|
175
175
|
function mapSelectElement(select) {
|
|
176
|
-
const filtered = Array.from(select.options).filter((o) => o.value !== "");
|
|
176
|
+
const filtered = Array.from(select.options).filter((o) => o.value !== "" && !o.disabled);
|
|
177
177
|
if (filtered.length === 0) {
|
|
178
178
|
return { type: "string" };
|
|
179
179
|
}
|
|
@@ -435,6 +435,12 @@ function resolveNativeControlFallbackKey(control) {
|
|
|
435
435
|
const label = control.getAttribute("aria-label");
|
|
436
436
|
if (label)
|
|
437
437
|
return sanitizeName(label);
|
|
438
|
+
if ((control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) && control.placeholder?.trim()) {
|
|
439
|
+
return sanitizeName(control.placeholder.trim());
|
|
440
|
+
}
|
|
441
|
+
if (control instanceof HTMLInputElement && control.type !== "text") {
|
|
442
|
+
return control.type;
|
|
443
|
+
}
|
|
438
444
|
return null;
|
|
439
445
|
}
|
|
440
446
|
function collectAriaControls(form) {
|
|
@@ -519,6 +525,9 @@ function inferFieldTitle(control) {
|
|
|
519
525
|
return humanizeName(control.name);
|
|
520
526
|
if (control.id)
|
|
521
527
|
return humanizeName(control.id);
|
|
528
|
+
if ((control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) && control.placeholder?.trim()) {
|
|
529
|
+
return control.placeholder.trim();
|
|
530
|
+
}
|
|
522
531
|
return "";
|
|
523
532
|
}
|
|
524
533
|
function inferFieldDescription(control) {
|
|
@@ -659,6 +668,7 @@ init_registry();
|
|
|
659
668
|
var pendingExecutions = /* @__PURE__ */ new WeakMap();
|
|
660
669
|
var lastParams = /* @__PURE__ */ new WeakMap();
|
|
661
670
|
var formFieldElements = /* @__PURE__ */ new WeakMap();
|
|
671
|
+
var pendingWarnings = /* @__PURE__ */ new WeakMap();
|
|
662
672
|
var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
663
673
|
var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
|
|
664
674
|
var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
|
|
@@ -673,22 +683,36 @@ function buildExecuteHandler(form, config, toolName, metadata) {
|
|
|
673
683
|
return new Promise((resolve, reject) => {
|
|
674
684
|
pendingExecutions.set(form, { resolve, reject });
|
|
675
685
|
if (config.autoSubmit || form.hasAttribute("toolautosubmit") || form.dataset["webmcpAutosubmit"] !== void 0) {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
686
|
+
waitForDomStable(form).then(async () => {
|
|
687
|
+
try {
|
|
688
|
+
fillFormFields(form, params);
|
|
689
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
690
|
+
const reset = getResetFields(form, params, formFieldElements.get(form));
|
|
691
|
+
if (reset.length === 0)
|
|
692
|
+
break;
|
|
693
|
+
fillFormFields(form, params);
|
|
694
|
+
await waitForDomStable(form, 400, 100);
|
|
695
|
+
}
|
|
696
|
+
let submitForm = form;
|
|
697
|
+
if (!form.isConnected) {
|
|
698
|
+
const liveBtn = document.querySelector(
|
|
699
|
+
'button[type="submit"]:not([disabled]), input[type="submit"]:not([disabled])'
|
|
700
|
+
);
|
|
701
|
+
const found = liveBtn?.closest("form");
|
|
702
|
+
if (found) {
|
|
703
|
+
submitForm = found;
|
|
704
|
+
pendingExecutions.set(submitForm, { resolve, reject });
|
|
705
|
+
attachSubmitInterceptor(submitForm, toolName);
|
|
706
|
+
}
|
|
688
707
|
}
|
|
708
|
+
const missing = getMissingRequired(metadata, params);
|
|
709
|
+
if (missing.length > 0)
|
|
710
|
+
pendingWarnings.set(submitForm, missing);
|
|
711
|
+
submitForm.requestSubmit();
|
|
712
|
+
} catch (err) {
|
|
713
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
689
714
|
}
|
|
690
|
-
|
|
691
|
-
}, 300);
|
|
715
|
+
});
|
|
692
716
|
}
|
|
693
717
|
});
|
|
694
718
|
};
|
|
@@ -704,7 +728,10 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
704
728
|
const { resolve } = pending;
|
|
705
729
|
pendingExecutions.delete(form);
|
|
706
730
|
const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
|
|
707
|
-
const
|
|
731
|
+
const missing = pendingWarnings.get(form);
|
|
732
|
+
pendingWarnings.delete(form);
|
|
733
|
+
const warningText = missing?.length ? ` Note: required fields were not filled: ${missing.join(", ")}.` : "";
|
|
734
|
+
const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
|
|
708
735
|
const result = { content: [{ type: "text", text }] };
|
|
709
736
|
if (e.agentInvoked && typeof e.respondWith === "function") {
|
|
710
737
|
e.preventDefault();
|
|
@@ -910,6 +937,50 @@ function fillElement(el, value) {
|
|
|
910
937
|
fillAriaField(el, value);
|
|
911
938
|
}
|
|
912
939
|
}
|
|
940
|
+
function waitForDomStable(form, maxMs = 800, debounceMs = 150) {
|
|
941
|
+
return new Promise((resolve) => {
|
|
942
|
+
let settled = false;
|
|
943
|
+
let debounceTimer = null;
|
|
944
|
+
const settle = () => {
|
|
945
|
+
if (settled)
|
|
946
|
+
return;
|
|
947
|
+
settled = true;
|
|
948
|
+
observer2.disconnect();
|
|
949
|
+
if (debounceTimer !== null)
|
|
950
|
+
clearTimeout(debounceTimer);
|
|
951
|
+
resolve();
|
|
952
|
+
};
|
|
953
|
+
const observer2 = new MutationObserver(() => {
|
|
954
|
+
if (debounceTimer !== null)
|
|
955
|
+
clearTimeout(debounceTimer);
|
|
956
|
+
debounceTimer = setTimeout(settle, debounceMs);
|
|
957
|
+
});
|
|
958
|
+
observer2.observe(form, { childList: true, subtree: true, attributes: true, characterData: true });
|
|
959
|
+
setTimeout(settle, maxMs);
|
|
960
|
+
debounceTimer = setTimeout(settle, debounceMs);
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
function getResetFields(form, params, fieldEls) {
|
|
964
|
+
const reset = [];
|
|
965
|
+
for (const [key, expected] of Object.entries(params)) {
|
|
966
|
+
const el = findNativeField(form, key) ?? (fieldEls?.get(key) ?? null);
|
|
967
|
+
if (!el)
|
|
968
|
+
continue;
|
|
969
|
+
if (el instanceof HTMLInputElement && el.type === "checkbox") {
|
|
970
|
+
if (el.checked !== Boolean(expected))
|
|
971
|
+
reset.push(key);
|
|
972
|
+
} else if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
973
|
+
if (el.value !== String(expected ?? ""))
|
|
974
|
+
reset.push(key);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return reset;
|
|
978
|
+
}
|
|
979
|
+
function getMissingRequired(metadata, params) {
|
|
980
|
+
if (!metadata?.inputSchema?.required?.length)
|
|
981
|
+
return [];
|
|
982
|
+
return metadata.inputSchema.required.filter((fieldKey) => !(fieldKey in params));
|
|
983
|
+
}
|
|
913
984
|
|
|
914
985
|
// src/enhancer.ts
|
|
915
986
|
async function enrichMetadata(metadata, enhancer) {
|