@zapier/zapier-sdk 0.84.2 → 0.84.4

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.
@@ -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 {
@@ -5194,7 +5281,7 @@ function parseDeprecationDate(value) {
5194
5281
  }
5195
5282
 
5196
5283
  // src/sdk-version.ts
5197
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.2" : void 0) || "unknown";
5284
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.4" : void 0) || "unknown";
5198
5285
 
5199
5286
  // src/utils/open-url.ts
5200
5287
  var nodePrefix = "node:";
@@ -6929,6 +7016,7 @@ function transformConnectionItem(item) {
6929
7016
  is_private: item.is_private,
6930
7017
  shared_with_all: item.shared_with_all,
6931
7018
  title: item.title,
7019
+ slug: item.slug,
6932
7020
  lastchanged: item.lastchanged,
6933
7021
  is_stale: item.is_stale,
6934
7022
  is_shared: item.is_shared,
@@ -8089,8 +8177,9 @@ var appKeyResolver = defineResolver({
8089
8177
  },
8090
8178
  listItems: ({
8091
8179
  imports,
8092
- search
8093
- }) => imports.listApps({ search }),
8180
+ search,
8181
+ cursor
8182
+ }) => imports.listApps({ search, cursor }),
8094
8183
  prompt: ({ items }) => ({
8095
8184
  type: "list",
8096
8185
  message: "Select app:",
@@ -8111,9 +8200,11 @@ var actionTypeResolver = defineResolver({
8111
8200
  imports,
8112
8201
  input
8113
8202
  }) => {
8114
- const { data } = await imports.listActions({ app: input.app });
8115
- const types = [...new Set(data.map((action) => action.action_type))];
8116
- return { data: types.map((type) => ({ key: type, name: type })) };
8203
+ const types = /* @__PURE__ */ new Set();
8204
+ for await (const action of imports.listActions({ app: input.app }).items()) {
8205
+ types.add(action.action_type);
8206
+ }
8207
+ return { data: [...types].map((type) => ({ key: type, name: type })) };
8117
8208
  },
8118
8209
  prompt: ({ items }) => ({
8119
8210
  type: "list",
@@ -8129,13 +8220,15 @@ var actionKeyResolver = defineResolver({
8129
8220
  requireParameters: ["app", "actionType"],
8130
8221
  listItems: async ({
8131
8222
  imports,
8132
- input
8223
+ input,
8224
+ cursor
8133
8225
  }) => {
8134
- const { data } = await imports.listActions({ app: input.app });
8226
+ const page = await imports.listActions({ app: input.app, cursor });
8135
8227
  return {
8136
- data: data.filter(
8228
+ data: page.data.filter(
8137
8229
  (action) => action.action_type === input.actionType && !action.is_hidden
8138
- )
8230
+ ),
8231
+ nextCursor: page.nextCursor
8139
8232
  };
8140
8233
  },
8141
8234
  prompt: ({ items }) => ({
@@ -8252,9 +8345,10 @@ var connectionIdResolver = defineResolver({
8252
8345
  }
8253
8346
  return null;
8254
8347
  },
8255
- listItems: ({ imports, input, context }) => imports.listConnections({
8348
+ listItems: ({ imports, input, context, cursor }) => imports.listConnections({
8256
8349
  app: input.app,
8257
- includeShared: context?.canIncludeShared || void 0
8350
+ includeShared: context?.canIncludeShared || void 0,
8351
+ cursor
8258
8352
  }),
8259
8353
  prompt: ({ items, input, context }) => buildConnectionPrompt(
8260
8354
  items,
@@ -8270,9 +8364,10 @@ var connectionIdGenericResolver = defineResolver({
8270
8364
  );
8271
8365
  return { canIncludeShared: canIncludeShared ?? false };
8272
8366
  },
8273
- listItems: ({ imports, input, context }) => imports.listConnections({
8367
+ listItems: ({ imports, input, context, cursor }) => imports.listConnections({
8274
8368
  app: input.app,
8275
- includeShared: context?.canIncludeShared || void 0
8369
+ includeShared: context?.canIncludeShared || void 0,
8370
+ cursor
8276
8371
  }),
8277
8372
  prompt: ({ items, input, context }) => buildConnectionPrompt(
8278
8373
  items,
@@ -8300,12 +8395,13 @@ var listActionInputFieldChoicesRef = declareMethod({ id: "listActionInputFieldCh
8300
8395
  var choiceResolver = defineResolver({
8301
8396
  imports: [listActionInputFieldChoicesRef],
8302
8397
  requireParameters: ["app", "action", "actionType"],
8303
- listItems: ({ imports, input }) => imports.listActionInputFieldChoices({
8398
+ listItems: ({ imports, input, cursor }) => imports.listActionInputFieldChoices({
8304
8399
  app: input.app,
8305
8400
  action: input.action,
8306
8401
  actionType: input.actionType,
8307
8402
  connection: input.connection,
8308
- inputField: input.inputField
8403
+ inputField: input.inputField,
8404
+ cursor
8309
8405
  }),
8310
8406
  prompt: ({ items }) => ({
8311
8407
  type: "list",
@@ -8464,7 +8560,7 @@ var clientCredentialsNameResolver = defineResolver({
8464
8560
  var listClientCredentialsRef = declareMethod({ id: "listClientCredentials" });
8465
8561
  var clientIdResolver = defineResolver({
8466
8562
  imports: [listClientCredentialsRef],
8467
- listItems: ({ imports }) => imports.listClientCredentials({}),
8563
+ listItems: ({ imports, cursor }) => imports.listClientCredentials({ cursor }),
8468
8564
  prompt: ({ items }) => ({
8469
8565
  type: "list",
8470
8566
  message: "Select client credentials to delete:",
@@ -8476,9 +8572,9 @@ var clientIdResolver = defineResolver({
8476
8572
  });
8477
8573
 
8478
8574
  // src/resolvers/tableId.ts
8479
- var listTablesRef = declareMethod({ id: "listTables" });
8575
+ var listTablesInternalRef = declareMethod({ id: "listTablesInternal" });
8480
8576
  var tableIdResolver = defineResolver({
8481
- imports: [listTablesRef, capabilitiesPluginRef],
8577
+ imports: [listTablesInternalRef, capabilitiesPluginRef],
8482
8578
  getContext: async ({ imports }) => {
8483
8579
  const includeShared = await imports.capabilities.hasCapability?.(
8484
8580
  "canIncludeSharedTables"
@@ -8486,27 +8582,36 @@ var tableIdResolver = defineResolver({
8486
8582
  return { includeShared: includeShared ?? false };
8487
8583
  },
8488
8584
  // Unlike connections, the tables API does not return personal tables first,
8489
- // so we use concatPaginated to hoist own tables above shared.
8490
- listItems: ({ imports, context }) => {
8585
+ // so we concatenate personal-only and shared-only slices to hoist own
8586
+ // tables above shared. The slices are disjoint by construction, so the
8587
+ // concatenation paginates with stateless cursors and needs no dedupe.
8588
+ listItems: ({ imports, context, cursor }) => {
8491
8589
  const includeShared = context?.includeShared;
8492
8590
  if (includeShared) {
8493
8591
  return concatPaginated({
8494
8592
  sources: [
8495
- () => imports.listTables({}),
8496
- () => imports.listTables({ includeShared: true })
8593
+ ({ cursor: sourceCursor }) => imports.listTablesInternal({ cursor: sourceCursor }),
8594
+ ({ cursor: sourceCursor }) => imports.listTablesInternal({
8595
+ includeShared: true,
8596
+ includePersonal: false,
8597
+ cursor: sourceCursor
8598
+ })
8497
8599
  ],
8498
- dedupe: (table) => table.id
8600
+ cursor
8499
8601
  });
8500
8602
  }
8501
- return imports.listTables({});
8603
+ return imports.listTablesInternal({ cursor });
8502
8604
  },
8503
- prompt: ({ items }) => ({
8605
+ prompt: ({ items, context }) => ({
8504
8606
  type: "list",
8505
8607
  message: "Select a table:",
8506
8608
  choices: items.map((table) => ({
8507
8609
  label: table.name,
8508
8610
  value: table.id
8509
- }))
8611
+ })),
8612
+ // The capability hint the legacy picker showed as a fake disabled row:
8613
+ // without it, a gated account just sees fewer tables with no explanation.
8614
+ ...context?.includeShared ? {} : { notes: ["Shared tables are hidden for this account."] }
8510
8615
  })
8511
8616
  });
8512
8617
 
@@ -8514,7 +8619,7 @@ var tableIdResolver = defineResolver({
8514
8619
  var listTriggerInboxesRef = declareMethod({ id: "listTriggerInboxes" });
8515
8620
  var triggerInboxResolver = defineResolver({
8516
8621
  imports: [listTriggerInboxesRef],
8517
- listItems: ({ imports }) => imports.listTriggerInboxes({}),
8622
+ listItems: ({ imports, cursor }) => imports.listTriggerInboxes({ cursor }),
8518
8623
  prompt: ({ items }) => ({
8519
8624
  type: "list",
8520
8625
  message: "Select a trigger inbox:",
@@ -8532,7 +8637,7 @@ var triggerInboxResolver = defineResolver({
8532
8637
  var listWorkflowsRef = declareMethod({ id: "listWorkflows" });
8533
8638
  var workflowIdResolver = defineResolver({
8534
8639
  imports: [listWorkflowsRef],
8535
- listItems: ({ imports }) => imports.listWorkflows({}),
8640
+ listItems: ({ imports, cursor }) => imports.listWorkflows({ cursor }),
8536
8641
  prompt: ({ items }) => ({
8537
8642
  type: "list",
8538
8643
  message: "Select a workflow:",
@@ -8548,7 +8653,7 @@ var workflowIdResolver = defineResolver({
8548
8653
  var listDurableRunsRef = declareMethod({ id: "listDurableRuns" });
8549
8654
  var durableRunIdResolver = defineResolver({
8550
8655
  imports: [listDurableRunsRef],
8551
- listItems: ({ imports }) => imports.listDurableRuns({}),
8656
+ listItems: ({ imports, cursor }) => imports.listDurableRuns({ cursor }),
8552
8657
  prompt: ({ items }) => ({
8553
8658
  type: "list",
8554
8659
  message: "Select a run:",
@@ -8565,7 +8670,14 @@ var listWorkflowVersionsRef = declareMethod({ id: "listWorkflowVersions" });
8565
8670
  var workflowVersionIdResolver = defineResolver({
8566
8671
  imports: [listWorkflowVersionsRef],
8567
8672
  requireParameters: ["workflow"],
8568
- listItems: ({ imports, input }) => imports.listWorkflowVersions({ workflow: input.workflow }),
8673
+ listItems: ({
8674
+ imports,
8675
+ input,
8676
+ cursor
8677
+ }) => imports.listWorkflowVersions({
8678
+ workflow: input.workflow,
8679
+ cursor
8680
+ }),
8569
8681
  prompt: ({ items }) => ({
8570
8682
  type: "list",
8571
8683
  message: "Select a workflow version:",
@@ -8581,7 +8693,11 @@ var listWorkflowRunsRef = declareMethod({ id: "listWorkflowRuns" });
8581
8693
  var workflowRunIdResolver = defineResolver({
8582
8694
  imports: [listWorkflowRunsRef],
8583
8695
  requireParameters: ["workflow"],
8584
- listItems: ({ imports, input }) => imports.listWorkflowRuns({ workflow: input.workflow }),
8696
+ listItems: ({
8697
+ imports,
8698
+ input,
8699
+ cursor
8700
+ }) => imports.listWorkflowRuns({ workflow: input.workflow, cursor }),
8585
8701
  prompt: ({ items }) => ({
8586
8702
  type: "list",
8587
8703
  message: "Select a workflow run:",
@@ -8599,8 +8715,9 @@ var triggerMessagesResolver = defineResolver({
8599
8715
  requireParameters: ["inbox"],
8600
8716
  listItems: ({
8601
8717
  imports,
8602
- input
8603
- }) => imports.listTriggerInboxMessages({ inbox: input.inbox }),
8718
+ input,
8719
+ cursor
8720
+ }) => imports.listTriggerInboxMessages({ inbox: input.inbox, cursor }),
8604
8721
  prompt: ({ items }) => ({
8605
8722
  type: "checkbox",
8606
8723
  message: "Select messages:",
@@ -8873,9 +8990,10 @@ function recordChoices(records) {
8873
8990
  var tableRecordIdResolver = defineResolver({
8874
8991
  imports: [listTableRecordsRef],
8875
8992
  requireParameters: ["table"],
8876
- listItems: ({ imports, input }) => imports.listTableRecords({
8993
+ listItems: ({ imports, input, cursor }) => imports.listTableRecords({
8877
8994
  table: input.table,
8878
- keyMode: "names"
8995
+ keyMode: "names",
8996
+ cursor
8879
8997
  }),
8880
8998
  prompt: ({ items }) => ({
8881
8999
  type: "list",
@@ -8886,16 +9004,17 @@ var tableRecordIdResolver = defineResolver({
8886
9004
  var tableRecordIdsResolver = defineResolver({
8887
9005
  imports: [listTableRecordsRef],
8888
9006
  requireParameters: ["table"],
8889
- listItems: ({ imports, input }) => imports.listTableRecords({
9007
+ listItems: ({ imports, input, cursor }) => imports.listTableRecords({
8890
9008
  table: input.table,
8891
- keyMode: "names"
9009
+ keyMode: "names",
9010
+ cursor
8892
9011
  }),
8893
9012
  prompt: ({ items }) => ({
8894
9013
  type: "checkbox",
8895
9014
  message: "Select records to delete:",
8896
- choices: recordChoices(items),
8897
- validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Select at least one record"
8898
- })
9015
+ choices: recordChoices(items)
9016
+ }),
9017
+ validate: ({ value }) => Array.isArray(value) && value.length > 0 ? true : "Select at least one record"
8899
9018
  });
8900
9019
 
8901
9020
  // src/resolvers/tableFieldIds.ts
@@ -8903,6 +9022,8 @@ var listTableFieldsRef = declareMethod({ id: "listTableFields" });
8903
9022
  var tableFieldIdsResolver = defineResolver({
8904
9023
  imports: [listTableFieldsRef],
8905
9024
  requireParameters: ["table"],
9025
+ // No cursor forwarding: the fields API is unpaginated (no cursor on the
9026
+ // response), so the listing is always exhausted after one page.
8906
9027
  listItems: ({ imports, input }) => imports.listTableFields({ table: input.table }),
8907
9028
  prompt: ({ items }) => ({
8908
9029
  type: "checkbox",
@@ -8911,9 +9032,9 @@ var tableFieldIdsResolver = defineResolver({
8911
9032
  label: field.name,
8912
9033
  hint: [field.id, field.type],
8913
9034
  value: field.id
8914
- })),
8915
- validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Select at least one field"
8916
- })
9035
+ }))
9036
+ }),
9037
+ validate: ({ value }) => Array.isArray(value) && value.length > 0 ? true : "Select at least one field"
8917
9038
  });
8918
9039
 
8919
9040
  // src/resolvers/tableName.ts
@@ -9918,6 +10039,11 @@ var ConnectionItemSchema = ConnectionItemSchema$1;
9918
10039
  // src/formatters/connection.ts
9919
10040
  function formatConnectionItem(item) {
9920
10041
  const details = [];
10042
+ const appKey = item.app_key ?? "unknown";
10043
+ details.push({
10044
+ text: item.slug ? `App: ${appKey} | App Slug: ${item.slug}` : `App: ${appKey}`,
10045
+ style: "accent"
10046
+ });
9921
10047
  if (item.identifier) {
9922
10048
  details.push({
9923
10049
  text: `Identifier: ${item.identifier}`,
@@ -13088,27 +13214,31 @@ var ListTablesOptionsSchema = z.object({
13088
13214
  maxItems: z.number().min(1).optional().describe("Maximum total items to return across all pages"),
13089
13215
  cursor: z.string().optional().describe("Cursor to start from")
13090
13216
  }).describe("List tables available to the authenticated user");
13217
+ var ListTablesInternalOptionsSchema = ListTablesOptionsSchema.extend({
13218
+ includePersonal: z.boolean().optional().describe(
13219
+ "Include your own tables (default true). Set false with includeShared to list only tables shared with you."
13220
+ )
13221
+ });
13091
13222
 
13092
- // src/plugins/tables/shared.ts
13093
- var tableCategories = ["table"];
13094
-
13095
- // src/plugins/tables/listTables/index.ts
13096
- var listTablesPlugin = defineMethod({
13097
- name: "listTables",
13223
+ // src/plugins/tables/listTables/internal.ts
13224
+ var listTablesInternalPlugin = defineMethod({
13225
+ name: "listTablesInternal",
13098
13226
  imports: [apiPluginRef, capabilitiesPluginRef],
13099
- categories: tableCategories,
13100
- itemType: "Table",
13101
- inputSchema: ListTablesOptionsSchema,
13102
- outputSchema: TableItemSchema,
13227
+ inputSchema: ListTablesInternalOptionsSchema,
13103
13228
  output: {
13104
13229
  type: "list",
13105
13230
  adaptPage: adaptZapierPage,
13106
13231
  defaultPageSize: DEFAULT_PAGE_SIZE
13107
13232
  },
13108
13233
  run: async ({ imports, input }) => {
13109
- if (input.includeShared) {
13234
+ const includePersonal = input.includePersonal ?? true;
13235
+ const includeShared = input.includeShared ?? false;
13236
+ if (includeShared) {
13110
13237
  await imports.capabilities.checkCapability("canIncludeSharedTables");
13111
13238
  }
13239
+ if (!includePersonal && !includeShared) {
13240
+ return { data: [] };
13241
+ }
13112
13242
  const api = imports.api;
13113
13243
  const searchParams = {};
13114
13244
  if (input.pageSize !== void 0) {
@@ -13124,23 +13254,18 @@ var listTablesPlugin = defineMethod({
13124
13254
  if (input.search) {
13125
13255
  searchParams.q = input.search;
13126
13256
  }
13127
- if (input.owner && input.owner !== "me" && !input.includeShared) {
13257
+ if (input.owner && input.owner !== "me" && !includeShared) {
13128
13258
  throw new ZapierValidationError(
13129
13259
  'The "owner" option requires "includeShared" to be true. Without includeShared, only your own tables are returned.'
13130
13260
  );
13131
13261
  }
13132
- const owner = input.includeShared ? input.owner : "me";
13262
+ const owner = includeShared ? input.owner : "me";
13263
+ const needsProfileId = owner === "me" || !includePersonal && includeShared;
13264
+ const profileId = needsProfileId ? (await api.get("/zapier/api/v4/profile/", {
13265
+ authRequired: true
13266
+ })).id : void 0;
13133
13267
  if (owner) {
13134
- if (owner === "me") {
13135
- const profile = await api.get("/zapier/api/v4/profile/", {
13136
- authRequired: true
13137
- });
13138
- searchParams.owner_customuser_id = String(
13139
- profile.id
13140
- );
13141
- } else {
13142
- searchParams.owner_customuser_id = owner;
13143
- }
13268
+ searchParams.owner_customuser_id = owner === "me" ? String(profileId) : owner;
13144
13269
  }
13145
13270
  if (input.cursor) {
13146
13271
  searchParams.offset = input.cursor;
@@ -13150,12 +13275,35 @@ var listTablesPlugin = defineMethod({
13150
13275
  authRequired: true
13151
13276
  });
13152
13277
  const response = ListTablesApiResponseSchema.parse(rawResponse);
13278
+ const apiItems = includePersonal ? response.data : response.data.filter(
13279
+ (item) => item.owner_zapier_customuser_id !== profileId
13280
+ );
13153
13281
  return {
13154
- data: response.data.map(transformTableItem),
13282
+ data: apiItems.map(transformTableItem),
13155
13283
  links: response.links
13156
13284
  };
13157
13285
  }
13158
13286
  });
13287
+
13288
+ // src/plugins/tables/shared.ts
13289
+ var tableCategories = ["table"];
13290
+
13291
+ // src/plugins/tables/listTables/index.ts
13292
+ var listTablesPlugin = defineMethod({
13293
+ name: "listTables",
13294
+ imports: [listTablesInternalPlugin],
13295
+ categories: tableCategories,
13296
+ itemType: "Table",
13297
+ inputSchema: ListTablesOptionsSchema,
13298
+ outputSchema: TableItemSchema,
13299
+ output: "list",
13300
+ run: async ({ imports, input }) => {
13301
+ return await imports.listTablesInternal({
13302
+ ...input,
13303
+ includePersonal: void 0
13304
+ });
13305
+ }
13306
+ });
13159
13307
  var GetTableApiResponseSchema = z.object({
13160
13308
  data: TableApiItemSchema
13161
13309
  });