@zapier/kitcore 0.7.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 +25 -0
- package/dist/index.cjs +626 -316
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +229 -114
- package/dist/index.d.ts +229 -114
- package/dist/index.mjs +621 -313
- 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,7 +30,9 @@ __export(index_exports, {
|
|
|
30
30
|
CoreErrorCode: () => CoreErrorCode,
|
|
31
31
|
CoreSignal: () => CoreSignal,
|
|
32
32
|
addPlugin: () => addPlugin,
|
|
33
|
+
canonicalInputSchema: () => canonicalInputSchema,
|
|
33
34
|
composePlugins: () => composePlugins,
|
|
35
|
+
concatLists: () => concatLists,
|
|
34
36
|
concatPaginated: () => concatPaginated,
|
|
35
37
|
coreOptionsPluginRef: () => coreOptionsPluginRef,
|
|
36
38
|
createAsyncContext: () => createAsyncContext,
|
|
@@ -97,9 +99,6 @@ __export(index_exports, {
|
|
|
97
99
|
});
|
|
98
100
|
module.exports = __toCommonJS(index_exports);
|
|
99
101
|
|
|
100
|
-
// src/registry.ts
|
|
101
|
-
var import_zod = require("zod");
|
|
102
|
-
|
|
103
102
|
// src/utils/string-utils.ts
|
|
104
103
|
function toTitleCase(input) {
|
|
105
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(" ");
|
|
@@ -123,6 +122,65 @@ function pluralizeLastWord(title) {
|
|
|
123
122
|
return [...words.slice(0, -1), pluralize(words[words.length - 1])].join(" ");
|
|
124
123
|
}
|
|
125
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
|
+
|
|
126
184
|
// src/registry.ts
|
|
127
185
|
function resolveCategoryDefinition(ref) {
|
|
128
186
|
const def = typeof ref === "string" ? { key: ref } : ref;
|
|
@@ -133,30 +191,25 @@ function resolveCategoryDefinition(ref) {
|
|
|
133
191
|
titlePlural: def.titlePlural ?? pluralizeLastWord(title)
|
|
134
192
|
};
|
|
135
193
|
}
|
|
136
|
-
function canonicalInputSchema(schema) {
|
|
137
|
-
if (schema instanceof import_zod.z.ZodUnion) {
|
|
138
|
-
return schema.options[0];
|
|
139
|
-
}
|
|
140
|
-
return schema;
|
|
141
|
-
}
|
|
142
194
|
function buildRegistry({
|
|
143
195
|
sdk,
|
|
144
196
|
meta,
|
|
145
197
|
formatters,
|
|
146
|
-
|
|
198
|
+
resolvers,
|
|
147
199
|
positional,
|
|
200
|
+
skipInputValidation,
|
|
148
201
|
packageFilter
|
|
149
202
|
}) {
|
|
150
203
|
const definitionsByKey = /* @__PURE__ */ new Map();
|
|
151
204
|
const objectDeclaredKeys = /* @__PURE__ */ new Set();
|
|
152
205
|
for (const m of Object.values(meta)) {
|
|
153
206
|
for (const ref of m.categories ?? []) {
|
|
154
|
-
const
|
|
207
|
+
const key = typeof ref === "string" ? ref : ref.key;
|
|
155
208
|
if (typeof ref === "object") {
|
|
156
|
-
objectDeclaredKeys.add(
|
|
157
|
-
definitionsByKey.set(
|
|
158
|
-
} else if (!objectDeclaredKeys.has(
|
|
159
|
-
definitionsByKey.set(
|
|
209
|
+
objectDeclaredKeys.add(key);
|
|
210
|
+
definitionsByKey.set(key, resolveCategoryDefinition(ref));
|
|
211
|
+
} else if (!objectDeclaredKeys.has(key)) {
|
|
212
|
+
definitionsByKey.set(key, resolveCategoryDefinition(ref));
|
|
160
213
|
}
|
|
161
214
|
}
|
|
162
215
|
}
|
|
@@ -164,30 +217,29 @@ function buildRegistry({
|
|
|
164
217
|
definitionsByKey.set("other", resolveCategoryDefinition("other"));
|
|
165
218
|
}
|
|
166
219
|
const knownCategories = Array.from(definitionsByKey.keys());
|
|
167
|
-
const functions = Object.keys(meta).filter((
|
|
168
|
-
const property = sdk[
|
|
220
|
+
const functions = Object.keys(meta).filter((key) => {
|
|
221
|
+
const property = sdk[key];
|
|
169
222
|
if (typeof property === "function") return true;
|
|
170
|
-
const [rootKey] =
|
|
223
|
+
const [rootKey] = key.split(".");
|
|
171
224
|
const rootProperty = sdk[rootKey];
|
|
172
225
|
return typeof rootProperty === "object" && rootProperty !== null;
|
|
173
|
-
}).map((
|
|
174
|
-
const m = meta[
|
|
226
|
+
}).map((key) => {
|
|
227
|
+
const m = meta[key];
|
|
175
228
|
return {
|
|
176
|
-
name:
|
|
229
|
+
name: key,
|
|
177
230
|
description: m.description,
|
|
178
231
|
type: m.type,
|
|
179
232
|
itemType: m.itemType,
|
|
180
233
|
returnType: m.returnType,
|
|
181
234
|
inputSchema: canonicalInputSchema(m.inputSchema),
|
|
182
|
-
inputParameters: m.inputParameters,
|
|
183
235
|
outputSchema: m.outputSchema,
|
|
184
|
-
positional: positional?.[
|
|
236
|
+
positional: positional?.[key],
|
|
237
|
+
skipInputValidation: skipInputValidation?.[key],
|
|
185
238
|
categories: (m.categories ?? []).map(
|
|
186
239
|
(c) => typeof c === "string" ? c : c.key
|
|
187
240
|
),
|
|
188
|
-
resolvers:
|
|
189
|
-
|
|
190
|
-
formatter: formatters?.[key2],
|
|
241
|
+
resolvers: resolvers?.[key],
|
|
242
|
+
formatter: formatters?.[key],
|
|
191
243
|
experimental: m.experimental,
|
|
192
244
|
packages: m.packages,
|
|
193
245
|
confirm: m.confirm ?? (m.type === "delete" ? "delete" : void 0),
|
|
@@ -544,53 +596,49 @@ function decodeConcatCursor(incoming) {
|
|
|
544
596
|
}
|
|
545
597
|
return { index: 0, cursor: incoming };
|
|
546
598
|
}
|
|
547
|
-
function
|
|
599
|
+
async function concatLists({
|
|
548
600
|
sources,
|
|
549
601
|
pageSize = 100,
|
|
550
602
|
cursor
|
|
551
603
|
}) {
|
|
552
604
|
if (sources.length === 0) {
|
|
553
|
-
|
|
554
|
-
return Object.assign(Promise.resolve(empty), {
|
|
555
|
-
[Symbol.asyncIterator]: async function* () {
|
|
556
|
-
yield empty;
|
|
557
|
-
}
|
|
558
|
-
});
|
|
605
|
+
return { data: [] };
|
|
559
606
|
}
|
|
560
607
|
const pageFunction = async (options) => {
|
|
561
|
-
let { index, cursor:
|
|
608
|
+
let { index, cursor: listCursor } = decodeConcatCursor(options.cursor);
|
|
562
609
|
while (index < sources.length) {
|
|
563
|
-
const page = await sources[index]({ cursor:
|
|
564
|
-
const
|
|
565
|
-
if (page.data.length === 0 && !
|
|
610
|
+
const page = await sources[index]({ cursor: listCursor });
|
|
611
|
+
const hasMoreInList = page.nextCursor != null;
|
|
612
|
+
if (page.data.length === 0 && !hasMoreInList) {
|
|
566
613
|
index++;
|
|
567
|
-
|
|
614
|
+
listCursor = void 0;
|
|
568
615
|
continue;
|
|
569
616
|
}
|
|
570
617
|
return {
|
|
571
618
|
data: page.data,
|
|
572
|
-
nextCursor:
|
|
619
|
+
nextCursor: hasMoreInList ? encodeConcatCursor(index, page.nextCursor) : index < sources.length - 1 ? encodeConcatCursor(index + 1, void 0) : void 0
|
|
573
620
|
};
|
|
574
621
|
}
|
|
575
622
|
return { data: [] };
|
|
576
623
|
};
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
});
|
|
624
|
+
const result = await paginateBuffered(pageFunction, {
|
|
625
|
+
pageSize,
|
|
626
|
+
cursor
|
|
627
|
+
}).next();
|
|
628
|
+
return result.done ? { data: [] } : result.value;
|
|
629
|
+
}
|
|
630
|
+
function concatPaginated({
|
|
631
|
+
sources,
|
|
632
|
+
pageSize,
|
|
633
|
+
cursor
|
|
634
|
+
}) {
|
|
635
|
+
logDeprecation("concatPaginated() is deprecated. Use concatLists() instead.");
|
|
636
|
+
return concatLists({ sources, pageSize, cursor });
|
|
592
637
|
}
|
|
593
638
|
function toIterable(source) {
|
|
639
|
+
logDeprecation(
|
|
640
|
+
"toIterable() is deprecated. Call .pages() on the paginated result instead."
|
|
641
|
+
);
|
|
594
642
|
return { [Symbol.asyncIterator]: () => source[Symbol.asyncIterator]() };
|
|
595
643
|
}
|
|
596
644
|
|
|
@@ -678,6 +726,52 @@ function runInMethodScope(fn) {
|
|
|
678
726
|
var runWithTelemetryContext = runInMethodScope;
|
|
679
727
|
var isTelemetryNested = isNestedMethodCall;
|
|
680
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
|
+
|
|
681
775
|
// src/utils/core-options.ts
|
|
682
776
|
function defaultLogDeprecation({
|
|
683
777
|
methodName,
|
|
@@ -696,6 +790,9 @@ function resolveCoreOptions(context) {
|
|
|
696
790
|
return context.core;
|
|
697
791
|
}
|
|
698
792
|
var INTERNAL_CALL = Symbol("kitcore.internalCall");
|
|
793
|
+
function resolveCallContext(secondArg) {
|
|
794
|
+
return isCallContext(secondArg) ? secondArg : rootCallContext();
|
|
795
|
+
}
|
|
699
796
|
function signalDeprecation(context, methodName, getDeprecation) {
|
|
700
797
|
if (isInsideObserver()) return;
|
|
701
798
|
const deprecation = getDeprecation?.();
|
|
@@ -725,14 +822,16 @@ function createFunction(coreFn, options) {
|
|
|
725
822
|
const functionName = name || coreFn.name;
|
|
726
823
|
const namedFunctions = {
|
|
727
824
|
[functionName]: async function(callOptions) {
|
|
728
|
-
|
|
825
|
+
const internal = arguments[1];
|
|
826
|
+
const context = resolveCallContext(internal);
|
|
827
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
729
828
|
signalDeprecation(sdk.context, functionName, getDeprecation);
|
|
730
829
|
}
|
|
731
830
|
return runInMethodScope(async () => {
|
|
732
831
|
const startTime = Date.now();
|
|
733
832
|
const normalizedOptions = callOptions ?? {};
|
|
734
833
|
const args = [normalizedOptions];
|
|
735
|
-
const depth = getCurrentDepth();
|
|
834
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
736
835
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
737
836
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
738
837
|
hooks?.onMethodStart?.({
|
|
@@ -751,12 +850,15 @@ function createFunction(coreFn, options) {
|
|
|
751
850
|
adaptError
|
|
752
851
|
}
|
|
753
852
|
);
|
|
754
|
-
result = await coreFn(
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
853
|
+
result = await coreFn(
|
|
854
|
+
{
|
|
855
|
+
...normalizedOptions,
|
|
856
|
+
...validatedOptions
|
|
857
|
+
},
|
|
858
|
+
context
|
|
859
|
+
);
|
|
758
860
|
} else {
|
|
759
|
-
result = await coreFn(normalizedOptions);
|
|
861
|
+
result = await coreFn(normalizedOptions, context);
|
|
760
862
|
}
|
|
761
863
|
hooks?.onMethodEnd?.({
|
|
762
864
|
methodName: functionName,
|
|
@@ -786,17 +888,19 @@ function createFunction(coreFn, options) {
|
|
|
786
888
|
function createRawFunction(coreFn, options) {
|
|
787
889
|
const { sdk, name, schema, positional, getDeprecation } = options;
|
|
788
890
|
return function(rawInput) {
|
|
789
|
-
|
|
891
|
+
const internal = arguments[1];
|
|
892
|
+
const context = resolveCallContext(internal);
|
|
893
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
790
894
|
signalDeprecation(sdk.context, name, getDeprecation);
|
|
791
895
|
}
|
|
792
896
|
return runInMethodScope(() => {
|
|
793
897
|
const startTime = Date.now();
|
|
794
|
-
const depth = getCurrentDepth();
|
|
898
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
795
899
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
796
900
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
797
901
|
const input = schema ? rawInput ?? {} : rawInput;
|
|
798
902
|
const record = input;
|
|
799
|
-
const args = positional ? positional.filter((
|
|
903
|
+
const args = positional ? positional.filter((key) => record?.[key] !== void 0).map((key) => record?.[key]) : [input];
|
|
800
904
|
hooks?.onMethodStart?.({
|
|
801
905
|
methodName: name,
|
|
802
906
|
args,
|
|
@@ -815,7 +919,7 @@ function createRawFunction(coreFn, options) {
|
|
|
815
919
|
};
|
|
816
920
|
try {
|
|
817
921
|
const parsed = schema ? validateOptions(schema, input, { adaptError }) : input;
|
|
818
|
-
const result = coreFn(parsed);
|
|
922
|
+
const result = coreFn(parsed, context);
|
|
819
923
|
if (result !== null && typeof result === "object" && typeof result.then === "function") {
|
|
820
924
|
return result.then(
|
|
821
925
|
(value) => {
|
|
@@ -854,9 +958,9 @@ function createPageFunction(coreFn, {
|
|
|
854
958
|
}) {
|
|
855
959
|
const functionName = coreFn.name + "Page";
|
|
856
960
|
const namedFunctions = {
|
|
857
|
-
[functionName]: async function(options) {
|
|
961
|
+
[functionName]: async function(options, callContext) {
|
|
858
962
|
try {
|
|
859
|
-
const response = await coreFn(options);
|
|
963
|
+
const response = await coreFn(options, callContext);
|
|
860
964
|
const page = adaptPage ? adaptPage(response) : response;
|
|
861
965
|
if (!isSdkPage(page)) {
|
|
862
966
|
throw new Error(
|
|
@@ -880,14 +984,16 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
880
984
|
const functionName = name || coreFn.name;
|
|
881
985
|
const namedFunctions = {
|
|
882
986
|
[functionName]: function(callOptions) {
|
|
883
|
-
|
|
987
|
+
const internal = arguments[1];
|
|
988
|
+
const context = resolveCallContext(internal);
|
|
989
|
+
if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
|
|
884
990
|
signalDeprecation(sdk.context, functionName, getDeprecation);
|
|
885
991
|
}
|
|
886
992
|
return runInMethodScope(() => {
|
|
887
993
|
const startTime = Date.now();
|
|
888
994
|
const normalizedOptions = callOptions ?? {};
|
|
889
995
|
const args = [normalizedOptions];
|
|
890
|
-
const depth = getCurrentDepth();
|
|
996
|
+
const depth = Math.max(context.depth, getCurrentDepth());
|
|
891
997
|
const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
|
|
892
998
|
const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
|
|
893
999
|
hooks?.onMethodStart?.({
|
|
@@ -906,7 +1012,11 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
906
1012
|
...validatedOptions,
|
|
907
1013
|
pageSize
|
|
908
1014
|
};
|
|
909
|
-
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
|
+
);
|
|
910
1020
|
const firstPagePromise = iterator.next().then((result) => {
|
|
911
1021
|
if (result.done) {
|
|
912
1022
|
throw new Error("Paginate should always iterate at least once");
|
|
@@ -943,6 +1053,13 @@ function createPaginatedFunction(coreFn, options) {
|
|
|
943
1053
|
[Symbol.asyncIterator]() {
|
|
944
1054
|
return pageStream;
|
|
945
1055
|
},
|
|
1056
|
+
pages: function() {
|
|
1057
|
+
return {
|
|
1058
|
+
[Symbol.asyncIterator]() {
|
|
1059
|
+
return pageStream;
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
},
|
|
946
1063
|
items: function() {
|
|
947
1064
|
return {
|
|
948
1065
|
[Symbol.asyncIterator]: async function* () {
|
|
@@ -1050,11 +1167,11 @@ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
|
|
|
1050
1167
|
"context",
|
|
1051
1168
|
"getRegistry"
|
|
1052
1169
|
]);
|
|
1053
|
-
function hasOwn(obj,
|
|
1054
|
-
return Object.prototype.hasOwnProperty.call(obj,
|
|
1170
|
+
function hasOwn(obj, key) {
|
|
1171
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
1055
1172
|
}
|
|
1056
|
-
function setOwn(target,
|
|
1057
|
-
Object.defineProperty(target,
|
|
1173
|
+
function setOwn(target, key, value) {
|
|
1174
|
+
Object.defineProperty(target, key, {
|
|
1058
1175
|
value,
|
|
1059
1176
|
enumerable: true,
|
|
1060
1177
|
configurable: true,
|
|
@@ -1066,31 +1183,31 @@ function checkCollisions(target, source, kind, callerLabel, override) {
|
|
|
1066
1183
|
checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
|
|
1067
1184
|
return;
|
|
1068
1185
|
}
|
|
1069
|
-
for (const
|
|
1070
|
-
if (!override && hasOwn(target,
|
|
1186
|
+
for (const key of Object.keys(source)) {
|
|
1187
|
+
if (!override && hasOwn(target, key)) {
|
|
1071
1188
|
throw new Error(
|
|
1072
|
-
`${callerLabel}: duplicate ${kind} "${
|
|
1189
|
+
`${callerLabel}: duplicate ${kind} "${key}". If the override is intentional, pass { override: true } in the options.`
|
|
1073
1190
|
);
|
|
1074
1191
|
}
|
|
1075
1192
|
}
|
|
1076
1193
|
}
|
|
1077
1194
|
function checkRootKeyCollisions(target, keys, override, callerLabel) {
|
|
1078
|
-
for (const
|
|
1079
|
-
if (RESERVED_ROOT_KEYS.has(
|
|
1195
|
+
for (const key of keys) {
|
|
1196
|
+
if (RESERVED_ROOT_KEYS.has(key)) {
|
|
1080
1197
|
throw new Error(
|
|
1081
|
-
`${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.`
|
|
1082
1199
|
);
|
|
1083
1200
|
}
|
|
1084
|
-
if (!override && hasOwn(target,
|
|
1201
|
+
if (!override && hasOwn(target, key)) {
|
|
1085
1202
|
throw new Error(
|
|
1086
|
-
`${callerLabel}: duplicate root key "${
|
|
1203
|
+
`${callerLabel}: duplicate root key "${key}". If the override is intentional, pass { override: true } in the options.`
|
|
1087
1204
|
);
|
|
1088
1205
|
}
|
|
1089
1206
|
}
|
|
1090
1207
|
}
|
|
1091
1208
|
function applyOwnProperties(target, source) {
|
|
1092
|
-
for (const
|
|
1093
|
-
setOwn(target,
|
|
1209
|
+
for (const key of Object.keys(source)) {
|
|
1210
|
+
setOwn(target, key, source[key]);
|
|
1094
1211
|
}
|
|
1095
1212
|
}
|
|
1096
1213
|
function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
|
|
@@ -1308,7 +1425,6 @@ var LEAF_META_KEYS = [
|
|
|
1308
1425
|
"itemType",
|
|
1309
1426
|
"returnType",
|
|
1310
1427
|
"outputSchema",
|
|
1311
|
-
"inputParameters",
|
|
1312
1428
|
"packages",
|
|
1313
1429
|
"experimental",
|
|
1314
1430
|
"confirm",
|
|
@@ -1348,8 +1464,8 @@ function normalizeImports(deps) {
|
|
|
1348
1464
|
}
|
|
1349
1465
|
function collectLeafMeta(config) {
|
|
1350
1466
|
let meta;
|
|
1351
|
-
for (const
|
|
1352
|
-
if (config[
|
|
1467
|
+
for (const key of LEAF_META_KEYS) {
|
|
1468
|
+
if (config[key] !== void 0) (meta ?? (meta = {}))[key] = config[key];
|
|
1353
1469
|
}
|
|
1354
1470
|
return meta;
|
|
1355
1471
|
}
|
|
@@ -1432,7 +1548,8 @@ function defineResolver(config) {
|
|
|
1432
1548
|
type: "object",
|
|
1433
1549
|
properties: config.properties,
|
|
1434
1550
|
definitions: config.definitions,
|
|
1435
|
-
getProperties: config.getProperties
|
|
1551
|
+
getProperties: config.getProperties,
|
|
1552
|
+
additionalKeys: config.additionalKeys
|
|
1436
1553
|
};
|
|
1437
1554
|
case "array":
|
|
1438
1555
|
return {
|
|
@@ -1744,7 +1861,7 @@ function normalizeFormatter(entry, sdk) {
|
|
|
1744
1861
|
const legacy = entry.meta?.formatter;
|
|
1745
1862
|
return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
|
|
1746
1863
|
}
|
|
1747
|
-
function
|
|
1864
|
+
function normalizeResolvers(entry) {
|
|
1748
1865
|
if (entry.pluginType !== "method") return void 0;
|
|
1749
1866
|
return entry.resolvers;
|
|
1750
1867
|
}
|
|
@@ -1785,17 +1902,20 @@ function collectSurfaceProjection(context, formatterSdk) {
|
|
|
1785
1902
|
foldDynamicMembers(entry, surfaceBindings, meta);
|
|
1786
1903
|
}
|
|
1787
1904
|
const formatters = {};
|
|
1788
|
-
const
|
|
1905
|
+
const resolvers = {};
|
|
1789
1906
|
const positional = {};
|
|
1907
|
+
const skipInputValidation = {};
|
|
1790
1908
|
for (const [binding, entry] of Object.entries(entries)) {
|
|
1791
1909
|
const f = normalizeFormatter(entry, formatterSdk);
|
|
1792
1910
|
if (f) formatters[binding] = f;
|
|
1793
|
-
const r =
|
|
1794
|
-
if (r)
|
|
1911
|
+
const r = normalizeResolvers(entry);
|
|
1912
|
+
if (r) resolvers[binding] = r;
|
|
1795
1913
|
const p = methodPositional(entry);
|
|
1796
1914
|
if (p) positional[binding] = p;
|
|
1915
|
+
if (entry.pluginType === "method" && entry.skipInputValidation)
|
|
1916
|
+
skipInputValidation[binding] = true;
|
|
1797
1917
|
}
|
|
1798
|
-
return { meta, formatters,
|
|
1918
|
+
return { meta, formatters, resolvers, positional, skipInputValidation };
|
|
1799
1919
|
}
|
|
1800
1920
|
function buildSurfaceRegistry(context, packageFilter) {
|
|
1801
1921
|
const surface = {};
|
|
@@ -1852,6 +1972,11 @@ function nestedResolvers(resolver) {
|
|
|
1852
1972
|
for (const field of Object.values(resolver.properties ?? {})) {
|
|
1853
1973
|
if (!isResolverRef(field.resolver)) out.push(field.resolver);
|
|
1854
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
|
+
}
|
|
1855
1980
|
out.push(...Object.values(resolver.definitions ?? {}));
|
|
1856
1981
|
} else if (resolver.type === "array") {
|
|
1857
1982
|
if (!isResolverRef(resolver.items)) out.push(resolver.items);
|
|
@@ -1976,16 +2101,16 @@ function collectPlugins(root, materialized = /* @__PURE__ */ new Set(), configur
|
|
|
1976
2101
|
}
|
|
1977
2102
|
return byId;
|
|
1978
2103
|
}
|
|
1979
|
-
function bindValue(target,
|
|
2104
|
+
function bindValue(target, key, entry, callType = "surface", ctx) {
|
|
1980
2105
|
if (entry.pluginType === "property" && entry.getValue) {
|
|
1981
|
-
Object.defineProperty(target,
|
|
2106
|
+
Object.defineProperty(target, key, {
|
|
1982
2107
|
get: entry.getValue,
|
|
1983
2108
|
enumerable: true,
|
|
1984
2109
|
configurable: true
|
|
1985
2110
|
});
|
|
1986
2111
|
} else {
|
|
1987
|
-
const value = callType === "internal" && entry.pluginType === "method" ? entry.internalValue ?? entry.value : entry.value;
|
|
1988
|
-
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, {
|
|
1989
2114
|
value,
|
|
1990
2115
|
writable: true,
|
|
1991
2116
|
enumerable: true,
|
|
@@ -2002,7 +2127,7 @@ function buildSurface(context, ...maps) {
|
|
|
2002
2127
|
sdk[CONTEXT] = context;
|
|
2003
2128
|
return sdk;
|
|
2004
2129
|
}
|
|
2005
|
-
function buildImports(plugins, importBindings) {
|
|
2130
|
+
function buildImports(plugins, importBindings, ctx) {
|
|
2006
2131
|
const imports = {};
|
|
2007
2132
|
for (const { binding, id, optional } of importBindings) {
|
|
2008
2133
|
const entry = plugins[id];
|
|
@@ -2015,7 +2140,7 @@ function buildImports(plugins, importBindings) {
|
|
|
2015
2140
|
});
|
|
2016
2141
|
continue;
|
|
2017
2142
|
}
|
|
2018
|
-
bindValue(imports, binding, entry, "internal");
|
|
2143
|
+
bindValue(imports, binding, entry, "internal", ctx);
|
|
2019
2144
|
}
|
|
2020
2145
|
return imports;
|
|
2021
2146
|
}
|
|
@@ -2094,6 +2219,19 @@ function bindResolver(resolver, plugins) {
|
|
|
2094
2219
|
const { getProperties } = resolver;
|
|
2095
2220
|
if (getProperties)
|
|
2096
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
|
+
}
|
|
2097
2235
|
return bound;
|
|
2098
2236
|
}
|
|
2099
2237
|
case "array": {
|
|
@@ -2149,8 +2287,8 @@ function bindResolver(resolver, plugins) {
|
|
|
2149
2287
|
}
|
|
2150
2288
|
function bindFields(fields, plugins) {
|
|
2151
2289
|
const out = {};
|
|
2152
|
-
for (const [
|
|
2153
|
-
out[
|
|
2290
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
2291
|
+
out[key] = {
|
|
2154
2292
|
...field,
|
|
2155
2293
|
resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
|
|
2156
2294
|
};
|
|
@@ -2159,8 +2297,8 @@ function bindFields(fields, plugins) {
|
|
|
2159
2297
|
}
|
|
2160
2298
|
function bindDefinitions(definitions, plugins) {
|
|
2161
2299
|
const out = {};
|
|
2162
|
-
for (const [
|
|
2163
|
-
out[
|
|
2300
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
2301
|
+
out[key] = bindResolver(def, plugins);
|
|
2164
2302
|
}
|
|
2165
2303
|
return out;
|
|
2166
2304
|
}
|
|
@@ -2245,6 +2383,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2245
2383
|
name: descriptor.name,
|
|
2246
2384
|
chain: [],
|
|
2247
2385
|
inputSchema: descriptor.inputSchema,
|
|
2386
|
+
skipInputValidation: descriptor.skipInputValidation,
|
|
2248
2387
|
// Derive the presentation type from the output mode when the author did
|
|
2249
2388
|
// not set one; an explicit meta.type (e.g. "create") still wins.
|
|
2250
2389
|
meta: out.type === "raw" || descriptor.meta?.type ? descriptor.meta : { ...descriptor.meta, type: out.type },
|
|
@@ -2252,17 +2391,17 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2252
2391
|
// Replaced below; never called.
|
|
2253
2392
|
value: () => void 0
|
|
2254
2393
|
};
|
|
2255
|
-
const callRun = (input) => descriptor.run({
|
|
2256
|
-
imports: buildImports(plugins, descriptor.importBindings),
|
|
2394
|
+
const callRun = (input, ctx) => descriptor.run({
|
|
2395
|
+
imports: buildImports(plugins, descriptor.importBindings, ctx),
|
|
2257
2396
|
state: states.get(id),
|
|
2258
2397
|
input
|
|
2259
2398
|
});
|
|
2260
|
-
const fold = (coreFn) => (input) => {
|
|
2261
|
-
let next = coreFn;
|
|
2399
|
+
const fold = (coreFn) => (input, ctx) => {
|
|
2400
|
+
let next = (i) => coreFn(i, ctx);
|
|
2262
2401
|
for (const wrap of entry.chain) {
|
|
2263
2402
|
const inner = next;
|
|
2264
2403
|
next = (i) => wrap.run({
|
|
2265
|
-
imports: buildImports(plugins, wrap.owner.importBindings),
|
|
2404
|
+
imports: buildImports(plugins, wrap.owner.importBindings, ctx),
|
|
2266
2405
|
next: inner,
|
|
2267
2406
|
input: i,
|
|
2268
2407
|
// Overwritten by the chain item's own closure with the owning
|
|
@@ -2286,7 +2425,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2286
2425
|
}
|
|
2287
2426
|
);
|
|
2288
2427
|
} else if (out.type === "item") {
|
|
2289
|
-
const itemCore = async (input) => callRun(input);
|
|
2428
|
+
const itemCore = async (input, ctx) => callRun(input, ctx);
|
|
2290
2429
|
entry.value = createFunction(
|
|
2291
2430
|
fold(itemCore),
|
|
2292
2431
|
{
|
|
@@ -2298,7 +2437,7 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2298
2437
|
);
|
|
2299
2438
|
} else {
|
|
2300
2439
|
entry.value = createRawFunction(
|
|
2301
|
-
(input) => fold(callRun)(input),
|
|
2440
|
+
(input, ctx) => fold(callRun)(input, ctx),
|
|
2302
2441
|
{
|
|
2303
2442
|
sdk,
|
|
2304
2443
|
name: descriptor.name,
|
|
@@ -2321,11 +2460,15 @@ function buildMethodEntries(descriptors, context, states) {
|
|
|
2321
2460
|
});
|
|
2322
2461
|
return packed;
|
|
2323
2462
|
};
|
|
2463
|
+
const internalValue = (...args) => canonicalValue(pack(args), INTERNAL_CALL);
|
|
2324
2464
|
entry.value = (...args) => canonicalValue(pack(args));
|
|
2325
|
-
entry.internalValue =
|
|
2465
|
+
entry.internalValue = internalValue;
|
|
2466
|
+
entry.bindInternal = (ctx) => ctx ? (...args) => canonicalValue(pack(args), childCallContext(ctx)) : internalValue;
|
|
2326
2467
|
entry.positional = names;
|
|
2327
2468
|
} else {
|
|
2328
|
-
|
|
2469
|
+
const internalValue = (input) => canonicalValue(input, INTERNAL_CALL);
|
|
2470
|
+
entry.internalValue = internalValue;
|
|
2471
|
+
entry.bindInternal = (ctx) => ctx ? (input) => canonicalValue(input, childCallContext(ctx)) : internalValue;
|
|
2329
2472
|
}
|
|
2330
2473
|
plugins[id] = entry;
|
|
2331
2474
|
}
|
|
@@ -2565,7 +2708,7 @@ function createSdk(root, options) {
|
|
|
2565
2708
|
pluginSurface = {};
|
|
2566
2709
|
bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
|
|
2567
2710
|
}
|
|
2568
|
-
for (const
|
|
2711
|
+
for (const key of Object.keys(legacyExports)) context.surface[key] = key;
|
|
2569
2712
|
if (plugin.pluginType === "aggregate") {
|
|
2570
2713
|
recordExportSurface(context, plugin.exports);
|
|
2571
2714
|
} else {
|
|
@@ -2704,6 +2847,7 @@ function valueTypeOf(inner) {
|
|
|
2704
2847
|
if (inner instanceof import_zod3.z.ZodEnum) return "string";
|
|
2705
2848
|
if (inner instanceof import_zod3.z.ZodArray) return "array";
|
|
2706
2849
|
if (inner instanceof import_zod3.z.ZodObject) return "object";
|
|
2850
|
+
if (inner instanceof import_zod3.z.ZodRecord) return "object";
|
|
2707
2851
|
return void 0;
|
|
2708
2852
|
}
|
|
2709
2853
|
function staticChoicesOf(inner) {
|
|
@@ -2714,7 +2858,8 @@ function staticChoicesOf(inner) {
|
|
|
2714
2858
|
return void 0;
|
|
2715
2859
|
}
|
|
2716
2860
|
function objectShape(schema) {
|
|
2717
|
-
const
|
|
2861
|
+
const canonical = canonicalInputSchema(schema);
|
|
2862
|
+
const { inner } = canonical ? unwrap(canonical) : { inner: void 0 };
|
|
2718
2863
|
if (inner instanceof import_zod3.z.ZodObject) {
|
|
2719
2864
|
return inner.shape;
|
|
2720
2865
|
}
|
|
@@ -2736,7 +2881,7 @@ function topoOrder2(specs) {
|
|
|
2736
2881
|
}
|
|
2737
2882
|
function planParameters(entry) {
|
|
2738
2883
|
const shape = objectShape(entry.inputSchema);
|
|
2739
|
-
const resolvers = entry.
|
|
2884
|
+
const resolvers = entry.resolvers ?? {};
|
|
2740
2885
|
const names = shape ? [
|
|
2741
2886
|
...Object.keys(shape),
|
|
2742
2887
|
...Object.keys(resolvers).filter(
|
|
@@ -2774,24 +2919,48 @@ function getAtPath(root, path) {
|
|
|
2774
2919
|
}
|
|
2775
2920
|
return node;
|
|
2776
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
|
+
}
|
|
2777
2930
|
function setAtPath(root, path, value) {
|
|
2778
2931
|
let node = root;
|
|
2779
2932
|
for (let i = 0; i < path.length - 1; i++) {
|
|
2780
2933
|
const seg = path[i];
|
|
2781
|
-
|
|
2782
|
-
|
|
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
|
+
}
|
|
2783
2942
|
}
|
|
2784
|
-
node
|
|
2943
|
+
defineOwn(node, path[path.length - 1], value);
|
|
2785
2944
|
}
|
|
2786
|
-
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
|
+
};
|
|
2787
2956
|
function isSettled(state, path) {
|
|
2788
|
-
return state.settled.includes(
|
|
2957
|
+
return state.settled.includes(pathToKey(path));
|
|
2789
2958
|
}
|
|
2790
2959
|
function remember(state, k) {
|
|
2791
2960
|
if (!state.settled.includes(k)) state.settled.push(k);
|
|
2792
2961
|
}
|
|
2793
2962
|
function settle(state, path) {
|
|
2794
|
-
remember(state,
|
|
2963
|
+
remember(state, pathToKey(path));
|
|
2795
2964
|
}
|
|
2796
2965
|
function clone(state) {
|
|
2797
2966
|
return JSON.parse(JSON.stringify(state));
|
|
@@ -2806,6 +2975,28 @@ function coerce(leaf, raw) {
|
|
|
2806
2975
|
if (raw === "true") return true;
|
|
2807
2976
|
if (raw === "false") return false;
|
|
2808
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
|
+
}
|
|
2809
3000
|
return raw;
|
|
2810
3001
|
}
|
|
2811
3002
|
async function validationError(leaf, value, state) {
|
|
@@ -2863,27 +3054,6 @@ async function objectChildren(resolver, input) {
|
|
|
2863
3054
|
return toLeaf(name, field, resolver.definitions);
|
|
2864
3055
|
});
|
|
2865
3056
|
}
|
|
2866
|
-
function arrayItem(resolver) {
|
|
2867
|
-
const items = resolver.items;
|
|
2868
|
-
const valueType = resolver.itemValueType;
|
|
2869
|
-
if (isRef(items)) {
|
|
2870
|
-
return {
|
|
2871
|
-
name: "",
|
|
2872
|
-
required: true,
|
|
2873
|
-
resolver: resolver.definitions?.[items.ref],
|
|
2874
|
-
extraInput: items.input,
|
|
2875
|
-
valueType,
|
|
2876
|
-
requires: []
|
|
2877
|
-
};
|
|
2878
|
-
}
|
|
2879
|
-
return {
|
|
2880
|
-
name: "",
|
|
2881
|
-
required: true,
|
|
2882
|
-
resolver: items,
|
|
2883
|
-
valueType,
|
|
2884
|
-
requires: []
|
|
2885
|
-
};
|
|
2886
|
-
}
|
|
2887
3057
|
function autoSettles(resolver) {
|
|
2888
3058
|
return resolver.type === "constant" || resolver.type === "info";
|
|
2889
3059
|
}
|
|
@@ -2903,10 +3073,28 @@ async function leafAt(ctx, path, resolved) {
|
|
|
2903
3073
|
const seg = path[i];
|
|
2904
3074
|
if (typeof seg === "number") {
|
|
2905
3075
|
if (leaf?.resolver?.type !== "array") return void 0;
|
|
2906
|
-
leaf =
|
|
3076
|
+
leaf = boundLeaf(
|
|
3077
|
+
"",
|
|
3078
|
+
leaf.resolver.items,
|
|
3079
|
+
leaf.resolver.definitions,
|
|
3080
|
+
leaf.resolver.itemValueType
|
|
3081
|
+
);
|
|
2907
3082
|
} else {
|
|
2908
|
-
|
|
2909
|
-
|
|
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
|
+
}
|
|
2910
3098
|
}
|
|
2911
3099
|
if (i < path.length - 1 && typeof path[i + 1] === "string") {
|
|
2912
3100
|
if (leaf?.resolver?.type !== "object") return void 0;
|
|
@@ -2918,16 +3106,81 @@ async function leafAt(ctx, path, resolved) {
|
|
|
2918
3106
|
}
|
|
2919
3107
|
return leaf;
|
|
2920
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
|
+
}
|
|
2921
3169
|
async function arrayInfoAt(ctx, path, resolved) {
|
|
2922
3170
|
const leaf = await leafAt(ctx, path, resolved);
|
|
2923
3171
|
const resolver = leaf?.resolver;
|
|
2924
3172
|
if (resolver?.type !== "array") {
|
|
2925
|
-
throw new Error(`expected an array resolver at "${
|
|
3173
|
+
throw new Error(`expected an array resolver at "${pathToKey(path)}"`);
|
|
2926
3174
|
}
|
|
2927
3175
|
return {
|
|
2928
3176
|
min: resolver.minItems ?? 0,
|
|
2929
3177
|
max: resolver.maxItems ?? Infinity,
|
|
2930
|
-
item:
|
|
3178
|
+
item: boundLeaf(
|
|
3179
|
+
String(path[path.length - 1]),
|
|
3180
|
+
resolver.items,
|
|
3181
|
+
resolver.definitions,
|
|
3182
|
+
resolver.itemValueType
|
|
3183
|
+
)
|
|
2931
3184
|
};
|
|
2932
3185
|
}
|
|
2933
3186
|
async function firstPage(result) {
|
|
@@ -3008,6 +3261,9 @@ var AFFORDANCE = {
|
|
|
3008
3261
|
retry: { action: "retry", description: "Retry loading the options" },
|
|
3009
3262
|
cancel: { action: "cancel", description: "Cancel resolution" }
|
|
3010
3263
|
};
|
|
3264
|
+
function affordance(base, description) {
|
|
3265
|
+
return { ...base, description };
|
|
3266
|
+
}
|
|
3011
3267
|
function selectActions(leaf, page, multiple) {
|
|
3012
3268
|
const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
|
|
3013
3269
|
if (searchMode && page.position.search === void 0 && page.items.length === 0) {
|
|
@@ -3122,7 +3378,7 @@ async function buildQuestion(leaf, path, input) {
|
|
|
3122
3378
|
}
|
|
3123
3379
|
};
|
|
3124
3380
|
}
|
|
3125
|
-
function
|
|
3381
|
+
function arrayItemsQuestion(t) {
|
|
3126
3382
|
const actions = [AFFORDANCE.add];
|
|
3127
3383
|
if (t.count >= t.min) actions.push(AFFORDANCE.done);
|
|
3128
3384
|
return {
|
|
@@ -3138,22 +3394,37 @@ function collectionQuestion(t) {
|
|
|
3138
3394
|
actions
|
|
3139
3395
|
};
|
|
3140
3396
|
}
|
|
3141
|
-
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) {
|
|
3142
3416
|
return {
|
|
3143
3417
|
type: "collection",
|
|
3144
3418
|
path,
|
|
3145
3419
|
message: `Add ${path[path.length - 1]}?`,
|
|
3146
3420
|
container: "object",
|
|
3147
3421
|
actions: [
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
description: "Provide values for these fields"
|
|
3151
|
-
},
|
|
3152
|
-
{ action: "done", description: "Skip these fields" }
|
|
3422
|
+
affordance(AFFORDANCE.add, "Provide values for these fields"),
|
|
3423
|
+
affordance(AFFORDANCE.done, "Skip these fields")
|
|
3153
3424
|
]
|
|
3154
3425
|
};
|
|
3155
3426
|
}
|
|
3156
|
-
function
|
|
3427
|
+
function objectOptionalPropertiesQuestion(path, pending) {
|
|
3157
3428
|
return {
|
|
3158
3429
|
type: "collection",
|
|
3159
3430
|
path,
|
|
@@ -3170,8 +3441,8 @@ function optionalsGateQuestion(path, pending) {
|
|
|
3170
3441
|
...leaf.valueType ? { valueType: leaf.valueType } : {}
|
|
3171
3442
|
})),
|
|
3172
3443
|
actions: [
|
|
3173
|
-
|
|
3174
|
-
|
|
3444
|
+
affordance(AFFORDANCE.add, "Configure the optional fields"),
|
|
3445
|
+
affordance(AFFORDANCE.done, "Skip the optional fields")
|
|
3175
3446
|
]
|
|
3176
3447
|
};
|
|
3177
3448
|
}
|
|
@@ -3189,7 +3460,8 @@ function finalize(ctx, resolved) {
|
|
|
3189
3460
|
}));
|
|
3190
3461
|
return { status: "invalid", issues };
|
|
3191
3462
|
}
|
|
3192
|
-
var optionalsMarker = (path) => `${
|
|
3463
|
+
var optionalsMarker = (path) => `${pathToKey(path)}?optionals`;
|
|
3464
|
+
var UNSAFE_RECORD_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3193
3465
|
async function findInArray(ctx, state, path) {
|
|
3194
3466
|
if (isSettled(state, path)) return null;
|
|
3195
3467
|
if (getAtPath(state.resolved, path) == null)
|
|
@@ -3210,7 +3482,28 @@ async function findInArray(ctx, state, path) {
|
|
|
3210
3482
|
}
|
|
3211
3483
|
}
|
|
3212
3484
|
if (len < min) return descendItem(ctx, state, path, len, item);
|
|
3213
|
-
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 };
|
|
3214
3507
|
settle(state, path);
|
|
3215
3508
|
return null;
|
|
3216
3509
|
}
|
|
@@ -3228,10 +3521,10 @@ function seedItemSlot(state, itemPath, item) {
|
|
|
3228
3521
|
}
|
|
3229
3522
|
async function descendItem(ctx, state, arrayPath, index, item) {
|
|
3230
3523
|
const itemPath = [...arrayPath, index];
|
|
3231
|
-
const
|
|
3232
|
-
if (
|
|
3233
|
-
if (
|
|
3234
|
-
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 };
|
|
3235
3528
|
}
|
|
3236
3529
|
async function findNext(ctx, state, path = []) {
|
|
3237
3530
|
const container = getAtPath(state.resolved, path) ?? {};
|
|
@@ -3256,7 +3549,7 @@ async function findNext(ctx, state, path = []) {
|
|
|
3256
3549
|
const pending = ordered.filter(
|
|
3257
3550
|
(c) => !c.required && asksUser(c) && isPendingChild(c)
|
|
3258
3551
|
);
|
|
3259
|
-
return {
|
|
3552
|
+
return { type: "object_optional_properties", path, pending };
|
|
3260
3553
|
}
|
|
3261
3554
|
if (leaf.resolver?.type === "object") {
|
|
3262
3555
|
if (isSettled(state, childPath)) continue;
|
|
@@ -3266,7 +3559,7 @@ async function findNext(ctx, state, path = []) {
|
|
|
3266
3559
|
settle(state, childPath);
|
|
3267
3560
|
continue;
|
|
3268
3561
|
}
|
|
3269
|
-
return {
|
|
3562
|
+
return { type: "object_optional", path: childPath, leaf };
|
|
3270
3563
|
}
|
|
3271
3564
|
setAtPath(state.resolved, childPath, {});
|
|
3272
3565
|
}
|
|
@@ -3298,13 +3591,21 @@ async function findNext(ctx, state, path = []) {
|
|
|
3298
3591
|
}
|
|
3299
3592
|
if (container[leaf.name] !== void 0 || isSettled(state, childPath))
|
|
3300
3593
|
continue;
|
|
3301
|
-
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
|
+
}
|
|
3302
3602
|
}
|
|
3303
3603
|
return null;
|
|
3304
3604
|
}
|
|
3305
3605
|
async function askLeaf(state, path, leaf, opts = {}) {
|
|
3306
3606
|
state.current = path;
|
|
3307
|
-
|
|
3607
|
+
if (opts.gate) state.gate = opts.gate;
|
|
3608
|
+
else delete state.gate;
|
|
3308
3609
|
try {
|
|
3309
3610
|
const { question, pagination } = await buildQuestion(
|
|
3310
3611
|
leaf,
|
|
@@ -3325,6 +3626,28 @@ async function askLeaf(state, path, leaf, opts = {}) {
|
|
|
3325
3626
|
return failedResult(state, leaf.name, error);
|
|
3326
3627
|
}
|
|
3327
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
|
+
}
|
|
3328
3651
|
async function advance(ctx, state) {
|
|
3329
3652
|
for (; ; ) {
|
|
3330
3653
|
const target = await findNext(ctx, state);
|
|
@@ -3334,54 +3657,56 @@ async function advance(ctx, state) {
|
|
|
3334
3657
|
delete state.pagination;
|
|
3335
3658
|
return { state, result: finalize(ctx, state.resolved) };
|
|
3336
3659
|
}
|
|
3337
|
-
if (target.
|
|
3660
|
+
if (target.type === "array_items") {
|
|
3338
3661
|
state.current = target.path;
|
|
3339
|
-
state.gate = "
|
|
3662
|
+
state.gate = "array_items";
|
|
3340
3663
|
delete state.pagination;
|
|
3341
3664
|
return {
|
|
3342
3665
|
state,
|
|
3343
|
-
result: { status: "ask", question:
|
|
3666
|
+
result: { status: "ask", question: arrayItemsQuestion(target) }
|
|
3344
3667
|
};
|
|
3345
3668
|
}
|
|
3346
|
-
if (target.
|
|
3669
|
+
if (target.type === "object_optional") {
|
|
3347
3670
|
state.current = target.path;
|
|
3348
|
-
state.gate = "
|
|
3671
|
+
state.gate = "object_optional";
|
|
3349
3672
|
delete state.pagination;
|
|
3350
3673
|
return {
|
|
3351
3674
|
state,
|
|
3352
|
-
result: {
|
|
3675
|
+
result: {
|
|
3676
|
+
status: "ask",
|
|
3677
|
+
question: objectOptionalQuestion(target.path)
|
|
3678
|
+
}
|
|
3353
3679
|
};
|
|
3354
3680
|
}
|
|
3355
|
-
if (target.
|
|
3681
|
+
if (target.type === "object_optional_properties") {
|
|
3356
3682
|
state.current = target.path;
|
|
3357
|
-
state.gate = "
|
|
3683
|
+
state.gate = "object_optional_properties";
|
|
3358
3684
|
delete state.pagination;
|
|
3359
3685
|
return {
|
|
3360
3686
|
state,
|
|
3361
3687
|
result: {
|
|
3362
3688
|
status: "ask",
|
|
3363
|
-
question:
|
|
3689
|
+
question: objectOptionalPropertiesQuestion(
|
|
3690
|
+
target.path,
|
|
3691
|
+
target.pending
|
|
3692
|
+
)
|
|
3364
3693
|
}
|
|
3365
3694
|
};
|
|
3366
3695
|
}
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
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
|
+
};
|
|
3375
3704
|
}
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
}) : void 0;
|
|
3379
|
-
if (auto) {
|
|
3380
|
-
if (auto.resolvedValue !== void 0)
|
|
3381
|
-
setAtPath(state.resolved, path, auto.resolvedValue);
|
|
3382
|
-
settle(state, path);
|
|
3383
|
-
continue;
|
|
3705
|
+
if (target.type === "record_key") {
|
|
3706
|
+
return askRecordKey(state, target.path, target.leaf);
|
|
3384
3707
|
}
|
|
3708
|
+
const { path, leaf } = target;
|
|
3709
|
+
if (await autoResolveLeaf(state, path, leaf)) continue;
|
|
3385
3710
|
if (!state.interactive) {
|
|
3386
3711
|
if (!leaf.required) {
|
|
3387
3712
|
settle(state, path);
|
|
@@ -3414,10 +3739,18 @@ async function step(ctx, prior, action) {
|
|
|
3414
3739
|
delete state.pagination;
|
|
3415
3740
|
return { state, result: { status: "cancelled" } };
|
|
3416
3741
|
}
|
|
3742
|
+
if (state.gate === "record_key") {
|
|
3743
|
+
return stepRecordKey(ctx, state, action);
|
|
3744
|
+
}
|
|
3417
3745
|
const path = state.current;
|
|
3418
3746
|
if (!path) throw new Error("step called with no outstanding question");
|
|
3419
3747
|
const leaf = await leafAt(ctx, path, state.resolved);
|
|
3420
|
-
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") {
|
|
3421
3754
|
return refine(ctx, state, leaf, path, action);
|
|
3422
3755
|
}
|
|
3423
3756
|
if (action.type === "add" || action.type === "done") {
|
|
@@ -3434,19 +3767,26 @@ async function step(ctx, prior, action) {
|
|
|
3434
3767
|
settle(state, path);
|
|
3435
3768
|
return advance(ctx, state);
|
|
3436
3769
|
}
|
|
3437
|
-
if (gate === "
|
|
3770
|
+
if (gate === "object_optional") {
|
|
3438
3771
|
setAtPath(state.resolved, path, {});
|
|
3439
3772
|
return advance(ctx, state);
|
|
3440
3773
|
}
|
|
3441
|
-
if (gate === "
|
|
3774
|
+
if (gate === "object_optional_properties") {
|
|
3442
3775
|
remember(state, optionalsMarker(path));
|
|
3443
3776
|
return advance(ctx, state);
|
|
3444
3777
|
}
|
|
3778
|
+
if (gate === "record_entries") {
|
|
3779
|
+
const { keyLeaf } = await recordInfoAt(ctx, path, state.resolved);
|
|
3780
|
+
return askRecordKey(state, path, keyLeaf);
|
|
3781
|
+
}
|
|
3445
3782
|
const items = getAtPath(state.resolved, path) ?? [];
|
|
3446
3783
|
const { item } = await arrayInfoAt(ctx, path, state.resolved);
|
|
3447
3784
|
const itemPath = [...path, items.length];
|
|
3448
|
-
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);
|
|
3449
3788
|
return askLeaf(state, itemPath, item);
|
|
3789
|
+
}
|
|
3450
3790
|
return advance(ctx, state);
|
|
3451
3791
|
}
|
|
3452
3792
|
if (state.gate) {
|
|
@@ -3457,81 +3797,37 @@ async function step(ctx, prior, action) {
|
|
|
3457
3797
|
switch (action.type) {
|
|
3458
3798
|
case "choose":
|
|
3459
3799
|
case "custom": {
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
if (
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
const page = await fetchListing(
|
|
3472
|
-
leaf,
|
|
3473
|
-
state.resolved,
|
|
3474
|
-
state.pagination.position,
|
|
3475
|
-
context
|
|
3476
|
-
);
|
|
3477
|
-
state.pagination = toPagination(page);
|
|
3478
|
-
return {
|
|
3479
|
-
state,
|
|
3480
|
-
result: {
|
|
3481
|
-
status: "ask",
|
|
3482
|
-
question: selectQuestion(
|
|
3483
|
-
leaf,
|
|
3484
|
-
path,
|
|
3485
|
-
state.resolved,
|
|
3486
|
-
page,
|
|
3487
|
-
context
|
|
3488
|
-
),
|
|
3489
|
-
error
|
|
3490
|
-
}
|
|
3491
|
-
};
|
|
3492
|
-
} catch (fetchError) {
|
|
3493
|
-
state.pagination = failedPagination(
|
|
3494
|
-
state.pagination,
|
|
3495
|
-
state.pagination.position
|
|
3496
|
-
);
|
|
3497
|
-
return failedResult(state, leaf.name, fetchError);
|
|
3498
|
-
}
|
|
3499
|
-
}
|
|
3500
|
-
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
|
+
});
|
|
3501
3811
|
}
|
|
3812
|
+
return askLeaf(state, path, leaf, { error });
|
|
3502
3813
|
}
|
|
3503
|
-
setAtPath(
|
|
3504
|
-
state.resolved,
|
|
3505
|
-
path,
|
|
3506
|
-
leaf ? coerce(leaf, action.value) : action.value
|
|
3507
|
-
);
|
|
3814
|
+
setAtPath(state.resolved, path, coerce(leaf, action.value));
|
|
3508
3815
|
break;
|
|
3509
3816
|
}
|
|
3510
3817
|
case "skip":
|
|
3511
3818
|
settle(state, path);
|
|
3512
3819
|
break;
|
|
3513
3820
|
default:
|
|
3514
|
-
throw new Error(
|
|
3821
|
+
throw new Error(
|
|
3822
|
+
`action "${action.type}" is not supported here`
|
|
3823
|
+
);
|
|
3515
3824
|
}
|
|
3516
3825
|
delete state.current;
|
|
3517
3826
|
delete state.pagination;
|
|
3518
3827
|
return advance(ctx, state);
|
|
3519
3828
|
}
|
|
3520
|
-
async function
|
|
3521
|
-
const position = positionAfter(state.pagination, action);
|
|
3829
|
+
async function renderPageAt(state, leaf, path, position, opts = {}) {
|
|
3522
3830
|
try {
|
|
3523
|
-
if (action.type === "search") {
|
|
3524
|
-
const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
|
|
3525
|
-
input: mergeInput(state.resolved, leaf.extraInput),
|
|
3526
|
-
search: action.term
|
|
3527
|
-
}) : void 0;
|
|
3528
|
-
if (exact) {
|
|
3529
|
-
setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
|
|
3530
|
-
delete state.current;
|
|
3531
|
-
delete state.pagination;
|
|
3532
|
-
return advance(ctx, state);
|
|
3533
|
-
}
|
|
3534
|
-
}
|
|
3535
3831
|
const context = await resolveContext(leaf, state.resolved);
|
|
3536
3832
|
const page = await fetchListing(leaf, state.resolved, position, context);
|
|
3537
3833
|
state.pagination = toPagination(page);
|
|
@@ -3539,7 +3835,8 @@ async function refine(ctx, state, leaf, path, action) {
|
|
|
3539
3835
|
state,
|
|
3540
3836
|
result: {
|
|
3541
3837
|
status: "ask",
|
|
3542
|
-
question: selectQuestion(leaf, path, state.resolved, page, context)
|
|
3838
|
+
question: selectQuestion(leaf, path, state.resolved, page, context),
|
|
3839
|
+
...opts.error ? { error: opts.error } : {}
|
|
3543
3840
|
}
|
|
3544
3841
|
};
|
|
3545
3842
|
} catch (error) {
|
|
@@ -3547,6 +3844,65 @@ async function refine(ctx, state, leaf, path, action) {
|
|
|
3547
3844
|
return failedResult(state, leaf.name, error);
|
|
3548
3845
|
}
|
|
3549
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
|
+
}
|
|
3550
3906
|
function failedPagination(pagination, retryPosition) {
|
|
3551
3907
|
return {
|
|
3552
3908
|
position: pagination?.position ?? firstPagePosition(),
|
|
@@ -3602,7 +3958,7 @@ function projectSummary(entry) {
|
|
|
3602
3958
|
};
|
|
3603
3959
|
}
|
|
3604
3960
|
function projectMethod(entry) {
|
|
3605
|
-
const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
|
|
3961
|
+
const inputProperties = toJsonSchema(canonicalInputSchema(entry.inputSchema))?.properties;
|
|
3606
3962
|
const parameters = {};
|
|
3607
3963
|
for (const spec of planParameters(entry).parameters) {
|
|
3608
3964
|
const dynamic = spec.resolver?.type === "dynamic" ? spec.resolver : void 0;
|
|
@@ -3635,7 +3991,12 @@ function createController(sdk) {
|
|
|
3635
3991
|
const entry = entryFor(method);
|
|
3636
3992
|
return {
|
|
3637
3993
|
method,
|
|
3638
|
-
|
|
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,
|
|
3639
4000
|
parameters: planParameters(entry).parameters
|
|
3640
4001
|
};
|
|
3641
4002
|
}
|
|
@@ -3700,59 +4061,6 @@ function createCorePlugin(options) {
|
|
|
3700
4061
|
}
|
|
3701
4062
|
});
|
|
3702
4063
|
}
|
|
3703
|
-
|
|
3704
|
-
// src/utils/schema-utils.ts
|
|
3705
|
-
var import_zod5 = require("zod");
|
|
3706
|
-
function getOutputSchema(inputSchema) {
|
|
3707
|
-
return inputSchema._zod.def.outputSchema;
|
|
3708
|
-
}
|
|
3709
|
-
function withOutputSchema(inputSchema, outputSchema) {
|
|
3710
|
-
Object.assign(inputSchema._zod.def, {
|
|
3711
|
-
outputSchema
|
|
3712
|
-
});
|
|
3713
|
-
return inputSchema;
|
|
3714
|
-
}
|
|
3715
|
-
function withResolver(schema, config) {
|
|
3716
|
-
schema._zod.def.resolverMeta = config;
|
|
3717
|
-
return schema;
|
|
3718
|
-
}
|
|
3719
|
-
function getSchemaDescription(schema) {
|
|
3720
|
-
return schema.description;
|
|
3721
|
-
}
|
|
3722
|
-
function getFieldDescriptions(schema) {
|
|
3723
|
-
const descriptions = {};
|
|
3724
|
-
const shape = schema.shape;
|
|
3725
|
-
for (const [key2, fieldSchema] of Object.entries(shape)) {
|
|
3726
|
-
if (fieldSchema instanceof import_zod5.z.ZodType && fieldSchema.description) {
|
|
3727
|
-
descriptions[key2] = fieldSchema.description;
|
|
3728
|
-
}
|
|
3729
|
-
}
|
|
3730
|
-
return descriptions;
|
|
3731
|
-
}
|
|
3732
|
-
function withPositional(schema) {
|
|
3733
|
-
Object.assign(schema._zod.def, {
|
|
3734
|
-
positionalMeta: { positional: true }
|
|
3735
|
-
});
|
|
3736
|
-
return schema;
|
|
3737
|
-
}
|
|
3738
|
-
function schemaHasPositionalMeta(schema) {
|
|
3739
|
-
return "positionalMeta" in schema._zod.def;
|
|
3740
|
-
}
|
|
3741
|
-
function isPositional(schema) {
|
|
3742
|
-
if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
|
|
3743
|
-
return true;
|
|
3744
|
-
}
|
|
3745
|
-
if (schema instanceof import_zod5.z.ZodOptional) {
|
|
3746
|
-
return isPositional(schema._zod.def.innerType);
|
|
3747
|
-
}
|
|
3748
|
-
if (schema instanceof import_zod5.z.ZodDefault) {
|
|
3749
|
-
return isPositional(schema._zod.def.innerType);
|
|
3750
|
-
}
|
|
3751
|
-
return false;
|
|
3752
|
-
}
|
|
3753
|
-
function openEnum(values, description) {
|
|
3754
|
-
return import_zod5.z.union([import_zod5.z.enum(values), import_zod5.z.string()]).describe(description);
|
|
3755
|
-
}
|
|
3756
4064
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3757
4065
|
0 && (module.exports = {
|
|
3758
4066
|
CONTEXT,
|
|
@@ -3765,7 +4073,9 @@ function openEnum(values, description) {
|
|
|
3765
4073
|
CoreErrorCode,
|
|
3766
4074
|
CoreSignal,
|
|
3767
4075
|
addPlugin,
|
|
4076
|
+
canonicalInputSchema,
|
|
3768
4077
|
composePlugins,
|
|
4078
|
+
concatLists,
|
|
3769
4079
|
concatPaginated,
|
|
3770
4080
|
coreOptionsPluginRef,
|
|
3771
4081
|
createAsyncContext,
|