@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.
@@ -203,7 +203,8 @@ function getCoreErrorCause(value) {
203
203
  var CURSOR_VERSION = 1;
204
204
  var CURSOR_SOURCE = {
205
205
  API: "api",
206
- SDK: "sdk"
206
+ SDK: "sdk",
207
+ CONCAT: "concat"
207
208
  };
208
209
  function encodeBase64(str) {
209
210
  return btoa(
@@ -387,10 +388,32 @@ async function* paginateBuffered(pageFunction, pageOptions) {
387
388
  }
388
389
  }
389
390
  var paginate = paginateBuffered;
391
+ function encodeConcatCursor(index, cursor) {
392
+ const envelope = {
393
+ v: CURSOR_VERSION,
394
+ source: CURSOR_SOURCE.CONCAT,
395
+ index,
396
+ cursor
397
+ };
398
+ return encodeBase64(JSON.stringify(envelope));
399
+ }
400
+ function decodeConcatCursor(incoming) {
401
+ if (!incoming) {
402
+ return { index: 0, cursor: void 0 };
403
+ }
404
+ try {
405
+ const envelope = JSON.parse(decodeBase64(incoming));
406
+ if (envelope.v === CURSOR_VERSION && envelope.source === CURSOR_SOURCE.CONCAT && typeof envelope.index === "number") {
407
+ return { index: envelope.index, cursor: envelope.cursor };
408
+ }
409
+ } catch {
410
+ }
411
+ return { index: 0, cursor: incoming };
412
+ }
390
413
  function concatPaginated({
391
414
  sources,
392
- dedupe,
393
- pageSize = 100
415
+ pageSize = 100,
416
+ cursor
394
417
  }) {
395
418
  if (sources.length === 0) {
396
419
  const empty = { data: [] };
@@ -400,40 +423,24 @@ function concatPaginated({
400
423
  }
401
424
  });
402
425
  }
403
- let sourceIndex = 0;
404
- let currentIterator = null;
405
- const seen = /* @__PURE__ */ new Set();
406
- const pageFunction = async (_options) => {
407
- while (sourceIndex < sources.length) {
408
- if (!currentIterator) {
409
- const result = sources[sourceIndex]();
410
- currentIterator = result[Symbol.asyncIterator]();
411
- }
412
- const next = await currentIterator.next();
413
- if (next.done) {
414
- sourceIndex++;
415
- currentIterator = null;
426
+ const pageFunction = async (options) => {
427
+ let { index, cursor: sourceCursor } = decodeConcatCursor(options.cursor);
428
+ while (index < sources.length) {
429
+ const page = await sources[index]({ cursor: sourceCursor });
430
+ const hasMoreInSource = page.nextCursor != null;
431
+ if (page.data.length === 0 && !hasMoreInSource) {
432
+ index++;
433
+ sourceCursor = void 0;
416
434
  continue;
417
435
  }
418
- let items = next.value.data;
419
- if (dedupe) {
420
- if (sourceIndex > 0) {
421
- items = items.filter((item) => !seen.has(dedupe(item)));
422
- }
423
- for (const item of items) {
424
- seen.add(dedupe(item));
425
- }
426
- }
427
- const hasMoreInSource = next.value.nextCursor != null;
428
- const hasMoreSources = sourceIndex < sources.length - 1;
429
436
  return {
430
- data: items,
431
- nextCursor: hasMoreInSource || hasMoreSources ? "__has_more__" : void 0
437
+ data: page.data,
438
+ nextCursor: hasMoreInSource ? encodeConcatCursor(index, page.nextCursor) : index < sources.length - 1 ? encodeConcatCursor(index + 1, void 0) : void 0
432
439
  };
433
440
  }
434
441
  return { data: [] };
435
442
  };
436
- const iterator = paginateBuffered(pageFunction, { pageSize });
443
+ const iterator = paginateBuffered(pageFunction, { pageSize, cursor });
437
444
  const firstPagePromise = iterator.next().then((result) => {
438
445
  if (result.done) {
439
446
  return { data: [] };
@@ -1285,6 +1292,7 @@ function defineResolver(config) {
1285
1292
  getContext: config.getContext,
1286
1293
  listItems: config.listItems,
1287
1294
  prompt: config.prompt,
1295
+ validate: config.validate,
1288
1296
  tryResolveWithoutPrompt: config.tryResolveWithoutPrompt,
1289
1297
  tryResolveFromSearch: config.tryResolveFromSearch
1290
1298
  };
@@ -1930,6 +1938,7 @@ function bindResolver(resolver, plugins) {
1930
1938
  const {
1931
1939
  getContext: getContext2,
1932
1940
  listItems,
1941
+ validate,
1933
1942
  tryResolveWithoutPrompt,
1934
1943
  tryResolveFromSearch
1935
1944
  } = resolver;
@@ -1943,6 +1952,9 @@ function bindResolver(resolver, plugins) {
1943
1952
  };
1944
1953
  if (getContext2)
1945
1954
  bound.getContext = ({ input }) => getContext2({ imports, input });
1955
+ if (validate) {
1956
+ bound.validate = ({ value, input, context }) => validate({ imports, value, input, context });
1957
+ }
1946
1958
  if (tryResolveWithoutPrompt) {
1947
1959
  bound.tryResolveWithoutPrompt = ({ input }) => tryResolveWithoutPrompt({ imports, input });
1948
1960
  }
@@ -2611,14 +2623,14 @@ function coerce(leaf, raw) {
2611
2623
  }
2612
2624
  async function validationError(leaf, value, state) {
2613
2625
  if (leaf.resolver?.type !== "dynamic") return null;
2626
+ const validate = leaf.resolver.validate;
2627
+ if (!validate) return null;
2614
2628
  const context = await resolveContext(leaf, state.resolved);
2615
- const config = leaf.resolver.prompt?.({
2616
- items: state.listing?.items ?? [],
2629
+ const verdict = await validate({
2630
+ value,
2617
2631
  input: mergeInput(state.resolved, leaf.extraInput),
2618
2632
  context
2619
2633
  });
2620
- if (!config?.validate) return null;
2621
- const verdict = config.validate(value);
2622
2634
  if (verdict === true) return null;
2623
2635
  return typeof verdict === "string" ? verdict : `${leaf.name}: invalid value`;
2624
2636
  }
@@ -2744,20 +2756,36 @@ async function resolveContext(leaf, input) {
2744
2756
  input: mergeInput(input, leaf.extraInput)
2745
2757
  });
2746
2758
  }
2747
- async function fetchListing(leaf, input, opts = {}) {
2759
+ function firstPagePosition(opts = {}) {
2760
+ return {
2761
+ ...opts.search !== void 0 ? { search: opts.search } : {},
2762
+ pageCursor: null,
2763
+ previousCursors: [],
2764
+ generation: opts.generation ?? 0
2765
+ };
2766
+ }
2767
+ async function fetchListing(leaf, input, position, context) {
2768
+ if (leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search" && position.search === void 0) {
2769
+ return { position, items: [] };
2770
+ }
2748
2771
  const page = await firstPage(
2749
2772
  leaf.resolver?.type === "dynamic" ? leaf.resolver.listItems({
2750
2773
  input: mergeInput(input, leaf.extraInput),
2751
- context: opts.context,
2752
- search: opts.search,
2753
- cursor: opts.cursor
2774
+ context,
2775
+ search: position.search,
2776
+ cursor: position.pageCursor ?? void 0
2754
2777
  }) : void 0
2755
2778
  );
2756
2779
  return {
2757
- items: [...opts.priorItems ?? [], ...page.data],
2758
- cursor: page.nextCursor,
2759
- search: opts.search,
2760
- exhausted: page.nextCursor == null
2780
+ position,
2781
+ items: page.data,
2782
+ ...page.nextCursor != null ? { nextCursor: page.nextCursor } : {}
2783
+ };
2784
+ }
2785
+ function toPagination(page) {
2786
+ return {
2787
+ position: page.position,
2788
+ ...page.nextCursor !== void 0 ? { nextCursor: page.nextCursor } : {}
2761
2789
  };
2762
2790
  }
2763
2791
  function toChoice(c) {
@@ -2777,23 +2805,32 @@ var AFFORDANCE = {
2777
2805
  description: "Filter the options by a search term",
2778
2806
  supply: "term"
2779
2807
  },
2780
- more: { action: "more", description: "Load more options" },
2808
+ nextPage: {
2809
+ action: "next_page",
2810
+ description: "Fetch the next page of options"
2811
+ },
2812
+ previousPage: {
2813
+ action: "previous_page",
2814
+ description: "Return to the previous page of options"
2815
+ },
2781
2816
  skip: { action: "skip", description: "Omit this optional parameter" },
2782
2817
  add: { action: "add", description: "Add another item" },
2783
2818
  done: { action: "done", description: "Finish the list" },
2784
2819
  retry: { action: "retry", description: "Retry loading the options" },
2785
2820
  cancel: { action: "cancel", description: "Cancel resolution" }
2786
2821
  };
2787
- function selectActions(leaf, listing, multiple) {
2822
+ function selectActions(leaf, page, multiple) {
2788
2823
  const searchMode = leaf.resolver?.type === "dynamic" && leaf.resolver.inputType === "search";
2789
- if (searchMode && listing.search === void 0 && listing.items.length === 0) {
2824
+ if (searchMode && page.position.search === void 0 && page.items.length === 0) {
2790
2825
  const actions2 = multiple ? [AFFORDANCE.search] : [AFFORDANCE.search, AFFORDANCE.custom];
2791
2826
  if (!leaf.required) actions2.push(AFFORDANCE.skip);
2792
2827
  return actions2;
2793
2828
  }
2794
2829
  const actions = multiple ? [AFFORDANCE.choose] : [AFFORDANCE.choose, AFFORDANCE.custom];
2795
2830
  if (searchMode) actions.push(AFFORDANCE.search);
2796
- if (listing.cursor) actions.push(AFFORDANCE.more);
2831
+ if (page.nextCursor) actions.push(AFFORDANCE.nextPage);
2832
+ if (page.position.previousCursors.length > 0)
2833
+ actions.push(AFFORDANCE.previousPage);
2797
2834
  if (!leaf.required) actions.push(AFFORDANCE.skip);
2798
2835
  return actions;
2799
2836
  }
@@ -2801,16 +2838,17 @@ function labeledMessage(leaf) {
2801
2838
  if (!leaf.label) return void 0;
2802
2839
  return `${leaf.label} (${leaf.required ? "required" : "optional"}):`;
2803
2840
  }
2804
- function selectQuestion(leaf, input, listing, context) {
2841
+ function selectQuestion(leaf, path, input, page, context) {
2805
2842
  const resolver = leaf.resolver?.type === "dynamic" ? leaf.resolver : void 0;
2806
2843
  const config = resolver?.prompt?.({
2807
- items: listing.items,
2844
+ items: page.items,
2808
2845
  input: mergeInput(input, leaf.extraInput),
2809
2846
  context
2810
2847
  });
2811
2848
  const multiple = config?.type === "checkbox";
2812
2849
  return {
2813
2850
  type: "select",
2851
+ path,
2814
2852
  // A labeled field's title beats the resolver's message: per-field
2815
2853
  // resolvers are shared across fields (one choices-fetcher for every
2816
2854
  // field), so only the leaf knows which field is being asked.
@@ -2818,9 +2856,13 @@ function selectQuestion(leaf, input, listing, context) {
2818
2856
  choices: (config?.choices ?? []).map(toChoice),
2819
2857
  ...multiple ? { multiple: true } : {},
2820
2858
  ...config?.notes?.length ? { notes: config.notes } : {},
2821
- ...listing.search !== void 0 ? { search: listing.search } : {},
2859
+ ...page.position.search !== void 0 ? { search: page.position.search } : {},
2822
2860
  ...resolver?.placeholder ? { placeholder: resolver.placeholder } : {},
2823
- actions: selectActions(leaf, listing, multiple)
2861
+ page: {
2862
+ generation: page.position.generation,
2863
+ index: page.position.previousCursors.length
2864
+ },
2865
+ actions: selectActions(leaf, page, multiple)
2824
2866
  };
2825
2867
  }
2826
2868
  function toControllerError(error) {
@@ -2842,6 +2884,7 @@ function failedResult(state, name, error) {
2842
2884
  error: toControllerError(error),
2843
2885
  question: {
2844
2886
  type: "select",
2887
+ path: state.current ?? [],
2845
2888
  message: `Could not load options for ${name}.`,
2846
2889
  choices: [],
2847
2890
  actions: [AFFORDANCE.retry, AFFORDANCE.cancel]
@@ -2849,27 +2892,15 @@ function failedResult(state, name, error) {
2849
2892
  }
2850
2893
  };
2851
2894
  }
2852
- async function buildQuestion(leaf, input) {
2895
+ async function buildQuestion(leaf, path, input) {
2853
2896
  const optional = !leaf.required;
2854
2897
  const resolver = leaf.resolver;
2855
2898
  if (resolver?.type === "dynamic") {
2856
2899
  const context = await resolveContext(leaf, input);
2857
- if (resolver.inputType === "search") {
2858
- const listing2 = {
2859
- items: [],
2860
- cursor: void 0,
2861
- search: void 0,
2862
- exhausted: true
2863
- };
2864
- return {
2865
- question: selectQuestion(leaf, input, listing2, context),
2866
- listing: listing2
2867
- };
2868
- }
2869
- const listing = await fetchListing(leaf, input, { context });
2900
+ const page = await fetchListing(leaf, input, firstPagePosition(), context);
2870
2901
  return {
2871
- question: selectQuestion(leaf, input, listing, context),
2872
- listing
2902
+ question: selectQuestion(leaf, path, input, page, context),
2903
+ pagination: toPagination(page)
2873
2904
  };
2874
2905
  }
2875
2906
  if (leaf.staticChoices) {
@@ -2878,6 +2909,7 @@ async function buildQuestion(leaf, input) {
2878
2909
  return {
2879
2910
  question: {
2880
2911
  type: "select",
2912
+ path,
2881
2913
  message: `Select ${leaf.name}:`,
2882
2914
  choices: leaf.staticChoices,
2883
2915
  actions: actions2
@@ -2891,6 +2923,7 @@ async function buildQuestion(leaf, input) {
2891
2923
  return {
2892
2924
  question: {
2893
2925
  type: "input",
2926
+ path,
2894
2927
  // The optional marker makes Enter-to-pass discoverable on a bare
2895
2928
  // parameter; a labeled field carries its marker via labeledMessage.
2896
2929
  message: labeledMessage(leaf) ?? `Enter ${leaf.name}${optional ? " (optional)" : ""}:`,
@@ -2905,6 +2938,7 @@ function collectionQuestion(t) {
2905
2938
  if (t.count >= t.min) actions.push(AFFORDANCE.done);
2906
2939
  return {
2907
2940
  type: "collection",
2941
+ path: t.path,
2908
2942
  message: `Add ${t.path[t.path.length - 1]}[${t.count}]?`,
2909
2943
  container: "array",
2910
2944
  count: t.count,
@@ -2918,6 +2952,7 @@ function collectionQuestion(t) {
2918
2952
  function objectGateQuestion(path) {
2919
2953
  return {
2920
2954
  type: "collection",
2955
+ path,
2921
2956
  message: `Add ${path[path.length - 1]}?`,
2922
2957
  container: "object",
2923
2958
  actions: [
@@ -2929,9 +2964,10 @@ function objectGateQuestion(path) {
2929
2964
  ]
2930
2965
  };
2931
2966
  }
2932
- function optionalsGateQuestion(pending) {
2967
+ function optionalsGateQuestion(path, pending) {
2933
2968
  return {
2934
2969
  type: "collection",
2970
+ path,
2935
2971
  // The prompt and its context ride separately so a host renders the info
2936
2972
  // line above the confirm without composing any text of its own.
2937
2973
  message: "Would you like to configure optional fields?",
@@ -3079,8 +3115,12 @@ async function askLeaf(state, path, leaf, opts = {}) {
3079
3115
  state.current = path;
3080
3116
  delete state.gate;
3081
3117
  try {
3082
- const { question, listing } = await buildQuestion(leaf, state.resolved);
3083
- state.listing = listing;
3118
+ const { question, pagination } = await buildQuestion(
3119
+ leaf,
3120
+ path,
3121
+ state.resolved
3122
+ );
3123
+ state.pagination = pagination;
3084
3124
  return {
3085
3125
  state,
3086
3126
  result: {
@@ -3090,7 +3130,7 @@ async function askLeaf(state, path, leaf, opts = {}) {
3090
3130
  }
3091
3131
  };
3092
3132
  } catch (error) {
3093
- state.listing = { items: [], exhausted: false };
3133
+ state.pagination = failedPagination(void 0, firstPagePosition());
3094
3134
  return failedResult(state, leaf.name, error);
3095
3135
  }
3096
3136
  }
@@ -3100,13 +3140,13 @@ async function advance(ctx, state) {
3100
3140
  if (!target) {
3101
3141
  delete state.current;
3102
3142
  delete state.gate;
3103
- delete state.listing;
3143
+ delete state.pagination;
3104
3144
  return { state, result: finalize(ctx, state.resolved) };
3105
3145
  }
3106
3146
  if (target.kind === "array") {
3107
3147
  state.current = target.path;
3108
3148
  state.gate = "array";
3109
- delete state.listing;
3149
+ delete state.pagination;
3110
3150
  return {
3111
3151
  state,
3112
3152
  result: { status: "ask", question: collectionQuestion(target) }
@@ -3115,7 +3155,7 @@ async function advance(ctx, state) {
3115
3155
  if (target.kind === "object") {
3116
3156
  state.current = target.path;
3117
3157
  state.gate = "entry";
3118
- delete state.listing;
3158
+ delete state.pagination;
3119
3159
  return {
3120
3160
  state,
3121
3161
  result: { status: "ask", question: objectGateQuestion(target.path) }
@@ -3124,12 +3164,12 @@ async function advance(ctx, state) {
3124
3164
  if (target.kind === "optionals") {
3125
3165
  state.current = target.path;
3126
3166
  state.gate = "optionals";
3127
- delete state.listing;
3167
+ delete state.pagination;
3128
3168
  return {
3129
3169
  state,
3130
3170
  result: {
3131
3171
  status: "ask",
3132
- question: optionalsGateQuestion(target.pending)
3172
+ question: optionalsGateQuestion(target.path, target.pending)
3133
3173
  }
3134
3174
  };
3135
3175
  }
@@ -3180,13 +3220,13 @@ async function step(ctx, prior, action) {
3180
3220
  if (action.type === "cancel") {
3181
3221
  delete state.current;
3182
3222
  delete state.gate;
3183
- delete state.listing;
3223
+ delete state.pagination;
3184
3224
  return { state, result: { status: "cancelled" } };
3185
3225
  }
3186
3226
  const path = state.current;
3187
3227
  if (!path) throw new Error("step called with no outstanding question");
3188
3228
  const leaf = await leafAt(ctx, path, state.resolved);
3189
- if (leaf && (action.type === "search" || action.type === "more" || action.type === "retry")) {
3229
+ if (leaf && (action.type === "search" || action.type === "next_page" || action.type === "previous_page" || action.type === "retry")) {
3190
3230
  return refine(ctx, state, leaf, path, action);
3191
3231
  }
3192
3232
  if (action.type === "add" || action.type === "done") {
@@ -3198,7 +3238,7 @@ async function step(ctx, prior, action) {
3198
3238
  }
3199
3239
  delete state.current;
3200
3240
  delete state.gate;
3201
- delete state.listing;
3241
+ delete state.pagination;
3202
3242
  if (action.type === "done") {
3203
3243
  settle(state, path);
3204
3244
  return advance(ctx, state);
@@ -3227,23 +3267,44 @@ async function step(ctx, prior, action) {
3227
3267
  case "choose":
3228
3268
  case "custom": {
3229
3269
  if (leaf) {
3230
- const error = await validationError(leaf, action.value, state);
3270
+ let error;
3271
+ try {
3272
+ error = await validationError(leaf, action.value, state);
3273
+ } catch (thrown) {
3274
+ return failedResult(state, leaf.name, thrown);
3275
+ }
3231
3276
  if (error) {
3232
- if (state.listing && leaf.resolver?.type === "dynamic") {
3233
- const context = await resolveContext(leaf, state.resolved);
3234
- return {
3235
- state,
3236
- result: {
3237
- status: "ask",
3238
- question: selectQuestion(
3239
- leaf,
3240
- state.resolved,
3241
- state.listing,
3242
- context
3243
- ),
3244
- error
3245
- }
3246
- };
3277
+ if (state.pagination && leaf.resolver?.type === "dynamic") {
3278
+ try {
3279
+ const context = await resolveContext(leaf, state.resolved);
3280
+ const page = await fetchListing(
3281
+ leaf,
3282
+ state.resolved,
3283
+ state.pagination.position,
3284
+ context
3285
+ );
3286
+ state.pagination = toPagination(page);
3287
+ return {
3288
+ state,
3289
+ result: {
3290
+ status: "ask",
3291
+ question: selectQuestion(
3292
+ leaf,
3293
+ path,
3294
+ state.resolved,
3295
+ page,
3296
+ context
3297
+ ),
3298
+ error
3299
+ }
3300
+ };
3301
+ } catch (fetchError) {
3302
+ state.pagination = failedPagination(
3303
+ state.pagination,
3304
+ state.pagination.position
3305
+ );
3306
+ return failedResult(state, leaf.name, fetchError);
3307
+ }
3247
3308
  }
3248
3309
  return askLeaf(state, path, leaf, { error });
3249
3310
  }
@@ -3262,15 +3323,11 @@ async function step(ctx, prior, action) {
3262
3323
  throw new Error(`action "${action.type}" is not supported here`);
3263
3324
  }
3264
3325
  delete state.current;
3265
- delete state.listing;
3326
+ delete state.pagination;
3266
3327
  return advance(ctx, state);
3267
3328
  }
3268
3329
  async function refine(ctx, state, leaf, path, action) {
3269
- const attempt = action.type === "search" ? { search: action.term, cursor: void 0, priorItems: [] } : {
3270
- search: state.listing?.search,
3271
- cursor: state.listing?.cursor,
3272
- priorItems: state.listing?.items ?? []
3273
- };
3330
+ const position = positionAfter(state.pagination, action);
3274
3331
  try {
3275
3332
  if (action.type === "search") {
3276
3333
  const exact = leaf.resolver?.type === "dynamic" ? await leaf.resolver.tryResolveFromSearch?.({
@@ -3280,32 +3337,62 @@ async function refine(ctx, state, leaf, path, action) {
3280
3337
  if (exact) {
3281
3338
  setAtPath(state.resolved, path, coerce(leaf, exact.resolvedValue));
3282
3339
  delete state.current;
3283
- delete state.listing;
3340
+ delete state.pagination;
3284
3341
  return advance(ctx, state);
3285
3342
  }
3286
3343
  }
3287
3344
  const context = await resolveContext(leaf, state.resolved);
3288
- state.listing = await fetchListing(leaf, state.resolved, {
3289
- ...attempt,
3290
- context
3291
- });
3345
+ const page = await fetchListing(leaf, state.resolved, position, context);
3346
+ state.pagination = toPagination(page);
3292
3347
  return {
3293
3348
  state,
3294
3349
  result: {
3295
3350
  status: "ask",
3296
- question: selectQuestion(leaf, state.resolved, state.listing, context)
3351
+ question: selectQuestion(leaf, path, state.resolved, page, context)
3297
3352
  }
3298
3353
  };
3299
3354
  } catch (error) {
3300
- state.listing = {
3301
- items: attempt.priorItems,
3302
- search: attempt.search,
3303
- cursor: attempt.cursor,
3304
- exhausted: false
3305
- };
3355
+ state.pagination = failedPagination(state.pagination, position);
3306
3356
  return failedResult(state, leaf.name, error);
3307
3357
  }
3308
3358
  }
3359
+ function failedPagination(pagination, retryPosition) {
3360
+ return {
3361
+ position: pagination?.position ?? firstPagePosition(),
3362
+ ...pagination?.nextCursor !== void 0 ? { nextCursor: pagination.nextCursor } : {},
3363
+ retryPosition
3364
+ };
3365
+ }
3366
+ function positionAfter(pagination, action) {
3367
+ const current = pagination?.position ?? firstPagePosition();
3368
+ switch (action.type) {
3369
+ case "search":
3370
+ return firstPagePosition({
3371
+ search: action.term,
3372
+ generation: current.generation + 1
3373
+ });
3374
+ case "next_page": {
3375
+ if (pagination?.nextCursor == null) return current;
3376
+ return {
3377
+ ...current.search !== void 0 ? { search: current.search } : {},
3378
+ pageCursor: pagination.nextCursor,
3379
+ previousCursors: [...current.previousCursors, current.pageCursor],
3380
+ generation: current.generation
3381
+ };
3382
+ }
3383
+ case "previous_page": {
3384
+ if (current.previousCursors.length === 0) return current;
3385
+ return {
3386
+ ...current.search !== void 0 ? { search: current.search } : {},
3387
+ pageCursor: current.previousCursors[current.previousCursors.length - 1],
3388
+ previousCursors: current.previousCursors.slice(0, -1),
3389
+ generation: current.generation
3390
+ };
3391
+ }
3392
+ case "retry":
3393
+ return pagination?.retryPosition ?? current;
3394
+ }
3395
+ }
3309
3396
  function toJsonSchema(schema) {
3310
3397
  if (!schema) return void 0;
3311
3398
  try {
@@ -5196,7 +5283,7 @@ function parseDeprecationDate(value) {
5196
5283
  }
5197
5284
 
5198
5285
  // src/sdk-version.ts
5199
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.2" : void 0) || "unknown";
5286
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.84.4" : void 0) || "unknown";
5200
5287
 
5201
5288
  // src/utils/open-url.ts
5202
5289
  var nodePrefix = "node:";
@@ -6931,6 +7018,7 @@ function transformConnectionItem(item) {
6931
7018
  is_private: item.is_private,
6932
7019
  shared_with_all: item.shared_with_all,
6933
7020
  title: item.title,
7021
+ slug: item.slug,
6934
7022
  lastchanged: item.lastchanged,
6935
7023
  is_stale: item.is_stale,
6936
7024
  is_shared: item.is_shared,
@@ -8091,8 +8179,9 @@ var appKeyResolver = defineResolver({
8091
8179
  },
8092
8180
  listItems: ({
8093
8181
  imports,
8094
- search
8095
- }) => imports.listApps({ search }),
8182
+ search,
8183
+ cursor
8184
+ }) => imports.listApps({ search, cursor }),
8096
8185
  prompt: ({ items }) => ({
8097
8186
  type: "list",
8098
8187
  message: "Select app:",
@@ -8113,9 +8202,11 @@ var actionTypeResolver = defineResolver({
8113
8202
  imports,
8114
8203
  input
8115
8204
  }) => {
8116
- const { data } = await imports.listActions({ app: input.app });
8117
- const types = [...new Set(data.map((action) => action.action_type))];
8118
- return { data: types.map((type) => ({ key: type, name: type })) };
8205
+ const types = /* @__PURE__ */ new Set();
8206
+ for await (const action of imports.listActions({ app: input.app }).items()) {
8207
+ types.add(action.action_type);
8208
+ }
8209
+ return { data: [...types].map((type) => ({ key: type, name: type })) };
8119
8210
  },
8120
8211
  prompt: ({ items }) => ({
8121
8212
  type: "list",
@@ -8131,13 +8222,15 @@ var actionKeyResolver = defineResolver({
8131
8222
  requireParameters: ["app", "actionType"],
8132
8223
  listItems: async ({
8133
8224
  imports,
8134
- input
8225
+ input,
8226
+ cursor
8135
8227
  }) => {
8136
- const { data } = await imports.listActions({ app: input.app });
8228
+ const page = await imports.listActions({ app: input.app, cursor });
8137
8229
  return {
8138
- data: data.filter(
8230
+ data: page.data.filter(
8139
8231
  (action) => action.action_type === input.actionType && !action.is_hidden
8140
- )
8232
+ ),
8233
+ nextCursor: page.nextCursor
8141
8234
  };
8142
8235
  },
8143
8236
  prompt: ({ items }) => ({
@@ -8254,9 +8347,10 @@ var connectionIdResolver = defineResolver({
8254
8347
  }
8255
8348
  return null;
8256
8349
  },
8257
- listItems: ({ imports, input, context }) => imports.listConnections({
8350
+ listItems: ({ imports, input, context, cursor }) => imports.listConnections({
8258
8351
  app: input.app,
8259
- includeShared: context?.canIncludeShared || void 0
8352
+ includeShared: context?.canIncludeShared || void 0,
8353
+ cursor
8260
8354
  }),
8261
8355
  prompt: ({ items, input, context }) => buildConnectionPrompt(
8262
8356
  items,
@@ -8272,9 +8366,10 @@ var connectionIdGenericResolver = defineResolver({
8272
8366
  );
8273
8367
  return { canIncludeShared: canIncludeShared ?? false };
8274
8368
  },
8275
- listItems: ({ imports, input, context }) => imports.listConnections({
8369
+ listItems: ({ imports, input, context, cursor }) => imports.listConnections({
8276
8370
  app: input.app,
8277
- includeShared: context?.canIncludeShared || void 0
8371
+ includeShared: context?.canIncludeShared || void 0,
8372
+ cursor
8278
8373
  }),
8279
8374
  prompt: ({ items, input, context }) => buildConnectionPrompt(
8280
8375
  items,
@@ -8302,12 +8397,13 @@ var listActionInputFieldChoicesRef = declareMethod({ id: "listActionInputFieldCh
8302
8397
  var choiceResolver = defineResolver({
8303
8398
  imports: [listActionInputFieldChoicesRef],
8304
8399
  requireParameters: ["app", "action", "actionType"],
8305
- listItems: ({ imports, input }) => imports.listActionInputFieldChoices({
8400
+ listItems: ({ imports, input, cursor }) => imports.listActionInputFieldChoices({
8306
8401
  app: input.app,
8307
8402
  action: input.action,
8308
8403
  actionType: input.actionType,
8309
8404
  connection: input.connection,
8310
- inputField: input.inputField
8405
+ inputField: input.inputField,
8406
+ cursor
8311
8407
  }),
8312
8408
  prompt: ({ items }) => ({
8313
8409
  type: "list",
@@ -8466,7 +8562,7 @@ var clientCredentialsNameResolver = defineResolver({
8466
8562
  var listClientCredentialsRef = declareMethod({ id: "listClientCredentials" });
8467
8563
  var clientIdResolver = defineResolver({
8468
8564
  imports: [listClientCredentialsRef],
8469
- listItems: ({ imports }) => imports.listClientCredentials({}),
8565
+ listItems: ({ imports, cursor }) => imports.listClientCredentials({ cursor }),
8470
8566
  prompt: ({ items }) => ({
8471
8567
  type: "list",
8472
8568
  message: "Select client credentials to delete:",
@@ -8478,9 +8574,9 @@ var clientIdResolver = defineResolver({
8478
8574
  });
8479
8575
 
8480
8576
  // src/resolvers/tableId.ts
8481
- var listTablesRef = declareMethod({ id: "listTables" });
8577
+ var listTablesInternalRef = declareMethod({ id: "listTablesInternal" });
8482
8578
  var tableIdResolver = defineResolver({
8483
- imports: [listTablesRef, capabilitiesPluginRef],
8579
+ imports: [listTablesInternalRef, capabilitiesPluginRef],
8484
8580
  getContext: async ({ imports }) => {
8485
8581
  const includeShared = await imports.capabilities.hasCapability?.(
8486
8582
  "canIncludeSharedTables"
@@ -8488,27 +8584,36 @@ var tableIdResolver = defineResolver({
8488
8584
  return { includeShared: includeShared ?? false };
8489
8585
  },
8490
8586
  // Unlike connections, the tables API does not return personal tables first,
8491
- // so we use concatPaginated to hoist own tables above shared.
8492
- listItems: ({ imports, context }) => {
8587
+ // so we concatenate personal-only and shared-only slices to hoist own
8588
+ // tables above shared. The slices are disjoint by construction, so the
8589
+ // concatenation paginates with stateless cursors and needs no dedupe.
8590
+ listItems: ({ imports, context, cursor }) => {
8493
8591
  const includeShared = context?.includeShared;
8494
8592
  if (includeShared) {
8495
8593
  return concatPaginated({
8496
8594
  sources: [
8497
- () => imports.listTables({}),
8498
- () => imports.listTables({ includeShared: true })
8595
+ ({ cursor: sourceCursor }) => imports.listTablesInternal({ cursor: sourceCursor }),
8596
+ ({ cursor: sourceCursor }) => imports.listTablesInternal({
8597
+ includeShared: true,
8598
+ includePersonal: false,
8599
+ cursor: sourceCursor
8600
+ })
8499
8601
  ],
8500
- dedupe: (table) => table.id
8602
+ cursor
8501
8603
  });
8502
8604
  }
8503
- return imports.listTables({});
8605
+ return imports.listTablesInternal({ cursor });
8504
8606
  },
8505
- prompt: ({ items }) => ({
8607
+ prompt: ({ items, context }) => ({
8506
8608
  type: "list",
8507
8609
  message: "Select a table:",
8508
8610
  choices: items.map((table) => ({
8509
8611
  label: table.name,
8510
8612
  value: table.id
8511
- }))
8613
+ })),
8614
+ // The capability hint the legacy picker showed as a fake disabled row:
8615
+ // without it, a gated account just sees fewer tables with no explanation.
8616
+ ...context?.includeShared ? {} : { notes: ["Shared tables are hidden for this account."] }
8512
8617
  })
8513
8618
  });
8514
8619
 
@@ -8516,7 +8621,7 @@ var tableIdResolver = defineResolver({
8516
8621
  var listTriggerInboxesRef = declareMethod({ id: "listTriggerInboxes" });
8517
8622
  var triggerInboxResolver = defineResolver({
8518
8623
  imports: [listTriggerInboxesRef],
8519
- listItems: ({ imports }) => imports.listTriggerInboxes({}),
8624
+ listItems: ({ imports, cursor }) => imports.listTriggerInboxes({ cursor }),
8520
8625
  prompt: ({ items }) => ({
8521
8626
  type: "list",
8522
8627
  message: "Select a trigger inbox:",
@@ -8534,7 +8639,7 @@ var triggerInboxResolver = defineResolver({
8534
8639
  var listWorkflowsRef = declareMethod({ id: "listWorkflows" });
8535
8640
  var workflowIdResolver = defineResolver({
8536
8641
  imports: [listWorkflowsRef],
8537
- listItems: ({ imports }) => imports.listWorkflows({}),
8642
+ listItems: ({ imports, cursor }) => imports.listWorkflows({ cursor }),
8538
8643
  prompt: ({ items }) => ({
8539
8644
  type: "list",
8540
8645
  message: "Select a workflow:",
@@ -8550,7 +8655,7 @@ var workflowIdResolver = defineResolver({
8550
8655
  var listDurableRunsRef = declareMethod({ id: "listDurableRuns" });
8551
8656
  var durableRunIdResolver = defineResolver({
8552
8657
  imports: [listDurableRunsRef],
8553
- listItems: ({ imports }) => imports.listDurableRuns({}),
8658
+ listItems: ({ imports, cursor }) => imports.listDurableRuns({ cursor }),
8554
8659
  prompt: ({ items }) => ({
8555
8660
  type: "list",
8556
8661
  message: "Select a run:",
@@ -8567,7 +8672,14 @@ var listWorkflowVersionsRef = declareMethod({ id: "listWorkflowVersions" });
8567
8672
  var workflowVersionIdResolver = defineResolver({
8568
8673
  imports: [listWorkflowVersionsRef],
8569
8674
  requireParameters: ["workflow"],
8570
- listItems: ({ imports, input }) => imports.listWorkflowVersions({ workflow: input.workflow }),
8675
+ listItems: ({
8676
+ imports,
8677
+ input,
8678
+ cursor
8679
+ }) => imports.listWorkflowVersions({
8680
+ workflow: input.workflow,
8681
+ cursor
8682
+ }),
8571
8683
  prompt: ({ items }) => ({
8572
8684
  type: "list",
8573
8685
  message: "Select a workflow version:",
@@ -8583,7 +8695,11 @@ var listWorkflowRunsRef = declareMethod({ id: "listWorkflowRuns" });
8583
8695
  var workflowRunIdResolver = defineResolver({
8584
8696
  imports: [listWorkflowRunsRef],
8585
8697
  requireParameters: ["workflow"],
8586
- listItems: ({ imports, input }) => imports.listWorkflowRuns({ workflow: input.workflow }),
8698
+ listItems: ({
8699
+ imports,
8700
+ input,
8701
+ cursor
8702
+ }) => imports.listWorkflowRuns({ workflow: input.workflow, cursor }),
8587
8703
  prompt: ({ items }) => ({
8588
8704
  type: "list",
8589
8705
  message: "Select a workflow run:",
@@ -8601,8 +8717,9 @@ var triggerMessagesResolver = defineResolver({
8601
8717
  requireParameters: ["inbox"],
8602
8718
  listItems: ({
8603
8719
  imports,
8604
- input
8605
- }) => imports.listTriggerInboxMessages({ inbox: input.inbox }),
8720
+ input,
8721
+ cursor
8722
+ }) => imports.listTriggerInboxMessages({ inbox: input.inbox, cursor }),
8606
8723
  prompt: ({ items }) => ({
8607
8724
  type: "checkbox",
8608
8725
  message: "Select messages:",
@@ -8875,9 +8992,10 @@ function recordChoices(records) {
8875
8992
  var tableRecordIdResolver = defineResolver({
8876
8993
  imports: [listTableRecordsRef],
8877
8994
  requireParameters: ["table"],
8878
- listItems: ({ imports, input }) => imports.listTableRecords({
8995
+ listItems: ({ imports, input, cursor }) => imports.listTableRecords({
8879
8996
  table: input.table,
8880
- keyMode: "names"
8997
+ keyMode: "names",
8998
+ cursor
8881
8999
  }),
8882
9000
  prompt: ({ items }) => ({
8883
9001
  type: "list",
@@ -8888,16 +9006,17 @@ var tableRecordIdResolver = defineResolver({
8888
9006
  var tableRecordIdsResolver = defineResolver({
8889
9007
  imports: [listTableRecordsRef],
8890
9008
  requireParameters: ["table"],
8891
- listItems: ({ imports, input }) => imports.listTableRecords({
9009
+ listItems: ({ imports, input, cursor }) => imports.listTableRecords({
8892
9010
  table: input.table,
8893
- keyMode: "names"
9011
+ keyMode: "names",
9012
+ cursor
8894
9013
  }),
8895
9014
  prompt: ({ items }) => ({
8896
9015
  type: "checkbox",
8897
9016
  message: "Select records to delete:",
8898
- choices: recordChoices(items),
8899
- validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Select at least one record"
8900
- })
9017
+ choices: recordChoices(items)
9018
+ }),
9019
+ validate: ({ value }) => Array.isArray(value) && value.length > 0 ? true : "Select at least one record"
8901
9020
  });
8902
9021
 
8903
9022
  // src/resolvers/tableFieldIds.ts
@@ -8905,6 +9024,8 @@ var listTableFieldsRef = declareMethod({ id: "listTableFields" });
8905
9024
  var tableFieldIdsResolver = defineResolver({
8906
9025
  imports: [listTableFieldsRef],
8907
9026
  requireParameters: ["table"],
9027
+ // No cursor forwarding: the fields API is unpaginated (no cursor on the
9028
+ // response), so the listing is always exhausted after one page.
8908
9029
  listItems: ({ imports, input }) => imports.listTableFields({ table: input.table }),
8909
9030
  prompt: ({ items }) => ({
8910
9031
  type: "checkbox",
@@ -8913,9 +9034,9 @@ var tableFieldIdsResolver = defineResolver({
8913
9034
  label: field.name,
8914
9035
  hint: [field.id, field.type],
8915
9036
  value: field.id
8916
- })),
8917
- validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Select at least one field"
8918
- })
9037
+ }))
9038
+ }),
9039
+ validate: ({ value }) => Array.isArray(value) && value.length > 0 ? true : "Select at least one field"
8919
9040
  });
8920
9041
 
8921
9042
  // src/resolvers/tableName.ts
@@ -9920,6 +10041,11 @@ var ConnectionItemSchema = connections.ConnectionItemSchema;
9920
10041
  // src/formatters/connection.ts
9921
10042
  function formatConnectionItem(item) {
9922
10043
  const details = [];
10044
+ const appKey = item.app_key ?? "unknown";
10045
+ details.push({
10046
+ text: item.slug ? `App: ${appKey} | App Slug: ${item.slug}` : `App: ${appKey}`,
10047
+ style: "accent"
10048
+ });
9923
10049
  if (item.identifier) {
9924
10050
  details.push({
9925
10051
  text: `Identifier: ${item.identifier}`,
@@ -13090,27 +13216,31 @@ var ListTablesOptionsSchema = zod.z.object({
13090
13216
  maxItems: zod.z.number().min(1).optional().describe("Maximum total items to return across all pages"),
13091
13217
  cursor: zod.z.string().optional().describe("Cursor to start from")
13092
13218
  }).describe("List tables available to the authenticated user");
13219
+ var ListTablesInternalOptionsSchema = ListTablesOptionsSchema.extend({
13220
+ includePersonal: zod.z.boolean().optional().describe(
13221
+ "Include your own tables (default true). Set false with includeShared to list only tables shared with you."
13222
+ )
13223
+ });
13093
13224
 
13094
- // src/plugins/tables/shared.ts
13095
- var tableCategories = ["table"];
13096
-
13097
- // src/plugins/tables/listTables/index.ts
13098
- var listTablesPlugin = defineMethod({
13099
- name: "listTables",
13225
+ // src/plugins/tables/listTables/internal.ts
13226
+ var listTablesInternalPlugin = defineMethod({
13227
+ name: "listTablesInternal",
13100
13228
  imports: [apiPluginRef, capabilitiesPluginRef],
13101
- categories: tableCategories,
13102
- itemType: "Table",
13103
- inputSchema: ListTablesOptionsSchema,
13104
- outputSchema: TableItemSchema,
13229
+ inputSchema: ListTablesInternalOptionsSchema,
13105
13230
  output: {
13106
13231
  type: "list",
13107
13232
  adaptPage: adaptZapierPage,
13108
13233
  defaultPageSize: DEFAULT_PAGE_SIZE
13109
13234
  },
13110
13235
  run: async ({ imports, input }) => {
13111
- if (input.includeShared) {
13236
+ const includePersonal = input.includePersonal ?? true;
13237
+ const includeShared = input.includeShared ?? false;
13238
+ if (includeShared) {
13112
13239
  await imports.capabilities.checkCapability("canIncludeSharedTables");
13113
13240
  }
13241
+ if (!includePersonal && !includeShared) {
13242
+ return { data: [] };
13243
+ }
13114
13244
  const api = imports.api;
13115
13245
  const searchParams = {};
13116
13246
  if (input.pageSize !== void 0) {
@@ -13126,23 +13256,18 @@ var listTablesPlugin = defineMethod({
13126
13256
  if (input.search) {
13127
13257
  searchParams.q = input.search;
13128
13258
  }
13129
- if (input.owner && input.owner !== "me" && !input.includeShared) {
13259
+ if (input.owner && input.owner !== "me" && !includeShared) {
13130
13260
  throw new ZapierValidationError(
13131
13261
  'The "owner" option requires "includeShared" to be true. Without includeShared, only your own tables are returned.'
13132
13262
  );
13133
13263
  }
13134
- const owner = input.includeShared ? input.owner : "me";
13264
+ const owner = includeShared ? input.owner : "me";
13265
+ const needsProfileId = owner === "me" || !includePersonal && includeShared;
13266
+ const profileId = needsProfileId ? (await api.get("/zapier/api/v4/profile/", {
13267
+ authRequired: true
13268
+ })).id : void 0;
13135
13269
  if (owner) {
13136
- if (owner === "me") {
13137
- const profile = await api.get("/zapier/api/v4/profile/", {
13138
- authRequired: true
13139
- });
13140
- searchParams.owner_customuser_id = String(
13141
- profile.id
13142
- );
13143
- } else {
13144
- searchParams.owner_customuser_id = owner;
13145
- }
13270
+ searchParams.owner_customuser_id = owner === "me" ? String(profileId) : owner;
13146
13271
  }
13147
13272
  if (input.cursor) {
13148
13273
  searchParams.offset = input.cursor;
@@ -13152,12 +13277,35 @@ var listTablesPlugin = defineMethod({
13152
13277
  authRequired: true
13153
13278
  });
13154
13279
  const response = ListTablesApiResponseSchema.parse(rawResponse);
13280
+ const apiItems = includePersonal ? response.data : response.data.filter(
13281
+ (item) => item.owner_zapier_customuser_id !== profileId
13282
+ );
13155
13283
  return {
13156
- data: response.data.map(transformTableItem),
13284
+ data: apiItems.map(transformTableItem),
13157
13285
  links: response.links
13158
13286
  };
13159
13287
  }
13160
13288
  });
13289
+
13290
+ // src/plugins/tables/shared.ts
13291
+ var tableCategories = ["table"];
13292
+
13293
+ // src/plugins/tables/listTables/index.ts
13294
+ var listTablesPlugin = defineMethod({
13295
+ name: "listTables",
13296
+ imports: [listTablesInternalPlugin],
13297
+ categories: tableCategories,
13298
+ itemType: "Table",
13299
+ inputSchema: ListTablesOptionsSchema,
13300
+ outputSchema: TableItemSchema,
13301
+ output: "list",
13302
+ run: async ({ imports, input }) => {
13303
+ return await imports.listTablesInternal({
13304
+ ...input,
13305
+ includePersonal: void 0
13306
+ });
13307
+ }
13308
+ });
13161
13309
  var GetTableApiResponseSchema = zod.z.object({
13162
13310
  data: TableApiItemSchema
13163
13311
  });