@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.cjs
CHANGED
|
@@ -9,9 +9,9 @@ var __export = (target, all) => {
|
|
|
9
9
|
};
|
|
10
10
|
var __copyProps = (to, from, except, desc) => {
|
|
11
11
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let
|
|
13
|
-
if (!__hasOwnProp.call(to,
|
|
14
|
-
__defProp(to,
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
15
|
}
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
CoreErrorCode: () => CoreErrorCode,
|
|
31
31
|
CoreSignal: () => CoreSignal,
|
|
32
32
|
addPlugin: () => addPlugin,
|
|
33
|
+
canonicalInputSchema: () => canonicalInputSchema,
|
|
33
34
|
composePlugins: () => composePlugins,
|
|
34
35
|
concatLists: () => concatLists,
|
|
35
36
|
concatPaginated: () => concatPaginated,
|
|
@@ -73,6 +74,7 @@ __export(index_exports, {
|
|
|
73
74
|
getOutputSchema: () => getOutputSchema,
|
|
74
75
|
getRegistryPlugin: () => getRegistryPlugin,
|
|
75
76
|
getSchemaDescription: () => getSchemaDescription,
|
|
77
|
+
isCoreCancelledSignal: () => isCoreCancelledSignal,
|
|
76
78
|
isCoreError: () => isCoreError,
|
|
77
79
|
isCoreSignal: () => isCoreSignal,
|
|
78
80
|
isNestedMethodCall: () => isNestedMethodCall,
|
|
@@ -98,9 +100,6 @@ __export(index_exports, {
|
|
|
98
100
|
});
|
|
99
101
|
module.exports = __toCommonJS(index_exports);
|
|
100
102
|
|
|
101
|
-
// src/registry.ts
|
|
102
|
-
var import_zod = require("zod");
|
|
103
|
-
|
|
104
103
|
// src/utils/string-utils.ts
|
|
105
104
|
function toTitleCase(input) {
|
|
106
105
|
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(" ");
|
|
@@ -124,6 +123,65 @@ function pluralizeLastWord(title) {
|
|
|
124
123
|
return [...words.slice(0, -1), pluralize(words[words.length - 1])].join(" ");
|
|
125
124
|
}
|
|
126
125
|
|
|
126
|
+
// src/utils/schema-utils.ts
|
|
127
|
+
var import_zod = require("zod");
|
|
128
|
+
function canonicalInputSchema(schema) {
|
|
129
|
+
if (schema instanceof import_zod.z.ZodUnion) {
|
|
130
|
+
return schema.options[0];
|
|
131
|
+
}
|
|
132
|
+
return schema;
|
|
133
|
+
}
|
|
134
|
+
function getOutputSchema(inputSchema) {
|
|
135
|
+
return inputSchema._zod.def.outputSchema;
|
|
136
|
+
}
|
|
137
|
+
function withOutputSchema(inputSchema, outputSchema) {
|
|
138
|
+
Object.assign(inputSchema._zod.def, {
|
|
139
|
+
outputSchema
|
|
140
|
+
});
|
|
141
|
+
return inputSchema;
|
|
142
|
+
}
|
|
143
|
+
function withResolver(schema, config) {
|
|
144
|
+
schema._zod.def.resolverMeta = config;
|
|
145
|
+
return schema;
|
|
146
|
+
}
|
|
147
|
+
function getSchemaDescription(schema) {
|
|
148
|
+
return schema.description;
|
|
149
|
+
}
|
|
150
|
+
function getFieldDescriptions(schema) {
|
|
151
|
+
const descriptions = {};
|
|
152
|
+
const shape = schema.shape;
|
|
153
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
154
|
+
if (fieldSchema instanceof import_zod.z.ZodType && fieldSchema.description) {
|
|
155
|
+
descriptions[key] = fieldSchema.description;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return descriptions;
|
|
159
|
+
}
|
|
160
|
+
function withPositional(schema) {
|
|
161
|
+
Object.assign(schema._zod.def, {
|
|
162
|
+
positionalMeta: { positional: true }
|
|
163
|
+
});
|
|
164
|
+
return schema;
|
|
165
|
+
}
|
|
166
|
+
function schemaHasPositionalMeta(schema) {
|
|
167
|
+
return "positionalMeta" in schema._zod.def;
|
|
168
|
+
}
|
|
169
|
+
function isPositional(schema) {
|
|
170
|
+
if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (schema instanceof import_zod.z.ZodOptional) {
|
|
174
|
+
return isPositional(schema._zod.def.innerType);
|
|
175
|
+
}
|
|
176
|
+
if (schema instanceof import_zod.z.ZodDefault) {
|
|
177
|
+
return isPositional(schema._zod.def.innerType);
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
function openEnum(values, description) {
|
|
182
|
+
return import_zod.z.union([import_zod.z.enum(values), import_zod.z.string()]).describe(description);
|
|
183
|
+
}
|
|
184
|
+
|
|
127
185
|
// src/registry.ts
|
|
128
186
|
function resolveCategoryDefinition(ref) {
|
|
129
187
|
const def = typeof ref === "string" ? { key: ref } : ref;
|
|
@@ -134,30 +192,25 @@ function resolveCategoryDefinition(ref) {
|
|
|
134
192
|
titlePlural: def.titlePlural ?? pluralizeLastWord(title)
|
|
135
193
|
};
|
|
136
194
|
}
|
|
137
|
-
function canonicalInputSchema(schema) {
|
|
138
|
-
if (schema instanceof import_zod.z.ZodUnion) {
|
|
139
|
-
return schema.options[0];
|
|
140
|
-
}
|
|
141
|
-
return schema;
|
|
142
|
-
}
|
|
143
195
|
function buildRegistry({
|
|
144
196
|
sdk,
|
|
145
197
|
meta,
|
|
146
198
|
formatters,
|
|
147
|
-
|
|
199
|
+
resolvers,
|
|
148
200
|
positional,
|
|
201
|
+
skipInputValidation,
|
|
149
202
|
packageFilter
|
|
150
203
|
}) {
|
|
151
204
|
const definitionsByKey = /* @__PURE__ */ new Map();
|
|
152
205
|
const objectDeclaredKeys = /* @__PURE__ */ new Set();
|
|
153
206
|
for (const m of Object.values(meta)) {
|
|
154
207
|
for (const ref of m.categories ?? []) {
|
|
155
|
-
const
|
|
208
|
+
const key = typeof ref === "string" ? ref : ref.key;
|
|
156
209
|
if (typeof ref === "object") {
|
|
157
|
-
objectDeclaredKeys.add(
|
|
158
|
-
definitionsByKey.set(
|
|
159
|
-
} else if (!objectDeclaredKeys.has(
|
|
160
|
-
definitionsByKey.set(
|
|
210
|
+
objectDeclaredKeys.add(key);
|
|
211
|
+
definitionsByKey.set(key, resolveCategoryDefinition(ref));
|
|
212
|
+
} else if (!objectDeclaredKeys.has(key)) {
|
|
213
|
+
definitionsByKey.set(key, resolveCategoryDefinition(ref));
|
|
161
214
|
}
|
|
162
215
|
}
|
|
163
216
|
}
|
|
@@ -165,30 +218,29 @@ function buildRegistry({
|
|
|
165
218
|
definitionsByKey.set("other", resolveCategoryDefinition("other"));
|
|
166
219
|
}
|
|
167
220
|
const knownCategories = Array.from(definitionsByKey.keys());
|
|
168
|
-
const functions = Object.keys(meta).filter((
|
|
169
|
-
const property = sdk[
|
|
221
|
+
const functions = Object.keys(meta).filter((key) => {
|
|
222
|
+
const property = sdk[key];
|
|
170
223
|
if (typeof property === "function") return true;
|
|
171
|
-
const [rootKey] =
|
|
224
|
+
const [rootKey] = key.split(".");
|
|
172
225
|
const rootProperty = sdk[rootKey];
|
|
173
226
|
return typeof rootProperty === "object" && rootProperty !== null;
|
|
174
|
-
}).map((
|
|
175
|
-
const m = meta[
|
|
227
|
+
}).map((key) => {
|
|
228
|
+
const m = meta[key];
|
|
176
229
|
return {
|
|
177
|
-
name:
|
|
230
|
+
name: key,
|
|
178
231
|
description: m.description,
|
|
179
232
|
type: m.type,
|
|
180
233
|
itemType: m.itemType,
|
|
181
234
|
returnType: m.returnType,
|
|
182
235
|
inputSchema: canonicalInputSchema(m.inputSchema),
|
|
183
|
-
inputParameters: m.inputParameters,
|
|
184
236
|
outputSchema: m.outputSchema,
|
|
185
|
-
positional: positional?.[
|
|
237
|
+
positional: positional?.[key],
|
|
238
|
+
skipInputValidation: skipInputValidation?.[key],
|
|
186
239
|
categories: (m.categories ?? []).map(
|
|
187
240
|
(c) => typeof c === "string" ? c : c.key
|
|
188
241
|
),
|
|
189
|
-
resolvers:
|
|
190
|
-
|
|
191
|
-
formatter: formatters?.[key2],
|
|
242
|
+
resolvers: resolvers?.[key],
|
|
243
|
+
formatter: formatters?.[key],
|
|
192
244
|
experimental: m.experimental,
|
|
193
245
|
packages: m.packages,
|
|
194
246
|
confirm: m.confirm ?? (m.type === "delete" ? "delete" : void 0),
|
|
@@ -675,6 +727,52 @@ function runInMethodScope(fn) {
|
|
|
675
727
|
var runWithTelemetryContext = runInMethodScope;
|
|
676
728
|
var isTelemetryNested = isNestedMethodCall;
|
|
677
729
|
|
|
730
|
+
// src/utils/call-context.ts
|
|
731
|
+
var CALL_CONTEXT_BRAND = Symbol("kitcore.callContext");
|
|
732
|
+
function isCallContext(value) {
|
|
733
|
+
return typeof value === "object" && value !== null && value[CALL_CONTEXT_BRAND] === true;
|
|
734
|
+
}
|
|
735
|
+
function generateCallId() {
|
|
736
|
+
try {
|
|
737
|
+
const webCrypto = globalThis.crypto;
|
|
738
|
+
if (webCrypto?.randomUUID) {
|
|
739
|
+
return webCrypto.randomUUID();
|
|
740
|
+
}
|
|
741
|
+
if (webCrypto?.getRandomValues) {
|
|
742
|
+
const bytes = webCrypto.getRandomValues(new Uint8Array(16));
|
|
743
|
+
const hex = Array.from(bytes, (byte, i) => {
|
|
744
|
+
const value = i === 6 ? byte & 15 | 64 : i === 8 ? byte & 63 | 128 : byte;
|
|
745
|
+
return value.toString(16).padStart(2, "0");
|
|
746
|
+
});
|
|
747
|
+
return [
|
|
748
|
+
hex.slice(0, 4).join(""),
|
|
749
|
+
hex.slice(4, 6).join(""),
|
|
750
|
+
hex.slice(6, 8).join(""),
|
|
751
|
+
hex.slice(8, 10).join(""),
|
|
752
|
+
hex.slice(10, 16).join("")
|
|
753
|
+
].join("-");
|
|
754
|
+
}
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
function rootCallContext() {
|
|
760
|
+
return {
|
|
761
|
+
callId: generateCallId(),
|
|
762
|
+
depth: 0,
|
|
763
|
+
annotations: {},
|
|
764
|
+
[CALL_CONTEXT_BRAND]: true
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
function childCallContext(parent) {
|
|
768
|
+
return {
|
|
769
|
+
callId: parent.callId,
|
|
770
|
+
depth: parent.depth + 1,
|
|
771
|
+
annotations: {},
|
|
772
|
+
[CALL_CONTEXT_BRAND]: true
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
678
776
|
// src/utils/core-options.ts
|
|
679
777
|
function defaultLogDeprecation({
|
|
680
778
|
methodName,
|
|
@@ -693,6 +791,9 @@ function resolveCoreOptions(context) {
|
|
|
693
791
|
return context.core;
|
|
694
792
|
}
|
|
695
793
|
var INTERNAL_CALL = Symbol("kitcore.internalCall");
|
|
794
|
+
function resolveCallContext(secondArg) {
|
|
795
|
+
return isCallContext(secondArg) ? secondArg : rootCallContext();
|
|
796
|
+
}
|
|
696
797
|
function signalDeprecation(context, methodName, getDeprecation) {
|
|
697
798
|
if (isInsideObserver()) return;
|
|
698
799
|
const deprecation = getDeprecation?.();
|
|
@@ -722,14 +823,16 @@ function createFunction(coreFn, options) {
|
|
|
722
823
|
const functionName = name || coreFn.name;
|
|
723
824
|
const namedFunctions = {
|
|
724
825
|
[functionName]: async function(callOptions) {
|
|
725
|
-
|
|
826
|
+
const internal = arguments[1];
|
|
827
|
+
const context = resolveCallContext(internal);
|
|
828
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
726
829
|
signalDeprecation(sdk.context, functionName, getDeprecation);
|
|
727
830
|
}
|
|
728
831
|
return runInMethodScope(async () => {
|
|
729
832
|
const startTime = Date.now();
|
|
730
833
|
const normalizedOptions = callOptions ?? {};
|
|
731
834
|
const args = [normalizedOptions];
|
|
732
|
-
const depth = getCurrentDepth();
|
|
835
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
733
836
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
734
837
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
735
838
|
hooks?.onMethodStart?.({
|
|
@@ -748,12 +851,15 @@ function createFunction(coreFn, options) {
|
|
|
748
851
|
adaptError
|
|
749
852
|
}
|
|
750
853
|
);
|
|
751
|
-
result = await coreFn(
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
854
|
+
result = await coreFn(
|
|
855
|
+
{
|
|
856
|
+
...normalizedOptions,
|
|
857
|
+
...validatedOptions
|
|
858
|
+
},
|
|
859
|
+
context
|
|
860
|
+
);
|
|
755
861
|
} else {
|
|
756
|
-
result = await coreFn(normalizedOptions);
|
|
862
|
+
result = await coreFn(normalizedOptions, context);
|
|
757
863
|
}
|
|
758
864
|
hooks?.onMethodEnd?.({
|
|
759
865
|
methodName: functionName,
|
|
@@ -783,17 +889,19 @@ function createFunction(coreFn, options) {
|
|
|
783
889
|
function createRawFunction(coreFn, options) {
|
|
784
890
|
const { sdk, name, schema, positional, getDeprecation } = options;
|
|
785
891
|
return function(rawInput) {
|
|
786
|
-
|
|
892
|
+
const internal = arguments[1];
|
|
893
|
+
const context = resolveCallContext(internal);
|
|
894
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
787
895
|
signalDeprecation(sdk.context, name, getDeprecation);
|
|
788
896
|
}
|
|
789
897
|
return runInMethodScope(() => {
|
|
790
898
|
const startTime = Date.now();
|
|
791
|
-
const depth = getCurrentDepth();
|
|
899
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
792
900
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
793
901
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
794
902
|
const input = schema ? rawInput ?? {} : rawInput;
|
|
795
903
|
const record = input;
|
|
796
|
-
const args = positional ? positional.filter((
|
|
904
|
+
const args = positional ? positional.filter((key) => record?.[key] !== void 0).map((key) => record?.[key]) : [input];
|
|
797
905
|
hooks?.onMethodStart?.({
|
|
798
906
|
methodName: name,
|
|
799
907
|
args,
|
|
@@ -812,7 +920,7 @@ function createRawFunction(coreFn, options) {
|
|
|
812
920
|
};
|
|
813
921
|
try {
|
|
814
922
|
const parsed = schema ? validateOptions(schema, input, { adaptError }) : input;
|
|
815
|
-
const result = coreFn(parsed);
|
|
923
|
+
const result = coreFn(parsed, context);
|
|
816
924
|
if (result !== null && typeof result === "object" && typeof result.then === "function") {
|
|
817
925
|
return result.then(
|
|
818
926
|
(value) => {
|
|
@@ -851,9 +959,9 @@ function createPageFunction(coreFn, {
|
|
|
851
959
|
}) {
|
|
852
960
|
const functionName = coreFn.name + "Page";
|
|
853
961
|
const namedFunctions = {
|
|
854
|
-
[functionName]: async function(options) {
|
|
962
|
+
[functionName]: async function(options, callContext) {
|
|
855
963
|
try {
|
|
856
|
-
const response = await coreFn(options);
|
|
964
|
+
const response = await coreFn(options, callContext);
|
|
857
965
|
const page = adaptPage ? adaptPage(response) : response;
|
|
858
966
|
if (!isSdkPage(page)) {
|
|
859
967
|
throw new Error(
|
|
@@ -877,14 +985,16 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
877
985
|
const functionName = name || coreFn.name;
|
|
878
986
|
const namedFunctions = {
|
|
879
987
|
[functionName]: function(callOptions) {
|
|
880
|
-
|
|
988
|
+
const internal = arguments[1];
|
|
989
|
+
const context = resolveCallContext(internal);
|
|
990
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
881
991
|
signalDeprecation(sdk.context, functionName, getDeprecation);
|
|
882
992
|
}
|
|
883
993
|
return runInMethodScope(() => {
|
|
884
994
|
const startTime = Date.now();
|
|
885
995
|
const normalizedOptions = callOptions ?? {};
|
|
886
996
|
const args = [normalizedOptions];
|
|
887
|
-
const depth = getCurrentDepth();
|
|
997
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
888
998
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
889
999
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
890
1000
|
hooks?.onMethodStart?.({
|
|
@@ -903,7 +1013,11 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
903
1013
|
...validatedOptions,
|
|
904
1014
|
pageSize
|
|
905
1015
|
};
|
|
906
|
-
const iterator = paginate(
|
|
1016
|
+
const iterator = paginate(
|
|
1017
|
+
(pageOptions) => pageFunction(pageOptions, context),
|
|
1018
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1019
|
+
optimizedOptions
|
|
1020
|
+
);
|
|
907
1021
|
const firstPagePromise = iterator.next().then((result) => {
|
|
908
1022
|
if (result.done) {
|
|
909
1023
|
throw new Error("Paginate should always iterate at least once");
|
|
@@ -1054,11 +1168,11 @@ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
|
|
|
1054
1168
|
"context",
|
|
1055
1169
|
"getRegistry"
|
|
1056
1170
|
]);
|
|
1057
|
-
function hasOwn(obj,
|
|
1058
|
-
return Object.prototype.hasOwnProperty.call(obj,
|
|
1171
|
+
function hasOwn(obj, key) {
|
|
1172
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
1059
1173
|
}
|
|
1060
|
-
function setOwn(target,
|
|
1061
|
-
Object.defineProperty(target,
|
|
1174
|
+
function setOwn(target, key, value) {
|
|
1175
|
+
Object.defineProperty(target, key, {
|
|
1062
1176
|
value,
|
|
1063
1177
|
enumerable: true,
|
|
1064
1178
|
configurable: true,
|
|
@@ -1070,31 +1184,31 @@ function checkCollisions(target, source, kind, callerLabel, override) {
|
|
|
1070
1184
|
checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
|
|
1071
1185
|
return;
|
|
1072
1186
|
}
|
|
1073
|
-
for (const
|
|
1074
|
-
if (!override && hasOwn(target,
|
|
1187
|
+
for (const key of Object.keys(source)) {
|
|
1188
|
+
if (!override && hasOwn(target, key)) {
|
|
1075
1189
|
throw new Error(
|
|
1076
|
-
`${callerLabel}: duplicate ${kind} "${
|
|
1190
|
+
`${callerLabel}: duplicate ${kind} "${key}". If the override is intentional, pass { override: true } in the options.`
|
|
1077
1191
|
);
|
|
1078
1192
|
}
|
|
1079
1193
|
}
|
|
1080
1194
|
}
|
|
1081
1195
|
function checkRootKeyCollisions(target, keys, override, callerLabel) {
|
|
1082
|
-
for (const
|
|
1083
|
-
if (RESERVED_ROOT_KEYS.has(
|
|
1196
|
+
for (const key of keys) {
|
|
1197
|
+
if (RESERVED_ROOT_KEYS.has(key)) {
|
|
1084
1198
|
throw new Error(
|
|
1085
|
-
`${callerLabel}: plugin attempted to register reserved root key "${
|
|
1199
|
+
`${callerLabel}: plugin attempted to register reserved root key "${key}". The SDK uses this key for its own accessor; rename the plugin's method.`
|
|
1086
1200
|
);
|
|
1087
1201
|
}
|
|
1088
|
-
if (!override && hasOwn(target,
|
|
1202
|
+
if (!override && hasOwn(target, key)) {
|
|
1089
1203
|
throw new Error(
|
|
1090
|
-
`${callerLabel}: duplicate root key "${
|
|
1204
|
+
`${callerLabel}: duplicate root key "${key}". If the override is intentional, pass { override: true } in the options.`
|
|
1091
1205
|
);
|
|
1092
1206
|
}
|
|
1093
1207
|
}
|
|
1094
1208
|
}
|
|
1095
1209
|
function applyOwnProperties(target, source) {
|
|
1096
|
-
for (const
|
|
1097
|
-
setOwn(target,
|
|
1210
|
+
for (const key of Object.keys(source)) {
|
|
1211
|
+
setOwn(target, key, source[key]);
|
|
1098
1212
|
}
|
|
1099
1213
|
}
|
|
1100
1214
|
function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
|
|
@@ -1312,7 +1426,6 @@ var LEAF_META_KEYS = [
|
|
|
1312
1426
|
"itemType",
|
|
1313
1427
|
"returnType",
|
|
1314
1428
|
"outputSchema",
|
|
1315
|
-
"inputParameters",
|
|
1316
1429
|
"packages",
|
|
1317
1430
|
"experimental",
|
|
1318
1431
|
"confirm",
|
|
@@ -1352,8 +1465,8 @@ function normalizeImports(deps) {
|
|
|
1352
1465
|
}
|
|
1353
1466
|
function collectLeafMeta(config) {
|
|
1354
1467
|
let meta;
|
|
1355
|
-
for (const
|
|
1356
|
-
if (config[
|
|
1468
|
+
for (const key of LEAF_META_KEYS) {
|
|
1469
|
+
if (config[key] !== void 0) (meta ?? (meta = {}))[key] = config[key];
|
|
1357
1470
|
}
|
|
1358
1471
|
return meta;
|
|
1359
1472
|
}
|
|
@@ -1436,7 +1549,8 @@ function defineResolver(config) {
|
|
|
1436
1549
|
type: "object",
|
|
1437
1550
|
properties: config.properties,
|
|
1438
1551
|
definitions: config.definitions,
|
|
1439
|
-
getProperties: config.getProperties
|
|
1552
|
+
getProperties: config.getProperties,
|
|
1553
|
+
additionalKeys: config.additionalKeys
|
|
1440
1554
|
};
|
|
1441
1555
|
case "array":
|
|
1442
1556
|
return {
|
|
@@ -1748,7 +1862,7 @@ function normalizeFormatter(entry, sdk) {
|
|
|
1748
1862
|
const legacy = entry.meta?.formatter;
|
|
1749
1863
|
return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
|
|
1750
1864
|
}
|
|
1751
|
-
function
|
|
1865
|
+
function normalizeResolvers(entry) {
|
|
1752
1866
|
if (entry.pluginType !== "method") return void 0;
|
|
1753
1867
|
return entry.resolvers;
|
|
1754
1868
|
}
|
|
@@ -1789,17 +1903,20 @@ function collectSurfaceProjection(context, formatterSdk) {
|
|
|
1789
1903
|
foldDynamicMembers(entry, surfaceBindings, meta);
|
|
1790
1904
|
}
|
|
1791
1905
|
const formatters = {};
|
|
1792
|
-
const
|
|
1906
|
+
const resolvers = {};
|
|
1793
1907
|
const positional = {};
|
|
1908
|
+
const skipInputValidation = {};
|
|
1794
1909
|
for (const [binding, entry] of Object.entries(entries)) {
|
|
1795
1910
|
const f = normalizeFormatter(entry, formatterSdk);
|
|
1796
1911
|
if (f) formatters[binding] = f;
|
|
1797
|
-
const r =
|
|
1798
|
-
if (r)
|
|
1912
|
+
const r = normalizeResolvers(entry);
|
|
1913
|
+
if (r) resolvers[binding] = r;
|
|
1799
1914
|
const p = methodPositional(entry);
|
|
1800
1915
|
if (p) positional[binding] = p;
|
|
1916
|
+
if (entry.pluginType === "method" && entry.skipInputValidation)
|
|
1917
|
+
skipInputValidation[binding] = true;
|
|
1801
1918
|
}
|
|
1802
|
-
return { meta, formatters,
|
|
1919
|
+
return { meta, formatters, resolvers, positional, skipInputValidation };
|
|
1803
1920
|
}
|
|
1804
1921
|
function buildSurfaceRegistry(context, packageFilter) {
|
|
1805
1922
|
const surface = {};
|
|
@@ -1856,6 +1973,11 @@ function nestedResolvers(resolver) {
|
|
|
1856
1973
|
for (const field of Object.values(resolver.properties ?? {})) {
|
|
1857
1974
|
if (!isResolverRef(field.resolver)) out.push(field.resolver);
|
|
1858
1975
|
}
|
|
1976
|
+
const ak = resolver.additionalKeys;
|
|
1977
|
+
if (ak) {
|
|
1978
|
+
if (!isResolverRef(ak.values)) out.push(ak.values);
|
|
1979
|
+
if (ak.keys && !isResolverRef(ak.keys)) out.push(ak.keys);
|
|
1980
|
+
}
|
|
1859
1981
|
out.push(...Object.values(resolver.definitions ?? {}));
|
|
1860
1982
|
} else if (resolver.type === "array") {
|
|
1861
1983
|
if (!isResolverRef(resolver.items)) out.push(resolver.items);
|
|
@@ -1980,16 +2102,16 @@ function collectPlugins(root, materialized = /* @__PURE__ */ new Set(), configur
|
|
|
1980
2102
|
}
|
|
1981
2103
|
return byId;
|
|
1982
2104
|
}
|
|
1983
|
-
function bindValue(target,
|
|
2105
|
+
function bindValue(target, key, entry, callType = "surface", ctx) {
|
|
1984
2106
|
if (entry.pluginType === "property" && entry.getValue) {
|
|
1985
|
-
Object.defineProperty(target,
|
|
2107
|
+
Object.defineProperty(target, key, {
|
|
1986
2108
|
get: entry.getValue,
|
|
1987
2109
|
enumerable: true,
|
|
1988
2110
|
configurable: true
|
|
1989
2111
|
});
|
|
1990
2112
|
} else {
|
|
1991
|
-
const value = callType === "internal" && entry.pluginType === "method" ? entry.internalValue ?? entry.value : entry.value;
|
|
1992
|
-
Object.defineProperty(target,
|
|
2113
|
+
const value = callType === "internal" && entry.pluginType === "method" ? entry.bindInternal?.(ctx) ?? entry.internalValue ?? entry.value : entry.value;
|
|
2114
|
+
Object.defineProperty(target, key, {
|
|
1993
2115
|
value,
|
|
1994
2116
|
writable: true,
|
|
1995
2117
|
enumerable: true,
|
|
@@ -2006,7 +2128,7 @@ function buildSurface(context, ...maps) {
|
|
|
2006
2128
|
sdk[CONTEXT] = context;
|
|
2007
2129
|
return sdk;
|
|
2008
2130
|
}
|
|
2009
|
-
function buildImports(plugins, importBindings) {
|
|
2131
|
+
function buildImports(plugins, importBindings, ctx) {
|
|
2010
2132
|
const imports = {};
|
|
2011
2133
|
for (const { binding, id, optional } of importBindings) {
|
|
2012
2134
|
const entry = plugins[id];
|
|
@@ -2019,7 +2141,7 @@ function buildImports(plugins, importBindings) {
|
|
|
2019
2141
|
});
|
|
2020
2142
|
continue;
|
|
2021
2143
|
}
|
|
2022
|
-
bindValue(imports, binding, entry, "internal");
|
|
2144
|
+
bindValue(imports, binding, entry, "internal", ctx);
|
|
2023
2145
|
}
|
|
2024
2146
|
return imports;
|
|
2025
2147
|
}
|
|
@@ -2098,6 +2220,19 @@ function bindResolver(resolver, plugins) {
|
|
|
2098
2220
|
const { getProperties } = resolver;
|
|
2099
2221
|
if (getProperties)
|
|
2100
2222
|
bound.getProperties = ({ input }) => getProperties({ imports, input });
|
|
2223
|
+
if (resolver.additionalKeys) {
|
|
2224
|
+
const ak = resolver.additionalKeys;
|
|
2225
|
+
const boundAk = {
|
|
2226
|
+
values: isResolverRef(ak.values) ? ak.values : bindResolver(ak.values, plugins),
|
|
2227
|
+
minEntries: ak.minEntries,
|
|
2228
|
+
maxEntries: ak.maxEntries,
|
|
2229
|
+
keyValueType: ak.keyValueType,
|
|
2230
|
+
valueValueType: ak.valueValueType
|
|
2231
|
+
};
|
|
2232
|
+
if (ak.keys)
|
|
2233
|
+
boundAk.keys = isResolverRef(ak.keys) ? ak.keys : bindResolver(ak.keys, plugins);
|
|
2234
|
+
bound.additionalKeys = boundAk;
|
|
2235
|
+
}
|
|
2101
2236
|
return bound;
|
|
2102
2237
|
}
|
|
2103
2238
|
case "array": {
|
|
@@ -2153,8 +2288,8 @@ function bindResolver(resolver, plugins) {
|
|
|
2153
2288
|
}
|
|
2154
2289
|
function bindFields(fields, plugins) {
|
|
2155
2290
|
const out = {};
|
|
2156
|
-
for (const [
|
|
2157
|
-
out[
|
|
2291
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
2292
|
+
out[key] = {
|
|
2158
2293
|
...field,
|
|
2159
2294
|
resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
|
|
2160
2295
|
};
|
|
@@ -2163,8 +2298,8 @@ function bindFields(fields, plugins) {
|
|
|
2163
2298
|
}
|
|
2164
2299
|
function bindDefinitions(definitions, plugins) {
|
|
2165
2300
|
const out = {};
|
|
2166
|
-
for (const [
|
|
2167
|
-
out[
|
|
2301
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
2302
|
+
out[key] = bindResolver(def, plugins);
|
|
2168
2303
|
}
|
|
2169
2304
|
return out;
|
|
2170
2305
|
}
|
|
@@ -2249,6 +2384,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2249
2384
|
name: descriptor.name,
|
|
2250
2385
|
chain: [],
|
|
2251
2386
|
inputSchema: descriptor.inputSchema,
|
|
2387
|
+
skipInputValidation: descriptor.skipInputValidation,
|
|
2252
2388
|
// Derive the presentation type from the output mode when the author did
|
|
2253
2389
|
// not set one; an explicit meta.type (e.g. "create") still wins.
|
|
2254
2390
|
meta: out.type === "raw" || descriptor.meta?.type ? descriptor.meta : { ...descriptor.meta, type: out.type },
|
|
@@ -2256,17 +2392,17 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2256
2392
|
// Replaced below; never called.
|
|
2257
2393
|
value: () => void 0
|
|
2258
2394
|
};
|
|
2259
|
-
const callRun = (input) => descriptor.run({
|
|
2260
|
-
imports: buildImports(plugins, descriptor.importBindings),
|
|
2395
|
+
const callRun = (input, ctx) => descriptor.run({
|
|
2396
|
+
imports: buildImports(plugins, descriptor.importBindings, ctx),
|
|
2261
2397
|
state: states.get(id),
|
|
2262
2398
|
input
|
|
2263
2399
|
});
|
|
2264
|
-
const fold = (coreFn) => (input) => {
|
|
2265
|
-
let next = coreFn;
|
|
2400
|
+
const fold = (coreFn) => (input, ctx) => {
|
|
2401
|
+
let next = (i) => coreFn(i, ctx);
|
|
2266
2402
|
for (const wrap of entry.chain) {
|
|
2267
2403
|
const inner = next;
|
|
2268
2404
|
next = (i) => wrap.run({
|
|
2269
|
-
imports: buildImports(plugins, wrap.owner.importBindings),
|
|
2405
|
+
imports: buildImports(plugins, wrap.owner.importBindings, ctx),
|
|
2270
2406
|
next: inner,
|
|
2271
2407
|
input: i,
|
|
2272
2408
|
// Overwritten by the chain item's own closure with the owning
|
|
@@ -2290,7 +2426,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2290
2426
|
}
|
|
2291
2427
|
);
|
|
2292
2428
|
} else if (out.type === "item") {
|
|
2293
|
-
const itemCore = async (input) => callRun(input);
|
|
2429
|
+
const itemCore = async (input, ctx) => callRun(input, ctx);
|
|
2294
2430
|
entry.value = createFunction(
|
|
2295
2431
|
fold(itemCore),
|
|
2296
2432
|
{
|
|
@@ -2302,7 +2438,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2302
2438
|
);
|
|
2303
2439
|
} else {
|
|
2304
2440
|
entry.value = createRawFunction(
|
|
2305
|
-
(input) => fold(callRun)(input),
|
|
2441
|
+
(input, ctx) => fold(callRun)(input, ctx),
|
|
2306
2442
|
{
|
|
2307
2443
|
sdk,
|
|
2308
2444
|
name: descriptor.name,
|
|
@@ -2325,11 +2461,15 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2325
2461
|
});
|
|
2326
2462
|
return packed;
|
|
2327
2463
|
};
|
|
2464
|
+
const internalValue = (...args) => canonicalValue(pack(args), INTERNAL_CALL);
|
|
2328
2465
|
entry.value = (...args) => canonicalValue(pack(args));
|
|
2329
|
-
entry.internalValue =
|
|
2466
|
+
entry.internalValue = internalValue;
|
|
2467
|
+
entry.bindInternal = (ctx) => ctx ? (...args) => canonicalValue(pack(args), childCallContext(ctx)) : internalValue;
|
|
2330
2468
|
entry.positional = names;
|
|
2331
2469
|
} else {
|
|
2332
|
-
|
|
2470
|
+
const internalValue = (input) => canonicalValue(input, INTERNAL_CALL);
|
|
2471
|
+
entry.internalValue = internalValue;
|
|
2472
|
+
entry.bindInternal = (ctx) => ctx ? (input) => canonicalValue(input, childCallContext(ctx)) : internalValue;
|
|
2333
2473
|
}
|
|
2334
2474
|
plugins[id] = entry;
|
|
2335
2475
|
}
|
|
@@ -2569,7 +2709,7 @@ function createSdk(root, options) {
|
|
|
2569
2709
|
pluginSurface = {};
|
|
2570
2710
|
bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
|
|
2571
2711
|
}
|
|
2572
|
-
for (const
|
|
2712
|
+
for (const key of Object.keys(legacyExports)) context.surface[key] = key;
|
|
2573
2713
|
if (plugin.pluginType === "aggregate") {
|
|
2574
2714
|
recordExportSurface(context, plugin.exports);
|
|
2575
2715
|
} else {
|
|
@@ -2680,6 +2820,9 @@ var CoreCancelledSignal = class extends CoreSignal {
|
|
|
2680
2820
|
this.code = "CANCELLED";
|
|
2681
2821
|
}
|
|
2682
2822
|
};
|
|
2823
|
+
function isCoreCancelledSignal(value) {
|
|
2824
|
+
return isCoreSignal(value) && value.code === "CANCELLED";
|
|
2825
|
+
}
|
|
2683
2826
|
|
|
2684
2827
|
// src/model/resolution/plan.ts
|
|
2685
2828
|
var import_zod3 = require("zod");
|
|
@@ -2708,6 +2851,7 @@ function valueTypeOf(inner) {
|
|
|
2708
2851
|
if (inner instanceof import_zod3.z.ZodEnum) return "string";
|
|
2709
2852
|
if (inner instanceof import_zod3.z.ZodArray) return "array";
|
|
2710
2853
|
if (inner instanceof import_zod3.z.ZodObject) return "object";
|
|
2854
|
+
if (inner instanceof import_zod3.z.ZodRecord) return "object";
|
|
2711
2855
|
return void 0;
|
|
2712
2856
|
}
|
|
2713
2857
|
function staticChoicesOf(inner) {
|
|
@@ -2718,7 +2862,8 @@ function staticChoicesOf(inner) {
|
|
|
2718
2862
|
return void 0;
|
|
2719
2863
|
}
|
|
2720
2864
|
function objectShape(schema) {
|
|
2721
|
-
const
|
|
2865
|
+
const canonical = canonicalInputSchema(schema);
|
|
2866
|
+
const { inner } = canonical ? unwrap(canonical) : { inner: void 0 };
|
|
2722
2867
|
if (inner instanceof import_zod3.z.ZodObject) {
|
|
2723
2868
|
return inner.shape;
|
|
2724
2869
|
}
|
|
@@ -2740,7 +2885,7 @@ function topoOrder2(specs) {
|
|
|
2740
2885
|
}
|
|
2741
2886
|
function planParameters(entry) {
|
|
2742
2887
|
const shape = objectShape(entry.inputSchema);
|
|
2743
|
-
const resolvers = entry.
|
|
2888
|
+
const resolvers = entry.resolvers ?? {};
|
|
2744
2889
|
const names = shape ? [
|
|
2745
2890
|
...Object.keys(shape),
|
|
2746
2891
|
...Object.keys(resolvers).filter(
|
|
@@ -2778,24 +2923,48 @@ function getAtPath(root, path) {
|
|
|
2778
2923
|
}
|
|
2779
2924
|
return node;
|
|
2780
2925
|
}
|
|
2926
|
+
function defineOwn(node, key, value) {
|
|
2927
|
+
Object.defineProperty(node, key, {
|
|
2928
|
+
value,
|
|
2929
|
+
writable: true,
|
|
2930
|
+
enumerable: true,
|
|
2931
|
+
configurable: true
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2781
2934
|
function setAtPath(root, path, value) {
|
|
2782
2935
|
let node = root;
|
|
2783
2936
|
for (let i = 0; i < path.length - 1; i++) {
|
|
2784
2937
|
const seg = path[i];
|
|
2785
|
-
|
|
2786
|
-
|
|
2938
|
+
const existing = Object.prototype.hasOwnProperty.call(node, seg) ? node[seg] : void 0;
|
|
2939
|
+
if (existing != null && typeof existing === "object") {
|
|
2940
|
+
node = existing;
|
|
2941
|
+
} else {
|
|
2942
|
+
const child = {};
|
|
2943
|
+
defineOwn(node, seg, child);
|
|
2944
|
+
node = child;
|
|
2945
|
+
}
|
|
2787
2946
|
}
|
|
2788
|
-
node
|
|
2947
|
+
defineOwn(node, path[path.length - 1], value);
|
|
2789
2948
|
}
|
|
2790
|
-
var
|
|
2949
|
+
var SAFE_SEGMENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2950
|
+
var pathToKey = (path) => {
|
|
2951
|
+
let out = "";
|
|
2952
|
+
for (const segment of path) {
|
|
2953
|
+
if (typeof segment === "number") out += `[${segment}]`;
|
|
2954
|
+
else if (SAFE_SEGMENT.test(segment))
|
|
2955
|
+
out += out === "" ? segment : `.${segment}`;
|
|
2956
|
+
else out += `[${JSON.stringify(segment)}]`;
|
|
2957
|
+
}
|
|
2958
|
+
return out;
|
|
2959
|
+
};
|
|
2791
2960
|
function isSettled(state, path) {
|
|
2792
|
-
return state.settled.includes(
|
|
2961
|
+
return state.settled.includes(pathToKey(path));
|
|
2793
2962
|
}
|
|
2794
2963
|
function remember(state, k) {
|
|
2795
2964
|
if (!state.settled.includes(k)) state.settled.push(k);
|
|
2796
2965
|
}
|
|
2797
2966
|
function settle(state, path) {
|
|
2798
|
-
remember(state,
|
|
2967
|
+
remember(state, pathToKey(path));
|
|
2799
2968
|
}
|
|
2800
2969
|
function clone(state) {
|
|
2801
2970
|
return JSON.parse(JSON.stringify(state));
|
|
@@ -2810,6 +2979,28 @@ function coerce(leaf, raw) {
|
|
|
2810
2979
|
if (raw === "true") return true;
|
|
2811
2980
|
if (raw === "false") return false;
|
|
2812
2981
|
}
|
|
2982
|
+
if (leaf.valueType === "object") {
|
|
2983
|
+
const trimmed = raw.trim();
|
|
2984
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
2985
|
+
try {
|
|
2986
|
+
return JSON.parse(trimmed);
|
|
2987
|
+
} catch {
|
|
2988
|
+
return raw;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
return raw;
|
|
2992
|
+
}
|
|
2993
|
+
if (leaf.valueType === "array") {
|
|
2994
|
+
const trimmed = raw.trim();
|
|
2995
|
+
if (trimmed.startsWith("[")) {
|
|
2996
|
+
try {
|
|
2997
|
+
return JSON.parse(trimmed);
|
|
2998
|
+
} catch {
|
|
2999
|
+
return raw;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
return raw;
|
|
3003
|
+
}
|
|
2813
3004
|
return raw;
|
|
2814
3005
|
}
|
|
2815
3006
|
async function validationError(leaf, value, state) {
|
|
@@ -2867,27 +3058,6 @@ async function objectChildren(resolver, input) {
|
|
|
2867
3058
|
return toLeaf(name, field, resolver.definitions);
|
|
2868
3059
|
});
|
|
2869
3060
|
}
|
|
2870
|
-
function arrayItem(resolver) {
|
|
2871
|
-
const items = resolver.items;
|
|
2872
|
-
const valueType = resolver.itemValueType;
|
|
2873
|
-
if (isRef(items)) {
|
|
2874
|
-
return {
|
|
2875
|
-
name: "",
|
|
2876
|
-
required: true,
|
|
2877
|
-
resolver: resolver.definitions?.[items.ref],
|
|
2878
|
-
extraInput: items.input,
|
|
2879
|
-
valueType,
|
|
2880
|
-
requires: []
|
|
2881
|
-
};
|
|
2882
|
-
}
|
|
2883
|
-
return {
|
|
2884
|
-
name: "",
|
|
2885
|
-
required: true,
|
|
2886
|
-
resolver: items,
|
|
2887
|
-
valueType,
|
|
2888
|
-
requires: []
|
|
2889
|
-
};
|
|
2890
|
-
}
|
|
2891
3061
|
function autoSettles(resolver) {
|
|
2892
3062
|
return resolver.type === "constant" || resolver.type === "info";
|
|
2893
3063
|
}
|
|
@@ -2907,10 +3077,28 @@ async function leafAt(ctx, path, resolved) {
|
|
|
2907
3077
|
const seg = path[i];
|
|
2908
3078
|
if (typeof seg === "number") {
|
|
2909
3079
|
if (leaf?.resolver?.type !== "array") return void 0;
|
|
2910
|
-
leaf =
|
|
3080
|
+
leaf = boundLeaf(
|
|
3081
|
+
"",
|
|
3082
|
+
leaf.resolver.items,
|
|
3083
|
+
leaf.resolver.definitions,
|
|
3084
|
+
leaf.resolver.itemValueType
|
|
3085
|
+
);
|
|
2911
3086
|
} else {
|
|
2912
|
-
|
|
2913
|
-
|
|
3087
|
+
const parent = leaf;
|
|
3088
|
+
const found = children.find((c) => c.name === seg);
|
|
3089
|
+
if (found) {
|
|
3090
|
+
leaf = found;
|
|
3091
|
+
} else if (parent?.resolver?.type === "object" && parent.resolver.additionalKeys) {
|
|
3092
|
+
const ak = parent.resolver.additionalKeys;
|
|
3093
|
+
leaf = boundLeaf(
|
|
3094
|
+
String(seg),
|
|
3095
|
+
ak.values,
|
|
3096
|
+
parent.resolver.definitions,
|
|
3097
|
+
ak.valueValueType
|
|
3098
|
+
);
|
|
3099
|
+
} else {
|
|
3100
|
+
return void 0;
|
|
3101
|
+
}
|
|
2914
3102
|
}
|
|
2915
3103
|
if (i < path.length - 1 && typeof path[i + 1] === "string") {
|
|
2916
3104
|
if (leaf?.resolver?.type !== "object") return void 0;
|
|
@@ -2922,16 +3110,81 @@ async function leafAt(ctx, path, resolved) {
|
|
|
2922
3110
|
}
|
|
2923
3111
|
return leaf;
|
|
2924
3112
|
}
|
|
3113
|
+
function boundLeaf(name, resolverOrRef, definitions, valueType) {
|
|
3114
|
+
if (isRef(resolverOrRef)) {
|
|
3115
|
+
return {
|
|
3116
|
+
name,
|
|
3117
|
+
required: true,
|
|
3118
|
+
resolver: definitions?.[resolverOrRef.ref],
|
|
3119
|
+
extraInput: resolverOrRef.input,
|
|
3120
|
+
valueType,
|
|
3121
|
+
requires: []
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
return {
|
|
3125
|
+
name,
|
|
3126
|
+
required: true,
|
|
3127
|
+
resolver: resolverOrRef,
|
|
3128
|
+
valueType,
|
|
3129
|
+
requires: []
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
async function recordInfoAt(ctx, path, resolved) {
|
|
3133
|
+
const leaf = await leafAt(ctx, path, resolved);
|
|
3134
|
+
const resolver = leaf?.resolver;
|
|
3135
|
+
if (resolver?.type !== "object" || !resolver.additionalKeys) {
|
|
3136
|
+
throw new Error(
|
|
3137
|
+
`expected an object resolver with additionalKeys at "${pathToKey(path)}"`
|
|
3138
|
+
);
|
|
3139
|
+
}
|
|
3140
|
+
if (resolver.getProperties) {
|
|
3141
|
+
throw new Error(
|
|
3142
|
+
`object resolver at "${pathToKey(path)}" cannot combine getProperties with additionalKeys`
|
|
3143
|
+
);
|
|
3144
|
+
}
|
|
3145
|
+
const ak = resolver.additionalKeys;
|
|
3146
|
+
const defs = resolver.definitions;
|
|
3147
|
+
const keyLeaf = ak.keys ? boundLeaf("key", ak.keys, defs, ak.keyValueType ?? "string") : {
|
|
3148
|
+
name: "key",
|
|
3149
|
+
required: true,
|
|
3150
|
+
resolver: { type: "static", inputType: "text" },
|
|
3151
|
+
valueType: "string",
|
|
3152
|
+
requires: []
|
|
3153
|
+
};
|
|
3154
|
+
const valueLeaf = boundLeaf("value", ak.values, defs, ak.valueValueType);
|
|
3155
|
+
if (keyLeaf.resolver && keyLeaf.resolver.type !== "static") {
|
|
3156
|
+
throw new Error(
|
|
3157
|
+
`record key resolver at "${pathToKey(path)}" must be a static free-text prompt, not "${keyLeaf.resolver.type}"`
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
if (valueLeaf.resolver?.type === "object" || valueLeaf.resolver?.type === "array") {
|
|
3161
|
+
throw new Error(
|
|
3162
|
+
`record value resolver at "${pathToKey(path)}" must be a single value, not "${valueLeaf.resolver.type}"`
|
|
3163
|
+
);
|
|
3164
|
+
}
|
|
3165
|
+
return {
|
|
3166
|
+
min: ak.minEntries ?? 0,
|
|
3167
|
+
max: ak.maxEntries ?? Infinity,
|
|
3168
|
+
keyLeaf,
|
|
3169
|
+
valueLeaf,
|
|
3170
|
+
fixedKeys: Object.keys(resolver.properties ?? {})
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
2925
3173
|
async function arrayInfoAt(ctx, path, resolved) {
|
|
2926
3174
|
const leaf = await leafAt(ctx, path, resolved);
|
|
2927
3175
|
const resolver = leaf?.resolver;
|
|
2928
3176
|
if (resolver?.type !== "array") {
|
|
2929
|
-
throw new Error(`expected an array resolver at "${
|
|
3177
|
+
throw new Error(`expected an array resolver at "${pathToKey(path)}"`);
|
|
2930
3178
|
}
|
|
2931
3179
|
return {
|
|
2932
3180
|
min: resolver.minItems ?? 0,
|
|
2933
3181
|
max: resolver.maxItems ?? Infinity,
|
|
2934
|
-
item:
|
|
3182
|
+
item: boundLeaf(
|
|
3183
|
+
String(path[path.length - 1]),
|
|
3184
|
+
resolver.items,
|
|
3185
|
+
resolver.definitions,
|
|
3186
|
+
resolver.itemValueType
|
|
3187
|
+
)
|
|
2935
3188
|
};
|
|
2936
3189
|
}
|
|
2937
3190
|
async function firstPage(result) {
|
|
@@ -3012,6 +3265,9 @@ var AFFORDANCE = {
|
|
|
3012
3265
|
retry: { action: "retry", description: "Retry loading the options" },
|
|
3013
3266
|
cancel: { action: "cancel", description: "Cancel resolution" }
|
|
3014
3267
|
};
|
|
3268
|
+
function affordance(base, description) {
|
|
3269
|
+
return { ...base, description };
|
|
3270
|
+
}
|
|
3015
3271
|
function selectActions(leaf, page, multiple) {
|
|
3016
3272
|
const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
|
|
3017
3273
|
if (searchMode && page.position.search === void 0 && page.items.length === 0) {
|
|
@@ -3126,7 +3382,7 @@ async function buildQuestion(leaf, path, input) {
|
|
|
3126
3382
|
}
|
|
3127
3383
|
};
|
|
3128
3384
|
}
|
|
3129
|
-
function
|
|
3385
|
+
function arrayItemsQuestion(t) {
|
|
3130
3386
|
const actions = [AFFORDANCE.add];
|
|
3131
3387
|
if (t.count >= t.min) actions.push(AFFORDANCE.done);
|
|
3132
3388
|
return {
|
|
@@ -3142,22 +3398,37 @@ function collectionQuestion(t) {
|
|
|
3142
3398
|
actions
|
|
3143
3399
|
};
|
|
3144
3400
|
}
|
|
3145
|
-
function
|
|
3401
|
+
function recordEntriesQuestion(t) {
|
|
3402
|
+
const actions = [
|
|
3403
|
+
affordance(AFFORDANCE.add, "Add another entry")
|
|
3404
|
+
];
|
|
3405
|
+
if (t.count >= t.min) {
|
|
3406
|
+
actions.push(affordance(AFFORDANCE.done, "Finish the entries"));
|
|
3407
|
+
}
|
|
3408
|
+
return {
|
|
3409
|
+
type: "collection",
|
|
3410
|
+
path: t.path,
|
|
3411
|
+
message: `Add another ${t.path[t.path.length - 1]} entry? (${t.count} so far)`,
|
|
3412
|
+
container: "record",
|
|
3413
|
+
count: t.count,
|
|
3414
|
+
min: t.min,
|
|
3415
|
+
...Number.isFinite(t.max) ? { max: t.max } : {},
|
|
3416
|
+
actions
|
|
3417
|
+
};
|
|
3418
|
+
}
|
|
3419
|
+
function objectOptionalQuestion(path) {
|
|
3146
3420
|
return {
|
|
3147
3421
|
type: "collection",
|
|
3148
3422
|
path,
|
|
3149
3423
|
message: `Add ${path[path.length - 1]}?`,
|
|
3150
3424
|
container: "object",
|
|
3151
3425
|
actions: [
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
description: "Provide values for these fields"
|
|
3155
|
-
},
|
|
3156
|
-
{ action: "done", description: "Skip these fields" }
|
|
3426
|
+
affordance(AFFORDANCE.add, "Provide values for these fields"),
|
|
3427
|
+
affordance(AFFORDANCE.done, "Skip these fields")
|
|
3157
3428
|
]
|
|
3158
3429
|
};
|
|
3159
3430
|
}
|
|
3160
|
-
function
|
|
3431
|
+
function objectOptionalPropertiesQuestion(path, pending) {
|
|
3161
3432
|
return {
|
|
3162
3433
|
type: "collection",
|
|
3163
3434
|
path,
|
|
@@ -3174,8 +3445,8 @@ function optionalsGateQuestion(path, pending) {
|
|
|
3174
3445
|
...leaf.valueType ? { valueType: leaf.valueType } : {}
|
|
3175
3446
|
})),
|
|
3176
3447
|
actions: [
|
|
3177
|
-
|
|
3178
|
-
|
|
3448
|
+
affordance(AFFORDANCE.add, "Configure the optional fields"),
|
|
3449
|
+
affordance(AFFORDANCE.done, "Skip the optional fields")
|
|
3179
3450
|
]
|
|
3180
3451
|
};
|
|
3181
3452
|
}
|
|
@@ -3193,7 +3464,8 @@ function finalize(ctx, resolved) {
|
|
|
3193
3464
|
}));
|
|
3194
3465
|
return { status: "invalid", issues };
|
|
3195
3466
|
}
|
|
3196
|
-
var optionalsMarker = (path) => `${
|
|
3467
|
+
var optionalsMarker = (path) => `${pathToKey(path)}?optionals`;
|
|
3468
|
+
var UNSAFE_RECORD_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3197
3469
|
async function findInArray(ctx, state, path) {
|
|
3198
3470
|
if (isSettled(state, path)) return null;
|
|
3199
3471
|
if (getAtPath(state.resolved, path) == null)
|
|
@@ -3214,7 +3486,28 @@ async function findInArray(ctx, state, path) {
|
|
|
3214
3486
|
}
|
|
3215
3487
|
}
|
|
3216
3488
|
if (len < min) return descendItem(ctx, state, path, len, item);
|
|
3217
|
-
if (len < max) return {
|
|
3489
|
+
if (len < max) return { type: "array_items", path, count: len, min, max };
|
|
3490
|
+
settle(state, path);
|
|
3491
|
+
return null;
|
|
3492
|
+
}
|
|
3493
|
+
async function findInRecord(ctx, state, path) {
|
|
3494
|
+
if (isSettled(state, path)) return null;
|
|
3495
|
+
if (getAtPath(state.resolved, path) == null)
|
|
3496
|
+
setAtPath(state.resolved, path, {});
|
|
3497
|
+
if (!state.interactive) {
|
|
3498
|
+
settle(state, path);
|
|
3499
|
+
return null;
|
|
3500
|
+
}
|
|
3501
|
+
const { min, max, keyLeaf, fixedKeys } = await recordInfoAt(
|
|
3502
|
+
ctx,
|
|
3503
|
+
path,
|
|
3504
|
+
state.resolved
|
|
3505
|
+
);
|
|
3506
|
+
const container = getAtPath(state.resolved, path);
|
|
3507
|
+
const fixed = new Set(fixedKeys);
|
|
3508
|
+
const count = Object.keys(container).filter((k) => !fixed.has(k)).length;
|
|
3509
|
+
if (count < min) return { type: "record_key", path, leaf: keyLeaf };
|
|
3510
|
+
if (count < max) return { type: "record_entries", path, count, min, max };
|
|
3218
3511
|
settle(state, path);
|
|
3219
3512
|
return null;
|
|
3220
3513
|
}
|
|
@@ -3232,10 +3525,10 @@ function seedItemSlot(state, itemPath, item) {
|
|
|
3232
3525
|
}
|
|
3233
3526
|
async function descendItem(ctx, state, arrayPath, index, item) {
|
|
3234
3527
|
const itemPath = [...arrayPath, index];
|
|
3235
|
-
const
|
|
3236
|
-
if (
|
|
3237
|
-
if (
|
|
3238
|
-
return {
|
|
3528
|
+
const slotType = seedItemSlot(state, itemPath, item);
|
|
3529
|
+
if (slotType === "object") return findNext(ctx, state, itemPath);
|
|
3530
|
+
if (slotType === "array") return findInArray(ctx, state, itemPath);
|
|
3531
|
+
return { type: "leaf", path: itemPath, leaf: item };
|
|
3239
3532
|
}
|
|
3240
3533
|
async function findNext(ctx, state, path = []) {
|
|
3241
3534
|
const container = getAtPath(state.resolved, path) ?? {};
|
|
@@ -3260,7 +3553,7 @@ async function findNext(ctx, state, path = []) {
|
|
|
3260
3553
|
const pending = ordered.filter(
|
|
3261
3554
|
(c) => !c.required && asksUser(c) && isPendingChild(c)
|
|
3262
3555
|
);
|
|
3263
|
-
return {
|
|
3556
|
+
return { type: "object_optional_properties", path, pending };
|
|
3264
3557
|
}
|
|
3265
3558
|
if (leaf.resolver?.type === "object") {
|
|
3266
3559
|
if (isSettled(state, childPath)) continue;
|
|
@@ -3270,7 +3563,7 @@ async function findNext(ctx, state, path = []) {
|
|
|
3270
3563
|
settle(state, childPath);
|
|
3271
3564
|
continue;
|
|
3272
3565
|
}
|
|
3273
|
-
return {
|
|
3566
|
+
return { type: "object_optional", path: childPath, leaf };
|
|
3274
3567
|
}
|
|
3275
3568
|
setAtPath(state.resolved, childPath, {});
|
|
3276
3569
|
}
|
|
@@ -3302,13 +3595,21 @@ async function findNext(ctx, state, path = []) {
|
|
|
3302
3595
|
}
|
|
3303
3596
|
if (container[leaf.name] !== void 0 || isSettled(state, childPath))
|
|
3304
3597
|
continue;
|
|
3305
|
-
return {
|
|
3598
|
+
return { type: "leaf", path: childPath, leaf };
|
|
3599
|
+
}
|
|
3600
|
+
if (inObject && !isSettled(state, path)) {
|
|
3601
|
+
const self = await leafAt(ctx, path, state.resolved);
|
|
3602
|
+
if (self?.resolver?.type === "object" && self.resolver.additionalKeys) {
|
|
3603
|
+
const rec = await findInRecord(ctx, state, path);
|
|
3604
|
+
if (rec) return rec;
|
|
3605
|
+
}
|
|
3306
3606
|
}
|
|
3307
3607
|
return null;
|
|
3308
3608
|
}
|
|
3309
3609
|
async function askLeaf(state, path, leaf, opts = {}) {
|
|
3310
3610
|
state.current = path;
|
|
3311
|
-
|
|
3611
|
+
if (opts.gate) state.gate = opts.gate;
|
|
3612
|
+
else delete state.gate;
|
|
3312
3613
|
try {
|
|
3313
3614
|
const { question, pagination } = await buildQuestion(
|
|
3314
3615
|
leaf,
|
|
@@ -3329,6 +3630,28 @@ async function askLeaf(state, path, leaf, opts = {}) {
|
|
|
3329
3630
|
return failedResult(state, leaf.name, error);
|
|
3330
3631
|
}
|
|
3331
3632
|
}
|
|
3633
|
+
async function askRecordKey(state, path, keyLeaf, opts = {}) {
|
|
3634
|
+
return askLeaf(state, path, keyLeaf, { gate: "record_key", ...opts });
|
|
3635
|
+
}
|
|
3636
|
+
async function autoResolveLeaf(state, path, leaf) {
|
|
3637
|
+
const resolver = leaf.resolver;
|
|
3638
|
+
if (resolver && autoSettles(resolver)) {
|
|
3639
|
+
if (resolver.type === "constant")
|
|
3640
|
+
setAtPath(state.resolved, path, resolver.value);
|
|
3641
|
+
settle(state, path);
|
|
3642
|
+
return true;
|
|
3643
|
+
}
|
|
3644
|
+
const auto = resolver?.type === "dynamic" ? await resolver.tryResolveWithoutPrompt?.({
|
|
3645
|
+
input: mergeInput(state.resolved, leaf.extraInput)
|
|
3646
|
+
}) : void 0;
|
|
3647
|
+
if (auto) {
|
|
3648
|
+
if (auto.resolvedValue !== void 0)
|
|
3649
|
+
setAtPath(state.resolved, path, auto.resolvedValue);
|
|
3650
|
+
settle(state, path);
|
|
3651
|
+
return true;
|
|
3652
|
+
}
|
|
3653
|
+
return false;
|
|
3654
|
+
}
|
|
3332
3655
|
async function advance(ctx, state) {
|
|
3333
3656
|
for (; ; ) {
|
|
3334
3657
|
const target = await findNext(ctx, state);
|
|
@@ -3338,54 +3661,56 @@ async function advance(ctx, state) {
|
|
|
3338
3661
|
delete state.pagination;
|
|
3339
3662
|
return { state, result: finalize(ctx, state.resolved) };
|
|
3340
3663
|
}
|
|
3341
|
-
if (target.
|
|
3664
|
+
if (target.type === "array_items") {
|
|
3342
3665
|
state.current = target.path;
|
|
3343
|
-
state.gate = "
|
|
3666
|
+
state.gate = "array_items";
|
|
3344
3667
|
delete state.pagination;
|
|
3345
3668
|
return {
|
|
3346
3669
|
state,
|
|
3347
|
-
result: { status: "ask", question:
|
|
3670
|
+
result: { status: "ask", question: arrayItemsQuestion(target) }
|
|
3348
3671
|
};
|
|
3349
3672
|
}
|
|
3350
|
-
if (target.
|
|
3673
|
+
if (target.type === "object_optional") {
|
|
3351
3674
|
state.current = target.path;
|
|
3352
|
-
state.gate = "
|
|
3675
|
+
state.gate = "object_optional";
|
|
3353
3676
|
delete state.pagination;
|
|
3354
3677
|
return {
|
|
3355
3678
|
state,
|
|
3356
|
-
result: {
|
|
3679
|
+
result: {
|
|
3680
|
+
status: "ask",
|
|
3681
|
+
question: objectOptionalQuestion(target.path)
|
|
3682
|
+
}
|
|
3357
3683
|
};
|
|
3358
3684
|
}
|
|
3359
|
-
if (target.
|
|
3685
|
+
if (target.type === "object_optional_properties") {
|
|
3360
3686
|
state.current = target.path;
|
|
3361
|
-
state.gate = "
|
|
3687
|
+
state.gate = "object_optional_properties";
|
|
3362
3688
|
delete state.pagination;
|
|
3363
3689
|
return {
|
|
3364
3690
|
state,
|
|
3365
3691
|
result: {
|
|
3366
3692
|
status: "ask",
|
|
3367
|
-
question:
|
|
3693
|
+
question: objectOptionalPropertiesQuestion(
|
|
3694
|
+
target.path,
|
|
3695
|
+
target.pending
|
|
3696
|
+
)
|
|
3368
3697
|
}
|
|
3369
3698
|
};
|
|
3370
3699
|
}
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3700
|
+
if (target.type === "record_entries") {
|
|
3701
|
+
state.current = target.path;
|
|
3702
|
+
state.gate = "record_entries";
|
|
3703
|
+
delete state.pagination;
|
|
3704
|
+
return {
|
|
3705
|
+
state,
|
|
3706
|
+
result: { status: "ask", question: recordEntriesQuestion(target) }
|
|
3707
|
+
};
|
|
3379
3708
|
}
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
}) : void 0;
|
|
3383
|
-
if (auto) {
|
|
3384
|
-
if (auto.resolvedValue !== void 0)
|
|
3385
|
-
setAtPath(state.resolved, path, auto.resolvedValue);
|
|
3386
|
-
settle(state, path);
|
|
3387
|
-
continue;
|
|
3709
|
+
if (target.type === "record_key") {
|
|
3710
|
+
return askRecordKey(state, target.path, target.leaf);
|
|
3388
3711
|
}
|
|
3712
|
+
const { path, leaf } = target;
|
|
3713
|
+
if (await autoResolveLeaf(state, path, leaf)) continue;
|
|
3389
3714
|
if (!state.interactive) {
|
|
3390
3715
|
if (!leaf.required) {
|
|
3391
3716
|
settle(state, path);
|
|
@@ -3418,10 +3743,18 @@ async function step(ctx, prior, action) {
|
|
|
3418
3743
|
delete state.pagination;
|
|
3419
3744
|
return { state, result: { status: "cancelled" } };
|
|
3420
3745
|
}
|
|
3746
|
+
if (state.gate === "record_key") {
|
|
3747
|
+
return stepRecordKey(ctx, state, action);
|
|
3748
|
+
}
|
|
3421
3749
|
const path = state.current;
|
|
3422
3750
|
if (!path) throw new Error("step called with no outstanding question");
|
|
3423
3751
|
const leaf = await leafAt(ctx, path, state.resolved);
|
|
3424
|
-
if (leaf
|
|
3752
|
+
if (!leaf) {
|
|
3753
|
+
throw new Error(
|
|
3754
|
+
`no resolver for the outstanding question at "${pathToKey(path)}"`
|
|
3755
|
+
);
|
|
3756
|
+
}
|
|
3757
|
+
if (action.type === "search" || action.type === "next_page" || action.type === "previous_page" || action.type === "retry") {
|
|
3425
3758
|
return refine(ctx, state, leaf, path, action);
|
|
3426
3759
|
}
|
|
3427
3760
|
if (action.type === "add" || action.type === "done") {
|
|
@@ -3438,19 +3771,26 @@ async function step(ctx, prior, action) {
|
|
|
3438
3771
|
settle(state, path);
|
|
3439
3772
|
return advance(ctx, state);
|
|
3440
3773
|
}
|
|
3441
|
-
if (gate === "
|
|
3774
|
+
if (gate === "object_optional") {
|
|
3442
3775
|
setAtPath(state.resolved, path, {});
|
|
3443
3776
|
return advance(ctx, state);
|
|
3444
3777
|
}
|
|
3445
|
-
if (gate === "
|
|
3778
|
+
if (gate === "object_optional_properties") {
|
|
3446
3779
|
remember(state, optionalsMarker(path));
|
|
3447
3780
|
return advance(ctx, state);
|
|
3448
3781
|
}
|
|
3782
|
+
if (gate === "record_entries") {
|
|
3783
|
+
const { keyLeaf } = await recordInfoAt(ctx, path, state.resolved);
|
|
3784
|
+
return askRecordKey(state, path, keyLeaf);
|
|
3785
|
+
}
|
|
3449
3786
|
const items = getAtPath(state.resolved, path) ?? [];
|
|
3450
3787
|
const { item } = await arrayInfoAt(ctx, path, state.resolved);
|
|
3451
3788
|
const itemPath = [...path, items.length];
|
|
3452
|
-
if (seedItemSlot(state, itemPath, item) === "leaf")
|
|
3789
|
+
if (seedItemSlot(state, itemPath, item) === "leaf") {
|
|
3790
|
+
if (await autoResolveLeaf(state, itemPath, item))
|
|
3791
|
+
return advance(ctx, state);
|
|
3453
3792
|
return askLeaf(state, itemPath, item);
|
|
3793
|
+
}
|
|
3454
3794
|
return advance(ctx, state);
|
|
3455
3795
|
}
|
|
3456
3796
|
if (state.gate) {
|
|
@@ -3461,81 +3801,37 @@ async function step(ctx, prior, action) {
|
|
|
3461
3801
|
switch (action.type) {
|
|
3462
3802
|
case "choose":
|
|
3463
3803
|
case "custom": {
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
if (
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
const page = await fetchListing(
|
|
3476
|
-
leaf,
|
|
3477
|
-
state.resolved,
|
|
3478
|
-
state.pagination.position,
|
|
3479
|
-
context
|
|
3480
|
-
);
|
|
3481
|
-
state.pagination = toPagination(page);
|
|
3482
|
-
return {
|
|
3483
|
-
state,
|
|
3484
|
-
result: {
|
|
3485
|
-
status: "ask",
|
|
3486
|
-
question: selectQuestion(
|
|
3487
|
-
leaf,
|
|
3488
|
-
path,
|
|
3489
|
-
state.resolved,
|
|
3490
|
-
page,
|
|
3491
|
-
context
|
|
3492
|
-
),
|
|
3493
|
-
error
|
|
3494
|
-
}
|
|
3495
|
-
};
|
|
3496
|
-
} catch (fetchError) {
|
|
3497
|
-
state.pagination = failedPagination(
|
|
3498
|
-
state.pagination,
|
|
3499
|
-
state.pagination.position
|
|
3500
|
-
);
|
|
3501
|
-
return failedResult(state, leaf.name, fetchError);
|
|
3502
|
-
}
|
|
3503
|
-
}
|
|
3504
|
-
return askLeaf(state, path, leaf, { error });
|
|
3804
|
+
let error;
|
|
3805
|
+
try {
|
|
3806
|
+
error = await validationError(leaf, action.value, state);
|
|
3807
|
+
} catch (thrown) {
|
|
3808
|
+
return failedResult(state, leaf.name, thrown);
|
|
3809
|
+
}
|
|
3810
|
+
if (error) {
|
|
3811
|
+
if (state.pagination && leaf.resolver?.type === "dynamic") {
|
|
3812
|
+
return renderPageAt(state, leaf, path, state.pagination.position, {
|
|
3813
|
+
error
|
|
3814
|
+
});
|
|
3505
3815
|
}
|
|
3816
|
+
return askLeaf(state, path, leaf, { error });
|
|
3506
3817
|
}
|
|
3507
|
-
setAtPath(
|
|
3508
|
-
state.resolved,
|
|
3509
|
-
path,
|
|
3510
|
-
leaf ? coerce(leaf, action.value) : action.value
|
|
3511
|
-
);
|
|
3818
|
+
setAtPath(state.resolved, path, coerce(leaf, action.value));
|
|
3512
3819
|
break;
|
|
3513
3820
|
}
|
|
3514
3821
|
case "skip":
|
|
3515
3822
|
settle(state, path);
|
|
3516
3823
|
break;
|
|
3517
3824
|
default:
|
|
3518
|
-
throw new Error(
|
|
3825
|
+
throw new Error(
|
|
3826
|
+
`action "${action.type}" is not supported here`
|
|
3827
|
+
);
|
|
3519
3828
|
}
|
|
3520
3829
|
delete state.current;
|
|
3521
3830
|
delete state.pagination;
|
|
3522
3831
|
return advance(ctx, state);
|
|
3523
3832
|
}
|
|
3524
|
-
async function
|
|
3525
|
-
const position = positionAfter(state.pagination, action);
|
|
3833
|
+
async function renderPageAt(state, leaf, path, position, opts = {}) {
|
|
3526
3834
|
try {
|
|
3527
|
-
if (action.type === "search") {
|
|
3528
|
-
const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
|
|
3529
|
-
input: mergeInput(state.resolved, leaf.extraInput),
|
|
3530
|
-
search: action.term
|
|
3531
|
-
}) : void 0;
|
|
3532
|
-
if (exact) {
|
|
3533
|
-
setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
|
|
3534
|
-
delete state.current;
|
|
3535
|
-
delete state.pagination;
|
|
3536
|
-
return advance(ctx, state);
|
|
3537
|
-
}
|
|
3538
|
-
}
|
|
3539
3835
|
const context = await resolveContext(leaf, state.resolved);
|
|
3540
3836
|
const page = await fetchListing(leaf, state.resolved, position, context);
|
|
3541
3837
|
state.pagination = toPagination(page);
|
|
@@ -3543,7 +3839,8 @@ async function refine(ctx, state, leaf, path, action) {
|
|
|
3543
3839
|
state,
|
|
3544
3840
|
result: {
|
|
3545
3841
|
status: "ask",
|
|
3546
|
-
question: selectQuestion(leaf, path, state.resolved, page, context)
|
|
3842
|
+
question: selectQuestion(leaf, path, state.resolved, page, context),
|
|
3843
|
+
...opts.error ? { error: opts.error } : {}
|
|
3547
3844
|
}
|
|
3548
3845
|
};
|
|
3549
3846
|
} catch (error) {
|
|
@@ -3551,6 +3848,65 @@ async function refine(ctx, state, leaf, path, action) {
|
|
|
3551
3848
|
return failedResult(state, leaf.name, error);
|
|
3552
3849
|
}
|
|
3553
3850
|
}
|
|
3851
|
+
async function refine(ctx, state, leaf, path, action) {
|
|
3852
|
+
const position = positionAfter(state.pagination, action);
|
|
3853
|
+
if (action.type === "search") {
|
|
3854
|
+
try {
|
|
3855
|
+
const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
|
|
3856
|
+
input: mergeInput(state.resolved, leaf.extraInput),
|
|
3857
|
+
search: action.term
|
|
3858
|
+
}) : void 0;
|
|
3859
|
+
if (exact) {
|
|
3860
|
+
setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
|
|
3861
|
+
delete state.current;
|
|
3862
|
+
delete state.pagination;
|
|
3863
|
+
return advance(ctx, state);
|
|
3864
|
+
}
|
|
3865
|
+
} catch (error) {
|
|
3866
|
+
state.pagination = failedPagination(state.pagination, position);
|
|
3867
|
+
return failedResult(state, leaf.name, error);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
return renderPageAt(state, leaf, path, position);
|
|
3871
|
+
}
|
|
3872
|
+
async function stepRecordKey(ctx, state, action) {
|
|
3873
|
+
const path = state.current;
|
|
3874
|
+
if (!path)
|
|
3875
|
+
throw new Error("record key step called with no outstanding question");
|
|
3876
|
+
const { keyLeaf, valueLeaf } = await recordInfoAt(ctx, path, state.resolved);
|
|
3877
|
+
if (action.type === "skip") {
|
|
3878
|
+
delete state.gate;
|
|
3879
|
+
delete state.current;
|
|
3880
|
+
delete state.pagination;
|
|
3881
|
+
return advance(ctx, state);
|
|
3882
|
+
}
|
|
3883
|
+
if (action.type !== "custom" && action.type !== "choose") {
|
|
3884
|
+
throw new Error(
|
|
3885
|
+
`action "${action.type}" is not supported while entering a record key`
|
|
3886
|
+
);
|
|
3887
|
+
}
|
|
3888
|
+
const raw = Array.isArray(action.value) ? action.value[0] : action.value;
|
|
3889
|
+
const entryKey = String(coerce(keyLeaf, raw));
|
|
3890
|
+
if (entryKey.trim() === "") {
|
|
3891
|
+
return askRecordKey(state, path, keyLeaf, { error: "A key is required." });
|
|
3892
|
+
}
|
|
3893
|
+
if (UNSAFE_RECORD_KEYS.has(entryKey)) {
|
|
3894
|
+
return askRecordKey(state, path, keyLeaf, {
|
|
3895
|
+
error: `"${entryKey}" is not an allowed key.`
|
|
3896
|
+
});
|
|
3897
|
+
}
|
|
3898
|
+
const container = getAtPath(state.resolved, path);
|
|
3899
|
+
if (Object.prototype.hasOwnProperty.call(container, entryKey)) {
|
|
3900
|
+
return askRecordKey(state, path, keyLeaf, {
|
|
3901
|
+
error: `"${entryKey}" is already set.`
|
|
3902
|
+
});
|
|
3903
|
+
}
|
|
3904
|
+
const valuePath = [...path, entryKey];
|
|
3905
|
+
if (await autoResolveLeaf(state, valuePath, valueLeaf)) {
|
|
3906
|
+
return advance(ctx, state);
|
|
3907
|
+
}
|
|
3908
|
+
return askLeaf(state, valuePath, valueLeaf);
|
|
3909
|
+
}
|
|
3554
3910
|
function failedPagination(pagination, retryPosition) {
|
|
3555
3911
|
return {
|
|
3556
3912
|
position: pagination?.position ?? firstPagePosition(),
|
|
@@ -3606,7 +3962,7 @@ function projectSummary(entry) {
|
|
|
3606
3962
|
};
|
|
3607
3963
|
}
|
|
3608
3964
|
function projectMethod(entry) {
|
|
3609
|
-
const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
|
|
3965
|
+
const inputProperties = toJsonSchema(canonicalInputSchema(entry.inputSchema))?.properties;
|
|
3610
3966
|
const parameters = {};
|
|
3611
3967
|
for (const spec of planParameters(entry).parameters) {
|
|
3612
3968
|
const dynamic = spec.resolver?.type === "dynamic" ? spec.resolver : void 0;
|
|
@@ -3639,7 +3995,12 @@ function createController(sdk) {
|
|
|
3639
3995
|
const entry = entryFor(method);
|
|
3640
3996
|
return {
|
|
3641
3997
|
method,
|
|
3642
|
-
|
|
3998
|
+
// A method that owns its input validation (`skipInputValidation`, e.g.
|
|
3999
|
+
// fetch) must not be re-validated by the controller's final `safeParse`;
|
|
4000
|
+
// drop the schema so `finalize` returns the resolved input untouched.
|
|
4001
|
+
// Planning still reads `entry.inputSchema` directly, so parameters are
|
|
4002
|
+
// unaffected.
|
|
4003
|
+
schema: entry.skipInputValidation ? void 0 : entry.inputSchema,
|
|
3643
4004
|
parameters: planParameters(entry).parameters
|
|
3644
4005
|
};
|
|
3645
4006
|
}
|
|
@@ -3704,59 +4065,6 @@ function createCorePlugin(options) {
|
|
|
3704
4065
|
}
|
|
3705
4066
|
});
|
|
3706
4067
|
}
|
|
3707
|
-
|
|
3708
|
-
// src/utils/schema-utils.ts
|
|
3709
|
-
var import_zod5 = require("zod");
|
|
3710
|
-
function getOutputSchema(inputSchema) {
|
|
3711
|
-
return inputSchema._zod.def.outputSchema;
|
|
3712
|
-
}
|
|
3713
|
-
function withOutputSchema(inputSchema, outputSchema) {
|
|
3714
|
-
Object.assign(inputSchema._zod.def, {
|
|
3715
|
-
outputSchema
|
|
3716
|
-
});
|
|
3717
|
-
return inputSchema;
|
|
3718
|
-
}
|
|
3719
|
-
function withResolver(schema, config) {
|
|
3720
|
-
schema._zod.def.resolverMeta = config;
|
|
3721
|
-
return schema;
|
|
3722
|
-
}
|
|
3723
|
-
function getSchemaDescription(schema) {
|
|
3724
|
-
return schema.description;
|
|
3725
|
-
}
|
|
3726
|
-
function getFieldDescriptions(schema) {
|
|
3727
|
-
const descriptions = {};
|
|
3728
|
-
const shape = schema.shape;
|
|
3729
|
-
for (const [key2, fieldSchema] of Object.entries(shape)) {
|
|
3730
|
-
if (fieldSchema instanceof import_zod5.z.ZodType && fieldSchema.description) {
|
|
3731
|
-
descriptions[key2] = fieldSchema.description;
|
|
3732
|
-
}
|
|
3733
|
-
}
|
|
3734
|
-
return descriptions;
|
|
3735
|
-
}
|
|
3736
|
-
function withPositional(schema) {
|
|
3737
|
-
Object.assign(schema._zod.def, {
|
|
3738
|
-
positionalMeta: { positional: true }
|
|
3739
|
-
});
|
|
3740
|
-
return schema;
|
|
3741
|
-
}
|
|
3742
|
-
function schemaHasPositionalMeta(schema) {
|
|
3743
|
-
return "positionalMeta" in schema._zod.def;
|
|
3744
|
-
}
|
|
3745
|
-
function isPositional(schema) {
|
|
3746
|
-
if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
|
|
3747
|
-
return true;
|
|
3748
|
-
}
|
|
3749
|
-
if (schema instanceof import_zod5.z.ZodOptional) {
|
|
3750
|
-
return isPositional(schema._zod.def.innerType);
|
|
3751
|
-
}
|
|
3752
|
-
if (schema instanceof import_zod5.z.ZodDefault) {
|
|
3753
|
-
return isPositional(schema._zod.def.innerType);
|
|
3754
|
-
}
|
|
3755
|
-
return false;
|
|
3756
|
-
}
|
|
3757
|
-
function openEnum(values, description) {
|
|
3758
|
-
return import_zod5.z.union([import_zod5.z.enum(values), import_zod5.z.string()]).describe(description);
|
|
3759
|
-
}
|
|
3760
4068
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3761
4069
|
0 && (module.exports = {
|
|
3762
4070
|
CONTEXT,
|
|
@@ -3769,6 +4077,7 @@ function openEnum(values, description) {
|
|
|
3769
4077
|
CoreErrorCode,
|
|
3770
4078
|
CoreSignal,
|
|
3771
4079
|
addPlugin,
|
|
4080
|
+
canonicalInputSchema,
|
|
3772
4081
|
composePlugins,
|
|
3773
4082
|
concatLists,
|
|
3774
4083
|
concatPaginated,
|
|
@@ -3812,6 +4121,7 @@ function openEnum(values, description) {
|
|
|
3812
4121
|
getOutputSchema,
|
|
3813
4122
|
getRegistryPlugin,
|
|
3814
4123
|
getSchemaDescription,
|
|
4124
|
+
isCoreCancelledSignal,
|
|
3815
4125
|
isCoreError,
|
|
3816
4126
|
isCoreSignal,
|
|
3817
4127
|
isNestedMethodCall,
|