@zapier/zapier-sdk-cli 0.17.3 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { createFunction, OutputPropertySchema, DEFAULT_CONFIG_PATH, ZapierError, getOsInfo, getPlatformVersions, getCiPlatform, isCi, createZapierSdkWithoutRegistry, registryPlugin, getReleaseId, getCurrentTimestamp, generateEventId, ZapierValidationError, ZapierUnknownError, batch, toSnakeCase } from '@zapier/zapier-sdk';
1
+ import { createFunction, OutputPropertySchema, DEFAULT_CONFIG_PATH, getOsInfo, getPlatformVersions, getCiPlatform, isCi, createZapierSdkWithoutRegistry, registryPlugin, getReleaseId, getCurrentTimestamp, generateEventId, ZapierValidationError, ZapierUnknownError, batch, toSnakeCase, isCredentialsObject, ZapierError } from '@zapier/zapier-sdk';
2
2
  import open from 'open';
3
3
  import crypto from 'crypto';
4
4
  import express from 'express';
5
5
  import pkceChallenge from 'pkce-challenge';
6
- import { getLoggedInUser, logout, getAuthTokenUrl, getAuthAuthorizeUrl, ZAPIER_AUTH_CLIENT_ID, AUTH_MODE_HEADER, updateLogin, getConfigPath } from '@zapier/zapier-sdk-cli-login';
6
+ import { logout, getConfigPath, getLoggedInUser, getPkceLoginConfig, AUTH_MODE_HEADER, updateLogin } from '@zapier/zapier-sdk-cli-login';
7
7
  import ora from 'ora';
8
8
  import chalk from 'chalk';
9
9
  import { z } from 'zod';
@@ -151,15 +151,22 @@ var generateRandomString = () => {
151
151
  (dec) => ("0" + dec.toString(16)).substring(-2)
152
152
  ).join("");
153
153
  };
154
+ function ensureOfflineAccess(scope) {
155
+ if (scope.includes("offline_access")) {
156
+ return scope;
157
+ }
158
+ return `${scope} offline_access`;
159
+ }
154
160
  var login = async ({
155
161
  timeoutMs = LOGIN_TIMEOUT_MS,
156
- baseUrl,
157
- authBaseUrl,
158
- authClientId
162
+ credentials
159
163
  }) => {
160
- const authOptions = { baseUrl, authBaseUrl };
161
- const tokenUrl = getAuthTokenUrl(authOptions);
162
- const authorizeUrl = getAuthAuthorizeUrl(authOptions);
164
+ const { clientId, tokenUrl, authorizeUrl } = getPkceLoginConfig({
165
+ credentials
166
+ });
167
+ const scope = ensureOfflineAccess(
168
+ credentials?.scope || "internal credentials"
169
+ );
163
170
  logout();
164
171
  const availablePort = await findAvailablePort();
165
172
  const redirectUri = `http://localhost:${availablePort}/oauth`;
@@ -191,9 +198,9 @@ var login = async ({
191
198
  const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge();
192
199
  const authUrl = `${authorizeUrl}?${new URLSearchParams({
193
200
  response_type: "code",
194
- client_id: authClientId || ZAPIER_AUTH_CLIENT_ID,
201
+ client_id: clientId,
195
202
  redirect_uri: redirectUri,
196
- scope: "internal offline_access",
203
+ scope,
197
204
  state: generateRandomString(),
198
205
  code_challenge: codeChallenge,
199
206
  code_challenge_method: "S256"
@@ -243,7 +250,7 @@ var login = async ({
243
250
  grant_type: "authorization_code",
244
251
  code: await promisedCode,
245
252
  redirect_uri: redirectUri,
246
- client_id: authClientId || ZAPIER_AUTH_CLIENT_ID,
253
+ client_id: clientId,
247
254
  code_verifier: codeVerifier
248
255
  },
249
256
  {
@@ -264,7 +271,7 @@ var LoginSchema = z.object({
264
271
 
265
272
  // package.json
266
273
  var package_default = {
267
- version: "0.17.3"};
274
+ version: "0.18.0"};
268
275
 
269
276
  // src/telemetry/builders.ts
270
277
  function createCliBaseEvent(context = {}) {
@@ -321,22 +328,17 @@ function buildCliCommandExecutedEvent({
321
328
 
322
329
  // src/plugins/login/index.ts
323
330
  var CLI_COMMAND_EXECUTED_EVENT_SUBJECT = "platform.sdk.CliCommandExecutedEvent";
324
- var loginWithSdk = createFunction(
325
- async (options) => {
326
- const timeoutSeconds = options.timeout ? parseInt(options.timeout, 10) : 300;
327
- if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
328
- throw new Error("Timeout must be a positive number");
329
- }
330
- await login_default({
331
- timeoutMs: timeoutSeconds * 1e3,
332
- baseUrl: options.baseUrl,
333
- authBaseUrl: options.authBaseUrl,
334
- authClientId: options.authClientId
335
- });
336
- const user = await getLoggedInUser();
337
- console.log(`\u2705 Successfully logged in as ${user.email}`);
331
+ function toPkceCredentials(credentials) {
332
+ if (credentials && isCredentialsObject(credentials) && !("clientSecret" in credentials)) {
333
+ return {
334
+ type: "pkce",
335
+ clientId: credentials.clientId,
336
+ baseUrl: credentials.baseUrl,
337
+ scope: credentials.scope
338
+ };
338
339
  }
339
- );
340
+ return void 0;
341
+ }
340
342
  var loginPlugin = ({ context }) => {
341
343
  const loginWithTelemetry = async (options) => {
342
344
  const startTime = Date.now();
@@ -345,17 +347,21 @@ var loginPlugin = ({ context }) => {
345
347
  let accountId = null;
346
348
  let customUserId = null;
347
349
  try {
348
- await loginWithSdk({
349
- ...options,
350
- baseUrl: context.options?.baseUrl,
351
- authBaseUrl: context.options?.authBaseUrl,
352
- authClientId: context.options?.authClientId
350
+ const timeoutSeconds = options.timeout ? parseInt(options.timeout, 10) : 300;
351
+ if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
352
+ throw new Error("Timeout must be a positive number");
353
+ }
354
+ const resolvedCredentials = await context.resolveCredentials();
355
+ const pkceCredentials = toPkceCredentials(resolvedCredentials);
356
+ await login_default({
357
+ timeoutMs: timeoutSeconds * 1e3,
358
+ credentials: pkceCredentials
353
359
  });
360
+ const user = await getLoggedInUser();
361
+ accountId = user.accountId;
362
+ customUserId = user.customUserId;
363
+ console.log(`\u2705 Successfully logged in as ${user.email}`);
354
364
  success = true;
355
- try {
356
- ({ accountId, customUserId } = await getLoggedInUser());
357
- } catch {
358
- }
359
365
  } catch (error) {
360
366
  success = false;
361
367
  errorMessage = error instanceof Error ? error.message : "Login failed";
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.17.3",
3
+ "version": "0.18.0",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
package/dist/src/cli.js CHANGED
@@ -12,29 +12,61 @@ program
12
12
  .version(packageJson.version, "-v, --version", "display version number")
13
13
  .option("--debug", "Enable debug logging")
14
14
  .option("--base-url <url>", "Base URL for Zapier API endpoints")
15
- .option("--auth-base-url <url>", "Base URL for Zapier authentication endpoints")
16
- .option("--auth-client-id <id>", "OAuth client ID for Zapier authentication")
15
+ .option("--credentials <token>", "Authentication token")
16
+ .option("--credentials-client-id <id>", "OAuth client ID for authentication")
17
+ .option("--credentials-client-secret <secret>", "OAuth client secret for authentication")
18
+ .option("--credentials-base-url <url>", "Base URL for authentication endpoints")
17
19
  .option("--tracking-base-url <url>", "Base URL for Zapier tracking endpoints");
18
20
  // Check for debug flag early (support both flag and env var)
19
21
  const isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
20
- // Extract URL options from process.argv for early SDK creation
22
+ // Helper to get flag value from argv
23
+ function getFlagValue(flagName) {
24
+ const index = process.argv.indexOf(flagName);
25
+ return index !== -1 ? process.argv[index + 1] : undefined;
26
+ }
27
+ // Extract options from process.argv for early SDK creation
21
28
  // We need to create the SDK before parsing to generate commands from schemas
22
- const baseUrlIndex = process.argv.indexOf("--base-url");
23
- const authBaseUrlIndex = process.argv.indexOf("--auth-base-url");
24
- const authClientIdIndex = process.argv.indexOf("--auth-client-id");
25
- const trackingBaseUrlIndex = process.argv.indexOf("--tracking-base-url");
26
- const baseUrl = baseUrlIndex !== -1 ? process.argv[baseUrlIndex + 1] : undefined;
27
- const authBaseUrl = authBaseUrlIndex !== -1 ? process.argv[authBaseUrlIndex + 1] : undefined;
28
- const authClientId = authClientIdIndex !== -1 ? process.argv[authClientIdIndex + 1] : undefined;
29
- const trackingBaseUrl = trackingBaseUrlIndex !== -1
30
- ? process.argv[trackingBaseUrlIndex + 1]
31
- : undefined;
29
+ const baseUrl = getFlagValue("--base-url");
30
+ const credentialsToken = getFlagValue("--credentials");
31
+ const credentialsClientId = getFlagValue("--credentials-client-id");
32
+ const credentialsClientSecret = getFlagValue("--credentials-client-secret");
33
+ const credentialsBaseUrl = getFlagValue("--credentials-base-url");
34
+ const trackingBaseUrl = getFlagValue("--tracking-base-url");
35
+ // Build credentials object from flags
36
+ function buildCredentialsFromFlags() {
37
+ // If a direct token is provided, use it
38
+ if (credentialsToken) {
39
+ return credentialsToken;
40
+ }
41
+ // If client ID is provided, build a credentials object
42
+ if (credentialsClientId) {
43
+ if (credentialsClientSecret) {
44
+ // Client credentials flow
45
+ return {
46
+ type: "client_credentials",
47
+ clientId: credentialsClientId,
48
+ clientSecret: credentialsClientSecret,
49
+ baseUrl: credentialsBaseUrl,
50
+ };
51
+ }
52
+ else {
53
+ // PKCE flow (no secret)
54
+ return {
55
+ type: "pkce",
56
+ clientId: credentialsClientId,
57
+ baseUrl: credentialsBaseUrl,
58
+ };
59
+ }
60
+ }
61
+ // No credentials from flags - will fall back to env vars or stored login
62
+ return undefined;
63
+ }
64
+ const credentials = buildCredentialsFromFlags();
32
65
  // Create CLI SDK instance with all plugins and URL options
33
66
  const sdk = createZapierCliSdk({
34
67
  debug: isDebugMode,
68
+ credentials,
35
69
  baseUrl,
36
- authBaseUrl,
37
- authClientId,
38
70
  trackingBaseUrl,
39
71
  });
40
72
  // Auth commands now handled by plugins
@@ -1,4 +1,4 @@
1
- import type { Plugin } from "@zapier/zapier-sdk";
1
+ import type { Plugin, ResolvedCredentials } from "@zapier/zapier-sdk";
2
2
  import type { EventEmissionContext } from "@zapier/zapier-sdk";
3
3
  import { LoginSchema, type LoginOptions } from "./schemas";
4
4
  interface CliContext {
@@ -6,6 +6,7 @@ interface CliContext {
6
6
  selected_api?: string | null;
7
7
  app_id?: number | null;
8
8
  app_version_id?: number | null;
9
+ resolveCredentials: () => Promise<ResolvedCredentials | undefined>;
9
10
  }
10
11
  interface LoginPluginProvides {
11
12
  login: (options: LoginOptions) => Promise<void>;
@@ -1,26 +1,23 @@
1
- import { createFunction } from "@zapier/zapier-sdk";
1
+ import { isCredentialsObject } from "@zapier/zapier-sdk";
2
2
  import login from "../../utils/auth/login";
3
- import { getLoggedInUser } from "@zapier/zapier-sdk-cli-login";
3
+ import { getLoggedInUser, } from "@zapier/zapier-sdk-cli-login";
4
4
  import { LoginSchema } from "./schemas";
5
5
  import { buildCliCommandExecutedEvent } from "../../telemetry/builders";
6
6
  import cliPackageJson from "../../../package.json";
7
7
  const CLI_COMMAND_EXECUTED_EVENT_SUBJECT = "platform.sdk.CliCommandExecutedEvent";
8
- const loginWithSdk = createFunction(async (options) => {
9
- const timeoutSeconds = options.timeout
10
- ? parseInt(options.timeout, 10)
11
- : 300;
12
- if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
13
- throw new Error("Timeout must be a positive number");
8
+ function toPkceCredentials(credentials) {
9
+ if (credentials &&
10
+ isCredentialsObject(credentials) &&
11
+ !("clientSecret" in credentials)) {
12
+ return {
13
+ type: "pkce",
14
+ clientId: credentials.clientId,
15
+ baseUrl: credentials.baseUrl,
16
+ scope: credentials.scope,
17
+ };
14
18
  }
15
- await login({
16
- timeoutMs: timeoutSeconds * 1000,
17
- baseUrl: options.baseUrl,
18
- authBaseUrl: options.authBaseUrl,
19
- authClientId: options.authClientId,
20
- });
21
- const user = await getLoggedInUser();
22
- console.log(`✅ Successfully logged in as ${user.email}`);
23
- });
19
+ return undefined;
20
+ }
24
21
  export const loginPlugin = ({ context }) => {
25
22
  // Wrap the login function to emit telemetry events
26
23
  const loginWithTelemetry = async (options) => {
@@ -30,20 +27,25 @@ export const loginPlugin = ({ context }) => {
30
27
  let accountId = null;
31
28
  let customUserId = null;
32
29
  try {
33
- await loginWithSdk({
34
- ...options,
35
- baseUrl: context.options?.baseUrl,
36
- authBaseUrl: context.options?.authBaseUrl,
37
- authClientId: context.options?.authClientId,
30
+ const timeoutSeconds = options.timeout
31
+ ? parseInt(options.timeout, 10)
32
+ : 300;
33
+ if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
34
+ throw new Error("Timeout must be a positive number");
35
+ }
36
+ // Resolve credentials from options and env vars
37
+ const resolvedCredentials = await context.resolveCredentials();
38
+ const pkceCredentials = toPkceCredentials(resolvedCredentials);
39
+ await login({
40
+ timeoutMs: timeoutSeconds * 1000,
41
+ credentials: pkceCredentials,
38
42
  });
43
+ // Get user info after successful login
44
+ const user = await getLoggedInUser();
45
+ accountId = user.accountId;
46
+ customUserId = user.customUserId;
47
+ console.log(`✅ Successfully logged in as ${user.email}`);
39
48
  success = true;
40
- // Extract user IDs after successful login
41
- try {
42
- ({ accountId, customUserId } = await getLoggedInUser());
43
- }
44
- catch {
45
- // If we can't get user info, continue without it
46
- }
47
49
  }
48
50
  catch (error) {
49
51
  success = false;
@@ -1,8 +1,7 @@
1
+ import { type PkceCredentials } from "@zapier/zapier-sdk-cli-login";
1
2
  interface LoginOptions {
2
3
  timeoutMs?: number;
3
- baseUrl?: string;
4
- authBaseUrl?: string;
5
- authClientId?: string;
4
+ credentials?: PkceCredentials;
6
5
  }
7
- declare const login: ({ timeoutMs, baseUrl, authBaseUrl, authClientId, }: LoginOptions) => Promise<string>;
6
+ declare const login: ({ timeoutMs, credentials, }: LoginOptions) => Promise<string>;
8
7
  export default login;
@@ -2,12 +2,12 @@ import open from "open";
2
2
  import crypto from "node:crypto";
3
3
  import express from "express";
4
4
  import pkceChallenge from "pkce-challenge";
5
- import { AUTH_MODE_HEADER, ZAPIER_AUTH_CLIENT_ID, LOGIN_PORTS, LOGIN_TIMEOUT_MS, } from "../constants";
5
+ import { AUTH_MODE_HEADER, LOGIN_PORTS, LOGIN_TIMEOUT_MS } from "../constants";
6
6
  import { spinPromise } from "../spinner";
7
7
  import log from "../log";
8
8
  import api from "../api/client";
9
9
  import getCallablePromise from "../getCallablePromise";
10
- import { updateLogin, logout, getAuthTokenUrl, getAuthAuthorizeUrl, } from "@zapier/zapier-sdk-cli-login";
10
+ import { updateLogin, logout, getPkceLoginConfig, } from "@zapier/zapier-sdk-cli-login";
11
11
  import { ZapierCliUserCancellationError } from "../errors";
12
12
  const findAvailablePort = () => {
13
13
  return new Promise((resolve, reject) => {
@@ -46,10 +46,18 @@ const generateRandomString = () => {
46
46
  crypto.getRandomValues(array);
47
47
  return Array.from(array, (dec) => ("0" + dec.toString(16)).substring(-2)).join("");
48
48
  };
49
- const login = async ({ timeoutMs = LOGIN_TIMEOUT_MS, baseUrl, authBaseUrl, authClientId, }) => {
50
- const authOptions = { baseUrl, authBaseUrl };
51
- const tokenUrl = getAuthTokenUrl(authOptions);
52
- const authorizeUrl = getAuthAuthorizeUrl(authOptions);
49
+ // Ensure offline_access is included in scope for PKCE (needed for refresh tokens)
50
+ function ensureOfflineAccess(scope) {
51
+ if (scope.includes("offline_access")) {
52
+ return scope;
53
+ }
54
+ return `${scope} offline_access`;
55
+ }
56
+ const login = async ({ timeoutMs = LOGIN_TIMEOUT_MS, credentials, }) => {
57
+ const { clientId, tokenUrl, authorizeUrl } = getPkceLoginConfig({
58
+ credentials,
59
+ });
60
+ const scope = ensureOfflineAccess(credentials?.scope || "internal credentials");
53
61
  // Force logout
54
62
  logout();
55
63
  // Find an available port
@@ -82,9 +90,9 @@ const login = async ({ timeoutMs = LOGIN_TIMEOUT_MS, baseUrl, authBaseUrl, authC
82
90
  const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge();
83
91
  const authUrl = `${authorizeUrl}?${new URLSearchParams({
84
92
  response_type: "code",
85
- client_id: authClientId || ZAPIER_AUTH_CLIENT_ID,
93
+ client_id: clientId,
86
94
  redirect_uri: redirectUri,
87
- scope: "internal offline_access",
95
+ scope,
88
96
  state: generateRandomString(),
89
97
  code_challenge: codeChallenge,
90
98
  code_challenge_method: "S256",
@@ -131,7 +139,7 @@ const login = async ({ timeoutMs = LOGIN_TIMEOUT_MS, baseUrl, authBaseUrl, authC
131
139
  grant_type: "authorization_code",
132
140
  code: await promisedCode,
133
141
  redirect_uri: redirectUri,
134
- client_id: authClientId || ZAPIER_AUTH_CLIENT_ID,
142
+ client_id: clientId,
135
143
  code_verifier: codeVerifier,
136
144
  }, {
137
145
  headers: {
@@ -1,3 +1,3 @@
1
- export { ZAPIER_AUTH_CLIENT_ID, AUTH_MODE_HEADER, } from "@zapier/zapier-sdk-cli-login";
1
+ export { AUTH_MODE_HEADER } from "@zapier/zapier-sdk-cli-login";
2
2
  export declare const LOGIN_PORTS: number[];
3
3
  export declare const LOGIN_TIMEOUT_MS = 300000;
@@ -1,5 +1,5 @@
1
1
  // Import shared OAuth constants from login package
2
- export { ZAPIER_AUTH_CLIENT_ID, AUTH_MODE_HEADER, } from "@zapier/zapier-sdk-cli-login";
2
+ export { AUTH_MODE_HEADER } from "@zapier/zapier-sdk-cli-login";
3
3
  // CLI-specific constants
4
4
  export const LOGIN_PORTS = [49505, 50575, 52804, 55981, 61010, 63851];
5
5
  export const LOGIN_TIMEOUT_MS = 300000; // 5 minutes