@zapier/zapier-sdk-cli 0.55.4 → 0.55.6
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 +30 -0
- package/README.md +4 -2
- package/dist/cli.cjs +45 -6
- package/dist/cli.mjs +45 -6
- package/dist/experimental.cjs +44 -5
- package/dist/experimental.mjs +44 -5
- package/dist/index.cjs +45 -6
- package/dist/index.mjs +45 -6
- package/dist/package.json +1 -1
- package/dist/src/login/credentials-store.d.ts +9 -0
- package/dist/src/login/credentials-store.js +9 -0
- package/dist/src/plugins/login/index.d.ts +1 -0
- package/dist/src/plugins/login/schemas.d.ts +1 -0
- package/dist/src/plugins/login/schemas.js +4 -0
- package/dist/src/utils/auth/account-auth.d.ts +1 -0
- package/dist/src/utils/auth/account-auth.js +41 -12
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -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");
|
|
@@ -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()
|
|
@@ -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
|
|
246
|
-
|
|
279
|
+
const credentialName = providedName ??
|
|
280
|
+
(await resolveCredentialName({
|
|
247
281
|
email: profile.email,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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,
|