@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/CHANGELOG.md +16 -0
- package/dist/cli.cjs +32 -6
- package/dist/cli.mjs +33 -7
- package/dist/experimental.cjs +57 -31
- package/dist/experimental.mjs +57 -31
- package/dist/index.cjs +60 -32
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +61 -33
- package/dist/login.cjs +2 -0
- package/dist/login.mjs +2 -0
- package/dist/package.json +1 -1
- package/dist/src/login/credentials-store.d.ts +22 -0
- package/dist/src/login/credentials-store.js +33 -0
- package/dist/src/telemetry/builders.js +3 -1
- package/dist/src/telemetry/events.d.ts +3 -0
- package/dist/src/utils/auth/account-auth.js +11 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
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
|
|
1882
|
-
email,
|
|
1907
|
+
const baseName = interactive ? await promptCredentialsName({
|
|
1908
|
+
email: profile.email,
|
|
1883
1909
|
promptMessage: getCredentialsPromptMessage(entryPoint)
|
|
1884
|
-
}) : resolveDefaultCredentialsName;
|
|
1885
|
-
const credentialName =
|
|
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.
|
|
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.
|
|
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
package/dist/login.mjs
CHANGED
package/dist/package.json
CHANGED
|
@@ -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
|
|
246
|
-
?
|
|
247
|
-
email,
|
|
245
|
+
const baseName = interactive
|
|
246
|
+
? await promptCredentialsName({
|
|
247
|
+
email: profile.email,
|
|
248
248
|
promptMessage: getCredentialsPromptMessage(entryPoint),
|
|
249
249
|
})
|
|
250
|
-
: resolveDefaultCredentialsName;
|
|
251
|
-
|
|
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,
|