@zapier/zapier-sdk 0.84.4 → 0.86.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.
@@ -32,6 +32,36 @@ function pluralizeLastWord(title) {
32
32
  const words = title.split(" ");
33
33
  return [...words.slice(0, -1), pluralize(words[words.length - 1])].join(" ");
34
34
  }
35
+ function canonicalInputSchema(schema) {
36
+ if (schema instanceof z.ZodUnion) {
37
+ return schema.options[0];
38
+ }
39
+ return schema;
40
+ }
41
+ function withPositional(schema) {
42
+ Object.assign(schema._zod.def, {
43
+ positionalMeta: { positional: true }
44
+ });
45
+ return schema;
46
+ }
47
+ function schemaHasPositionalMeta(schema) {
48
+ return "positionalMeta" in schema._zod.def;
49
+ }
50
+ function isPositional(schema) {
51
+ if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
52
+ return true;
53
+ }
54
+ if (schema instanceof z.ZodOptional) {
55
+ return isPositional(schema._zod.def.innerType);
56
+ }
57
+ if (schema instanceof z.ZodDefault) {
58
+ return isPositional(schema._zod.def.innerType);
59
+ }
60
+ return false;
61
+ }
62
+ function openEnum(values, description) {
63
+ return z.union([z.enum(values), z.string()]).describe(description);
64
+ }
35
65
  function resolveCategoryDefinition(ref) {
36
66
  const def = typeof ref === "string" ? { key: ref } : ref;
37
67
  const title = def.title ?? toTitleCase(def.key);
@@ -41,30 +71,25 @@ function resolveCategoryDefinition(ref) {
41
71
  titlePlural: def.titlePlural ?? pluralizeLastWord(title)
42
72
  };
43
73
  }
44
- function canonicalInputSchema(schema) {
45
- if (schema instanceof z.ZodUnion) {
46
- return schema.options[0];
47
- }
48
- return schema;
49
- }
50
74
  function buildRegistry({
51
75
  sdk,
52
76
  meta,
53
77
  formatters,
54
- boundResolvers,
78
+ resolvers,
55
79
  positional,
80
+ skipInputValidation,
56
81
  packageFilter
57
82
  }) {
58
83
  const definitionsByKey = /* @__PURE__ */ new Map();
59
84
  const objectDeclaredKeys = /* @__PURE__ */ new Set();
60
85
  for (const m of Object.values(meta)) {
61
86
  for (const ref of m.categories ?? []) {
62
- const key2 = typeof ref === "string" ? ref : ref.key;
87
+ const key = typeof ref === "string" ? ref : ref.key;
63
88
  if (typeof ref === "object") {
64
- objectDeclaredKeys.add(key2);
65
- definitionsByKey.set(key2, resolveCategoryDefinition(ref));
66
- } else if (!objectDeclaredKeys.has(key2)) {
67
- definitionsByKey.set(key2, resolveCategoryDefinition(ref));
89
+ objectDeclaredKeys.add(key);
90
+ definitionsByKey.set(key, resolveCategoryDefinition(ref));
91
+ } else if (!objectDeclaredKeys.has(key)) {
92
+ definitionsByKey.set(key, resolveCategoryDefinition(ref));
68
93
  }
69
94
  }
70
95
  }
@@ -72,30 +97,29 @@ function buildRegistry({
72
97
  definitionsByKey.set("other", resolveCategoryDefinition("other"));
73
98
  }
74
99
  const knownCategories = Array.from(definitionsByKey.keys());
75
- const functions = Object.keys(meta).filter((key2) => {
76
- const property = sdk[key2];
100
+ const functions = Object.keys(meta).filter((key) => {
101
+ const property = sdk[key];
77
102
  if (typeof property === "function") return true;
78
- const [rootKey] = key2.split(".");
103
+ const [rootKey] = key.split(".");
79
104
  const rootProperty = sdk[rootKey];
80
105
  return typeof rootProperty === "object" && rootProperty !== null;
81
- }).map((key2) => {
82
- const m = meta[key2];
106
+ }).map((key) => {
107
+ const m = meta[key];
83
108
  return {
84
- name: key2,
109
+ name: key,
85
110
  description: m.description,
86
111
  type: m.type,
87
112
  itemType: m.itemType,
88
113
  returnType: m.returnType,
89
114
  inputSchema: canonicalInputSchema(m.inputSchema),
90
- inputParameters: m.inputParameters,
91
115
  outputSchema: m.outputSchema,
92
- positional: positional?.[key2],
116
+ positional: positional?.[key],
117
+ skipInputValidation: skipInputValidation?.[key],
93
118
  categories: (m.categories ?? []).map(
94
119
  (c) => typeof c === "string" ? c : c.key
95
120
  ),
96
- resolvers: m.resolvers,
97
- boundResolvers: boundResolvers?.[key2],
98
- formatter: formatters?.[key2],
121
+ resolvers: resolvers?.[key],
122
+ formatter: formatters?.[key],
99
123
  experimental: m.experimental,
100
124
  packages: m.packages,
101
125
  confirm: m.confirm ?? (m.type === "delete" ? "delete" : void 0),
@@ -408,51 +432,36 @@ function decodeConcatCursor(incoming) {
408
432
  }
409
433
  return { index: 0, cursor: incoming };
410
434
  }
411
- function concatPaginated({
435
+ async function concatLists({
412
436
  sources,
413
437
  pageSize = 100,
414
438
  cursor
415
439
  }) {
416
440
  if (sources.length === 0) {
417
- const empty = { data: [] };
418
- return Object.assign(Promise.resolve(empty), {
419
- [Symbol.asyncIterator]: async function* () {
420
- yield empty;
421
- }
422
- });
441
+ return { data: [] };
423
442
  }
424
443
  const pageFunction = async (options) => {
425
- let { index, cursor: sourceCursor } = decodeConcatCursor(options.cursor);
444
+ let { index, cursor: listCursor } = decodeConcatCursor(options.cursor);
426
445
  while (index < sources.length) {
427
- const page = await sources[index]({ cursor: sourceCursor });
428
- const hasMoreInSource = page.nextCursor != null;
429
- if (page.data.length === 0 && !hasMoreInSource) {
446
+ const page = await sources[index]({ cursor: listCursor });
447
+ const hasMoreInList = page.nextCursor != null;
448
+ if (page.data.length === 0 && !hasMoreInList) {
430
449
  index++;
431
- sourceCursor = void 0;
450
+ listCursor = void 0;
432
451
  continue;
433
452
  }
434
453
  return {
435
454
  data: page.data,
436
- nextCursor: hasMoreInSource ? encodeConcatCursor(index, page.nextCursor) : index < sources.length - 1 ? encodeConcatCursor(index + 1, void 0) : void 0
455
+ nextCursor: hasMoreInList ? encodeConcatCursor(index, page.nextCursor) : index < sources.length - 1 ? encodeConcatCursor(index + 1, void 0) : void 0
437
456
  };
438
457
  }
439
458
  return { data: [] };
440
459
  };
441
- const iterator = paginateBuffered(pageFunction, { pageSize, cursor });
442
- const firstPagePromise = iterator.next().then((result) => {
443
- if (result.done) {
444
- return { data: [] };
445
- }
446
- return result.value;
447
- });
448
- return Object.assign(firstPagePromise, {
449
- [Symbol.asyncIterator]: async function* () {
450
- yield await firstPagePromise;
451
- for await (const page of { [Symbol.asyncIterator]: () => iterator }) {
452
- yield page;
453
- }
454
- }
455
- });
460
+ const result = await paginateBuffered(pageFunction, {
461
+ pageSize,
462
+ cursor
463
+ }).next();
464
+ return result.done ? { data: [] } : result.value;
456
465
  }
457
466
  var parseOrThrow = (schema, input, { adaptError } = {}) => {
458
467
  const result = schema.safeParse(input);
@@ -525,6 +534,50 @@ function runInMethodScope(fn) {
525
534
  return scope.run({ depth: currentDepth + 1 }, fn);
526
535
  }
527
536
  var runWithTelemetryContext = runInMethodScope;
537
+ var CALL_CONTEXT_BRAND = Symbol("kitcore.callContext");
538
+ function isCallContext(value) {
539
+ return typeof value === "object" && value !== null && value[CALL_CONTEXT_BRAND] === true;
540
+ }
541
+ function generateCallId() {
542
+ try {
543
+ const webCrypto = globalThis.crypto;
544
+ if (webCrypto?.randomUUID) {
545
+ return webCrypto.randomUUID();
546
+ }
547
+ if (webCrypto?.getRandomValues) {
548
+ const bytes = webCrypto.getRandomValues(new Uint8Array(16));
549
+ const hex = Array.from(bytes, (byte, i) => {
550
+ const value = i === 6 ? byte & 15 | 64 : i === 8 ? byte & 63 | 128 : byte;
551
+ return value.toString(16).padStart(2, "0");
552
+ });
553
+ return [
554
+ hex.slice(0, 4).join(""),
555
+ hex.slice(4, 6).join(""),
556
+ hex.slice(6, 8).join(""),
557
+ hex.slice(8, 10).join(""),
558
+ hex.slice(10, 16).join("")
559
+ ].join("-");
560
+ }
561
+ } catch {
562
+ }
563
+ return null;
564
+ }
565
+ function rootCallContext() {
566
+ return {
567
+ callId: generateCallId(),
568
+ depth: 0,
569
+ annotations: {},
570
+ [CALL_CONTEXT_BRAND]: true
571
+ };
572
+ }
573
+ function childCallContext(parent) {
574
+ return {
575
+ callId: parent.callId,
576
+ depth: parent.depth + 1,
577
+ annotations: {},
578
+ [CALL_CONTEXT_BRAND]: true
579
+ };
580
+ }
528
581
  function defaultLogDeprecation({
529
582
  methodName,
530
583
  deprecation
@@ -540,6 +593,9 @@ function resolveCoreOptions(context) {
540
593
  return context.core;
541
594
  }
542
595
  var INTERNAL_CALL = Symbol("kitcore.internalCall");
596
+ function resolveCallContext(secondArg) {
597
+ return isCallContext(secondArg) ? secondArg : rootCallContext();
598
+ }
543
599
  function signalDeprecation(context, methodName, getDeprecation) {
544
600
  if (isInsideObserver()) return;
545
601
  const deprecation = getDeprecation?.();
@@ -569,14 +625,16 @@ function createFunction(coreFn, options) {
569
625
  const functionName = name || coreFn.name;
570
626
  const namedFunctions = {
571
627
  [functionName]: async function(callOptions) {
572
- if (arguments[1] !== INTERNAL_CALL) {
628
+ const internal = arguments[1];
629
+ const context = resolveCallContext(internal);
630
+ if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
573
631
  signalDeprecation(sdk.context, functionName, getDeprecation);
574
632
  }
575
633
  return runInMethodScope(async () => {
576
634
  const startTime = Date.now();
577
635
  const normalizedOptions = callOptions ?? {};
578
636
  const args = [normalizedOptions];
579
- const depth = getCurrentDepth();
637
+ const depth = Math.max(context.depth, getCurrentDepth());
580
638
  const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
581
639
  const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
582
640
  hooks?.onMethodStart?.({
@@ -595,12 +653,15 @@ function createFunction(coreFn, options) {
595
653
  adaptError
596
654
  }
597
655
  );
598
- result = await coreFn({
599
- ...normalizedOptions,
600
- ...validatedOptions
601
- });
656
+ result = await coreFn(
657
+ {
658
+ ...normalizedOptions,
659
+ ...validatedOptions
660
+ },
661
+ context
662
+ );
602
663
  } else {
603
- result = await coreFn(normalizedOptions);
664
+ result = await coreFn(normalizedOptions, context);
604
665
  }
605
666
  hooks?.onMethodEnd?.({
606
667
  methodName: functionName,
@@ -630,17 +691,19 @@ function createFunction(coreFn, options) {
630
691
  function createRawFunction(coreFn, options) {
631
692
  const { sdk, name, schema, positional, getDeprecation } = options;
632
693
  return function(rawInput) {
633
- if (arguments[1] !== INTERNAL_CALL) {
694
+ const internal = arguments[1];
695
+ const context = resolveCallContext(internal);
696
+ if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
634
697
  signalDeprecation(sdk.context, name, getDeprecation);
635
698
  }
636
699
  return runInMethodScope(() => {
637
700
  const startTime = Date.now();
638
- const depth = getCurrentDepth();
701
+ const depth = Math.max(context.depth, getCurrentDepth());
639
702
  const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
640
703
  const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
641
704
  const input = schema ? rawInput ?? {} : rawInput;
642
705
  const record = input;
643
- const args = positional ? positional.filter((key2) => record?.[key2] !== void 0).map((key2) => record?.[key2]) : [input];
706
+ const args = positional ? positional.filter((key) => record?.[key] !== void 0).map((key) => record?.[key]) : [input];
644
707
  hooks?.onMethodStart?.({
645
708
  methodName: name,
646
709
  args,
@@ -659,7 +722,7 @@ function createRawFunction(coreFn, options) {
659
722
  };
660
723
  try {
661
724
  const parsed = schema ? validateOptions(schema, input, { adaptError }) : input;
662
- const result = coreFn(parsed);
725
+ const result = coreFn(parsed, context);
663
726
  if (result !== null && typeof result === "object" && typeof result.then === "function") {
664
727
  return result.then(
665
728
  (value) => {
@@ -698,9 +761,9 @@ function createPageFunction(coreFn, {
698
761
  }) {
699
762
  const functionName = coreFn.name + "Page";
700
763
  const namedFunctions = {
701
- [functionName]: async function(options) {
764
+ [functionName]: async function(options, callContext) {
702
765
  try {
703
- const response = await coreFn(options);
766
+ const response = await coreFn(options, callContext);
704
767
  const page = adaptPage ? adaptPage(response) : response;
705
768
  if (!isSdkPage(page)) {
706
769
  throw new Error(
@@ -724,14 +787,16 @@ function createPaginatedFunction(coreFn, options) {
724
787
  const functionName = name || coreFn.name;
725
788
  const namedFunctions = {
726
789
  [functionName]: function(callOptions) {
727
- if (arguments[1] !== INTERNAL_CALL) {
790
+ const internal = arguments[1];
791
+ const context = resolveCallContext(internal);
792
+ if (!isCallContext(internal) && internal !== INTERNAL_CALL) {
728
793
  signalDeprecation(sdk.context, functionName, getDeprecation);
729
794
  }
730
795
  return runInMethodScope(() => {
731
796
  const startTime = Date.now();
732
797
  const normalizedOptions = callOptions ?? {};
733
798
  const args = [normalizedOptions];
734
- const depth = getCurrentDepth();
799
+ const depth = Math.max(context.depth, getCurrentDepth());
735
800
  const hooks = isInsideObserver() ? void 0 : sdk.context.hooks;
736
801
  const adaptError = resolveCoreOptions(sdk.context)?.adaptError;
737
802
  hooks?.onMethodStart?.({
@@ -750,7 +815,11 @@ function createPaginatedFunction(coreFn, options) {
750
815
  ...validatedOptions,
751
816
  pageSize
752
817
  };
753
- const iterator = paginate(pageFunction, optimizedOptions);
818
+ const iterator = paginate(
819
+ (pageOptions) => pageFunction(pageOptions, context),
820
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
821
+ optimizedOptions
822
+ );
754
823
  const firstPagePromise = iterator.next().then((result) => {
755
824
  if (result.done) {
756
825
  throw new Error("Paginate should always iterate at least once");
@@ -787,6 +856,13 @@ function createPaginatedFunction(coreFn, options) {
787
856
  [Symbol.asyncIterator]() {
788
857
  return pageStream;
789
858
  },
859
+ pages: function() {
860
+ return {
861
+ [Symbol.asyncIterator]() {
862
+ return pageStream;
863
+ }
864
+ };
865
+ },
790
866
  items: function() {
791
867
  return {
792
868
  [Symbol.asyncIterator]: async function* () {
@@ -892,11 +968,11 @@ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
892
968
  "context",
893
969
  "getRegistry"
894
970
  ]);
895
- function hasOwn(obj, key2) {
896
- return Object.prototype.hasOwnProperty.call(obj, key2);
971
+ function hasOwn(obj, key) {
972
+ return Object.prototype.hasOwnProperty.call(obj, key);
897
973
  }
898
- function setOwn(target, key2, value) {
899
- Object.defineProperty(target, key2, {
974
+ function setOwn(target, key, value) {
975
+ Object.defineProperty(target, key, {
900
976
  value,
901
977
  enumerable: true,
902
978
  configurable: true,
@@ -908,31 +984,31 @@ function checkCollisions(target, source, kind, callerLabel, override) {
908
984
  checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
909
985
  return;
910
986
  }
911
- for (const key2 of Object.keys(source)) {
912
- if (!override && hasOwn(target, key2)) {
987
+ for (const key of Object.keys(source)) {
988
+ if (!override && hasOwn(target, key)) {
913
989
  throw new Error(
914
- `${callerLabel}: duplicate ${kind} "${key2}". If the override is intentional, pass { override: true } in the options.`
990
+ `${callerLabel}: duplicate ${kind} "${key}". If the override is intentional, pass { override: true } in the options.`
915
991
  );
916
992
  }
917
993
  }
918
994
  }
919
995
  function checkRootKeyCollisions(target, keys, override, callerLabel) {
920
- for (const key2 of keys) {
921
- if (RESERVED_ROOT_KEYS.has(key2)) {
996
+ for (const key of keys) {
997
+ if (RESERVED_ROOT_KEYS.has(key)) {
922
998
  throw new Error(
923
- `${callerLabel}: plugin attempted to register reserved root key "${key2}". The SDK uses this key for its own accessor; rename the plugin's method.`
999
+ `${callerLabel}: plugin attempted to register reserved root key "${key}". The SDK uses this key for its own accessor; rename the plugin's method.`
924
1000
  );
925
1001
  }
926
- if (!override && hasOwn(target, key2)) {
1002
+ if (!override && hasOwn(target, key)) {
927
1003
  throw new Error(
928
- `${callerLabel}: duplicate root key "${key2}". If the override is intentional, pass { override: true } in the options.`
1004
+ `${callerLabel}: duplicate root key "${key}". If the override is intentional, pass { override: true } in the options.`
929
1005
  );
930
1006
  }
931
1007
  }
932
1008
  }
933
1009
  function applyOwnProperties(target, source) {
934
- for (const key2 of Object.keys(source)) {
935
- setOwn(target, key2, source[key2]);
1010
+ for (const key of Object.keys(source)) {
1011
+ setOwn(target, key, source[key]);
936
1012
  }
937
1013
  }
938
1014
  function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
@@ -1146,7 +1222,6 @@ var LEAF_META_KEYS = [
1146
1222
  "itemType",
1147
1223
  "returnType",
1148
1224
  "outputSchema",
1149
- "inputParameters",
1150
1225
  "packages",
1151
1226
  "experimental",
1152
1227
  "confirm",
@@ -1183,8 +1258,8 @@ function normalizeImports(deps) {
1183
1258
  }
1184
1259
  function collectLeafMeta(config) {
1185
1260
  let meta;
1186
- for (const key2 of LEAF_META_KEYS) {
1187
- if (config[key2] !== void 0) (meta ?? (meta = {}))[key2] = config[key2];
1261
+ for (const key of LEAF_META_KEYS) {
1262
+ if (config[key] !== void 0) (meta ?? (meta = {}))[key] = config[key];
1188
1263
  }
1189
1264
  return meta;
1190
1265
  }
@@ -1267,7 +1342,8 @@ function defineResolver(config) {
1267
1342
  type: "object",
1268
1343
  properties: config.properties,
1269
1344
  definitions: config.definitions,
1270
- getProperties: config.getProperties
1345
+ getProperties: config.getProperties,
1346
+ additionalKeys: config.additionalKeys
1271
1347
  };
1272
1348
  case "array":
1273
1349
  return {
@@ -1570,7 +1646,7 @@ function normalizeFormatter(entry, sdk) {
1570
1646
  const legacy = entry.meta?.formatter;
1571
1647
  return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
1572
1648
  }
1573
- function normalizeBoundResolvers(entry) {
1649
+ function normalizeResolvers(entry) {
1574
1650
  if (entry.pluginType !== "method") return void 0;
1575
1651
  return entry.resolvers;
1576
1652
  }
@@ -1611,17 +1687,20 @@ function collectSurfaceProjection(context, formatterSdk) {
1611
1687
  foldDynamicMembers(entry, surfaceBindings, meta);
1612
1688
  }
1613
1689
  const formatters = {};
1614
- const boundResolvers = {};
1690
+ const resolvers = {};
1615
1691
  const positional = {};
1692
+ const skipInputValidation = {};
1616
1693
  for (const [binding, entry] of Object.entries(entries)) {
1617
1694
  const f = normalizeFormatter(entry, formatterSdk);
1618
1695
  if (f) formatters[binding] = f;
1619
- const r = normalizeBoundResolvers(entry);
1620
- if (r) boundResolvers[binding] = r;
1696
+ const r = normalizeResolvers(entry);
1697
+ if (r) resolvers[binding] = r;
1621
1698
  const p = methodPositional(entry);
1622
1699
  if (p) positional[binding] = p;
1700
+ if (entry.pluginType === "method" && entry.skipInputValidation)
1701
+ skipInputValidation[binding] = true;
1623
1702
  }
1624
- return { meta, formatters, boundResolvers, positional };
1703
+ return { meta, formatters, resolvers, positional, skipInputValidation };
1625
1704
  }
1626
1705
  function buildSurfaceRegistry(context, packageFilter) {
1627
1706
  const surface = {};
@@ -1674,6 +1753,11 @@ function nestedResolvers(resolver) {
1674
1753
  for (const field of Object.values(resolver.properties ?? {})) {
1675
1754
  if (!isResolverRef(field.resolver)) out.push(field.resolver);
1676
1755
  }
1756
+ const ak = resolver.additionalKeys;
1757
+ if (ak) {
1758
+ if (!isResolverRef(ak.values)) out.push(ak.values);
1759
+ if (ak.keys && !isResolverRef(ak.keys)) out.push(ak.keys);
1760
+ }
1677
1761
  out.push(...Object.values(resolver.definitions ?? {}));
1678
1762
  } else if (resolver.type === "array") {
1679
1763
  if (!isResolverRef(resolver.items)) out.push(resolver.items);
@@ -1798,16 +1882,16 @@ function collectPlugins(root, materialized = /* @__PURE__ */ new Set(), configur
1798
1882
  }
1799
1883
  return byId;
1800
1884
  }
1801
- function bindValue(target, key2, entry, callType = "surface") {
1885
+ function bindValue(target, key, entry, callType = "surface", ctx) {
1802
1886
  if (entry.pluginType === "property" && entry.getValue) {
1803
- Object.defineProperty(target, key2, {
1887
+ Object.defineProperty(target, key, {
1804
1888
  get: entry.getValue,
1805
1889
  enumerable: true,
1806
1890
  configurable: true
1807
1891
  });
1808
1892
  } else {
1809
- const value = callType === "internal" && entry.pluginType === "method" ? entry.internalValue ?? entry.value : entry.value;
1810
- Object.defineProperty(target, key2, {
1893
+ const value = callType === "internal" && entry.pluginType === "method" ? entry.bindInternal?.(ctx) ?? entry.internalValue ?? entry.value : entry.value;
1894
+ Object.defineProperty(target, key, {
1811
1895
  value,
1812
1896
  writable: true,
1813
1897
  enumerable: true,
@@ -1824,7 +1908,7 @@ function buildSurface(context, ...maps) {
1824
1908
  sdk[CONTEXT] = context;
1825
1909
  return sdk;
1826
1910
  }
1827
- function buildImports(plugins, importBindings) {
1911
+ function buildImports(plugins, importBindings, ctx) {
1828
1912
  const imports = {};
1829
1913
  for (const { binding, id, optional } of importBindings) {
1830
1914
  const entry = plugins[id];
@@ -1837,7 +1921,7 @@ function buildImports(plugins, importBindings) {
1837
1921
  });
1838
1922
  continue;
1839
1923
  }
1840
- bindValue(imports, binding, entry, "internal");
1924
+ bindValue(imports, binding, entry, "internal", ctx);
1841
1925
  }
1842
1926
  return imports;
1843
1927
  }
@@ -1916,6 +2000,19 @@ function bindResolver(resolver, plugins) {
1916
2000
  const { getProperties } = resolver;
1917
2001
  if (getProperties)
1918
2002
  bound.getProperties = ({ input }) => getProperties({ imports, input });
2003
+ if (resolver.additionalKeys) {
2004
+ const ak = resolver.additionalKeys;
2005
+ const boundAk = {
2006
+ values: isResolverRef(ak.values) ? ak.values : bindResolver(ak.values, plugins),
2007
+ minEntries: ak.minEntries,
2008
+ maxEntries: ak.maxEntries,
2009
+ keyValueType: ak.keyValueType,
2010
+ valueValueType: ak.valueValueType
2011
+ };
2012
+ if (ak.keys)
2013
+ boundAk.keys = isResolverRef(ak.keys) ? ak.keys : bindResolver(ak.keys, plugins);
2014
+ bound.additionalKeys = boundAk;
2015
+ }
1919
2016
  return bound;
1920
2017
  }
1921
2018
  case "array": {
@@ -1971,8 +2068,8 @@ function bindResolver(resolver, plugins) {
1971
2068
  }
1972
2069
  function bindFields(fields, plugins) {
1973
2070
  const out = {};
1974
- for (const [key2, field] of Object.entries(fields)) {
1975
- out[key2] = {
2071
+ for (const [key, field] of Object.entries(fields)) {
2072
+ out[key] = {
1976
2073
  ...field,
1977
2074
  resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
1978
2075
  };
@@ -1981,8 +2078,8 @@ function bindFields(fields, plugins) {
1981
2078
  }
1982
2079
  function bindDefinitions(definitions, plugins) {
1983
2080
  const out = {};
1984
- for (const [key2, def] of Object.entries(definitions)) {
1985
- out[key2] = bindResolver(def, plugins);
2081
+ for (const [key, def] of Object.entries(definitions)) {
2082
+ out[key] = bindResolver(def, plugins);
1986
2083
  }
1987
2084
  return out;
1988
2085
  }
@@ -2066,6 +2163,7 @@ function buildMethodEntries(descriptors, context, states) {
2066
2163
  name: descriptor.name,
2067
2164
  chain: [],
2068
2165
  inputSchema: descriptor.inputSchema,
2166
+ skipInputValidation: descriptor.skipInputValidation,
2069
2167
  // Derive the presentation type from the output mode when the author did
2070
2168
  // not set one; an explicit meta.type (e.g. "create") still wins.
2071
2169
  meta: out.type === "raw" || descriptor.meta?.type ? descriptor.meta : { ...descriptor.meta, type: out.type },
@@ -2073,17 +2171,17 @@ function buildMethodEntries(descriptors, context, states) {
2073
2171
  // Replaced below; never called.
2074
2172
  value: () => void 0
2075
2173
  };
2076
- const callRun = (input) => descriptor.run({
2077
- imports: buildImports(plugins, descriptor.importBindings),
2174
+ const callRun = (input, ctx) => descriptor.run({
2175
+ imports: buildImports(plugins, descriptor.importBindings, ctx),
2078
2176
  state: states.get(id),
2079
2177
  input
2080
2178
  });
2081
- const fold = (coreFn) => (input) => {
2082
- let next = coreFn;
2179
+ const fold = (coreFn) => (input, ctx) => {
2180
+ let next = (i) => coreFn(i, ctx);
2083
2181
  for (const wrap of entry.chain) {
2084
2182
  const inner = next;
2085
2183
  next = (i) => wrap.run({
2086
- imports: buildImports(plugins, wrap.owner.importBindings),
2184
+ imports: buildImports(plugins, wrap.owner.importBindings, ctx),
2087
2185
  next: inner,
2088
2186
  input: i,
2089
2187
  // Overwritten by the chain item's own closure with the owning
@@ -2107,7 +2205,7 @@ function buildMethodEntries(descriptors, context, states) {
2107
2205
  }
2108
2206
  );
2109
2207
  } else if (out.type === "item") {
2110
- const itemCore = async (input) => callRun(input);
2208
+ const itemCore = async (input, ctx) => callRun(input, ctx);
2111
2209
  entry.value = createFunction(
2112
2210
  fold(itemCore),
2113
2211
  {
@@ -2119,7 +2217,7 @@ function buildMethodEntries(descriptors, context, states) {
2119
2217
  );
2120
2218
  } else {
2121
2219
  entry.value = createRawFunction(
2122
- (input) => fold(callRun)(input),
2220
+ (input, ctx) => fold(callRun)(input, ctx),
2123
2221
  {
2124
2222
  sdk,
2125
2223
  name: descriptor.name,
@@ -2142,11 +2240,15 @@ function buildMethodEntries(descriptors, context, states) {
2142
2240
  });
2143
2241
  return packed;
2144
2242
  };
2243
+ const internalValue = (...args) => canonicalValue(pack(args), INTERNAL_CALL);
2145
2244
  entry.value = (...args) => canonicalValue(pack(args));
2146
- entry.internalValue = (...args) => canonicalValue(pack(args), INTERNAL_CALL);
2245
+ entry.internalValue = internalValue;
2246
+ entry.bindInternal = (ctx) => ctx ? (...args) => canonicalValue(pack(args), childCallContext(ctx)) : internalValue;
2147
2247
  entry.positional = names;
2148
2248
  } else {
2149
- entry.internalValue = (input) => canonicalValue(input, INTERNAL_CALL);
2249
+ const internalValue = (input) => canonicalValue(input, INTERNAL_CALL);
2250
+ entry.internalValue = internalValue;
2251
+ entry.bindInternal = (ctx) => ctx ? (input) => canonicalValue(input, childCallContext(ctx)) : internalValue;
2150
2252
  }
2151
2253
  plugins[id] = entry;
2152
2254
  }
@@ -2386,7 +2488,7 @@ function createSdk(root, options) {
2386
2488
  pluginSurface = {};
2387
2489
  bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
2388
2490
  }
2389
- for (const key2 of Object.keys(legacyExports)) context.surface[key2] = key2;
2491
+ for (const key of Object.keys(legacyExports)) context.surface[key] = key;
2390
2492
  if (plugin.pluginType === "aggregate") {
2391
2493
  recordExportSurface(context, plugin.exports);
2392
2494
  } else {
@@ -2517,6 +2619,7 @@ function valueTypeOf(inner) {
2517
2619
  if (inner instanceof z.ZodEnum) return "string";
2518
2620
  if (inner instanceof z.ZodArray) return "array";
2519
2621
  if (inner instanceof z.ZodObject) return "object";
2622
+ if (inner instanceof z.ZodRecord) return "object";
2520
2623
  return void 0;
2521
2624
  }
2522
2625
  function staticChoicesOf(inner) {
@@ -2527,7 +2630,8 @@ function staticChoicesOf(inner) {
2527
2630
  return void 0;
2528
2631
  }
2529
2632
  function objectShape(schema) {
2530
- const { inner } = schema ? unwrap(schema) : { inner: void 0 };
2633
+ const canonical = canonicalInputSchema(schema);
2634
+ const { inner } = canonical ? unwrap(canonical) : { inner: void 0 };
2531
2635
  if (inner instanceof z.ZodObject) {
2532
2636
  return inner.shape;
2533
2637
  }
@@ -2549,7 +2653,7 @@ function topoOrder2(specs) {
2549
2653
  }
2550
2654
  function planParameters(entry) {
2551
2655
  const shape = objectShape(entry.inputSchema);
2552
- const resolvers = entry.boundResolvers ?? {};
2656
+ const resolvers = entry.resolvers ?? {};
2553
2657
  const names = shape ? [
2554
2658
  ...Object.keys(shape),
2555
2659
  ...Object.keys(resolvers).filter(
@@ -2585,24 +2689,48 @@ function getAtPath(root, path) {
2585
2689
  }
2586
2690
  return node;
2587
2691
  }
2692
+ function defineOwn(node, key, value) {
2693
+ Object.defineProperty(node, key, {
2694
+ value,
2695
+ writable: true,
2696
+ enumerable: true,
2697
+ configurable: true
2698
+ });
2699
+ }
2588
2700
  function setAtPath(root, path, value) {
2589
2701
  let node = root;
2590
2702
  for (let i = 0; i < path.length - 1; i++) {
2591
2703
  const seg = path[i];
2592
- if (node[seg] == null || typeof node[seg] !== "object") node[seg] = {};
2593
- node = node[seg];
2704
+ const existing = Object.prototype.hasOwnProperty.call(node, seg) ? node[seg] : void 0;
2705
+ if (existing != null && typeof existing === "object") {
2706
+ node = existing;
2707
+ } else {
2708
+ const child = {};
2709
+ defineOwn(node, seg, child);
2710
+ node = child;
2711
+ }
2594
2712
  }
2595
- node[path[path.length - 1]] = value;
2713
+ defineOwn(node, path[path.length - 1], value);
2596
2714
  }
2597
- var key = (path) => path.join(".");
2715
+ var SAFE_SEGMENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
2716
+ var pathToKey = (path) => {
2717
+ let out = "";
2718
+ for (const segment of path) {
2719
+ if (typeof segment === "number") out += `[${segment}]`;
2720
+ else if (SAFE_SEGMENT.test(segment))
2721
+ out += out === "" ? segment : `.${segment}`;
2722
+ else out += `[${JSON.stringify(segment)}]`;
2723
+ }
2724
+ return out;
2725
+ };
2598
2726
  function isSettled(state, path) {
2599
- return state.settled.includes(key(path));
2727
+ return state.settled.includes(pathToKey(path));
2600
2728
  }
2601
2729
  function remember(state, k) {
2602
2730
  if (!state.settled.includes(k)) state.settled.push(k);
2603
2731
  }
2604
2732
  function settle(state, path) {
2605
- remember(state, key(path));
2733
+ remember(state, pathToKey(path));
2606
2734
  }
2607
2735
  function clone(state) {
2608
2736
  return JSON.parse(JSON.stringify(state));
@@ -2617,6 +2745,28 @@ function coerce(leaf, raw) {
2617
2745
  if (raw === "true") return true;
2618
2746
  if (raw === "false") return false;
2619
2747
  }
2748
+ if (leaf.valueType === "object") {
2749
+ const trimmed = raw.trim();
2750
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2751
+ try {
2752
+ return JSON.parse(trimmed);
2753
+ } catch {
2754
+ return raw;
2755
+ }
2756
+ }
2757
+ return raw;
2758
+ }
2759
+ if (leaf.valueType === "array") {
2760
+ const trimmed = raw.trim();
2761
+ if (trimmed.startsWith("[")) {
2762
+ try {
2763
+ return JSON.parse(trimmed);
2764
+ } catch {
2765
+ return raw;
2766
+ }
2767
+ }
2768
+ return raw;
2769
+ }
2620
2770
  return raw;
2621
2771
  }
2622
2772
  async function validationError(leaf, value, state) {
@@ -2674,27 +2824,6 @@ async function objectChildren(resolver, input) {
2674
2824
  return toLeaf(name, field, resolver.definitions);
2675
2825
  });
2676
2826
  }
2677
- function arrayItem(resolver) {
2678
- const items = resolver.items;
2679
- const valueType = resolver.itemValueType;
2680
- if (isRef(items)) {
2681
- return {
2682
- name: "",
2683
- required: true,
2684
- resolver: resolver.definitions?.[items.ref],
2685
- extraInput: items.input,
2686
- valueType,
2687
- requires: []
2688
- };
2689
- }
2690
- return {
2691
- name: "",
2692
- required: true,
2693
- resolver: items,
2694
- valueType,
2695
- requires: []
2696
- };
2697
- }
2698
2827
  function autoSettles(resolver) {
2699
2828
  return resolver.type === "constant" || resolver.type === "info";
2700
2829
  }
@@ -2714,10 +2843,28 @@ async function leafAt(ctx, path, resolved) {
2714
2843
  const seg = path[i];
2715
2844
  if (typeof seg === "number") {
2716
2845
  if (leaf?.resolver?.type !== "array") return void 0;
2717
- leaf = arrayItem(leaf.resolver);
2846
+ leaf = boundLeaf(
2847
+ "",
2848
+ leaf.resolver.items,
2849
+ leaf.resolver.definitions,
2850
+ leaf.resolver.itemValueType
2851
+ );
2718
2852
  } else {
2719
- leaf = children.find((c) => c.name === seg);
2720
- if (!leaf) return void 0;
2853
+ const parent = leaf;
2854
+ const found = children.find((c) => c.name === seg);
2855
+ if (found) {
2856
+ leaf = found;
2857
+ } else if (parent?.resolver?.type === "object" && parent.resolver.additionalKeys) {
2858
+ const ak = parent.resolver.additionalKeys;
2859
+ leaf = boundLeaf(
2860
+ String(seg),
2861
+ ak.values,
2862
+ parent.resolver.definitions,
2863
+ ak.valueValueType
2864
+ );
2865
+ } else {
2866
+ return void 0;
2867
+ }
2721
2868
  }
2722
2869
  if (i < path.length - 1 && typeof path[i + 1] === "string") {
2723
2870
  if (leaf?.resolver?.type !== "object") return void 0;
@@ -2729,16 +2876,81 @@ async function leafAt(ctx, path, resolved) {
2729
2876
  }
2730
2877
  return leaf;
2731
2878
  }
2879
+ function boundLeaf(name, resolverOrRef, definitions, valueType) {
2880
+ if (isRef(resolverOrRef)) {
2881
+ return {
2882
+ name,
2883
+ required: true,
2884
+ resolver: definitions?.[resolverOrRef.ref],
2885
+ extraInput: resolverOrRef.input,
2886
+ valueType,
2887
+ requires: []
2888
+ };
2889
+ }
2890
+ return {
2891
+ name,
2892
+ required: true,
2893
+ resolver: resolverOrRef,
2894
+ valueType,
2895
+ requires: []
2896
+ };
2897
+ }
2898
+ async function recordInfoAt(ctx, path, resolved) {
2899
+ const leaf = await leafAt(ctx, path, resolved);
2900
+ const resolver = leaf?.resolver;
2901
+ if (resolver?.type !== "object" || !resolver.additionalKeys) {
2902
+ throw new Error(
2903
+ `expected an object resolver with additionalKeys at "${pathToKey(path)}"`
2904
+ );
2905
+ }
2906
+ if (resolver.getProperties) {
2907
+ throw new Error(
2908
+ `object resolver at "${pathToKey(path)}" cannot combine getProperties with additionalKeys`
2909
+ );
2910
+ }
2911
+ const ak = resolver.additionalKeys;
2912
+ const defs = resolver.definitions;
2913
+ const keyLeaf = ak.keys ? boundLeaf("key", ak.keys, defs, ak.keyValueType ?? "string") : {
2914
+ name: "key",
2915
+ required: true,
2916
+ resolver: { type: "static", inputType: "text" },
2917
+ valueType: "string",
2918
+ requires: []
2919
+ };
2920
+ const valueLeaf = boundLeaf("value", ak.values, defs, ak.valueValueType);
2921
+ if (keyLeaf.resolver && keyLeaf.resolver.type !== "static") {
2922
+ throw new Error(
2923
+ `record key resolver at "${pathToKey(path)}" must be a static free-text prompt, not "${keyLeaf.resolver.type}"`
2924
+ );
2925
+ }
2926
+ if (valueLeaf.resolver?.type === "object" || valueLeaf.resolver?.type === "array") {
2927
+ throw new Error(
2928
+ `record value resolver at "${pathToKey(path)}" must be a single value, not "${valueLeaf.resolver.type}"`
2929
+ );
2930
+ }
2931
+ return {
2932
+ min: ak.minEntries ?? 0,
2933
+ max: ak.maxEntries ?? Infinity,
2934
+ keyLeaf,
2935
+ valueLeaf,
2936
+ fixedKeys: Object.keys(resolver.properties ?? {})
2937
+ };
2938
+ }
2732
2939
  async function arrayInfoAt(ctx, path, resolved) {
2733
2940
  const leaf = await leafAt(ctx, path, resolved);
2734
2941
  const resolver = leaf?.resolver;
2735
2942
  if (resolver?.type !== "array") {
2736
- throw new Error(`expected an array resolver at "${key(path)}"`);
2943
+ throw new Error(`expected an array resolver at "${pathToKey(path)}"`);
2737
2944
  }
2738
2945
  return {
2739
2946
  min: resolver.minItems ?? 0,
2740
2947
  max: resolver.maxItems ?? Infinity,
2741
- item: { ...arrayItem(resolver), name: String(path[path.length - 1]) }
2948
+ item: boundLeaf(
2949
+ String(path[path.length - 1]),
2950
+ resolver.items,
2951
+ resolver.definitions,
2952
+ resolver.itemValueType
2953
+ )
2742
2954
  };
2743
2955
  }
2744
2956
  async function firstPage(result) {
@@ -2817,6 +3029,9 @@ var AFFORDANCE = {
2817
3029
  retry: { action: "retry", description: "Retry loading the options" },
2818
3030
  cancel: { action: "cancel", description: "Cancel resolution" }
2819
3031
  };
3032
+ function affordance(base, description) {
3033
+ return { ...base, description };
3034
+ }
2820
3035
  function selectActions(leaf, page, multiple) {
2821
3036
  const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
2822
3037
  if (searchMode && page.position.search === void 0 && page.items.length === 0) {
@@ -2931,7 +3146,7 @@ async function buildQuestion(leaf, path, input) {
2931
3146
  }
2932
3147
  };
2933
3148
  }
2934
- function collectionQuestion(t) {
3149
+ function arrayItemsQuestion(t) {
2935
3150
  const actions = [AFFORDANCE.add];
2936
3151
  if (t.count >= t.min) actions.push(AFFORDANCE.done);
2937
3152
  return {
@@ -2947,22 +3162,37 @@ function collectionQuestion(t) {
2947
3162
  actions
2948
3163
  };
2949
3164
  }
2950
- function objectGateQuestion(path) {
3165
+ function recordEntriesQuestion(t) {
3166
+ const actions = [
3167
+ affordance(AFFORDANCE.add, "Add another entry")
3168
+ ];
3169
+ if (t.count >= t.min) {
3170
+ actions.push(affordance(AFFORDANCE.done, "Finish the entries"));
3171
+ }
3172
+ return {
3173
+ type: "collection",
3174
+ path: t.path,
3175
+ message: `Add another ${t.path[t.path.length - 1]} entry? (${t.count} so far)`,
3176
+ container: "record",
3177
+ count: t.count,
3178
+ min: t.min,
3179
+ ...Number.isFinite(t.max) ? { max: t.max } : {},
3180
+ actions
3181
+ };
3182
+ }
3183
+ function objectOptionalQuestion(path) {
2951
3184
  return {
2952
3185
  type: "collection",
2953
3186
  path,
2954
3187
  message: `Add ${path[path.length - 1]}?`,
2955
3188
  container: "object",
2956
3189
  actions: [
2957
- {
2958
- action: "add",
2959
- description: "Provide values for these fields"
2960
- },
2961
- { action: "done", description: "Skip these fields" }
3190
+ affordance(AFFORDANCE.add, "Provide values for these fields"),
3191
+ affordance(AFFORDANCE.done, "Skip these fields")
2962
3192
  ]
2963
3193
  };
2964
3194
  }
2965
- function optionalsGateQuestion(path, pending) {
3195
+ function objectOptionalPropertiesQuestion(path, pending) {
2966
3196
  return {
2967
3197
  type: "collection",
2968
3198
  path,
@@ -2979,8 +3209,8 @@ function optionalsGateQuestion(path, pending) {
2979
3209
  ...leaf.valueType ? { valueType: leaf.valueType } : {}
2980
3210
  })),
2981
3211
  actions: [
2982
- { action: "add", description: "Configure the optional fields" },
2983
- { action: "done", description: "Skip the optional fields" }
3212
+ affordance(AFFORDANCE.add, "Configure the optional fields"),
3213
+ affordance(AFFORDANCE.done, "Skip the optional fields")
2984
3214
  ]
2985
3215
  };
2986
3216
  }
@@ -2996,7 +3226,8 @@ function finalize(ctx, resolved) {
2996
3226
  }));
2997
3227
  return { status: "invalid", issues };
2998
3228
  }
2999
- var optionalsMarker = (path) => `${key(path)}?optionals`;
3229
+ var optionalsMarker = (path) => `${pathToKey(path)}?optionals`;
3230
+ var UNSAFE_RECORD_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
3000
3231
  async function findInArray(ctx, state, path) {
3001
3232
  if (isSettled(state, path)) return null;
3002
3233
  if (getAtPath(state.resolved, path) == null)
@@ -3017,7 +3248,28 @@ async function findInArray(ctx, state, path) {
3017
3248
  }
3018
3249
  }
3019
3250
  if (len < min) return descendItem(ctx, state, path, len, item);
3020
- if (len < max) return { kind: "array", path, count: len, min, max };
3251
+ if (len < max) return { type: "array_items", path, count: len, min, max };
3252
+ settle(state, path);
3253
+ return null;
3254
+ }
3255
+ async function findInRecord(ctx, state, path) {
3256
+ if (isSettled(state, path)) return null;
3257
+ if (getAtPath(state.resolved, path) == null)
3258
+ setAtPath(state.resolved, path, {});
3259
+ if (!state.interactive) {
3260
+ settle(state, path);
3261
+ return null;
3262
+ }
3263
+ const { min, max, keyLeaf, fixedKeys } = await recordInfoAt(
3264
+ ctx,
3265
+ path,
3266
+ state.resolved
3267
+ );
3268
+ const container = getAtPath(state.resolved, path);
3269
+ const fixed = new Set(fixedKeys);
3270
+ const count = Object.keys(container).filter((k) => !fixed.has(k)).length;
3271
+ if (count < min) return { type: "record_key", path, leaf: keyLeaf };
3272
+ if (count < max) return { type: "record_entries", path, count, min, max };
3021
3273
  settle(state, path);
3022
3274
  return null;
3023
3275
  }
@@ -3035,10 +3287,10 @@ function seedItemSlot(state, itemPath, item) {
3035
3287
  }
3036
3288
  async function descendItem(ctx, state, arrayPath, index, item) {
3037
3289
  const itemPath = [...arrayPath, index];
3038
- const kind = seedItemSlot(state, itemPath, item);
3039
- if (kind === "object") return findNext(ctx, state, itemPath);
3040
- if (kind === "array") return findInArray(ctx, state, itemPath);
3041
- return { kind: "leaf", path: itemPath, leaf: item };
3290
+ const slotType = seedItemSlot(state, itemPath, item);
3291
+ if (slotType === "object") return findNext(ctx, state, itemPath);
3292
+ if (slotType === "array") return findInArray(ctx, state, itemPath);
3293
+ return { type: "leaf", path: itemPath, leaf: item };
3042
3294
  }
3043
3295
  async function findNext(ctx, state, path = []) {
3044
3296
  const container = getAtPath(state.resolved, path) ?? {};
@@ -3063,7 +3315,7 @@ async function findNext(ctx, state, path = []) {
3063
3315
  const pending = ordered.filter(
3064
3316
  (c) => !c.required && asksUser(c) && isPendingChild(c)
3065
3317
  );
3066
- return { kind: "optionals", path, pending };
3318
+ return { type: "object_optional_properties", path, pending };
3067
3319
  }
3068
3320
  if (leaf.resolver?.type === "object") {
3069
3321
  if (isSettled(state, childPath)) continue;
@@ -3073,7 +3325,7 @@ async function findNext(ctx, state, path = []) {
3073
3325
  settle(state, childPath);
3074
3326
  continue;
3075
3327
  }
3076
- return { kind: "object", path: childPath, leaf };
3328
+ return { type: "object_optional", path: childPath, leaf };
3077
3329
  }
3078
3330
  setAtPath(state.resolved, childPath, {});
3079
3331
  }
@@ -3105,13 +3357,21 @@ async function findNext(ctx, state, path = []) {
3105
3357
  }
3106
3358
  if (container[leaf.name] !== void 0 || isSettled(state, childPath))
3107
3359
  continue;
3108
- return { kind: "leaf", path: childPath, leaf };
3360
+ return { type: "leaf", path: childPath, leaf };
3361
+ }
3362
+ if (inObject && !isSettled(state, path)) {
3363
+ const self = await leafAt(ctx, path, state.resolved);
3364
+ if (self?.resolver?.type === "object" && self.resolver.additionalKeys) {
3365
+ const rec = await findInRecord(ctx, state, path);
3366
+ if (rec) return rec;
3367
+ }
3109
3368
  }
3110
3369
  return null;
3111
3370
  }
3112
3371
  async function askLeaf(state, path, leaf, opts = {}) {
3113
3372
  state.current = path;
3114
- delete state.gate;
3373
+ if (opts.gate) state.gate = opts.gate;
3374
+ else delete state.gate;
3115
3375
  try {
3116
3376
  const { question, pagination } = await buildQuestion(
3117
3377
  leaf,
@@ -3132,6 +3392,28 @@ async function askLeaf(state, path, leaf, opts = {}) {
3132
3392
  return failedResult(state, leaf.name, error);
3133
3393
  }
3134
3394
  }
3395
+ async function askRecordKey(state, path, keyLeaf, opts = {}) {
3396
+ return askLeaf(state, path, keyLeaf, { gate: "record_key", ...opts });
3397
+ }
3398
+ async function autoResolveLeaf(state, path, leaf) {
3399
+ const resolver = leaf.resolver;
3400
+ if (resolver && autoSettles(resolver)) {
3401
+ if (resolver.type === "constant")
3402
+ setAtPath(state.resolved, path, resolver.value);
3403
+ settle(state, path);
3404
+ return true;
3405
+ }
3406
+ const auto = resolver?.type === "dynamic" ? await resolver.tryResolveWithoutPrompt?.({
3407
+ input: mergeInput(state.resolved, leaf.extraInput)
3408
+ }) : void 0;
3409
+ if (auto) {
3410
+ if (auto.resolvedValue !== void 0)
3411
+ setAtPath(state.resolved, path, auto.resolvedValue);
3412
+ settle(state, path);
3413
+ return true;
3414
+ }
3415
+ return false;
3416
+ }
3135
3417
  async function advance(ctx, state) {
3136
3418
  for (; ; ) {
3137
3419
  const target = await findNext(ctx, state);
@@ -3141,54 +3423,56 @@ async function advance(ctx, state) {
3141
3423
  delete state.pagination;
3142
3424
  return { state, result: finalize(ctx, state.resolved) };
3143
3425
  }
3144
- if (target.kind === "array") {
3426
+ if (target.type === "array_items") {
3145
3427
  state.current = target.path;
3146
- state.gate = "array";
3428
+ state.gate = "array_items";
3147
3429
  delete state.pagination;
3148
3430
  return {
3149
3431
  state,
3150
- result: { status: "ask", question: collectionQuestion(target) }
3432
+ result: { status: "ask", question: arrayItemsQuestion(target) }
3151
3433
  };
3152
3434
  }
3153
- if (target.kind === "object") {
3435
+ if (target.type === "object_optional") {
3154
3436
  state.current = target.path;
3155
- state.gate = "entry";
3437
+ state.gate = "object_optional";
3156
3438
  delete state.pagination;
3157
3439
  return {
3158
3440
  state,
3159
- result: { status: "ask", question: objectGateQuestion(target.path) }
3441
+ result: {
3442
+ status: "ask",
3443
+ question: objectOptionalQuestion(target.path)
3444
+ }
3160
3445
  };
3161
3446
  }
3162
- if (target.kind === "optionals") {
3447
+ if (target.type === "object_optional_properties") {
3163
3448
  state.current = target.path;
3164
- state.gate = "optionals";
3449
+ state.gate = "object_optional_properties";
3165
3450
  delete state.pagination;
3166
3451
  return {
3167
3452
  state,
3168
3453
  result: {
3169
3454
  status: "ask",
3170
- question: optionalsGateQuestion(target.path, target.pending)
3455
+ question: objectOptionalPropertiesQuestion(
3456
+ target.path,
3457
+ target.pending
3458
+ )
3171
3459
  }
3172
3460
  };
3173
3461
  }
3174
- const { path, leaf } = target;
3175
- const resolver = leaf.resolver;
3176
- if (resolver && autoSettles(resolver)) {
3177
- if (resolver.type === "constant") {
3178
- setAtPath(state.resolved, path, resolver.value);
3179
- }
3180
- settle(state, path);
3181
- continue;
3462
+ if (target.type === "record_entries") {
3463
+ state.current = target.path;
3464
+ state.gate = "record_entries";
3465
+ delete state.pagination;
3466
+ return {
3467
+ state,
3468
+ result: { status: "ask", question: recordEntriesQuestion(target) }
3469
+ };
3182
3470
  }
3183
- const auto = resolver?.type === "dynamic" ? await resolver.tryResolveWithoutPrompt?.({
3184
- input: mergeInput(state.resolved, leaf.extraInput)
3185
- }) : void 0;
3186
- if (auto) {
3187
- if (auto.resolvedValue !== void 0)
3188
- setAtPath(state.resolved, path, auto.resolvedValue);
3189
- settle(state, path);
3190
- continue;
3471
+ if (target.type === "record_key") {
3472
+ return askRecordKey(state, target.path, target.leaf);
3191
3473
  }
3474
+ const { path, leaf } = target;
3475
+ if (await autoResolveLeaf(state, path, leaf)) continue;
3192
3476
  if (!state.interactive) {
3193
3477
  if (!leaf.required) {
3194
3478
  settle(state, path);
@@ -3221,10 +3505,18 @@ async function step(ctx, prior, action) {
3221
3505
  delete state.pagination;
3222
3506
  return { state, result: { status: "cancelled" } };
3223
3507
  }
3508
+ if (state.gate === "record_key") {
3509
+ return stepRecordKey(ctx, state, action);
3510
+ }
3224
3511
  const path = state.current;
3225
3512
  if (!path) throw new Error("step called with no outstanding question");
3226
3513
  const leaf = await leafAt(ctx, path, state.resolved);
3227
- if (leaf && (action.type === "search" || action.type === "next_page" || action.type === "previous_page" || action.type === "retry")) {
3514
+ if (!leaf) {
3515
+ throw new Error(
3516
+ `no resolver for the outstanding question at "${pathToKey(path)}"`
3517
+ );
3518
+ }
3519
+ if (action.type === "search" || action.type === "next_page" || action.type === "previous_page" || action.type === "retry") {
3228
3520
  return refine(ctx, state, leaf, path, action);
3229
3521
  }
3230
3522
  if (action.type === "add" || action.type === "done") {
@@ -3241,19 +3533,26 @@ async function step(ctx, prior, action) {
3241
3533
  settle(state, path);
3242
3534
  return advance(ctx, state);
3243
3535
  }
3244
- if (gate === "entry") {
3536
+ if (gate === "object_optional") {
3245
3537
  setAtPath(state.resolved, path, {});
3246
3538
  return advance(ctx, state);
3247
3539
  }
3248
- if (gate === "optionals") {
3540
+ if (gate === "object_optional_properties") {
3249
3541
  remember(state, optionalsMarker(path));
3250
3542
  return advance(ctx, state);
3251
3543
  }
3544
+ if (gate === "record_entries") {
3545
+ const { keyLeaf } = await recordInfoAt(ctx, path, state.resolved);
3546
+ return askRecordKey(state, path, keyLeaf);
3547
+ }
3252
3548
  const items = getAtPath(state.resolved, path) ?? [];
3253
3549
  const { item } = await arrayInfoAt(ctx, path, state.resolved);
3254
3550
  const itemPath = [...path, items.length];
3255
- if (seedItemSlot(state, itemPath, item) === "leaf")
3551
+ if (seedItemSlot(state, itemPath, item) === "leaf") {
3552
+ if (await autoResolveLeaf(state, itemPath, item))
3553
+ return advance(ctx, state);
3256
3554
  return askLeaf(state, itemPath, item);
3555
+ }
3257
3556
  return advance(ctx, state);
3258
3557
  }
3259
3558
  if (state.gate) {
@@ -3264,81 +3563,37 @@ async function step(ctx, prior, action) {
3264
3563
  switch (action.type) {
3265
3564
  case "choose":
3266
3565
  case "custom": {
3267
- if (leaf) {
3268
- let error;
3269
- try {
3270
- error = await validationError(leaf, action.value, state);
3271
- } catch (thrown) {
3272
- return failedResult(state, leaf.name, thrown);
3273
- }
3274
- if (error) {
3275
- if (state.pagination && leaf.resolver?.type === "dynamic") {
3276
- try {
3277
- const context = await resolveContext(leaf, state.resolved);
3278
- const page = await fetchListing(
3279
- leaf,
3280
- state.resolved,
3281
- state.pagination.position,
3282
- context
3283
- );
3284
- state.pagination = toPagination(page);
3285
- return {
3286
- state,
3287
- result: {
3288
- status: "ask",
3289
- question: selectQuestion(
3290
- leaf,
3291
- path,
3292
- state.resolved,
3293
- page,
3294
- context
3295
- ),
3296
- error
3297
- }
3298
- };
3299
- } catch (fetchError) {
3300
- state.pagination = failedPagination(
3301
- state.pagination,
3302
- state.pagination.position
3303
- );
3304
- return failedResult(state, leaf.name, fetchError);
3305
- }
3306
- }
3307
- return askLeaf(state, path, leaf, { error });
3566
+ let error;
3567
+ try {
3568
+ error = await validationError(leaf, action.value, state);
3569
+ } catch (thrown) {
3570
+ return failedResult(state, leaf.name, thrown);
3571
+ }
3572
+ if (error) {
3573
+ if (state.pagination && leaf.resolver?.type === "dynamic") {
3574
+ return renderPageAt(state, leaf, path, state.pagination.position, {
3575
+ error
3576
+ });
3308
3577
  }
3578
+ return askLeaf(state, path, leaf, { error });
3309
3579
  }
3310
- setAtPath(
3311
- state.resolved,
3312
- path,
3313
- leaf ? coerce(leaf, action.value) : action.value
3314
- );
3580
+ setAtPath(state.resolved, path, coerce(leaf, action.value));
3315
3581
  break;
3316
3582
  }
3317
3583
  case "skip":
3318
3584
  settle(state, path);
3319
3585
  break;
3320
3586
  default:
3321
- throw new Error(`action "${action.type}" is not supported here`);
3587
+ throw new Error(
3588
+ `action "${action.type}" is not supported here`
3589
+ );
3322
3590
  }
3323
3591
  delete state.current;
3324
3592
  delete state.pagination;
3325
3593
  return advance(ctx, state);
3326
3594
  }
3327
- async function refine(ctx, state, leaf, path, action) {
3328
- const position = positionAfter(state.pagination, action);
3595
+ async function renderPageAt(state, leaf, path, position, opts = {}) {
3329
3596
  try {
3330
- if (action.type === "search") {
3331
- const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
3332
- input: mergeInput(state.resolved, leaf.extraInput),
3333
- search: action.term
3334
- }) : void 0;
3335
- if (exact) {
3336
- setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
3337
- delete state.current;
3338
- delete state.pagination;
3339
- return advance(ctx, state);
3340
- }
3341
- }
3342
3597
  const context = await resolveContext(leaf, state.resolved);
3343
3598
  const page = await fetchListing(leaf, state.resolved, position, context);
3344
3599
  state.pagination = toPagination(page);
@@ -3346,7 +3601,8 @@ async function refine(ctx, state, leaf, path, action) {
3346
3601
  state,
3347
3602
  result: {
3348
3603
  status: "ask",
3349
- question: selectQuestion(leaf, path, state.resolved, page, context)
3604
+ question: selectQuestion(leaf, path, state.resolved, page, context),
3605
+ ...opts.error ? { error: opts.error } : {}
3350
3606
  }
3351
3607
  };
3352
3608
  } catch (error) {
@@ -3354,6 +3610,65 @@ async function refine(ctx, state, leaf, path, action) {
3354
3610
  return failedResult(state, leaf.name, error);
3355
3611
  }
3356
3612
  }
3613
+ async function refine(ctx, state, leaf, path, action) {
3614
+ const position = positionAfter(state.pagination, action);
3615
+ if (action.type === "search") {
3616
+ try {
3617
+ const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
3618
+ input: mergeInput(state.resolved, leaf.extraInput),
3619
+ search: action.term
3620
+ }) : void 0;
3621
+ if (exact) {
3622
+ setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
3623
+ delete state.current;
3624
+ delete state.pagination;
3625
+ return advance(ctx, state);
3626
+ }
3627
+ } catch (error) {
3628
+ state.pagination = failedPagination(state.pagination, position);
3629
+ return failedResult(state, leaf.name, error);
3630
+ }
3631
+ }
3632
+ return renderPageAt(state, leaf, path, position);
3633
+ }
3634
+ async function stepRecordKey(ctx, state, action) {
3635
+ const path = state.current;
3636
+ if (!path)
3637
+ throw new Error("record key step called with no outstanding question");
3638
+ const { keyLeaf, valueLeaf } = await recordInfoAt(ctx, path, state.resolved);
3639
+ if (action.type === "skip") {
3640
+ delete state.gate;
3641
+ delete state.current;
3642
+ delete state.pagination;
3643
+ return advance(ctx, state);
3644
+ }
3645
+ if (action.type !== "custom" && action.type !== "choose") {
3646
+ throw new Error(
3647
+ `action "${action.type}" is not supported while entering a record key`
3648
+ );
3649
+ }
3650
+ const raw = Array.isArray(action.value) ? action.value[0] : action.value;
3651
+ const entryKey = String(coerce(keyLeaf, raw));
3652
+ if (entryKey.trim() === "") {
3653
+ return askRecordKey(state, path, keyLeaf, { error: "A key is required." });
3654
+ }
3655
+ if (UNSAFE_RECORD_KEYS.has(entryKey)) {
3656
+ return askRecordKey(state, path, keyLeaf, {
3657
+ error: `"${entryKey}" is not an allowed key.`
3658
+ });
3659
+ }
3660
+ const container = getAtPath(state.resolved, path);
3661
+ if (Object.prototype.hasOwnProperty.call(container, entryKey)) {
3662
+ return askRecordKey(state, path, keyLeaf, {
3663
+ error: `"${entryKey}" is already set.`
3664
+ });
3665
+ }
3666
+ const valuePath = [...path, entryKey];
3667
+ if (await autoResolveLeaf(state, valuePath, valueLeaf)) {
3668
+ return advance(ctx, state);
3669
+ }
3670
+ return askLeaf(state, valuePath, valueLeaf);
3671
+ }
3357
3672
  function failedPagination(pagination, retryPosition) {
3358
3673
  return {
3359
3674
  position: pagination?.position ?? firstPagePosition(),
@@ -3407,7 +3722,7 @@ function projectSummary(entry) {
3407
3722
  };
3408
3723
  }
3409
3724
  function projectMethod(entry) {
3410
- const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
3725
+ const inputProperties = toJsonSchema(canonicalInputSchema(entry.inputSchema))?.properties;
3411
3726
  const parameters = {};
3412
3727
  for (const spec of planParameters(entry).parameters) {
3413
3728
  const dynamic = spec.resolver?.type === "dynamic" ? spec.resolver : void 0;
@@ -3440,7 +3755,12 @@ function createController(sdk) {
3440
3755
  const entry = entryFor(method);
3441
3756
  return {
3442
3757
  method,
3443
- schema: entry.inputSchema,
3758
+ // A method that owns its input validation (`skipInputValidation`, e.g.
3759
+ // fetch) must not be re-validated by the controller's final `safeParse`;
3760
+ // drop the schema so `finalize` returns the resolved input untouched.
3761
+ // Planning still reads `entry.inputSchema` directly, so parameters are
3762
+ // unaffected.
3763
+ schema: entry.skipInputValidation ? void 0 : entry.inputSchema,
3444
3764
  parameters: planParameters(entry).parameters
3445
3765
  };
3446
3766
  }
@@ -3503,30 +3823,6 @@ function createCorePlugin(options) {
3503
3823
  }
3504
3824
  });
3505
3825
  }
3506
- function withPositional(schema) {
3507
- Object.assign(schema._zod.def, {
3508
- positionalMeta: { positional: true }
3509
- });
3510
- return schema;
3511
- }
3512
- function schemaHasPositionalMeta(schema) {
3513
- return "positionalMeta" in schema._zod.def;
3514
- }
3515
- function isPositional(schema) {
3516
- if (schemaHasPositionalMeta(schema) && schema._zod.def.positionalMeta?.positional) {
3517
- return true;
3518
- }
3519
- if (schema instanceof z.ZodOptional) {
3520
- return isPositional(schema._zod.def.innerType);
3521
- }
3522
- if (schema instanceof z.ZodDefault) {
3523
- return isPositional(schema._zod.def.innerType);
3524
- }
3525
- return false;
3526
- }
3527
- function openEnum(values, description) {
3528
- return z.union([z.enum(values), z.string()]).describe(description);
3529
- }
3530
3826
 
3531
3827
  // src/utils/logging.ts
3532
3828
  var { logDeprecation: logDeprecation2, resetDeprecationWarnings: resetDeprecationWarnings2 } = createDeprecationLogger("zapier-sdk");
@@ -3935,8 +4231,8 @@ function censorHeaders(headers) {
3935
4231
  if (!headers) return headers;
3936
4232
  const headersObj = new Headers(headers);
3937
4233
  const authKeys = ["authorization", "x-api-key"];
3938
- for (const [key2, value] of headersObj.entries()) {
3939
- if (authKeys.some((authKey) => key2.toLowerCase() === authKey)) {
4234
+ for (const [key, value] of headersObj.entries()) {
4235
+ if (authKeys.some((authKey) => key.toLowerCase() === authKey)) {
3940
4236
  const spaceIndex = value.indexOf(" ");
3941
4237
  if (spaceIndex > 0 && spaceIndex < value.length - 1) {
3942
4238
  const prefix = value.substring(0, spaceIndex + 1);
@@ -3944,19 +4240,19 @@ function censorHeaders(headers) {
3944
4240
  if (token.length > 12) {
3945
4241
  const start2 = token.substring(0, 4);
3946
4242
  const end = token.substring(token.length - 4);
3947
- headersObj.set(key2, `${prefix}${start2}...${end}`);
4243
+ headersObj.set(key, `${prefix}${start2}...${end}`);
3948
4244
  } else {
3949
4245
  const firstChar = token.charAt(0);
3950
- headersObj.set(key2, `${prefix}${firstChar}...`);
4246
+ headersObj.set(key, `${prefix}${firstChar}...`);
3951
4247
  }
3952
4248
  } else {
3953
4249
  if (value.length > 12) {
3954
4250
  const start2 = value.substring(0, 4);
3955
4251
  const end = value.substring(value.length - 4);
3956
- headersObj.set(key2, `${start2}...${end}`);
4252
+ headersObj.set(key, `${start2}...${end}`);
3957
4253
  } else {
3958
4254
  const firstChar = value.charAt(0);
3959
- headersObj.set(key2, `${firstChar}...`);
4255
+ headersObj.set(key, `${firstChar}...`);
3960
4256
  }
3961
4257
  }
3962
4258
  }
@@ -4604,21 +4900,21 @@ function getClientIdFromCredentials(credentials) {
4604
4900
  function createMemoryCache() {
4605
4901
  const store = /* @__PURE__ */ new Map();
4606
4902
  return {
4607
- async get(key2) {
4608
- const entry = store.get(key2);
4903
+ async get(key) {
4904
+ const entry = store.get(key);
4609
4905
  if (!entry) return void 0;
4610
4906
  if (entry.expiresAt !== void 0 && entry.expiresAt <= Date.now()) {
4611
- store.delete(key2);
4907
+ store.delete(key);
4612
4908
  return void 0;
4613
4909
  }
4614
4910
  return { value: entry.value, expiresAt: entry.expiresAt };
4615
4911
  },
4616
- async set(key2, value, options) {
4912
+ async set(key, value, options) {
4617
4913
  const expiresAt = options?.ttl ? Date.now() + options.ttl * 1e3 : void 0;
4618
- store.set(key2, { value, expiresAt });
4914
+ store.set(key, { value, expiresAt });
4619
4915
  },
4620
- async delete(key2) {
4621
- store.delete(key2);
4916
+ async delete(key) {
4917
+ store.delete(key);
4622
4918
  }
4623
4919
  };
4624
4920
  }
@@ -5281,7 +5577,7 @@ function parseDeprecationDate(value) {
5281
5577
  }
5282
5578
 
5283
5579
  // src/sdk-version.ts
5284
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.4" : void 0) || "unknown";
5580
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.86.0" : void 0) || "unknown";
5285
5581
 
5286
5582
  // src/utils/open-url.ts
5287
5583
  var nodePrefix = "node:";
@@ -5539,11 +5835,11 @@ var ZapierApiClient = class {
5539
5835
  );
5540
5836
  const inputHeaders = new Headers(init?.headers ?? {});
5541
5837
  const mergedHeaders = new Headers();
5542
- builtHeaders.forEach((value, key2) => {
5543
- mergedHeaders.set(key2, value);
5838
+ builtHeaders.forEach((value, key) => {
5839
+ mergedHeaders.set(key, value);
5544
5840
  });
5545
- inputHeaders.forEach((value, key2) => {
5546
- mergedHeaders.set(key2, value);
5841
+ inputHeaders.forEach((value, key) => {
5842
+ mergedHeaders.set(key, value);
5547
5843
  });
5548
5844
  this.applyTelemetryHeaders(mergedHeaders);
5549
5845
  let retries = 0;
@@ -6068,8 +6364,8 @@ var ZapierApiClient = class {
6068
6364
  canSendDeprecationMessaging
6069
6365
  } = this.applyPathConfiguration(path);
6070
6366
  if (searchParams) {
6071
- Object.entries(searchParams).forEach(([key2, value]) => {
6072
- url.searchParams.set(key2, value);
6367
+ Object.entries(searchParams).forEach(([key, value]) => {
6368
+ url.searchParams.set(key, value);
6073
6369
  });
6074
6370
  }
6075
6371
  return {
@@ -7126,13 +7422,13 @@ function parseManifestSection({
7126
7422
  return void 0;
7127
7423
  }
7128
7424
  const kept = {};
7129
- for (const [key2, value] of Object.entries(raw)) {
7425
+ for (const [key, value] of Object.entries(raw)) {
7130
7426
  const result = schema.safeParse(value);
7131
7427
  if (result.success) {
7132
- kept[key2] = result.data;
7428
+ kept[key] = result.data;
7133
7429
  } else {
7134
7430
  console.warn(
7135
- `\u26A0\uFE0F Dropping invalid "${section}" entry "${key2}" in ${source}: ${result.error}`
7431
+ `\u26A0\uFE0F Dropping invalid "${section}" entry "${key}" in ${source}: ${result.error}`
7136
7432
  );
7137
7433
  }
7138
7434
  }
@@ -7281,9 +7577,9 @@ function findManifestEntry({
7281
7577
  return [slug, manifest.apps[slug]];
7282
7578
  }
7283
7579
  }
7284
- for (const [key2, entry] of Object.entries(manifest.apps)) {
7580
+ for (const [key, entry] of Object.entries(manifest.apps)) {
7285
7581
  if (entry.implementationName === appKeyWithoutVersion) {
7286
- return [key2, entry];
7582
+ return [key, entry];
7287
7583
  }
7288
7584
  }
7289
7585
  return null;
@@ -7537,8 +7833,8 @@ function normalizeHeaders(optionsHeaders) {
7537
7833
  return headers;
7538
7834
  }
7539
7835
  const headerEntries = optionsHeaders instanceof Headers ? Array.from(optionsHeaders.entries()) : Array.isArray(optionsHeaders) ? optionsHeaders : Object.entries(optionsHeaders);
7540
- for (const [key2, value] of headerEntries) {
7541
- headers[key2] = value;
7836
+ for (const [key, value] of headerEntries) {
7837
+ headers[key] = value;
7542
7838
  }
7543
7839
  return headers;
7544
7840
  }
@@ -7609,14 +7905,9 @@ var fetchPlugin = defineMethod({
7609
7905
  // of order.
7610
7906
  categories: [{ key: "http", title: "HTTP Request" }],
7611
7907
  returnType: "Response",
7612
- // The controller / MCP project fetch's parameters from `inputSchema` +
7613
- // `positional`. The CLI command layer instead flattens `init`'s fields into
7614
- // individual flags (--method, --connection, ...) from `inputParameters`; it is
7615
- // the only surface that reads this. Both describe the same (url, init) shape.
7616
- inputParameters: [
7617
- { name: "url", schema: FetchUrlSchema },
7618
- { name: "init", schema: FetchInitSchema }
7619
- ],
7908
+ // The CLI, controller, and MCP all derive fetch's `(url, init)` shape from
7909
+ // `inputSchema` + `positional`; the CLI flattens `init`'s fields into
7910
+ // individual flags (--method, --connection, ...) off that same schema.
7620
7911
  // Build the validator once, binding it to the head's `adaptError` so failures
7621
7912
  // surface as `ZapierValidationError` rather than the neutral kitcore fallback.
7622
7913
  setup: ({ imports }) => {
@@ -7755,9 +8046,9 @@ var RunActionInputSchema = z.union([RunActionSchema, RunActionSchemaDeprecated])
7755
8046
  var ActionResultItemSchema = z.unknown().describe("Action execution result");
7756
8047
 
7757
8048
  // src/formatters/actionResult.ts
7758
- function getStringProperty(obj, key2) {
7759
- if (typeof obj === "object" && obj !== null && key2 in obj) {
7760
- const value = obj[key2];
8049
+ function getStringProperty(obj, key) {
8050
+ if (typeof obj === "object" && obj !== null && key in obj) {
8051
+ const value = obj[key];
7761
8052
  return typeof value === "string" ? value : void 0;
7762
8053
  }
7763
8054
  return void 0;
@@ -8243,21 +8534,21 @@ var actionKeyResolver = defineResolver({
8243
8534
  });
8244
8535
 
8245
8536
  // src/plugins/capabilities/index.ts
8246
- function toDescription(key2) {
8247
- const words = key2.replace(/^can/, "").replace(/([A-Z])/g, " $1").trim().toLowerCase();
8537
+ function toDescription(key) {
8538
+ const words = key.replace(/^can/, "").replace(/([A-Z])/g, " $1").trim().toLowerCase();
8248
8539
  return `To ${words}`;
8249
8540
  }
8250
- function toEnvVar(key2) {
8251
- return "ZAPIER_" + key2.replace(/([A-Z])/g, "_$1").toUpperCase();
8541
+ function toEnvVar(key) {
8542
+ return "ZAPIER_" + key.replace(/([A-Z])/g, "_$1").toUpperCase();
8252
8543
  }
8253
- function toCliFlag(key2) {
8254
- return "--" + key2.replace(/([A-Z])/g, "-$1").toLowerCase();
8544
+ function toCliFlag(key) {
8545
+ return "--" + key.replace(/([A-Z])/g, "-$1").toLowerCase();
8255
8546
  }
8256
- function buildCapabilityMessage(key2) {
8547
+ function buildCapabilityMessage(key) {
8257
8548
  return [
8258
- `${toDescription(key2)}, use ${toCliFlag(key2)} in the CLI,`,
8259
- `set ${key2}: true in SDK options or .zapierrc,`,
8260
- `or set ${toEnvVar(key2)}=true.`
8549
+ `${toDescription(key)}, use ${toCliFlag(key)} in the CLI,`,
8550
+ `set ${key}: true in SDK options or .zapierrc,`,
8551
+ `or set ${toEnvVar(key)}=true.`
8261
8552
  ].join(" ");
8262
8553
  }
8263
8554
  var GATED_FLAGS = [
@@ -8265,8 +8556,8 @@ var GATED_FLAGS = [
8265
8556
  "canIncludeSharedTables",
8266
8557
  "canDeleteTables"
8267
8558
  ];
8268
- function isEnabledByEnv(key2) {
8269
- const value = globalThis.process?.env?.[toEnvVar(key2)];
8559
+ function isEnabledByEnv(key) {
8560
+ const value = globalThis.process?.env?.[toEnvVar(key)];
8270
8561
  if (value === void 0) return void 0;
8271
8562
  if (value === "true" || value === "1") return true;
8272
8563
  if (value === "false" || value === "0") return false;
@@ -8293,17 +8584,17 @@ var capabilitiesPlugin = defineProperty({
8293
8584
  return cached;
8294
8585
  }
8295
8586
  return {
8296
- checkCapability: async (key2) => {
8587
+ checkCapability: async (key) => {
8297
8588
  const flags = await resolveFlags();
8298
- if (flags[key2]) return;
8589
+ if (flags[key]) return;
8299
8590
  throw new ZapierConfigurationError(
8300
- buildCapabilityMessage(key2) + " (If you are an AI agent, you MUST NOT retry. Ask the user if they want to enable this.)",
8301
- { configType: key2 }
8591
+ buildCapabilityMessage(key) + " (If you are an AI agent, you MUST NOT retry. Ask the user if they want to enable this.)",
8592
+ { configType: key }
8302
8593
  );
8303
8594
  },
8304
- hasCapability: async (key2) => {
8595
+ hasCapability: async (key) => {
8305
8596
  const flags = await resolveFlags();
8306
- return flags[key2];
8597
+ return flags[key];
8307
8598
  }
8308
8599
  };
8309
8600
  },
@@ -8588,13 +8879,13 @@ var tableIdResolver = defineResolver({
8588
8879
  listItems: ({ imports, context, cursor }) => {
8589
8880
  const includeShared = context?.includeShared;
8590
8881
  if (includeShared) {
8591
- return concatPaginated({
8882
+ return concatLists({
8592
8883
  sources: [
8593
- ({ cursor: sourceCursor }) => imports.listTablesInternal({ cursor: sourceCursor }),
8594
- ({ cursor: sourceCursor }) => imports.listTablesInternal({
8884
+ ({ cursor: listCursor }) => imports.listTablesInternal({ cursor: listCursor }),
8885
+ ({ cursor: listCursor }) => imports.listTablesInternal({
8595
8886
  includeShared: true,
8596
8887
  includePersonal: false,
8597
- cursor: sourceCursor
8888
+ cursor: listCursor
8598
8889
  })
8599
8890
  ],
8600
8891
  cursor
@@ -8800,7 +9091,7 @@ function formatRecordError(fieldId, err) {
8800
9091
  function formatResponseError(err) {
8801
9092
  const message = err.human_title || err.title || "Unknown error";
8802
9093
  if (err.meta && Object.keys(err.meta).length > 0) {
8803
- const metaParts = Object.entries(err.meta).map(([key2, val]) => `${key2}: ${JSON.stringify(val)}`).join(", ");
9094
+ const metaParts = Object.entries(err.meta).map(([key, val]) => `${key}: ${JSON.stringify(val)}`).join(", ");
8804
9095
  return `${message} (${metaParts})`;
8805
9096
  }
8806
9097
  return message;
@@ -8835,8 +9126,8 @@ var TrashSchema = z.enum(["exclude", "include", "only"]).optional().describe(
8835
9126
  'Control soft-deleted item visibility. "exclude" (default) returns active items only, "include" returns both active and soft-deleted, "only" returns soft-deleted items only.'
8836
9127
  );
8837
9128
  var FIELD_ID_PATTERN = /^f\d+$/;
8838
- function isFieldId(key2) {
8839
- return FIELD_ID_PATTERN.test(key2);
9129
+ function isFieldId(key) {
9130
+ return FIELD_ID_PATTERN.test(key);
8840
9131
  }
8841
9132
  var NESTED_COMPONENTS = {
8842
9133
  labeled_string: /* @__PURE__ */ new Set(["value"]),
@@ -8874,7 +9165,7 @@ async function resolveFieldKeys({
8874
9165
  fieldKeys
8875
9166
  }) {
8876
9167
  const allAreIds = fieldKeys.every(
8877
- (key2) => typeof key2 === "number" || /^(f?\d+)$/.test(key2)
9168
+ (key) => typeof key === "number" || /^(f?\d+)$/.test(key)
8878
9169
  );
8879
9170
  if (allAreIds) {
8880
9171
  return fieldKeys.map(toNumericFieldId);
@@ -8883,13 +9174,13 @@ async function resolveFieldKeys({
8883
9174
  if (!mapping) {
8884
9175
  return fieldKeys.map(toNumericFieldId);
8885
9176
  }
8886
- return fieldKeys.map((key2) => {
8887
- if (typeof key2 === "number") return key2;
8888
- if (FIELD_ID_PATTERN.test(key2)) return toNumericFieldId(key2);
8889
- const id = mapping.nameToId.get(key2);
9177
+ return fieldKeys.map((key) => {
9178
+ if (typeof key === "number") return key;
9179
+ if (FIELD_ID_PATTERN.test(key)) return toNumericFieldId(key);
9180
+ const id = mapping.nameToId.get(key);
8890
9181
  if (!id) {
8891
9182
  throw new ZapierValidationError(
8892
- `Unknown field name: "${key2}". Use a valid field name or ID.`
9183
+ `Unknown field name: "${key}". Use a valid field name or ID.`
8893
9184
  );
8894
9185
  }
8895
9186
  return toNumericFieldId(id);
@@ -8905,13 +9196,13 @@ async function createFieldKeyTranslator({
8905
9196
  translateInput(data) {
8906
9197
  if (!mapping) return data;
8907
9198
  const result = {};
8908
- for (const [key2, value] of Object.entries(data)) {
8909
- if (FIELD_ID_PATTERN.test(key2) && mapping.idToName.has(key2)) {
8910
- result[key2] = value;
8911
- } else if (mapping.nameToId.has(key2)) {
8912
- result[mapping.nameToId.get(key2)] = value;
9199
+ for (const [key, value] of Object.entries(data)) {
9200
+ if (FIELD_ID_PATTERN.test(key) && mapping.idToName.has(key)) {
9201
+ result[key] = value;
9202
+ } else if (mapping.nameToId.has(key)) {
9203
+ result[mapping.nameToId.get(key)] = value;
8913
9204
  } else {
8914
- result[key2] = value;
9205
+ result[key] = value;
8915
9206
  }
8916
9207
  }
8917
9208
  return result;
@@ -8919,29 +9210,29 @@ async function createFieldKeyTranslator({
8919
9210
  translateOutput(data) {
8920
9211
  if (!mapping) return data;
8921
9212
  const result = {};
8922
- for (const [key2, value] of Object.entries(data)) {
8923
- if (mapping.idToName.has(key2)) {
8924
- result[mapping.idToName.get(key2)] = value;
9213
+ for (const [key, value] of Object.entries(data)) {
9214
+ if (mapping.idToName.has(key)) {
9215
+ result[mapping.idToName.get(key)] = value;
8925
9216
  } else {
8926
- result[key2] = value;
9217
+ result[key] = value;
8927
9218
  }
8928
9219
  }
8929
9220
  return result;
8930
9221
  },
8931
- translateFieldKey(key2) {
8932
- if (!mapping) return key2;
8933
- if (FIELD_ID_PATTERN.test(key2) && mapping.idToName.has(key2)) {
8934
- const fieldType = mapping.idToType.get(key2);
9222
+ translateFieldKey(key) {
9223
+ if (!mapping) return key;
9224
+ if (FIELD_ID_PATTERN.test(key) && mapping.idToName.has(key)) {
9225
+ const fieldType = mapping.idToType.get(key);
8935
9226
  if (fieldType) {
8936
9227
  const components = NESTED_COMPONENTS[fieldType];
8937
9228
  if (components?.size === 1) {
8938
- return `${key2}__${[...components][0]}`;
9229
+ return `${key}__${[...components][0]}`;
8939
9230
  }
8940
9231
  }
8941
- return key2;
9232
+ return key;
8942
9233
  }
8943
- if (mapping.nameToId.has(key2)) {
8944
- const fieldId = mapping.nameToId.get(key2);
9234
+ if (mapping.nameToId.has(key)) {
9235
+ const fieldId = mapping.nameToId.get(key);
8945
9236
  const fieldType = mapping.idToType.get(fieldId);
8946
9237
  if (fieldType) {
8947
9238
  const components = NESTED_COMPONENTS[fieldType];
@@ -8951,10 +9242,10 @@ async function createFieldKeyTranslator({
8951
9242
  }
8952
9243
  return fieldId;
8953
9244
  }
8954
- const sepIndex = key2.lastIndexOf("__");
9245
+ const sepIndex = key.lastIndexOf("__");
8955
9246
  if (sepIndex > 0) {
8956
- const prefix = key2.slice(0, sepIndex);
8957
- const component = key2.slice(sepIndex + 2);
9247
+ const prefix = key.slice(0, sepIndex);
9248
+ const component = key.slice(sepIndex + 2);
8958
9249
  let fieldId;
8959
9250
  if (FIELD_ID_PATTERN.test(prefix) && mapping.idToName.has(prefix)) {
8960
9251
  fieldId = prefix;
@@ -8968,7 +9259,7 @@ async function createFieldKeyTranslator({
8968
9259
  }
8969
9260
  }
8970
9261
  }
8971
- return key2;
9262
+ return key;
8972
9263
  }
8973
9264
  };
8974
9265
  }
@@ -9564,13 +9855,13 @@ var runActionPlugin = defineMethod({
9564
9855
  let oldestKey;
9565
9856
  let oldestExpiry = Infinity;
9566
9857
  let evictedAny = false;
9567
- for (const [key2, entry] of cache) {
9858
+ for (const [key, entry] of cache) {
9568
9859
  if (now >= entry.expiresAt) {
9569
- cache.delete(key2);
9860
+ cache.delete(key);
9570
9861
  evictedAny = true;
9571
9862
  } else if (entry.expiresAt < oldestExpiry) {
9572
9863
  oldestExpiry = entry.expiresAt;
9573
- oldestKey = key2;
9864
+ oldestKey = key;
9574
9865
  }
9575
9866
  }
9576
9867
  if (!evictedAny && oldestKey) cache.delete(oldestKey);
@@ -9928,7 +10219,7 @@ var listAppsPlugin = defineMethod({
9928
10219
  locator
9929
10220
  ];
9930
10221
  }
9931
- const duplicatedLookupAppKeys = Object.keys(implementationNameToLocator).filter((key2) => implementationNameToLocator[key2].length > 1).map((key2) => implementationNameToLocator[key2]).flat().map((locator) => locator.lookupAppKey);
10222
+ const duplicatedLookupAppKeys = Object.keys(implementationNameToLocator).filter((key) => implementationNameToLocator[key].length > 1).map((key) => implementationNameToLocator[key]).flat().map((locator) => locator.lookupAppKey);
9932
10223
  if (duplicatedLookupAppKeys.length > 0) {
9933
10224
  throw new Error(
9934
10225
  `Duplicate lookup app keys found: ${duplicatedLookupAppKeys.join(", ")}`
@@ -10880,8 +11171,8 @@ function formatRootField(item) {
10880
11171
  }
10881
11172
  var rootFieldItemFormatter = defineFormatter({
10882
11173
  format: ({ item }) => {
10883
- const { key: key2, ...rest } = formatRootField(item);
10884
- return { ...rest, hint: key2 };
11174
+ const { key, ...rest } = formatRootField(item);
11175
+ return { ...rest, hint: key };
10885
11176
  }
10886
11177
  });
10887
11178
 
@@ -11622,7 +11913,7 @@ var createTriggerInboxPlugin = defineMethod({
11622
11913
  inputs = {},
11623
11914
  notificationUrl
11624
11915
  } = input;
11625
- const key2 = input.key ?? input.name;
11916
+ const key = input.key ?? input.name;
11626
11917
  const resolvedConnectionId = await resolveConnectionId({
11627
11918
  connection,
11628
11919
  resolveConnection
@@ -11642,8 +11933,8 @@ var createTriggerInboxPlugin = defineMethod({
11642
11933
  connection_id: resolvedConnectionId ?? null
11643
11934
  }
11644
11935
  };
11645
- if (key2 !== void 0) {
11646
- requestBody.key = key2;
11936
+ if (key !== void 0) {
11937
+ requestBody.key = key;
11647
11938
  }
11648
11939
  if (notificationUrl !== void 0) {
11649
11940
  requestBody.notification_url = notificationUrl;
@@ -11657,7 +11948,7 @@ var createTriggerInboxPlugin = defineMethod({
11657
11948
  if (status === 409) {
11658
11949
  const detail = extractErrorDetail(data);
11659
11950
  return new ZapierConflictError(
11660
- detail ?? `An inbox with key "${key2}" already exists with a different subscription.`,
11951
+ detail ?? `An inbox with key "${key}" already exists with a different subscription.`,
11661
11952
  { statusCode: status, resourceType: "trigger_inbox" }
11662
11953
  );
11663
11954
  }
@@ -11725,7 +12016,7 @@ var ensureTriggerInboxPlugin = defineMethod({
11725
12016
  inputs = {},
11726
12017
  notificationUrl
11727
12018
  } = input;
11728
- const key2 = "key" in input ? input.key : input.name;
12019
+ const key = "key" in input ? input.key : input.name;
11729
12020
  const resolvedConnectionId = await resolveConnectionId({
11730
12021
  connection,
11731
12022
  resolveConnection
@@ -11738,7 +12029,7 @@ var ensureTriggerInboxPlugin = defineMethod({
11738
12029
  );
11739
12030
  }
11740
12031
  const requestBody = {
11741
- key: key2,
12032
+ key,
11742
12033
  subscription: {
11743
12034
  app_key: selectedApi,
11744
12035
  action_key: actionKey,
@@ -11758,7 +12049,7 @@ var ensureTriggerInboxPlugin = defineMethod({
11758
12049
  if (status === 409) {
11759
12050
  const detail = extractErrorDetail(data);
11760
12051
  return new ZapierConflictError(
11761
- detail ?? `An inbox with key "${key2}" already exists with a different subscription.`,
12052
+ detail ?? `An inbox with key "${key}" already exists with a different subscription.`,
11762
12053
  { statusCode: status, resourceType: "trigger_inbox" }
11763
12054
  );
11764
12055
  }
@@ -12405,9 +12696,9 @@ function createWaiter() {
12405
12696
  }
12406
12697
  };
12407
12698
  }
12408
- function addToMap(m, key2, value) {
12409
- const existing = m.get(key2) ?? [];
12410
- m.set(key2, [...existing, value]);
12699
+ function addToMap(m, key, value) {
12700
+ const existing = m.get(key) ?? [];
12701
+ m.set(key, [...existing, value]);
12411
12702
  }
12412
12703
  async function runBatchedDrainPipeline(options) {
12413
12704
  const {
@@ -14166,8 +14457,8 @@ function getOsInfo() {
14166
14457
  function getPlatformVersions() {
14167
14458
  const versions = {};
14168
14459
  if (typeof globalThis.process?.versions === "object") {
14169
- for (const [key2, value] of Object.entries(globalThis.process.versions)) {
14170
- versions[key2] = value || null;
14460
+ for (const [key, value] of Object.entries(globalThis.process.versions)) {
14461
+ versions[key] = value || null;
14171
14462
  }
14172
14463
  }
14173
14464
  return versions;
@@ -14421,9 +14712,9 @@ async function emitWithTimeout(transport, subject, event) {
14421
14712
  }
14422
14713
  function mergeUserContext(event, userContext) {
14423
14714
  const merged = { ...event };
14424
- for (const [key2, value] of Object.entries(userContext)) {
14425
- if (merged[key2] == null) {
14426
- merged[key2] = value;
14715
+ for (const [key, value] of Object.entries(userContext)) {
14716
+ if (merged[key] == null) {
14717
+ merged[key] = value;
14427
14718
  }
14428
14719
  }
14429
14720
  return merged;
@@ -14902,14 +15193,14 @@ function toWireConnections(connections) {
14902
15193
  }
14903
15194
  function toWireAppVersions(appVersions) {
14904
15195
  const wire = {};
14905
- for (const [key2, entry] of Object.entries(appVersions)) {
15196
+ for (const [key, entry] of Object.entries(appVersions)) {
14906
15197
  const implementationName = entry.implementationName ?? entry.implementation_name;
14907
15198
  if (implementationName === void 0) {
14908
15199
  throw new ZapierValidationError(
14909
- `appVersions["${key2}"] is missing implementationName`
15200
+ `appVersions["${key}"] is missing implementationName`
14910
15201
  );
14911
15202
  }
14912
- wire[key2] = {
15203
+ wire[key] = {
14913
15204
  implementation_name: implementationName,
14914
15205
  ...entry.version !== void 0 ? { version: entry.version } : {}
14915
15206
  };
@@ -15582,6 +15873,26 @@ var RunDurableResponseSchema = z.object({
15582
15873
  created_at: z.string().describe("When the run was created (ISO-8601)")
15583
15874
  });
15584
15875
 
15876
+ // src/resolvers/sourceFiles.ts
15877
+ var sourceFilesResolver = defineResolver({
15878
+ type: "object",
15879
+ additionalKeys: {
15880
+ minEntries: 1,
15881
+ keys: defineResolver({
15882
+ type: "static",
15883
+ inputType: "text",
15884
+ placeholder: "filename (e.g. index.ts)"
15885
+ }),
15886
+ values: defineResolver({
15887
+ type: "static",
15888
+ inputType: "text",
15889
+ placeholder: "file contents"
15890
+ }),
15891
+ keyValueType: "string",
15892
+ valueValueType: "string"
15893
+ }
15894
+ });
15895
+
15585
15896
  // src/plugins/codeSubstrate/runDurable/index.ts
15586
15897
  var runDurablePlugin = defineMethod({
15587
15898
  ...codeSubstrateDefaults,
@@ -15592,6 +15903,7 @@ var runDurablePlugin = defineMethod({
15592
15903
  inputSchema: RunDurableOptionsSchema,
15593
15904
  outputSchema: RunDurableResponseSchema,
15594
15905
  output: "item",
15906
+ resolvers: { sourceFiles: sourceFilesResolver },
15595
15907
  run: async ({ imports, input }) => {
15596
15908
  const api = imports.api;
15597
15909
  const sourceFiles = "sourceFiles" in input ? input.sourceFiles : input.source_files;
@@ -15762,7 +16074,7 @@ var publishWorkflowVersionPlugin = defineMethod({
15762
16074
  inputSchema: PublishWorkflowVersionOptionsSchema,
15763
16075
  outputSchema: PublishWorkflowVersionResponseSchema,
15764
16076
  output: "item",
15765
- resolvers: { workflow: workflowIdResolver },
16077
+ resolvers: { workflow: workflowIdResolver, sourceFiles: sourceFilesResolver },
15766
16078
  run: async ({ imports, input }) => {
15767
16079
  const api = imports.api;
15768
16080
  const sourceFiles = "sourceFiles" in input ? input.sourceFiles : input.source_files;