@zapier/zapier-sdk-cli 0.42.1 → 0.43.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/CHANGELOG.md +21 -0
- package/README.md +4 -4
- package/dist/cli.cjs +619 -34
- package/dist/cli.d.mts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.mjs +601 -19
- package/dist/index.cjs +607 -23
- package/dist/index.mjs +592 -11
- package/dist/login.cjs +599 -7
- package/dist/login.d.mts +144 -1
- package/dist/login.d.ts +144 -1
- package/dist/login.mjs +565 -1
- package/dist/package.json +6 -3
- package/dist/src/login/filesystem-cache.d.ts +25 -0
- package/dist/src/login/filesystem-cache.js +195 -0
- package/dist/src/login/index.d.ts +115 -0
- package/dist/src/login/index.js +442 -0
- package/dist/src/login/keychain.d.ts +18 -0
- package/dist/src/login/keychain.js +74 -0
- package/dist/src/login.d.ts +10 -1
- package/dist/src/login.js +10 -1
- package/dist/src/plugins/feedback/index.js +1 -1
- package/dist/src/plugins/getLoginConfigPath/index.js +1 -1
- package/dist/src/plugins/login/index.js +1 -1
- package/dist/src/plugins/logout/index.js +1 -1
- package/dist/src/sdk.js +1 -1
- package/dist/src/utils/auth/login.d.ts +1 -1
- package/dist/src/utils/auth/login.js +1 -1
- package/dist/src/utils/constants.d.ts +1 -1
- package/dist/src/utils/constants.js +1 -1
- package/dist/src/utils/version-checker.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -5
package/dist/cli.d.mts
CHANGED
package/dist/cli.d.ts
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -7,18 +7,20 @@ import chalk7 from 'chalk';
|
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import util from 'util';
|
|
9
9
|
import wrapAnsi from 'wrap-ansi';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
10
|
+
import Conf from 'conf';
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import { existsSync, promises, createWriteStream, readdirSync, rmSync, mkdirSync, writeFileSync, copyFileSync, readFileSync } from 'fs';
|
|
13
|
+
import * as jwt from 'jsonwebtoken';
|
|
14
|
+
import { setPassword, getKeyring, getPassword, deletePassword } from 'cross-keychain';
|
|
13
15
|
import crypto, { createHash } from 'crypto';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import { resolve, join, dirname, basename, relative, extname } from 'path';
|
|
18
|
+
import * as lockfile from 'proper-lockfile';
|
|
19
|
+
import open from 'open';
|
|
14
20
|
import express from 'express';
|
|
15
21
|
import pkceChallenge from 'pkce-challenge';
|
|
16
22
|
import { startMcpServer } from '@zapier/zapier-sdk-mcp';
|
|
17
23
|
import { buildSync } from 'esbuild';
|
|
18
|
-
import * as fs from 'fs';
|
|
19
|
-
import { promises, createWriteStream, existsSync, readdirSync, rmSync, mkdirSync, writeFileSync, copyFileSync, readFileSync } from 'fs';
|
|
20
|
-
import * as path from 'path';
|
|
21
|
-
import { resolve, join, dirname, basename, relative, extname } from 'path';
|
|
22
24
|
import { mkdir, writeFile, access } from 'fs/promises';
|
|
23
25
|
import * as ts from 'typescript';
|
|
24
26
|
import isInstalledGlobally from 'is-installed-globally';
|
|
@@ -28,6 +30,11 @@ import { fileURLToPath } from 'url';
|
|
|
28
30
|
import packageJsonLib from 'package-json';
|
|
29
31
|
import semver from 'semver';
|
|
30
32
|
|
|
33
|
+
var __defProp = Object.defineProperty;
|
|
34
|
+
var __export = (target, all) => {
|
|
35
|
+
for (var name in all)
|
|
36
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
37
|
+
};
|
|
31
38
|
var ZapierCliError = class extends ZapierError {
|
|
32
39
|
};
|
|
33
40
|
var ZapierCliUserCancellationError = class extends ZapierCliError {
|
|
@@ -1065,7 +1072,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
|
|
|
1065
1072
|
|
|
1066
1073
|
// package.json
|
|
1067
1074
|
var package_default = {
|
|
1068
|
-
version: "0.
|
|
1075
|
+
version: "0.43.0"};
|
|
1069
1076
|
|
|
1070
1077
|
// src/telemetry/builders.ts
|
|
1071
1078
|
function createCliBaseEvent(context = {}) {
|
|
@@ -1795,8 +1802,8 @@ function generateCliCommands(program2, sdk2) {
|
|
|
1795
1802
|
return;
|
|
1796
1803
|
}
|
|
1797
1804
|
const cliCommandName = methodNameToCliCommand(fnInfo.name);
|
|
1798
|
-
const
|
|
1799
|
-
addCommand(program2, cliCommandName,
|
|
1805
|
+
const config2 = createCommandConfig(cliCommandName, fnInfo, sdk2);
|
|
1806
|
+
addCommand(program2, cliCommandName, config2);
|
|
1800
1807
|
});
|
|
1801
1808
|
program2.configureHelp({
|
|
1802
1809
|
formatHelp: (cmd, helper) => {
|
|
@@ -2053,10 +2060,10 @@ function collect(value, previous = []) {
|
|
|
2053
2060
|
previous.push(value);
|
|
2054
2061
|
return previous;
|
|
2055
2062
|
}
|
|
2056
|
-
function addCommand(program2, commandName,
|
|
2057
|
-
const command = program2.command(commandName, { hidden:
|
|
2063
|
+
function addCommand(program2, commandName, config2) {
|
|
2064
|
+
const command = program2.command(commandName, { hidden: config2.hidden ?? false }).description(config2.description);
|
|
2058
2065
|
let hasPositionalArray = false;
|
|
2059
|
-
|
|
2066
|
+
config2.parameters.forEach((param) => {
|
|
2060
2067
|
const kebabName = toKebabCase(param.name);
|
|
2061
2068
|
if (param.hasResolver && param.required) {
|
|
2062
2069
|
command.argument(
|
|
@@ -2090,7 +2097,7 @@ function addCommand(program2, commandName, config) {
|
|
|
2090
2097
|
);
|
|
2091
2098
|
} else {
|
|
2092
2099
|
const flags = [];
|
|
2093
|
-
const alias =
|
|
2100
|
+
const alias = config2.aliases?.[param.name];
|
|
2094
2101
|
if (alias && alias.length === 1) {
|
|
2095
2102
|
flags.push(`-${alias}`);
|
|
2096
2103
|
}
|
|
@@ -2119,13 +2126,13 @@ function addCommand(program2, commandName, config) {
|
|
|
2119
2126
|
}
|
|
2120
2127
|
}
|
|
2121
2128
|
});
|
|
2122
|
-
const paramNames = new Set(
|
|
2129
|
+
const paramNames = new Set(config2.parameters.map((p) => p.name));
|
|
2123
2130
|
SHARED_COMMAND_CLI_OPTIONS.forEach((opt) => {
|
|
2124
2131
|
if (paramNames.has(opt.name)) return;
|
|
2125
|
-
if (
|
|
2132
|
+
if (config2.supportsJsonOutput === false && opt.name === "json") return;
|
|
2126
2133
|
command.option(opt.flag, opt.description);
|
|
2127
2134
|
});
|
|
2128
|
-
command.action(
|
|
2135
|
+
command.action(config2.handler);
|
|
2129
2136
|
}
|
|
2130
2137
|
function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
|
|
2131
2138
|
const sdkParams = {};
|
|
@@ -2197,6 +2204,581 @@ function convertValue(value, type, elementType) {
|
|
|
2197
2204
|
return value;
|
|
2198
2205
|
}
|
|
2199
2206
|
}
|
|
2207
|
+
|
|
2208
|
+
// src/login.ts
|
|
2209
|
+
var login_exports = {};
|
|
2210
|
+
__export(login_exports, {
|
|
2211
|
+
AUTH_MODE_HEADER: () => AUTH_MODE_HEADER,
|
|
2212
|
+
ZapierAuthenticationError: () => ZapierAuthenticationError,
|
|
2213
|
+
createCache: () => createCache,
|
|
2214
|
+
getAuthAuthorizeUrl: () => getAuthAuthorizeUrl,
|
|
2215
|
+
getAuthTokenUrl: () => getAuthTokenUrl,
|
|
2216
|
+
getConfig: () => getConfig,
|
|
2217
|
+
getConfigPath: () => getConfigPath,
|
|
2218
|
+
getLoggedInUser: () => getLoggedInUser,
|
|
2219
|
+
getLoginStorageMode: () => getLoginStorageMode,
|
|
2220
|
+
getPkceLoginConfig: () => getPkceLoginConfig,
|
|
2221
|
+
getToken: () => getToken,
|
|
2222
|
+
logout: () => logout,
|
|
2223
|
+
unloadConfig: () => unloadConfig,
|
|
2224
|
+
updateLogin: () => updateLogin
|
|
2225
|
+
});
|
|
2226
|
+
var SERVICE = "zapier-sdk-cli";
|
|
2227
|
+
var ACCOUNT = "login";
|
|
2228
|
+
var cachedBackendInfo;
|
|
2229
|
+
async function getBackendInfo() {
|
|
2230
|
+
if (!cachedBackendInfo) {
|
|
2231
|
+
const keyring = await getKeyring();
|
|
2232
|
+
cachedBackendInfo = `${keyring.name} (${keyring.id})`;
|
|
2233
|
+
}
|
|
2234
|
+
return cachedBackendInfo;
|
|
2235
|
+
}
|
|
2236
|
+
var keychainQueue = Promise.resolve();
|
|
2237
|
+
function enqueue(fn) {
|
|
2238
|
+
const result = keychainQueue.then(fn, fn);
|
|
2239
|
+
keychainQueue = result.then(
|
|
2240
|
+
() => {
|
|
2241
|
+
},
|
|
2242
|
+
() => {
|
|
2243
|
+
}
|
|
2244
|
+
);
|
|
2245
|
+
return result;
|
|
2246
|
+
}
|
|
2247
|
+
async function getTokensFromKeychain({
|
|
2248
|
+
debugLog
|
|
2249
|
+
} = {}) {
|
|
2250
|
+
return enqueue(async () => {
|
|
2251
|
+
const backendInfo = await getBackendInfo();
|
|
2252
|
+
debugLog?.(`Keychain read via ${backendInfo}`);
|
|
2253
|
+
const startTime = Date.now();
|
|
2254
|
+
const raw = await getPassword(SERVICE, ACCOUNT);
|
|
2255
|
+
debugLog?.(`Keychain read completed in ${Date.now() - startTime}ms`);
|
|
2256
|
+
if (!raw) {
|
|
2257
|
+
debugLog?.("Keychain returned no data");
|
|
2258
|
+
return void 0;
|
|
2259
|
+
}
|
|
2260
|
+
let parsed;
|
|
2261
|
+
try {
|
|
2262
|
+
parsed = JSON.parse(raw);
|
|
2263
|
+
} catch {
|
|
2264
|
+
debugLog?.("Keychain data is not valid JSON");
|
|
2265
|
+
return void 0;
|
|
2266
|
+
}
|
|
2267
|
+
if (typeof parsed.login_jwt === "string" && typeof parsed.login_refresh_token === "string") {
|
|
2268
|
+
return {
|
|
2269
|
+
login_jwt: parsed.login_jwt,
|
|
2270
|
+
login_refresh_token: parsed.login_refresh_token
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
debugLog?.("Keychain data has invalid shape", parsed);
|
|
2274
|
+
return void 0;
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
async function setTokensInKeychain({
|
|
2278
|
+
data,
|
|
2279
|
+
debugLog
|
|
2280
|
+
}) {
|
|
2281
|
+
return enqueue(async () => {
|
|
2282
|
+
const backendInfo = await getBackendInfo();
|
|
2283
|
+
debugLog?.(`Keychain write via ${backendInfo}`);
|
|
2284
|
+
const startTime = Date.now();
|
|
2285
|
+
await setPassword(SERVICE, ACCOUNT, JSON.stringify(data));
|
|
2286
|
+
debugLog?.(`Keychain write completed in ${Date.now() - startTime}ms`);
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2289
|
+
async function clearTokensFromKeychain({
|
|
2290
|
+
debugLog
|
|
2291
|
+
} = {}) {
|
|
2292
|
+
return enqueue(async () => {
|
|
2293
|
+
try {
|
|
2294
|
+
const backendInfo = await getBackendInfo();
|
|
2295
|
+
debugLog?.(`Keychain clear via ${backendInfo}`);
|
|
2296
|
+
await deletePassword(SERVICE, ACCOUNT);
|
|
2297
|
+
} catch {
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
var SERVICE2 = "zapier-sdk-cache";
|
|
2302
|
+
var CONFIG_KEY = "cache";
|
|
2303
|
+
var LOCK_UPDATE_MS = 5e3;
|
|
2304
|
+
var LOCK_STALE_MS = 1e4;
|
|
2305
|
+
var LOCK_RETRY_WAIT_MS = 100;
|
|
2306
|
+
var LOCK_RETRY_MAX_WAIT_MS = 1e3;
|
|
2307
|
+
var LOCK_RETRY_COUNT = 120;
|
|
2308
|
+
function keychainAccount(key) {
|
|
2309
|
+
return createHash("sha256").update(key).digest("hex");
|
|
2310
|
+
}
|
|
2311
|
+
function readConfigMap() {
|
|
2312
|
+
const cfg = getConfig();
|
|
2313
|
+
const stored = cfg.get(CONFIG_KEY);
|
|
2314
|
+
if (stored && typeof stored === "object") {
|
|
2315
|
+
return stored;
|
|
2316
|
+
}
|
|
2317
|
+
return {};
|
|
2318
|
+
}
|
|
2319
|
+
function writeConfigMap(map) {
|
|
2320
|
+
getConfig().set(CONFIG_KEY, map);
|
|
2321
|
+
}
|
|
2322
|
+
function entryIsExpired(entry) {
|
|
2323
|
+
return entry.expires_at !== void 0 && entry.expires_at <= Date.now();
|
|
2324
|
+
}
|
|
2325
|
+
function createCache() {
|
|
2326
|
+
return {
|
|
2327
|
+
async get(key) {
|
|
2328
|
+
const entry = readConfigMap()[key];
|
|
2329
|
+
if (!entry) return void 0;
|
|
2330
|
+
if (entryIsExpired(entry)) return void 0;
|
|
2331
|
+
if (entry.secret) {
|
|
2332
|
+
const stored = await enqueue(async () => {
|
|
2333
|
+
await getBackendInfo();
|
|
2334
|
+
return getPassword(SERVICE2, keychainAccount(key));
|
|
2335
|
+
});
|
|
2336
|
+
if (!stored) {
|
|
2337
|
+
return void 0;
|
|
2338
|
+
}
|
|
2339
|
+
return { value: stored, expiresAt: entry.expires_at };
|
|
2340
|
+
}
|
|
2341
|
+
if (entry.value === void 0) return void 0;
|
|
2342
|
+
return { value: entry.value, expiresAt: entry.expires_at };
|
|
2343
|
+
},
|
|
2344
|
+
async set(key, value, options) {
|
|
2345
|
+
const secret = options?.secret ?? false;
|
|
2346
|
+
const expiresAt = options?.ttl ? Date.now() + options.ttl * 1e3 : void 0;
|
|
2347
|
+
if (secret) {
|
|
2348
|
+
try {
|
|
2349
|
+
await enqueue(async () => {
|
|
2350
|
+
await getBackendInfo();
|
|
2351
|
+
await setPassword(SERVICE2, keychainAccount(key), value);
|
|
2352
|
+
});
|
|
2353
|
+
} catch {
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
const map = readConfigMap();
|
|
2357
|
+
map[key] = { secret: true, expires_at: expiresAt };
|
|
2358
|
+
try {
|
|
2359
|
+
writeConfigMap(map);
|
|
2360
|
+
} catch {
|
|
2361
|
+
}
|
|
2362
|
+
} else {
|
|
2363
|
+
const map = readConfigMap();
|
|
2364
|
+
map[key] = { secret: false, value, expires_at: expiresAt };
|
|
2365
|
+
try {
|
|
2366
|
+
writeConfigMap(map);
|
|
2367
|
+
} catch {
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
},
|
|
2371
|
+
async delete(key) {
|
|
2372
|
+
const map = readConfigMap();
|
|
2373
|
+
const entry = map[key];
|
|
2374
|
+
if (entry) {
|
|
2375
|
+
delete map[key];
|
|
2376
|
+
try {
|
|
2377
|
+
writeConfigMap(map);
|
|
2378
|
+
} catch {
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
if (entry?.secret) {
|
|
2382
|
+
try {
|
|
2383
|
+
await enqueue(async () => {
|
|
2384
|
+
await getBackendInfo();
|
|
2385
|
+
await deletePassword(SERVICE2, keychainAccount(key));
|
|
2386
|
+
});
|
|
2387
|
+
} catch {
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
},
|
|
2391
|
+
async withLock(_key, fn) {
|
|
2392
|
+
const cfg = getConfig();
|
|
2393
|
+
const lockTarget = `${cfg.path}.cache-lock`;
|
|
2394
|
+
try {
|
|
2395
|
+
mkdirSync(dirname(lockTarget), { recursive: true });
|
|
2396
|
+
if (!existsSync(lockTarget)) {
|
|
2397
|
+
writeFileSync(lockTarget, "");
|
|
2398
|
+
}
|
|
2399
|
+
} catch {
|
|
2400
|
+
return fn();
|
|
2401
|
+
}
|
|
2402
|
+
let release = null;
|
|
2403
|
+
try {
|
|
2404
|
+
release = await lockfile.lock(lockTarget, {
|
|
2405
|
+
stale: LOCK_STALE_MS,
|
|
2406
|
+
update: LOCK_UPDATE_MS,
|
|
2407
|
+
retries: {
|
|
2408
|
+
retries: LOCK_RETRY_COUNT,
|
|
2409
|
+
factor: 1.2,
|
|
2410
|
+
minTimeout: LOCK_RETRY_WAIT_MS,
|
|
2411
|
+
maxTimeout: LOCK_RETRY_MAX_WAIT_MS
|
|
2412
|
+
}
|
|
2413
|
+
});
|
|
2414
|
+
} catch {
|
|
2415
|
+
return fn();
|
|
2416
|
+
}
|
|
2417
|
+
try {
|
|
2418
|
+
return await fn();
|
|
2419
|
+
} finally {
|
|
2420
|
+
try {
|
|
2421
|
+
await release();
|
|
2422
|
+
} catch {
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
// src/login/index.ts
|
|
2430
|
+
var ZapierAuthenticationError = class extends Error {
|
|
2431
|
+
constructor(message) {
|
|
2432
|
+
super(message);
|
|
2433
|
+
this.name = "ZapierAuthenticationError";
|
|
2434
|
+
}
|
|
2435
|
+
};
|
|
2436
|
+
var config = null;
|
|
2437
|
+
var DEFAULT_AUTH_CLIENT_ID = "grwWZD5hUWGvb4V8ODBuOtXer3h0DBEZ2HR8aay6";
|
|
2438
|
+
var TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1e3;
|
|
2439
|
+
function createDebugLog(enabled) {
|
|
2440
|
+
if (!enabled) {
|
|
2441
|
+
return () => {
|
|
2442
|
+
};
|
|
2443
|
+
}
|
|
2444
|
+
return (message, data) => {
|
|
2445
|
+
if (data === void 0) {
|
|
2446
|
+
console.log(`[Zapier SDK CLI Login] ${message}`);
|
|
2447
|
+
} else {
|
|
2448
|
+
console.log(`[Zapier SDK CLI Login] ${message}`, data);
|
|
2449
|
+
}
|
|
2450
|
+
};
|
|
2451
|
+
}
|
|
2452
|
+
function censorHeaderValue(value) {
|
|
2453
|
+
if (value.length > 12) {
|
|
2454
|
+
return `${value.substring(0, 4)}...${value.substring(value.length - 4)}`;
|
|
2455
|
+
}
|
|
2456
|
+
return `${value.charAt(0)}...`;
|
|
2457
|
+
}
|
|
2458
|
+
function getAuthClientId(clientId) {
|
|
2459
|
+
return clientId || DEFAULT_AUTH_CLIENT_ID;
|
|
2460
|
+
}
|
|
2461
|
+
var AUTH_MODE_HEADER = "X-Auth";
|
|
2462
|
+
var DEFAULT_AUTH_BASE_URL = "https://zapier.com";
|
|
2463
|
+
function getAuthTokenUrl(options) {
|
|
2464
|
+
const authBaseUrl = options?.baseUrl || DEFAULT_AUTH_BASE_URL;
|
|
2465
|
+
return `${authBaseUrl}/oauth/token/`;
|
|
2466
|
+
}
|
|
2467
|
+
function getAuthAuthorizeUrl(options) {
|
|
2468
|
+
const authBaseUrl = options?.baseUrl || DEFAULT_AUTH_BASE_URL;
|
|
2469
|
+
return `${authBaseUrl}/oauth/authorize/`;
|
|
2470
|
+
}
|
|
2471
|
+
function getPkceLoginConfig(options) {
|
|
2472
|
+
return {
|
|
2473
|
+
clientId: getAuthClientId(options?.credentials?.clientId),
|
|
2474
|
+
tokenUrl: getAuthTokenUrl({ baseUrl: options?.credentials?.baseUrl }),
|
|
2475
|
+
authorizeUrl: getAuthAuthorizeUrl({
|
|
2476
|
+
baseUrl: options?.credentials?.baseUrl
|
|
2477
|
+
})
|
|
2478
|
+
};
|
|
2479
|
+
}
|
|
2480
|
+
var cachedLogin;
|
|
2481
|
+
function getConfig() {
|
|
2482
|
+
if (!config) {
|
|
2483
|
+
config = new Conf({ projectName: "zapier-sdk-cli" });
|
|
2484
|
+
if (!config.has("login_storage_mode")) {
|
|
2485
|
+
config.set(
|
|
2486
|
+
"login_storage_mode",
|
|
2487
|
+
existsSync(config.path) ? "config" : "keychain"
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
return config;
|
|
2492
|
+
}
|
|
2493
|
+
function unloadConfig() {
|
|
2494
|
+
config = null;
|
|
2495
|
+
cachedLogin = void 0;
|
|
2496
|
+
}
|
|
2497
|
+
async function updateLogin(loginData, options = {}) {
|
|
2498
|
+
const debugLog = createDebugLog(options.debug ?? false);
|
|
2499
|
+
const storage = options.storage ?? cachedLogin?.storage ?? "keychain";
|
|
2500
|
+
const expiresAt = Date.now() + loginData.expires_in * 1e3;
|
|
2501
|
+
const cfg = getConfig();
|
|
2502
|
+
cfg.set("login_storage_mode", storage);
|
|
2503
|
+
if (storage === "keychain") {
|
|
2504
|
+
await setTokensInKeychain({
|
|
2505
|
+
data: {
|
|
2506
|
+
login_jwt: loginData.access_token,
|
|
2507
|
+
login_refresh_token: loginData.refresh_token
|
|
2508
|
+
},
|
|
2509
|
+
debugLog
|
|
2510
|
+
});
|
|
2511
|
+
cfg.set("login_expires_at", expiresAt);
|
|
2512
|
+
cfg.delete("login_jwt");
|
|
2513
|
+
cfg.delete("login_refresh_token");
|
|
2514
|
+
} else {
|
|
2515
|
+
cfg.set("login_jwt", loginData.access_token);
|
|
2516
|
+
cfg.set("login_refresh_token", loginData.refresh_token);
|
|
2517
|
+
cfg.set("login_expires_at", expiresAt);
|
|
2518
|
+
await clearTokensFromKeychain({ debugLog });
|
|
2519
|
+
}
|
|
2520
|
+
cachedLogin = {
|
|
2521
|
+
jwt: loginData.access_token,
|
|
2522
|
+
refreshToken: loginData.refresh_token,
|
|
2523
|
+
expiresAt,
|
|
2524
|
+
storage
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
function decodeJwtOrThrow(token) {
|
|
2528
|
+
if (typeof token !== "string") {
|
|
2529
|
+
throw new Error("Expected JWT to be a string");
|
|
2530
|
+
}
|
|
2531
|
+
const decodedJwt = jwt.decode(token, { complete: true });
|
|
2532
|
+
if (!decodedJwt) {
|
|
2533
|
+
throw new Error("Could not decode JWT");
|
|
2534
|
+
}
|
|
2535
|
+
if (typeof decodedJwt.payload === "string") {
|
|
2536
|
+
throw new Error("Did not expect JWT payload to be a string");
|
|
2537
|
+
}
|
|
2538
|
+
return decodedJwt;
|
|
2539
|
+
}
|
|
2540
|
+
async function refreshJwt(refreshToken, options = {}) {
|
|
2541
|
+
const {
|
|
2542
|
+
onEvent,
|
|
2543
|
+
fetch: fetch2 = globalThis.fetch,
|
|
2544
|
+
credentials: credentials2,
|
|
2545
|
+
debug = false
|
|
2546
|
+
} = options;
|
|
2547
|
+
const debugLog = createDebugLog(debug);
|
|
2548
|
+
const tokenUrl = getAuthTokenUrl({ baseUrl: credentials2?.baseUrl });
|
|
2549
|
+
const clientId = getAuthClientId(credentials2?.clientId);
|
|
2550
|
+
const startTime = Date.now();
|
|
2551
|
+
try {
|
|
2552
|
+
onEvent?.({
|
|
2553
|
+
type: "auth_refreshing",
|
|
2554
|
+
payload: {
|
|
2555
|
+
message: "Refreshing your token...",
|
|
2556
|
+
operation: "token_refresh"
|
|
2557
|
+
},
|
|
2558
|
+
timestamp: Date.now()
|
|
2559
|
+
});
|
|
2560
|
+
debugLog(`\u2192 POST ${tokenUrl}`, {
|
|
2561
|
+
headers: {
|
|
2562
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
2563
|
+
[AUTH_MODE_HEADER]: "no"
|
|
2564
|
+
},
|
|
2565
|
+
body: {
|
|
2566
|
+
client_id: clientId,
|
|
2567
|
+
refresh_token: censorHeaderValue(refreshToken),
|
|
2568
|
+
grant_type: "refresh_token"
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2571
|
+
const response = await fetch2(tokenUrl, {
|
|
2572
|
+
method: "POST",
|
|
2573
|
+
headers: {
|
|
2574
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
2575
|
+
[AUTH_MODE_HEADER]: "no"
|
|
2576
|
+
},
|
|
2577
|
+
body: new URLSearchParams({
|
|
2578
|
+
client_id: clientId,
|
|
2579
|
+
refresh_token: refreshToken,
|
|
2580
|
+
grant_type: "refresh_token"
|
|
2581
|
+
})
|
|
2582
|
+
});
|
|
2583
|
+
const duration = Date.now() - startTime;
|
|
2584
|
+
if (!response.ok) {
|
|
2585
|
+
debugLog(`\u2190 ${response.status} ${response.statusText} (${duration}ms)`);
|
|
2586
|
+
throw new Error(
|
|
2587
|
+
`Token refresh failed: ${response.status} ${response.statusText}`
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
debugLog(`\u2190 ${response.status} ${response.statusText} (${duration}ms)`);
|
|
2591
|
+
const data = await response.json();
|
|
2592
|
+
await updateLogin(data, { debug });
|
|
2593
|
+
debugLog(
|
|
2594
|
+
`Token refreshed and saved to ${cachedLogin?.storage ?? "keychain"}`
|
|
2595
|
+
);
|
|
2596
|
+
onEvent?.({
|
|
2597
|
+
type: "auth_success",
|
|
2598
|
+
payload: {
|
|
2599
|
+
message: "Token refreshed successfully",
|
|
2600
|
+
operation: "token_refresh"
|
|
2601
|
+
},
|
|
2602
|
+
timestamp: Date.now()
|
|
2603
|
+
});
|
|
2604
|
+
return data.access_token;
|
|
2605
|
+
} catch (error) {
|
|
2606
|
+
const duration = Date.now() - startTime;
|
|
2607
|
+
debugLog(`\u2716 Token refresh failed (${duration}ms)`, {
|
|
2608
|
+
error: error instanceof Error ? error.message : error
|
|
2609
|
+
});
|
|
2610
|
+
cachedLogin = void 0;
|
|
2611
|
+
const errorMessage = `Token refresh failed: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
2612
|
+
onEvent?.({
|
|
2613
|
+
type: "auth_error",
|
|
2614
|
+
payload: {
|
|
2615
|
+
message: errorMessage,
|
|
2616
|
+
error: errorMessage,
|
|
2617
|
+
operation: "token_refresh"
|
|
2618
|
+
},
|
|
2619
|
+
timestamp: Date.now()
|
|
2620
|
+
});
|
|
2621
|
+
throw error;
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
var pendingRefresh = null;
|
|
2625
|
+
var pendingResolve = null;
|
|
2626
|
+
async function resolveStoredLogin(debugLog) {
|
|
2627
|
+
if (cachedLogin) {
|
|
2628
|
+
debugLog("Using in-memory cached credentials");
|
|
2629
|
+
return cachedLogin;
|
|
2630
|
+
}
|
|
2631
|
+
if (pendingResolve) {
|
|
2632
|
+
debugLog("Waiting for existing keychain read to complete");
|
|
2633
|
+
return pendingResolve;
|
|
2634
|
+
}
|
|
2635
|
+
pendingResolve = resolveStoredLoginFromStorage(debugLog).finally(() => {
|
|
2636
|
+
pendingResolve = null;
|
|
2637
|
+
});
|
|
2638
|
+
return pendingResolve;
|
|
2639
|
+
}
|
|
2640
|
+
async function resolveStoredLoginFromStorage(debugLog) {
|
|
2641
|
+
let cfg;
|
|
2642
|
+
try {
|
|
2643
|
+
cfg = getConfig();
|
|
2644
|
+
} catch (error) {
|
|
2645
|
+
debugLog("Failed to load config", {
|
|
2646
|
+
error: error instanceof Error ? error.message : error
|
|
2647
|
+
});
|
|
2648
|
+
return void 0;
|
|
2649
|
+
}
|
|
2650
|
+
const expiresAt = cfg.get("login_expires_at");
|
|
2651
|
+
const configJwt = cfg.get("login_jwt");
|
|
2652
|
+
const configRefresh = cfg.get("login_refresh_token");
|
|
2653
|
+
if (configJwt && configRefresh && typeof expiresAt === "number") {
|
|
2654
|
+
debugLog("Loaded credentials from config (legacy format)");
|
|
2655
|
+
cachedLogin = {
|
|
2656
|
+
jwt: configJwt,
|
|
2657
|
+
refreshToken: configRefresh,
|
|
2658
|
+
expiresAt,
|
|
2659
|
+
storage: "config"
|
|
2660
|
+
};
|
|
2661
|
+
return cachedLogin;
|
|
2662
|
+
}
|
|
2663
|
+
if (typeof expiresAt !== "number") {
|
|
2664
|
+
debugLog("No stored login credentials found");
|
|
2665
|
+
return void 0;
|
|
2666
|
+
}
|
|
2667
|
+
const keychainData = await getTokensFromKeychain({ debugLog });
|
|
2668
|
+
if (!keychainData) {
|
|
2669
|
+
debugLog("No tokens found in keychain");
|
|
2670
|
+
return void 0;
|
|
2671
|
+
}
|
|
2672
|
+
debugLog("Loaded credentials from keychain");
|
|
2673
|
+
cachedLogin = {
|
|
2674
|
+
jwt: keychainData.login_jwt,
|
|
2675
|
+
refreshToken: keychainData.login_refresh_token,
|
|
2676
|
+
expiresAt,
|
|
2677
|
+
storage: "keychain"
|
|
2678
|
+
};
|
|
2679
|
+
return cachedLogin;
|
|
2680
|
+
}
|
|
2681
|
+
async function resolveOrRefreshToken(options = {}) {
|
|
2682
|
+
const { debug = false } = options;
|
|
2683
|
+
const debugLog = createDebugLog(debug);
|
|
2684
|
+
const stored = await resolveStoredLogin(debugLog);
|
|
2685
|
+
if (!stored) {
|
|
2686
|
+
return void 0;
|
|
2687
|
+
}
|
|
2688
|
+
const { jwt: storedJwt, refreshToken, expiresAt } = stored;
|
|
2689
|
+
if (expiresAt > Date.now() + TOKEN_REFRESH_BUFFER_MS) {
|
|
2690
|
+
debugLog("Using cached token (still valid)");
|
|
2691
|
+
return storedJwt;
|
|
2692
|
+
}
|
|
2693
|
+
debugLog("Token expired, refreshing...");
|
|
2694
|
+
if (pendingRefresh) {
|
|
2695
|
+
debugLog("Waiting for existing refresh to complete");
|
|
2696
|
+
return pendingRefresh;
|
|
2697
|
+
}
|
|
2698
|
+
pendingRefresh = refreshJwt(refreshToken, options).finally(() => {
|
|
2699
|
+
pendingRefresh = null;
|
|
2700
|
+
});
|
|
2701
|
+
return await pendingRefresh;
|
|
2702
|
+
}
|
|
2703
|
+
async function getToken(options = {}) {
|
|
2704
|
+
try {
|
|
2705
|
+
return await resolveOrRefreshToken(options);
|
|
2706
|
+
} catch (error) {
|
|
2707
|
+
const message = error instanceof Error ? error.message : "Token refresh failed";
|
|
2708
|
+
throw new ZapierAuthenticationError(
|
|
2709
|
+
`${message}
|
|
2710
|
+
Please run 'login' to authenticate again.`
|
|
2711
|
+
);
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
async function getLoggedInUser(options = {}) {
|
|
2715
|
+
const jwt2 = await getToken(options).catch(() => void 0);
|
|
2716
|
+
if (!jwt2) {
|
|
2717
|
+
throw new Error(
|
|
2718
|
+
"No valid authentication token available. Please login first."
|
|
2719
|
+
);
|
|
2720
|
+
}
|
|
2721
|
+
let decodedJwt = decodeJwtOrThrow(jwt2);
|
|
2722
|
+
if (decodedJwt.payload["sub_type"] == "service") {
|
|
2723
|
+
decodedJwt = decodeJwtOrThrow(decodedJwt.payload["njwt"]);
|
|
2724
|
+
}
|
|
2725
|
+
if (typeof decodedJwt.payload["zap:acc"] !== "string") {
|
|
2726
|
+
throw new Error("JWT payload does not contain accountId");
|
|
2727
|
+
}
|
|
2728
|
+
const accountId = parseInt(decodedJwt.payload["zap:acc"], 10);
|
|
2729
|
+
if (isNaN(accountId)) {
|
|
2730
|
+
throw new Error("JWT accountId is not a number");
|
|
2731
|
+
}
|
|
2732
|
+
if (decodedJwt.payload["sub_type"] !== "customuser" || typeof decodedJwt.payload["sub"] !== "string") {
|
|
2733
|
+
throw new Error("JWT payload does not contain customUserId");
|
|
2734
|
+
}
|
|
2735
|
+
const customUserId = parseInt(decodedJwt.payload["sub"], 10);
|
|
2736
|
+
if (isNaN(customUserId)) {
|
|
2737
|
+
throw new Error("JWT customUserId is not a number");
|
|
2738
|
+
}
|
|
2739
|
+
const email = decodedJwt.payload["zap:uname"];
|
|
2740
|
+
if (typeof email !== "string") {
|
|
2741
|
+
throw new Error("JWT payload does not contain email");
|
|
2742
|
+
}
|
|
2743
|
+
return {
|
|
2744
|
+
accountId,
|
|
2745
|
+
customUserId,
|
|
2746
|
+
email
|
|
2747
|
+
};
|
|
2748
|
+
}
|
|
2749
|
+
function getLoginStorageMode() {
|
|
2750
|
+
const cfg = getConfig();
|
|
2751
|
+
if (typeof cfg.get("login_jwt") === "string") {
|
|
2752
|
+
return "config";
|
|
2753
|
+
}
|
|
2754
|
+
const explicitMode = cfg.get("login_storage_mode");
|
|
2755
|
+
if (explicitMode === "keychain" || explicitMode === "config") {
|
|
2756
|
+
return explicitMode;
|
|
2757
|
+
}
|
|
2758
|
+
return "keychain";
|
|
2759
|
+
}
|
|
2760
|
+
async function logout(options = {}) {
|
|
2761
|
+
const { onEvent } = options;
|
|
2762
|
+
const mode = getLoginStorageMode();
|
|
2763
|
+
cachedLogin = void 0;
|
|
2764
|
+
await clearTokensFromKeychain();
|
|
2765
|
+
const cfg = getConfig();
|
|
2766
|
+
cfg.set("login_storage_mode", mode);
|
|
2767
|
+
cfg.delete("login_expires_at");
|
|
2768
|
+
cfg.delete("login_jwt");
|
|
2769
|
+
cfg.delete("login_refresh_token");
|
|
2770
|
+
onEvent?.({
|
|
2771
|
+
type: "auth_logout",
|
|
2772
|
+
payload: { message: "Logged out successfully", operation: "logout" },
|
|
2773
|
+
timestamp: Date.now()
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2776
|
+
function getConfigPath() {
|
|
2777
|
+
const cfg = getConfig();
|
|
2778
|
+
return cfg.path;
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
// src/utils/constants.ts
|
|
2200
2782
|
var LOGIN_PORTS = [49505, 50575, 52804, 55981, 61010, 63851];
|
|
2201
2783
|
var LOGIN_TIMEOUT_MS = 3e5;
|
|
2202
2784
|
var spinPromise = async (promise, text) => {
|
|
@@ -4650,10 +5232,10 @@ var initPlugin = () => {
|
|
|
4650
5232
|
// package.json with { type: 'json' }
|
|
4651
5233
|
var package_default2 = {
|
|
4652
5234
|
name: "@zapier/zapier-sdk-cli",
|
|
4653
|
-
version: "0.
|
|
5235
|
+
version: "0.43.0"};
|
|
4654
5236
|
|
|
4655
5237
|
// src/sdk.ts
|
|
4656
|
-
injectCliLogin(
|
|
5238
|
+
injectCliLogin(login_exports);
|
|
4657
5239
|
function createZapierCliSdk(options = {}) {
|
|
4658
5240
|
return createZapierSdk({
|
|
4659
5241
|
...options,
|