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