@leeguoo/wrangler-accounts 1.1.1 → 1.2.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/bin/wrangler-accounts.js
CHANGED
|
@@ -236,6 +236,8 @@ function parseArgs(argv) {
|
|
|
236
236
|
opts.backup = false;
|
|
237
237
|
} else if (arg === "--unset") {
|
|
238
238
|
opts.unset = true;
|
|
239
|
+
} else if (arg === "--deep" || arg === "--verify") {
|
|
240
|
+
opts.deep = true;
|
|
239
241
|
} else if (arg === "--config" || arg === "-c") {
|
|
240
242
|
opts.config = argv[i + 1];
|
|
241
243
|
if (!opts.config) die("Missing value for --config");
|
|
@@ -451,9 +453,59 @@ function main() {
|
|
|
451
453
|
status,
|
|
452
454
|
expirationTime: session.expirationTime,
|
|
453
455
|
identity,
|
|
456
|
+
verified: null,
|
|
457
|
+
verifyError: null,
|
|
454
458
|
};
|
|
455
459
|
});
|
|
456
460
|
|
|
461
|
+
// --deep: actually run `wrangler whoami` inside a shadow HOME for
|
|
462
|
+
// each profile. This is the only authoritative check — the fast
|
|
463
|
+
// status column above is derived purely from the saved
|
|
464
|
+
// expiration_time, which does not tell us whether the refresh token
|
|
465
|
+
// still works or whether Cloudflare has revoked the session.
|
|
466
|
+
if (opts.deep) {
|
|
467
|
+
if (entries.length > 0 && !opts.json) {
|
|
468
|
+
process.stderr.write(
|
|
469
|
+
`[wrangler-accounts] running deep check (wrangler whoami) for ${entries.length} profile(s)...\n`,
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
const cloudflaredPath = findCloudflared();
|
|
473
|
+
for (const e of entries) {
|
|
474
|
+
const profileCfg = path.join(profilesDir, e.name, "config.toml");
|
|
475
|
+
try {
|
|
476
|
+
const r = runIsolated({
|
|
477
|
+
profile: e.name,
|
|
478
|
+
profileCfg,
|
|
479
|
+
realHome: os.homedir(),
|
|
480
|
+
command: "wrangler",
|
|
481
|
+
args: ["whoami"],
|
|
482
|
+
baseEnv: process.env,
|
|
483
|
+
captureStdout: true,
|
|
484
|
+
cloudflaredPath,
|
|
485
|
+
});
|
|
486
|
+
const output = `${r.stdout || ""}\n${r.stderr || ""}`;
|
|
487
|
+
if (r.exitCode === 0) {
|
|
488
|
+
const live = parseWranglerWhoamiOutput(output);
|
|
489
|
+
if (live) {
|
|
490
|
+
e.verified = true;
|
|
491
|
+
e.liveIdentity = live;
|
|
492
|
+
} else {
|
|
493
|
+
e.verified = false;
|
|
494
|
+
e.verifyError = "could not parse wrangler whoami output";
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
e.verified = false;
|
|
498
|
+
e.verifyError = /not logged in/i.test(output)
|
|
499
|
+
? "not logged in (refresh token may be revoked)"
|
|
500
|
+
: `wrangler whoami exit ${r.exitCode}`;
|
|
501
|
+
}
|
|
502
|
+
} catch (err) {
|
|
503
|
+
e.verified = false;
|
|
504
|
+
e.verifyError = err.message;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
457
509
|
if (opts.plain) {
|
|
458
510
|
// --plain keeps the v1.0 contract: one name per line, scriptable.
|
|
459
511
|
if (entries.length) console.log(entries.map((e) => e.name).join("\n"));
|
|
@@ -479,22 +531,51 @@ function main() {
|
|
|
479
531
|
: e.status === "valid" ? "valid"
|
|
480
532
|
: "unknown",
|
|
481
533
|
expires: formatExpiry(e.expirationTime),
|
|
534
|
+
verified:
|
|
535
|
+
e.verified === true ? "✓ ok"
|
|
536
|
+
: e.verified === false ? `✗ ${e.verifyError || "failed"}`
|
|
537
|
+
: "—",
|
|
482
538
|
identity: e.identity ? describeIdentity(e.identity) : "(no identity)",
|
|
483
539
|
}));
|
|
484
540
|
const nameW = Math.max(4, ...rows.map((r) => r.name.length));
|
|
485
541
|
const statusW = Math.max(6, ...rows.map((r) => r.status.length));
|
|
486
542
|
const expiresW = Math.max(7, ...rows.map((r) => r.expires.length));
|
|
487
|
-
const
|
|
543
|
+
const verifiedW = Math.max(8, ...rows.map((r) => r.verified.length));
|
|
544
|
+
|
|
545
|
+
let header;
|
|
546
|
+
if (opts.deep) {
|
|
547
|
+
header = ` ${"NAME".padEnd(nameW)} ${"STATUS".padEnd(statusW)} ${"EXPIRES".padEnd(expiresW)} ${"VERIFIED".padEnd(verifiedW)} IDENTITY`;
|
|
548
|
+
} else {
|
|
549
|
+
header = ` ${"NAME".padEnd(nameW)} ${"STATUS".padEnd(statusW)} ${"EXPIRES".padEnd(expiresW)} IDENTITY`;
|
|
550
|
+
}
|
|
488
551
|
console.log(header);
|
|
489
552
|
for (const r of rows) {
|
|
553
|
+
if (opts.deep) {
|
|
554
|
+
console.log(
|
|
555
|
+
`${r.marker} ${r.name.padEnd(nameW)} ${r.status.padEnd(statusW)} ${r.expires.padEnd(expiresW)} ${r.verified.padEnd(verifiedW)} ${r.identity}`,
|
|
556
|
+
);
|
|
557
|
+
} else {
|
|
558
|
+
console.log(
|
|
559
|
+
`${r.marker} ${r.name.padEnd(nameW)} ${r.status.padEnd(statusW)} ${r.expires.padEnd(expiresW)} ${r.identity}`,
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
console.log();
|
|
564
|
+
if (opts.deep) {
|
|
565
|
+
console.log(
|
|
566
|
+
"Legend: * = default profile, VERIFIED ✓ = wrangler whoami succeeded in shadow HOME, ✗ = authoritative failure",
|
|
567
|
+
);
|
|
568
|
+
} else {
|
|
490
569
|
console.log(
|
|
491
|
-
|
|
570
|
+
"Legend: * = default profile, EXPIRED = access token past expiration_time (wrangler may still auto-refresh)",
|
|
571
|
+
);
|
|
572
|
+
console.log(
|
|
573
|
+
" STATUS is derived from the saved file only. For a live check that runs 'wrangler whoami' against Cloudflare,",
|
|
574
|
+
);
|
|
575
|
+
console.log(
|
|
576
|
+
" pass --deep (slower, makes network calls).",
|
|
492
577
|
);
|
|
493
578
|
}
|
|
494
|
-
console.log();
|
|
495
|
-
console.log(
|
|
496
|
-
`Legend: * = default profile, EXPIRED = OAuth session needs 'wrangler-accounts login <name>'`,
|
|
497
|
-
);
|
|
498
579
|
return;
|
|
499
580
|
}
|
|
500
581
|
|
package/lib/isolation.js
CHANGED
|
@@ -150,8 +150,13 @@ function runIsolated({
|
|
|
150
150
|
|
|
151
151
|
let result;
|
|
152
152
|
try {
|
|
153
|
+
// captureStdout mode is used for non-interactive checks (e.g.
|
|
154
|
+
// background `wrangler whoami` during `list --deep`), so we close
|
|
155
|
+
// stdin on the child rather than letting it read from the user's
|
|
156
|
+
// terminal. Normal inherit mode keeps stdin attached for interactive
|
|
157
|
+
// flows like `login` and `exec`.
|
|
153
158
|
result = spawnSync(command, args, {
|
|
154
|
-
stdio: captureStdout ? ['
|
|
159
|
+
stdio: captureStdout ? ['ignore', 'pipe', 'pipe'] : 'inherit',
|
|
155
160
|
env,
|
|
156
161
|
encoding: 'utf8',
|
|
157
162
|
});
|
package/package.json
CHANGED
|
@@ -76,10 +76,15 @@ Use `--json` for structured output.
|
|
|
76
76
|
|
|
77
77
|
### List and inspect profiles
|
|
78
78
|
|
|
79
|
-
- `wrangler-accounts list` /
|
|
79
|
+
- `wrangler-accounts list` — text table with NAME / STATUS / EXPIRES / IDENTITY columns
|
|
80
|
+
- `wrangler-accounts list --json` — structured: array of `{name, isDefault, isActive, status, expirationTime, identity}`
|
|
81
|
+
- `wrangler-accounts list --plain` — one profile name per line (scriptable)
|
|
82
|
+
- `wrangler-accounts list --deep` — **authoritative** check: spawns `wrangler whoami` in a shadow HOME for every profile and reports whether Cloudflare actually accepts the credentials. Slower (makes network calls), but the only way to catch revoked refresh tokens or broken profile files.
|
|
80
83
|
- `wrangler-accounts status` / `status --json`
|
|
81
84
|
- Pass `--include-backups` to show hidden backup profiles.
|
|
82
85
|
|
|
86
|
+
**Accuracy note:** the `STATUS` column without `--deep` is derived purely from the saved `expiration_time` and tells you *when the access token will expire*, not whether the profile is actually usable. Wrangler auto-refreshes access tokens via the refresh token, so an `EXPIRED` access token is often fine in practice. When the user needs a real verdict, suggest `wrangler-accounts list --deep`.
|
|
87
|
+
|
|
83
88
|
### Save, sync, login, remove
|
|
84
89
|
|
|
85
90
|
- `wrangler-accounts save <name>` — snapshot current Wrangler config as a profile
|