@secondlayer/cli 21.2.0 → 21.3.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/dist/cli.js +148 -27
- package/dist/cli.js.map +5 -4
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -202692,7 +202692,7 @@ var {
|
|
|
202692
202692
|
// package.json
|
|
202693
202693
|
var package_default = {
|
|
202694
202694
|
name: "@secondlayer/cli",
|
|
202695
|
-
version: "21.
|
|
202695
|
+
version: "21.3.0",
|
|
202696
202696
|
description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
|
|
202697
202697
|
repository: {
|
|
202698
202698
|
type: "git",
|
|
@@ -202732,7 +202732,7 @@ var package_default = {
|
|
|
202732
202732
|
"@secondlayer/bundler": "^0.7.1",
|
|
202733
202733
|
"@secondlayer/scaffold": "^1.6.2",
|
|
202734
202734
|
"@secondlayer/sdk": "^15.1.0",
|
|
202735
|
-
"@secondlayer/shared": "^13.
|
|
202735
|
+
"@secondlayer/shared": "^13.7.0",
|
|
202736
202736
|
"@secondlayer/stacks": "^6.4.0",
|
|
202737
202737
|
"@secondlayer/subgraphs": "^7.2.0",
|
|
202738
202738
|
"@secondlayer/verify": "^0.6.0",
|
|
@@ -207801,9 +207801,32 @@ function registerWhoamiCommand(program) {
|
|
|
207801
207801
|
// src/commands/login.ts
|
|
207802
207802
|
init_api_url();
|
|
207803
207803
|
init_http();
|
|
207804
|
+
import { hostname } from "node:os";
|
|
207805
|
+
import { createInterface } from "node:readline";
|
|
207806
|
+
import { confirm as confirm3, input } from "@inquirer/prompts";
|
|
207807
|
+
|
|
207808
|
+
// src/lib/open-browser.ts
|
|
207809
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
207810
|
+
function browserCommand(url, platform = process.platform) {
|
|
207811
|
+
if (platform === "darwin")
|
|
207812
|
+
return { cmd: "open", args: [url] };
|
|
207813
|
+
if (platform === "win32") {
|
|
207814
|
+
return { cmd: "cmd", args: ["/c", "start", "", url] };
|
|
207815
|
+
}
|
|
207816
|
+
return { cmd: "xdg-open", args: [url] };
|
|
207817
|
+
}
|
|
207818
|
+
function openBrowser(url) {
|
|
207819
|
+
try {
|
|
207820
|
+
const { cmd, args } = browserCommand(url);
|
|
207821
|
+
const child = spawn3(cmd, args, { detached: true, stdio: "ignore" });
|
|
207822
|
+
child.on("error", () => {});
|
|
207823
|
+
child.unref();
|
|
207824
|
+
} catch {}
|
|
207825
|
+
}
|
|
207826
|
+
|
|
207827
|
+
// src/commands/login.ts
|
|
207804
207828
|
init_output();
|
|
207805
207829
|
init_session();
|
|
207806
|
-
import { confirm as confirm3, input } from "@inquirer/prompts";
|
|
207807
207830
|
function sessionExpiry() {
|
|
207808
207831
|
return new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString();
|
|
207809
207832
|
}
|
|
@@ -207838,31 +207861,127 @@ async function runTokenLogin(opts) {
|
|
|
207838
207861
|
}, target);
|
|
207839
207862
|
success(`Logged in as ${account.email} (${target})`);
|
|
207840
207863
|
}
|
|
207841
|
-
async function
|
|
207842
|
-
|
|
207843
|
-
|
|
207844
|
-
|
|
207845
|
-
|
|
207846
|
-
|
|
207847
|
-
|
|
207848
|
-
|
|
207849
|
-
|
|
207850
|
-
|
|
207851
|
-
|
|
207852
|
-
|
|
207853
|
-
|
|
207854
|
-
|
|
207855
|
-
|
|
207856
|
-
|
|
207857
|
-
|
|
207858
|
-
|
|
207864
|
+
async function shouldContinueLogin(target, options) {
|
|
207865
|
+
if (options.force)
|
|
207866
|
+
return true;
|
|
207867
|
+
const existing = await readSession(target);
|
|
207868
|
+
if (!existing)
|
|
207869
|
+
return true;
|
|
207870
|
+
info(`Already logged in as ${existing.email} (${target}).`);
|
|
207871
|
+
const hint = "Run 'secondlayer logout' first, or re-run with --force to switch accounts.";
|
|
207872
|
+
if (!process.stdin.isTTY) {
|
|
207873
|
+
info(dim(hint));
|
|
207874
|
+
return false;
|
|
207875
|
+
}
|
|
207876
|
+
try {
|
|
207877
|
+
const proceed = await confirm3({
|
|
207878
|
+
message: "Log in as a different user?",
|
|
207879
|
+
default: false
|
|
207880
|
+
});
|
|
207881
|
+
if (!proceed) {
|
|
207882
|
+
info(dim("Run 'secondlayer logout' to sign out."));
|
|
207883
|
+
return false;
|
|
207884
|
+
}
|
|
207885
|
+
} catch {
|
|
207886
|
+
info(dim(hint));
|
|
207887
|
+
return false;
|
|
207888
|
+
}
|
|
207889
|
+
return true;
|
|
207890
|
+
}
|
|
207891
|
+
async function pollDeviceToken(start, deps) {
|
|
207892
|
+
const deadline = deps.now() + start.expiresIn * 1000;
|
|
207893
|
+
let failures = 0;
|
|
207894
|
+
while (deps.now() < deadline) {
|
|
207895
|
+
await deps.sleep(start.interval * 1000);
|
|
207896
|
+
try {
|
|
207897
|
+
const res = await deps.post("/api/cli/device/token", { deviceCode: start.deviceCode });
|
|
207898
|
+
return { kind: "approved", key: res.key, account: res.account };
|
|
207899
|
+
} catch (err) {
|
|
207900
|
+
if (err instanceof CliHttpError) {
|
|
207901
|
+
if (err.status === 428) {
|
|
207902
|
+
failures = 0;
|
|
207903
|
+
continue;
|
|
207859
207904
|
}
|
|
207860
|
-
|
|
207861
|
-
|
|
207862
|
-
|
|
207905
|
+
if (err.status === 403 && err.body.error === "access_denied") {
|
|
207906
|
+
return { kind: "denied" };
|
|
207907
|
+
}
|
|
207908
|
+
if (err.status === 409 && err.body.error === "key_limit") {
|
|
207909
|
+
return { kind: "key_limit" };
|
|
207910
|
+
}
|
|
207911
|
+
if (err.status === 410)
|
|
207912
|
+
return { kind: "expired" };
|
|
207913
|
+
throw err;
|
|
207863
207914
|
}
|
|
207915
|
+
if (++failures >= 3)
|
|
207916
|
+
throw err;
|
|
207864
207917
|
}
|
|
207865
207918
|
}
|
|
207919
|
+
return { kind: "expired" };
|
|
207920
|
+
}
|
|
207921
|
+
var KEY_LIMIT_MESSAGE = "You have 50 keys. Revoke one under Keys, then run secondlayer login again.";
|
|
207922
|
+
function clientName() {
|
|
207923
|
+
return hostname().trim().slice(0, 64) || "this machine";
|
|
207924
|
+
}
|
|
207925
|
+
async function runDeviceLogin(options = {}) {
|
|
207926
|
+
const target = loginTarget(options);
|
|
207927
|
+
if (!await shouldContinueLogin(target, options))
|
|
207928
|
+
return;
|
|
207929
|
+
let start;
|
|
207930
|
+
try {
|
|
207931
|
+
start = await httpAt(target, "/api/cli/device", {
|
|
207932
|
+
method: "POST",
|
|
207933
|
+
body: { clientName: clientName() }
|
|
207934
|
+
});
|
|
207935
|
+
} catch (err) {
|
|
207936
|
+
error(err instanceof Error ? err.message : String(err));
|
|
207937
|
+
process.exit(1);
|
|
207938
|
+
}
|
|
207939
|
+
info(`First copy your one-time code: ${start.userCode}`);
|
|
207940
|
+
const readline = process.stdin.isTTY ? createInterface({ input: process.stdin }) : null;
|
|
207941
|
+
if (readline) {
|
|
207942
|
+
info("Press Enter to open secondlayer.tools in your browser...");
|
|
207943
|
+
readline.once("line", () => openBrowser(start.verificationUrl));
|
|
207944
|
+
}
|
|
207945
|
+
info(dim(`Or open ${start.verificationUrl}`));
|
|
207946
|
+
info(dim("Waiting for you to approve in the browser..."));
|
|
207947
|
+
let outcome;
|
|
207948
|
+
try {
|
|
207949
|
+
outcome = await pollDeviceToken(start, {
|
|
207950
|
+
post: (path, body) => httpAt(target, path, { method: "POST", body }),
|
|
207951
|
+
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
207952
|
+
now: Date.now
|
|
207953
|
+
});
|
|
207954
|
+
} catch (err) {
|
|
207955
|
+
readline?.close();
|
|
207956
|
+
error(err instanceof Error ? err.message : String(err));
|
|
207957
|
+
process.exit(1);
|
|
207958
|
+
}
|
|
207959
|
+
readline?.close();
|
|
207960
|
+
if (outcome.kind === "denied") {
|
|
207961
|
+
error("Cancelled in the browser.");
|
|
207962
|
+
process.exit(1);
|
|
207963
|
+
}
|
|
207964
|
+
if (outcome.kind === "key_limit") {
|
|
207965
|
+
error(KEY_LIMIT_MESSAGE);
|
|
207966
|
+
process.exit(1);
|
|
207967
|
+
}
|
|
207968
|
+
if (outcome.kind === "expired") {
|
|
207969
|
+
error("The code expired. Run secondlayer login again.");
|
|
207970
|
+
process.exit(1);
|
|
207971
|
+
}
|
|
207972
|
+
await writeSession({
|
|
207973
|
+
token: outcome.key,
|
|
207974
|
+
email: outcome.account.email,
|
|
207975
|
+
accountId: outcome.account.id,
|
|
207976
|
+
expiresAt: sessionExpiry()
|
|
207977
|
+
}, target);
|
|
207978
|
+
success(`Logged in as ${outcome.account.email} on ${clientName()}`);
|
|
207979
|
+
info(dim("This machine has its own key. Revoke it under Keys."));
|
|
207980
|
+
}
|
|
207981
|
+
async function runLoginFlow(options = {}) {
|
|
207982
|
+
const target = loginTarget(options);
|
|
207983
|
+
if (!await shouldContinueLogin(target, options))
|
|
207984
|
+
return;
|
|
207866
207985
|
const email = await input({
|
|
207867
207986
|
message: "Email",
|
|
207868
207987
|
validate: (v) => /^.+@.+\..+$/.test(v) ? true : "Invalid email"
|
|
@@ -207911,10 +208030,12 @@ async function runLoginFlow(options = {}) {
|
|
|
207911
208030
|
}
|
|
207912
208031
|
}
|
|
207913
208032
|
function registerLoginCommand(program) {
|
|
207914
|
-
program.command("login").description("Log in to Secondlayer
|
|
208033
|
+
program.command("login").description("Log in to Secondlayer through your browser").option("--force", "Skip the already-logged-in check and re-run the flow").option("--email", "Sign in with an emailed 6-digit code instead of a browser").option("--with-token", "Read an API key from stdin (non-interactive)").option("--credits", "Log in to the archive credits account used by bootstrap, repair, and credits").addHelpText("after", `
|
|
207915
208034
|
Examples:
|
|
208035
|
+
$ secondlayer login
|
|
208036
|
+
$ secondlayer login --email
|
|
207916
208037
|
$ secondlayer login --credits
|
|
207917
|
-
$ echo "$SECONDLAYER_API_KEY" | secondlayer login --with-token`).action((opts) => opts.withToken ? runTokenLogin({ credits: opts.credits }) : runLoginFlow({ force: opts.force, credits: opts.credits }));
|
|
208038
|
+
$ echo "$SECONDLAYER_API_KEY" | secondlayer login --with-token`).action((opts) => opts.withToken ? runTokenLogin({ credits: opts.credits }) : opts.email ? runLoginFlow({ force: opts.force, credits: opts.credits }) : runDeviceLogin({ force: opts.force, credits: opts.credits }));
|
|
207918
208039
|
}
|
|
207919
208040
|
// src/commands/logout.ts
|
|
207920
208041
|
init_http();
|
|
@@ -208543,5 +208664,5 @@ registerCreditsCommand(program);
|
|
|
208543
208664
|
registerArchiveCommand(program);
|
|
208544
208665
|
program.parse();
|
|
208545
208666
|
|
|
208546
|
-
//# debugId=
|
|
208667
|
+
//# debugId=9552E9D4123BD8E564756E2164756E21
|
|
208547
208668
|
//# sourceMappingURL=cli.js.map
|