simple-webmcp 0.2.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 +30 -12
- package/dist/devtools.d.cts +2 -2
- package/dist/devtools.d.ts +2 -2
- package/dist/index.cjs +313 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -34
- package/dist/index.d.ts +60 -34
- package/dist/index.js +307 -5
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.cts +2 -2
- package/dist/inspect.d.ts +2 -2
- package/dist/react.cjs +353 -12
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +23 -2
- package/dist/react.d.ts +23 -2
- package/dist/react.js +353 -15
- package/dist/react.js.map +1 -1
- package/dist/{registry-BcPw1qCf.d.cts → registry-A4DdpmDn.d.cts} +1 -1
- package/dist/{registry-C6Pz_Rja.d.ts → registry-Dscedahn.d.ts} +1 -1
- package/dist/{types-DH78HDAE.d.cts → types-CF8kTj5O.d.cts} +60 -1
- package/dist/{types-DH78HDAE.d.ts → types-CF8kTj5O.d.ts} +60 -1
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { jsxs, Fragment
|
|
1
|
+
import { createContext, useContext, useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/internal/utils.ts
|
|
5
5
|
function toSnakeCase(name) {
|
|
@@ -79,6 +79,11 @@ var RegistrationError = class extends SimpleWebMCPError {
|
|
|
79
79
|
super(message, "REGISTRATION_ERROR", opts?.cause);
|
|
80
80
|
}
|
|
81
81
|
};
|
|
82
|
+
var ValidationError = class extends SimpleWebMCPError {
|
|
83
|
+
constructor(message, opts) {
|
|
84
|
+
super(message, "VALIDATION_ERROR", opts?.cause);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
82
87
|
var ConfigurationError = class extends SimpleWebMCPError {
|
|
83
88
|
constructor(message, opts) {
|
|
84
89
|
super(message, "CONFIGURATION_ERROR", opts?.cause);
|
|
@@ -585,7 +590,12 @@ function normalizeResult(value) {
|
|
|
585
590
|
}
|
|
586
591
|
}
|
|
587
592
|
function normalizeError(err) {
|
|
588
|
-
const message =
|
|
593
|
+
const message = (() => {
|
|
594
|
+
if (err instanceof Error) return err.message;
|
|
595
|
+
if (typeof err === "string") return err;
|
|
596
|
+
if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
597
|
+
return err.message;
|
|
598
|
+
}
|
|
589
599
|
try {
|
|
590
600
|
return JSON.stringify(err);
|
|
591
601
|
} catch {
|
|
@@ -597,20 +607,247 @@ function normalizeError(err) {
|
|
|
597
607
|
isError: true
|
|
598
608
|
};
|
|
599
609
|
}
|
|
600
|
-
|
|
610
|
+
|
|
611
|
+
// src/hooks/engine.ts
|
|
612
|
+
var fallbackCounter = 0;
|
|
613
|
+
function genInvocationId() {
|
|
614
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
615
|
+
return crypto.randomUUID();
|
|
616
|
+
}
|
|
617
|
+
return fallbackInvocationId();
|
|
618
|
+
}
|
|
619
|
+
function fallbackInvocationId() {
|
|
620
|
+
fallbackCounter = (fallbackCounter + 1) % Number.MAX_SAFE_INTEGER;
|
|
621
|
+
return `webmcp_${Date.now().toString(36)}_${fallbackCounter}_${Math.random().toString(36).slice(2, 8)}`;
|
|
622
|
+
}
|
|
623
|
+
function isDenyResult(r) {
|
|
624
|
+
return !!r && typeof r === "object" && r.action === "deny";
|
|
625
|
+
}
|
|
626
|
+
async function runErrorHooks(hooks, ctx) {
|
|
627
|
+
if (!hooks || hooks.length === 0) return;
|
|
628
|
+
for (const h of hooks) {
|
|
629
|
+
try {
|
|
630
|
+
await h(ctx);
|
|
631
|
+
} catch {
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
async function runDeniedHooks(hooks, ctx) {
|
|
636
|
+
if (!hooks || hooks.length === 0) return;
|
|
637
|
+
for (const h of hooks) {
|
|
638
|
+
try {
|
|
639
|
+
await h(ctx);
|
|
640
|
+
} catch {
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
function createHookedExecute(fn, tool, contract, options) {
|
|
601
645
|
return async (args, _ctx) => {
|
|
646
|
+
const invocationId = genInvocationId();
|
|
647
|
+
const metadata = {};
|
|
648
|
+
const signal = tool.__activeSignal ?? createNeverAbortedSignal();
|
|
649
|
+
const merged = options.getHooks();
|
|
650
|
+
let currentInput = args;
|
|
651
|
+
const base = { invocationId, tool, contract, signal, metadata };
|
|
652
|
+
const beforeHooks = merged.before ?? [];
|
|
653
|
+
for (const hook of beforeHooks) {
|
|
654
|
+
if (signal.aborted) {
|
|
655
|
+
const abortErr = new DOMException("Aborted", "AbortError");
|
|
656
|
+
await runErrorHooks(merged.error, {
|
|
657
|
+
...base,
|
|
658
|
+
input: currentInput,
|
|
659
|
+
error: abortErr
|
|
660
|
+
});
|
|
661
|
+
return normalizeError(abortErr);
|
|
662
|
+
}
|
|
663
|
+
let res;
|
|
664
|
+
try {
|
|
665
|
+
const ctx = { ...base, input: currentInput };
|
|
666
|
+
res = await hook(ctx);
|
|
667
|
+
} catch (hookErr) {
|
|
668
|
+
await runErrorHooks(merged.error, {
|
|
669
|
+
...base,
|
|
670
|
+
input: currentInput,
|
|
671
|
+
error: hookErr
|
|
672
|
+
});
|
|
673
|
+
return normalizeError(hookErr);
|
|
674
|
+
}
|
|
675
|
+
if (res != null && typeof res === "object") {
|
|
676
|
+
if (isDenyResult(res)) {
|
|
677
|
+
const reason = res.message;
|
|
678
|
+
const code = res.code;
|
|
679
|
+
await runDeniedHooks(merged.denied, {
|
|
680
|
+
...base,
|
|
681
|
+
input: currentInput,
|
|
682
|
+
reason,
|
|
683
|
+
code
|
|
684
|
+
});
|
|
685
|
+
const msg = reason ?? "Tool execution denied";
|
|
686
|
+
return {
|
|
687
|
+
content: [{ type: "text", text: `Denied: ${msg}` }],
|
|
688
|
+
isError: true,
|
|
689
|
+
...code ? { code } : {}
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
if ("input" in res && res.input !== void 0) {
|
|
693
|
+
currentInput = res.input;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (signal.aborted) {
|
|
698
|
+
const abortErr = new DOMException("Aborted", "AbortError");
|
|
699
|
+
await runErrorHooks(merged.error, {
|
|
700
|
+
...base,
|
|
701
|
+
input: currentInput,
|
|
702
|
+
error: abortErr
|
|
703
|
+
});
|
|
704
|
+
return normalizeError(abortErr);
|
|
705
|
+
}
|
|
706
|
+
if (options.validate) {
|
|
707
|
+
try {
|
|
708
|
+
options.validate(currentInput);
|
|
709
|
+
} catch (valErr) {
|
|
710
|
+
await runErrorHooks(merged.error, {
|
|
711
|
+
...base,
|
|
712
|
+
input: currentInput,
|
|
713
|
+
error: valErr
|
|
714
|
+
});
|
|
715
|
+
return normalizeError(valErr);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
let rawOutput;
|
|
602
719
|
try {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
720
|
+
rawOutput = await fn(currentInput);
|
|
721
|
+
} catch (fnErr) {
|
|
722
|
+
await runErrorHooks(merged.error, {
|
|
723
|
+
...base,
|
|
724
|
+
input: currentInput,
|
|
725
|
+
error: fnErr
|
|
726
|
+
});
|
|
727
|
+
return normalizeError(fnErr);
|
|
728
|
+
}
|
|
729
|
+
let currentOutput = rawOutput;
|
|
730
|
+
const afterHooks = merged.after ?? [];
|
|
731
|
+
for (const hook of afterHooks) {
|
|
732
|
+
if (signal.aborted) ;
|
|
733
|
+
try {
|
|
734
|
+
const ctx = {
|
|
735
|
+
...base,
|
|
736
|
+
input: currentInput,
|
|
737
|
+
output: currentOutput
|
|
738
|
+
};
|
|
739
|
+
const res = await hook(ctx);
|
|
740
|
+
if (res != null && typeof res === "object" && "output" in res && res.output !== void 0) {
|
|
741
|
+
currentOutput = res.output;
|
|
742
|
+
}
|
|
743
|
+
} catch (hookErr) {
|
|
744
|
+
await runErrorHooks(merged.error, {
|
|
745
|
+
...base,
|
|
746
|
+
input: currentInput,
|
|
747
|
+
error: hookErr
|
|
748
|
+
});
|
|
749
|
+
return normalizeError(hookErr);
|
|
607
750
|
}
|
|
608
|
-
return normalizeResult(result);
|
|
609
|
-
} catch (err) {
|
|
610
|
-
return normalizeError(err);
|
|
611
751
|
}
|
|
752
|
+
return normalizeResult(currentOutput);
|
|
612
753
|
};
|
|
613
754
|
}
|
|
755
|
+
function createNeverAbortedSignal() {
|
|
756
|
+
try {
|
|
757
|
+
return new AbortController().signal;
|
|
758
|
+
} catch {
|
|
759
|
+
return {
|
|
760
|
+
aborted: false,
|
|
761
|
+
addEventListener() {
|
|
762
|
+
},
|
|
763
|
+
removeEventListener() {
|
|
764
|
+
},
|
|
765
|
+
dispatchEvent() {
|
|
766
|
+
return false;
|
|
767
|
+
},
|
|
768
|
+
onabort: null,
|
|
769
|
+
reason: void 0,
|
|
770
|
+
throwIfAborted() {
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/hooks/config.ts
|
|
777
|
+
var GLOBAL_KEY = "__simpleWebmcp_hooks";
|
|
778
|
+
function getStore() {
|
|
779
|
+
const g = globalThis;
|
|
780
|
+
if (!g[GLOBAL_KEY]) {
|
|
781
|
+
g[GLOBAL_KEY] = { hooks: {} };
|
|
782
|
+
}
|
|
783
|
+
return g[GLOBAL_KEY];
|
|
784
|
+
}
|
|
785
|
+
function getGlobalHooks() {
|
|
786
|
+
return getStore().hooks ?? {};
|
|
787
|
+
}
|
|
788
|
+
function configureWebMCP(opts) {
|
|
789
|
+
const store = getStore();
|
|
790
|
+
if (!opts.hooks) return;
|
|
791
|
+
if (opts.replace) {
|
|
792
|
+
store.hooks = normalizeHooks(opts.hooks);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
store.hooks = mergeHooks(store.hooks, opts.hooks);
|
|
796
|
+
}
|
|
797
|
+
function resetGlobalHooks() {
|
|
798
|
+
const store = getStore();
|
|
799
|
+
store.hooks = {};
|
|
800
|
+
}
|
|
801
|
+
function normalizeHooks(hooks) {
|
|
802
|
+
return {
|
|
803
|
+
before: hooks.before ? [...hooks.before] : void 0,
|
|
804
|
+
after: hooks.after ? [...hooks.after] : void 0,
|
|
805
|
+
error: hooks.error ? [...hooks.error] : void 0,
|
|
806
|
+
denied: hooks.denied ? [...hooks.denied] : void 0
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
function mergeHooks(a, b) {
|
|
810
|
+
if (!a && !b) return {};
|
|
811
|
+
if (!a) return normalizeHooks(b);
|
|
812
|
+
if (!b) return a;
|
|
813
|
+
return {
|
|
814
|
+
before: [...a.before ?? [], ...b.before ?? []],
|
|
815
|
+
after: [...a.after ?? [], ...b.after ?? []],
|
|
816
|
+
error: [...a.error ?? [], ...b.error ?? []],
|
|
817
|
+
denied: [...a.denied ?? [], ...b.denied ?? []]
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
function mergeHooksOrdered(opts) {
|
|
821
|
+
const globalHooks = opts.globalHooks ?? {};
|
|
822
|
+
const scopedHooks = opts.scopedHooks ?? {};
|
|
823
|
+
const toolHooks = opts.toolHooks ?? {};
|
|
824
|
+
const before = [
|
|
825
|
+
...globalHooks.before ?? [],
|
|
826
|
+
...scopedHooks.before ?? [],
|
|
827
|
+
...toolHooks.before ?? []
|
|
828
|
+
];
|
|
829
|
+
const after = [
|
|
830
|
+
...toolHooks.after ?? [],
|
|
831
|
+
...scopedHooks.after ?? [],
|
|
832
|
+
...globalHooks.after ?? []
|
|
833
|
+
];
|
|
834
|
+
const error = [
|
|
835
|
+
...toolHooks.error ?? [],
|
|
836
|
+
...scopedHooks.error ?? [],
|
|
837
|
+
...globalHooks.error ?? []
|
|
838
|
+
];
|
|
839
|
+
const denied = [
|
|
840
|
+
...toolHooks.denied ?? [],
|
|
841
|
+
...scopedHooks.denied ?? [],
|
|
842
|
+
...globalHooks.denied ?? []
|
|
843
|
+
];
|
|
844
|
+
const out = {};
|
|
845
|
+
if (before.length) out.before = before;
|
|
846
|
+
if (after.length) out.after = after;
|
|
847
|
+
if (error.length) out.error = error;
|
|
848
|
+
if (denied.length) out.denied = denied;
|
|
849
|
+
return out;
|
|
850
|
+
}
|
|
614
851
|
|
|
615
852
|
// src/webmcp.ts
|
|
616
853
|
function resolveScope(opts) {
|
|
@@ -625,8 +862,24 @@ function webmcp(fn, options) {
|
|
|
625
862
|
const anyFn = fn;
|
|
626
863
|
if (anyFn.__webmcpBrand === true && anyFn.definition) {
|
|
627
864
|
if (!options || Object.keys(options).length === 0) return anyFn;
|
|
865
|
+
const prevOpts = anyFn.__webmcpOptions || {};
|
|
866
|
+
const mergedOpts = { ...prevOpts, ...options };
|
|
867
|
+
if (prevOpts.hooks || options?.hooks) {
|
|
868
|
+
const prevHooks = prevOpts.hooks ?? {};
|
|
869
|
+
const nextHooks = options.hooks ?? {};
|
|
870
|
+
mergedOpts.hooks = {
|
|
871
|
+
before: [...prevHooks.before ?? [], ...nextHooks.before ?? []],
|
|
872
|
+
after: [...prevHooks.after ?? [], ...nextHooks.after ?? []],
|
|
873
|
+
error: [...prevHooks.error ?? [], ...nextHooks.error ?? []],
|
|
874
|
+
denied: [...prevHooks.denied ?? [], ...nextHooks.denied ?? []]
|
|
875
|
+
};
|
|
876
|
+
for (const k of ["before", "after", "error", "denied"]) {
|
|
877
|
+
if (mergedOpts.hooks[k]?.length === 0) delete mergedOpts.hooks[k];
|
|
878
|
+
}
|
|
879
|
+
if (mergedOpts.hooks && Object.keys(mergedOpts.hooks).length === 0) delete mergedOpts.hooks;
|
|
880
|
+
}
|
|
628
881
|
const original = anyFn.__fn ?? fn;
|
|
629
|
-
return webmcp(original,
|
|
882
|
+
return webmcp(original, mergedOpts);
|
|
630
883
|
}
|
|
631
884
|
const name = options?.name ?? toSnakeCase(getFunctionName(fn));
|
|
632
885
|
if (!name) throw new ConfigurationError('Tool name could not be inferred \u2014 pass {name:"my_tool"}');
|
|
@@ -679,15 +932,30 @@ function webmcp(fn, options) {
|
|
|
679
932
|
let registrationPromise = null;
|
|
680
933
|
let unregisterFn = null;
|
|
681
934
|
let activeController = null;
|
|
682
|
-
const
|
|
935
|
+
const toolHooks = options?.hooks ? { ...options.hooks } : void 0;
|
|
683
936
|
const toolWrapper = wrapper;
|
|
684
937
|
toolWrapper.__webmcpBrand = true;
|
|
685
938
|
toolWrapper.__fn = fn;
|
|
686
939
|
toolWrapper.__webmcpOptions = options;
|
|
687
940
|
if (standard) toolWrapper.__standardSchema = standard;
|
|
688
941
|
if (outNorm.standard) toolWrapper.__outputStandardSchema = outNorm.standard;
|
|
942
|
+
if (toolHooks) toolWrapper.__hooks = toolHooks;
|
|
689
943
|
toolWrapper.tool = contract;
|
|
690
944
|
toolWrapper.definition = contract;
|
|
945
|
+
const hookedExec = createHookedExecute(fn, toolWrapper, contract, {
|
|
946
|
+
getHooks: () => {
|
|
947
|
+
const globalHooks = getGlobalHooks();
|
|
948
|
+
const scopeHooks = toolWrapper.__scopeHooks;
|
|
949
|
+
return mergeHooksOrdered({ globalHooks, scopedHooks: scopeHooks, toolHooks });
|
|
950
|
+
},
|
|
951
|
+
validate: standard ? (input) => {
|
|
952
|
+
const res = standard["~standard"].validate(input);
|
|
953
|
+
if ("issues" in res && res.issues && res.issues.length > 0) {
|
|
954
|
+
const msg = res.issues.map((i) => i.message).join("; ");
|
|
955
|
+
throw new ValidationError(`Validation failed: ${msg}`);
|
|
956
|
+
}
|
|
957
|
+
} : void 0
|
|
958
|
+
});
|
|
691
959
|
Object.defineProperty(toolWrapper, "status", {
|
|
692
960
|
get() {
|
|
693
961
|
return status;
|
|
@@ -720,11 +988,16 @@ function webmcp(fn, options) {
|
|
|
720
988
|
status = "registering";
|
|
721
989
|
const controller = new AbortController();
|
|
722
990
|
activeController = controller;
|
|
991
|
+
toolWrapper.__activeSignal = controller.signal;
|
|
723
992
|
if (opts?.signal) {
|
|
724
993
|
if (opts.signal.aborted) {
|
|
725
994
|
controller.abort();
|
|
726
995
|
status = "unregistered";
|
|
727
996
|
activeController = null;
|
|
997
|
+
try {
|
|
998
|
+
delete toolWrapper.__activeSignal;
|
|
999
|
+
} catch {
|
|
1000
|
+
}
|
|
728
1001
|
return () => {
|
|
729
1002
|
};
|
|
730
1003
|
}
|
|
@@ -739,11 +1012,15 @@ function webmcp(fn, options) {
|
|
|
739
1012
|
controller.signal.addEventListener("abort", () => {
|
|
740
1013
|
if (status !== "unregistered") status = "unregistered";
|
|
741
1014
|
activeController = null;
|
|
1015
|
+
try {
|
|
1016
|
+
delete toolWrapper.__activeSignal;
|
|
1017
|
+
} catch {
|
|
1018
|
+
}
|
|
742
1019
|
}, { once: true });
|
|
743
1020
|
try {
|
|
744
1021
|
const unregister = await registry.register(contract, {
|
|
745
1022
|
signal: controller.signal,
|
|
746
|
-
execute:
|
|
1023
|
+
execute: hookedExec
|
|
747
1024
|
});
|
|
748
1025
|
unregisterFn = unregister;
|
|
749
1026
|
registrationPromise = Promise.resolve();
|
|
@@ -761,6 +1038,10 @@ function webmcp(fn, options) {
|
|
|
761
1038
|
}
|
|
762
1039
|
status = "unregistered";
|
|
763
1040
|
activeController = null;
|
|
1041
|
+
try {
|
|
1042
|
+
delete toolWrapper.__activeSignal;
|
|
1043
|
+
} catch {
|
|
1044
|
+
}
|
|
764
1045
|
unregisterFn = null;
|
|
765
1046
|
};
|
|
766
1047
|
} catch (err) {
|
|
@@ -769,6 +1050,11 @@ function webmcp(fn, options) {
|
|
|
769
1050
|
} else {
|
|
770
1051
|
status = "error";
|
|
771
1052
|
}
|
|
1053
|
+
activeController = null;
|
|
1054
|
+
try {
|
|
1055
|
+
delete toolWrapper.__activeSignal;
|
|
1056
|
+
} catch {
|
|
1057
|
+
}
|
|
772
1058
|
registrationPromise = Promise.reject(err);
|
|
773
1059
|
if (err instanceof SimpleWebMCPError) throw err;
|
|
774
1060
|
throw err;
|
|
@@ -787,6 +1073,10 @@ function webmcp(fn, options) {
|
|
|
787
1073
|
}
|
|
788
1074
|
status = "unregistered";
|
|
789
1075
|
activeController = null;
|
|
1076
|
+
try {
|
|
1077
|
+
delete toolWrapper.__activeSignal;
|
|
1078
|
+
} catch {
|
|
1079
|
+
}
|
|
790
1080
|
unregisterFn = null;
|
|
791
1081
|
registrationPromise = null;
|
|
792
1082
|
};
|
|
@@ -805,9 +1095,30 @@ function webmcp(fn, options) {
|
|
|
805
1095
|
webmcp.global = function global(fn, opts) {
|
|
806
1096
|
return webmcp(fn, { ...opts, global: true });
|
|
807
1097
|
};
|
|
1098
|
+
webmcp.configure = configureWebMCP;
|
|
1099
|
+
webmcp.getGlobalHooks = getGlobalHooks;
|
|
1100
|
+
webmcp.resetGlobalHooks = resetGlobalHooks;
|
|
808
1101
|
webmcp.isWebMCPTool = function isWebMCPTool(v) {
|
|
809
1102
|
return !!v?.__webmcpBrand;
|
|
810
1103
|
};
|
|
1104
|
+
var WebMCPHooksContext = createContext({});
|
|
1105
|
+
function WebMCPProvider({ hooks, children }) {
|
|
1106
|
+
const parent = useContext(WebMCPHooksContext);
|
|
1107
|
+
const merged = useMemo(() => {
|
|
1108
|
+
if (!hooks) return parent;
|
|
1109
|
+
if (!parent || Object.keys(parent).length === 0) return hooks;
|
|
1110
|
+
return {
|
|
1111
|
+
before: [...parent.before ?? [], ...hooks.before ?? []],
|
|
1112
|
+
after: [...parent.after ?? [], ...hooks.after ?? []],
|
|
1113
|
+
error: [...parent.error ?? [], ...hooks.error ?? []],
|
|
1114
|
+
denied: [...parent.denied ?? [], ...hooks.denied ?? []]
|
|
1115
|
+
};
|
|
1116
|
+
}, [parent, hooks]);
|
|
1117
|
+
return /* @__PURE__ */ jsx(WebMCPHooksContext.Provider, { value: merged, children });
|
|
1118
|
+
}
|
|
1119
|
+
function useWebMCPHooksContext() {
|
|
1120
|
+
return useContext(WebMCPHooksContext);
|
|
1121
|
+
}
|
|
811
1122
|
|
|
812
1123
|
// src/react/useWebMCP.ts
|
|
813
1124
|
function isTool(v) {
|
|
@@ -815,6 +1126,7 @@ function isTool(v) {
|
|
|
815
1126
|
}
|
|
816
1127
|
function useWebMCP(arg, opts) {
|
|
817
1128
|
const enabled = opts?.enabled ?? true;
|
|
1129
|
+
const scopedHooks = useWebMCPHooksContext();
|
|
818
1130
|
const isRawFunction = useMemo(() => {
|
|
819
1131
|
return typeof arg === "function" && !isTool(arg);
|
|
820
1132
|
}, [arg]);
|
|
@@ -836,6 +1148,7 @@ function useWebMCP(arg, opts) {
|
|
|
836
1148
|
opts?.global,
|
|
837
1149
|
opts?.strict,
|
|
838
1150
|
opts?.outputSchema,
|
|
1151
|
+
opts?.hooks,
|
|
839
1152
|
opts?.enabled
|
|
840
1153
|
]);
|
|
841
1154
|
const [registered, setRegistered] = useState(false);
|
|
@@ -848,6 +1161,31 @@ function useWebMCP(arg, opts) {
|
|
|
848
1161
|
}, [supported]);
|
|
849
1162
|
const toolRef = useRef(tool);
|
|
850
1163
|
toolRef.current = tool;
|
|
1164
|
+
useEffect(() => {
|
|
1165
|
+
const t = toolRef.current;
|
|
1166
|
+
const hasScoped = scopedHooks && Object.keys(scopedHooks).length > 0;
|
|
1167
|
+
if (hasScoped) t.__scopeHooks = scopedHooks;
|
|
1168
|
+
else if (t.__scopeHooks) delete t.__scopeHooks;
|
|
1169
|
+
return () => {
|
|
1170
|
+
const cur = t.__scopeHooks;
|
|
1171
|
+
if (cur === scopedHooks) {
|
|
1172
|
+
try {
|
|
1173
|
+
delete t.__scopeHooks;
|
|
1174
|
+
} catch {
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
}, [scopedHooks, tool]);
|
|
1179
|
+
if (scopedHooks && Object.keys(scopedHooks).length > 0) {
|
|
1180
|
+
tool.__scopeHooks = scopedHooks;
|
|
1181
|
+
} else if (tool.__scopeHooks) {
|
|
1182
|
+
if (!(scopedHooks && Object.keys(scopedHooks).length > 0)) {
|
|
1183
|
+
try {
|
|
1184
|
+
delete tool.__scopeHooks;
|
|
1185
|
+
} catch {
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
851
1189
|
useEffect(() => {
|
|
852
1190
|
if (!enabled) {
|
|
853
1191
|
setRegistered(false);
|
|
@@ -938,6 +1276,6 @@ function Scope({ tools, enabled = true, children }) {
|
|
|
938
1276
|
}
|
|
939
1277
|
var WebMCPScope = Scope;
|
|
940
1278
|
|
|
941
|
-
export { Scope, WebMCPScope, useTool, useWebMCP };
|
|
1279
|
+
export { Scope, WebMCPHooksContext, WebMCPProvider, WebMCPScope, useTool, useWebMCP, useWebMCPHooksContext };
|
|
942
1280
|
//# sourceMappingURL=react.js.map
|
|
943
1281
|
//# sourceMappingURL=react.js.map
|