@zapier/zapier-sdk 0.70.4 → 0.71.1

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +149 -31
  3. package/dist/api/approval-review-stream.d.ts +25 -0
  4. package/dist/api/approval-review-stream.d.ts.map +1 -0
  5. package/dist/api/approval-review-stream.js +104 -0
  6. package/dist/api/client.d.ts.map +1 -1
  7. package/dist/api/client.js +215 -27
  8. package/dist/api/types.d.ts +13 -3
  9. package/dist/api/types.d.ts.map +1 -1
  10. package/dist/constants.d.ts +1 -0
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +6 -0
  13. package/dist/experimental.cjs +602 -37
  14. package/dist/experimental.d.mts +88 -2
  15. package/dist/experimental.d.ts +90 -4
  16. package/dist/experimental.d.ts.map +1 -1
  17. package/dist/experimental.js +10 -0
  18. package/dist/experimental.mjs +602 -38
  19. package/dist/{index-BNaiNmM-.d.mts → index-B43uST61.d.mts} +181 -12
  20. package/dist/{index-BNaiNmM-.d.ts → index-B43uST61.d.ts} +181 -12
  21. package/dist/index.cjs +592 -32
  22. package/dist/index.d.mts +1 -1
  23. package/dist/index.mjs +592 -33
  24. package/dist/plugins/api/index.d.ts.map +1 -1
  25. package/dist/plugins/api/index.js +2 -1
  26. package/dist/plugins/codeSubstrate/createWorkflow/index.d.ts +1 -0
  27. package/dist/plugins/codeSubstrate/createWorkflow/index.d.ts.map +1 -1
  28. package/dist/plugins/codeSubstrate/createWorkflow/index.js +3 -2
  29. package/dist/plugins/codeSubstrate/createWorkflow/schemas.d.ts +1 -0
  30. package/dist/plugins/codeSubstrate/createWorkflow/schemas.d.ts.map +1 -1
  31. package/dist/plugins/codeSubstrate/createWorkflow/schemas.js +7 -1
  32. package/dist/plugins/codeSubstrate/deleteWorkflow/index.d.ts +1 -1
  33. package/dist/plugins/codeSubstrate/disableWorkflow/index.d.ts +1 -1
  34. package/dist/plugins/codeSubstrate/enableWorkflow/index.d.ts +1 -1
  35. package/dist/plugins/codeSubstrate/getDurableRun/schemas.d.ts +4 -4
  36. package/dist/plugins/codeSubstrate/getWorkflow/index.d.ts +2 -2
  37. package/dist/plugins/codeSubstrate/getWorkflow/schemas.d.ts +1 -1
  38. package/dist/plugins/codeSubstrate/getWorkflowRun/index.d.ts +1 -1
  39. package/dist/plugins/codeSubstrate/getWorkflowVersion/index.d.ts +1 -1
  40. package/dist/plugins/codeSubstrate/listWorkflowRuns/index.d.ts +1 -1
  41. package/dist/plugins/codeSubstrate/listWorkflowVersions/index.d.ts +1 -1
  42. package/dist/plugins/codeSubstrate/listWorkflows/index.d.ts +1 -1
  43. package/dist/plugins/codeSubstrate/listWorkflows/schemas.d.ts +2 -2
  44. package/dist/plugins/codeSubstrate/publishWorkflowVersion/index.d.ts +1 -1
  45. package/dist/plugins/codeSubstrate/runDurable/schemas.js +1 -1
  46. package/dist/plugins/codeSubstrate/shared-schemas.d.ts +2 -2
  47. package/dist/plugins/codeSubstrate/triggerWorkflow/index.d.ts +1 -1
  48. package/dist/plugins/codeSubstrate/updateWorkflow/index.d.ts +1 -1
  49. package/dist/plugins/createConnection/index.d.ts +189 -0
  50. package/dist/plugins/createConnection/index.d.ts.map +1 -0
  51. package/dist/plugins/createConnection/index.js +71 -0
  52. package/dist/plugins/createConnection/schemas.d.ts +21 -0
  53. package/dist/plugins/createConnection/schemas.d.ts.map +1 -0
  54. package/dist/plugins/createConnection/schemas.js +38 -0
  55. package/dist/plugins/getConnectionStartUrl/index.d.ts +206 -0
  56. package/dist/plugins/getConnectionStartUrl/index.d.ts.map +1 -0
  57. package/dist/plugins/getConnectionStartUrl/index.js +39 -0
  58. package/dist/plugins/getConnectionStartUrl/schemas.d.ts +15 -0
  59. package/dist/plugins/getConnectionStartUrl/schemas.d.ts.map +1 -0
  60. package/dist/plugins/getConnectionStartUrl/schemas.js +23 -0
  61. package/dist/plugins/waitForNewConnection/index.d.ts +209 -0
  62. package/dist/plugins/waitForNewConnection/index.d.ts.map +1 -0
  63. package/dist/plugins/waitForNewConnection/index.js +75 -0
  64. package/dist/plugins/waitForNewConnection/schemas.d.ts +17 -0
  65. package/dist/plugins/waitForNewConnection/schemas.d.ts.map +1 -0
  66. package/dist/plugins/waitForNewConnection/schemas.js +39 -0
  67. package/dist/sdk.d.ts +126 -0
  68. package/dist/sdk.d.ts.map +1 -1
  69. package/dist/sdk.js +8 -0
  70. package/dist/types/errors.d.ts +13 -4
  71. package/dist/types/errors.d.ts.map +1 -1
  72. package/dist/types/errors.js +2 -0
  73. package/dist/types/sdk.d.ts +1 -0
  74. package/dist/types/sdk.d.ts.map +1 -1
  75. package/dist/types/sdk.js +5 -1
  76. package/dist/utils/open-url.d.ts.map +1 -1
  77. package/dist/utils/open-url.js +7 -0
  78. package/dist/utils/should-open-browser.d.ts +24 -0
  79. package/dist/utils/should-open-browser.d.ts.map +1 -0
  80. package/dist/utils/should-open-browser.js +55 -0
  81. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1060,6 +1060,11 @@ function getZapierApprovalMode() {
1060
1060
  return value;
1061
1061
  return void 0;
1062
1062
  }
1063
+ function getZapierOpenAutoModeApprovalsInBrowser() {
1064
+ const value = globalThis.process?.env?.ZAPIER_OPEN_AUTO_MODE_APPROVALS_IN_BROWSER;
1065
+ if (value === void 0) return void 0;
1066
+ return value === "true";
1067
+ }
1063
1068
  function getZapierDefaultApprovalMode() {
1064
1069
  const isInteractive = !!globalThis.process?.stdin?.isTTY && !!globalThis.process?.stdout?.isTTY;
1065
1070
  return isInteractive ? "poll" : "throw";
@@ -1283,6 +1288,8 @@ var ZapierApprovalError = class extends ZapierError {
1283
1288
  this.approvalStatus = options.status;
1284
1289
  this.approvalUrl = options.approvalUrl;
1285
1290
  this.pollUrl = options.pollUrl;
1291
+ this.streamUrl = options.streamUrl;
1292
+ this.reason = options.reason;
1286
1293
  }
1287
1294
  };
1288
1295
  var ZapierRelayError = class extends ZapierError {
@@ -6779,9 +6786,101 @@ function createSseParserStream() {
6779
6786
  }
6780
6787
  });
6781
6788
  }
6789
+ var ApprovalReviewChunkSchema = zod.z.discriminatedUnion("type", [
6790
+ zod.z.object({
6791
+ type: zod.z.literal("text-delta"),
6792
+ delta: zod.z.string()
6793
+ }).passthrough(),
6794
+ zod.z.object({
6795
+ type: zod.z.literal("tool-input-available"),
6796
+ toolCallId: zod.z.string(),
6797
+ toolName: zod.z.string()
6798
+ }).passthrough(),
6799
+ zod.z.object({
6800
+ type: zod.z.literal("tool-output-available"),
6801
+ toolCallId: zod.z.string(),
6802
+ output: zod.z.unknown()
6803
+ }).passthrough()
6804
+ ]);
6805
+ var ReportDecisionOutputSchema = zod.z.object({
6806
+ success: zod.z.boolean().optional(),
6807
+ decision: zod.z.enum(["approved", "denied"]),
6808
+ reason: zod.z.string().optional()
6809
+ }).passthrough();
6810
+ async function consumeApprovalReviewStream({
6811
+ approvalId,
6812
+ streamUrl,
6813
+ signal,
6814
+ stream,
6815
+ emitEvent
6816
+ }) {
6817
+ try {
6818
+ const toolNames = /* @__PURE__ */ new Map();
6819
+ for await (const frame of stream(streamUrl, {
6820
+ method: "GET",
6821
+ headers: {
6822
+ "Accept-Encoding": "identity"
6823
+ },
6824
+ signal
6825
+ })) {
6826
+ if (!frame.parsed) continue;
6827
+ const payload = parseApprovalReviewStreamPayload(frame.data, toolNames);
6828
+ if (!payload) continue;
6829
+ if (payload.kind === "message") {
6830
+ emitEvent("approval:review_message", {
6831
+ approvalId,
6832
+ streamUrl,
6833
+ data: payload.data,
6834
+ message: payload.message
6835
+ });
6836
+ continue;
6837
+ }
6838
+ emitEvent("approval:review_decision", {
6839
+ approvalId,
6840
+ streamUrl,
6841
+ data: payload.data,
6842
+ decision: payload.decision,
6843
+ ...payload.reason ? { reason: payload.reason } : {}
6844
+ });
6845
+ }
6846
+ } catch (err) {
6847
+ if (isAbortError(err) || signal.aborted) return;
6848
+ emitEvent("approval:review_stream_error", {
6849
+ approvalId,
6850
+ streamUrl,
6851
+ message: err instanceof Error ? err.message : String(err)
6852
+ });
6853
+ }
6854
+ }
6855
+ function parseApprovalReviewStreamPayload(parsed, toolNames) {
6856
+ const chunk = ApprovalReviewChunkSchema.safeParse(parsed);
6857
+ if (!chunk.success) return void 0;
6858
+ switch (chunk.data.type) {
6859
+ case "text-delta": {
6860
+ const message = chunk.data.delta.trim();
6861
+ return message.length > 0 ? { kind: "message", data: parsed, message } : void 0;
6862
+ }
6863
+ case "tool-input-available":
6864
+ toolNames.set(chunk.data.toolCallId, chunk.data.toolName);
6865
+ return void 0;
6866
+ case "tool-output-available": {
6867
+ if (toolNames.get(chunk.data.toolCallId) !== "report_decision") {
6868
+ return void 0;
6869
+ }
6870
+ const decision = ReportDecisionOutputSchema.safeParse(chunk.data.output);
6871
+ if (!decision.success) return void 0;
6872
+ return {
6873
+ kind: "decision",
6874
+ data: parsed,
6875
+ decision: decision.data.decision,
6876
+ ...decision.data.reason ? { reason: decision.data.reason } : {}
6877
+ };
6878
+ }
6879
+ }
6880
+ }
6782
6881
 
6783
6882
  // src/sdk-version.ts
6784
- var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.70.4" : void 0) || "unknown";
6883
+ var SDK_VERSION = (typeof process !== "undefined" && process.env ? "0.71.1" : void 0) || "unknown";
6785
6884
 
6786
6885
  // src/utils/open-url.ts
6787
6886
  var nodePrefix = "node:";
@@ -6833,6 +6932,9 @@ var openUrl = async (url) => {
6833
6932
  } else if (platform === "win32") {
6834
6933
  command = "rundll32";
6835
6934
  args = ["url.dll,FileProtocolHandler", target];
6935
+ } else if (platform === "linux") {
6936
+ command = "xdg-open";
6937
+ args = [target];
6836
6938
  } else {
6837
6939
  throw new Error(`Unsupported platform: ${platform}`);
6838
6940
  }
@@ -6855,16 +6957,39 @@ async function openApproval(url) {
6855
6957
  } catch {
6856
6958
  }
6857
6959
  }
6858
- var ApprovalStatusSchema = zod.z.enum(["pending_approval", "approved", "denied"]);
6960
+ var ApprovalStatusSchema = zod.z.enum([
6961
+ "pending_approval",
6962
+ "approved",
6963
+ "denied",
6964
+ "failed"
6965
+ ]);
6966
+ var ApprovalModeSchema = zod.z.enum(["manual", "auto"]);
6859
6967
  var CreateApprovalResponseSchema = zod.z.object({
6968
+ id: zod.z.string().optional(),
6860
6969
  status: ApprovalStatusSchema,
6861
- approval_id: zod.z.string(),
6970
+ approval_id: zod.z.string().optional(),
6971
+ mode: ApprovalModeSchema,
6862
6972
  approval_url: zod.z.string().url(),
6863
- poll_url: zod.z.string().url()
6973
+ poll_url: zod.z.string().url(),
6974
+ stream_url: zod.z.string().url().optional(),
6975
+ reason: zod.z.string().optional()
6976
+ }).transform((approval, ctx) => {
6977
+ const id = approval.id ?? approval.approval_id;
6978
+ if (!id) {
6979
+ ctx.addIssue({
6980
+ code: "custom",
6981
+ message: "Approval response must include id"
6982
+ });
6983
+ return zod.z.NEVER;
6984
+ }
6985
+ return { ...approval, id };
6864
6986
  });
6865
6987
  var PollApprovalResponseSchema = zod.z.object({
6988
+ id: zod.z.string().optional(),
6866
6989
  status: ApprovalStatusSchema,
6867
- approval_id: zod.z.string()
6990
+ approval_id: zod.z.string().optional(),
6991
+ mode: ApprovalModeSchema.optional(),
6992
+ reason: zod.z.string().optional()
6868
6993
  });
6869
6994
  var APPROVAL_MAX_POLLING_INTERVAL_MS = 5e3;
6870
6995
  function parseRateLimitHeaders(response) {
@@ -7137,7 +7262,11 @@ var ZapierApiClient = class {
7137
7262
  { statusCode: 403 }
7138
7263
  );
7139
7264
  }
7140
- await this.runOneApprovalRound(init.approvalContext, mode);
7265
+ await this.runOneApprovalRound(
7266
+ init.approvalContext,
7267
+ mode,
7268
+ init.signal ?? void 0
7269
+ );
7141
7270
  }
7142
7271
  throw new ZapierApprovalError(
7143
7272
  `Exceeded maximum approval retries (${maxRetries}) for ${path}`,
@@ -7165,6 +7294,7 @@ var ZapierApiClient = class {
7165
7294
  * any frame), so transport / auth failures surface as usual.
7166
7295
  */
7167
7296
  this.fetchJsonStream = (path, init) => jsonFrames(this.fetchStream(path, init));
7297
+ this.streamTrustedJsonUrl = (url, init) => jsonFrames(this.streamTrustedSseUrl(url, init));
7168
7298
  this.get = async (path, options = {}) => {
7169
7299
  return this.fetchJson("GET", path, void 0, options);
7170
7300
  };
@@ -7504,7 +7634,7 @@ var ZapierApiClient = class {
7504
7634
  // bound `fetchStream` arrow above for parity with the other client methods.
7505
7635
  async *streamSse(path, init) {
7506
7636
  const { onOpen, headers: initHeaders, ...fetchInit } = init ?? {};
7507
- const signal = fetchInit.signal;
7637
+ const signal = fetchInit.signal ?? void 0;
7508
7638
  if (signal?.aborted) return;
7509
7639
  const wasMissingAuthToken = fetchInit.authRequired === true && await this.getAuthToken({
7510
7640
  requiredScopes: fetchInit.requiredScopes
@@ -7522,13 +7652,62 @@ var ZapierApiClient = class {
7522
7652
  if (signal?.aborted || isAbortError(err)) return;
7523
7653
  throw err;
7524
7654
  }
7655
+ yield* this.readSseResponse({
7656
+ response,
7657
+ signal,
7658
+ onOpen,
7659
+ wasMissingAuthToken,
7660
+ requiredScopes: fetchInit.requiredScopes
7661
+ });
7662
+ }
7663
+ // Approval `stream_url` is server-supplied and origin-pinned before use, like
7664
+ // `poll_url`; keep absolute-URL streaming private rather than widening the
7665
+ // public path-based `fetchStream` API.
7666
+ async *streamTrustedSseUrl(url, init) {
7667
+ const { onOpen, headers: initHeaders, ...fetchInit } = init ?? {};
7668
+ const signal = fetchInit.signal ?? void 0;
7669
+ if (signal?.aborted) return;
7670
+ const wasMissingAuthToken = fetchInit.authRequired === true && await this.getAuthToken({
7671
+ requiredScopes: fetchInit.requiredScopes
7672
+ }) == null;
7673
+ const headers = new Headers(initHeaders);
7674
+ if (!headers.has("Accept")) headers.set("Accept", "text/event-stream");
7675
+ let response;
7676
+ try {
7677
+ response = await this.withSemaphore(
7678
+ { url, method: fetchInit.method ?? "GET", signal },
7679
+ () => this.rawFetchUrl(url, {
7680
+ ...fetchInit,
7681
+ method: fetchInit.method ?? "GET",
7682
+ headers
7683
+ })
7684
+ );
7685
+ } catch (err) {
7686
+ if (signal?.aborted || isAbortError(err)) return;
7687
+ throw err;
7688
+ }
7689
+ yield* this.readSseResponse({
7690
+ response,
7691
+ signal,
7692
+ onOpen,
7693
+ wasMissingAuthToken,
7694
+ requiredScopes: fetchInit.requiredScopes
7695
+ });
7696
+ }
7697
+ async *readSseResponse({
7698
+ response,
7699
+ signal,
7700
+ onOpen,
7701
+ wasMissingAuthToken,
7702
+ requiredScopes
7703
+ }) {
7525
7704
  if (!response.ok) {
7526
7705
  const { data } = await this.parseResult(response);
7527
7706
  await this.throwForErrorResponse({
7528
7707
  response,
7529
7708
  responseData: data,
7530
7709
  wasMissingAuthToken,
7531
- requiredScopes: fetchInit.requiredScopes
7710
+ requiredScopes
7532
7711
  });
7533
7712
  }
7534
7713
  if (!response.body) return;
@@ -7554,12 +7733,12 @@ var ZapierApiClient = class {
7554
7733
  /**
7555
7734
  * Run a single approval round: create the approval, open the URL (poll mode)
7556
7735
  * or throw (throw mode), poll until resolved, and emit events. Throws on
7557
- * denied/timeout/unexpected status. Returns on approved.
7736
+ * denied/failed/timeout/unexpected status. Returns on approved.
7558
7737
  *
7559
7738
  * Caller is responsible for passing a non-"disabled" mode; this method
7560
7739
  * unconditionally creates an approval.
7561
7740
  */
7562
- async runOneApprovalRound(buildContext, mode) {
7741
+ async runOneApprovalRound(buildContext, mode, signal) {
7563
7742
  const context = buildContext();
7564
7743
  let approvalResponse;
7565
7744
  try {
@@ -7569,9 +7748,11 @@ var ZapierApiClient = class {
7569
7748
  "Content-Type": "application/json",
7570
7749
  Accept: "application/json"
7571
7750
  },
7572
- body: JSON.stringify({ context })
7751
+ body: JSON.stringify({ context }),
7752
+ signal
7573
7753
  });
7574
7754
  } catch (err) {
7755
+ if (isAbortError(err)) throw err;
7575
7756
  throw new ZapierApiError("Failed to create approval request", {
7576
7757
  statusCode: 0,
7577
7758
  cause: err
@@ -7624,6 +7805,9 @@ var ZapierApiClient = class {
7624
7805
  };
7625
7806
  if (!isLocalhostBaseUrl(this.options.baseUrl)) {
7626
7807
  assertApprovalOrigin(approval.poll_url, sdkapiOrigin, "poll_url");
7808
+ if (approval.stream_url) {
7809
+ assertApprovalOrigin(approval.stream_url, sdkapiOrigin, "stream_url");
7810
+ }
7627
7811
  assertApprovalOrigin(
7628
7812
  approval.approval_url,
7629
7813
  browserOrigin,
@@ -7631,19 +7815,79 @@ var ZapierApiClient = class {
7631
7815
  );
7632
7816
  }
7633
7817
  this.emitEvent("approval:required", {
7634
- approvalId: approval.approval_id,
7635
- approvalUrl: approval.approval_url
7818
+ approvalId: approval.id,
7819
+ approvalUrl: approval.approval_url,
7820
+ mode: approval.mode,
7821
+ ...approval.stream_url ? { streamUrl: approval.stream_url } : {}
7636
7822
  });
7637
- if (mode === "throw") {
7638
- throw new ZapierApprovalError("This request requires approval.", {
7639
- approvalId: approval.approval_id,
7640
- approvalUrl: approval.approval_url,
7641
- pollUrl: approval.poll_url,
7642
- status: "pending"
7643
- });
7823
+ const shouldOpenAutoModeApproval = this.options.openAutoModeApprovalsInBrowser ?? getZapierOpenAutoModeApprovalsInBrowser() ?? false;
7824
+ if (approval.mode === "auto") {
7825
+ if (shouldOpenAutoModeApproval) {
7826
+ await openApproval(approval.approval_url);
7827
+ }
7828
+ if (approval.status === "approved") {
7829
+ this.emitEvent("approval:approved", {
7830
+ approvalId: approval.id
7831
+ });
7832
+ return;
7833
+ }
7834
+ if (approval.status === "denied") {
7835
+ this.emitEvent("approval:denied", {
7836
+ approvalId: approval.id,
7837
+ ...approval.reason ? { reason: approval.reason } : {}
7838
+ });
7839
+ throw new ZapierApprovalError(
7840
+ approval.reason ? `Request denied: ${approval.reason}` : "Request denied by user",
7841
+ {
7842
+ approvalId: approval.id,
7843
+ status: "denied",
7844
+ reason: approval.reason
7845
+ }
7846
+ );
7847
+ }
7848
+ if (approval.status === "failed") {
7849
+ this.throwApprovalFailed({
7850
+ approvalId: approval.id,
7851
+ approvalUrl: approval.approval_url,
7852
+ pollUrl: approval.poll_url,
7853
+ streamUrl: approval.stream_url,
7854
+ reason: approval.reason
7855
+ });
7856
+ }
7857
+ } else {
7858
+ if (mode === "throw") {
7859
+ throw new ZapierApprovalError("This request requires approval.", {
7860
+ approvalId: approval.id,
7861
+ approvalUrl: approval.approval_url,
7862
+ pollUrl: approval.poll_url,
7863
+ streamUrl: approval.stream_url,
7864
+ status: "pending"
7865
+ });
7866
+ }
7867
+ await openApproval(approval.approval_url);
7644
7868
  }
7645
- await openApproval(approval.approval_url);
7646
7869
  const timeoutMs = this.options.approvalTimeoutMs ?? DEFAULT_APPROVAL_TIMEOUT_MS;
7870
+ let streamAbortController;
7871
+ let streamPromise;
7872
+ let removeStreamAbortListener;
7873
+ if (approval.mode === "auto" && approval.stream_url) {
7874
+ const streamUrl = approval.stream_url;
7875
+ streamAbortController = new AbortController();
7876
+ const abortStream = () => streamAbortController?.abort();
7877
+ if (signal?.aborted) {
7878
+ abortStream();
7879
+ } else if (signal) {
7880
+ signal.addEventListener("abort", abortStream, { once: true });
7881
+ removeStreamAbortListener = () => signal.removeEventListener("abort", abortStream);
7882
+ }
7883
+ streamPromise = consumeApprovalReviewStream({
7884
+ approvalId: approval.id,
7885
+ streamUrl,
7886
+ signal: streamAbortController.signal,
7887
+ stream: (url, streamInit) => this.streamTrustedJsonUrl(url, streamInit),
7888
+ emitEvent: (type, payload) => this.emitEvent(type, payload)
7889
+ });
7890
+ }
7647
7891
  let rawPollResult;
7648
7892
  try {
7649
7893
  rawPollResult = await pollUntilComplete({
@@ -7654,14 +7898,16 @@ var ZapierApiClient = class {
7654
7898
  // semaphore — but we deliberately do not hold a slot across the
7655
7899
  // sleep between polls or across the human-approval wait.
7656
7900
  fetchPoll: () => this.withSemaphore(
7657
- { url: approval.poll_url, method: "GET" },
7901
+ { url: approval.poll_url, method: "GET", signal },
7658
7902
  () => this.rawFetchUrl(approval.poll_url, {
7659
7903
  method: "GET",
7660
- headers: { Accept: "application/json" }
7904
+ headers: { Accept: "application/json" },
7905
+ signal
7661
7906
  })
7662
7907
  ),
7663
7908
  timeoutMs,
7664
7909
  maxPollingIntervalMs: APPROVAL_MAX_POLLING_INTERVAL_MS,
7910
+ signal,
7665
7911
  isPending: (body2) => {
7666
7912
  const parsed = PollApprovalResponseSchema.safeParse(body2);
7667
7913
  return parsed.success && parsed.data.status === "pending_approval";
@@ -7669,25 +7915,38 @@ var ZapierApiClient = class {
7669
7915
  });
7670
7916
  } catch (err) {
7671
7917
  if (!(err instanceof ZapierTimeoutError)) {
7918
+ this.emitEvent("approval:error", {
7919
+ approvalId: approval.id,
7920
+ message: err instanceof Error ? err.message : String(err)
7921
+ });
7672
7922
  throw err;
7673
7923
  }
7674
7924
  this.emitEvent("approval:timeout", {
7675
- approvalId: approval.approval_id
7925
+ approvalId: approval.id
7676
7926
  });
7677
7927
  throw new ZapierApprovalError(
7678
7928
  `Approval timed out after ${timeoutMs / 1e3} seconds`,
7679
7929
  {
7680
- approvalId: approval.approval_id,
7930
+ approvalId: approval.id,
7681
7931
  approvalUrl: approval.approval_url,
7682
7932
  pollUrl: approval.poll_url,
7933
+ streamUrl: approval.stream_url,
7683
7934
  status: "timeout",
7684
7935
  cause: err
7685
7936
  }
7686
7937
  );
7938
+ } finally {
7939
+ removeStreamAbortListener?.();
7940
+ streamAbortController?.abort();
7941
+ await streamPromise;
7687
7942
  }
7688
7943
  const pollParse = PollApprovalResponseSchema.safeParse(rawPollResult);
7689
7944
  if (!pollParse.success) {
7690
7945
  const bodyPreview = typeof rawPollResult === "string" ? rawPollResult : JSON.stringify(rawPollResult);
7946
+ this.emitEvent("approval:error", {
7947
+ approvalId: approval.id,
7948
+ message: `Failed to parse approval poll response: ${bodyPreview}`
7949
+ });
7691
7950
  throw new ZapierApiError(
7692
7951
  `Failed to parse approval poll response: ${bodyPreview}`,
7693
7952
  {
@@ -7700,21 +7959,62 @@ var ZapierApiClient = class {
7700
7959
  const pollResult = pollParse.data;
7701
7960
  if (pollResult.status === "denied") {
7702
7961
  this.emitEvent("approval:denied", {
7703
- approvalId: approval.approval_id
7962
+ approvalId: approval.id,
7963
+ ...pollResult.reason ? { reason: pollResult.reason } : {}
7704
7964
  });
7705
- throw new ZapierApprovalError("Request denied by user", {
7706
- approvalId: approval.approval_id,
7707
- status: "denied"
7965
+ throw new ZapierApprovalError(
7966
+ pollResult.reason ? `Request denied: ${pollResult.reason}` : "Request denied by user",
7967
+ {
7968
+ approvalId: approval.id,
7969
+ status: "denied",
7970
+ reason: pollResult.reason
7971
+ }
7972
+ );
7973
+ }
7974
+ if (pollResult.status === "failed") {
7975
+ this.throwApprovalFailed({
7976
+ approvalId: approval.id,
7977
+ approvalUrl: approval.approval_url,
7978
+ pollUrl: approval.poll_url,
7979
+ streamUrl: approval.stream_url,
7980
+ reason: pollResult.reason
7708
7981
  });
7709
7982
  }
7710
7983
  if (pollResult.status !== "approved") {
7984
+ this.emitEvent("approval:error", {
7985
+ approvalId: approval.id,
7986
+ message: `Unexpected approval status received: ${pollResult.status}`
7987
+ });
7711
7988
  throw new ZapierApiError(
7712
7989
  `Unexpected approval status received: ${pollResult.status}`
7713
7990
  );
7714
7991
  }
7715
7992
  this.emitEvent("approval:approved", {
7716
- approvalId: approval.approval_id
7993
+ approvalId: approval.id
7994
+ });
7995
+ }
7996
+ throwApprovalFailed({
7997
+ approvalId,
7998
+ approvalUrl,
7999
+ pollUrl,
8000
+ streamUrl,
8001
+ reason
8002
+ }) {
8003
+ this.emitEvent("approval:failed", {
8004
+ approvalId,
8005
+ ...reason ? { reason } : {}
7717
8006
  });
8007
+ throw new ZapierApprovalError(
8008
+ reason ? `Approval failed: ${reason}` : "Approval failed",
8009
+ {
8010
+ approvalId,
8011
+ approvalUrl,
8012
+ pollUrl,
8013
+ streamUrl,
8014
+ status: "failed",
8015
+ reason
8016
+ }
8017
+ );
7718
8018
  }
7719
8019
  };
7720
8020
  var createZapierApi = (options) => {
@@ -7776,6 +8076,7 @@ var apiPlugin = definePlugin(
7776
8076
  approvalTimeoutMs,
7777
8077
  maxApprovalRetries,
7778
8078
  approvalMode,
8079
+ openAutoModeApprovalsInBrowser,
7779
8080
  callerPackage
7780
8081
  } = sdk.context.options;
7781
8082
  const api = createZapierApi({
@@ -7791,6 +8092,7 @@ var apiPlugin = definePlugin(
7791
8092
  approvalTimeoutMs,
7792
8093
  maxApprovalRetries,
7793
8094
  approvalMode,
8095
+ openAutoModeApprovalsInBrowser,
7794
8096
  callerPackage
7795
8097
  });
7796
8098
  return {
@@ -8783,6 +9085,260 @@ var zapierCorePlugin = createCorePlugin({
8783
9085
  function createZapierCoreStack() {
8784
9086
  return createPluginStack().use(zapierCorePlugin);
8785
9087
  }
9088
+ var GetConnectionStartUrlSchema = zod.z.object({
9089
+ app: AppPropertySchema
9090
+ }).describe(
9091
+ "Mint a short-lived URL that begins an SDK-initiated connection flow. The URL is signed by zapier.com and bound to the current user/account \u2014 opening it in a different browser session will fail the binding check. Returns the URL as data so the caller decides what to do with it.\n\nUse this directly (rather than the higher-level `create-connection`) when you want either of: (a) hand off the URL and *not* block waiting for completion \u2014 call this alone, skip `wait-for-new-connection` entirely, or (b) do something custom between minting the URL and waiting for the connection \u2014 call this, then email or DM the URL, render it as a QR code for mobile sign-in, etc., then call `wait-for-new-connection`. For the common case where you'd just print and poll back-to-back, `create-connection` is one call.\n\nPair with `wait-for-new-connection` to detect completion: pass the `startedAt` returned here straight through (it's the server's mint time, so polling isn't affected by client clock skew). Example (JS):\n\n```ts\nconst { data: { url, app, startedAt } } = await zapier.getConnectionStartUrl({ app: 'slack' });\n// hand `url` off \u2014 print it, DM it, email it, render a button, whatever\nconst { data: conn } = await zapier.waitForNewConnection({ app, startedAt });\n```"
9092
+ );
9093
+ var GetConnectionStartUrlItemSchema = zod.z.object({
9094
+ url: zod.z.string().describe(
9095
+ "URL the user should open in their browser to complete the auth flow. Single-use, time-limited."
9096
+ ),
9097
+ expiresAt: zod.z.number().describe(
9098
+ "Unix timestamp (seconds) after which the URL's signature is rejected by zapier.com."
9099
+ ),
9100
+ startedAt: zod.z.number().describe(
9101
+ "Unix timestamp (seconds) when the server minted the URL. Use it as the `startedAt` for `wait-for-new-connection` so polling is anchored to server time rather than a possibly-skewed client clock."
9102
+ ),
9103
+ app: zod.z.string().describe(
9104
+ "Versionless app key the URL was minted for (e.g., 'SlackCLIAPI'). Useful for downstream filtering."
9105
+ )
9106
+ }).describe(
9107
+ "The signed start-URL plus metadata needed to poll for completion."
9108
+ );
9109
+
9110
+ // src/plugins/getConnectionStartUrl/index.ts
9111
+ var START_PATH = "/zapier/api/authentications/v1/sdk/connections/start";
9112
+ var getConnectionStartUrlPlugin = definePlugin(
9113
+ (sdk) => createPluginMethod(sdk, {
9114
+ name: "getConnectionStartUrl",
9115
+ categories: ["connection"],
9116
+ type: "create",
9117
+ itemType: "ConnectionStartUrl",
9118
+ inputSchema: GetConnectionStartUrlSchema,
9119
+ outputSchema: GetConnectionStartUrlItemSchema,
9120
+ resolvers: { app: appKeyResolver },
9121
+ handler: async ({
9122
+ sdk: inner,
9123
+ options
9124
+ }) => {
9125
+ const versionedKey = await inner.context.getVersionedImplementationId(
9126
+ options.app
9127
+ );
9128
+ const selectedApi = versionedKey ? versionedKey.split("@")[0] : options.app;
9129
+ setMethodMetadata({ selectedApi });
9130
+ const response = await inner.context.api.post(
9131
+ START_PATH,
9132
+ { selected_api: selectedApi },
9133
+ { authRequired: true }
9134
+ );
9135
+ return {
9136
+ data: GetConnectionStartUrlItemSchema.parse({
9137
+ url: response.url,
9138
+ expiresAt: response.expires_at,
9139
+ startedAt: response.started_at,
9140
+ app: selectedApi
9141
+ })
9142
+ };
9143
+ }
9144
+ })
9145
+ );
9146
+ var WaitForNewConnectionSchema = zod.z.object({
9147
+ app: AppPropertySchema,
9148
+ startedAt: zod.z.number().int().nonnegative().describe(
9149
+ "Unix timestamp (seconds). Only connections whose `date` is at or after this value count as 'new'. Prefer the `startedAt` returned by `get-connection-start-url` \u2014 it's server-stamped, so the comparison isn't thrown off by client clock skew. If you mint the timestamp yourself, capture it *before* showing the start URL so a fast OAuth completion isn't missed."
9150
+ ),
9151
+ timeoutMs: zod.z.number().int().positive().optional().describe(
9152
+ "How long to wait before giving up. Default 5 minutes (300_000)."
9153
+ ),
9154
+ pollIntervalMs: zod.z.number().int().positive().optional().describe(
9155
+ "Delay before the first poll request, in ms. Default 3 seconds (3_000). Subsequent polling cadence is managed by the SDK's polling primitive (backoff with sane defaults)."
9156
+ )
9157
+ }).describe(
9158
+ "Wait for a new connection to appear for the given app. Polls `/api/v0/connections` with server-side `ordering=-date` until the most recent matching row's `date` is at or after the started-at timestamp, then returns it. Pair with `get-connection-start-url` \u2014 that mints the URL the user opens, this waits for the resulting connection to land. Errors with a timeout after the configured timeout (default 5 min). Example (JS):\n\n```ts\nconst { data: { url, app, startedAt } } = await zapier.getConnectionStartUrl({ app: 'slack' });\n// show `url` to the user via the channel they're reading from\nconst { data: conn } = await zapier.waitForNewConnection({ app, startedAt });\n```"
9159
+ );
9160
+ var WaitForNewConnectionItemSchema = zod.z.object({
9161
+ id: zod.z.string().describe(
9162
+ "The new connection's ID. Public UUID when available, falling back to the numeric ID."
9163
+ ),
9164
+ app: zod.z.string().describe(
9165
+ "Versionless app key the connection was created for (e.g., 'SlackCLIAPI')."
9166
+ ),
9167
+ title: zod.z.string().nullable().optional().describe(
9168
+ "Human-readable connection title set by the auth flow, when available."
9169
+ )
9170
+ }).describe("The new connection that was detected.");
9171
+
9172
+ // src/plugins/waitForNewConnection/index.ts
9173
+ var CONNECTIONS_PATH = "/api/v0/connections";
9174
+ var waitForNewConnectionPlugin = definePlugin(
9175
+ (sdk) => createPluginMethod(sdk, {
9176
+ name: "waitForNewConnection",
9177
+ categories: ["connection"],
9178
+ type: "item",
9179
+ itemType: "Connection",
9180
+ inputSchema: WaitForNewConnectionSchema,
9181
+ outputSchema: WaitForNewConnectionItemSchema,
9182
+ resolvers: { app: appKeyResolver },
9183
+ handler: async ({
9184
+ sdk: inner,
9185
+ options
9186
+ }) => {
9187
+ const versionedKey = await inner.context.getVersionedImplementationId(
9188
+ options.app
9189
+ );
9190
+ const appKey = versionedKey ? versionedKey.split("@")[0] : options.app;
9191
+ setMethodMetadata({ selectedApi: appKey });
9192
+ try {
9193
+ const top = await inner.context.api.poll(
9194
+ CONNECTIONS_PATH,
9195
+ {
9196
+ searchParams: {
9197
+ app_key: appKey,
9198
+ // Scope to the current user's own connections. The connection
9199
+ // we're waiting on is by definition owned by the caller; without
9200
+ // this the one-row head-check could match a teammate's freshly
9201
+ // created connection for the same app.
9202
+ owner: "me",
9203
+ is_expired: "false",
9204
+ ordering: "-date",
9205
+ page_size: "1"
9206
+ },
9207
+ authRequired: true,
9208
+ timeoutMs: options.timeoutMs ?? 3e5,
9209
+ initialDelay: options.pollIntervalMs ?? 3e3,
9210
+ isPending: (body) => {
9211
+ const rows = body.data ?? [];
9212
+ const head = rows[0];
9213
+ if (!head?.date) return true;
9214
+ const created = Math.floor(new Date(head.date).getTime() / 1e3);
9215
+ return !Number.isFinite(created) || created < options.startedAt;
9216
+ },
9217
+ resultExtractor: (body) => (
9218
+ // `isPending` guaranteed a fresh row at index 0 before this fires.
9219
+ body.data[0]
9220
+ )
9221
+ }
9222
+ );
9223
+ return {
9224
+ data: WaitForNewConnectionItemSchema.parse({
9225
+ id: String(top.public_id ?? top.id),
9226
+ app: appKey,
9227
+ title: top.title ?? null
9228
+ })
9229
+ };
9230
+ } catch (err) {
9231
+ if (err instanceof ZapierTimeoutError) {
9232
+ throw new ZapierTimeoutError(
9233
+ `Timed out waiting for a new "${appKey}" connection. If the user completed the auth flow, retrieve the connection via sdk.getConnection({ id }) with the ID shown on the completion page.`
9234
+ );
9235
+ }
9236
+ throw err;
9237
+ }
9238
+ }
9239
+ })
9240
+ );
9241
+
9242
+ // src/utils/should-open-browser.ts
9243
+ function shouldOpenBrowser() {
9244
+ if (isCiEnv()) return false;
9245
+ const env = globalThis.process?.env;
9246
+ if (env?.SSH_TTY || env?.SSH_CONNECTION) return false;
9247
+ if (globalThis.process?.platform === "linux" && !env?.DISPLAY && !env?.WAYLAND_DISPLAY) {
9248
+ return false;
9249
+ }
9250
+ return true;
9251
+ }
9252
+ function isCiEnv() {
9253
+ const env = globalThis.process?.env;
9254
+ return !!(env?.CI || env?.CONTINUOUS_INTEGRATION || env?.GITHUB_ACTIONS || env?.JENKINS_URL || env?.GITLAB_CI || env?.CIRCLECI || env?.TRAVIS || env?.BUILDKITE || env?.DRONE || env?.BITBUCKET_PIPELINES_UUID);
9255
+ }
9256
+ var CreateConnectionSchema = zod.z.object({
9257
+ app: AppPropertySchema,
9258
+ browser: zod.z.enum(["auto", "always", "never"]).default("auto").describe(
9259
+ "When to auto-open the URL in a browser. `auto` (default) opens in local sessions and skips opening in CI / SSH / headless-Linux. `always` forces the open attempt. `never` skips it. The URL is always printed to stderr regardless \u2014 a failed or skipped open degrades gracefully to copy-paste."
9260
+ ),
9261
+ timeoutMs: zod.z.number().int().positive().optional().describe(
9262
+ "How long to wait for the user to complete the connection flow before giving up. Default 5 minutes (300_000)."
9263
+ ),
9264
+ pollIntervalMs: zod.z.number().int().positive().optional().describe(
9265
+ "Delay before the first poll request, in ms. Default 3 seconds (3_000). Subsequent polling cadence is managed by the SDK's polling primitive (backoff with sane defaults)."
9266
+ )
9267
+ }).describe(
9268
+ "Create a new app connection, end-to-end. Mints the start URL via `get-connection-start-url`, prints it to stderr, opportunistically opens it in a browser when it looks safe to do so (skipping CI / SSH / headless-Linux by default \u2014 pass `--browser always` to force, `--browser never` to suppress), then polls via `wait-for-new-connection` until the user completes OAuth and the new connection appears. Returns the connection.\n\nThis is the right command for most callers. Reach for the lower-level building blocks when you want either of: (a) hand off the URL and *not* block on completion \u2014 call `get-connection-start-url` alone, no `wait-for-new-connection` needed, or (b) do something custom between minting the URL and waiting \u2014 call `get-connection-start-url`, do your work (email or DM the URL, render a QR code, etc.), then `wait-for-new-connection`."
9269
+ );
9270
+ var CreateConnectionItemSchema = zod.z.object({
9271
+ id: zod.z.string().describe(
9272
+ "The new connection's ID. Public UUID when available, falling back to the numeric ID."
9273
+ ),
9274
+ app: zod.z.string().describe(
9275
+ "Versionless app key the connection was created for (e.g., 'SlackCLIAPI')."
9276
+ ),
9277
+ title: zod.z.string().nullable().optional().describe(
9278
+ "Human-readable connection title set by the auth flow, when available."
9279
+ )
9280
+ }).describe("The newly created connection.");
9281
+
9282
+ // src/plugins/createConnection/index.ts
9283
+ var createConnectionPlugin = definePlugin(
9284
+ (sdk) => createPluginMethod(sdk, {
9285
+ name: "createConnection",
9286
+ categories: ["connection"],
9287
+ type: "create",
9288
+ itemType: "Connection",
9289
+ inputSchema: CreateConnectionSchema,
9290
+ outputSchema: CreateConnectionItemSchema,
9291
+ resolvers: { app: appKeyResolver },
9292
+ formatter: {
9293
+ format: (item) => ({
9294
+ title: `Connection created: ${item.title || item.id}`,
9295
+ id: item.id,
9296
+ details: [
9297
+ { text: `App: ${item.app}`, style: "normal" },
9298
+ { text: `ID: ${item.id}`, style: "accent" }
9299
+ ]
9300
+ })
9301
+ },
9302
+ handler: async ({
9303
+ sdk: inner,
9304
+ options
9305
+ }) => {
9306
+ const { data: start } = await inner.getConnectionStartUrl({
9307
+ app: options.app
9308
+ });
9309
+ setMethodMetadata({ selectedApi: start.app });
9310
+ console.error(
9311
+ `
9312
+ Open this URL to complete the connection:
9313
+ ${start.url}
9314
+ `
9315
+ );
9316
+ const shouldOpen = options.browser === "always" || options.browser === "auto" && shouldOpenBrowser();
9317
+ if (shouldOpen) {
9318
+ try {
9319
+ await open_url_default(start.url);
9320
+ } catch {
9321
+ }
9322
+ }
9323
+ const { data: fresh } = await inner.waitForNewConnection({
9324
+ app: start.app,
9325
+ // Server-stamped mint time: measured on the same clock as a
9326
+ // connection's `date`, so the freshness check is immune to
9327
+ // client/server clock skew.
9328
+ startedAt: start.startedAt,
9329
+ timeoutMs: options.timeoutMs,
9330
+ pollIntervalMs: options.pollIntervalMs
9331
+ });
9332
+ return {
9333
+ data: CreateConnectionItemSchema.parse({
9334
+ id: fresh.id,
9335
+ app: start.app,
9336
+ title: fresh.title ?? null
9337
+ })
9338
+ };
9339
+ }
9340
+ })
9341
+ );
8786
9342
 
8787
9343
  // src/plugins/deprecated/authentications.ts
8788
9344
  var listAuthenticationsPlugin = definePlugin(
@@ -9638,7 +10194,7 @@ function createZapierSdkWithoutRegistry(options = {}) {
9638
10194
  return createZapierSdk(options);
9639
10195
  }
9640
10196
  function createZapierSdkStack(options = {}) {
9641
- return createZapierCoreStack().use(createOptionsPlugin(options)).use(eventEmissionPlugin).use(apiPlugin).use(manifestPlugin).use(capabilitiesPlugin).use(connectionsPlugin).use(listAppsPlugin).use(getAppPlugin).use(listConnectionsPlugin).use(getConnectionPlugin).use(findFirstConnectionPlugin).use(findUniqueConnectionPlugin).use(listActionsPlugin).use(getActionPlugin).use(listActionInputFieldsPlugin).use(getActionInputFieldsSchemaPlugin).use(listActionInputFieldChoicesPlugin).use(listInputFieldsDeprecatedPlugin).use(getInputFieldsSchemaDeprecatedPlugin).use(listInputFieldChoicesDeprecatedPlugin).use(runActionPlugin).use(listAuthenticationsPlugin).use(getAuthenticationPlugin).use(findFirstAuthenticationPlugin).use(findUniqueAuthenticationPlugin).use(listClientCredentialsPlugin).use(createClientCredentialsPlugin).use(deleteClientCredentialsPlugin).use(fetchPlugin).use(requestPlugin).use(listTablesPlugin).use(getTablePlugin).use(deleteTablePlugin).use(createTablePlugin).use(listTableFieldsPlugin).use(createTableFieldsPlugin).use(deleteTableFieldsPlugin).use(listTableRecordsPlugin).use(getTableRecordPlugin).use(createTableRecordsPlugin).use(deleteTableRecordsPlugin).use(updateTableRecordsPlugin).use(appsPlugin).use(getProfilePlugin);
10197
+ return createZapierCoreStack().use(createOptionsPlugin(options)).use(eventEmissionPlugin).use(apiPlugin).use(manifestPlugin).use(capabilitiesPlugin).use(connectionsPlugin).use(listAppsPlugin).use(getAppPlugin).use(listConnectionsPlugin).use(getConnectionPlugin).use(findFirstConnectionPlugin).use(findUniqueConnectionPlugin).use(getConnectionStartUrlPlugin).use(waitForNewConnectionPlugin).use(createConnectionPlugin).use(listActionsPlugin).use(getActionPlugin).use(listActionInputFieldsPlugin).use(getActionInputFieldsSchemaPlugin).use(listActionInputFieldChoicesPlugin).use(listInputFieldsDeprecatedPlugin).use(getInputFieldsSchemaDeprecatedPlugin).use(listInputFieldChoicesDeprecatedPlugin).use(runActionPlugin).use(listAuthenticationsPlugin).use(getAuthenticationPlugin).use(findFirstAuthenticationPlugin).use(findUniqueAuthenticationPlugin).use(listClientCredentialsPlugin).use(createClientCredentialsPlugin).use(deleteClientCredentialsPlugin).use(fetchPlugin).use(requestPlugin).use(listTablesPlugin).use(getTablePlugin).use(deleteTablePlugin).use(createTablePlugin).use(listTableFieldsPlugin).use(createTableFieldsPlugin).use(deleteTableFieldsPlugin).use(listTableRecordsPlugin).use(getTableRecordPlugin).use(createTableRecordsPlugin).use(deleteTableRecordsPlugin).use(updateTableRecordsPlugin).use(appsPlugin).use(getProfilePlugin);
9642
10198
  }
9643
10199
  function createZapierSdk(options = {}) {
9644
10200
  return withDeprecatedAddPlugin(createZapierSdkStack(options).toSdk());
@@ -9684,7 +10240,10 @@ var BaseSdkOptionsSchema = zod.z.object({
9684
10240
  "Maximum number of sequential approval rounds per request (one per gating policy) before giving up. Default: 2."
9685
10241
  ),
9686
10242
  approvalMode: zod.z.enum(["disabled", "poll", "throw"]).optional().describe(
9687
- 'Approval flow behavior. "poll" creates the approval, opens it in a browser, polls until resolved, and retries the original request. "throw" creates the approval and throws a ZapierApprovalError with the approval URL so the caller can surface it. "disabled" throws a ZapierApprovalError on approval-required responses without creating an approval. Resolution order is: explicit option, then ZAPIER_APPROVAL_MODE, then the default behavior (poll for interactive TTY, throw otherwise).'
10243
+ 'Approval flow behavior for manual approvals. "poll" creates the approval, opens it in a browser, polls until resolved, and retries the original request. "throw" creates the manual approval and throws a ZapierApprovalError with the approval URL so the caller can surface it. Server-created auto-mode approvals always poll until they reach a terminal status and retry the original request on approval, even when this option is "throw". "disabled" throws a ZapierApprovalError on approval-required responses without creating an approval. Resolution order is: explicit option, then ZAPIER_APPROVAL_MODE, then the default behavior (poll for interactive TTY, throw otherwise).'
10244
+ ),
10245
+ openAutoModeApprovalsInBrowser: zod.z.boolean().optional().describe(
10246
+ "By default, auto-mode approvals do not open in a browser. Enable this option to open the approval URL and watch the approval process. Resolution order is: explicit option, then ZAPIER_OPEN_AUTO_MODE_APPROVALS_IN_BROWSER, then false."
9688
10247
  ),
9689
10248
  // Internal
9690
10249
  manifestPath: zod.z.string().optional().describe("Path to a .zapierrc manifest file for app version locking.").meta({ internal: true }),
@@ -9861,6 +10420,7 @@ exports.getTokenFromCliLogin = getTokenFromCliLogin;
9861
10420
  exports.getTtyContext = getTtyContext;
9862
10421
  exports.getZapierApprovalMode = getZapierApprovalMode;
9863
10422
  exports.getZapierDefaultApprovalMode = getZapierDefaultApprovalMode;
10423
+ exports.getZapierOpenAutoModeApprovalsInBrowser = getZapierOpenAutoModeApprovalsInBrowser;
9864
10424
  exports.getZapierSdkService = getZapierSdkService;
9865
10425
  exports.injectCliLogin = injectCliLogin;
9866
10426
  exports.inputFieldKeyResolver = inputFieldKeyResolver;