@zapier/zapier-sdk-cli 0.59.1 → 0.59.2

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 (174) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli.cjs +2 -2
  3. package/dist/cli.mjs +2 -2
  4. package/dist/experimental.cjs +1 -1
  5. package/dist/experimental.mjs +1 -1
  6. package/dist/index.cjs +2 -2
  7. package/dist/index.mjs +2 -2
  8. package/package.json +3 -3
  9. package/dist/package.json +0 -121
  10. package/dist/src/cli.d.ts +0 -2
  11. package/dist/src/cli.js +0 -219
  12. package/dist/src/experimental.d.ts +0 -33
  13. package/dist/src/experimental.js +0 -86
  14. package/dist/src/generators/ast-generator.d.ts +0 -41
  15. package/dist/src/generators/ast-generator.js +0 -405
  16. package/dist/src/index.d.ts +0 -5
  17. package/dist/src/index.js +0 -5
  18. package/dist/src/login/config.d.ts +0 -4
  19. package/dist/src/login/config.js +0 -21
  20. package/dist/src/login/credentials-revoke.d.ts +0 -14
  21. package/dist/src/login/credentials-revoke.js +0 -95
  22. package/dist/src/login/credentials-store.d.ts +0 -60
  23. package/dist/src/login/credentials-store.js +0 -181
  24. package/dist/src/login/filesystem-cache.d.ts +0 -25
  25. package/dist/src/login/filesystem-cache.js +0 -195
  26. package/dist/src/login/index.d.ts +0 -110
  27. package/dist/src/login/index.js +0 -424
  28. package/dist/src/login/keychain.d.ts +0 -18
  29. package/dist/src/login/keychain.js +0 -74
  30. package/dist/src/login/legacy-jwt.d.ts +0 -4
  31. package/dist/src/login/legacy-jwt.js +0 -18
  32. package/dist/src/login.d.ts +0 -10
  33. package/dist/src/login.js +0 -10
  34. package/dist/src/paths.d.ts +0 -1
  35. package/dist/src/paths.js +0 -6
  36. package/dist/src/plugins/add/index.d.ts +0 -254
  37. package/dist/src/plugins/add/index.js +0 -95
  38. package/dist/src/plugins/add/schemas.d.ts +0 -8
  39. package/dist/src/plugins/add/schemas.js +0 -22
  40. package/dist/src/plugins/auth/credentials-base-url.d.ts +0 -11
  41. package/dist/src/plugins/auth/credentials-base-url.js +0 -24
  42. package/dist/src/plugins/buildManifest/index.d.ts +0 -120
  43. package/dist/src/plugins/buildManifest/index.js +0 -71
  44. package/dist/src/plugins/buildManifest/schemas.d.ts +0 -44
  45. package/dist/src/plugins/buildManifest/schemas.js +0 -17
  46. package/dist/src/plugins/bundleCode/index.d.ts +0 -23
  47. package/dist/src/plugins/bundleCode/index.js +0 -62
  48. package/dist/src/plugins/bundleCode/schemas.d.ts +0 -10
  49. package/dist/src/plugins/bundleCode/schemas.js +0 -19
  50. package/dist/src/plugins/cliOverrides/index.d.ts +0 -21
  51. package/dist/src/plugins/cliOverrides/index.js +0 -17
  52. package/dist/src/plugins/curl/index.d.ts +0 -76
  53. package/dist/src/plugins/curl/index.js +0 -236
  54. package/dist/src/plugins/curl/schemas.d.ts +0 -40
  55. package/dist/src/plugins/curl/schemas.js +0 -108
  56. package/dist/src/plugins/curl/utils.d.ts +0 -34
  57. package/dist/src/plugins/curl/utils.js +0 -150
  58. package/dist/src/plugins/drainTriggerInbox/index.d.ts +0 -46
  59. package/dist/src/plugins/drainTriggerInbox/index.js +0 -178
  60. package/dist/src/plugins/feedback/index.d.ts +0 -24
  61. package/dist/src/plugins/feedback/index.js +0 -52
  62. package/dist/src/plugins/feedback/schemas.d.ts +0 -5
  63. package/dist/src/plugins/feedback/schemas.js +0 -8
  64. package/dist/src/plugins/generateAppTypes/index.d.ts +0 -265
  65. package/dist/src/plugins/generateAppTypes/index.js +0 -129
  66. package/dist/src/plugins/generateAppTypes/schemas.d.ts +0 -58
  67. package/dist/src/plugins/generateAppTypes/schemas.js +0 -21
  68. package/dist/src/plugins/getLoginConfigPath/index.d.ts +0 -16
  69. package/dist/src/plugins/getLoginConfigPath/index.js +0 -9
  70. package/dist/src/plugins/getLoginConfigPath/schemas.d.ts +0 -3
  71. package/dist/src/plugins/getLoginConfigPath/schemas.js +0 -5
  72. package/dist/src/plugins/index.d.ts +0 -15
  73. package/dist/src/plugins/index.js +0 -15
  74. package/dist/src/plugins/init/display.d.ts +0 -9
  75. package/dist/src/plugins/init/display.js +0 -72
  76. package/dist/src/plugins/init/index.d.ts +0 -21
  77. package/dist/src/plugins/init/index.js +0 -56
  78. package/dist/src/plugins/init/schemas.d.ts +0 -9
  79. package/dist/src/plugins/init/schemas.js +0 -19
  80. package/dist/src/plugins/init/steps.d.ts +0 -39
  81. package/dist/src/plugins/init/steps.js +0 -141
  82. package/dist/src/plugins/init/types.d.ts +0 -31
  83. package/dist/src/plugins/init/types.js +0 -1
  84. package/dist/src/plugins/init/utils.d.ts +0 -48
  85. package/dist/src/plugins/init/utils.js +0 -135
  86. package/dist/src/plugins/login/index.d.ts +0 -25
  87. package/dist/src/plugins/login/index.js +0 -12
  88. package/dist/src/plugins/login/schemas.d.ts +0 -9
  89. package/dist/src/plugins/login/schemas.js +0 -27
  90. package/dist/src/plugins/logout/index.d.ts +0 -30
  91. package/dist/src/plugins/logout/index.js +0 -33
  92. package/dist/src/plugins/logout/schemas.d.ts +0 -2
  93. package/dist/src/plugins/logout/schemas.js +0 -4
  94. package/dist/src/plugins/mcp/index.d.ts +0 -28
  95. package/dist/src/plugins/mcp/index.js +0 -24
  96. package/dist/src/plugins/mcp/schemas.d.ts +0 -5
  97. package/dist/src/plugins/mcp/schemas.js +0 -10
  98. package/dist/src/plugins/signup/index.d.ts +0 -25
  99. package/dist/src/plugins/signup/index.js +0 -12
  100. package/dist/src/plugins/signup/schemas.d.ts +0 -9
  101. package/dist/src/plugins/signup/schemas.js +0 -26
  102. package/dist/src/plugins/signup/test-harness.d.ts +0 -34
  103. package/dist/src/plugins/signup/test-harness.js +0 -76
  104. package/dist/src/plugins/watchTriggerInbox/index.d.ts +0 -46
  105. package/dist/src/plugins/watchTriggerInbox/index.js +0 -166
  106. package/dist/src/sdk.d.ts +0 -17
  107. package/dist/src/sdk.js +0 -67
  108. package/dist/src/telemetry/builders.d.ts +0 -44
  109. package/dist/src/telemetry/builders.js +0 -59
  110. package/dist/src/telemetry/events.d.ts +0 -40
  111. package/dist/src/telemetry/events.js +0 -4
  112. package/dist/src/types/sdk.d.ts +0 -6
  113. package/dist/src/types/sdk.js +0 -1
  114. package/dist/src/utils/api/client.d.ts +0 -15
  115. package/dist/src/utils/api/client.js +0 -27
  116. package/dist/src/utils/approval-errors.d.ts +0 -1
  117. package/dist/src/utils/approval-errors.js +0 -9
  118. package/dist/src/utils/approval-progress.d.ts +0 -12
  119. package/dist/src/utils/approval-progress.js +0 -179
  120. package/dist/src/utils/auth/account-auth.d.ts +0 -33
  121. package/dist/src/utils/auth/account-auth.js +0 -302
  122. package/dist/src/utils/auth/client-credentials.d.ts +0 -26
  123. package/dist/src/utils/auth/client-credentials.js +0 -67
  124. package/dist/src/utils/auth/oauth-callback.d.ts +0 -6
  125. package/dist/src/utils/auth/oauth-callback.js +0 -28
  126. package/dist/src/utils/auth/oauth-errors.d.ts +0 -2
  127. package/dist/src/utils/auth/oauth-errors.js +0 -39
  128. package/dist/src/utils/auth/oauth-flow.d.ts +0 -37
  129. package/dist/src/utils/auth/oauth-flow.js +0 -313
  130. package/dist/src/utils/auth/oauth-transaction.d.ts +0 -35
  131. package/dist/src/utils/auth/oauth-transaction.js +0 -69
  132. package/dist/src/utils/cli-generator-utils.d.ts +0 -14
  133. package/dist/src/utils/cli-generator-utils.js +0 -122
  134. package/dist/src/utils/cli-generator.d.ts +0 -4
  135. package/dist/src/utils/cli-generator.js +0 -831
  136. package/dist/src/utils/cli-options.d.ts +0 -16
  137. package/dist/src/utils/cli-options.js +0 -34
  138. package/dist/src/utils/cli-renderer.d.ts +0 -53
  139. package/dist/src/utils/cli-renderer.js +0 -265
  140. package/dist/src/utils/constants.d.ts +0 -3
  141. package/dist/src/utils/constants.js +0 -5
  142. package/dist/src/utils/directory-detection.d.ts +0 -5
  143. package/dist/src/utils/directory-detection.js +0 -21
  144. package/dist/src/utils/errors.d.ts +0 -33
  145. package/dist/src/utils/errors.js +0 -36
  146. package/dist/src/utils/extensions.d.ts +0 -20
  147. package/dist/src/utils/extensions.js +0 -66
  148. package/dist/src/utils/getCallablePromise.d.ts +0 -6
  149. package/dist/src/utils/getCallablePromise.js +0 -14
  150. package/dist/src/utils/log.d.ts +0 -8
  151. package/dist/src/utils/log.js +0 -26
  152. package/dist/src/utils/manifest-helpers.d.ts +0 -10
  153. package/dist/src/utils/manifest-helpers.js +0 -19
  154. package/dist/src/utils/non-interactive.d.ts +0 -14
  155. package/dist/src/utils/non-interactive.js +0 -15
  156. package/dist/src/utils/package-manager-detector.d.ts +0 -18
  157. package/dist/src/utils/package-manager-detector.js +0 -72
  158. package/dist/src/utils/parameter-resolver.d.ts +0 -179
  159. package/dist/src/utils/parameter-resolver.js +0 -1554
  160. package/dist/src/utils/retry.d.ts +0 -6
  161. package/dist/src/utils/retry.js +0 -21
  162. package/dist/src/utils/schema-formatter.d.ts +0 -11
  163. package/dist/src/utils/schema-formatter.js +0 -131
  164. package/dist/src/utils/serializeAsync.d.ts +0 -2
  165. package/dist/src/utils/serializeAsync.js +0 -16
  166. package/dist/src/utils/spinner.d.ts +0 -1
  167. package/dist/src/utils/spinner.js +0 -21
  168. package/dist/src/utils/string-utils.d.ts +0 -1
  169. package/dist/src/utils/string-utils.js +0 -6
  170. package/dist/src/utils/triggerDrain.d.ts +0 -144
  171. package/dist/src/utils/triggerDrain.js +0 -351
  172. package/dist/src/utils/version-checker.d.ts +0 -17
  173. package/dist/src/utils/version-checker.js +0 -154
  174. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,67 +0,0 @@
1
- import { storeClientCredentials } from "../../login/credentials-store";
2
- import { withRetry } from "../retry";
3
- // "external" allows SDK operations (listing, running actions, etc.);
4
- // "credentials" allows managing client credentials (list, create, delete).
5
- const CREDENTIALS_SCOPES = ["external", "credentials"];
6
- /**
7
- * The canonical empty approvals policy. Attaching this to a credential at
8
- * creation time tells the server that requests made with these credentials
9
- * are subject to approval. Server-side enforcement decides which specific
10
- * requests trigger the approval flow; the SDK only attaches the policy.
11
- */
12
- export const EMPTY_POLICY = {
13
- version: 2,
14
- statements: [],
15
- };
16
- async function createCredentialsOnServer(api, name, policy) {
17
- // The server wraps the credential in `{ data: { ... } }`; mirror the
18
- // shape the SDK's own createClientCredentials plugin reads.
19
- const response = await api.post("/api/v0/client-credentials", {
20
- name,
21
- allowed_scopes: CREDENTIALS_SCOPES,
22
- ...(policy !== undefined && { policy }),
23
- }, { authRequired: true, requiredScopes: ["credentials"] });
24
- return {
25
- clientId: response.data.client_id,
26
- clientSecret: response.data.client_secret,
27
- };
28
- }
29
- async function deleteCredentialsOnServer(api, clientId) {
30
- await api.delete(`/api/v0/client-credentials/${clientId}`, undefined, {
31
- authRequired: true,
32
- requiredScopes: ["credentials"],
33
- });
34
- }
35
- /**
36
- * Create a client credential server-side and persist it locally. If the
37
- * local store fails after the server-side credential is created, attempt
38
- * to roll back the orphan; if that rollback also fails, surface a
39
- * manual-fix message and re-throw the original store error.
40
- */
41
- export async function setupClientCredentials({ api, name, credentialsBaseUrl, policy, }) {
42
- const { clientId, clientSecret } = await createCredentialsOnServer(api, name, policy);
43
- try {
44
- await withRetry({
45
- action: () => storeClientCredentials({
46
- name,
47
- clientId,
48
- clientSecret,
49
- scopes: [...CREDENTIALS_SCOPES],
50
- baseUrl: credentialsBaseUrl,
51
- }),
52
- });
53
- }
54
- catch (storeErr) {
55
- try {
56
- await withRetry({
57
- action: () => deleteCredentialsOnServer(api, clientId),
58
- });
59
- }
60
- catch {
61
- console.error(`Failed to roll back orphaned credential ${clientId}. ` +
62
- `Delete it manually with: zapier-sdk delete-client-credentials ${clientId}`);
63
- }
64
- throw storeErr;
65
- }
66
- return { clientId };
67
- }
@@ -1,6 +0,0 @@
1
- import type { OauthTransaction } from "./oauth-transaction";
2
- export declare function getCallbackCode({ callbackUrl, transaction, recoveryMessage, }: {
3
- callbackUrl: string;
4
- transaction: Pick<OauthTransaction, "redirectUri" | "state">;
5
- recoveryMessage?: string;
6
- }): string;
@@ -1,28 +0,0 @@
1
- import { ZapierCliValidationError } from "../errors";
2
- export function getCallbackCode({ callbackUrl, transaction, recoveryMessage, }) {
3
- let parsed;
4
- try {
5
- parsed = new URL(callbackUrl.trim());
6
- }
7
- catch {
8
- throw new ZapierCliValidationError("Paste the final OAuth callback URL from your browser.");
9
- }
10
- const expected = new URL(transaction.redirectUri);
11
- if (parsed.protocol !== "http:" ||
12
- parsed.hostname !== expected.hostname ||
13
- parsed.pathname !== expected.pathname ||
14
- parsed.port !== expected.port) {
15
- throw new ZapierCliValidationError(`Expected the final OAuth callback URL to start with ${transaction.redirectUri}.`);
16
- }
17
- if (parsed.searchParams.get("state") !== transaction.state) {
18
- throw new ZapierCliValidationError(`OAuth state mismatch.${recoveryMessage ? ` ${recoveryMessage}` : ""}`);
19
- }
20
- if (parsed.searchParams.has("error")) {
21
- throw new ZapierCliValidationError(`Authorization denied: ${parsed.searchParams.get("error_description") ?? parsed.searchParams.get("error")}.${recoveryMessage ? ` ${recoveryMessage}` : ""}`);
22
- }
23
- const code = parsed.searchParams.get("code");
24
- if (!code) {
25
- throw new ZapierCliValidationError("No authorization code found in the pasted callback URL.");
26
- }
27
- return code;
28
- }
@@ -1,2 +0,0 @@
1
- export declare function redactSensitiveOauthErrorMessage(message: string): string;
2
- export declare function toRedactedOauthError(error: unknown): Error;
@@ -1,39 +0,0 @@
1
- import { ZapierCliValidationError } from "../errors";
2
- const SENSITIVE_OAUTH_FIELDS = [
3
- "access_token",
4
- "refresh_token",
5
- "id_token",
6
- "client_secret",
7
- "code_verifier",
8
- "code_challenge",
9
- ];
10
- function getErrorMessage(error) {
11
- return error instanceof Error ? error.message : String(error);
12
- }
13
- function toCamelCase(field) {
14
- return field.replace(/_([a-z])/g, (_match, letter) => letter.toUpperCase());
15
- }
16
- function escapeRegExp(value) {
17
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18
- }
19
- const sensitiveOauthFieldPattern = Array.from(new Set(SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])))
20
- .map(escapeRegExp)
21
- .join("|");
22
- const sensitiveQueryParamPattern = new RegExp(`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`, "gi");
23
- export function redactSensitiveOauthErrorMessage(message) {
24
- return message
25
- .replace(sensitiveQueryParamPattern, (_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`)
26
- .replace(new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"), (_match, key, separator) => `"${key}"${separator}"[REDACTED]"`);
27
- }
28
- export function toRedactedOauthError(error) {
29
- const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
30
- if (error instanceof ZapierCliValidationError) {
31
- return new ZapierCliValidationError(message);
32
- }
33
- if (error instanceof Error) {
34
- const redactedError = new Error(message);
35
- redactedError.name = error.name;
36
- return redactedError;
37
- }
38
- return new ZapierCliValidationError(message);
39
- }
@@ -1,37 +0,0 @@
1
- import { type PkceCredentials } from "../../login";
2
- import { buildBrowserAuthUrl, OAUTH_LOOPBACK_HOST, type OauthTokens } from "./oauth-transaction";
3
- export { buildBrowserAuthUrl, OAUTH_LOOPBACK_HOST };
4
- export type { OauthFlowEntryPoint, OauthTokens } from "./oauth-transaction";
5
- export type OauthFlowProgressEvent = {
6
- type: "browser_opening";
7
- url: string;
8
- } | {
9
- type: "browser_opened";
10
- url: string;
11
- } | {
12
- type: "browser_open_failed";
13
- url: string;
14
- reason: string;
15
- } | {
16
- type: "callback_waiting";
17
- } | {
18
- type: "callback_accepted";
19
- } | {
20
- type: "token_exchange_started";
21
- } | {
22
- type: "token_exchange_completed";
23
- };
24
- export interface RunOauthFlowOptions {
25
- timeoutMs?: number;
26
- pkceCredentials?: PkceCredentials;
27
- baseUrl?: string;
28
- silent?: boolean;
29
- onProgress?: (event: OauthFlowProgressEvent) => void;
30
- recoveryMessage?: string;
31
- }
32
- interface RunSignupOauthFlowOptions extends RunOauthFlowOptions {
33
- headless?: boolean;
34
- interactive?: boolean;
35
- }
36
- export declare function runLoginOauthFlow(options: RunOauthFlowOptions): Promise<OauthTokens>;
37
- export declare function runSignupOauthFlow(options: RunSignupOauthFlowOptions): Promise<OauthTokens>;
@@ -1,313 +0,0 @@
1
- import express from "express";
2
- import { createInterface } from "node:readline/promises";
3
- import open from "open";
4
- import { LOGIN_PORTS, LOGIN_TIMEOUT_MS } from "../constants";
5
- import { ZapierCliUserCancellationError, ZapierCliValidationError, } from "../errors";
6
- import getCallablePromise from "../getCallablePromise";
7
- import log from "../log";
8
- import { spinPromise } from "../spinner";
9
- import { getCallbackCode } from "./oauth-callback";
10
- import { buildBrowserAuthUrl, exchangeOauthCode, OAUTH_LOOPBACK_HOST, prepareOauthTransaction, } from "./oauth-transaction";
11
- export { buildBrowserAuthUrl, OAUTH_LOOPBACK_HOST };
12
- class OauthFlowTimeoutError extends Error {
13
- constructor(timeoutMs) {
14
- super("OAuth flow timed out");
15
- this.timeoutMs = timeoutMs;
16
- this.name = "OauthFlowTimeoutError";
17
- }
18
- }
19
- class OauthAuthorizationDeniedError extends Error {
20
- constructor(reason) {
21
- super("OAuth authorization denied");
22
- this.reason = reason;
23
- this.name = "OauthAuthorizationDeniedError";
24
- }
25
- }
26
- function findAvailablePort() {
27
- return new Promise((resolve, reject) => {
28
- let portIndex = 0;
29
- const tryPort = (port) => {
30
- const server = express().listen(port, OAUTH_LOOPBACK_HOST, () => {
31
- server.close();
32
- resolve(port);
33
- });
34
- server.on("error", (err) => {
35
- if (err.code === "EADDRINUSE" && portIndex < LOGIN_PORTS.length) {
36
- tryPort(LOGIN_PORTS[portIndex++]);
37
- }
38
- else if (err.code === "EADDRINUSE") {
39
- reject(new Error(`All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`));
40
- }
41
- else {
42
- reject(err);
43
- }
44
- });
45
- };
46
- if (LOGIN_PORTS.length > 0)
47
- tryPort(LOGIN_PORTS[portIndex++]);
48
- else
49
- reject(new Error("No OAuth callback ports configured"));
50
- });
51
- }
52
- export async function runLoginOauthFlow(options) {
53
- return runOauthFlowEntryPoint({
54
- ...options,
55
- entryPoint: "login",
56
- authAction: "log in",
57
- flowName: "Login",
58
- });
59
- }
60
- export async function runSignupOauthFlow(options) {
61
- if (options.headless) {
62
- return runOauthFlowEntryPoint({
63
- ...options,
64
- entryPoint: "signup",
65
- authAction: "sign up",
66
- flowName: "Signup",
67
- headless: true,
68
- });
69
- }
70
- return runOauthFlowEntryPoint({
71
- ...options,
72
- entryPoint: "signup",
73
- authAction: "sign up",
74
- flowName: "Signup",
75
- });
76
- }
77
- async function runOauthFlowEntryPoint({ flowName, ...options }) {
78
- try {
79
- return options.headless
80
- ? await runHeadlessSignupOauthFlow(options)
81
- : await runOauthFlow(options);
82
- }
83
- catch (error) {
84
- if (error instanceof OauthFlowTimeoutError) {
85
- throw new Error(withRecoveryMessage(`${flowName} timed out after ${Math.round(error.timeoutMs / 1000)} seconds.`, options.recoveryMessage));
86
- }
87
- if (error instanceof OauthAuthorizationDeniedError) {
88
- throw new Error(withRecoveryMessage(`Authorization denied: ${error.reason}.`, options.recoveryMessage));
89
- }
90
- if (error instanceof ZapierCliUserCancellationError && !options.silent) {
91
- log.info(`\n❌ ${flowName} cancelled by user`);
92
- }
93
- throw error;
94
- }
95
- }
96
- function withRecoveryMessage(message, recoveryMessage) {
97
- return recoveryMessage ? `${message} ${recoveryMessage}` : message;
98
- }
99
- async function runOauthFlow({ timeoutMs = LOGIN_TIMEOUT_MS, pkceCredentials, baseUrl, entryPoint, authAction, silent = false, onProgress, }) {
100
- const port = await findAvailablePort();
101
- if (!silent)
102
- log.info(`Using port ${port} for OAuth callback`);
103
- const transaction = await prepareOauthTransaction({
104
- pkceCredentials,
105
- baseUrl,
106
- redirectUri: `http://${OAUTH_LOOPBACK_HOST}:${port}/oauth`,
107
- entryPoint,
108
- });
109
- const code = await collectLocalCallbackCode({
110
- transaction,
111
- timeoutMs,
112
- authAction,
113
- silent,
114
- onProgress,
115
- });
116
- onProgress?.({ type: "callback_accepted" });
117
- if (!silent)
118
- log.info("Exchanging authorization code for tokens...");
119
- onProgress?.({ type: "token_exchange_started" });
120
- const tokens = await exchangeOauthCode({ ...transaction, code });
121
- if (!silent)
122
- log.info("Token exchange completed successfully");
123
- onProgress?.({ type: "token_exchange_completed" });
124
- return tokens;
125
- }
126
- async function readHeadlessCallbackUrl({ timeoutMs, interactive, recoveryMessage, }) {
127
- const timeoutMessage = withRecoveryMessage(`Signup timed out after ${Math.round(timeoutMs / 1000)} seconds.`, recoveryMessage);
128
- const missingCallbackUrlMessage = withRecoveryMessage("Paste the final OAuth callback URL from your browser.", recoveryMessage);
129
- // Keep TTY echo enabled for paste feedback; the PKCE code is single-use, verifier-protected, and exchanged immediately.
130
- const rl = createInterface({ input: process.stdin, output: process.stderr });
131
- const abortController = new AbortController();
132
- const timeoutTimer = setTimeout(() => abortController.abort(), timeoutMs);
133
- const readUrl = interactive
134
- ? rl.question("Paste the final OAuth callback URL: ", {
135
- signal: abortController.signal,
136
- })
137
- : new Promise((resolve, reject) => {
138
- let settled = false;
139
- const settleResolve = (value) => {
140
- settled = true;
141
- resolve(value);
142
- };
143
- const settleReject = (error) => {
144
- if (settled)
145
- return;
146
- settled = true;
147
- reject(error);
148
- };
149
- abortController.signal.addEventListener("abort", () => settleReject(new Error(timeoutMessage)), { once: true });
150
- rl.once("line", settleResolve);
151
- rl.once("close", () => settleReject(new ZapierCliValidationError(missingCallbackUrlMessage)));
152
- rl.once("error", settleReject);
153
- });
154
- try {
155
- return await readUrl.catch((error) => {
156
- if (error instanceof Error && error.name === "AbortError") {
157
- throw new Error(timeoutMessage);
158
- }
159
- throw error;
160
- });
161
- }
162
- finally {
163
- clearTimeout(timeoutTimer);
164
- rl.close();
165
- }
166
- }
167
- async function runHeadlessSignupOauthFlow({ timeoutMs = LOGIN_TIMEOUT_MS, pkceCredentials, baseUrl, interactive = true, onProgress, recoveryMessage, }) {
168
- const port = LOGIN_PORTS[0];
169
- if (port === undefined) {
170
- throw new Error("No OAuth callback ports configured");
171
- }
172
- const transaction = await prepareOauthTransaction({
173
- pkceCredentials,
174
- baseUrl,
175
- redirectUri: `http://${OAUTH_LOOPBACK_HOST}:${port}/oauth`,
176
- entryPoint: "signup",
177
- });
178
- console.log("Use this mode when signing up from a machine that has no browser.");
179
- console.log("Open this signup URL in a browser on another machine:");
180
- console.log(transaction.browserAuthUrl);
181
- console.log(`When the browser lands on ${transaction.redirectUri} and cannot connect, paste the full final URL back here.`);
182
- const callbackUrl = await readHeadlessCallbackUrl({
183
- timeoutMs,
184
- interactive,
185
- recoveryMessage,
186
- });
187
- const code = getCallbackCode({
188
- callbackUrl,
189
- transaction,
190
- recoveryMessage,
191
- });
192
- onProgress?.({ type: "callback_accepted" });
193
- console.log("Exchanging authorization code for tokens...");
194
- onProgress?.({ type: "token_exchange_started" });
195
- const tokens = await exchangeOauthCode({ ...transaction, code });
196
- onProgress?.({ type: "token_exchange_completed" });
197
- return tokens;
198
- }
199
- async function collectLocalCallbackCode({ transaction, timeoutMs, authAction, silent, onProgress, }) {
200
- const { promise, resolve, reject } = getCallablePromise();
201
- const app = express();
202
- app.get("/oauth", (req, res) => {
203
- res.setHeader("Connection", "close");
204
- if (req.query.state !== transaction.state) {
205
- res.status(400).end("Invalid state. You can close this tab.");
206
- }
207
- else if (req.query.error) {
208
- reject(new OauthAuthorizationDeniedError(String(req.query.error_description ?? req.query.error)));
209
- res.end("Authorization was denied. You can close this tab.");
210
- }
211
- else if (!req.query.code) {
212
- reject(new Error("No authorization code received"));
213
- res.end("No authorization code received. You can close this tab.");
214
- }
215
- else {
216
- resolve(String(req.query.code));
217
- res.end("You can now close this tab and return to the CLI.");
218
- }
219
- });
220
- const server = app.listen(Number(new URL(transaction.redirectUri).port), OAUTH_LOOPBACK_HOST);
221
- const connections = new Set();
222
- server.on("connection", (conn) => {
223
- connections.add(conn);
224
- conn.on("close", () => connections.delete(conn));
225
- });
226
- const cleanup = () => {
227
- server.close();
228
- reject(new ZapierCliUserCancellationError());
229
- };
230
- process.on("SIGINT", cleanup);
231
- process.on("SIGTERM", cleanup);
232
- let timeoutTimer;
233
- try {
234
- await waitForServerListening(server);
235
- await openBrowser({ transaction, authAction, silent, onProgress });
236
- const waitForCode = Promise.race([
237
- promise,
238
- new Promise((_resolve, rejectTimeout) => {
239
- timeoutTimer = setTimeout(() => {
240
- rejectTimeout(new OauthFlowTimeoutError(timeoutMs));
241
- }, timeoutMs);
242
- }),
243
- ]);
244
- onProgress?.({ type: "callback_waiting" });
245
- return silent
246
- ? await waitForCode
247
- : await spinPromise(waitForCode, `Waiting for you to ${authAction} and authorize`);
248
- }
249
- finally {
250
- if (timeoutTimer)
251
- clearTimeout(timeoutTimer);
252
- process.off("SIGINT", cleanup);
253
- process.off("SIGTERM", cleanup);
254
- await closeServer({ server, connections, silent });
255
- }
256
- }
257
- async function waitForServerListening(server) {
258
- if (server.listening)
259
- return;
260
- await new Promise((resolve, reject) => {
261
- const cleanup = () => {
262
- server.off("listening", handleListening);
263
- server.off("error", handleError);
264
- };
265
- const handleListening = () => {
266
- cleanup();
267
- resolve();
268
- };
269
- const handleError = (error) => {
270
- cleanup();
271
- reject(error);
272
- };
273
- server.once("listening", handleListening);
274
- server.once("error", handleError);
275
- });
276
- }
277
- async function openBrowser({ transaction, authAction, silent, onProgress, }) {
278
- if (!silent) {
279
- log.info(`Opening your browser to ${authAction}.`);
280
- log.info("If it doesn't open, visit:", transaction.browserAuthUrl);
281
- }
282
- onProgress?.({ type: "browser_opening", url: transaction.browserAuthUrl });
283
- try {
284
- await open(transaction.browserAuthUrl);
285
- onProgress?.({ type: "browser_opened", url: transaction.browserAuthUrl });
286
- }
287
- catch (err) {
288
- const reason = err instanceof Error ? err.message : String(err);
289
- if (!silent) {
290
- log.info(`Browser did not open automatically to ${authAction}: ${reason}`);
291
- log.info("Visit this URL manually:", transaction.browserAuthUrl);
292
- }
293
- onProgress?.({
294
- type: "browser_open_failed",
295
- url: transaction.browserAuthUrl,
296
- reason,
297
- });
298
- }
299
- }
300
- async function closeServer({ server, connections, silent, }) {
301
- await new Promise((resolve) => {
302
- const timeout = setTimeout(() => {
303
- if (!silent)
304
- log.info("Server close timed out, forcing connection shutdown...");
305
- connections.forEach((conn) => conn.destroy());
306
- resolve();
307
- }, 1000);
308
- server.close(() => {
309
- clearTimeout(timeout);
310
- resolve();
311
- });
312
- });
313
- }
@@ -1,35 +0,0 @@
1
- import { type PkceCredentials } from "../../login";
2
- export declare const OAUTH_LOOPBACK_HOST = "localhost";
3
- export interface OauthTokens {
4
- accessToken: string;
5
- refreshToken: string;
6
- expiresIn: number;
7
- }
8
- export type OauthFlowEntryPoint = "login" | "signup";
9
- interface PrepareOauthTransactionOptions {
10
- pkceCredentials?: PkceCredentials;
11
- baseUrl?: string;
12
- redirectUri: string;
13
- entryPoint?: OauthFlowEntryPoint;
14
- }
15
- export interface OauthTransaction {
16
- browserAuthUrl: string;
17
- clientId: string;
18
- codeVerifier: string;
19
- redirectUri: string;
20
- state: string;
21
- tokenUrl: string;
22
- }
23
- export declare function buildBrowserAuthUrl({ authorizeUrl, entryPoint, }: {
24
- authorizeUrl: string;
25
- entryPoint?: OauthFlowEntryPoint;
26
- }): string;
27
- export declare function prepareOauthTransaction({ pkceCredentials, baseUrl, redirectUri, entryPoint, }: PrepareOauthTransactionOptions): Promise<OauthTransaction>;
28
- export declare function exchangeOauthCode({ tokenUrl, code, redirectUri, clientId, codeVerifier, }: {
29
- tokenUrl: string;
30
- code: string;
31
- redirectUri: string;
32
- clientId: string;
33
- codeVerifier: string;
34
- }): Promise<OauthTokens>;
35
- export {};
@@ -1,69 +0,0 @@
1
- import crypto from "node:crypto";
2
- import pkceChallenge from "pkce-challenge";
3
- import { AUTH_MODE_HEADER } from "../constants";
4
- import api from "../api/client";
5
- import { getPkceLoginConfig } from "../../login";
6
- export const OAUTH_LOOPBACK_HOST = "localhost";
7
- export function buildBrowserAuthUrl({ authorizeUrl, entryPoint = "login", }) {
8
- if (entryPoint === "login")
9
- return authorizeUrl;
10
- const parsedAuthorizeUrl = new URL(authorizeUrl);
11
- const signupUrl = new URL("/sign-up", parsedAuthorizeUrl);
12
- signupUrl.searchParams.set("skipOnboarding", "true");
13
- signupUrl.searchParams.set("next", `${parsedAuthorizeUrl.pathname}${parsedAuthorizeUrl.search}`);
14
- return signupUrl.toString();
15
- }
16
- function generateRandomString() {
17
- const array = new Uint32Array(28);
18
- crypto.getRandomValues(array);
19
- return Array.from(array, (dec) => ("0" + dec.toString(16)).slice(-2)).join("");
20
- }
21
- function ensureOfflineAccess(scope) {
22
- if (scope.includes("offline_access"))
23
- return scope;
24
- return `${scope} offline_access`;
25
- }
26
- export async function prepareOauthTransaction({ pkceCredentials, baseUrl, redirectUri, entryPoint = "login", }) {
27
- const { clientId, tokenUrl, authorizeUrl } = getPkceLoginConfig({
28
- credentials: pkceCredentials,
29
- baseUrl,
30
- });
31
- const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge();
32
- const state = generateRandomString();
33
- const authUrl = `${authorizeUrl}?${new URLSearchParams({
34
- response_type: "code",
35
- client_id: clientId,
36
- redirect_uri: redirectUri,
37
- scope: ensureOfflineAccess(pkceCredentials?.scope || "internal credentials"),
38
- state,
39
- code_challenge: codeChallenge,
40
- code_challenge_method: "S256",
41
- }).toString()}`;
42
- return {
43
- browserAuthUrl: buildBrowserAuthUrl({ authorizeUrl: authUrl, entryPoint }),
44
- clientId,
45
- codeVerifier,
46
- redirectUri,
47
- state,
48
- tokenUrl,
49
- };
50
- }
51
- export async function exchangeOauthCode({ tokenUrl, code, redirectUri, clientId, codeVerifier, }) {
52
- const { data } = await api.post(tokenUrl, {
53
- grant_type: "authorization_code",
54
- code,
55
- redirect_uri: redirectUri,
56
- client_id: clientId,
57
- code_verifier: codeVerifier,
58
- }, {
59
- headers: {
60
- [AUTH_MODE_HEADER]: "no",
61
- "Content-Type": "application/x-www-form-urlencoded",
62
- },
63
- });
64
- return {
65
- accessToken: data.access_token,
66
- refreshToken: data.refresh_token,
67
- expiresIn: data.expires_in,
68
- };
69
- }
@@ -1,14 +0,0 @@
1
- import { z } from "zod";
2
- import { type FunctionRegistryEntry } from "@zapier/zapier-sdk";
3
- export interface CliParameter {
4
- name: string;
5
- type: "string" | "number" | "boolean" | "array";
6
- required: boolean;
7
- description?: string;
8
- default?: unknown;
9
- choices?: string[];
10
- hasResolver?: boolean;
11
- isPositional?: boolean;
12
- }
13
- export declare function analyzeZodSchema(schema: z.ZodSchema, functionInfo?: FunctionRegistryEntry): CliParameter[];
14
- export declare function convertCliArgsToSdkParams(parameters: CliParameter[], positionalArgs: unknown[], options: Record<string, unknown>): Record<string, unknown>;