@zapier/zapier-sdk 0.84.2 → 0.84.3

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.mjs CHANGED
@@ -201,7 +201,8 @@ function getCoreErrorCause(value) {
201
201
  var CURSOR_VERSION = 1;
202
202
  var CURSOR_SOURCE = {
203
203
  API: "api",
204
- SDK: "sdk"
204
+ SDK: "sdk",
205
+ CONCAT: "concat"
205
206
  };
206
207
  function encodeBase64(str) {
207
208
  return btoa(
@@ -385,10 +386,32 @@ async function* paginateBuffered(pageFunction, pageOptions) {
385
386
  }
386
387
  }
387
388
  var paginate = paginateBuffered;
389
+ function encodeConcatCursor(index, cursor) {
390
+ const envelope = {
391
+ v: CURSOR_VERSION,
392
+ source: CURSOR_SOURCE.CONCAT,
393
+ index,
394
+ cursor
395
+ };
396
+ return encodeBase64(JSON.stringify(envelope));
397
+ }
398
+ function decodeConcatCursor(incoming) {
399
+ if (!incoming) {
400
+ return { index: 0, cursor: void 0 };
401
+ }
402
+ try {
403
+ const envelope = JSON.parse(decodeBase64(incoming));
404
+ if (envelope.v === CURSOR_VERSION && envelope.source === CURSOR_SOURCE.CONCAT && typeof envelope.index === "number") {
405
+ return { index: envelope.index, cursor: envelope.cursor };
406
+ }
407
+ } catch {
408
+ }
409
+ return { index: 0, cursor: incoming };
410
+ }
388
411
  function concatPaginated({
389
412
  sources,
390
- dedupe,
391
- pageSize = 100
413
+ pageSize = 100,
414
+ cursor
392
415
  }) {
393
416
  if (sources.length === 0) {
394
417
  const empty = { data: [] };
@@ -398,40 +421,24 @@ function concatPaginated({
398
421
  }
399
422
  });
400
423
  }
401
- let sourceIndex = 0;
402
- let currentIterator = null;
403
- const seen = /* @__PURE__ */ new Set();
404
- const pageFunction = async (_options) => {
405
- while (sourceIndex < sources.length) {
406
- if (!currentIterator) {
407
- const result = sources[sourceIndex]();
408
- currentIterator = result[Symbol.asyncIterator]();
409
- }
410
- const next = await currentIterator.next();
411
- if (next.done) {
412
- sourceIndex++;
413
- currentIterator = null;
424
+ const pageFunction = async (options) => {
425
+ let { index, cursor: sourceCursor } = decodeConcatCursor(options.cursor);
426
+ 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) {
430
+ index++;
431
+ sourceCursor = void 0;
414
432
  continue;
415
433
  }
416
- let items = next.value.data;
417
- if (dedupe) {
418
- if (sourceIndex > 0) {
419
- items = items.filter((item) => !seen.has(dedupe(item)));
420
- }
421
- for (const item of items) {
422
- seen.add(dedupe(item));
423
- }
424
- }
425
- const hasMoreInSource = next.value.nextCursor != null;
426
- const hasMoreSources = sourceIndex < sources.length - 1;
427
434
  return {
428
- data: items,
429
- nextCursor: hasMoreInSource || hasMoreSources ? "__has_more__" : void 0
435
+ data: page.data,
436
+ nextCursor: hasMoreInSource ? encodeConcatCursor(index, page.nextCursor) : index < sources.length - 1 ? encodeConcatCursor(index + 1, void 0) : void 0
430
437
  };
431
438
  }
432
439
  return { data: [] };
433
440
  };
434
- const iterator = paginateBuffered(pageFunction, { pageSize });
441
+ const iterator = paginateBuffered(pageFunction, { pageSize, cursor });
435
442
  const firstPagePromise = iterator.next().then((result) => {
436
443
  if (result.done) {
437
444
  return { data: [] };
@@ -1283,6 +1290,7 @@ function defineResolver(config) {
1283
1290
  getContext: config.getContext,
1284
1291
  listItems: config.listItems,
1285
1292
  prompt: config.prompt,
1293
+ validate: config.validate,
1286
1294
  tryResolveWithoutPrompt: config.tryResolveWithoutPrompt,
1287
1295
  tryResolveFromSearch: config.tryResolveFromSearch
1288
1296
  };
@@ -1928,6 +1936,7 @@ function bindResolver(resolver, plugins) {
1928
1936
  const {
1929
1937
  getContext: getContext2,
1930
1938
  listItems,
1939
+ validate,
1931
1940
  tryResolveWithoutPrompt,
1932
1941
  tryResolveFromSearch
1933
1942
  } = resolver;
@@ -1941,6 +1950,9 @@ function bindResolver(resolver, plugins) {
1941
1950
  };
1942
1951
  if (getContext2)
1943
1952
  bound.getContext = ({ input }) => getContext2({ imports, input });
1953
+ if (validate) {
1954
+ bound.validate = ({ value, input, context }) => validate({ imports, value, input, context });
1955
+ }
1944
1956
  if (tryResolveWithoutPrompt) {
1945
1957
  bound.tryResolveWithoutPrompt = ({ input }) => tryResolveWithoutPrompt({ imports, input });
1946
1958
  }
@@ -2609,14 +2621,14 @@ function coerce(leaf, raw) {
2609
2621
  }
2610
2622
  async function validationError(leaf, value, state) {
2611
2623
  if (leaf.resolver?.type !== "dynamic") return null;
2624
+ const validate = leaf.resolver.validate;
2625
+ if (!validate) return null;
2612
2626
  const context = await resolveContext(leaf, state.resolved);
2613
- const config = leaf.resolver.prompt?.({
2614
- items: state.listing?.items ?? [],
2627
+ const verdict = await validate({
2628
+ value,
2615
2629
  input: mergeInput(state.resolved, leaf.extraInput),
2616
2630
  context
2617
2631
  });
2618
- if (!config?.validate) return null;
2619
- const verdict = config.validate(value);
2620
2632
  if (verdict === true) return null;
2621
2633
  return typeof verdict === "string" ? verdict : `${leaf.name}: invalid value`;
2622
2634
  }
@@ -2742,20 +2754,36 @@ async function resolveContext(leaf, input) {
2742
2754
  input: mergeInput(input, leaf.extraInput)
2743
2755
  });
2744
2756
  }
2745
- async function fetchListing(leaf, input, opts = {}) {
2757
+ function firstPagePosition(opts = {}) {
2758
+ return {
2759
+ ...opts.search !== void 0 ? { search: opts.search } : {},
2760
+ pageCursor: null,
2761
+ previousCursors: [],
2762
+ generation: opts.generation ?? 0
2763
+ };
2764
+ }
2765
+ async function fetchListing(leaf, input, position, context) {
2766
+ if (leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search" && position.search === void 0) {
2767
+ return { position, items: [] };
2768
+ }
2746
2769
  const page = await firstPage(
2747
2770
  leaf.resolver?.type === "dynamic" ? leaf.resolver.listItems({
2748
2771
  input: mergeInput(input, leaf.extraInput),
2749
- context: opts.context,
2750
- search: opts.search,
2751
- cursor: opts.cursor
2772
+ context,
2773
+ search: position.search,
2774
+ cursor: position.pageCursor ?? void 0
2752
2775
  }) : void 0
2753
2776
  );
2754
2777
  return {
2755
- items: [...opts.priorItems ?? [], ...page.data],
2756
- cursor: page.nextCursor,
2757
- search: opts.search,
2758
- exhausted: page.nextCursor == null
2778
+ position,
2779
+ items: page.data,
2780
+ ...page.nextCursor != null ? { nextCursor: page.nextCursor } : {}
2781
+ };
2782
+ }
2783
+ function toPagination(page) {
2784
+ return {
2785
+ position: page.position,
2786
+ ...page.nextCursor !== void 0 ? { nextCursor: page.nextCursor } : {}
2759
2787
  };
2760
2788
  }
2761
2789
  function toChoice(c) {
@@ -2775,23 +2803,32 @@ var AFFORDANCE = {
2775
2803
  description: "Filter the options by a search term",
2776
2804
  supply: "term"
2777
2805
  },
2778
- more: { action: "more", description: "Load more options" },
2806
+ nextPage: {
2807
+ action: "next_page",
2808
+ description: "Fetch the next page of options"
2809
+ },
2810
+ previousPage: {
2811
+ action: "previous_page",
2812
+ description: "Return to the previous page of options"
2813
+ },
2779
2814
  skip: { action: "skip", description: "Omit this optional parameter" },
2780
2815
  add: { action: "add", description: "Add another item" },
2781
2816
  done: { action: "done", description: "Finish the list" },
2782
2817
  retry: { action: "retry", description: "Retry loading the options" },
2783
2818
  cancel: { action: "cancel", description: "Cancel resolution" }
2784
2819
  };
2785
- function selectActions(leaf, listing, multiple) {
2820
+ function selectActions(leaf, page, multiple) {
2786
2821
  const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
2787
- if (searchMode && listing.search === void 0 && listing.items.length === 0) {
2822
+ if (searchMode && page.position.search === void 0 && page.items.length === 0) {
2788
2823
  const actions2 = multiple ? [AFFORDANCE.search] : [AFFORDANCE.search, AFFORDANCE.custom];
2789
2824
  if (!leaf.required) actions2.push(AFFORDANCE.skip);
2790
2825
  return actions2;
2791
2826
  }
2792
2827
  const actions = multiple ? [AFFORDANCE.choose] : [AFFORDANCE.choose, AFFORDANCE.custom];
2793
2828
  if (searchMode) actions.push(AFFORDANCE.search);
2794
- if (listing.cursor) actions.push(AFFORDANCE.more);
2829
+ if (page.nextCursor) actions.push(AFFORDANCE.nextPage);
2830
+ if (page.position.previousCursors.length > 0)
2831
+ actions.push(AFFORDANCE.previousPage);
2795
2832
  if (!leaf.required) actions.push(AFFORDANCE.skip);
2796
2833
  return actions;
2797
2834
  }
@@ -2799,16 +2836,17 @@ function labeledMessage(leaf) {
2799
2836
  if (!leaf.label) return void 0;
2800
2837
  return `${leaf.label} (${leaf.required ? "required" : "optional"}):`;
2801
2838
  }
2802
- function selectQuestion(leaf, input, listing, context) {
2839
+ function selectQuestion(leaf, path, input, page, context) {
2803
2840
  const resolver = leaf.resolver?.type === "dynamic" ? leaf.resolver : void 0;
2804
2841
  const config = resolver?.prompt?.({
2805
- items: listing.items,
2842
+ items: page.items,
2806
2843
  input: mergeInput(input, leaf.extraInput),
2807
2844
  context
2808
2845
  });
2809
2846
  const multiple = config?.type === "checkbox";
2810
2847
  return {
2811
2848
  type: "select",
2849
+ path,
2812
2850
  // A labeled field's title beats the resolver's message: per-field
2813
2851
  // resolvers are shared across fields (one choices-fetcher for every
2814
2852
  // field), so only the leaf knows which field is being asked.
@@ -2816,9 +2854,13 @@ function selectQuestion(leaf, input, listing, context) {
2816
2854
  choices: (config?.choices ?? []).map(toChoice),
2817
2855
  ...multiple ? { multiple: true } : {},
2818
2856
  ...config?.notes?.length ? { notes: config.notes } : {},
2819
- ...listing.search !== void 0 ? { search: listing.search } : {},
2857
+ ...page.position.search !== void 0 ? { search: page.position.search } : {},
2820
2858
  ...resolver?.placeholder ? { placeholder: resolver.placeholder } : {},
2821
- actions: selectActions(leaf, listing, multiple)
2859
+ page: {
2860
+ generation: page.position.generation,
2861
+ index: page.position.previousCursors.length
2862
+ },
2863
+ actions: selectActions(leaf, page, multiple)
2822
2864
  };
2823
2865
  }
2824
2866
  function toControllerError(error) {
@@ -2840,6 +2882,7 @@ function failedResult(state, name, error) {
2840
2882
  error: toControllerError(error),
2841
2883
  question: {
2842
2884
  type: "select",
2885
+ path: state.current ?? [],
2843
2886
  message: `Could not load options for ${name}.`,
2844
2887
  choices: [],
2845
2888
  actions: [AFFORDANCE.retry, AFFORDANCE.cancel]
@@ -2847,27 +2890,15 @@ function failedResult(state, name, error) {
2847
2890
  }
2848
2891
  };
2849
2892
  }
2850
- async function buildQuestion(leaf, input) {
2893
+ async function buildQuestion(leaf, path, input) {
2851
2894
  const optional = !leaf.required;
2852
2895
  const resolver = leaf.resolver;
2853
2896
  if (resolver?.type === "dynamic") {
2854
2897
  const context = await resolveContext(leaf, input);
2855
- if (resolver.inputType === "search") {
2856
- const listing2 = {
2857
- items: [],
2858
- cursor: void 0,
2859
- search: void 0,
2860
- exhausted: true
2861
- };
2862
- return {
2863
- question: selectQuestion(leaf, input, listing2, context),
2864
- listing: listing2
2865
- };
2866
- }
2867
- const listing = await fetchListing(leaf, input, { context });
2898
+ const page = await fetchListing(leaf, input, firstPagePosition(), context);
2868
2899
  return {
2869
- question: selectQuestion(leaf, input, listing, context),
2870
- listing
2900
+ question: selectQuestion(leaf, path, input, page, context),
2901
+ pagination: toPagination(page)
2871
2902
  };
2872
2903
  }
2873
2904
  if (leaf.staticChoices) {
@@ -2876,6 +2907,7 @@ async function buildQuestion(leaf, input) {
2876
2907
  return {
2877
2908
  question: {
2878
2909
  type: "select",
2910
+ path,
2879
2911
  message: `Select ${leaf.name}:`,
2880
2912
  choices: leaf.staticChoices,
2881
2913
  actions: actions2
@@ -2889,6 +2921,7 @@ async function buildQuestion(leaf, input) {
2889
2921
  return {
2890
2922
  question: {
2891
2923
  type: "input",
2924
+ path,
2892
2925
  // The optional marker makes Enter-to-pass discoverable on a bare
2893
2926
  // parameter; a labeled field carries its marker via labeledMessage.
2894
2927
  message: labeledMessage(leaf) ?? `Enter ${leaf.name}${optional ? " (optional)" : ""}:`,
@@ -2903,6 +2936,7 @@ function collectionQuestion(t) {
2903
2936
  if (t.count >= t.min) actions.push(AFFORDANCE.done);
2904
2937
  return {
2905
2938
  type: "collection",
2939
+ path: t.path,
2906
2940
  message: `Add ${t.path[t.path.length - 1]}[${t.count}]?`,
2907
2941
  container: "array",
2908
2942
  count: t.count,
@@ -2916,6 +2950,7 @@ function collectionQuestion(t) {
2916
2950
  function objectGateQuestion(path) {
2917
2951
  return {
2918
2952
  type: "collection",
2953
+ path,
2919
2954
  message: `Add ${path[path.length - 1]}?`,
2920
2955
  container: "object",
2921
2956
  actions: [
@@ -2927,9 +2962,10 @@ function objectGateQuestion(path) {
2927
2962
  ]
2928
2963
  };
2929
2964
  }
2930
- function optionalsGateQuestion(pending) {
2965
+ function optionalsGateQuestion(path, pending) {
2931
2966
  return {
2932
2967
  type: "collection",
2968
+ path,
2933
2969
  // The prompt and its context ride separately so a host renders the info
2934
2970
  // line above the confirm without composing any text of its own.
2935
2971
  message: "Would you like to configure optional fields?",
@@ -3077,8 +3113,12 @@ async function askLeaf(state, path, leaf, opts = {}) {
3077
3113
  state.current = path;
3078
3114
  delete state.gate;
3079
3115
  try {
3080
- const { question, listing } = await buildQuestion(leaf, state.resolved);
3081
- state.listing = listing;
3116
+ const { question, pagination } = await buildQuestion(
3117
+ leaf,
3118
+ path,
3119
+ state.resolved
3120
+ );
3121
+ state.pagination = pagination;
3082
3122
  return {
3083
3123
  state,
3084
3124
  result: {
@@ -3088,7 +3128,7 @@ async function askLeaf(state, path, leaf, opts = {}) {
3088
3128
  }
3089
3129
  };
3090
3130
  } catch (error) {
3091
- state.listing = { items: [], exhausted: false };
3131
+ state.pagination = failedPagination(void 0, firstPagePosition());
3092
3132
  return failedResult(state, leaf.name, error);
3093
3133
  }
3094
3134
  }
@@ -3098,13 +3138,13 @@ async function advance(ctx, state) {
3098
3138
  if (!target) {
3099
3139
  delete state.current;
3100
3140
  delete state.gate;
3101
- delete state.listing;
3141
+ delete state.pagination;
3102
3142
  return { state, result: finalize(ctx, state.resolved) };
3103
3143
  }
3104
3144
  if (target.kind === "array") {
3105
3145
  state.current = target.path;
3106
3146
  state.gate = "array";
3107
- delete state.listing;
3147
+ delete state.pagination;
3108
3148
  return {
3109
3149
  state,
3110
3150
  result: { status: "ask", question: collectionQuestion(target) }
@@ -3113,7 +3153,7 @@ async function advance(ctx, state) {
3113
3153
  if (target.kind === "object") {
3114
3154
  state.current = target.path;
3115
3155
  state.gate = "entry";
3116
- delete state.listing;
3156
+ delete state.pagination;
3117
3157
  return {
3118
3158
  state,
3119
3159
  result: { status: "ask", question: objectGateQuestion(target.path) }
@@ -3122,12 +3162,12 @@ async function advance(ctx, state) {
3122
3162
  if (target.kind === "optionals") {
3123
3163
  state.current = target.path;
3124
3164
  state.gate = "optionals";
3125
- delete state.listing;
3165
+ delete state.pagination;
3126
3166
  return {
3127
3167
  state,
3128
3168
  result: {
3129
3169
  status: "ask",
3130
- question: optionalsGateQuestion(target.pending)
3170
+ question: optionalsGateQuestion(target.path, target.pending)
3131
3171
  }
3132
3172
  };
3133
3173
  }
@@ -3178,13 +3218,13 @@ async function step(ctx, prior, action) {
3178
3218
  if (action.type === "cancel") {
3179
3219
  delete state.current;
3180
3220
  delete state.gate;
3181
- delete state.listing;
3221
+ delete state.pagination;
3182
3222
  return { state, result: { status: "cancelled" } };
3183
3223
  }
3184
3224
  const path = state.current;
3185
3225
  if (!path) throw new Error("step called with no outstanding question");
3186
3226
  const leaf = await leafAt(ctx, path, state.resolved);
3187
- if (leaf && (action.type === "search" || action.type === "more" || action.type === "retry")) {
3227
+ if (leaf && (action.type === "search" || action.type === "next_page" || action.type === "previous_page" || action.type === "retry")) {
3188
3228
  return refine(ctx, state, leaf, path, action);
3189
3229
  }
3190
3230
  if (action.type === "add" || action.type === "done") {
@@ -3196,7 +3236,7 @@ async function step(ctx, prior, action) {
3196
3236
  }
3197
3237
  delete state.current;
3198
3238
  delete state.gate;
3199
- delete state.listing;
3239
+ delete state.pagination;
3200
3240
  if (action.type === "done") {
3201
3241
  settle(state, path);
3202
3242
  return advance(ctx, state);
@@ -3225,23 +3265,44 @@ async function step(ctx, prior, action) {
3225
3265
  case "choose":
3226
3266
  case "custom": {
3227
3267
  if (leaf) {
3228
- const error = await validationError(leaf, action.value, state);
3268
+ let error;
3269
+ try {
3270
+ error = await validationError(leaf, action.value, state);
3271
+ } catch (thrown) {
3272
+ return failedResult(state, leaf.name, thrown);
3273
+ }
3229
3274
  if (error) {
3230
- if (state.listing && leaf.resolver?.type === "dynamic") {
3231
- const context = await resolveContext(leaf, state.resolved);
3232
- return {
3233
- state,
3234
- result: {
3235
- status: "ask",
3236
- question: selectQuestion(
3237
- leaf,
3238
- state.resolved,
3239
- state.listing,
3240
- context
3241
- ),
3242
- error
3243
- }
3244
- };
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
+ }
3245
3306
  }
3246
3307
  return askLeaf(state, path, leaf, { error });
3247
3308
  }
@@ -3260,15 +3321,11 @@ async function step(ctx, prior, action) {
3260
3321
  throw new Error(`action "${action.type}" is not supported here`);
3261
3322
  }
3262
3323
  delete state.current;
3263
- delete state.listing;
3324
+ delete state.pagination;
3264
3325
  return advance(ctx, state);
3265
3326
  }
3266
3327
  async function refine(ctx, state, leaf, path, action) {
3267
- const attempt = action.type === "search" ? { search: action.term, cursor: void 0, priorItems: [] } : {
3268
- search: state.listing?.search,
3269
- cursor: state.listing?.cursor,
3270
- priorItems: state.listing?.items ?? []
3271
- };
3328
+ const position = positionAfter(state.pagination, action);
3272
3329
  try {
3273
3330
  if (action.type === "search") {
3274
3331
  const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
@@ -3278,32 +3335,62 @@ async function refine(ctx, state, leaf, path, action) {
3278
3335
  if (exact) {
3279
3336
  setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
3280
3337
  delete state.current;
3281
- delete state.listing;
3338
+ delete state.pagination;
3282
3339
  return advance(ctx, state);
3283
3340
  }
3284
3341
  }
3285
3342
  const context = await resolveContext(leaf, state.resolved);
3286
- state.listing = await fetchListing(leaf, state.resolved, {
3287
- ...attempt,
3288
- context
3289
- });
3343
+ const page = await fetchListing(leaf, state.resolved, position, context);
3344
+ state.pagination = toPagination(page);
3290
3345
  return {
3291
3346
  state,
3292
3347
  result: {
3293
3348
  status: "ask",
3294
- question: selectQuestion(leaf, state.resolved, state.listing, context)
3349
+ question: selectQuestion(leaf, path, state.resolved, page, context)
3295
3350
  }
3296
3351
  };
3297
3352
  } catch (error) {
3298
- state.listing = {
3299
- items: attempt.priorItems,
3300
- search: attempt.search,
3301
- cursor: attempt.cursor,
3302
- exhausted: false
3303
- };
3353
+ state.pagination = failedPagination(state.pagination, position);
3304
3354
  return failedResult(state, leaf.name, error);
3305
3355
  }
3306
3356
  }
3357
+ function failedPagination(pagination, retryPosition) {
3358
+ return {
3359
+ position: pagination?.position ?? firstPagePosition(),
3360
+ ...pagination?.nextCursor !== void 0 ? { nextCursor: pagination.nextCursor } : {},
3361
+ retryPosition
3362
+ };
3363
+ }
3364
+ function positionAfter(pagination, action) {
3365
+ const current = pagination?.position ?? firstPagePosition();
3366
+ switch (action.type) {
3367
+ case "search":
3368
+ return firstPagePosition({
3369
+ search: action.term,
3370
+ generation: current.generation + 1
3371
+ });
3372
+ case "next_page": {
3373
+ if (pagination?.nextCursor == null) return current;
3374
+ return {
3375
+ ...current.search !== void 0 ? { search: current.search } : {},
3376
+ pageCursor: pagination.nextCursor,
3377
+ previousCursors: [...current.previousCursors, current.pageCursor],
3378
+ generation: current.generation
3379
+ };
3380
+ }
3381
+ case "previous_page": {
3382
+ if (current.previousCursors.length === 0) return current;
3383
+ return {
3384
+ ...current.search !== void 0 ? { search: current.search } : {},
3385
+ pageCursor: current.previousCursors[current.previousCursors.length - 1],
3386
+ previousCursors: current.previousCursors.slice(0, -1),
3387
+ generation: current.generation
3388
+ };
3389
+ }
3390
+ case "retry":
3391
+ return pagination?.retryPosition ?? current;
3392
+ }
3393
+ }
3307
3394
  function toJsonSchema(schema) {
3308
3395
  if (!schema) return void 0;
3309
3396
  try {
@@ -5340,7 +5427,7 @@ function parseDeprecationDate(value) {
5340
5427
  }
5341
5428
 
5342
5429
  // src/sdk-version.ts
5343
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.2" : void 0) || "unknown";
5430
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.3" : void 0) || "unknown";
5344
5431
 
5345
5432
  // src/utils/open-url.ts
5346
5433
  var nodePrefix = "node:";
@@ -8077,8 +8164,9 @@ var appKeyResolver = defineResolver({
8077
8164
  },
8078
8165
  listItems: ({
8079
8166
  imports,
8080
- search
8081
- }) => imports.listApps({ search }),
8167
+ search,
8168
+ cursor
8169
+ }) => imports.listApps({ search, cursor }),
8082
8170
  prompt: ({ items }) => ({
8083
8171
  type: "list",
8084
8172
  message: "Select app:",
@@ -8099,9 +8187,11 @@ var actionTypeResolver = defineResolver({
8099
8187
  imports,
8100
8188
  input
8101
8189
  }) => {
8102
- const { data } = await imports.listActions({ app: input.app });
8103
- const types = [...new Set(data.map((action) => action.action_type))];
8104
- return { data: types.map((type) => ({ key: type, name: type })) };
8190
+ const types = /* @__PURE__ */ new Set();
8191
+ for await (const action of imports.listActions({ app: input.app }).items()) {
8192
+ types.add(action.action_type);
8193
+ }
8194
+ return { data: [...types].map((type) => ({ key: type, name: type })) };
8105
8195
  },
8106
8196
  prompt: ({ items }) => ({
8107
8197
  type: "list",
@@ -8117,13 +8207,15 @@ var actionKeyResolver = defineResolver({
8117
8207
  requireParameters: ["app", "actionType"],
8118
8208
  listItems: async ({
8119
8209
  imports,
8120
- input
8210
+ input,
8211
+ cursor
8121
8212
  }) => {
8122
- const { data } = await imports.listActions({ app: input.app });
8213
+ const page = await imports.listActions({ app: input.app, cursor });
8123
8214
  return {
8124
- data: data.filter(
8215
+ data: page.data.filter(
8125
8216
  (action) => action.action_type === input.actionType && !action.is_hidden
8126
- )
8217
+ ),
8218
+ nextCursor: page.nextCursor
8127
8219
  };
8128
8220
  },
8129
8221
  prompt: ({ items }) => ({
@@ -8240,9 +8332,10 @@ var connectionIdResolver = defineResolver({
8240
8332
  }
8241
8333
  return null;
8242
8334
  },
8243
- listItems: ({ imports, input, context }) => imports.listConnections({
8335
+ listItems: ({ imports, input, context, cursor }) => imports.listConnections({
8244
8336
  app: input.app,
8245
- includeShared: context?.canIncludeShared || void 0
8337
+ includeShared: context?.canIncludeShared || void 0,
8338
+ cursor
8246
8339
  }),
8247
8340
  prompt: ({ items, input, context }) => buildConnectionPrompt(
8248
8341
  items,
@@ -8258,9 +8351,10 @@ var connectionIdGenericResolver = defineResolver({
8258
8351
  );
8259
8352
  return { canIncludeShared: canIncludeShared ?? false };
8260
8353
  },
8261
- listItems: ({ imports, input, context }) => imports.listConnections({
8354
+ listItems: ({ imports, input, context, cursor }) => imports.listConnections({
8262
8355
  app: input.app,
8263
- includeShared: context?.canIncludeShared || void 0
8356
+ includeShared: context?.canIncludeShared || void 0,
8357
+ cursor
8264
8358
  }),
8265
8359
  prompt: ({ items, input, context }) => buildConnectionPrompt(
8266
8360
  items,
@@ -8288,12 +8382,13 @@ var listActionInputFieldChoicesRef = declareMethod({ id: "listActionInputFieldCh
8288
8382
  var choiceResolver = defineResolver({
8289
8383
  imports: [listActionInputFieldChoicesRef],
8290
8384
  requireParameters: ["app", "action", "actionType"],
8291
- listItems: ({ imports, input }) => imports.listActionInputFieldChoices({
8385
+ listItems: ({ imports, input, cursor }) => imports.listActionInputFieldChoices({
8292
8386
  app: input.app,
8293
8387
  action: input.action,
8294
8388
  actionType: input.actionType,
8295
8389
  connection: input.connection,
8296
- inputField: input.inputField
8390
+ inputField: input.inputField,
8391
+ cursor
8297
8392
  }),
8298
8393
  prompt: ({ items }) => ({
8299
8394
  type: "list",
@@ -8452,7 +8547,7 @@ var clientCredentialsNameResolver = defineResolver({
8452
8547
  var listClientCredentialsRef = declareMethod({ id: "listClientCredentials" });
8453
8548
  var clientIdResolver = defineResolver({
8454
8549
  imports: [listClientCredentialsRef],
8455
- listItems: ({ imports }) => imports.listClientCredentials({}),
8550
+ listItems: ({ imports, cursor }) => imports.listClientCredentials({ cursor }),
8456
8551
  prompt: ({ items }) => ({
8457
8552
  type: "list",
8458
8553
  message: "Select client credentials to delete:",
@@ -8464,9 +8559,9 @@ var clientIdResolver = defineResolver({
8464
8559
  });
8465
8560
 
8466
8561
  // src/resolvers/tableId.ts
8467
- var listTablesRef = declareMethod({ id: "listTables" });
8562
+ var listTablesInternalRef = declareMethod({ id: "listTablesInternal" });
8468
8563
  var tableIdResolver = defineResolver({
8469
- imports: [listTablesRef, capabilitiesPluginRef],
8564
+ imports: [listTablesInternalRef, capabilitiesPluginRef],
8470
8565
  getContext: async ({ imports }) => {
8471
8566
  const includeShared = await imports.capabilities.hasCapability?.(
8472
8567
  "canIncludeSharedTables"
@@ -8474,27 +8569,36 @@ var tableIdResolver = defineResolver({
8474
8569
  return { includeShared: includeShared ?? false };
8475
8570
  },
8476
8571
  // Unlike connections, the tables API does not return personal tables first,
8477
- // so we use concatPaginated to hoist own tables above shared.
8478
- listItems: ({ imports, context }) => {
8572
+ // so we concatenate personal-only and shared-only slices to hoist own
8573
+ // tables above shared. The slices are disjoint by construction, so the
8574
+ // concatenation paginates with stateless cursors and needs no dedupe.
8575
+ listItems: ({ imports, context, cursor }) => {
8479
8576
  const includeShared = context?.includeShared;
8480
8577
  if (includeShared) {
8481
8578
  return concatPaginated({
8482
8579
  sources: [
8483
- () => imports.listTables({}),
8484
- () => imports.listTables({ includeShared: true })
8580
+ ({ cursor: sourceCursor }) => imports.listTablesInternal({ cursor: sourceCursor }),
8581
+ ({ cursor: sourceCursor }) => imports.listTablesInternal({
8582
+ includeShared: true,
8583
+ includePersonal: false,
8584
+ cursor: sourceCursor
8585
+ })
8485
8586
  ],
8486
- dedupe: (table) => table.id
8587
+ cursor
8487
8588
  });
8488
8589
  }
8489
- return imports.listTables({});
8590
+ return imports.listTablesInternal({ cursor });
8490
8591
  },
8491
- prompt: ({ items }) => ({
8592
+ prompt: ({ items, context }) => ({
8492
8593
  type: "list",
8493
8594
  message: "Select a table:",
8494
8595
  choices: items.map((table) => ({
8495
8596
  label: table.name,
8496
8597
  value: table.id
8497
- }))
8598
+ })),
8599
+ // The capability hint the legacy picker showed as a fake disabled row:
8600
+ // without it, a gated account just sees fewer tables with no explanation.
8601
+ ...context?.includeShared ? {} : { notes: ["Shared tables are hidden for this account."] }
8498
8602
  })
8499
8603
  });
8500
8604
 
@@ -8502,7 +8606,7 @@ var tableIdResolver = defineResolver({
8502
8606
  var listTriggerInboxesRef = declareMethod({ id: "listTriggerInboxes" });
8503
8607
  var triggerInboxResolver = defineResolver({
8504
8608
  imports: [listTriggerInboxesRef],
8505
- listItems: ({ imports }) => imports.listTriggerInboxes({}),
8609
+ listItems: ({ imports, cursor }) => imports.listTriggerInboxes({ cursor }),
8506
8610
  prompt: ({ items }) => ({
8507
8611
  type: "list",
8508
8612
  message: "Select a trigger inbox:",
@@ -8520,7 +8624,7 @@ var triggerInboxResolver = defineResolver({
8520
8624
  var listWorkflowsRef = declareMethod({ id: "listWorkflows" });
8521
8625
  var workflowIdResolver = defineResolver({
8522
8626
  imports: [listWorkflowsRef],
8523
- listItems: ({ imports }) => imports.listWorkflows({}),
8627
+ listItems: ({ imports, cursor }) => imports.listWorkflows({ cursor }),
8524
8628
  prompt: ({ items }) => ({
8525
8629
  type: "list",
8526
8630
  message: "Select a workflow:",
@@ -8536,7 +8640,7 @@ var workflowIdResolver = defineResolver({
8536
8640
  var listDurableRunsRef = declareMethod({ id: "listDurableRuns" });
8537
8641
  var durableRunIdResolver = defineResolver({
8538
8642
  imports: [listDurableRunsRef],
8539
- listItems: ({ imports }) => imports.listDurableRuns({}),
8643
+ listItems: ({ imports, cursor }) => imports.listDurableRuns({ cursor }),
8540
8644
  prompt: ({ items }) => ({
8541
8645
  type: "list",
8542
8646
  message: "Select a run:",
@@ -8553,7 +8657,14 @@ var listWorkflowVersionsRef = declareMethod({ id: "listWorkflowVersions" });
8553
8657
  var workflowVersionIdResolver = defineResolver({
8554
8658
  imports: [listWorkflowVersionsRef],
8555
8659
  requireParameters: ["workflow"],
8556
- listItems: ({ imports, input }) => imports.listWorkflowVersions({ workflow: input.workflow }),
8660
+ listItems: ({
8661
+ imports,
8662
+ input,
8663
+ cursor
8664
+ }) => imports.listWorkflowVersions({
8665
+ workflow: input.workflow,
8666
+ cursor
8667
+ }),
8557
8668
  prompt: ({ items }) => ({
8558
8669
  type: "list",
8559
8670
  message: "Select a workflow version:",
@@ -8569,7 +8680,11 @@ var listWorkflowRunsRef = declareMethod({ id: "listWorkflowRuns" });
8569
8680
  var workflowRunIdResolver = defineResolver({
8570
8681
  imports: [listWorkflowRunsRef],
8571
8682
  requireParameters: ["workflow"],
8572
- listItems: ({ imports, input }) => imports.listWorkflowRuns({ workflow: input.workflow }),
8683
+ listItems: ({
8684
+ imports,
8685
+ input,
8686
+ cursor
8687
+ }) => imports.listWorkflowRuns({ workflow: input.workflow, cursor }),
8573
8688
  prompt: ({ items }) => ({
8574
8689
  type: "list",
8575
8690
  message: "Select a workflow run:",
@@ -8587,8 +8702,9 @@ var triggerMessagesResolver = defineResolver({
8587
8702
  requireParameters: ["inbox"],
8588
8703
  listItems: ({
8589
8704
  imports,
8590
- input
8591
- }) => imports.listTriggerInboxMessages({ inbox: input.inbox }),
8705
+ input,
8706
+ cursor
8707
+ }) => imports.listTriggerInboxMessages({ inbox: input.inbox, cursor }),
8592
8708
  prompt: ({ items }) => ({
8593
8709
  type: "checkbox",
8594
8710
  message: "Select messages:",
@@ -8861,9 +8977,10 @@ function recordChoices(records) {
8861
8977
  var tableRecordIdResolver = defineResolver({
8862
8978
  imports: [listTableRecordsRef],
8863
8979
  requireParameters: ["table"],
8864
- listItems: ({ imports, input }) => imports.listTableRecords({
8980
+ listItems: ({ imports, input, cursor }) => imports.listTableRecords({
8865
8981
  table: input.table,
8866
- keyMode: "names"
8982
+ keyMode: "names",
8983
+ cursor
8867
8984
  }),
8868
8985
  prompt: ({ items }) => ({
8869
8986
  type: "list",
@@ -8874,16 +8991,17 @@ var tableRecordIdResolver = defineResolver({
8874
8991
  var tableRecordIdsResolver = defineResolver({
8875
8992
  imports: [listTableRecordsRef],
8876
8993
  requireParameters: ["table"],
8877
- listItems: ({ imports, input }) => imports.listTableRecords({
8994
+ listItems: ({ imports, input, cursor }) => imports.listTableRecords({
8878
8995
  table: input.table,
8879
- keyMode: "names"
8996
+ keyMode: "names",
8997
+ cursor
8880
8998
  }),
8881
8999
  prompt: ({ items }) => ({
8882
9000
  type: "checkbox",
8883
9001
  message: "Select records to delete:",
8884
- choices: recordChoices(items),
8885
- validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Select at least one record"
8886
- })
9002
+ choices: recordChoices(items)
9003
+ }),
9004
+ validate: ({ value }) => Array.isArray(value) && value.length > 0 ? true : "Select at least one record"
8887
9005
  });
8888
9006
 
8889
9007
  // src/resolvers/tableFieldIds.ts
@@ -8891,6 +9009,8 @@ var listTableFieldsRef = declareMethod({ id: "listTableFields" });
8891
9009
  var tableFieldIdsResolver = defineResolver({
8892
9010
  imports: [listTableFieldsRef],
8893
9011
  requireParameters: ["table"],
9012
+ // No cursor forwarding: the fields API is unpaginated (no cursor on the
9013
+ // response), so the listing is always exhausted after one page.
8894
9014
  listItems: ({ imports, input }) => imports.listTableFields({ table: input.table }),
8895
9015
  prompt: ({ items }) => ({
8896
9016
  type: "checkbox",
@@ -8899,9 +9019,9 @@ var tableFieldIdsResolver = defineResolver({
8899
9019
  label: field.name,
8900
9020
  hint: [field.id, field.type],
8901
9021
  value: field.id
8902
- })),
8903
- validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Select at least one field"
8904
- })
9022
+ }))
9023
+ }),
9024
+ validate: ({ value }) => Array.isArray(value) && value.length > 0 ? true : "Select at least one field"
8905
9025
  });
8906
9026
 
8907
9027
  // src/resolvers/tableName.ts
@@ -13145,27 +13265,31 @@ var ListTablesOptionsSchema = z.object({
13145
13265
  maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages"),
13146
13266
  cursor: z.string().optional().describe("Cursor to start from")
13147
13267
  }).describe("List tables available to the authenticated user");
13268
+ var ListTablesInternalOptionsSchema = ListTablesOptionsSchema.extend({
13269
+ includePersonal: z.boolean().optional().describe(
13270
+ "Include your own tables (default true). Set false with includeShared to list only tables shared with you."
13271
+ )
13272
+ });
13148
13273
 
13149
- // src/plugins/tables/shared.ts
13150
- var tableCategories = ["table"];
13151
-
13152
- // src/plugins/tables/listTables/index.ts
13153
- var listTablesPlugin = defineMethod({
13154
- name: "listTables",
13274
+ // src/plugins/tables/listTables/internal.ts
13275
+ var listTablesInternalPlugin = defineMethod({
13276
+ name: "listTablesInternal",
13155
13277
  imports: [apiPluginRef, capabilitiesPluginRef],
13156
- categories: tableCategories,
13157
- itemType: "Table",
13158
- inputSchema: ListTablesOptionsSchema,
13159
- outputSchema: TableItemSchema,
13278
+ inputSchema: ListTablesInternalOptionsSchema,
13160
13279
  output: {
13161
13280
  type: "list",
13162
13281
  adaptPage: adaptZapierPage,
13163
13282
  defaultPageSize: DEFAULT_PAGE_SIZE
13164
13283
  },
13165
13284
  run: async ({ imports, input }) => {
13166
- if (input.includeShared) {
13285
+ const includePersonal = input.includePersonal ?? true;
13286
+ const includeShared = input.includeShared ?? false;
13287
+ if (includeShared) {
13167
13288
  await imports.capabilities.checkCapability("canIncludeSharedTables");
13168
13289
  }
13290
+ if (!includePersonal && !includeShared) {
13291
+ return { data: [] };
13292
+ }
13169
13293
  const api = imports.api;
13170
13294
  const searchParams = {};
13171
13295
  if (input.pageSize !== void 0) {
@@ -13181,23 +13305,18 @@ var listTablesPlugin = defineMethod({
13181
13305
  if (input.search) {
13182
13306
  searchParams.q = input.search;
13183
13307
  }
13184
- if (input.owner && input.owner !== "me" && !input.includeShared) {
13308
+ if (input.owner && input.owner !== "me" && !includeShared) {
13185
13309
  throw new ZapierValidationError(
13186
13310
  'The "owner" option requires "includeShared" to be true. Without includeShared, only your own tables are returned.'
13187
13311
  );
13188
13312
  }
13189
- const owner = input.includeShared ? input.owner : "me";
13313
+ const owner = includeShared ? input.owner : "me";
13314
+ const needsProfileId = owner === "me" || !includePersonal && includeShared;
13315
+ const profileId = needsProfileId ? (await api.get("/zapier/api/v4/profile/", {
13316
+ authRequired: true
13317
+ })).id : void 0;
13190
13318
  if (owner) {
13191
- if (owner === "me") {
13192
- const profile = await api.get("/zapier/api/v4/profile/", {
13193
- authRequired: true
13194
- });
13195
- searchParams.owner_customuser_id = String(
13196
- profile.id
13197
- );
13198
- } else {
13199
- searchParams.owner_customuser_id = owner;
13200
- }
13319
+ searchParams.owner_customuser_id = owner === "me" ? String(profileId) : owner;
13201
13320
  }
13202
13321
  if (input.cursor) {
13203
13322
  searchParams.offset = input.cursor;
@@ -13207,12 +13326,35 @@ var listTablesPlugin = defineMethod({
13207
13326
  authRequired: true
13208
13327
  });
13209
13328
  const response = ListTablesApiResponseSchema.parse(rawResponse);
13329
+ const apiItems = includePersonal ? response.data : response.data.filter(
13330
+ (item) => item.owner_zapier_customuser_id !== profileId
13331
+ );
13210
13332
  return {
13211
- data: response.data.map(transformTableItem),
13333
+ data: apiItems.map(transformTableItem),
13212
13334
  links: response.links
13213
13335
  };
13214
13336
  }
13215
13337
  });
13338
+
13339
+ // src/plugins/tables/shared.ts
13340
+ var tableCategories = ["table"];
13341
+
13342
+ // src/plugins/tables/listTables/index.ts
13343
+ var listTablesPlugin = defineMethod({
13344
+ name: "listTables",
13345
+ imports: [listTablesInternalPlugin],
13346
+ categories: tableCategories,
13347
+ itemType: "Table",
13348
+ inputSchema: ListTablesOptionsSchema,
13349
+ outputSchema: TableItemSchema,
13350
+ output: "list",
13351
+ run: async ({ imports, input }) => {
13352
+ return await imports.listTablesInternal({
13353
+ ...input,
13354
+ includePersonal: void 0
13355
+ });
13356
+ }
13357
+ });
13216
13358
  var GetTableApiResponseSchema = z.object({
13217
13359
  data: TableApiItemSchema
13218
13360
  });