@zapier/kitcore 0.8.0 → 0.10.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/CHANGELOG.md +21 -0
- package/dist/index.cjs +598 -288
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +176 -83
- package/dist/index.d.ts +176 -83
- package/dist/index.mjs +593 -285
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// src/registry.ts
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
|
|
4
1
|
// src/utils/string-utils.ts
|
|
5
2
|
function toTitleCase(input) {
|
|
6
3
|
return input.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_\-]+/g, " ").replace(/\s+/g, " ").trim().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
@@ -24,6 +21,65 @@ function pluralizeLastWord(title) {
|
|
|
24
21
|
return [...words.slice(0, -1), pluralize(words[words.length - 1])].join(" ");
|
|
25
22
|
}
|
|
26
23
|
|
|
24
|
+
// src/utils/schema-utils.ts
|
|
25
|
+
import { z } from "zod";
|
|
26
|
+
function canonicalInputSchema(schema) {
|
|
27
|
+
if (schema instanceof z.ZodUnion) {
|
|
28
|
+
return schema.options[0];
|
|
29
|
+
}
|
|
30
|
+
return schema;
|
|
31
|
+
}
|
|
32
|
+
function getOutputSchema(inputSchema) {
|
|
33
|
+
return inputSchema._zod.def.outputSchema;
|
|
34
|
+
}
|
|
35
|
+
function withOutputSchema(inputSchema, outputSchema) {
|
|
36
|
+
Object.assign(inputSchema._zod.def, {
|
|
37
|
+
outputSchema
|
|
38
|
+
});
|
|
39
|
+
return inputSchema;
|
|
40
|
+
}
|
|
41
|
+
function withResolver(schema, config) {
|
|
42
|
+
schema._zod.def.resolverMeta = config;
|
|
43
|
+
return schema;
|
|
44
|
+
}
|
|
45
|
+
function getSchemaDescription(schema) {
|
|
46
|
+
return schema.description;
|
|
47
|
+
}
|
|
48
|
+
function getFieldDescriptions(schema) {
|
|
49
|
+
const descriptions = {};
|
|
50
|
+
const shape = schema.shape;
|
|
51
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
52
|
+
if (fieldSchema instanceof z.ZodType && fieldSchema.description) {
|
|
53
|
+
descriptions[key] = fieldSchema.description;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return descriptions;
|
|
57
|
+
}
|
|
58
|
+
function withPositional(schema) {
|
|
59
|
+
Object.assign(schema._zod.def, {
|
|
60
|
+
positionalMeta: { positional: true }
|
|
61
|
+
});
|
|
62
|
+
return schema;
|
|
63
|
+
}
|
|
64
|
+
function schemaHasPositionalMeta(schema) {
|
|
65
|
+
return "positionalMeta" in schema._zod.def;
|
|
66
|
+
}
|
|
67
|
+
function isPositional(schema) {
|
|
68
|
+
if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (schema instanceof z.ZodOptional) {
|
|
72
|
+
return isPositional(schema._zod.def.innerType);
|
|
73
|
+
}
|
|
74
|
+
if (schema instanceof z.ZodDefault) {
|
|
75
|
+
return isPositional(schema._zod.def.innerType);
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
function openEnum(values, description) {
|
|
80
|
+
return z.union([z.enum(values), z.string()]).describe(description);
|
|
81
|
+
}
|
|
82
|
+
|
|
27
83
|
// src/registry.ts
|
|
28
84
|
function resolveCategoryDefinition(ref) {
|
|
29
85
|
const def = typeof ref === "string" ? { key: ref } : ref;
|
|
@@ -34,30 +90,25 @@ function resolveCategoryDefinition(ref) {
|
|
|
34
90
|
titlePlural: def.titlePlural ?? pluralizeLastWord(title)
|
|
35
91
|
};
|
|
36
92
|
}
|
|
37
|
-
function canonicalInputSchema(schema) {
|
|
38
|
-
if (schema instanceof z.ZodUnion) {
|
|
39
|
-
return schema.options[0];
|
|
40
|
-
}
|
|
41
|
-
return schema;
|
|
42
|
-
}
|
|
43
93
|
function buildRegistry({
|
|
44
94
|
sdk,
|
|
45
95
|
meta,
|
|
46
96
|
formatters,
|
|
47
|
-
|
|
97
|
+
resolvers,
|
|
48
98
|
positional,
|
|
99
|
+
skipInputValidation,
|
|
49
100
|
packageFilter
|
|
50
101
|
}) {
|
|
51
102
|
const definitionsByKey = /* @__PURE__ */ new Map();
|
|
52
103
|
const objectDeclaredKeys = /* @__PURE__ */ new Set();
|
|
53
104
|
for (const m of Object.values(meta)) {
|
|
54
105
|
for (const ref of m.categories ?? []) {
|
|
55
|
-
const
|
|
106
|
+
const key = typeof ref === "string" ? ref : ref.key;
|
|
56
107
|
if (typeof ref === "object") {
|
|
57
|
-
objectDeclaredKeys.add(
|
|
58
|
-
definitionsByKey.set(
|
|
59
|
-
} else if (!objectDeclaredKeys.has(
|
|
60
|
-
definitionsByKey.set(
|
|
108
|
+
objectDeclaredKeys.add(key);
|
|
109
|
+
definitionsByKey.set(key, resolveCategoryDefinition(ref));
|
|
110
|
+
} else if (!objectDeclaredKeys.has(key)) {
|
|
111
|
+
definitionsByKey.set(key, resolveCategoryDefinition(ref));
|
|
61
112
|
}
|
|
62
113
|
}
|
|
63
114
|
}
|
|
@@ -65,30 +116,29 @@ function buildRegistry({
|
|
|
65
116
|
definitionsByKey.set("other", resolveCategoryDefinition("other"));
|
|
66
117
|
}
|
|
67
118
|
const knownCategories = Array.from(definitionsByKey.keys());
|
|
68
|
-
const functions = Object.keys(meta).filter((
|
|
69
|
-
const property = sdk[
|
|
119
|
+
const functions = Object.keys(meta).filter((key) => {
|
|
120
|
+
const property = sdk[key];
|
|
70
121
|
if (typeof property === "function") return true;
|
|
71
|
-
const [rootKey] =
|
|
122
|
+
const [rootKey] = key.split(".");
|
|
72
123
|
const rootProperty = sdk[rootKey];
|
|
73
124
|
return typeof rootProperty === "object" && rootProperty !== null;
|
|
74
|
-
}).map((
|
|
75
|
-
const m = meta[
|
|
125
|
+
}).map((key) => {
|
|
126
|
+
const m = meta[key];
|
|
76
127
|
return {
|
|
77
|
-
name:
|
|
128
|
+
name: key,
|
|
78
129
|
description: m.description,
|
|
79
130
|
type: m.type,
|
|
80
131
|
itemType: m.itemType,
|
|
81
132
|
returnType: m.returnType,
|
|
82
133
|
inputSchema: canonicalInputSchema(m.inputSchema),
|
|
83
|
-
inputParameters: m.inputParameters,
|
|
84
134
|
outputSchema: m.outputSchema,
|
|
85
|
-
positional: positional?.[
|
|
135
|
+
positional: positional?.[key],
|
|
136
|
+
skipInputValidation: skipInputValidation?.[key],
|
|
86
137
|
categories: (m.categories ?? []).map(
|
|
87
138
|
(c) => typeof c === "string" ? c : c.key
|
|
88
139
|
),
|
|
89
|
-
resolvers:
|
|
90
|
-
|
|
91
|
-
formatter: formatters?.[key2],
|
|
140
|
+
resolvers: resolvers?.[key],
|
|
141
|
+
formatter: formatters?.[key],
|
|
92
142
|
experimental: m.experimental,
|
|
93
143
|
packages: m.packages,
|
|
94
144
|
confirm: m.confirm ?? (m.type === "delete" ? "delete" : void 0),
|
|
@@ -577,6 +627,52 @@ function runInMethodScope(fn) {
|
|
|
577
627
|
var runWithTelemetryContext = runInMethodScope;
|
|
578
628
|
var isTelemetryNested = isNestedMethodCall;
|
|
579
629
|
|
|
630
|
+
// src/utils/call-context.ts
|
|
631
|
+
var CALL_CONTEXT_BRAND = Symbol("kitcore.callContext");
|
|
632
|
+
function isCallContext(value) {
|
|
633
|
+
return typeof value === "object" && value !== null && value[CALL_CONTEXT_BRAND] === true;
|
|
634
|
+
}
|
|
635
|
+
function generateCallId() {
|
|
636
|
+
try {
|
|
637
|
+
const webCrypto = globalThis.crypto;
|
|
638
|
+
if (webCrypto?.randomUUID) {
|
|
639
|
+
return webCrypto.randomUUID();
|
|
640
|
+
}
|
|
641
|
+
if (webCrypto?.getRandomValues) {
|
|
642
|
+
const bytes = webCrypto.getRandomValues(new Uint8Array(16));
|
|
643
|
+
const hex = Array.from(bytes, (byte, i) => {
|
|
644
|
+
const value = i === 6 ? byte & 15 | 64 : i === 8 ? byte & 63 | 128 : byte;
|
|
645
|
+
return value.toString(16).padStart(2, "0");
|
|
646
|
+
});
|
|
647
|
+
return [
|
|
648
|
+
hex.slice(0, 4).join(""),
|
|
649
|
+
hex.slice(4, 6).join(""),
|
|
650
|
+
hex.slice(6, 8).join(""),
|
|
651
|
+
hex.slice(8, 10).join(""),
|
|
652
|
+
hex.slice(10, 16).join("")
|
|
653
|
+
].join("-");
|
|
654
|
+
}
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
function rootCallContext() {
|
|
660
|
+
return {
|
|
661
|
+
callId: generateCallId(),
|
|
662
|
+
depth: 0,
|
|
663
|
+
annotations: {},
|
|
664
|
+
[CALL_CONTEXT_BRAND]: true
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
function childCallContext(parent) {
|
|
668
|
+
return {
|
|
669
|
+
callId: parent.callId,
|
|
670
|
+
depth: parent.depth + 1,
|
|
671
|
+
annotations: {},
|
|
672
|
+
[CALL_CONTEXT_BRAND]: true
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
|
|
580
676
|
// src/utils/core-options.ts
|
|
581
677
|
function defaultLogDeprecation({
|
|
582
678
|
methodName,
|
|
@@ -595,6 +691,9 @@ function resolveCoreOptions(context) {
|
|
|
595
691
|
return context.core;
|
|
596
692
|
}
|
|
597
693
|
var INTERNAL_CALL = Symbol("kitcore.internalCall");
|
|
694
|
+
function resolveCallContext(secondArg) {
|
|
695
|
+
return isCallContext(secondArg) ? secondArg : rootCallContext();
|
|
696
|
+
}
|
|
598
697
|
function signalDeprecation(context, methodName, getDeprecation) {
|
|
599
698
|
if (isInsideObserver()) return;
|
|
600
699
|
const deprecation = getDeprecation?.();
|
|
@@ -624,14 +723,16 @@ function createFunction(coreFn, options) {
|
|
|
624
723
|
const functionName = name || coreFn.name;
|
|
625
724
|
const namedFunctions = {
|
|
626
725
|
[functionName]: async function(callOptions) {
|
|
627
|
-
|
|
726
|
+
const internal = arguments[1];
|
|
727
|
+
const context = resolveCallContext(internal);
|
|
728
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
628
729
|
signalDeprecation(sdk.context, functionName, getDeprecation);
|
|
629
730
|
}
|
|
630
731
|
return runInMethodScope(async () => {
|
|
631
732
|
const startTime = Date.now();
|
|
632
733
|
const normalizedOptions = callOptions ?? {};
|
|
633
734
|
const args = [normalizedOptions];
|
|
634
|
-
const depth = getCurrentDepth();
|
|
735
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
635
736
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
636
737
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
637
738
|
hooks?.onMethodStart?.({
|
|
@@ -650,12 +751,15 @@ function createFunction(coreFn, options) {
|
|
|
650
751
|
adaptError
|
|
651
752
|
}
|
|
652
753
|
);
|
|
653
|
-
result = await coreFn(
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
754
|
+
result = await coreFn(
|
|
755
|
+
{
|
|
756
|
+
...normalizedOptions,
|
|
757
|
+
...validatedOptions
|
|
758
|
+
},
|
|
759
|
+
context
|
|
760
|
+
);
|
|
657
761
|
} else {
|
|
658
|
-
result = await coreFn(normalizedOptions);
|
|
762
|
+
result = await coreFn(normalizedOptions, context);
|
|
659
763
|
}
|
|
660
764
|
hooks?.onMethodEnd?.({
|
|
661
765
|
methodName: functionName,
|
|
@@ -685,17 +789,19 @@ function createFunction(coreFn, options) {
|
|
|
685
789
|
function createRawFunction(coreFn, options) {
|
|
686
790
|
const { sdk, name, schema, positional, getDeprecation } = options;
|
|
687
791
|
return function(rawInput) {
|
|
688
|
-
|
|
792
|
+
const internal = arguments[1];
|
|
793
|
+
const context = resolveCallContext(internal);
|
|
794
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
689
795
|
signalDeprecation(sdk.context, name, getDeprecation);
|
|
690
796
|
}
|
|
691
797
|
return runInMethodScope(() => {
|
|
692
798
|
const startTime = Date.now();
|
|
693
|
-
const depth = getCurrentDepth();
|
|
799
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
694
800
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
695
801
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
696
802
|
const input = schema ? rawInput ?? {} : rawInput;
|
|
697
803
|
const record = input;
|
|
698
|
-
const args = positional ? positional.filter((
|
|
804
|
+
const args = positional ? positional.filter((key) => record?.[key] !== void 0).map((key) => record?.[key]) : [input];
|
|
699
805
|
hooks?.onMethodStart?.({
|
|
700
806
|
methodName: name,
|
|
701
807
|
args,
|
|
@@ -714,7 +820,7 @@ function createRawFunction(coreFn, options) {
|
|
|
714
820
|
};
|
|
715
821
|
try {
|
|
716
822
|
const parsed = schema ? validateOptions(schema, input, { adaptError }) : input;
|
|
717
|
-
const result = coreFn(parsed);
|
|
823
|
+
const result = coreFn(parsed, context);
|
|
718
824
|
if (result !== null && typeof result === "object" && typeof result.then === "function") {
|
|
719
825
|
return result.then(
|
|
720
826
|
(value) => {
|
|
@@ -753,9 +859,9 @@ function createPageFunction(coreFn, {
|
|
|
753
859
|
}) {
|
|
754
860
|
const functionName = coreFn.name + "Page";
|
|
755
861
|
const namedFunctions = {
|
|
756
|
-
[functionName]: async function(options) {
|
|
862
|
+
[functionName]: async function(options, callContext) {
|
|
757
863
|
try {
|
|
758
|
-
const response = await coreFn(options);
|
|
864
|
+
const response = await coreFn(options, callContext);
|
|
759
865
|
const page = adaptPage ? adaptPage(response) : response;
|
|
760
866
|
if (!isSdkPage(page)) {
|
|
761
867
|
throw new Error(
|
|
@@ -779,14 +885,16 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
779
885
|
const functionName = name || coreFn.name;
|
|
780
886
|
const namedFunctions = {
|
|
781
887
|
[functionName]: function(callOptions) {
|
|
782
|
-
|
|
888
|
+
const internal = arguments[1];
|
|
889
|
+
const context = resolveCallContext(internal);
|
|
890
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
783
891
|
signalDeprecation(sdk.context, functionName, getDeprecation);
|
|
784
892
|
}
|
|
785
893
|
return runInMethodScope(() => {
|
|
786
894
|
const startTime = Date.now();
|
|
787
895
|
const normalizedOptions = callOptions ?? {};
|
|
788
896
|
const args = [normalizedOptions];
|
|
789
|
-
const depth = getCurrentDepth();
|
|
897
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
790
898
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
791
899
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
792
900
|
hooks?.onMethodStart?.({
|
|
@@ -805,7 +913,11 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
805
913
|
...validatedOptions,
|
|
806
914
|
pageSize
|
|
807
915
|
};
|
|
808
|
-
const iterator = paginate(
|
|
916
|
+
const iterator = paginate(
|
|
917
|
+
(pageOptions) => pageFunction(pageOptions, context),
|
|
918
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
919
|
+
optimizedOptions
|
|
920
|
+
);
|
|
809
921
|
const firstPagePromise = iterator.next().then((result) => {
|
|
810
922
|
if (result.done) {
|
|
811
923
|
throw new Error("Paginate should always iterate at least once");
|
|
@@ -956,11 +1068,11 @@ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
|
|
|
956
1068
|
"context",
|
|
957
1069
|
"getRegistry"
|
|
958
1070
|
]);
|
|
959
|
-
function hasOwn(obj,
|
|
960
|
-
return Object.prototype.hasOwnProperty.call(obj,
|
|
1071
|
+
function hasOwn(obj, key) {
|
|
1072
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
961
1073
|
}
|
|
962
|
-
function setOwn(target,
|
|
963
|
-
Object.defineProperty(target,
|
|
1074
|
+
function setOwn(target, key, value) {
|
|
1075
|
+
Object.defineProperty(target, key, {
|
|
964
1076
|
value,
|
|
965
1077
|
enumerable: true,
|
|
966
1078
|
configurable: true,
|
|
@@ -972,31 +1084,31 @@ function checkCollisions(target, source, kind, callerLabel, override) {
|
|
|
972
1084
|
checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
|
|
973
1085
|
return;
|
|
974
1086
|
}
|
|
975
|
-
for (const
|
|
976
|
-
if (!override && hasOwn(target,
|
|
1087
|
+
for (const key of Object.keys(source)) {
|
|
1088
|
+
if (!override && hasOwn(target, key)) {
|
|
977
1089
|
throw new Error(
|
|
978
|
-
`${callerLabel}: duplicate ${kind} "${
|
|
1090
|
+
`${callerLabel}: duplicate ${kind} "${key}". If the override is intentional, pass { override: true } in the options.`
|
|
979
1091
|
);
|
|
980
1092
|
}
|
|
981
1093
|
}
|
|
982
1094
|
}
|
|
983
1095
|
function checkRootKeyCollisions(target, keys, override, callerLabel) {
|
|
984
|
-
for (const
|
|
985
|
-
if (RESERVED_ROOT_KEYS.has(
|
|
1096
|
+
for (const key of keys) {
|
|
1097
|
+
if (RESERVED_ROOT_KEYS.has(key)) {
|
|
986
1098
|
throw new Error(
|
|
987
|
-
`${callerLabel}: plugin attempted to register reserved root key "${
|
|
1099
|
+
`${callerLabel}: plugin attempted to register reserved root key "${key}". The SDK uses this key for its own accessor; rename the plugin's method.`
|
|
988
1100
|
);
|
|
989
1101
|
}
|
|
990
|
-
if (!override && hasOwn(target,
|
|
1102
|
+
if (!override && hasOwn(target, key)) {
|
|
991
1103
|
throw new Error(
|
|
992
|
-
`${callerLabel}: duplicate root key "${
|
|
1104
|
+
`${callerLabel}: duplicate root key "${key}". If the override is intentional, pass { override: true } in the options.`
|
|
993
1105
|
);
|
|
994
1106
|
}
|
|
995
1107
|
}
|
|
996
1108
|
}
|
|
997
1109
|
function applyOwnProperties(target, source) {
|
|
998
|
-
for (const
|
|
999
|
-
setOwn(target,
|
|
1110
|
+
for (const key of Object.keys(source)) {
|
|
1111
|
+
setOwn(target, key, source[key]);
|
|
1000
1112
|
}
|
|
1001
1113
|
}
|
|
1002
1114
|
function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
|
|
@@ -1214,7 +1326,6 @@ var LEAF_META_KEYS = [
|
|
|
1214
1326
|
"itemType",
|
|
1215
1327
|
"returnType",
|
|
1216
1328
|
"outputSchema",
|
|
1217
|
-
"inputParameters",
|
|
1218
1329
|
"packages",
|
|
1219
1330
|
"experimental",
|
|
1220
1331
|
"confirm",
|
|
@@ -1254,8 +1365,8 @@ function normalizeImports(deps) {
|
|
|
1254
1365
|
}
|
|
1255
1366
|
function collectLeafMeta(config) {
|
|
1256
1367
|
let meta;
|
|
1257
|
-
for (const
|
|
1258
|
-
if (config[
|
|
1368
|
+
for (const key of LEAF_META_KEYS) {
|
|
1369
|
+
if (config[key] !== void 0) (meta ?? (meta = {}))[key] = config[key];
|
|
1259
1370
|
}
|
|
1260
1371
|
return meta;
|
|
1261
1372
|
}
|
|
@@ -1338,7 +1449,8 @@ function defineResolver(config) {
|
|
|
1338
1449
|
type: "object",
|
|
1339
1450
|
properties: config.properties,
|
|
1340
1451
|
definitions: config.definitions,
|
|
1341
|
-
getProperties: config.getProperties
|
|
1452
|
+
getProperties: config.getProperties,
|
|
1453
|
+
additionalKeys: config.additionalKeys
|
|
1342
1454
|
};
|
|
1343
1455
|
case "array":
|
|
1344
1456
|
return {
|
|
@@ -1650,7 +1762,7 @@ function normalizeFormatter(entry, sdk) {
|
|
|
1650
1762
|
const legacy = entry.meta?.formatter;
|
|
1651
1763
|
return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
|
|
1652
1764
|
}
|
|
1653
|
-
function
|
|
1765
|
+
function normalizeResolvers(entry) {
|
|
1654
1766
|
if (entry.pluginType !== "method") return void 0;
|
|
1655
1767
|
return entry.resolvers;
|
|
1656
1768
|
}
|
|
@@ -1691,17 +1803,20 @@ function collectSurfaceProjection(context, formatterSdk) {
|
|
|
1691
1803
|
foldDynamicMembers(entry, surfaceBindings, meta);
|
|
1692
1804
|
}
|
|
1693
1805
|
const formatters = {};
|
|
1694
|
-
const
|
|
1806
|
+
const resolvers = {};
|
|
1695
1807
|
const positional = {};
|
|
1808
|
+
const skipInputValidation = {};
|
|
1696
1809
|
for (const [binding, entry] of Object.entries(entries)) {
|
|
1697
1810
|
const f = normalizeFormatter(entry, formatterSdk);
|
|
1698
1811
|
if (f) formatters[binding] = f;
|
|
1699
|
-
const r =
|
|
1700
|
-
if (r)
|
|
1812
|
+
const r = normalizeResolvers(entry);
|
|
1813
|
+
if (r) resolvers[binding] = r;
|
|
1701
1814
|
const p = methodPositional(entry);
|
|
1702
1815
|
if (p) positional[binding] = p;
|
|
1816
|
+
if (entry.pluginType === "method" && entry.skipInputValidation)
|
|
1817
|
+
skipInputValidation[binding] = true;
|
|
1703
1818
|
}
|
|
1704
|
-
return { meta, formatters,
|
|
1819
|
+
return { meta, formatters, resolvers, positional, skipInputValidation };
|
|
1705
1820
|
}
|
|
1706
1821
|
function buildSurfaceRegistry(context, packageFilter) {
|
|
1707
1822
|
const surface = {};
|
|
@@ -1758,6 +1873,11 @@ function nestedResolvers(resolver) {
|
|
|
1758
1873
|
for (const field of Object.values(resolver.properties ?? {})) {
|
|
1759
1874
|
if (!isResolverRef(field.resolver)) out.push(field.resolver);
|
|
1760
1875
|
}
|
|
1876
|
+
const ak = resolver.additionalKeys;
|
|
1877
|
+
if (ak) {
|
|
1878
|
+
if (!isResolverRef(ak.values)) out.push(ak.values);
|
|
1879
|
+
if (ak.keys && !isResolverRef(ak.keys)) out.push(ak.keys);
|
|
1880
|
+
}
|
|
1761
1881
|
out.push(...Object.values(resolver.definitions ?? {}));
|
|
1762
1882
|
} else if (resolver.type === "array") {
|
|
1763
1883
|
if (!isResolverRef(resolver.items)) out.push(resolver.items);
|
|
@@ -1882,16 +2002,16 @@ function collectPlugins(root, materialized = /* @__PURE__ */ new Set(), configur
|
|
|
1882
2002
|
}
|
|
1883
2003
|
return byId;
|
|
1884
2004
|
}
|
|
1885
|
-
function bindValue(target,
|
|
2005
|
+
function bindValue(target, key, entry, callType = "surface", ctx) {
|
|
1886
2006
|
if (entry.pluginType === "property" && entry.getValue) {
|
|
1887
|
-
Object.defineProperty(target,
|
|
2007
|
+
Object.defineProperty(target, key, {
|
|
1888
2008
|
get: entry.getValue,
|
|
1889
2009
|
enumerable: true,
|
|
1890
2010
|
configurable: true
|
|
1891
2011
|
});
|
|
1892
2012
|
} else {
|
|
1893
|
-
const value = callType === "internal" && entry.pluginType === "method" ? entry.internalValue ?? entry.value : entry.value;
|
|
1894
|
-
Object.defineProperty(target,
|
|
2013
|
+
const value = callType === "internal" && entry.pluginType === "method" ? entry.bindInternal?.(ctx) ?? entry.internalValue ?? entry.value : entry.value;
|
|
2014
|
+
Object.defineProperty(target, key, {
|
|
1895
2015
|
value,
|
|
1896
2016
|
writable: true,
|
|
1897
2017
|
enumerable: true,
|
|
@@ -1908,7 +2028,7 @@ function buildSurface(context, ...maps) {
|
|
|
1908
2028
|
sdk[CONTEXT] = context;
|
|
1909
2029
|
return sdk;
|
|
1910
2030
|
}
|
|
1911
|
-
function buildImports(plugins, importBindings) {
|
|
2031
|
+
function buildImports(plugins, importBindings, ctx) {
|
|
1912
2032
|
const imports = {};
|
|
1913
2033
|
for (const { binding, id, optional } of importBindings) {
|
|
1914
2034
|
const entry = plugins[id];
|
|
@@ -1921,7 +2041,7 @@ function buildImports(plugins, importBindings) {
|
|
|
1921
2041
|
});
|
|
1922
2042
|
continue;
|
|
1923
2043
|
}
|
|
1924
|
-
bindValue(imports, binding, entry, "internal");
|
|
2044
|
+
bindValue(imports, binding, entry, "internal", ctx);
|
|
1925
2045
|
}
|
|
1926
2046
|
return imports;
|
|
1927
2047
|
}
|
|
@@ -2000,6 +2120,19 @@ function bindResolver(resolver, plugins) {
|
|
|
2000
2120
|
const { getProperties } = resolver;
|
|
2001
2121
|
if (getProperties)
|
|
2002
2122
|
bound.getProperties = ({ input }) => getProperties({ imports, input });
|
|
2123
|
+
if (resolver.additionalKeys) {
|
|
2124
|
+
const ak = resolver.additionalKeys;
|
|
2125
|
+
const boundAk = {
|
|
2126
|
+
values: isResolverRef(ak.values) ? ak.values : bindResolver(ak.values, plugins),
|
|
2127
|
+
minEntries: ak.minEntries,
|
|
2128
|
+
maxEntries: ak.maxEntries,
|
|
2129
|
+
keyValueType: ak.keyValueType,
|
|
2130
|
+
valueValueType: ak.valueValueType
|
|
2131
|
+
};
|
|
2132
|
+
if (ak.keys)
|
|
2133
|
+
boundAk.keys = isResolverRef(ak.keys) ? ak.keys : bindResolver(ak.keys, plugins);
|
|
2134
|
+
bound.additionalKeys = boundAk;
|
|
2135
|
+
}
|
|
2003
2136
|
return bound;
|
|
2004
2137
|
}
|
|
2005
2138
|
case "array": {
|
|
@@ -2055,8 +2188,8 @@ function bindResolver(resolver, plugins) {
|
|
|
2055
2188
|
}
|
|
2056
2189
|
function bindFields(fields, plugins) {
|
|
2057
2190
|
const out = {};
|
|
2058
|
-
for (const [
|
|
2059
|
-
out[
|
|
2191
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
2192
|
+
out[key] = {
|
|
2060
2193
|
...field,
|
|
2061
2194
|
resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
|
|
2062
2195
|
};
|
|
@@ -2065,8 +2198,8 @@ function bindFields(fields, plugins) {
|
|
|
2065
2198
|
}
|
|
2066
2199
|
function bindDefinitions(definitions, plugins) {
|
|
2067
2200
|
const out = {};
|
|
2068
|
-
for (const [
|
|
2069
|
-
out[
|
|
2201
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
2202
|
+
out[key] = bindResolver(def, plugins);
|
|
2070
2203
|
}
|
|
2071
2204
|
return out;
|
|
2072
2205
|
}
|
|
@@ -2151,6 +2284,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2151
2284
|
name: descriptor.name,
|
|
2152
2285
|
chain: [],
|
|
2153
2286
|
inputSchema: descriptor.inputSchema,
|
|
2287
|
+
skipInputValidation: descriptor.skipInputValidation,
|
|
2154
2288
|
// Derive the presentation type from the output mode when the author did
|
|
2155
2289
|
// not set one; an explicit meta.type (e.g. "create") still wins.
|
|
2156
2290
|
meta: out.type === "raw" || descriptor.meta?.type ? descriptor.meta : { ...descriptor.meta, type: out.type },
|
|
@@ -2158,17 +2292,17 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2158
2292
|
// Replaced below; never called.
|
|
2159
2293
|
value: () => void 0
|
|
2160
2294
|
};
|
|
2161
|
-
const callRun = (input) => descriptor.run({
|
|
2162
|
-
imports: buildImports(plugins, descriptor.importBindings),
|
|
2295
|
+
const callRun = (input, ctx) => descriptor.run({
|
|
2296
|
+
imports: buildImports(plugins, descriptor.importBindings, ctx),
|
|
2163
2297
|
state: states.get(id),
|
|
2164
2298
|
input
|
|
2165
2299
|
});
|
|
2166
|
-
const fold = (coreFn) => (input) => {
|
|
2167
|
-
let next = coreFn;
|
|
2300
|
+
const fold = (coreFn) => (input, ctx) => {
|
|
2301
|
+
let next = (i) => coreFn(i, ctx);
|
|
2168
2302
|
for (const wrap of entry.chain) {
|
|
2169
2303
|
const inner = next;
|
|
2170
2304
|
next = (i) => wrap.run({
|
|
2171
|
-
imports: buildImports(plugins, wrap.owner.importBindings),
|
|
2305
|
+
imports: buildImports(plugins, wrap.owner.importBindings, ctx),
|
|
2172
2306
|
next: inner,
|
|
2173
2307
|
input: i,
|
|
2174
2308
|
// Overwritten by the chain item's own closure with the owning
|
|
@@ -2192,7 +2326,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2192
2326
|
}
|
|
2193
2327
|
);
|
|
2194
2328
|
} else if (out.type === "item") {
|
|
2195
|
-
const itemCore = async (input) => callRun(input);
|
|
2329
|
+
const itemCore = async (input, ctx) => callRun(input, ctx);
|
|
2196
2330
|
entry.value = createFunction(
|
|
2197
2331
|
fold(itemCore),
|
|
2198
2332
|
{
|
|
@@ -2204,7 +2338,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2204
2338
|
);
|
|
2205
2339
|
} else {
|
|
2206
2340
|
entry.value = createRawFunction(
|
|
2207
|
-
(input) => fold(callRun)(input),
|
|
2341
|
+
(input, ctx) => fold(callRun)(input, ctx),
|
|
2208
2342
|
{
|
|
2209
2343
|
sdk,
|
|
2210
2344
|
name: descriptor.name,
|
|
@@ -2227,11 +2361,15 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2227
2361
|
});
|
|
2228
2362
|
return packed;
|
|
2229
2363
|
};
|
|
2364
|
+
const internalValue = (...args) => canonicalValue(pack(args), INTERNAL_CALL);
|
|
2230
2365
|
entry.value = (...args) => canonicalValue(pack(args));
|
|
2231
|
-
entry.internalValue =
|
|
2366
|
+
entry.internalValue = internalValue;
|
|
2367
|
+
entry.bindInternal = (ctx) => ctx ? (...args) => canonicalValue(pack(args), childCallContext(ctx)) : internalValue;
|
|
2232
2368
|
entry.positional = names;
|
|
2233
2369
|
} else {
|
|
2234
|
-
|
|
2370
|
+
const internalValue = (input) => canonicalValue(input, INTERNAL_CALL);
|
|
2371
|
+
entry.internalValue = internalValue;
|
|
2372
|
+
entry.bindInternal = (ctx) => ctx ? (input) => canonicalValue(input, childCallContext(ctx)) : internalValue;
|
|
2235
2373
|
}
|
|
2236
2374
|
plugins[id] = entry;
|
|
2237
2375
|
}
|
|
@@ -2471,7 +2609,7 @@ function createSdk(root, options) {
|
|
|
2471
2609
|
pluginSurface = {};
|
|
2472
2610
|
bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
|
|
2473
2611
|
}
|
|
2474
|
-
for (const
|
|
2612
|
+
for (const key of Object.keys(legacyExports)) context.surface[key] = key;
|
|
2475
2613
|
if (plugin.pluginType === "aggregate") {
|
|
2476
2614
|
recordExportSurface(context, plugin.exports);
|
|
2477
2615
|
} else {
|
|
@@ -2582,6 +2720,9 @@ var CoreCancelledSignal = class extends CoreSignal {
|
|
|
2582
2720
|
this.code = "CANCELLED";
|
|
2583
2721
|
}
|
|
2584
2722
|
};
|
|
2723
|
+
function isCoreCancelledSignal(value) {
|
|
2724
|
+
return isCoreSignal(value) && value.code === "CANCELLED";
|
|
2725
|
+
}
|
|
2585
2726
|
|
|
2586
2727
|
// src/model/resolution/plan.ts
|
|
2587
2728
|
import { z as z3 } from "zod";
|
|
@@ -2610,6 +2751,7 @@ function valueTypeOf(inner) {
|
|
|
2610
2751
|
if (inner instanceof z3.ZodEnum) return "string";
|
|
2611
2752
|
if (inner instanceof z3.ZodArray) return "array";
|
|
2612
2753
|
if (inner instanceof z3.ZodObject) return "object";
|
|
2754
|
+
if (inner instanceof z3.ZodRecord) return "object";
|
|
2613
2755
|
return void 0;
|
|
2614
2756
|
}
|
|
2615
2757
|
function staticChoicesOf(inner) {
|
|
@@ -2620,7 +2762,8 @@ function staticChoicesOf(inner) {
|
|
|
2620
2762
|
return void 0;
|
|
2621
2763
|
}
|
|
2622
2764
|
function objectShape(schema) {
|
|
2623
|
-
const
|
|
2765
|
+
const canonical = canonicalInputSchema(schema);
|
|
2766
|
+
const { inner } = canonical ? unwrap(canonical) : { inner: void 0 };
|
|
2624
2767
|
if (inner instanceof z3.ZodObject) {
|
|
2625
2768
|
return inner.shape;
|
|
2626
2769
|
}
|
|
@@ -2642,7 +2785,7 @@ function topoOrder2(specs) {
|
|
|
2642
2785
|
}
|
|
2643
2786
|
function planParameters(entry) {
|
|
2644
2787
|
const shape = objectShape(entry.inputSchema);
|
|
2645
|
-
const resolvers = entry.
|
|
2788
|
+
const resolvers = entry.resolvers ?? {};
|
|
2646
2789
|
const names = shape ? [
|
|
2647
2790
|
...Object.keys(shape),
|
|
2648
2791
|
...Object.keys(resolvers).filter(
|
|
@@ -2680,24 +2823,48 @@ function getAtPath(root, path) {
|
|
|
2680
2823
|
}
|
|
2681
2824
|
return node;
|
|
2682
2825
|
}
|
|
2826
|
+
function defineOwn(node, key, value) {
|
|
2827
|
+
Object.defineProperty(node, key, {
|
|
2828
|
+
value,
|
|
2829
|
+
writable: true,
|
|
2830
|
+
enumerable: true,
|
|
2831
|
+
configurable: true
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
2683
2834
|
function setAtPath(root, path, value) {
|
|
2684
2835
|
let node = root;
|
|
2685
2836
|
for (let i = 0; i < path.length - 1; i++) {
|
|
2686
2837
|
const seg = path[i];
|
|
2687
|
-
|
|
2688
|
-
|
|
2838
|
+
const existing = Object.prototype.hasOwnProperty.call(node, seg) ? node[seg] : void 0;
|
|
2839
|
+
if (existing != null && typeof existing === "object") {
|
|
2840
|
+
node = existing;
|
|
2841
|
+
} else {
|
|
2842
|
+
const child = {};
|
|
2843
|
+
defineOwn(node, seg, child);
|
|
2844
|
+
node = child;
|
|
2845
|
+
}
|
|
2689
2846
|
}
|
|
2690
|
-
node
|
|
2847
|
+
defineOwn(node, path[path.length - 1], value);
|
|
2691
2848
|
}
|
|
2692
|
-
var
|
|
2849
|
+
var SAFE_SEGMENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2850
|
+
var pathToKey = (path) => {
|
|
2851
|
+
let out = "";
|
|
2852
|
+
for (const segment of path) {
|
|
2853
|
+
if (typeof segment === "number") out += `[${segment}]`;
|
|
2854
|
+
else if (SAFE_SEGMENT.test(segment))
|
|
2855
|
+
out += out === "" ? segment : `.${segment}`;
|
|
2856
|
+
else out += `[${JSON.stringify(segment)}]`;
|
|
2857
|
+
}
|
|
2858
|
+
return out;
|
|
2859
|
+
};
|
|
2693
2860
|
function isSettled(state, path) {
|
|
2694
|
-
return state.settled.includes(
|
|
2861
|
+
return state.settled.includes(pathToKey(path));
|
|
2695
2862
|
}
|
|
2696
2863
|
function remember(state, k) {
|
|
2697
2864
|
if (!state.settled.includes(k)) state.settled.push(k);
|
|
2698
2865
|
}
|
|
2699
2866
|
function settle(state, path) {
|
|
2700
|
-
remember(state,
|
|
2867
|
+
remember(state, pathToKey(path));
|
|
2701
2868
|
}
|
|
2702
2869
|
function clone(state) {
|
|
2703
2870
|
return JSON.parse(JSON.stringify(state));
|
|
@@ -2712,6 +2879,28 @@ function coerce(leaf, raw) {
|
|
|
2712
2879
|
if (raw === "true") return true;
|
|
2713
2880
|
if (raw === "false") return false;
|
|
2714
2881
|
}
|
|
2882
|
+
if (leaf.valueType === "object") {
|
|
2883
|
+
const trimmed = raw.trim();
|
|
2884
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
2885
|
+
try {
|
|
2886
|
+
return JSON.parse(trimmed);
|
|
2887
|
+
} catch {
|
|
2888
|
+
return raw;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
return raw;
|
|
2892
|
+
}
|
|
2893
|
+
if (leaf.valueType === "array") {
|
|
2894
|
+
const trimmed = raw.trim();
|
|
2895
|
+
if (trimmed.startsWith("[")) {
|
|
2896
|
+
try {
|
|
2897
|
+
return JSON.parse(trimmed);
|
|
2898
|
+
} catch {
|
|
2899
|
+
return raw;
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
return raw;
|
|
2903
|
+
}
|
|
2715
2904
|
return raw;
|
|
2716
2905
|
}
|
|
2717
2906
|
async function validationError(leaf, value, state) {
|
|
@@ -2769,27 +2958,6 @@ async function objectChildren(resolver, input) {
|
|
|
2769
2958
|
return toLeaf(name, field, resolver.definitions);
|
|
2770
2959
|
});
|
|
2771
2960
|
}
|
|
2772
|
-
function arrayItem(resolver) {
|
|
2773
|
-
const items = resolver.items;
|
|
2774
|
-
const valueType = resolver.itemValueType;
|
|
2775
|
-
if (isRef(items)) {
|
|
2776
|
-
return {
|
|
2777
|
-
name: "",
|
|
2778
|
-
required: true,
|
|
2779
|
-
resolver: resolver.definitions?.[items.ref],
|
|
2780
|
-
extraInput: items.input,
|
|
2781
|
-
valueType,
|
|
2782
|
-
requires: []
|
|
2783
|
-
};
|
|
2784
|
-
}
|
|
2785
|
-
return {
|
|
2786
|
-
name: "",
|
|
2787
|
-
required: true,
|
|
2788
|
-
resolver: items,
|
|
2789
|
-
valueType,
|
|
2790
|
-
requires: []
|
|
2791
|
-
};
|
|
2792
|
-
}
|
|
2793
2961
|
function autoSettles(resolver) {
|
|
2794
2962
|
return resolver.type === "constant" || resolver.type === "info";
|
|
2795
2963
|
}
|
|
@@ -2809,10 +2977,28 @@ async function leafAt(ctx, path, resolved) {
|
|
|
2809
2977
|
const seg = path[i];
|
|
2810
2978
|
if (typeof seg === "number") {
|
|
2811
2979
|
if (leaf?.resolver?.type !== "array") return void 0;
|
|
2812
|
-
leaf =
|
|
2980
|
+
leaf = boundLeaf(
|
|
2981
|
+
"",
|
|
2982
|
+
leaf.resolver.items,
|
|
2983
|
+
leaf.resolver.definitions,
|
|
2984
|
+
leaf.resolver.itemValueType
|
|
2985
|
+
);
|
|
2813
2986
|
} else {
|
|
2814
|
-
|
|
2815
|
-
|
|
2987
|
+
const parent = leaf;
|
|
2988
|
+
const found = children.find((c) => c.name === seg);
|
|
2989
|
+
if (found) {
|
|
2990
|
+
leaf = found;
|
|
2991
|
+
} else if (parent?.resolver?.type === "object" && parent.resolver.additionalKeys) {
|
|
2992
|
+
const ak = parent.resolver.additionalKeys;
|
|
2993
|
+
leaf = boundLeaf(
|
|
2994
|
+
String(seg),
|
|
2995
|
+
ak.values,
|
|
2996
|
+
parent.resolver.definitions,
|
|
2997
|
+
ak.valueValueType
|
|
2998
|
+
);
|
|
2999
|
+
} else {
|
|
3000
|
+
return void 0;
|
|
3001
|
+
}
|
|
2816
3002
|
}
|
|
2817
3003
|
if (i < path.length - 1 && typeof path[i + 1] === "string") {
|
|
2818
3004
|
if (leaf?.resolver?.type !== "object") return void 0;
|
|
@@ -2824,16 +3010,81 @@ async function leafAt(ctx, path, resolved) {
|
|
|
2824
3010
|
}
|
|
2825
3011
|
return leaf;
|
|
2826
3012
|
}
|
|
3013
|
+
function boundLeaf(name, resolverOrRef, definitions, valueType) {
|
|
3014
|
+
if (isRef(resolverOrRef)) {
|
|
3015
|
+
return {
|
|
3016
|
+
name,
|
|
3017
|
+
required: true,
|
|
3018
|
+
resolver: definitions?.[resolverOrRef.ref],
|
|
3019
|
+
extraInput: resolverOrRef.input,
|
|
3020
|
+
valueType,
|
|
3021
|
+
requires: []
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
3024
|
+
return {
|
|
3025
|
+
name,
|
|
3026
|
+
required: true,
|
|
3027
|
+
resolver: resolverOrRef,
|
|
3028
|
+
valueType,
|
|
3029
|
+
requires: []
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
async function recordInfoAt(ctx, path, resolved) {
|
|
3033
|
+
const leaf = await leafAt(ctx, path, resolved);
|
|
3034
|
+
const resolver = leaf?.resolver;
|
|
3035
|
+
if (resolver?.type !== "object" || !resolver.additionalKeys) {
|
|
3036
|
+
throw new Error(
|
|
3037
|
+
`expected an object resolver with additionalKeys at "${pathToKey(path)}"`
|
|
3038
|
+
);
|
|
3039
|
+
}
|
|
3040
|
+
if (resolver.getProperties) {
|
|
3041
|
+
throw new Error(
|
|
3042
|
+
`object resolver at "${pathToKey(path)}" cannot combine getProperties with additionalKeys`
|
|
3043
|
+
);
|
|
3044
|
+
}
|
|
3045
|
+
const ak = resolver.additionalKeys;
|
|
3046
|
+
const defs = resolver.definitions;
|
|
3047
|
+
const keyLeaf = ak.keys ? boundLeaf("key", ak.keys, defs, ak.keyValueType ?? "string") : {
|
|
3048
|
+
name: "key",
|
|
3049
|
+
required: true,
|
|
3050
|
+
resolver: { type: "static", inputType: "text" },
|
|
3051
|
+
valueType: "string",
|
|
3052
|
+
requires: []
|
|
3053
|
+
};
|
|
3054
|
+
const valueLeaf = boundLeaf("value", ak.values, defs, ak.valueValueType);
|
|
3055
|
+
if (keyLeaf.resolver && keyLeaf.resolver.type !== "static") {
|
|
3056
|
+
throw new Error(
|
|
3057
|
+
`record key resolver at "${pathToKey(path)}" must be a static free-text prompt, not "${keyLeaf.resolver.type}"`
|
|
3058
|
+
);
|
|
3059
|
+
}
|
|
3060
|
+
if (valueLeaf.resolver?.type === "object" || valueLeaf.resolver?.type === "array") {
|
|
3061
|
+
throw new Error(
|
|
3062
|
+
`record value resolver at "${pathToKey(path)}" must be a single value, not "${valueLeaf.resolver.type}"`
|
|
3063
|
+
);
|
|
3064
|
+
}
|
|
3065
|
+
return {
|
|
3066
|
+
min: ak.minEntries ?? 0,
|
|
3067
|
+
max: ak.maxEntries ?? Infinity,
|
|
3068
|
+
keyLeaf,
|
|
3069
|
+
valueLeaf,
|
|
3070
|
+
fixedKeys: Object.keys(resolver.properties ?? {})
|
|
3071
|
+
};
|
|
3072
|
+
}
|
|
2827
3073
|
async function arrayInfoAt(ctx, path, resolved) {
|
|
2828
3074
|
const leaf = await leafAt(ctx, path, resolved);
|
|
2829
3075
|
const resolver = leaf?.resolver;
|
|
2830
3076
|
if (resolver?.type !== "array") {
|
|
2831
|
-
throw new Error(`expected an array resolver at "${
|
|
3077
|
+
throw new Error(`expected an array resolver at "${pathToKey(path)}"`);
|
|
2832
3078
|
}
|
|
2833
3079
|
return {
|
|
2834
3080
|
min: resolver.minItems ?? 0,
|
|
2835
3081
|
max: resolver.maxItems ?? Infinity,
|
|
2836
|
-
item:
|
|
3082
|
+
item: boundLeaf(
|
|
3083
|
+
String(path[path.length - 1]),
|
|
3084
|
+
resolver.items,
|
|
3085
|
+
resolver.definitions,
|
|
3086
|
+
resolver.itemValueType
|
|
3087
|
+
)
|
|
2837
3088
|
};
|
|
2838
3089
|
}
|
|
2839
3090
|
async function firstPage(result) {
|
|
@@ -2914,6 +3165,9 @@ var AFFORDANCE = {
|
|
|
2914
3165
|
retry: { action: "retry", description: "Retry loading the options" },
|
|
2915
3166
|
cancel: { action: "cancel", description: "Cancel resolution" }
|
|
2916
3167
|
};
|
|
3168
|
+
function affordance(base, description) {
|
|
3169
|
+
return { ...base, description };
|
|
3170
|
+
}
|
|
2917
3171
|
function selectActions(leaf, page, multiple) {
|
|
2918
3172
|
const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
|
|
2919
3173
|
if (searchMode && page.position.search === void 0 && page.items.length === 0) {
|
|
@@ -3028,7 +3282,7 @@ async function buildQuestion(leaf, path, input) {
|
|
|
3028
3282
|
}
|
|
3029
3283
|
};
|
|
3030
3284
|
}
|
|
3031
|
-
function
|
|
3285
|
+
function arrayItemsQuestion(t) {
|
|
3032
3286
|
const actions = [AFFORDANCE.add];
|
|
3033
3287
|
if (t.count >= t.min) actions.push(AFFORDANCE.done);
|
|
3034
3288
|
return {
|
|
@@ -3044,22 +3298,37 @@ function collectionQuestion(t) {
|
|
|
3044
3298
|
actions
|
|
3045
3299
|
};
|
|
3046
3300
|
}
|
|
3047
|
-
function
|
|
3301
|
+
function recordEntriesQuestion(t) {
|
|
3302
|
+
const actions = [
|
|
3303
|
+
affordance(AFFORDANCE.add, "Add another entry")
|
|
3304
|
+
];
|
|
3305
|
+
if (t.count >= t.min) {
|
|
3306
|
+
actions.push(affordance(AFFORDANCE.done, "Finish the entries"));
|
|
3307
|
+
}
|
|
3308
|
+
return {
|
|
3309
|
+
type: "collection",
|
|
3310
|
+
path: t.path,
|
|
3311
|
+
message: `Add another ${t.path[t.path.length - 1]} entry? (${t.count} so far)`,
|
|
3312
|
+
container: "record",
|
|
3313
|
+
count: t.count,
|
|
3314
|
+
min: t.min,
|
|
3315
|
+
...Number.isFinite(t.max) ? { max: t.max } : {},
|
|
3316
|
+
actions
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
function objectOptionalQuestion(path) {
|
|
3048
3320
|
return {
|
|
3049
3321
|
type: "collection",
|
|
3050
3322
|
path,
|
|
3051
3323
|
message: `Add ${path[path.length - 1]}?`,
|
|
3052
3324
|
container: "object",
|
|
3053
3325
|
actions: [
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
description: "Provide values for these fields"
|
|
3057
|
-
},
|
|
3058
|
-
{ action: "done", description: "Skip these fields" }
|
|
3326
|
+
affordance(AFFORDANCE.add, "Provide values for these fields"),
|
|
3327
|
+
affordance(AFFORDANCE.done, "Skip these fields")
|
|
3059
3328
|
]
|
|
3060
3329
|
};
|
|
3061
3330
|
}
|
|
3062
|
-
function
|
|
3331
|
+
function objectOptionalPropertiesQuestion(path, pending) {
|
|
3063
3332
|
return {
|
|
3064
3333
|
type: "collection",
|
|
3065
3334
|
path,
|
|
@@ -3076,8 +3345,8 @@ function optionalsGateQuestion(path, pending) {
|
|
|
3076
3345
|
...leaf.valueType ? { valueType: leaf.valueType } : {}
|
|
3077
3346
|
})),
|
|
3078
3347
|
actions: [
|
|
3079
|
-
|
|
3080
|
-
|
|
3348
|
+
affordance(AFFORDANCE.add, "Configure the optional fields"),
|
|
3349
|
+
affordance(AFFORDANCE.done, "Skip the optional fields")
|
|
3081
3350
|
]
|
|
3082
3351
|
};
|
|
3083
3352
|
}
|
|
@@ -3095,7 +3364,8 @@ function finalize(ctx, resolved) {
|
|
|
3095
3364
|
}));
|
|
3096
3365
|
return { status: "invalid", issues };
|
|
3097
3366
|
}
|
|
3098
|
-
var optionalsMarker = (path) => `${
|
|
3367
|
+
var optionalsMarker = (path) => `${pathToKey(path)}?optionals`;
|
|
3368
|
+
var UNSAFE_RECORD_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3099
3369
|
async function findInArray(ctx, state, path) {
|
|
3100
3370
|
if (isSettled(state, path)) return null;
|
|
3101
3371
|
if (getAtPath(state.resolved, path) == null)
|
|
@@ -3116,7 +3386,28 @@ async function findInArray(ctx, state, path) {
|
|
|
3116
3386
|
}
|
|
3117
3387
|
}
|
|
3118
3388
|
if (len < min) return descendItem(ctx, state, path, len, item);
|
|
3119
|
-
if (len < max) return {
|
|
3389
|
+
if (len < max) return { type: "array_items", path, count: len, min, max };
|
|
3390
|
+
settle(state, path);
|
|
3391
|
+
return null;
|
|
3392
|
+
}
|
|
3393
|
+
async function findInRecord(ctx, state, path) {
|
|
3394
|
+
if (isSettled(state, path)) return null;
|
|
3395
|
+
if (getAtPath(state.resolved, path) == null)
|
|
3396
|
+
setAtPath(state.resolved, path, {});
|
|
3397
|
+
if (!state.interactive) {
|
|
3398
|
+
settle(state, path);
|
|
3399
|
+
return null;
|
|
3400
|
+
}
|
|
3401
|
+
const { min, max, keyLeaf, fixedKeys } = await recordInfoAt(
|
|
3402
|
+
ctx,
|
|
3403
|
+
path,
|
|
3404
|
+
state.resolved
|
|
3405
|
+
);
|
|
3406
|
+
const container = getAtPath(state.resolved, path);
|
|
3407
|
+
const fixed = new Set(fixedKeys);
|
|
3408
|
+
const count = Object.keys(container).filter((k) => !fixed.has(k)).length;
|
|
3409
|
+
if (count < min) return { type: "record_key", path, leaf: keyLeaf };
|
|
3410
|
+
if (count < max) return { type: "record_entries", path, count, min, max };
|
|
3120
3411
|
settle(state, path);
|
|
3121
3412
|
return null;
|
|
3122
3413
|
}
|
|
@@ -3134,10 +3425,10 @@ function seedItemSlot(state, itemPath, item) {
|
|
|
3134
3425
|
}
|
|
3135
3426
|
async function descendItem(ctx, state, arrayPath, index, item) {
|
|
3136
3427
|
const itemPath = [...arrayPath, index];
|
|
3137
|
-
const
|
|
3138
|
-
if (
|
|
3139
|
-
if (
|
|
3140
|
-
return {
|
|
3428
|
+
const slotType = seedItemSlot(state, itemPath, item);
|
|
3429
|
+
if (slotType === "object") return findNext(ctx, state, itemPath);
|
|
3430
|
+
if (slotType === "array") return findInArray(ctx, state, itemPath);
|
|
3431
|
+
return { type: "leaf", path: itemPath, leaf: item };
|
|
3141
3432
|
}
|
|
3142
3433
|
async function findNext(ctx, state, path = []) {
|
|
3143
3434
|
const container = getAtPath(state.resolved, path) ?? {};
|
|
@@ -3162,7 +3453,7 @@ async function findNext(ctx, state, path = []) {
|
|
|
3162
3453
|
const pending = ordered.filter(
|
|
3163
3454
|
(c) => !c.required && asksUser(c) && isPendingChild(c)
|
|
3164
3455
|
);
|
|
3165
|
-
return {
|
|
3456
|
+
return { type: "object_optional_properties", path, pending };
|
|
3166
3457
|
}
|
|
3167
3458
|
if (leaf.resolver?.type === "object") {
|
|
3168
3459
|
if (isSettled(state, childPath)) continue;
|
|
@@ -3172,7 +3463,7 @@ async function findNext(ctx, state, path = []) {
|
|
|
3172
3463
|
settle(state, childPath);
|
|
3173
3464
|
continue;
|
|
3174
3465
|
}
|
|
3175
|
-
return {
|
|
3466
|
+
return { type: "object_optional", path: childPath, leaf };
|
|
3176
3467
|
}
|
|
3177
3468
|
setAtPath(state.resolved, childPath, {});
|
|
3178
3469
|
}
|
|
@@ -3204,13 +3495,21 @@ async function findNext(ctx, state, path = []) {
|
|
|
3204
3495
|
}
|
|
3205
3496
|
if (container[leaf.name] !== void 0 || isSettled(state, childPath))
|
|
3206
3497
|
continue;
|
|
3207
|
-
return {
|
|
3498
|
+
return { type: "leaf", path: childPath, leaf };
|
|
3499
|
+
}
|
|
3500
|
+
if (inObject && !isSettled(state, path)) {
|
|
3501
|
+
const self = await leafAt(ctx, path, state.resolved);
|
|
3502
|
+
if (self?.resolver?.type === "object" && self.resolver.additionalKeys) {
|
|
3503
|
+
const rec = await findInRecord(ctx, state, path);
|
|
3504
|
+
if (rec) return rec;
|
|
3505
|
+
}
|
|
3208
3506
|
}
|
|
3209
3507
|
return null;
|
|
3210
3508
|
}
|
|
3211
3509
|
async function askLeaf(state, path, leaf, opts = {}) {
|
|
3212
3510
|
state.current = path;
|
|
3213
|
-
|
|
3511
|
+
if (opts.gate) state.gate = opts.gate;
|
|
3512
|
+
else delete state.gate;
|
|
3214
3513
|
try {
|
|
3215
3514
|
const { question, pagination } = await buildQuestion(
|
|
3216
3515
|
leaf,
|
|
@@ -3231,6 +3530,28 @@ async function askLeaf(state, path, leaf, opts = {}) {
|
|
|
3231
3530
|
return failedResult(state, leaf.name, error);
|
|
3232
3531
|
}
|
|
3233
3532
|
}
|
|
3533
|
+
async function askRecordKey(state, path, keyLeaf, opts = {}) {
|
|
3534
|
+
return askLeaf(state, path, keyLeaf, { gate: "record_key", ...opts });
|
|
3535
|
+
}
|
|
3536
|
+
async function autoResolveLeaf(state, path, leaf) {
|
|
3537
|
+
const resolver = leaf.resolver;
|
|
3538
|
+
if (resolver && autoSettles(resolver)) {
|
|
3539
|
+
if (resolver.type === "constant")
|
|
3540
|
+
setAtPath(state.resolved, path, resolver.value);
|
|
3541
|
+
settle(state, path);
|
|
3542
|
+
return true;
|
|
3543
|
+
}
|
|
3544
|
+
const auto = resolver?.type === "dynamic" ? await resolver.tryResolveWithoutPrompt?.({
|
|
3545
|
+
input: mergeInput(state.resolved, leaf.extraInput)
|
|
3546
|
+
}) : void 0;
|
|
3547
|
+
if (auto) {
|
|
3548
|
+
if (auto.resolvedValue !== void 0)
|
|
3549
|
+
setAtPath(state.resolved, path, auto.resolvedValue);
|
|
3550
|
+
settle(state, path);
|
|
3551
|
+
return true;
|
|
3552
|
+
}
|
|
3553
|
+
return false;
|
|
3554
|
+
}
|
|
3234
3555
|
async function advance(ctx, state) {
|
|
3235
3556
|
for (; ; ) {
|
|
3236
3557
|
const target = await findNext(ctx, state);
|
|
@@ -3240,54 +3561,56 @@ async function advance(ctx, state) {
|
|
|
3240
3561
|
delete state.pagination;
|
|
3241
3562
|
return { state, result: finalize(ctx, state.resolved) };
|
|
3242
3563
|
}
|
|
3243
|
-
if (target.
|
|
3564
|
+
if (target.type === "array_items") {
|
|
3244
3565
|
state.current = target.path;
|
|
3245
|
-
state.gate = "
|
|
3566
|
+
state.gate = "array_items";
|
|
3246
3567
|
delete state.pagination;
|
|
3247
3568
|
return {
|
|
3248
3569
|
state,
|
|
3249
|
-
result: { status: "ask", question:
|
|
3570
|
+
result: { status: "ask", question: arrayItemsQuestion(target) }
|
|
3250
3571
|
};
|
|
3251
3572
|
}
|
|
3252
|
-
if (target.
|
|
3573
|
+
if (target.type === "object_optional") {
|
|
3253
3574
|
state.current = target.path;
|
|
3254
|
-
state.gate = "
|
|
3575
|
+
state.gate = "object_optional";
|
|
3255
3576
|
delete state.pagination;
|
|
3256
3577
|
return {
|
|
3257
3578
|
state,
|
|
3258
|
-
result: {
|
|
3579
|
+
result: {
|
|
3580
|
+
status: "ask",
|
|
3581
|
+
question: objectOptionalQuestion(target.path)
|
|
3582
|
+
}
|
|
3259
3583
|
};
|
|
3260
3584
|
}
|
|
3261
|
-
if (target.
|
|
3585
|
+
if (target.type === "object_optional_properties") {
|
|
3262
3586
|
state.current = target.path;
|
|
3263
|
-
state.gate = "
|
|
3587
|
+
state.gate = "object_optional_properties";
|
|
3264
3588
|
delete state.pagination;
|
|
3265
3589
|
return {
|
|
3266
3590
|
state,
|
|
3267
3591
|
result: {
|
|
3268
3592
|
status: "ask",
|
|
3269
|
-
question:
|
|
3593
|
+
question: objectOptionalPropertiesQuestion(
|
|
3594
|
+
target.path,
|
|
3595
|
+
target.pending
|
|
3596
|
+
)
|
|
3270
3597
|
}
|
|
3271
3598
|
};
|
|
3272
3599
|
}
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3600
|
+
if (target.type === "record_entries") {
|
|
3601
|
+
state.current = target.path;
|
|
3602
|
+
state.gate = "record_entries";
|
|
3603
|
+
delete state.pagination;
|
|
3604
|
+
return {
|
|
3605
|
+
state,
|
|
3606
|
+
result: { status: "ask", question: recordEntriesQuestion(target) }
|
|
3607
|
+
};
|
|
3281
3608
|
}
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
}) : void 0;
|
|
3285
|
-
if (auto) {
|
|
3286
|
-
if (auto.resolvedValue !== void 0)
|
|
3287
|
-
setAtPath(state.resolved, path, auto.resolvedValue);
|
|
3288
|
-
settle(state, path);
|
|
3289
|
-
continue;
|
|
3609
|
+
if (target.type === "record_key") {
|
|
3610
|
+
return askRecordKey(state, target.path, target.leaf);
|
|
3290
3611
|
}
|
|
3612
|
+
const { path, leaf } = target;
|
|
3613
|
+
if (await autoResolveLeaf(state, path, leaf)) continue;
|
|
3291
3614
|
if (!state.interactive) {
|
|
3292
3615
|
if (!leaf.required) {
|
|
3293
3616
|
settle(state, path);
|
|
@@ -3320,10 +3643,18 @@ async function step(ctx, prior, action) {
|
|
|
3320
3643
|
delete state.pagination;
|
|
3321
3644
|
return { state, result: { status: "cancelled" } };
|
|
3322
3645
|
}
|
|
3646
|
+
if (state.gate === "record_key") {
|
|
3647
|
+
return stepRecordKey(ctx, state, action);
|
|
3648
|
+
}
|
|
3323
3649
|
const path = state.current;
|
|
3324
3650
|
if (!path) throw new Error("step called with no outstanding question");
|
|
3325
3651
|
const leaf = await leafAt(ctx, path, state.resolved);
|
|
3326
|
-
if (leaf
|
|
3652
|
+
if (!leaf) {
|
|
3653
|
+
throw new Error(
|
|
3654
|
+
`no resolver for the outstanding question at "${pathToKey(path)}"`
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3657
|
+
if (action.type === "search" || action.type === "next_page" || action.type === "previous_page" || action.type === "retry") {
|
|
3327
3658
|
return refine(ctx, state, leaf, path, action);
|
|
3328
3659
|
}
|
|
3329
3660
|
if (action.type === "add" || action.type === "done") {
|
|
@@ -3340,19 +3671,26 @@ async function step(ctx, prior, action) {
|
|
|
3340
3671
|
settle(state, path);
|
|
3341
3672
|
return advance(ctx, state);
|
|
3342
3673
|
}
|
|
3343
|
-
if (gate === "
|
|
3674
|
+
if (gate === "object_optional") {
|
|
3344
3675
|
setAtPath(state.resolved, path, {});
|
|
3345
3676
|
return advance(ctx, state);
|
|
3346
3677
|
}
|
|
3347
|
-
if (gate === "
|
|
3678
|
+
if (gate === "object_optional_properties") {
|
|
3348
3679
|
remember(state, optionalsMarker(path));
|
|
3349
3680
|
return advance(ctx, state);
|
|
3350
3681
|
}
|
|
3682
|
+
if (gate === "record_entries") {
|
|
3683
|
+
const { keyLeaf } = await recordInfoAt(ctx, path, state.resolved);
|
|
3684
|
+
return askRecordKey(state, path, keyLeaf);
|
|
3685
|
+
}
|
|
3351
3686
|
const items = getAtPath(state.resolved, path) ?? [];
|
|
3352
3687
|
const { item } = await arrayInfoAt(ctx, path, state.resolved);
|
|
3353
3688
|
const itemPath = [...path, items.length];
|
|
3354
|
-
if (seedItemSlot(state, itemPath, item) === "leaf")
|
|
3689
|
+
if (seedItemSlot(state, itemPath, item) === "leaf") {
|
|
3690
|
+
if (await autoResolveLeaf(state, itemPath, item))
|
|
3691
|
+
return advance(ctx, state);
|
|
3355
3692
|
return askLeaf(state, itemPath, item);
|
|
3693
|
+
}
|
|
3356
3694
|
return advance(ctx, state);
|
|
3357
3695
|
}
|
|
3358
3696
|
if (state.gate) {
|
|
@@ -3363,81 +3701,37 @@ async function step(ctx, prior, action) {
|
|
|
3363
3701
|
switch (action.type) {
|
|
3364
3702
|
case "choose":
|
|
3365
3703
|
case "custom": {
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
if (
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
const page = await fetchListing(
|
|
3378
|
-
leaf,
|
|
3379
|
-
state.resolved,
|
|
3380
|
-
state.pagination.position,
|
|
3381
|
-
context
|
|
3382
|
-
);
|
|
3383
|
-
state.pagination = toPagination(page);
|
|
3384
|
-
return {
|
|
3385
|
-
state,
|
|
3386
|
-
result: {
|
|
3387
|
-
status: "ask",
|
|
3388
|
-
question: selectQuestion(
|
|
3389
|
-
leaf,
|
|
3390
|
-
path,
|
|
3391
|
-
state.resolved,
|
|
3392
|
-
page,
|
|
3393
|
-
context
|
|
3394
|
-
),
|
|
3395
|
-
error
|
|
3396
|
-
}
|
|
3397
|
-
};
|
|
3398
|
-
} catch (fetchError) {
|
|
3399
|
-
state.pagination = failedPagination(
|
|
3400
|
-
state.pagination,
|
|
3401
|
-
state.pagination.position
|
|
3402
|
-
);
|
|
3403
|
-
return failedResult(state, leaf.name, fetchError);
|
|
3404
|
-
}
|
|
3405
|
-
}
|
|
3406
|
-
return askLeaf(state, path, leaf, { error });
|
|
3704
|
+
let error;
|
|
3705
|
+
try {
|
|
3706
|
+
error = await validationError(leaf, action.value, state);
|
|
3707
|
+
} catch (thrown) {
|
|
3708
|
+
return failedResult(state, leaf.name, thrown);
|
|
3709
|
+
}
|
|
3710
|
+
if (error) {
|
|
3711
|
+
if (state.pagination && leaf.resolver?.type === "dynamic") {
|
|
3712
|
+
return renderPageAt(state, leaf, path, state.pagination.position, {
|
|
3713
|
+
error
|
|
3714
|
+
});
|
|
3407
3715
|
}
|
|
3716
|
+
return askLeaf(state, path, leaf, { error });
|
|
3408
3717
|
}
|
|
3409
|
-
setAtPath(
|
|
3410
|
-
state.resolved,
|
|
3411
|
-
path,
|
|
3412
|
-
leaf ? coerce(leaf, action.value) : action.value
|
|
3413
|
-
);
|
|
3718
|
+
setAtPath(state.resolved, path, coerce(leaf, action.value));
|
|
3414
3719
|
break;
|
|
3415
3720
|
}
|
|
3416
3721
|
case "skip":
|
|
3417
3722
|
settle(state, path);
|
|
3418
3723
|
break;
|
|
3419
3724
|
default:
|
|
3420
|
-
throw new Error(
|
|
3725
|
+
throw new Error(
|
|
3726
|
+
`action "${action.type}" is not supported here`
|
|
3727
|
+
);
|
|
3421
3728
|
}
|
|
3422
3729
|
delete state.current;
|
|
3423
3730
|
delete state.pagination;
|
|
3424
3731
|
return advance(ctx, state);
|
|
3425
3732
|
}
|
|
3426
|
-
async function
|
|
3427
|
-
const position = positionAfter(state.pagination, action);
|
|
3733
|
+
async function renderPageAt(state, leaf, path, position, opts = {}) {
|
|
3428
3734
|
try {
|
|
3429
|
-
if (action.type === "search") {
|
|
3430
|
-
const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
|
|
3431
|
-
input: mergeInput(state.resolved, leaf.extraInput),
|
|
3432
|
-
search: action.term
|
|
3433
|
-
}) : void 0;
|
|
3434
|
-
if (exact) {
|
|
3435
|
-
setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
|
|
3436
|
-
delete state.current;
|
|
3437
|
-
delete state.pagination;
|
|
3438
|
-
return advance(ctx, state);
|
|
3439
|
-
}
|
|
3440
|
-
}
|
|
3441
3735
|
const context = await resolveContext(leaf, state.resolved);
|
|
3442
3736
|
const page = await fetchListing(leaf, state.resolved, position, context);
|
|
3443
3737
|
state.pagination = toPagination(page);
|
|
@@ -3445,7 +3739,8 @@ async function refine(ctx, state, leaf, path, action) {
|
|
|
3445
3739
|
state,
|
|
3446
3740
|
result: {
|
|
3447
3741
|
status: "ask",
|
|
3448
|
-
question: selectQuestion(leaf, path, state.resolved, page, context)
|
|
3742
|
+
question: selectQuestion(leaf, path, state.resolved, page, context),
|
|
3743
|
+
...opts.error ? { error: opts.error } : {}
|
|
3449
3744
|
}
|
|
3450
3745
|
};
|
|
3451
3746
|
} catch (error) {
|
|
@@ -3453,6 +3748,65 @@ async function refine(ctx, state, leaf, path, action) {
|
|
|
3453
3748
|
return failedResult(state, leaf.name, error);
|
|
3454
3749
|
}
|
|
3455
3750
|
}
|
|
3751
|
+
async function refine(ctx, state, leaf, path, action) {
|
|
3752
|
+
const position = positionAfter(state.pagination, action);
|
|
3753
|
+
if (action.type === "search") {
|
|
3754
|
+
try {
|
|
3755
|
+
const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
|
|
3756
|
+
input: mergeInput(state.resolved, leaf.extraInput),
|
|
3757
|
+
search: action.term
|
|
3758
|
+
}) : void 0;
|
|
3759
|
+
if (exact) {
|
|
3760
|
+
setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
|
|
3761
|
+
delete state.current;
|
|
3762
|
+
delete state.pagination;
|
|
3763
|
+
return advance(ctx, state);
|
|
3764
|
+
}
|
|
3765
|
+
} catch (error) {
|
|
3766
|
+
state.pagination = failedPagination(state.pagination, position);
|
|
3767
|
+
return failedResult(state, leaf.name, error);
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
return renderPageAt(state, leaf, path, position);
|
|
3771
|
+
}
|
|
3772
|
+
async function stepRecordKey(ctx, state, action) {
|
|
3773
|
+
const path = state.current;
|
|
3774
|
+
if (!path)
|
|
3775
|
+
throw new Error("record key step called with no outstanding question");
|
|
3776
|
+
const { keyLeaf, valueLeaf } = await recordInfoAt(ctx, path, state.resolved);
|
|
3777
|
+
if (action.type === "skip") {
|
|
3778
|
+
delete state.gate;
|
|
3779
|
+
delete state.current;
|
|
3780
|
+
delete state.pagination;
|
|
3781
|
+
return advance(ctx, state);
|
|
3782
|
+
}
|
|
3783
|
+
if (action.type !== "custom" && action.type !== "choose") {
|
|
3784
|
+
throw new Error(
|
|
3785
|
+
`action "${action.type}" is not supported while entering a record key`
|
|
3786
|
+
);
|
|
3787
|
+
}
|
|
3788
|
+
const raw = Array.isArray(action.value) ? action.value[0] : action.value;
|
|
3789
|
+
const entryKey = String(coerce(keyLeaf, raw));
|
|
3790
|
+
if (entryKey.trim() === "") {
|
|
3791
|
+
return askRecordKey(state, path, keyLeaf, { error: "A key is required." });
|
|
3792
|
+
}
|
|
3793
|
+
if (UNSAFE_RECORD_KEYS.has(entryKey)) {
|
|
3794
|
+
return askRecordKey(state, path, keyLeaf, {
|
|
3795
|
+
error: `"${entryKey}" is not an allowed key.`
|
|
3796
|
+
});
|
|
3797
|
+
}
|
|
3798
|
+
const container = getAtPath(state.resolved, path);
|
|
3799
|
+
if (Object.prototype.hasOwnProperty.call(container, entryKey)) {
|
|
3800
|
+
return askRecordKey(state, path, keyLeaf, {
|
|
3801
|
+
error: `"${entryKey}" is already set.`
|
|
3802
|
+
});
|
|
3803
|
+
}
|
|
3804
|
+
const valuePath = [...path, entryKey];
|
|
3805
|
+
if (await autoResolveLeaf(state, valuePath, valueLeaf)) {
|
|
3806
|
+
return advance(ctx, state);
|
|
3807
|
+
}
|
|
3808
|
+
return askLeaf(state, valuePath, valueLeaf);
|
|
3809
|
+
}
|
|
3456
3810
|
function failedPagination(pagination, retryPosition) {
|
|
3457
3811
|
return {
|
|
3458
3812
|
position: pagination?.position ?? firstPagePosition(),
|
|
@@ -3508,7 +3862,7 @@ function projectSummary(entry) {
|
|
|
3508
3862
|
};
|
|
3509
3863
|
}
|
|
3510
3864
|
function projectMethod(entry) {
|
|
3511
|
-
const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
|
|
3865
|
+
const inputProperties = toJsonSchema(canonicalInputSchema(entry.inputSchema))?.properties;
|
|
3512
3866
|
const parameters = {};
|
|
3513
3867
|
for (const spec of planParameters(entry).parameters) {
|
|
3514
3868
|
const dynamic = spec.resolver?.type === "dynamic" ? spec.resolver : void 0;
|
|
@@ -3541,7 +3895,12 @@ function createController(sdk) {
|
|
|
3541
3895
|
const entry = entryFor(method);
|
|
3542
3896
|
return {
|
|
3543
3897
|
method,
|
|
3544
|
-
|
|
3898
|
+
// A method that owns its input validation (`skipInputValidation`, e.g.
|
|
3899
|
+
// fetch) must not be re-validated by the controller's final `safeParse`;
|
|
3900
|
+
// drop the schema so `finalize` returns the resolved input untouched.
|
|
3901
|
+
// Planning still reads `entry.inputSchema` directly, so parameters are
|
|
3902
|
+
// unaffected.
|
|
3903
|
+
schema: entry.skipInputValidation ? void 0 : entry.inputSchema,
|
|
3545
3904
|
parameters: planParameters(entry).parameters
|
|
3546
3905
|
};
|
|
3547
3906
|
}
|
|
@@ -3606,59 +3965,6 @@ function createCorePlugin(options) {
|
|
|
3606
3965
|
}
|
|
3607
3966
|
});
|
|
3608
3967
|
}
|
|
3609
|
-
|
|
3610
|
-
// src/utils/schema-utils.ts
|
|
3611
|
-
import { z as z5 } from "zod";
|
|
3612
|
-
function getOutputSchema(inputSchema) {
|
|
3613
|
-
return inputSchema._zod.def.outputSchema;
|
|
3614
|
-
}
|
|
3615
|
-
function withOutputSchema(inputSchema, outputSchema) {
|
|
3616
|
-
Object.assign(inputSchema._zod.def, {
|
|
3617
|
-
outputSchema
|
|
3618
|
-
});
|
|
3619
|
-
return inputSchema;
|
|
3620
|
-
}
|
|
3621
|
-
function withResolver(schema, config) {
|
|
3622
|
-
schema._zod.def.resolverMeta = config;
|
|
3623
|
-
return schema;
|
|
3624
|
-
}
|
|
3625
|
-
function getSchemaDescription(schema) {
|
|
3626
|
-
return schema.description;
|
|
3627
|
-
}
|
|
3628
|
-
function getFieldDescriptions(schema) {
|
|
3629
|
-
const descriptions = {};
|
|
3630
|
-
const shape = schema.shape;
|
|
3631
|
-
for (const [key2, fieldSchema] of Object.entries(shape)) {
|
|
3632
|
-
if (fieldSchema instanceof z5.ZodType && fieldSchema.description) {
|
|
3633
|
-
descriptions[key2] = fieldSchema.description;
|
|
3634
|
-
}
|
|
3635
|
-
}
|
|
3636
|
-
return descriptions;
|
|
3637
|
-
}
|
|
3638
|
-
function withPositional(schema) {
|
|
3639
|
-
Object.assign(schema._zod.def, {
|
|
3640
|
-
positionalMeta: { positional: true }
|
|
3641
|
-
});
|
|
3642
|
-
return schema;
|
|
3643
|
-
}
|
|
3644
|
-
function schemaHasPositionalMeta(schema) {
|
|
3645
|
-
return "positionalMeta" in schema._zod.def;
|
|
3646
|
-
}
|
|
3647
|
-
function isPositional(schema) {
|
|
3648
|
-
if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
|
|
3649
|
-
return true;
|
|
3650
|
-
}
|
|
3651
|
-
if (schema instanceof z5.ZodOptional) {
|
|
3652
|
-
return isPositional(schema._zod.def.innerType);
|
|
3653
|
-
}
|
|
3654
|
-
if (schema instanceof z5.ZodDefault) {
|
|
3655
|
-
return isPositional(schema._zod.def.innerType);
|
|
3656
|
-
}
|
|
3657
|
-
return false;
|
|
3658
|
-
}
|
|
3659
|
-
function openEnum(values, description) {
|
|
3660
|
-
return z5.union([z5.enum(values), z5.string()]).describe(description);
|
|
3661
|
-
}
|
|
3662
3968
|
export {
|
|
3663
3969
|
CONTEXT,
|
|
3664
3970
|
CORE_ERROR_SYMBOL,
|
|
@@ -3670,6 +3976,7 @@ export {
|
|
|
3670
3976
|
CoreErrorCode,
|
|
3671
3977
|
CoreSignal,
|
|
3672
3978
|
addPlugin,
|
|
3979
|
+
canonicalInputSchema,
|
|
3673
3980
|
composePlugins,
|
|
3674
3981
|
concatLists,
|
|
3675
3982
|
concatPaginated,
|
|
@@ -3713,6 +4020,7 @@ export {
|
|
|
3713
4020
|
getOutputSchema,
|
|
3714
4021
|
getRegistryPlugin,
|
|
3715
4022
|
getSchemaDescription,
|
|
4023
|
+
isCoreCancelledSignal,
|
|
3716
4024
|
isCoreError,
|
|
3717
4025
|
isCoreSignal,
|
|
3718
4026
|
isNestedMethodCall,
|