@zapier/zapier-sdk 0.78.0 → 0.80.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/dist/index.cjs CHANGED
@@ -53,18 +53,20 @@ function buildRegistry({
53
53
  sdk,
54
54
  meta,
55
55
  formatters,
56
+ boundResolvers,
57
+ positional,
56
58
  packageFilter
57
59
  }) {
58
60
  const definitionsByKey = /* @__PURE__ */ new Map();
59
61
  const objectDeclaredKeys = /* @__PURE__ */ new Set();
60
62
  for (const m of Object.values(meta)) {
61
63
  for (const ref of m.categories ?? []) {
62
- const key = typeof ref === "string" ? ref : ref.key;
64
+ const key2 = typeof ref === "string" ? ref : ref.key;
63
65
  if (typeof ref === "object") {
64
- objectDeclaredKeys.add(key);
65
- definitionsByKey.set(key, resolveCategoryDefinition(ref));
66
- } else if (!objectDeclaredKeys.has(key)) {
67
- definitionsByKey.set(key, resolveCategoryDefinition(ref));
66
+ objectDeclaredKeys.add(key2);
67
+ definitionsByKey.set(key2, resolveCategoryDefinition(ref));
68
+ } else if (!objectDeclaredKeys.has(key2)) {
69
+ definitionsByKey.set(key2, resolveCategoryDefinition(ref));
68
70
  }
69
71
  }
70
72
  }
@@ -72,16 +74,16 @@ function buildRegistry({
72
74
  definitionsByKey.set("other", resolveCategoryDefinition("other"));
73
75
  }
74
76
  const knownCategories = Array.from(definitionsByKey.keys());
75
- const functions = Object.keys(meta).filter((key) => {
76
- const property = sdk[key];
77
+ const functions = Object.keys(meta).filter((key2) => {
78
+ const property = sdk[key2];
77
79
  if (typeof property === "function") return true;
78
- const [rootKey] = key.split(".");
80
+ const [rootKey] = key2.split(".");
79
81
  const rootProperty = sdk[rootKey];
80
82
  return typeof rootProperty === "object" && rootProperty !== null;
81
- }).map((key) => {
82
- const m = meta[key];
83
+ }).map((key2) => {
84
+ const m = meta[key2];
83
85
  return {
84
- name: key,
86
+ name: key2,
85
87
  description: m.description,
86
88
  type: m.type,
87
89
  itemType: m.itemType,
@@ -89,11 +91,13 @@ function buildRegistry({
89
91
  inputSchema: canonicalInputSchema(m.inputSchema),
90
92
  inputParameters: m.inputParameters,
91
93
  outputSchema: m.outputSchema,
94
+ positional: positional?.[key2],
92
95
  categories: (m.categories ?? []).map(
93
96
  (c) => typeof c === "string" ? c : c.key
94
97
  ),
95
98
  resolvers: m.resolvers,
96
- formatter: formatters?.[key],
99
+ boundResolvers: boundResolvers?.[key2],
100
+ formatter: formatters?.[key2],
97
101
  experimental: m.experimental,
98
102
  packages: m.packages,
99
103
  confirm: m.confirm ?? (m.type === "delete" ? "delete" : void 0),
@@ -131,8 +135,8 @@ function composeVoid(existing, added) {
131
135
  }
132
136
  function buildHooks(existing, added) {
133
137
  const result = {};
134
- const start = composeVoid(existing.onMethodStart, added.onMethodStart);
135
- if (start) result.onMethodStart = start;
138
+ const start2 = composeVoid(existing.onMethodStart, added.onMethodStart);
139
+ if (start2) result.onMethodStart = start2;
136
140
  const end = composeVoid(existing.onMethodEnd, added.onMethodEnd);
137
141
  if (end) result.onMethodEnd = end;
138
142
  return result;
@@ -765,11 +769,11 @@ var RESERVED_ROOT_KEYS = /* @__PURE__ */ new Set([
765
769
  "context",
766
770
  "getRegistry"
767
771
  ]);
768
- function hasOwn(obj, key) {
769
- return Object.prototype.hasOwnProperty.call(obj, key);
772
+ function hasOwn(obj, key2) {
773
+ return Object.prototype.hasOwnProperty.call(obj, key2);
770
774
  }
771
- function setOwn(target, key, value) {
772
- Object.defineProperty(target, key, {
775
+ function setOwn(target, key2, value) {
776
+ Object.defineProperty(target, key2, {
773
777
  value,
774
778
  enumerable: true,
775
779
  configurable: true,
@@ -781,31 +785,31 @@ function checkCollisions(target, source, kind, callerLabel, override) {
781
785
  checkRootKeyCollisions(target, Object.keys(source), override, callerLabel);
782
786
  return;
783
787
  }
784
- for (const key of Object.keys(source)) {
785
- if (!override && hasOwn(target, key)) {
788
+ for (const key2 of Object.keys(source)) {
789
+ if (!override && hasOwn(target, key2)) {
786
790
  throw new Error(
787
- `${callerLabel}: duplicate ${kind} "${key}". If the override is intentional, pass { override: true } in the options.`
791
+ `${callerLabel}: duplicate ${kind} "${key2}". If the override is intentional, pass { override: true } in the options.`
788
792
  );
789
793
  }
790
794
  }
791
795
  }
792
796
  function checkRootKeyCollisions(target, keys, override, callerLabel) {
793
- for (const key of keys) {
794
- if (RESERVED_ROOT_KEYS.has(key)) {
797
+ for (const key2 of keys) {
798
+ if (RESERVED_ROOT_KEYS.has(key2)) {
795
799
  throw new Error(
796
- `${callerLabel}: plugin attempted to register reserved root key "${key}". The SDK uses this key for its own accessor; rename the plugin's method.`
800
+ `${callerLabel}: plugin attempted to register reserved root key "${key2}". The SDK uses this key for its own accessor; rename the plugin's method.`
797
801
  );
798
802
  }
799
- if (!override && hasOwn(target, key)) {
803
+ if (!override && hasOwn(target, key2)) {
800
804
  throw new Error(
801
- `${callerLabel}: duplicate root key "${key}". If the override is intentional, pass { override: true } in the options.`
805
+ `${callerLabel}: duplicate root key "${key2}". If the override is intentional, pass { override: true } in the options.`
802
806
  );
803
807
  }
804
808
  }
805
809
  }
806
810
  function applyOwnProperties(target, source) {
807
- for (const key of Object.keys(source)) {
808
- setOwn(target, key, source[key]);
811
+ for (const key2 of Object.keys(source)) {
812
+ setOwn(target, key2, source[key2]);
809
813
  }
810
814
  }
811
815
  function createPluginAccumulator(initialProperties = {}, initialContext = {}) {
@@ -1053,8 +1057,8 @@ function normalizeImports(deps) {
1053
1057
  }
1054
1058
  function collectLeafMeta(config) {
1055
1059
  let meta;
1056
- for (const key of LEAF_META_KEYS) {
1057
- if (config[key] !== void 0) (meta ?? (meta = {}))[key] = config[key];
1060
+ for (const key2 of LEAF_META_KEYS) {
1061
+ if (config[key2] !== void 0) (meta ?? (meta = {}))[key2] = config[key2];
1058
1062
  }
1059
1063
  return meta;
1060
1064
  }
@@ -1077,12 +1081,66 @@ function defineMethod(config) {
1077
1081
  run: config.run
1078
1082
  };
1079
1083
  }
1084
+ function defineResolver(config) {
1085
+ const deps = normalizeImports(config.imports);
1086
+ const base = { imports: deps.plugins, importBindings: deps.bindings };
1087
+ const gates = {
1088
+ requireParameters: config.requireParameters
1089
+ };
1090
+ switch (config.type) {
1091
+ case "static":
1092
+ return {
1093
+ ...base,
1094
+ ...gates,
1095
+ type: "static",
1096
+ inputType: config.inputType,
1097
+ placeholder: config.placeholder
1098
+ };
1099
+ case "constant":
1100
+ return { ...base, ...gates, type: "constant", value: config.value };
1101
+ case "info":
1102
+ return { ...base, type: "info", text: config.text ?? "" };
1103
+ case "object":
1104
+ return {
1105
+ ...base,
1106
+ ...gates,
1107
+ type: "object",
1108
+ properties: config.properties,
1109
+ definitions: config.definitions,
1110
+ getProperties: config.getProperties
1111
+ };
1112
+ case "array":
1113
+ return {
1114
+ ...base,
1115
+ ...gates,
1116
+ type: "array",
1117
+ items: config.items,
1118
+ minItems: config.minItems,
1119
+ maxItems: config.maxItems,
1120
+ itemValueType: config.itemValueType,
1121
+ definitions: config.definitions
1122
+ };
1123
+ default:
1124
+ return {
1125
+ ...base,
1126
+ ...gates,
1127
+ type: "dynamic",
1128
+ inputType: config.inputType,
1129
+ placeholder: config.placeholder,
1130
+ getContext: config.getContext,
1131
+ listItems: config.listItems,
1132
+ prompt: config.prompt,
1133
+ tryResolveWithoutPrompt: config.tryResolveWithoutPrompt,
1134
+ tryResolveFromSearch: config.tryResolveFromSearch
1135
+ };
1136
+ }
1137
+ }
1080
1138
  function defineFormatter(config) {
1081
1139
  const deps = normalizeImports(config.imports);
1082
1140
  return {
1083
1141
  imports: deps.plugins,
1084
1142
  importBindings: deps.bindings,
1085
- fetchContext: config.fetchContext,
1143
+ getContext: config.getContext,
1086
1144
  format: config.format
1087
1145
  };
1088
1146
  }
@@ -1211,7 +1269,7 @@ function legacyGraphEntry(name, value, pluginMeta) {
1211
1269
  function adaptLegacyFormatter(legacy, sdk) {
1212
1270
  const legacyFetch = legacy.fetch;
1213
1271
  return {
1214
- fetchContext: legacyFetch ? async ({ items, input, context }) => {
1272
+ getContext: legacyFetch ? async ({ items, input, context }) => {
1215
1273
  let ctx = context;
1216
1274
  for (const item of items) {
1217
1275
  ctx = await legacyFetch(sdk, input, item, ctx);
@@ -1227,6 +1285,14 @@ function normalizeFormatter(entry, sdk) {
1227
1285
  const legacy = entry.meta?.formatter;
1228
1286
  return legacy ? adaptLegacyFormatter(legacy, sdk) : void 0;
1229
1287
  }
1288
+ function normalizeBoundResolvers(entry) {
1289
+ if (entry.pluginType !== "method") return void 0;
1290
+ return entry.resolvers;
1291
+ }
1292
+ function methodPositional(entry) {
1293
+ if (entry.pluginType !== "method") return void 0;
1294
+ return entry.positional;
1295
+ }
1230
1296
  function pluginEntryMeta(entry) {
1231
1297
  if (entry.pluginType === "method" && entry.meta) {
1232
1298
  return entry.inputSchema ? { ...entry.meta, inputSchema: entry.inputSchema } : entry.meta;
@@ -1247,11 +1313,24 @@ function buildSurfaceRegistry(context, packageFilter) {
1247
1313
  if (m) meta[binding] = m;
1248
1314
  }
1249
1315
  const formatters = {};
1316
+ const boundResolvers = {};
1317
+ const positional = {};
1250
1318
  for (const [binding, entry] of Object.entries(entries)) {
1251
1319
  const f = normalizeFormatter(entry, surface);
1252
1320
  if (f) formatters[binding] = f;
1253
- }
1254
- return buildRegistry({ sdk: surface, meta, formatters, packageFilter });
1321
+ const r = normalizeBoundResolvers(entry);
1322
+ if (r) boundResolvers[binding] = r;
1323
+ const p = methodPositional(entry);
1324
+ if (p) positional[binding] = p;
1325
+ }
1326
+ return buildRegistry({
1327
+ sdk: surface,
1328
+ meta,
1329
+ formatters,
1330
+ boundResolvers,
1331
+ positional,
1332
+ packageFilter
1333
+ });
1255
1334
  }
1256
1335
  var dangerousContextPlugin = {
1257
1336
  pluginType: "property",
@@ -1368,15 +1447,15 @@ function collectPlugins(root, materialized = /* @__PURE__ */ new Set()) {
1368
1447
  }
1369
1448
  return byId;
1370
1449
  }
1371
- function bindValue(target, key, entry) {
1450
+ function bindValue(target, key2, entry) {
1372
1451
  if (entry.pluginType === "property" && entry.getValue) {
1373
- Object.defineProperty(target, key, {
1452
+ Object.defineProperty(target, key2, {
1374
1453
  get: entry.getValue,
1375
1454
  enumerable: true,
1376
1455
  configurable: true
1377
1456
  });
1378
1457
  } else {
1379
- Object.defineProperty(target, key, {
1458
+ Object.defineProperty(target, key2, {
1380
1459
  value: entry.value,
1381
1460
  writable: true,
1382
1461
  enumerable: true,
@@ -1428,8 +1507,7 @@ function bindResolver(resolver, plugins) {
1428
1507
  case "static":
1429
1508
  return {
1430
1509
  type: "static",
1431
- requireParams: resolver.requireParams,
1432
- requireCapabilities: resolver.requireCapabilities,
1510
+ requireParameters: resolver.requireParameters,
1433
1511
  inputType: resolver.inputType,
1434
1512
  placeholder: resolver.placeholder
1435
1513
  };
@@ -1437,8 +1515,7 @@ function bindResolver(resolver, plugins) {
1437
1515
  return {
1438
1516
  type: "constant",
1439
1517
  value: resolver.value,
1440
- requireParams: resolver.requireParams,
1441
- requireCapabilities: resolver.requireCapabilities
1518
+ requireParameters: resolver.requireParameters
1442
1519
  };
1443
1520
  case "info":
1444
1521
  return { type: "info", text: resolver.text };
@@ -1446,24 +1523,24 @@ function bindResolver(resolver, plugins) {
1446
1523
  const imports = buildImports(plugins, resolver.importBindings);
1447
1524
  const bound = {
1448
1525
  type: "object",
1449
- requireParams: resolver.requireParams,
1450
- requireCapabilities: resolver.requireCapabilities
1526
+ requireParameters: resolver.requireParameters
1451
1527
  };
1452
1528
  if (resolver.properties)
1453
1529
  bound.properties = bindFields(resolver.properties, plugins);
1454
1530
  if (resolver.definitions)
1455
1531
  bound.definitions = bindDefinitions(resolver.definitions, plugins);
1456
- const { fetch: fetch2 } = resolver;
1457
- if (fetch2) bound.fetch = ({ params }) => fetch2({ imports, params });
1532
+ const { getProperties } = resolver;
1533
+ if (getProperties)
1534
+ bound.getProperties = ({ input }) => getProperties({ imports, input });
1458
1535
  return bound;
1459
1536
  }
1460
1537
  case "array": {
1461
1538
  const bound = {
1462
1539
  type: "array",
1463
- requireParams: resolver.requireParams,
1464
- requireCapabilities: resolver.requireCapabilities,
1540
+ requireParameters: resolver.requireParameters,
1465
1541
  minItems: resolver.minItems,
1466
1542
  maxItems: resolver.maxItems,
1543
+ itemValueType: resolver.itemValueType,
1467
1544
  items: isResolverRef(resolver.items) ? resolver.items : bindResolver(resolver.items, plugins)
1468
1545
  };
1469
1546
  if (resolver.definitions)
@@ -1474,17 +1551,26 @@ function bindResolver(resolver, plugins) {
1474
1551
  const imports = buildImports(plugins, resolver.importBindings);
1475
1552
  const bound = {
1476
1553
  type: "dynamic",
1477
- requireParams: resolver.requireParams,
1478
- requireCapabilities: resolver.requireCapabilities,
1554
+ requireParameters: resolver.requireParameters,
1479
1555
  inputType: resolver.inputType,
1480
1556
  placeholder: resolver.placeholder,
1481
1557
  prompt: resolver.prompt
1482
1558
  };
1483
- const { fetch: fetch2, tryResolveWithoutPrompt } = resolver;
1484
- if (fetch2)
1485
- bound.fetch = ({ params, search }) => fetch2({ imports, params, search });
1559
+ const {
1560
+ getContext: getContext2,
1561
+ listItems,
1562
+ tryResolveWithoutPrompt,
1563
+ tryResolveFromSearch
1564
+ } = resolver;
1565
+ if (getContext2)
1566
+ bound.getContext = ({ input }) => getContext2({ imports, input });
1567
+ if (listItems)
1568
+ bound.listItems = ({ input, context, search, cursor }) => listItems({ imports, input, context, search, cursor });
1486
1569
  if (tryResolveWithoutPrompt) {
1487
- bound.tryResolveWithoutPrompt = ({ params }) => tryResolveWithoutPrompt({ imports, params });
1570
+ bound.tryResolveWithoutPrompt = ({ input }) => tryResolveWithoutPrompt({ imports, input });
1571
+ }
1572
+ if (tryResolveFromSearch) {
1573
+ bound.tryResolveFromSearch = ({ input, search }) => tryResolveFromSearch({ imports, input, search });
1488
1574
  }
1489
1575
  return bound;
1490
1576
  }
@@ -1492,8 +1578,8 @@ function bindResolver(resolver, plugins) {
1492
1578
  }
1493
1579
  function bindFields(fields, plugins) {
1494
1580
  const out = {};
1495
- for (const [key, field] of Object.entries(fields)) {
1496
- out[key] = {
1581
+ for (const [key2, field] of Object.entries(fields)) {
1582
+ out[key2] = {
1497
1583
  ...field,
1498
1584
  resolver: isResolverRef(field.resolver) ? field.resolver : bindResolver(field.resolver, plugins)
1499
1585
  };
@@ -1502,17 +1588,17 @@ function bindFields(fields, plugins) {
1502
1588
  }
1503
1589
  function bindDefinitions(definitions, plugins) {
1504
1590
  const out = {};
1505
- for (const [key, def] of Object.entries(definitions)) {
1506
- out[key] = bindResolver(def, plugins);
1591
+ for (const [key2, def] of Object.entries(definitions)) {
1592
+ out[key2] = bindResolver(def, plugins);
1507
1593
  }
1508
1594
  return out;
1509
1595
  }
1510
1596
  function bindFormatter(formatter, plugins) {
1511
1597
  const imports = buildImports(plugins, formatter.importBindings);
1512
1598
  const bound = { format: formatter.format };
1513
- const { fetchContext } = formatter;
1514
- if (fetchContext)
1515
- bound.fetchContext = ({ items, input, context }) => fetchContext({ imports, items, input, context });
1599
+ const { getContext: getContext2 } = formatter;
1600
+ if (getContext2)
1601
+ bound.getContext = ({ items, input, context }) => getContext2({ imports, items, input, context });
1516
1602
  return bound;
1517
1603
  }
1518
1604
  function bindAttachments(descriptors, context) {
@@ -1560,6 +1646,7 @@ function runLegacyPass(descriptors, context) {
1560
1646
  const sdk = this ?? exports;
1561
1647
  const meta2 = {};
1562
1648
  const formatters = {};
1649
+ const boundResolvers = {};
1563
1650
  for (const [binding, id2] of Object.entries(context.surface)) {
1564
1651
  const entry = context.plugins[id2];
1565
1652
  if (!entry || entry.pluginType === "aggregate") continue;
@@ -1567,12 +1654,15 @@ function runLegacyPass(descriptors, context) {
1567
1654
  if (m) meta2[binding] = m;
1568
1655
  const f = normalizeFormatter(entry, sdk);
1569
1656
  if (f) formatters[binding] = f;
1657
+ const r = normalizeBoundResolvers(entry);
1658
+ if (r) boundResolvers[binding] = r;
1570
1659
  }
1571
1660
  Object.assign(meta2, context.meta);
1572
1661
  return buildRegistry({
1573
1662
  sdk,
1574
1663
  meta: meta2,
1575
1664
  formatters,
1665
+ boundResolvers,
1576
1666
  packageFilter: options?.package
1577
1667
  });
1578
1668
  };
@@ -1788,7 +1878,7 @@ function createSdk(root) {
1788
1878
  pluginSurface = {};
1789
1879
  bindValue(pluginSurface, plugin.name, plugins2[plugin.id]);
1790
1880
  }
1791
- for (const key of Object.keys(legacyExports)) context.surface[key] = key;
1881
+ for (const key2 of Object.keys(legacyExports)) context.surface[key2] = key2;
1792
1882
  if (plugin.pluginType === "aggregate") {
1793
1883
  recordExportSurface(context, plugin.exports);
1794
1884
  } else {
@@ -1858,6 +1948,756 @@ function addPlugin(sdk, plugin, options) {
1858
1948
  options ?? {}
1859
1949
  );
1860
1950
  }
1951
+ var CORE_SIGNAL_SYMBOL = Symbol.for("kitcore.signal");
1952
+ var CoreSignal = class extends Error {
1953
+ constructor(message) {
1954
+ super(message);
1955
+ Object.setPrototypeOf(this, new.target.prototype);
1956
+ Object.defineProperty(this, CORE_SIGNAL_SYMBOL, {
1957
+ value: true,
1958
+ enumerable: false,
1959
+ configurable: true,
1960
+ writable: false
1961
+ });
1962
+ }
1963
+ };
1964
+ function isCoreSignal(value) {
1965
+ return Boolean(
1966
+ value && typeof value === "object" && value[CORE_SIGNAL_SYMBOL] === true
1967
+ );
1968
+ }
1969
+ var CoreCancelledSignal = class extends CoreSignal {
1970
+ constructor(message = "resolution cancelled") {
1971
+ super(message);
1972
+ this.name = "CoreCancelledSignal";
1973
+ this.code = "CANCELLED";
1974
+ }
1975
+ };
1976
+ function unwrap(schema) {
1977
+ let inner = schema;
1978
+ let required = true;
1979
+ for (; ; ) {
1980
+ if (inner instanceof zod.z.ZodOptional) {
1981
+ required = false;
1982
+ inner = inner._zod.def.innerType;
1983
+ } else if (inner instanceof zod.z.ZodDefault) {
1984
+ required = false;
1985
+ inner = inner._zod.def.innerType;
1986
+ } else if (inner instanceof zod.z.ZodNullable) {
1987
+ inner = inner._zod.def.innerType;
1988
+ } else {
1989
+ break;
1990
+ }
1991
+ }
1992
+ return { inner, required };
1993
+ }
1994
+ function valueTypeOf(inner) {
1995
+ if (inner instanceof zod.z.ZodString) return "string";
1996
+ if (inner instanceof zod.z.ZodNumber) return "number";
1997
+ if (inner instanceof zod.z.ZodBoolean) return "boolean";
1998
+ if (inner instanceof zod.z.ZodEnum) return "string";
1999
+ if (inner instanceof zod.z.ZodArray) return "array";
2000
+ if (inner instanceof zod.z.ZodObject) return "object";
2001
+ return void 0;
2002
+ }
2003
+ function staticChoicesOf(inner) {
2004
+ if (inner instanceof zod.z.ZodEnum) {
2005
+ const values = inner.options;
2006
+ return values.map((value) => ({ label: value, value }));
2007
+ }
2008
+ return void 0;
2009
+ }
2010
+ function objectShape(schema) {
2011
+ const { inner } = schema ? unwrap(schema) : { inner: void 0 };
2012
+ if (inner instanceof zod.z.ZodObject) {
2013
+ return inner.shape;
2014
+ }
2015
+ return void 0;
2016
+ }
2017
+ function topoOrder2(specs) {
2018
+ const byName = new Map(specs.map((s) => [s.name, s]));
2019
+ const ordered = [];
2020
+ const placed = /* @__PURE__ */ new Set();
2021
+ let progressed = true;
2022
+ while (ordered.length < specs.length && progressed) {
2023
+ progressed = false;
2024
+ for (const spec of specs) {
2025
+ if (placed.has(spec.name)) continue;
2026
+ const ready = spec.requires.every((r) => !byName.has(r) || placed.has(r));
2027
+ if (ready) {
2028
+ ordered.push(spec);
2029
+ placed.add(spec.name);
2030
+ progressed = true;
2031
+ }
2032
+ }
2033
+ }
2034
+ for (const spec of specs) if (!placed.has(spec.name)) ordered.push(spec);
2035
+ return ordered;
2036
+ }
2037
+ function planParameters(entry) {
2038
+ const shape = objectShape(entry.inputSchema);
2039
+ const resolvers = entry.boundResolvers ?? {};
2040
+ const names = shape ? Object.keys(shape) : Object.keys(resolvers);
2041
+ const specs = names.map((name) => {
2042
+ const field = shape?.[name];
2043
+ const { inner, required } = field ? unwrap(field) : { inner: void 0, required: false };
2044
+ const resolver = resolvers[name];
2045
+ return {
2046
+ name,
2047
+ required,
2048
+ valueType: inner ? valueTypeOf(inner) : void 0,
2049
+ staticChoices: inner ? staticChoicesOf(inner) : void 0,
2050
+ resolver,
2051
+ requires: resolver?.requireParameters ?? []
2052
+ };
2053
+ });
2054
+ return { parameters: topoOrder2(specs) };
2055
+ }
2056
+ function getAtPath(root, path) {
2057
+ let node = root;
2058
+ for (const seg of path) {
2059
+ if (node == null || typeof node !== "object") return void 0;
2060
+ node = node[seg];
2061
+ }
2062
+ return node;
2063
+ }
2064
+ function setAtPath(root, path, value) {
2065
+ let node = root;
2066
+ for (let i = 0; i < path.length - 1; i++) {
2067
+ const seg = path[i];
2068
+ if (node[seg] == null || typeof node[seg] !== "object") node[seg] = {};
2069
+ node = node[seg];
2070
+ }
2071
+ node[path[path.length - 1]] = value;
2072
+ }
2073
+ var key = (path) => path.join(".");
2074
+ function isSettled(state, path) {
2075
+ return state.settled.includes(key(path));
2076
+ }
2077
+ function settle(state, path) {
2078
+ const k = key(path);
2079
+ if (!state.settled.includes(k)) state.settled.push(k);
2080
+ }
2081
+ function clone(state) {
2082
+ return JSON.parse(JSON.stringify(state));
2083
+ }
2084
+ function coerce(leaf, raw) {
2085
+ if (typeof raw !== "string") return raw;
2086
+ if (leaf.valueType === "number") {
2087
+ const n = Number(raw);
2088
+ return raw.trim() !== "" && !Number.isNaN(n) ? n : raw;
2089
+ }
2090
+ if (leaf.valueType === "boolean") {
2091
+ if (raw === "true") return true;
2092
+ if (raw === "false") return false;
2093
+ }
2094
+ return raw;
2095
+ }
2096
+ async function validationError(leaf, value, state) {
2097
+ const context = await resolveContext(leaf, state.resolved);
2098
+ const config = leaf.resolver?.prompt?.({
2099
+ items: state.listing?.items ?? [],
2100
+ input: mergeInput(state.resolved, leaf.extraInput),
2101
+ context
2102
+ });
2103
+ if (!config?.validate) return null;
2104
+ const verdict = config.validate(value);
2105
+ if (verdict === true) return null;
2106
+ return typeof verdict === "string" ? verdict : `${leaf.name}: invalid value`;
2107
+ }
2108
+ function toChoice(c) {
2109
+ const label = "label" in c ? c.label : c.name;
2110
+ const hint = Array.isArray(c.hint) ? c.hint.join(", ") : c.hint;
2111
+ return { label, value: String(c.value), hint };
2112
+ }
2113
+ function isRef(r) {
2114
+ return typeof r === "object" && r !== null && "ref" in r;
2115
+ }
2116
+ function toLeaf(name, field, definitions) {
2117
+ let resolver;
2118
+ let extraInput;
2119
+ if (isRef(field.resolver)) {
2120
+ resolver = definitions?.[field.resolver.ref];
2121
+ extraInput = field.resolver.input;
2122
+ } else {
2123
+ resolver = field.resolver;
2124
+ }
2125
+ return {
2126
+ name,
2127
+ required: field.required ?? false,
2128
+ resolver,
2129
+ extraInput,
2130
+ // Carry the field's value type so nested answers coerce (number/boolean)
2131
+ // the same way top-level params do. Without this a nested `z.number()`
2132
+ // field's typed answer stays a string and fails final validation.
2133
+ valueType: field.valueType,
2134
+ requires: resolver?.requireParameters ?? []
2135
+ };
2136
+ }
2137
+ async function objectChildren(resolver, input) {
2138
+ if (resolver.properties) {
2139
+ return Object.entries(resolver.properties).map(
2140
+ ([name, field]) => toLeaf(name, field, resolver.definitions)
2141
+ );
2142
+ }
2143
+ if (!resolver.getProperties) return [];
2144
+ const fields = await resolver.getProperties({ input });
2145
+ return Object.entries(fields).map(([name, field]) => {
2146
+ if (!isRef(field.resolver) && (field.resolver.imports?.length ?? 0) > 0) {
2147
+ throw new Error(
2148
+ `dynamic object field "${name}" inlines an import-bearing resolver; use { ref } into the object's definitions so its imports bind`
2149
+ );
2150
+ }
2151
+ return toLeaf(name, field, resolver.definitions);
2152
+ });
2153
+ }
2154
+ function arrayItem(resolver) {
2155
+ const items = resolver.items;
2156
+ const valueType = resolver.itemValueType;
2157
+ if (isRef(items)) {
2158
+ return {
2159
+ name: "",
2160
+ required: true,
2161
+ resolver: resolver.definitions?.[items.ref],
2162
+ extraInput: items.input,
2163
+ valueType,
2164
+ requires: []
2165
+ };
2166
+ }
2167
+ return {
2168
+ name: "",
2169
+ required: true,
2170
+ resolver: items,
2171
+ valueType,
2172
+ requires: []
2173
+ };
2174
+ }
2175
+ function mergeInput(input, extra) {
2176
+ return extra ? { ...input, ...extra } : input;
2177
+ }
2178
+ async function childrenAt(ctx, path, resolved) {
2179
+ if (path.length === 0) return ctx.parameters;
2180
+ const leaf = await leafAt(ctx, path, resolved);
2181
+ if (!leaf?.resolver || leaf.resolver.type !== "object") return [];
2182
+ return objectChildren(leaf.resolver, mergeInput(resolved, leaf.extraInput));
2183
+ }
2184
+ async function leafAt(ctx, path, resolved) {
2185
+ let children = ctx.parameters;
2186
+ let leaf;
2187
+ for (let i = 0; i < path.length; i++) {
2188
+ const seg = path[i];
2189
+ if (typeof seg === "number") {
2190
+ if (leaf?.resolver?.type !== "array") return void 0;
2191
+ leaf = arrayItem(leaf.resolver);
2192
+ } else {
2193
+ leaf = children.find((c) => c.name === seg);
2194
+ if (!leaf) return void 0;
2195
+ }
2196
+ if (i < path.length - 1 && typeof path[i + 1] === "string") {
2197
+ if (leaf?.resolver?.type !== "object") return void 0;
2198
+ children = await objectChildren(
2199
+ leaf.resolver,
2200
+ mergeInput(resolved, leaf.extraInput)
2201
+ );
2202
+ }
2203
+ }
2204
+ return leaf;
2205
+ }
2206
+ async function arrayInfoAt(ctx, path, resolved) {
2207
+ const leaf = await leafAt(ctx, path, resolved);
2208
+ const resolver = leaf?.resolver;
2209
+ if (resolver?.type !== "array") {
2210
+ throw new Error(`expected an array resolver at "${key(path)}"`);
2211
+ }
2212
+ return {
2213
+ min: resolver.minItems ?? 0,
2214
+ max: resolver.maxItems ?? Infinity,
2215
+ item: { ...arrayItem(resolver), name: String(path[path.length - 1]) }
2216
+ };
2217
+ }
2218
+ var AFFORDANCE = {
2219
+ choose: { action: "choose", description: "Pick one of the listed options" },
2220
+ custom: {
2221
+ action: "custom",
2222
+ description: "Provide a value directly",
2223
+ supply: "value"
2224
+ },
2225
+ search: {
2226
+ action: "search",
2227
+ description: "Filter the options by a search term",
2228
+ supply: "term"
2229
+ },
2230
+ more: { action: "more", description: "Load more options" },
2231
+ skip: { action: "skip", description: "Omit this optional parameter" },
2232
+ add: { action: "add", description: "Add another item" },
2233
+ done: { action: "done", description: "Finish the list" },
2234
+ retry: { action: "retry", description: "Retry loading the options" },
2235
+ cancel: { action: "cancel", description: "Cancel resolution" }
2236
+ };
2237
+ async function firstPage(result) {
2238
+ const page = await result;
2239
+ return {
2240
+ data: Array.isArray(page?.data) ? page.data : [],
2241
+ nextCursor: page?.nextCursor
2242
+ };
2243
+ }
2244
+ async function resolveContext(leaf, input) {
2245
+ return leaf.resolver?.getContext?.({
2246
+ input: mergeInput(input, leaf.extraInput)
2247
+ });
2248
+ }
2249
+ async function fetchListing(leaf, input, opts = {}) {
2250
+ const page = await firstPage(
2251
+ leaf.resolver?.listItems?.({
2252
+ input: mergeInput(input, leaf.extraInput),
2253
+ context: opts.context,
2254
+ search: opts.search,
2255
+ cursor: opts.cursor
2256
+ })
2257
+ );
2258
+ return {
2259
+ items: [...opts.priorItems ?? [], ...page.data],
2260
+ cursor: page.nextCursor,
2261
+ search: opts.search,
2262
+ exhausted: page.nextCursor == null
2263
+ };
2264
+ }
2265
+ function selectActions(leaf, listing, multiple) {
2266
+ const actions = multiple ? [AFFORDANCE.choose] : [AFFORDANCE.choose, AFFORDANCE.custom];
2267
+ if (leaf.resolver?.inputType === "search") actions.push(AFFORDANCE.search);
2268
+ if (listing.cursor) actions.push(AFFORDANCE.more);
2269
+ if (!leaf.required) actions.push(AFFORDANCE.skip);
2270
+ return actions;
2271
+ }
2272
+ function selectQuestion(leaf, input, listing, context) {
2273
+ const config = leaf.resolver?.prompt?.({
2274
+ items: listing.items,
2275
+ input: mergeInput(input, leaf.extraInput),
2276
+ context
2277
+ });
2278
+ const multiple = config?.type === "checkbox";
2279
+ return {
2280
+ type: "select",
2281
+ message: config?.message ?? `Select ${leaf.name}:`,
2282
+ choices: (config?.choices ?? []).map(toChoice),
2283
+ ...multiple ? { multiple: true } : {},
2284
+ ...config?.notes?.length ? { notes: config.notes } : {},
2285
+ actions: selectActions(leaf, listing, multiple)
2286
+ };
2287
+ }
2288
+ function toControllerError(error) {
2289
+ if (error instanceof Error) {
2290
+ const code = error.code;
2291
+ return {
2292
+ name: error.name,
2293
+ message: error.message,
2294
+ ...typeof code === "string" ? { code } : {}
2295
+ };
2296
+ }
2297
+ return { name: "Error", message: String(error) };
2298
+ }
2299
+ function failedResult(state, name, error) {
2300
+ return {
2301
+ state,
2302
+ result: {
2303
+ status: "failed",
2304
+ error: toControllerError(error),
2305
+ question: {
2306
+ type: "select",
2307
+ message: `Could not load options for ${name}.`,
2308
+ choices: [],
2309
+ actions: [AFFORDANCE.retry, AFFORDANCE.cancel]
2310
+ }
2311
+ }
2312
+ };
2313
+ }
2314
+ async function buildQuestion(leaf, input) {
2315
+ const optional = !leaf.required;
2316
+ const resolver = leaf.resolver;
2317
+ if (resolver?.listItems) {
2318
+ const context = await resolveContext(leaf, input);
2319
+ const listing = await fetchListing(leaf, input, { context });
2320
+ return {
2321
+ question: selectQuestion(leaf, input, listing, context),
2322
+ listing
2323
+ };
2324
+ }
2325
+ if (leaf.staticChoices) {
2326
+ const actions2 = [AFFORDANCE.choose];
2327
+ if (optional) actions2.push(AFFORDANCE.skip);
2328
+ return {
2329
+ question: {
2330
+ type: "select",
2331
+ message: `Select ${leaf.name}:`,
2332
+ choices: leaf.staticChoices,
2333
+ actions: actions2
2334
+ }
2335
+ };
2336
+ }
2337
+ const inputType = resolver?.inputType && resolver.inputType !== "search" ? resolver.inputType : "text";
2338
+ const actions = [AFFORDANCE.custom];
2339
+ if (optional) actions.push(AFFORDANCE.skip);
2340
+ return {
2341
+ question: {
2342
+ type: "input",
2343
+ message: `Enter ${leaf.name}:`,
2344
+ inputType,
2345
+ placeholder: resolver?.placeholder,
2346
+ actions
2347
+ }
2348
+ };
2349
+ }
2350
+ function finalize(ctx, resolved) {
2351
+ if (!ctx.schema) return { status: "done", value: resolved };
2352
+ const parsed = ctx.schema.safeParse(resolved);
2353
+ if (parsed.success) {
2354
+ return { status: "done", value: parsed.data };
2355
+ }
2356
+ const issues = parsed.error.issues.map((i) => ({
2357
+ parameter: i.path.map(String).join(".") || void 0,
2358
+ message: i.message
2359
+ }));
2360
+ return { status: "invalid", issues };
2361
+ }
2362
+ function collectionQuestion(t) {
2363
+ const actions = [AFFORDANCE.add];
2364
+ if (t.count >= t.min) actions.push(AFFORDANCE.done);
2365
+ return {
2366
+ type: "collection",
2367
+ message: `Add another ${t.path[t.path.length - 1]}? (${t.count} so far)`,
2368
+ count: t.count,
2369
+ min: t.min,
2370
+ // An unbounded array's max is Infinity, which JSON.stringify turns to null;
2371
+ // omit it so the question round-trips across the wall as plain data.
2372
+ ...Number.isFinite(t.max) ? { max: t.max } : {},
2373
+ actions
2374
+ };
2375
+ }
2376
+ async function findInArray(ctx, state, path) {
2377
+ if (isSettled(state, path)) return null;
2378
+ if (getAtPath(state.resolved, path) == null)
2379
+ setAtPath(state.resolved, path, []);
2380
+ if (!state.interactive) {
2381
+ settle(state, path);
2382
+ return null;
2383
+ }
2384
+ const { min, max, item } = await arrayInfoAt(ctx, path, state.resolved);
2385
+ const items = getAtPath(state.resolved, path);
2386
+ const len = items.length;
2387
+ const itemType = item.resolver?.type;
2388
+ if (len > 0 && (itemType === "object" || itemType === "array")) {
2389
+ const inner = await findNext(ctx, state, [...path, len - 1]);
2390
+ if (inner) return inner;
2391
+ }
2392
+ if (len < min) return descendItem(ctx, state, path, len, item);
2393
+ if (len < max) return { kind: "array", path, count: len, min, max };
2394
+ settle(state, path);
2395
+ return null;
2396
+ }
2397
+ function seedItemSlot(state, itemPath, item) {
2398
+ const type = item.resolver?.type;
2399
+ if (type === "object") {
2400
+ setAtPath(state.resolved, itemPath, {});
2401
+ return "object";
2402
+ }
2403
+ if (type === "array") {
2404
+ setAtPath(state.resolved, itemPath, []);
2405
+ return "array";
2406
+ }
2407
+ return "leaf";
2408
+ }
2409
+ async function descendItem(ctx, state, arrayPath, index, item) {
2410
+ const itemPath = [...arrayPath, index];
2411
+ const kind = seedItemSlot(state, itemPath, item);
2412
+ if (kind === "object") return findNext(ctx, state, itemPath);
2413
+ if (kind === "array") return findInArray(ctx, state, itemPath);
2414
+ return { kind: "leaf", path: itemPath, leaf: item };
2415
+ }
2416
+ async function findNext(ctx, state, path = []) {
2417
+ const container = getAtPath(state.resolved, path) ?? {};
2418
+ for (const leaf of await childrenAt(ctx, path, state.resolved)) {
2419
+ const childPath = [...path, leaf.name];
2420
+ if (!leaf.requires.every((r) => container[r] !== void 0)) continue;
2421
+ if (leaf.resolver?.type === "object") {
2422
+ if (getAtPath(state.resolved, childPath) == null)
2423
+ setAtPath(state.resolved, childPath, {});
2424
+ const inner = await findNext(ctx, state, childPath);
2425
+ if (inner) return inner;
2426
+ continue;
2427
+ }
2428
+ if (leaf.resolver?.type === "array") {
2429
+ const inner = await findInArray(ctx, state, childPath);
2430
+ if (inner) return inner;
2431
+ continue;
2432
+ }
2433
+ if (container[leaf.name] !== void 0 || isSettled(state, childPath))
2434
+ continue;
2435
+ return { kind: "leaf", path: childPath, leaf };
2436
+ }
2437
+ return null;
2438
+ }
2439
+ async function askLeaf(state, path, leaf, opts = {}) {
2440
+ state.current = path;
2441
+ try {
2442
+ const { question, listing } = await buildQuestion(leaf, state.resolved);
2443
+ state.listing = listing;
2444
+ return {
2445
+ state,
2446
+ result: {
2447
+ status: "ask",
2448
+ question,
2449
+ ...opts.error ? { error: opts.error } : {}
2450
+ }
2451
+ };
2452
+ } catch (error) {
2453
+ state.listing = { items: [], exhausted: false };
2454
+ return failedResult(state, leaf.name, error);
2455
+ }
2456
+ }
2457
+ async function advance(ctx, state) {
2458
+ for (; ; ) {
2459
+ const target = await findNext(ctx, state);
2460
+ if (!target) {
2461
+ delete state.current;
2462
+ delete state.listing;
2463
+ return { state, result: finalize(ctx, state.resolved) };
2464
+ }
2465
+ if (target.kind === "array") {
2466
+ state.current = target.path;
2467
+ delete state.listing;
2468
+ return {
2469
+ state,
2470
+ result: { status: "ask", question: collectionQuestion(target) }
2471
+ };
2472
+ }
2473
+ const { path, leaf } = target;
2474
+ const auto = await leaf.resolver?.tryResolveWithoutPrompt?.({
2475
+ input: mergeInput(state.resolved, leaf.extraInput)
2476
+ });
2477
+ if (auto) {
2478
+ if (auto.resolvedValue !== void 0)
2479
+ setAtPath(state.resolved, path, auto.resolvedValue);
2480
+ settle(state, path);
2481
+ continue;
2482
+ }
2483
+ if (!state.interactive) {
2484
+ if (!leaf.required) {
2485
+ settle(state, path);
2486
+ continue;
2487
+ }
2488
+ } else if (!leaf.required && !leaf.resolver) {
2489
+ settle(state, path);
2490
+ continue;
2491
+ }
2492
+ return askLeaf(state, path, leaf);
2493
+ }
2494
+ }
2495
+ async function start(ctx, input = {}, interactive = true) {
2496
+ const resolved = {};
2497
+ for (const spec of ctx.parameters) {
2498
+ if (spec.resolver?.type === "constant")
2499
+ resolved[spec.name] = spec.resolver.value;
2500
+ }
2501
+ Object.assign(resolved, input);
2502
+ return advance(ctx, {
2503
+ method: ctx.method,
2504
+ resolved,
2505
+ settled: [],
2506
+ interactive
2507
+ });
2508
+ }
2509
+ async function step(ctx, prior, action) {
2510
+ const state = clone(prior);
2511
+ if (action.type === "cancel") {
2512
+ delete state.current;
2513
+ delete state.listing;
2514
+ return { state, result: { status: "cancelled" } };
2515
+ }
2516
+ const path = state.current;
2517
+ if (!path) throw new Error("step called with no outstanding question");
2518
+ const leaf = await leafAt(ctx, path, state.resolved);
2519
+ if (leaf && (action.type === "search" || action.type === "more" || action.type === "retry")) {
2520
+ return refine(ctx, state, leaf, path, action);
2521
+ }
2522
+ if (action.type === "add" || action.type === "done") {
2523
+ delete state.current;
2524
+ delete state.listing;
2525
+ if (action.type === "done") {
2526
+ settle(state, path);
2527
+ return advance(ctx, state);
2528
+ }
2529
+ const items = getAtPath(state.resolved, path) ?? [];
2530
+ const { item } = await arrayInfoAt(ctx, path, state.resolved);
2531
+ const itemPath = [...path, items.length];
2532
+ if (seedItemSlot(state, itemPath, item) === "leaf")
2533
+ return askLeaf(state, itemPath, item);
2534
+ return advance(ctx, state);
2535
+ }
2536
+ switch (action.type) {
2537
+ case "choose":
2538
+ case "custom": {
2539
+ if (leaf) {
2540
+ const error = await validationError(leaf, action.value, state);
2541
+ if (error) return askLeaf(state, path, leaf, { error });
2542
+ }
2543
+ setAtPath(
2544
+ state.resolved,
2545
+ path,
2546
+ leaf ? coerce(leaf, action.value) : action.value
2547
+ );
2548
+ break;
2549
+ }
2550
+ case "skip":
2551
+ settle(state, path);
2552
+ break;
2553
+ default:
2554
+ throw new Error(`action "${action.type}" is not supported here`);
2555
+ }
2556
+ delete state.current;
2557
+ delete state.listing;
2558
+ return advance(ctx, state);
2559
+ }
2560
+ async function refine(ctx, state, leaf, path, action) {
2561
+ const attempt = action.type === "search" ? { search: action.term, cursor: void 0, priorItems: [] } : {
2562
+ search: state.listing?.search,
2563
+ cursor: state.listing?.cursor,
2564
+ priorItems: state.listing?.items ?? []
2565
+ };
2566
+ try {
2567
+ if (action.type === "search") {
2568
+ const exact = await leaf.resolver?.tryResolveFromSearch?.({
2569
+ input: mergeInput(state.resolved, leaf.extraInput),
2570
+ search: action.term
2571
+ });
2572
+ if (exact) {
2573
+ setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
2574
+ delete state.current;
2575
+ delete state.listing;
2576
+ return advance(ctx, state);
2577
+ }
2578
+ }
2579
+ const context = await resolveContext(leaf, state.resolved);
2580
+ state.listing = await fetchListing(leaf, state.resolved, {
2581
+ ...attempt,
2582
+ context
2583
+ });
2584
+ return {
2585
+ state,
2586
+ result: {
2587
+ status: "ask",
2588
+ question: selectQuestion(leaf, state.resolved, state.listing, context)
2589
+ }
2590
+ };
2591
+ } catch (error) {
2592
+ state.listing = {
2593
+ items: attempt.priorItems,
2594
+ search: attempt.search,
2595
+ cursor: attempt.cursor,
2596
+ exhausted: false
2597
+ };
2598
+ return failedResult(state, leaf.name, error);
2599
+ }
2600
+ }
2601
+ function toJsonSchema(schema) {
2602
+ if (!schema) return void 0;
2603
+ try {
2604
+ return zod.z.toJSONSchema(schema);
2605
+ } catch {
2606
+ return void 0;
2607
+ }
2608
+ }
2609
+ function projectSummary(entry) {
2610
+ return {
2611
+ name: entry.name,
2612
+ ...entry.description ? { description: entry.description } : {},
2613
+ ...entry.categories?.length ? { categories: entry.categories } : {}
2614
+ };
2615
+ }
2616
+ function projectMethod(entry) {
2617
+ const inputProperties = toJsonSchema(entry.inputSchema)?.properties;
2618
+ const parameters = {};
2619
+ for (const spec of planParameters(entry).parameters) {
2620
+ parameters[spec.name] = {
2621
+ required: spec.required,
2622
+ dynamic: Boolean(spec.resolver?.listItems),
2623
+ ...spec.resolver?.inputType === "search" ? { searchable: true } : {},
2624
+ ...inputProperties?.[spec.name] ? { schema: inputProperties[spec.name] } : {},
2625
+ ...spec.staticChoices ? { choices: spec.staticChoices } : {},
2626
+ ...spec.requires.length ? { requireParameters: spec.requires } : {}
2627
+ };
2628
+ }
2629
+ const output = toJsonSchema(entry.outputSchema);
2630
+ return {
2631
+ name: entry.name,
2632
+ ...entry.description ? { description: entry.description } : {},
2633
+ ...entry.categories?.length ? { categories: entry.categories } : {},
2634
+ parameters,
2635
+ ...entry.positional?.length ? { positional: entry.positional } : {},
2636
+ ...output ? { output } : {}
2637
+ };
2638
+ }
2639
+ function createController(sdk) {
2640
+ function entryFor(method) {
2641
+ const entry = sdk.getRegistry().functions.find((f) => f.name === method);
2642
+ if (!entry) throw new Error(`unknown method "${method}"`);
2643
+ return entry;
2644
+ }
2645
+ function contextFor(method) {
2646
+ const entry = entryFor(method);
2647
+ return {
2648
+ method,
2649
+ schema: entry.inputSchema,
2650
+ parameters: planParameters(entry).parameters
2651
+ };
2652
+ }
2653
+ const start2 = ({ method, input, interactive }) => start(contextFor(method), input, interactive);
2654
+ const step2 = ({ state, action }) => step(contextFor(state.method), state, action);
2655
+ const resolve2 = async ({
2656
+ method,
2657
+ input,
2658
+ answer,
2659
+ interactive
2660
+ }) => {
2661
+ const ctx = contextFor(method);
2662
+ let { state, result } = await start(ctx, input, interactive);
2663
+ while (result.status === "ask" || result.status === "failed") {
2664
+ const action = await answer({ state, result });
2665
+ ({ state, result } = await step(ctx, state, action));
2666
+ }
2667
+ if (result.status === "done") return result.value;
2668
+ if (result.status === "cancelled") {
2669
+ throw new CoreCancelledSignal(`resolution cancelled for "${method}"`);
2670
+ }
2671
+ const detail = result.issues.map((i) => i.parameter ? `${i.parameter}: ${i.message}` : i.message).join("; ");
2672
+ throw new Error(`invalid input for "${method}": ${detail}`);
2673
+ };
2674
+ const listMethods = () => ({
2675
+ data: sdk.getRegistry().functions.map(projectSummary)
2676
+ });
2677
+ const getMethod = ({ method }) => ({
2678
+ data: projectMethod(entryFor(method))
2679
+ });
2680
+ const listChoices = async ({
2681
+ method,
2682
+ parameter,
2683
+ input = {},
2684
+ search,
2685
+ cursor
2686
+ }) => {
2687
+ const spec = contextFor(method).parameters.find(
2688
+ (p) => p.name === parameter
2689
+ );
2690
+ if (!spec?.resolver?.listItems) return { data: [] };
2691
+ const context = await spec.resolver.getContext?.({ input });
2692
+ const page = await firstPage(
2693
+ spec.resolver.listItems({ input, context, search, cursor })
2694
+ );
2695
+ const config = spec.resolver.prompt?.({ items: page.data, input, context });
2696
+ const data = (config?.choices ?? []).map(toChoice);
2697
+ return { data, nextCursor: page.nextCursor };
2698
+ };
2699
+ return { resolve: resolve2, start: start2, step: step2, listMethods, getMethod, listChoices };
2700
+ }
1861
2701
  function createCorePlugin(options) {
1862
2702
  return () => ({
1863
2703
  context: {
@@ -2810,8 +3650,8 @@ function normalizeHeaders(optionsHeaders) {
2810
3650
  return headers;
2811
3651
  }
2812
3652
  const headerEntries = optionsHeaders instanceof Headers ? Array.from(optionsHeaders.entries()) : Array.isArray(optionsHeaders) ? optionsHeaders : Object.entries(optionsHeaders);
2813
- for (const [key, value] of headerEntries) {
2814
- headers[key] = value;
3653
+ for (const [key2, value] of headerEntries) {
3654
+ headers[key2] = value;
2815
3655
  }
2816
3656
  return headers;
2817
3657
  }
@@ -3085,7 +3925,7 @@ var listAppsPlugin = definePlugin(
3085
3925
  locator
3086
3926
  ];
3087
3927
  }
3088
- const duplicatedLookupAppKeys = Object.keys(implementationNameToLocator).filter((key) => implementationNameToLocator[key].length > 1).map((key) => implementationNameToLocator[key]).flat().map((locator) => locator.lookupAppKey);
3928
+ const duplicatedLookupAppKeys = Object.keys(implementationNameToLocator).filter((key2) => implementationNameToLocator[key2].length > 1).map((key2) => implementationNameToLocator[key2]).flat().map((locator) => locator.lookupAppKey);
3089
3929
  if (duplicatedLookupAppKeys.length > 0) {
3090
3930
  throw new Error(
3091
3931
  `Duplicate lookup app keys found: ${duplicatedLookupAppKeys.join(", ")}`
@@ -3928,7 +4768,7 @@ function formatRecordError(fieldId, err) {
3928
4768
  function formatResponseError(err) {
3929
4769
  const message = err.human_title || err.title || "Unknown error";
3930
4770
  if (err.meta && Object.keys(err.meta).length > 0) {
3931
- const metaParts = Object.entries(err.meta).map(([key, val]) => `${key}: ${JSON.stringify(val)}`).join(", ");
4771
+ const metaParts = Object.entries(err.meta).map(([key2, val]) => `${key2}: ${JSON.stringify(val)}`).join(", ");
3932
4772
  return `${message} (${metaParts})`;
3933
4773
  }
3934
4774
  return message;
@@ -3963,8 +4803,8 @@ var TrashSchema = zod.z.enum(["exclude", "include", "only"]).optional().describe
3963
4803
  'Control soft-deleted item visibility. "exclude" (default) returns active items only, "include" returns both active and soft-deleted, "only" returns soft-deleted items only.'
3964
4804
  );
3965
4805
  var FIELD_ID_PATTERN = /^f\d+$/;
3966
- function isFieldId(key) {
3967
- return FIELD_ID_PATTERN.test(key);
4806
+ function isFieldId(key2) {
4807
+ return FIELD_ID_PATTERN.test(key2);
3968
4808
  }
3969
4809
  var NESTED_COMPONENTS = {
3970
4810
  labeled_string: /* @__PURE__ */ new Set(["value"]),
@@ -4002,7 +4842,7 @@ async function resolveFieldKeys({
4002
4842
  fieldKeys
4003
4843
  }) {
4004
4844
  const allAreIds = fieldKeys.every(
4005
- (key) => typeof key === "number" || /^(f?\d+)$/.test(key)
4845
+ (key2) => typeof key2 === "number" || /^(f?\d+)$/.test(key2)
4006
4846
  );
4007
4847
  if (allAreIds) {
4008
4848
  return fieldKeys.map(toNumericFieldId);
@@ -4011,13 +4851,13 @@ async function resolveFieldKeys({
4011
4851
  if (!mapping) {
4012
4852
  return fieldKeys.map(toNumericFieldId);
4013
4853
  }
4014
- return fieldKeys.map((key) => {
4015
- if (typeof key === "number") return key;
4016
- if (FIELD_ID_PATTERN.test(key)) return toNumericFieldId(key);
4017
- const id = mapping.nameToId.get(key);
4854
+ return fieldKeys.map((key2) => {
4855
+ if (typeof key2 === "number") return key2;
4856
+ if (FIELD_ID_PATTERN.test(key2)) return toNumericFieldId(key2);
4857
+ const id = mapping.nameToId.get(key2);
4018
4858
  if (!id) {
4019
4859
  throw new ZapierValidationError(
4020
- `Unknown field name: "${key}". Use a valid field name or ID.`
4860
+ `Unknown field name: "${key2}". Use a valid field name or ID.`
4021
4861
  );
4022
4862
  }
4023
4863
  return toNumericFieldId(id);
@@ -4033,13 +4873,13 @@ async function createFieldKeyTranslator({
4033
4873
  translateInput(data) {
4034
4874
  if (!mapping) return data;
4035
4875
  const result = {};
4036
- for (const [key, value] of Object.entries(data)) {
4037
- if (FIELD_ID_PATTERN.test(key) && mapping.idToName.has(key)) {
4038
- result[key] = value;
4039
- } else if (mapping.nameToId.has(key)) {
4040
- result[mapping.nameToId.get(key)] = value;
4876
+ for (const [key2, value] of Object.entries(data)) {
4877
+ if (FIELD_ID_PATTERN.test(key2) && mapping.idToName.has(key2)) {
4878
+ result[key2] = value;
4879
+ } else if (mapping.nameToId.has(key2)) {
4880
+ result[mapping.nameToId.get(key2)] = value;
4041
4881
  } else {
4042
- result[key] = value;
4882
+ result[key2] = value;
4043
4883
  }
4044
4884
  }
4045
4885
  return result;
@@ -4047,29 +4887,29 @@ async function createFieldKeyTranslator({
4047
4887
  translateOutput(data) {
4048
4888
  if (!mapping) return data;
4049
4889
  const result = {};
4050
- for (const [key, value] of Object.entries(data)) {
4051
- if (mapping.idToName.has(key)) {
4052
- result[mapping.idToName.get(key)] = value;
4890
+ for (const [key2, value] of Object.entries(data)) {
4891
+ if (mapping.idToName.has(key2)) {
4892
+ result[mapping.idToName.get(key2)] = value;
4053
4893
  } else {
4054
- result[key] = value;
4894
+ result[key2] = value;
4055
4895
  }
4056
4896
  }
4057
4897
  return result;
4058
4898
  },
4059
- translateFieldKey(key) {
4060
- if (!mapping) return key;
4061
- if (FIELD_ID_PATTERN.test(key) && mapping.idToName.has(key)) {
4062
- const fieldType = mapping.idToType.get(key);
4899
+ translateFieldKey(key2) {
4900
+ if (!mapping) return key2;
4901
+ if (FIELD_ID_PATTERN.test(key2) && mapping.idToName.has(key2)) {
4902
+ const fieldType = mapping.idToType.get(key2);
4063
4903
  if (fieldType) {
4064
4904
  const components = NESTED_COMPONENTS[fieldType];
4065
4905
  if (components?.size === 1) {
4066
- return `${key}__${[...components][0]}`;
4906
+ return `${key2}__${[...components][0]}`;
4067
4907
  }
4068
4908
  }
4069
- return key;
4909
+ return key2;
4070
4910
  }
4071
- if (mapping.nameToId.has(key)) {
4072
- const fieldId = mapping.nameToId.get(key);
4911
+ if (mapping.nameToId.has(key2)) {
4912
+ const fieldId = mapping.nameToId.get(key2);
4073
4913
  const fieldType = mapping.idToType.get(fieldId);
4074
4914
  if (fieldType) {
4075
4915
  const components = NESTED_COMPONENTS[fieldType];
@@ -4079,10 +4919,10 @@ async function createFieldKeyTranslator({
4079
4919
  }
4080
4920
  return fieldId;
4081
4921
  }
4082
- const sepIndex = key.lastIndexOf("__");
4922
+ const sepIndex = key2.lastIndexOf("__");
4083
4923
  if (sepIndex > 0) {
4084
- const prefix = key.slice(0, sepIndex);
4085
- const component = key.slice(sepIndex + 2);
4924
+ const prefix = key2.slice(0, sepIndex);
4925
+ const component = key2.slice(sepIndex + 2);
4086
4926
  let fieldId;
4087
4927
  if (FIELD_ID_PATTERN.test(prefix) && mapping.idToName.has(prefix)) {
4088
4928
  fieldId = prefix;
@@ -4096,7 +4936,7 @@ async function createFieldKeyTranslator({
4096
4936
  }
4097
4937
  }
4098
4938
  }
4099
- return key;
4939
+ return key2;
4100
4940
  }
4101
4941
  };
4102
4942
  }
@@ -5740,9 +6580,9 @@ var RunActionSchemaDeprecated = zod.z.object({
5740
6580
  var RunActionInputSchema = zod.z.union([RunActionSchema, RunActionSchemaDeprecated]).describe(RunActionDescription);
5741
6581
 
5742
6582
  // src/formatters/actionResult.ts
5743
- function getStringProperty(obj, key) {
5744
- if (typeof obj === "object" && obj !== null && key in obj) {
5745
- const value = obj[key];
6583
+ function getStringProperty(obj, key2) {
6584
+ if (typeof obj === "object" && obj !== null && key2 in obj) {
6585
+ const value = obj[key2];
5746
6586
  return typeof value === "string" ? value : void 0;
5747
6587
  }
5748
6588
  return void 0;
@@ -5829,13 +6669,13 @@ var runActionPlugin = definePlugin(
5829
6669
  let oldestKey;
5830
6670
  let oldestExpiry = Infinity;
5831
6671
  let evictedAny = false;
5832
- for (const [key, entry] of runActionContextCache) {
6672
+ for (const [key2, entry] of runActionContextCache) {
5833
6673
  if (now >= entry.expiresAt) {
5834
- runActionContextCache.delete(key);
6674
+ runActionContextCache.delete(key2);
5835
6675
  evictedAny = true;
5836
6676
  } else if (entry.expiresAt < oldestExpiry) {
5837
6677
  oldestExpiry = entry.expiresAt;
5838
- oldestKey = key;
6678
+ oldestKey = key2;
5839
6679
  }
5840
6680
  }
5841
6681
  if (!evictedAny && oldestKey) {
@@ -6236,9 +7076,9 @@ function findManifestEntry({
6236
7076
  return [slug, manifest.apps[slug]];
6237
7077
  }
6238
7078
  }
6239
- for (const [key, entry] of Object.entries(manifest.apps)) {
7079
+ for (const [key2, entry] of Object.entries(manifest.apps)) {
6240
7080
  if (entry.implementationName === appKeyWithoutVersion) {
6241
- return [key, entry];
7081
+ return [key2, entry];
6242
7082
  }
6243
7083
  }
6244
7084
  return null;
@@ -6649,28 +7489,28 @@ function censorHeaders(headers) {
6649
7489
  if (!headers) return headers;
6650
7490
  const headersObj = new Headers(headers);
6651
7491
  const authKeys = ["authorization", "x-api-key"];
6652
- for (const [key, value] of headersObj.entries()) {
6653
- if (authKeys.some((authKey) => key.toLowerCase() === authKey)) {
7492
+ for (const [key2, value] of headersObj.entries()) {
7493
+ if (authKeys.some((authKey) => key2.toLowerCase() === authKey)) {
6654
7494
  const spaceIndex = value.indexOf(" ");
6655
7495
  if (spaceIndex > 0 && spaceIndex < value.length - 1) {
6656
7496
  const prefix = value.substring(0, spaceIndex + 1);
6657
7497
  const token = value.substring(spaceIndex + 1);
6658
7498
  if (token.length > 12) {
6659
- const start = token.substring(0, 4);
7499
+ const start2 = token.substring(0, 4);
6660
7500
  const end = token.substring(token.length - 4);
6661
- headersObj.set(key, `${prefix}${start}...${end}`);
7501
+ headersObj.set(key2, `${prefix}${start2}...${end}`);
6662
7502
  } else {
6663
7503
  const firstChar = token.charAt(0);
6664
- headersObj.set(key, `${prefix}${firstChar}...`);
7504
+ headersObj.set(key2, `${prefix}${firstChar}...`);
6665
7505
  }
6666
7506
  } else {
6667
7507
  if (value.length > 12) {
6668
- const start = value.substring(0, 4);
7508
+ const start2 = value.substring(0, 4);
6669
7509
  const end = value.substring(value.length - 4);
6670
- headersObj.set(key, `${start}...${end}`);
7510
+ headersObj.set(key2, `${start2}...${end}`);
6671
7511
  } else {
6672
7512
  const firstChar = value.charAt(0);
6673
- headersObj.set(key, `${firstChar}...`);
7513
+ headersObj.set(key2, `${firstChar}...`);
6674
7514
  }
6675
7515
  }
6676
7516
  }
@@ -7239,21 +8079,21 @@ function getClientIdFromCredentials(credentials) {
7239
8079
  function createMemoryCache() {
7240
8080
  const store = /* @__PURE__ */ new Map();
7241
8081
  return {
7242
- async get(key) {
7243
- const entry = store.get(key);
8082
+ async get(key2) {
8083
+ const entry = store.get(key2);
7244
8084
  if (!entry) return void 0;
7245
8085
  if (entry.expiresAt !== void 0 && entry.expiresAt <= Date.now()) {
7246
- store.delete(key);
8086
+ store.delete(key2);
7247
8087
  return void 0;
7248
8088
  }
7249
8089
  return { value: entry.value, expiresAt: entry.expiresAt };
7250
8090
  },
7251
- async set(key, value, options) {
8091
+ async set(key2, value, options) {
7252
8092
  const expiresAt = options?.ttl ? Date.now() + options.ttl * 1e3 : void 0;
7253
- store.set(key, { value, expiresAt });
8093
+ store.set(key2, { value, expiresAt });
7254
8094
  },
7255
- async delete(key) {
7256
- store.delete(key);
8095
+ async delete(key2) {
8096
+ store.delete(key2);
7257
8097
  }
7258
8098
  };
7259
8099
  }
@@ -7744,14 +8584,14 @@ function createSseParserStream() {
7744
8584
  transform(chunk, controller) {
7745
8585
  buffer += chunk;
7746
8586
  const newline = /\r\n|\r|\n/g;
7747
- let start = 0;
8587
+ let start2 = 0;
7748
8588
  let match;
7749
8589
  while ((match = newline.exec(buffer)) !== null) {
7750
8590
  if (match[0] === "\r" && match.index === buffer.length - 1) break;
7751
- processLine(buffer.slice(start, match.index), controller);
7752
- start = match.index + match[0].length;
8591
+ processLine(buffer.slice(start2, match.index), controller);
8592
+ start2 = match.index + match[0].length;
7753
8593
  }
7754
- buffer = buffer.slice(start);
8594
+ buffer = buffer.slice(start2);
7755
8595
  },
7756
8596
  flush(controller) {
7757
8597
  if (buffer.endsWith("\r")) {
@@ -7853,8 +8693,63 @@ function parseApprovalReviewStreamPayload(parsed, toolNames) {
7853
8693
  }
7854
8694
  }
7855
8695
 
8696
+ // src/api/deprecation.ts
8697
+ var DEPRECATION_MESSAGE_HEADER = "zapier-sdk-deprecation-message";
8698
+ var DEPRECATION_ID_HEADER = "zapier-sdk-deprecation-id";
8699
+ var DEPRECATION_NOTICE_EVENT = "api:deprecation_notice";
8700
+ var displayedNoticeIds = /* @__PURE__ */ new Set();
8701
+ function handleDeprecationNotice({
8702
+ response,
8703
+ canSendDeprecationMessaging,
8704
+ onEvent
8705
+ }) {
8706
+ try {
8707
+ sniffDeprecationNotice({ response, canSendDeprecationMessaging, onEvent });
8708
+ } catch {
8709
+ }
8710
+ }
8711
+ function sniffDeprecationNotice({
8712
+ response,
8713
+ canSendDeprecationMessaging,
8714
+ onEvent
8715
+ }) {
8716
+ if (!canSendDeprecationMessaging) return;
8717
+ const message = response.headers?.get(DEPRECATION_MESSAGE_HEADER);
8718
+ if (!message) return;
8719
+ const id = response.headers.get(DEPRECATION_ID_HEADER) ?? message;
8720
+ if (!displayedNoticeIds.has(id)) {
8721
+ displayedNoticeIds.add(id);
8722
+ console.warn(`[zapier-sdk] Deprecation: ${message}`);
8723
+ }
8724
+ if (onEvent) {
8725
+ const payload = { id, message };
8726
+ const deprecation = parseDeprecationDate(
8727
+ response.headers.get("deprecation")
8728
+ );
8729
+ if (deprecation !== void 0) payload.deprecation = deprecation;
8730
+ const maybePromise = onEvent({
8731
+ type: DEPRECATION_NOTICE_EVENT,
8732
+ payload: { ...payload },
8733
+ timestamp: Date.now()
8734
+ });
8735
+ if (isPromiseLike(maybePromise)) {
8736
+ void Promise.resolve(maybePromise).catch(() => {
8737
+ });
8738
+ }
8739
+ }
8740
+ }
8741
+ function isPromiseLike(value) {
8742
+ return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
8743
+ }
8744
+ function parseDeprecationDate(value) {
8745
+ if (!value) return void 0;
8746
+ const match = /^@(-?\d+)$/.exec(value.trim());
8747
+ if (!match) return void 0;
8748
+ return Number(match[1]) * 1e3;
8749
+ }
8750
+
7856
8751
  // src/sdk-version.ts
7857
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.78.0" : void 0) || "unknown";
8752
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.80.0" : void 0) || "unknown";
7858
8753
 
7859
8754
  // src/utils/open-url.ts
7860
8755
  var nodePrefix = "node:";
@@ -7966,6 +8861,30 @@ var PollApprovalResponseSchema = zod.z.object({
7966
8861
  reason: zod.z.string().optional()
7967
8862
  });
7968
8863
  var APPROVAL_MAX_POLLING_INTERVAL_MS = 5e3;
8864
+ function validateSdkPath(path) {
8865
+ if (!path.startsWith("/") || path.startsWith("//")) {
8866
+ throw new ZapierValidationError(
8867
+ `fetch expects a path starting with a single '/', got: ${path}`
8868
+ );
8869
+ }
8870
+ }
8871
+ function findPathConfigEntries({
8872
+ path,
8873
+ matchResolvedGatewayPath = false
8874
+ }) {
8875
+ const pathSegments = path.split("/").filter(Boolean);
8876
+ return Object.entries(pathConfig).filter(([configPath, config]) => {
8877
+ if (!matchResolvedGatewayPath) {
8878
+ return path === configPath || path.startsWith(`${configPath}/`);
8879
+ }
8880
+ const prefixSegments = (config.pathPrefix ?? configPath).split("/").filter(Boolean);
8881
+ return pathSegments.some(
8882
+ (_, startIndex) => prefixSegments.every(
8883
+ (segment, offset) => pathSegments[startIndex + offset] === segment
8884
+ )
8885
+ );
8886
+ }).map(([configPath, config]) => ({ configPath, config }));
8887
+ }
7969
8888
  function parseRateLimitHeaders(response) {
7970
8889
  const info = {};
7971
8890
  const retryAfter = response.headers.get("retry-after");
@@ -8010,8 +8929,18 @@ var pathConfig = {
8010
8929
  // e.g. /relay -> https://sdkapi.zapier.com/api/v0/sdk/relay/...
8011
8930
  "/relay": {
8012
8931
  authHeader: "X-Relay-Authorization",
8013
- pathPrefix: "/api/v0/sdk/relay"
8932
+ pathPrefix: "/api/v0/sdk/relay",
8933
+ omitDeprecationMessaging: true
8934
+ },
8935
+ // The concrete gateway form of the relay route. Callers that pass the
8936
+ // already-prefixed path reach the same third-party upstreams, so it must
8937
+ // classify as relay too; without this entry it would match nothing and
8938
+ // sniff deprecation headers off a relay response.
8939
+ "/api/v0/sdk/relay": {
8940
+ omitDeprecationMessaging: true
8014
8941
  },
8942
+ // Concrete sdkapi routes that do not live behind /api/v0/sdk/<service>.
8943
+ "/api/v0": {},
8015
8944
  // e.g. /zapier -> https://sdkapi.zapier.com/api/v0/sdk/zapier/...
8016
8945
  "/zapier": {
8017
8946
  authHeader: "Authorization",
@@ -8066,11 +8995,11 @@ var ZapierApiClient = class {
8066
8995
  );
8067
8996
  const inputHeaders = new Headers(init?.headers ?? {});
8068
8997
  const mergedHeaders = new Headers();
8069
- builtHeaders.forEach((value, key) => {
8070
- mergedHeaders.set(key, value);
8998
+ builtHeaders.forEach((value, key2) => {
8999
+ mergedHeaders.set(key2, value);
8071
9000
  });
8072
- inputHeaders.forEach((value, key) => {
8073
- mergedHeaders.set(key, value);
9001
+ inputHeaders.forEach((value, key2) => {
9002
+ mergedHeaders.set(key2, value);
8074
9003
  });
8075
9004
  this.applyTelemetryHeaders(mergedHeaders);
8076
9005
  let retries = 0;
@@ -8160,17 +9089,50 @@ var ZapierApiClient = class {
8160
9089
  * parallelism into the queue.
8161
9090
  */
8162
9091
  this.rawFetch = async (path, init) => {
8163
- if (!path.startsWith("/")) {
8164
- throw new ZapierValidationError(
8165
- `fetch expects a path starting with '/', got: ${path}`
8166
- );
8167
- }
9092
+ validateSdkPath(path);
8168
9093
  const { url, pathConfig: pathConfig2 } = this.buildUrl(path, init?.searchParams);
8169
9094
  return this.withSemaphore(
8170
9095
  { url, method: init?.method ?? "GET", signal: init?.signal },
8171
9096
  () => this.rawFetchUrl(url, init, pathConfig2)
8172
9097
  );
8173
9098
  };
9099
+ this.runApprovalFetchLoop = async ({
9100
+ path,
9101
+ init,
9102
+ maxRetries,
9103
+ approvalMode,
9104
+ approvalContext
9105
+ }) => {
9106
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
9107
+ const response = await this.rawFetch(path, init);
9108
+ if (response.status !== 403) {
9109
+ return { response };
9110
+ }
9111
+ const errorType = response.headers.get("x-zapier-error-type");
9112
+ if (errorType !== "approval_required") {
9113
+ return { response };
9114
+ }
9115
+ if (attempt === maxRetries) {
9116
+ return { response };
9117
+ }
9118
+ if (approvalMode === "disabled") {
9119
+ return { response };
9120
+ }
9121
+ if (!approvalContext) {
9122
+ return { response };
9123
+ }
9124
+ try {
9125
+ await this.runOneApprovalRound(
9126
+ approvalContext,
9127
+ approvalMode,
9128
+ init?.signal ?? void 0
9129
+ );
9130
+ } catch (error) {
9131
+ return { response, approvalRoundError: error };
9132
+ }
9133
+ }
9134
+ throw new ZapierApiError("Approval retry loop ended unexpectedly");
9135
+ };
8174
9136
  /**
8175
9137
  * Approval-aware HTTP fetch.
8176
9138
  *
@@ -8200,46 +9162,62 @@ var ZapierApiClient = class {
8200
9162
  * `max_retries_exceeded` instead.
8201
9163
  */
8202
9164
  this.fetch = async (path, init) => {
9165
+ validateSdkPath(path);
8203
9166
  const maxRetries = this.options.maxApprovalRetries ?? DEFAULT_MAX_APPROVAL_RETRIES;
8204
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
8205
- const response = await this.rawFetch(path, init);
8206
- if (response.status !== 403) return response;
8207
- const errorType = response.headers.get("x-zapier-error-type");
8208
- if (errorType === "request_denied_by_policy") {
8209
- const { data } = await this.parseResult(response);
8210
- const { message, errors } = this.parseErrorResponse({
8211
- status: response.status,
8212
- statusText: response.statusText,
8213
- data
8214
- });
8215
- throw new ZapierApprovalError(
8216
- message || "Request explicitly denied by policy",
8217
- {
8218
- status: "policy_denied",
8219
- statusCode: response.status,
8220
- errors
8221
- }
8222
- );
8223
- }
8224
- if (errorType !== "approval_required") return response;
8225
- if (attempt === maxRetries) break;
8226
- const mode = this.options.approvalMode ?? getZapierApprovalMode() ?? getZapierDefaultApprovalMode();
8227
- if (mode === "disabled") {
8228
- throw new ZapierApprovalError(
8229
- "Approvals are disabled. Set approvalMode to 'poll' or 'throw' (or ZAPIER_APPROVAL_MODE) to enable.",
8230
- { status: "approval_required" }
8231
- );
8232
- }
8233
- if (!init?.approvalContext) {
8234
- throw new ZapierApiError(
8235
- `Received 403 approval_required for ${path}, but the caller did not provide an approvalContext builder. Every approval-capable request must pass approvalContext so the SDK can create the approval with the correct policy context.`,
8236
- { statusCode: 403 }
8237
- );
8238
- }
8239
- await this.runOneApprovalRound(
8240
- init.approvalContext,
8241
- mode,
8242
- init.signal ?? void 0
9167
+ const { canSendDeprecationMessaging } = this.buildUrl(
9168
+ path,
9169
+ init?.searchParams
9170
+ );
9171
+ const approvalMode = this.options.approvalMode ?? getZapierApprovalMode() ?? getZapierDefaultApprovalMode();
9172
+ const approvalContext = init?.approvalContext;
9173
+ const { response, approvalRoundError } = await this.runApprovalFetchLoop({
9174
+ path,
9175
+ init,
9176
+ maxRetries,
9177
+ approvalMode,
9178
+ approvalContext
9179
+ });
9180
+ handleDeprecationNotice({
9181
+ response,
9182
+ canSendDeprecationMessaging,
9183
+ onEvent: this.options.onEvent
9184
+ });
9185
+ if (response.status !== 403) {
9186
+ return response;
9187
+ }
9188
+ const errorType = response.headers.get("x-zapier-error-type");
9189
+ if (errorType === "request_denied_by_policy") {
9190
+ const { data } = await this.parseResult(response);
9191
+ const { message, errors } = this.parseErrorResponse({
9192
+ status: response.status,
9193
+ statusText: response.statusText,
9194
+ data
9195
+ });
9196
+ throw new ZapierApprovalError(
9197
+ message || "Request explicitly denied by policy",
9198
+ {
9199
+ status: "policy_denied",
9200
+ statusCode: response.status,
9201
+ errors
9202
+ }
9203
+ );
9204
+ }
9205
+ if (errorType !== "approval_required") {
9206
+ return response;
9207
+ }
9208
+ if (approvalRoundError) {
9209
+ throw approvalRoundError;
9210
+ }
9211
+ if (approvalMode === "disabled") {
9212
+ throw new ZapierApprovalError(
9213
+ "Approvals are disabled. Set approvalMode to 'poll' or 'throw' (or ZAPIER_APPROVAL_MODE) to enable.",
9214
+ { status: "approval_required" }
9215
+ );
9216
+ }
9217
+ if (!approvalContext) {
9218
+ throw new ZapierApiError(
9219
+ `Received 403 approval_required for ${path}, but the caller did not provide an approvalContext builder. Every approval-capable request must pass approvalContext so the SDK can create the approval with the correct policy context.`,
9220
+ { statusCode: 403 }
8243
9221
  );
8244
9222
  }
8245
9223
  throw new ZapierApprovalError(
@@ -8501,40 +9479,60 @@ var ZapierApiClient = class {
8501
9479
  }
8502
9480
  // Apply any special routing logic for configured paths.
8503
9481
  applyPathConfiguration(path) {
8504
- const matchingPathKey = Object.keys(pathConfig).find(
8505
- (configPath) => path === configPath || path.startsWith(configPath + "/")
8506
- );
8507
- const config = matchingPathKey ? pathConfig[matchingPathKey] : void 0;
9482
+ const matchingPathEntries = findPathConfigEntries({ path });
9483
+ const routingMatch = matchingPathEntries[0];
9484
+ const buildResult = (url2) => {
9485
+ const resolvedPathEntries = findPathConfigEntries({
9486
+ path: url2.pathname,
9487
+ matchResolvedGatewayPath: true
9488
+ });
9489
+ const deprecationPathMatches = [
9490
+ ...matchingPathEntries,
9491
+ ...resolvedPathEntries
9492
+ ];
9493
+ const canSendDeprecationMessaging = deprecationPathMatches.length > 0 && deprecationPathMatches.every(
9494
+ ({ config }) => config.omitDeprecationMessaging !== true
9495
+ );
9496
+ return {
9497
+ url: url2,
9498
+ pathConfig: routingMatch?.config,
9499
+ canSendDeprecationMessaging
9500
+ };
9501
+ };
8508
9502
  let finalPath = path;
8509
- if (config && "pathPrefix" in config && config.pathPrefix && matchingPathKey) {
8510
- const pathWithoutPrefix = path.slice(matchingPathKey.length) || "/";
8511
- finalPath = `${config.pathPrefix}${pathWithoutPrefix}`;
9503
+ if (routingMatch?.config.pathPrefix) {
9504
+ const pathWithoutPrefix = path.slice(routingMatch.configPath.length) || "/";
9505
+ finalPath = `${routingMatch.config.pathPrefix}${pathWithoutPrefix}`;
8512
9506
  }
8513
9507
  const zapierBaseUrl = getZapierBaseUrl(this.options.baseUrl);
8514
9508
  if (zapierBaseUrl === this.options.baseUrl.replace(/\/$/, "")) {
8515
9509
  const originalBaseUrl = new URL(this.options.baseUrl);
8516
9510
  const finalBaseUrl = `https://sdkapi.${originalBaseUrl.hostname}`;
8517
- return {
8518
- url: new URL(finalPath, finalBaseUrl),
8519
- pathConfig: config
8520
- };
9511
+ const url2 = new URL(finalPath, finalBaseUrl);
9512
+ return buildResult(url2);
8521
9513
  }
8522
9514
  const baseUrl = new URL(this.options.baseUrl);
8523
9515
  const basePath = baseUrl.pathname.replace(/\/$/, "");
8524
- return {
8525
- url: new URL(basePath + finalPath, baseUrl.origin),
8526
- pathConfig: config
8527
- };
9516
+ const url = new URL(basePath + finalPath, baseUrl.origin);
9517
+ return buildResult(url);
8528
9518
  }
8529
9519
  // Helper to build full URLs and return routing info
8530
9520
  buildUrl(path, searchParams) {
8531
- const { url, pathConfig: config } = this.applyPathConfiguration(path);
9521
+ const {
9522
+ url,
9523
+ pathConfig: config,
9524
+ canSendDeprecationMessaging
9525
+ } = this.applyPathConfiguration(path);
8532
9526
  if (searchParams) {
8533
- Object.entries(searchParams).forEach(([key, value]) => {
8534
- url.searchParams.set(key, value);
9527
+ Object.entries(searchParams).forEach(([key2, value]) => {
9528
+ url.searchParams.set(key2, value);
8535
9529
  });
8536
9530
  }
8537
- return { url: url.toString(), pathConfig: config };
9531
+ return {
9532
+ url: url.toString(),
9533
+ pathConfig: config,
9534
+ canSendDeprecationMessaging
9535
+ };
8538
9536
  }
8539
9537
  // Helper to build headers
8540
9538
  async buildHeaders(options = {}, pathConfig2) {
@@ -9324,36 +10322,36 @@ var createConnectionPlugin = definePlugin(
9324
10322
  sdk: inner,
9325
10323
  options
9326
10324
  }) => {
9327
- const { data: start } = await inner.getConnectionStartUrl({
10325
+ const { data: start2 } = await inner.getConnectionStartUrl({
9328
10326
  app: options.app
9329
10327
  });
9330
- setMethodMetadata({ selectedApi: start.app });
10328
+ setMethodMetadata({ selectedApi: start2.app });
9331
10329
  console.error(
9332
10330
  `
9333
10331
  Open this URL to complete the connection:
9334
- ${start.url}
10332
+ ${start2.url}
9335
10333
  `
9336
10334
  );
9337
10335
  const shouldOpen = options.browser === "always" || options.browser === "auto" && shouldOpenBrowser();
9338
10336
  if (shouldOpen) {
9339
10337
  try {
9340
- await open_url_default(start.url);
10338
+ await open_url_default(start2.url);
9341
10339
  } catch {
9342
10340
  }
9343
10341
  }
9344
10342
  const { data: fresh } = await inner.waitForNewConnection({
9345
- app: start.app,
10343
+ app: start2.app,
9346
10344
  // Server-stamped mint time: measured on the same clock as a
9347
10345
  // connection's `date`, so the freshness check is immune to
9348
10346
  // client/server clock skew.
9349
- startedAt: start.startedAt,
10347
+ startedAt: start2.startedAt,
9350
10348
  timeoutMs: options.timeoutMs,
9351
10349
  pollIntervalMs: options.pollIntervalMs
9352
10350
  });
9353
10351
  return {
9354
10352
  data: CreateConnectionItemSchema.parse({
9355
10353
  id: fresh.id,
9356
- app: start.app,
10354
+ app: start2.app,
9357
10355
  title: fresh.title ?? null
9358
10356
  })
9359
10357
  };
@@ -10289,21 +11287,21 @@ var updateTableRecordsPlugin = definePlugin(
10289
11287
  );
10290
11288
 
10291
11289
  // src/plugins/capabilities/index.ts
10292
- function toDescription(key) {
10293
- const words = key.replace(/^can/, "").replace(/([A-Z])/g, " $1").trim().toLowerCase();
11290
+ function toDescription(key2) {
11291
+ const words = key2.replace(/^can/, "").replace(/([A-Z])/g, " $1").trim().toLowerCase();
10294
11292
  return `To ${words}`;
10295
11293
  }
10296
- function toEnvVar(key) {
10297
- return "ZAPIER_" + key.replace(/([A-Z])/g, "_$1").toUpperCase();
11294
+ function toEnvVar(key2) {
11295
+ return "ZAPIER_" + key2.replace(/([A-Z])/g, "_$1").toUpperCase();
10298
11296
  }
10299
- function toCliFlag(key) {
10300
- return "--" + key.replace(/([A-Z])/g, "-$1").toLowerCase();
11297
+ function toCliFlag(key2) {
11298
+ return "--" + key2.replace(/([A-Z])/g, "-$1").toLowerCase();
10301
11299
  }
10302
- function buildCapabilityMessage(key) {
11300
+ function buildCapabilityMessage(key2) {
10303
11301
  return [
10304
- `${toDescription(key)}, use ${toCliFlag(key)} in the CLI,`,
10305
- `set ${key}: true in SDK options or .zapierrc,`,
10306
- `or set ${toEnvVar(key)}=true.`
11302
+ `${toDescription(key2)}, use ${toCliFlag(key2)} in the CLI,`,
11303
+ `set ${key2}: true in SDK options or .zapierrc,`,
11304
+ `or set ${toEnvVar(key2)}=true.`
10307
11305
  ].join(" ");
10308
11306
  }
10309
11307
  var GATED_FLAGS = [
@@ -10311,8 +11309,8 @@ var GATED_FLAGS = [
10311
11309
  "canIncludeSharedTables",
10312
11310
  "canDeleteTables"
10313
11311
  ];
10314
- function isEnabledByEnv(key) {
10315
- const value = globalThis.process?.env?.[toEnvVar(key)];
11312
+ function isEnabledByEnv(key2) {
11313
+ const value = globalThis.process?.env?.[toEnvVar(key2)];
10316
11314
  if (value === void 0) return void 0;
10317
11315
  if (value === "true" || value === "1") return true;
10318
11316
  if (value === "false" || value === "0") return false;
@@ -10335,17 +11333,17 @@ var capabilitiesPlugin = definePlugin(
10335
11333
  }
10336
11334
  return {
10337
11335
  context: {
10338
- checkCapability: async (key) => {
11336
+ checkCapability: async (key2) => {
10339
11337
  const flags = await resolveFlags();
10340
- if (flags[key]) return;
11338
+ if (flags[key2]) return;
10341
11339
  throw new ZapierConfigurationError(
10342
- buildCapabilityMessage(key) + " (If you are an AI agent, you MUST NOT retry. Ask the user if they want to enable this.)",
10343
- { configType: key }
11340
+ buildCapabilityMessage(key2) + " (If you are an AI agent, you MUST NOT retry. Ask the user if they want to enable this.)",
11341
+ { configType: key2 }
10344
11342
  );
10345
11343
  },
10346
- hasCapability: async (key) => {
11344
+ hasCapability: async (key2) => {
10347
11345
  const flags = await resolveFlags();
10348
- return flags[key];
11346
+ return flags[key2];
10349
11347
  }
10350
11348
  }
10351
11349
  };
@@ -10503,8 +11501,8 @@ function getOsInfo() {
10503
11501
  function getPlatformVersions() {
10504
11502
  const versions = {};
10505
11503
  if (typeof globalThis.process?.versions === "object") {
10506
- for (const [key, value] of Object.entries(globalThis.process.versions)) {
10507
- versions[key] = value || null;
11504
+ for (const [key2, value] of Object.entries(globalThis.process.versions)) {
11505
+ versions[key2] = value || null;
10508
11506
  }
10509
11507
  }
10510
11508
  return versions;
@@ -10746,9 +11744,9 @@ async function emitWithTimeout(transport, subject, event) {
10746
11744
  }
10747
11745
  function mergeUserContext(event, userContext) {
10748
11746
  const merged = { ...event };
10749
- for (const [key, value] of Object.entries(userContext)) {
10750
- if (merged[key] == null) {
10751
- merged[key] = value;
11747
+ for (const [key2, value] of Object.entries(userContext)) {
11748
+ if (merged[key2] == null) {
11749
+ merged[key2] = value;
10752
11750
  }
10753
11751
  }
10754
11752
  return merged;
@@ -11264,13 +12262,16 @@ exports.BaseSdkOptionsSchema = BaseSdkOptionsSchema;
11264
12262
  exports.CONTEXT_CACHE_MAX_SIZE = CONTEXT_CACHE_MAX_SIZE;
11265
12263
  exports.CONTEXT_CACHE_TTL_MS = CONTEXT_CACHE_TTL_MS;
11266
12264
  exports.CORE_ERROR_SYMBOL = CORE_ERROR_SYMBOL;
12265
+ exports.CORE_SIGNAL_SYMBOL = CORE_SIGNAL_SYMBOL;
11267
12266
  exports.ClientCredentialsObjectSchema = ClientCredentialsObjectSchema;
11268
12267
  exports.ConnectionEntrySchema = ConnectionEntrySchema;
11269
12268
  exports.ConnectionIdPropertySchema = ConnectionIdPropertySchema;
11270
12269
  exports.ConnectionPropertySchema = ConnectionPropertySchema;
11271
12270
  exports.ConnectionsMapSchema = ConnectionsMapSchema;
11272
12271
  exports.ConnectionsPropertySchema = ConnectionsPropertySchema;
12272
+ exports.CoreCancelledSignal = CoreCancelledSignal;
11273
12273
  exports.CoreErrorCode = CoreErrorCode;
12274
+ exports.CoreSignal = CoreSignal;
11274
12275
  exports.CredentialsFunctionSchema = CredentialsFunctionSchema;
11275
12276
  exports.CredentialsObjectSchema = CredentialsObjectSchema;
11276
12277
  exports.CredentialsSchema = CredentialsSchema;
@@ -11279,6 +12280,7 @@ exports.DEFAULT_APPROVAL_TIMEOUT_MS = DEFAULT_APPROVAL_TIMEOUT_MS;
11279
12280
  exports.DEFAULT_CONFIG_PATH = DEFAULT_CONFIG_PATH;
11280
12281
  exports.DEFAULT_MAX_APPROVAL_RETRIES = DEFAULT_MAX_APPROVAL_RETRIES;
11281
12282
  exports.DEFAULT_PAGE_SIZE = DEFAULT_PAGE_SIZE;
12283
+ exports.DEPRECATION_NOTICE_EVENT = DEPRECATION_NOTICE_EVENT;
11282
12284
  exports.DebugPropertySchema = DebugPropertySchema;
11283
12285
  exports.FieldsPropertySchema = FieldsPropertySchema;
11284
12286
  exports.InputFieldPropertySchema = InputFieldPropertySchema;
@@ -11349,6 +12351,7 @@ exports.connectionIdResolver = connectionIdResolver;
11349
12351
  exports.connectionsPlugin = connectionsPlugin;
11350
12352
  exports.createBaseEvent = createBaseEvent;
11351
12353
  exports.createClientCredentialsPlugin = createClientCredentialsPlugin;
12354
+ exports.createController = createController;
11352
12355
  exports.createCorePlugin = createCorePlugin;
11353
12356
  exports.createFunction = createFunction;
11354
12357
  exports.createMemoryCache = createMemoryCache;
@@ -11372,6 +12375,7 @@ exports.defineLegacyMerge = defineLegacyMerge;
11372
12375
  exports.defineMethod = defineMethod;
11373
12376
  exports.definePlugin = definePlugin;
11374
12377
  exports.defineProperty = defineProperty;
12378
+ exports.defineResolver = defineResolver;
11375
12379
  exports.deleteClientCredentialsPlugin = deleteClientCredentialsPlugin;
11376
12380
  exports.deleteTableFieldsPlugin = deleteTableFieldsPlugin;
11377
12381
  exports.deleteTablePlugin = deleteTablePlugin;
@@ -11424,6 +12428,7 @@ exports.isCi = isCi;
11424
12428
  exports.isCliLoginAvailable = isCliLoginAvailable;
11425
12429
  exports.isClientCredentials = isClientCredentials;
11426
12430
  exports.isCoreError = isCoreError;
12431
+ exports.isCoreSignal = isCoreSignal;
11427
12432
  exports.isCredentialsFunction = isCredentialsFunction;
11428
12433
  exports.isCredentialsObject = isCredentialsObject;
11429
12434
  exports.isPermanentHttpError = isPermanentHttpError;