@zapier/zapier-sdk-cli 0.55.2 → 0.55.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ import crypto, { createHash } from 'crypto';
7
7
  import * as path from 'path';
8
8
  import { resolve, join, dirname, basename, relative, extname } from 'path';
9
9
  import * as lockfile from 'proper-lockfile';
10
- import { definePlugin, createPluginMethod, OutputPropertySchema, ZapierBundleError, DEFAULT_CONFIG_PATH, ZapierValidationError, ZapierUnknownError, ZapierReleaseTriggerMessageSignal, injectCliLogin, getOrCreateApiClient, isPermanentHttpError, invalidateCachedToken, batch, toSnakeCase, ZapierAbortDrainSignal, isCredentialsObject, buildApplicationLifecycleEvent, ZapierAuthenticationError, ZapierError, createZapierSdkStack, addPlugin, getOsInfo, getPlatformVersions, getCiPlatform, isCi, getReleaseId, getCurrentTimestamp, generateEventId } from '@zapier/zapier-sdk';
10
+ import { definePlugin, createPluginMethod, OutputPropertySchema, ZapierBundleError, DEFAULT_CONFIG_PATH, ZapierValidationError, ZapierUnknownError, ZapierReleaseTriggerMessageSignal, injectCliLogin, getOrCreateApiClient, isPermanentHttpError, invalidateCachedToken, batch, toSnakeCase, ZapierAbortDrainSignal, isCredentialsObject, buildApplicationLifecycleEvent, ZapierAuthenticationError, ZapierError, createZapierSdkStack, addPlugin, getOsInfo, getPlatformVersions, getAgent, getTtyContext, getCiPlatform, isCi, getReleaseId, getCurrentTimestamp, generateEventId } from '@zapier/zapier-sdk';
11
11
  import { z } from 'zod';
12
12
  import { hostname } from 'os';
13
13
  import inquirer from 'inquirer';
@@ -289,6 +289,34 @@ function createCache() {
289
289
  }
290
290
  };
291
291
  }
292
+ var ZapierCliError = class extends ZapierError {
293
+ };
294
+ var ZapierCliUserCancellationError = class extends ZapierCliError {
295
+ constructor(message = "Operation cancelled by user") {
296
+ super(message);
297
+ this.name = "ZapierCliUserCancellationError";
298
+ this.code = "ZAPIER_CLI_USER_CANCELLATION";
299
+ this.exitCode = 0;
300
+ }
301
+ };
302
+ var ZapierCliExitError = class extends ZapierCliError {
303
+ constructor(message, exitCode = 1) {
304
+ super(message);
305
+ this.name = "ZapierCliExitError";
306
+ this.code = "ZAPIER_CLI_EXIT";
307
+ this.exitCode = exitCode;
308
+ }
309
+ };
310
+ var ZapierCliValidationError = class extends ZapierCliError {
311
+ constructor(message) {
312
+ super(message);
313
+ this.name = "ZapierCliValidationError";
314
+ this.code = "ZAPIER_CLI_VALIDATION_ERROR";
315
+ this.exitCode = 1;
316
+ }
317
+ };
318
+
319
+ // src/login/credentials-store.ts
292
320
  var SERVICE3 = "zapier-sdk-cli";
293
321
  var CREDENTIALS_KEY = "credentials";
294
322
  var REGISTRY_KEY = "credentialsRegistry";
@@ -325,6 +353,30 @@ function getActiveCredentials(options) {
325
353
  if (!name) return void 0;
326
354
  return findEntry(readRegistry(), name, normalizeBaseUrl(options?.baseUrl));
327
355
  }
356
+ var MAX_CREDENTIAL_NAME_ATTEMPTS = 500;
357
+ function firstAvailableCredentialName({
358
+ baseName,
359
+ taken
360
+ }) {
361
+ if (!taken.has(baseName)) return baseName;
362
+ for (let i = 1; i <= MAX_CREDENTIAL_NAME_ATTEMPTS; i++) {
363
+ const candidate = `${baseName}-${i}`;
364
+ if (!taken.has(candidate)) return candidate;
365
+ }
366
+ throw new ZapierCliValidationError(
367
+ `Could not find an available credential name for "${baseName}" after ${MAX_CREDENTIAL_NAME_ATTEMPTS} attempts.`
368
+ );
369
+ }
370
+ function resolveAvailableCredentialName({
371
+ baseName,
372
+ baseUrl
373
+ }) {
374
+ const resolvedBaseUrl = normalizeBaseUrl(baseUrl);
375
+ const taken = new Set(
376
+ readRegistry().filter((e) => e.baseUrl === resolvedBaseUrl).map((e) => e.name)
377
+ );
378
+ return firstAvailableCredentialName({ baseName, taken });
379
+ }
328
380
  async function storeClientCredentials({
329
381
  name,
330
382
  clientId,
@@ -891,32 +943,6 @@ async function resolveCredentialsBaseUrl(context) {
891
943
  function resolveNonInteractive(options) {
892
944
  return options.nonInteractive === true || options.skipPrompts === true || !process.stdin.isTTY || !process.stdout.isTTY;
893
945
  }
894
- var ZapierCliError = class extends ZapierError {
895
- };
896
- var ZapierCliUserCancellationError = class extends ZapierCliError {
897
- constructor(message = "Operation cancelled by user") {
898
- super(message);
899
- this.name = "ZapierCliUserCancellationError";
900
- this.code = "ZAPIER_CLI_USER_CANCELLATION";
901
- this.exitCode = 0;
902
- }
903
- };
904
- var ZapierCliExitError = class extends ZapierCliError {
905
- constructor(message, exitCode = 1) {
906
- super(message);
907
- this.name = "ZapierCliExitError";
908
- this.code = "ZAPIER_CLI_EXIT";
909
- this.exitCode = exitCode;
910
- }
911
- };
912
- var ZapierCliValidationError = class extends ZapierCliError {
913
- constructor(message) {
914
- super(message);
915
- this.name = "ZapierCliValidationError";
916
- this.code = "ZAPIER_CLI_VALIDATION_ERROR";
917
- this.exitCode = 1;
918
- }
919
- };
920
946
 
921
947
  // src/utils/auth/client-credentials.ts
922
948
  var CREDENTIALS_SCOPES = ["external", "credentials"];
@@ -1878,11 +1904,11 @@ async function runAccountAuth({
1878
1904
  console.log(
1879
1905
  "\nGenerating credentials so this machine can make authenticated requests on your behalf."
1880
1906
  );
1881
- const resolveCredentialsName = interactive ? ({ email }) => promptCredentialsName({
1882
- email,
1907
+ const baseName = interactive ? await promptCredentialsName({
1908
+ email: profile.email,
1883
1909
  promptMessage: getCredentialsPromptMessage(entryPoint)
1884
- }) : resolveDefaultCredentialsName;
1885
- const credentialName = await resolveCredentialsName({ email: profile.email });
1910
+ }) : resolveDefaultCredentialsName({ email: profile.email });
1911
+ const credentialName = interactive ? baseName : resolveAvailableCredentialName({ baseName, baseUrl: credentialsBaseUrl });
1886
1912
  const useApprovals = options.useApprovals === true;
1887
1913
  await saveClientCredentials({
1888
1914
  api: scopedApi,
@@ -4488,7 +4514,7 @@ definePlugin(
4488
4514
  // package.json with { type: 'json' }
4489
4515
  var package_default = {
4490
4516
  name: "@zapier/zapier-sdk-cli",
4491
- version: "0.55.2"};
4517
+ version: "0.55.4"};
4492
4518
 
4493
4519
  // src/sdk.ts
4494
4520
  injectCliLogin(login_exports);
@@ -4516,7 +4542,7 @@ function createZapierCliSdk(options = {}) {
4516
4542
 
4517
4543
  // package.json
4518
4544
  var package_default2 = {
4519
- version: "0.55.2"};
4545
+ version: "0.55.4"};
4520
4546
 
4521
4547
  // src/telemetry/builders.ts
4522
4548
  function createCliBaseEvent(context = {}) {
@@ -4560,6 +4586,8 @@ function buildCliCommandExecutedEvent({
4560
4586
  requires_auth: data.requires_auth ?? null,
4561
4587
  is_ci_environment: isCi(),
4562
4588
  ci_platform: getCiPlatform(),
4589
+ ...getTtyContext(),
4590
+ agent: getAgent(),
4563
4591
  package_manager: data.package_manager ?? "pnpm",
4564
4592
  // Default based on project setup
4565
4593
  made_network_requests: data.made_network_requests ?? null,
package/dist/login.cjs CHANGED
@@ -261,6 +261,8 @@ function createCache() {
261
261
  }
262
262
  };
263
263
  }
264
+
265
+ // src/login/credentials-store.ts
264
266
  var SERVICE3 = "zapier-sdk-cli";
265
267
  var CREDENTIALS_KEY = "credentials";
266
268
  var REGISTRY_KEY = "credentialsRegistry";
package/dist/login.mjs CHANGED
@@ -236,6 +236,8 @@ function createCache() {
236
236
  }
237
237
  };
238
238
  }
239
+
240
+ // src/login/credentials-store.ts
239
241
  var SERVICE3 = "zapier-sdk-cli";
240
242
  var CREDENTIALS_KEY = "credentials";
241
243
  var REGISTRY_KEY = "credentialsRegistry";
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.55.2",
3
+ "version": "0.55.4",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -11,6 +11,28 @@ export type CredentialsEntry = z.infer<typeof CredentialsEntrySchema>;
11
11
  export declare function getActiveCredentials(options?: {
12
12
  baseUrl?: string;
13
13
  }): CredentialsEntry | undefined;
14
+ /**
15
+ * Pick the first credential name not already present in `taken`. Returns
16
+ * `baseName` if it is free, otherwise appends an incrementing `-1`, `-2`, …
17
+ * suffix to the literal base — a base ending in a digit is left intact, so
18
+ * `acme-1` collides into `acme-1-1`. Storing a credential under a name that
19
+ * already exists locally silently replaces that entry (and deletes its
20
+ * keychain secret), so non-interactive login uses this to avoid clobbering a
21
+ * dormant credential of the same name.
22
+ */
23
+ export declare function firstAvailableCredentialName({ baseName, taken, }: {
24
+ baseName: string;
25
+ taken: ReadonlySet<string>;
26
+ }): string;
27
+ /**
28
+ * Resolve a locally-unique credential name for the given baseUrl. Local
29
+ * credentials are keyed by (name, baseUrl), so name collisions — and the
30
+ * suffixing that avoids them — are scoped per baseUrl.
31
+ */
32
+ export declare function resolveAvailableCredentialName({ baseName, baseUrl, }: {
33
+ baseName: string;
34
+ baseUrl?: string;
35
+ }): string;
14
36
  export declare function storeClientCredentials({ name, clientId, clientSecret, scopes, baseUrl, }: {
15
37
  name: string;
16
38
  clientId: string;
@@ -3,6 +3,7 @@ import { getPassword, setPassword, deletePassword } from "cross-keychain";
3
3
  import { z } from "zod";
4
4
  import { DEFAULT_AUTH_BASE_URL, getConfig } from "./config";
5
5
  import { enqueue, getBackendInfo } from "./keychain";
6
+ import { ZapierCliValidationError } from "../utils/errors";
6
7
  const SERVICE = "zapier-sdk-cli";
7
8
  const CREDENTIALS_KEY = "credentials";
8
9
  const REGISTRY_KEY = "credentialsRegistry";
@@ -41,6 +42,38 @@ export function getActiveCredentials(options) {
41
42
  return undefined;
42
43
  return findEntry(readRegistry(), name, normalizeBaseUrl(options?.baseUrl));
43
44
  }
45
+ const MAX_CREDENTIAL_NAME_ATTEMPTS = 500;
46
+ /**
47
+ * Pick the first credential name not already present in `taken`. Returns
48
+ * `baseName` if it is free, otherwise appends an incrementing `-1`, `-2`, …
49
+ * suffix to the literal base — a base ending in a digit is left intact, so
50
+ * `acme-1` collides into `acme-1-1`. Storing a credential under a name that
51
+ * already exists locally silently replaces that entry (and deletes its
52
+ * keychain secret), so non-interactive login uses this to avoid clobbering a
53
+ * dormant credential of the same name.
54
+ */
55
+ export function firstAvailableCredentialName({ baseName, taken, }) {
56
+ if (!taken.has(baseName))
57
+ return baseName;
58
+ for (let i = 1; i <= MAX_CREDENTIAL_NAME_ATTEMPTS; i++) {
59
+ const candidate = `${baseName}-${i}`;
60
+ if (!taken.has(candidate))
61
+ return candidate;
62
+ }
63
+ throw new ZapierCliValidationError(`Could not find an available credential name for "${baseName}" after ${MAX_CREDENTIAL_NAME_ATTEMPTS} attempts.`);
64
+ }
65
+ /**
66
+ * Resolve a locally-unique credential name for the given baseUrl. Local
67
+ * credentials are keyed by (name, baseUrl), so name collisions — and the
68
+ * suffixing that avoids them — are scoped per baseUrl.
69
+ */
70
+ export function resolveAvailableCredentialName({ baseName, baseUrl, }) {
71
+ const resolvedBaseUrl = normalizeBaseUrl(baseUrl);
72
+ const taken = new Set(readRegistry()
73
+ .filter((e) => e.baseUrl === resolvedBaseUrl)
74
+ .map((e) => e.name));
75
+ return firstAvailableCredentialName({ baseName, taken });
76
+ }
44
77
  export async function storeClientCredentials({ name, clientId, clientSecret, scopes, baseUrl, }) {
45
78
  if (!name || typeof name !== "string") {
46
79
  throw new Error("storeClientCredentials: name is required");
@@ -4,7 +4,7 @@
4
4
  * Provides builder functions for CLI command telemetry that auto-populate
5
5
  * common CLI fields and system information.
6
6
  */
7
- import { generateEventId, getCurrentTimestamp, getReleaseId, getOsInfo, getPlatformVersions, isCi, getCiPlatform, } from "@zapier/zapier-sdk";
7
+ import { generateEventId, getCurrentTimestamp, getReleaseId, getOsInfo, getPlatformVersions, isCi, getCiPlatform, getTtyContext, getAgent, } from "@zapier/zapier-sdk";
8
8
  import cliPackageJson from "../../package.json";
9
9
  // Create base event for CLI events
10
10
  function createCliBaseEvent(context = {}) {
@@ -44,6 +44,8 @@ export function buildCliCommandExecutedEvent({ data, context = {}, cliVersion =
44
44
  requires_auth: data.requires_auth ?? null,
45
45
  is_ci_environment: isCi(),
46
46
  ci_platform: getCiPlatform(),
47
+ ...getTtyContext(),
48
+ agent: getAgent(),
47
49
  package_manager: data.package_manager ?? "pnpm", // Default based on project setup
48
50
  made_network_requests: data.made_network_requests ?? null,
49
51
  files_modified_count: data.files_modified_count ?? null,
@@ -34,4 +34,7 @@ export interface CliCommandExecutedEvent extends BaseEvent {
34
34
  peak_memory_usage_bytes?: number | null;
35
35
  cpu_time_ms?: number | null;
36
36
  subprocess_count?: number | null;
37
+ stdin_is_tty?: boolean | null;
38
+ stdout_is_tty?: boolean | null;
39
+ agent?: string | null;
37
40
  }
@@ -2,7 +2,7 @@ import { hostname } from "node:os";
2
2
  import inquirer from "inquirer";
3
3
  import { buildApplicationLifecycleEvent, getOrCreateApiClient, isCredentialsObject, } from "@zapier/zapier-sdk";
4
4
  import { revokeCredentials } from "../../login/credentials-revoke";
5
- import { deleteStoredClientCredentials, getActiveCredentials, } from "../../login/credentials-store";
5
+ import { deleteStoredClientCredentials, getActiveCredentials, resolveAvailableCredentialName, } from "../../login/credentials-store";
6
6
  import { clearLegacyJwtState, hasLegacyJwtConfig, } from "../../login/legacy-jwt";
7
7
  import { resolveCredentialsBaseUrl } from "../../plugins/auth/credentials-base-url";
8
8
  import { resolveNonInteractive } from "../non-interactive";
@@ -242,13 +242,18 @@ export async function runAccountAuth({ sdk, options, entryPoint, }) {
242
242
  const profile = await getProfile(scopedApi);
243
243
  console.log(getProfileMessage(entryPoint, profile.email));
244
244
  console.log("\nGenerating credentials so this machine can make authenticated requests on your behalf.");
245
- const resolveCredentialsName = interactive
246
- ? ({ email }) => promptCredentialsName({
247
- email,
245
+ const baseName = interactive
246
+ ? await promptCredentialsName({
247
+ email: profile.email,
248
248
  promptMessage: getCredentialsPromptMessage(entryPoint),
249
249
  })
250
- : resolveDefaultCredentialsName;
251
- const credentialName = await resolveCredentialsName({ email: profile.email });
250
+ : resolveDefaultCredentialsName({ email: profile.email });
251
+ // Non-interactive login can't prompt for a new name, so a default name that
252
+ // already exists locally would silently overwrite that credential. Suffix it
253
+ // instead. Interactive callers chose the name themselves, so leave it as-is.
254
+ const credentialName = interactive
255
+ ? baseName
256
+ : resolveAvailableCredentialName({ baseName, baseUrl: credentialsBaseUrl });
252
257
  const useApprovals = options.useApprovals === true;
253
258
  await saveClientCredentials({
254
259
  api: scopedApi,