@zapier/zapier-sdk-cli 0.55.3 → 0.55.5

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';
@@ -377,6 +377,15 @@ function resolveAvailableCredentialName({
377
377
  );
378
378
  return firstAvailableCredentialName({ baseName, taken });
379
379
  }
380
+ function credentialNameExists({
381
+ name,
382
+ baseUrl
383
+ }) {
384
+ const resolvedBaseUrl = normalizeBaseUrl(baseUrl);
385
+ return readRegistry().some(
386
+ (e) => e.name === name && e.baseUrl === resolvedBaseUrl
387
+ );
388
+ }
380
389
  async function storeClientCredentials({
381
390
  name,
382
391
  clientId,
@@ -1682,6 +1691,21 @@ function resolveDefaultCredentialsName({
1682
1691
  }) {
1683
1692
  return validateCredentialsName(defaultCredentialsName(email));
1684
1693
  }
1694
+ async function resolveCredentialName({
1695
+ email,
1696
+ interactive,
1697
+ baseUrl,
1698
+ entryPoint
1699
+ }) {
1700
+ if (interactive) {
1701
+ return promptCredentialsName({
1702
+ email,
1703
+ promptMessage: getCredentialsPromptMessage(entryPoint)
1704
+ });
1705
+ }
1706
+ const baseName = resolveDefaultCredentialsName({ email });
1707
+ return resolveAvailableCredentialName({ baseName, baseUrl });
1708
+ }
1685
1709
  function toPkceCredentials(credentials) {
1686
1710
  if (credentials && isCredentialsObject(credentials) && !("clientSecret" in credentials)) {
1687
1711
  return {
@@ -1878,6 +1902,17 @@ async function runAccountAuth({
1878
1902
  ...sdk.context,
1879
1903
  resolvedCredentials
1880
1904
  });
1905
+ const providedName = options.name !== void 0 ? validateCredentialsName(options.name) : void 0;
1906
+ if (providedName !== void 0) {
1907
+ const activeCredentials = getActiveCredentials({
1908
+ baseUrl: credentialsBaseUrl
1909
+ });
1910
+ if (activeCredentials?.name !== providedName && credentialNameExists({ name: providedName, baseUrl: credentialsBaseUrl })) {
1911
+ throw new ZapierCliValidationError(
1912
+ `A credential named "${providedName}" already exists. Choose a different --name.`
1913
+ );
1914
+ }
1915
+ }
1881
1916
  if (!await clearExistingAuthState({
1882
1917
  sdk,
1883
1918
  baseUrl: credentialsBaseUrl,
@@ -1904,11 +1939,12 @@ async function runAccountAuth({
1904
1939
  console.log(
1905
1940
  "\nGenerating credentials so this machine can make authenticated requests on your behalf."
1906
1941
  );
1907
- const baseName = interactive ? await promptCredentialsName({
1942
+ const credentialName = providedName ?? await resolveCredentialName({
1908
1943
  email: profile.email,
1909
- promptMessage: getCredentialsPromptMessage(entryPoint)
1910
- }) : resolveDefaultCredentialsName({ email: profile.email });
1911
- const credentialName = interactive ? baseName : resolveAvailableCredentialName({ baseName, baseUrl: credentialsBaseUrl });
1944
+ interactive,
1945
+ baseUrl: credentialsBaseUrl,
1946
+ entryPoint
1947
+ });
1912
1948
  const useApprovals = options.useApprovals === true;
1913
1949
  await saveClientCredentials({
1914
1950
  api: scopedApi,
@@ -1926,6 +1962,9 @@ async function runAccountAuth({
1926
1962
  emitAccountAuthSuccess({ sdk, profile });
1927
1963
  }
1928
1964
  var LoginSchema = z.object({
1965
+ name: z.string().optional().describe(
1966
+ "Name to identify these credentials (defaults to <email>@<hostname>). Provide this to set a custom name without the interactive prompt."
1967
+ ),
1929
1968
  timeout: z.string().optional().describe("Login timeout in seconds (default: 300)"),
1930
1969
  useApprovals: z.boolean().optional().describe(
1931
1970
  "Require approvals for actions performed with these credentials"
@@ -4514,7 +4553,7 @@ definePlugin(
4514
4553
  // package.json with { type: 'json' }
4515
4554
  var package_default = {
4516
4555
  name: "@zapier/zapier-sdk-cli",
4517
- version: "0.55.3"};
4556
+ version: "0.55.5"};
4518
4557
 
4519
4558
  // src/sdk.ts
4520
4559
  injectCliLogin(login_exports);
@@ -4542,7 +4581,7 @@ function createZapierCliSdk(options = {}) {
4542
4581
 
4543
4582
  // package.json
4544
4583
  var package_default2 = {
4545
- version: "0.55.3"};
4584
+ version: "0.55.5"};
4546
4585
 
4547
4586
  // src/telemetry/builders.ts
4548
4587
  function createCliBaseEvent(context = {}) {
@@ -4586,6 +4625,8 @@ function buildCliCommandExecutedEvent({
4586
4625
  requires_auth: data.requires_auth ?? null,
4587
4626
  is_ci_environment: isCi(),
4588
4627
  ci_platform: getCiPlatform(),
4628
+ ...getTtyContext(),
4629
+ agent: getAgent(),
4589
4630
  package_manager: data.package_manager ?? "pnpm",
4590
4631
  // Default based on project setup
4591
4632
  made_network_requests: data.made_network_requests ?? null,
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.55.3",
3
+ "version": "0.55.5",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -33,6 +33,15 @@ export declare function resolveAvailableCredentialName({ baseName, baseUrl, }: {
33
33
  baseName: string;
34
34
  baseUrl?: string;
35
35
  }): string;
36
+ /**
37
+ * Whether a credential with this exact (name, baseUrl) is already stored
38
+ * locally. Used to reject an explicitly-supplied login name that would
39
+ * otherwise silently overwrite a dormant credential of the same name.
40
+ */
41
+ export declare function credentialNameExists({ name, baseUrl, }: {
42
+ name: string;
43
+ baseUrl?: string;
44
+ }): boolean;
36
45
  export declare function storeClientCredentials({ name, clientId, clientSecret, scopes, baseUrl, }: {
37
46
  name: string;
38
47
  clientId: string;
@@ -74,6 +74,15 @@ export function resolveAvailableCredentialName({ baseName, baseUrl, }) {
74
74
  .map((e) => e.name));
75
75
  return firstAvailableCredentialName({ baseName, taken });
76
76
  }
77
+ /**
78
+ * Whether a credential with this exact (name, baseUrl) is already stored
79
+ * locally. Used to reject an explicitly-supplied login name that would
80
+ * otherwise silently overwrite a dormant credential of the same name.
81
+ */
82
+ export function credentialNameExists({ name, baseUrl, }) {
83
+ const resolvedBaseUrl = normalizeBaseUrl(baseUrl);
84
+ return readRegistry().some((e) => e.name === name && e.baseUrl === resolvedBaseUrl);
85
+ }
77
86
  export async function storeClientCredentials({ name, clientId, clientSecret, scopes, baseUrl, }) {
78
87
  if (!name || typeof name !== "string") {
79
88
  throw new Error("storeClientCredentials: name is required");
@@ -9,6 +9,7 @@ export declare const loginPlugin: (sdk: {
9
9
  };
10
10
  }) => {
11
11
  login: (options?: {
12
+ name?: string | undefined;
12
13
  timeout?: string | undefined;
13
14
  useApprovals?: boolean | undefined;
14
15
  nonInteractive?: boolean | undefined;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const LoginSchema: z.ZodObject<{
3
+ name: z.ZodOptional<z.ZodString>;
3
4
  timeout: z.ZodOptional<z.ZodString>;
4
5
  useApprovals: z.ZodOptional<z.ZodBoolean>;
5
6
  nonInteractive: z.ZodOptional<z.ZodBoolean>;
@@ -2,6 +2,10 @@ import { z } from "zod";
2
2
  // Login schema
3
3
  export const LoginSchema = z
4
4
  .object({
5
+ name: z
6
+ .string()
7
+ .optional()
8
+ .describe("Name to identify these credentials (defaults to <email>@<hostname>). Provide this to set a custom name without the interactive prompt."),
5
9
  timeout: z
6
10
  .string()
7
11
  .optional()
@@ -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
  }
@@ -1,6 +1,7 @@
1
1
  import { type ApiClient, type EventEmissionProvides, type ResolvedCredentials } from "@zapier/zapier-sdk";
2
2
  export type AccountAuthEntryPoint = "login" | "signup";
3
3
  export interface AccountAuthOptions {
4
+ name?: string;
4
5
  timeout?: string;
5
6
  useApprovals?: boolean;
6
7
  nonInteractive?: boolean;
@@ -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, resolveAvailableCredentialName, } from "../../login/credentials-store";
5
+ import { credentialNameExists, 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";
@@ -61,6 +61,19 @@ async function promptCredentialsName({ email, promptMessage, }) {
61
61
  function resolveDefaultCredentialsName({ email, }) {
62
62
  return validateCredentialsName(defaultCredentialsName(email));
63
63
  }
64
+ async function resolveCredentialName({ email, interactive, baseUrl, entryPoint, }) {
65
+ if (interactive) {
66
+ return promptCredentialsName({
67
+ email,
68
+ promptMessage: getCredentialsPromptMessage(entryPoint),
69
+ });
70
+ }
71
+ // Non-interactive login can't prompt for a new name, so a default name that
72
+ // already exists locally would silently overwrite that credential. Suffix it
73
+ // instead.
74
+ const baseName = resolveDefaultCredentialsName({ email });
75
+ return resolveAvailableCredentialName({ baseName, baseUrl });
76
+ }
64
77
  function toPkceCredentials(credentials) {
65
78
  if (credentials &&
66
79
  isCredentialsObject(credentials) &&
@@ -218,6 +231,27 @@ export async function runAccountAuth({ sdk, options, entryPoint, }) {
218
231
  ...sdk.context,
219
232
  resolvedCredentials,
220
233
  });
234
+ // An explicitly-supplied name is validated and collision-checked up front,
235
+ // before we tear down the existing session or run OAuth. Otherwise a blank or
236
+ // already-taken name would only surface after revoking the active credential
237
+ // and completing the browser flow, leaving the user logged out for nothing.
238
+ // The name is trimmed but otherwise honored as given — never auto-suffixed —
239
+ // so a collision is rejected rather than silently overwriting an existing
240
+ // credential.
241
+ const providedName = options.name !== undefined
242
+ ? validateCredentialsName(options.name)
243
+ : undefined;
244
+ if (providedName !== undefined) {
245
+ const activeCredentials = getActiveCredentials({
246
+ baseUrl: credentialsBaseUrl,
247
+ });
248
+ // Re-login under the active credential's own name is a rotation, not a
249
+ // collision — clearExistingAuthState frees it below.
250
+ if (activeCredentials?.name !== providedName &&
251
+ credentialNameExists({ name: providedName, baseUrl: credentialsBaseUrl })) {
252
+ throw new ZapierCliValidationError(`A credential named "${providedName}" already exists. Choose a different --name.`);
253
+ }
254
+ }
221
255
  if (!(await clearExistingAuthState({
222
256
  sdk,
223
257
  baseUrl: credentialsBaseUrl,
@@ -242,18 +276,13 @@ export async function runAccountAuth({ sdk, options, entryPoint, }) {
242
276
  const profile = await getProfile(scopedApi);
243
277
  console.log(getProfileMessage(entryPoint, profile.email));
244
278
  console.log("\nGenerating credentials so this machine can make authenticated requests on your behalf.");
245
- const baseName = interactive
246
- ? await promptCredentialsName({
279
+ const credentialName = providedName ??
280
+ (await resolveCredentialName({
247
281
  email: profile.email,
248
- promptMessage: getCredentialsPromptMessage(entryPoint),
249
- })
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 });
282
+ interactive,
283
+ baseUrl: credentialsBaseUrl,
284
+ entryPoint,
285
+ }));
257
286
  const useApprovals = options.useApprovals === true;
258
287
  await saveClientCredentials({
259
288
  api: scopedApi,