@secondlayer/cli 21.3.0 → 22.0.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/README.md +2 -2
- package/dist/cli.js +30 -35
- package/dist/cli.js.map +11 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,8 +15,8 @@ secondlayer --version
|
|
|
15
15
|
Default API is `http://127.0.0.1:3800`. Override with `SECONDLAYER_API_URL`.
|
|
16
16
|
|
|
17
17
|
Writes against a published bind use `INSTANCE_TOKEN` from `secondlayer init`.
|
|
18
|
-
Loopback reads need no token.
|
|
19
|
-
`SECONDLAYER_API_KEY` (`sk-sl_*`).
|
|
18
|
+
Loopback reads need no token. Your hosted account (credits, archive fetches)
|
|
19
|
+
uses `secondlayer login` or `SECONDLAYER_API_KEY` (`sk-sl_*`).
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
export SECONDLAYER_API_URL=http://127.0.0.1:3800
|
package/dist/cli.js
CHANGED
|
@@ -2369,12 +2369,12 @@ async function resolveArchiveOpsBearer() {
|
|
|
2369
2369
|
};
|
|
2370
2370
|
}
|
|
2371
2371
|
function ignoredEnvKeyNote(ignored) {
|
|
2372
|
-
return ignored ? " INSTANCE_TOKEN was ignored: it unlocks this instance, not
|
|
2372
|
+
return ignored ? " INSTANCE_TOKEN was ignored: it unlocks this instance, not your account." : "";
|
|
2373
2373
|
}
|
|
2374
2374
|
async function httpArchiveOps(path, opts = {}) {
|
|
2375
2375
|
const { bearer, ignoredEnvKey } = await resolveArchiveOpsBearer();
|
|
2376
2376
|
if (!bearer) {
|
|
2377
|
-
throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, `
|
|
2377
|
+
throw new CliHttpError(401, "SESSION_EXPIRED", { error: "Not logged in" }, `This needs your Secondlayer account. ${ARCHIVE_AUTH_HINT}${ignoredEnvKeyNote(ignoredEnvKey)}`);
|
|
2378
2378
|
}
|
|
2379
2379
|
try {
|
|
2380
2380
|
return await request(`${resolveArchiveOpsUrl()}${path}`, {
|
|
@@ -2383,12 +2383,12 @@ async function httpArchiveOps(path, opts = {}) {
|
|
|
2383
2383
|
});
|
|
2384
2384
|
} catch (err) {
|
|
2385
2385
|
if (err instanceof CliHttpError && err.status === 401) {
|
|
2386
|
-
throw new CliHttpError(401, err.code, err.body, `
|
|
2386
|
+
throw new CliHttpError(401, err.code, err.body, `Your account rejected the credential (${err.message}). ${ARCHIVE_AUTH_HINT}${ignoredEnvKeyNote(ignoredEnvKey)}`);
|
|
2387
2387
|
}
|
|
2388
2388
|
throw err;
|
|
2389
2389
|
}
|
|
2390
2390
|
}
|
|
2391
|
-
var CliHttpError, REQUEST_TIMEOUT_MS = 30000, ARCHIVE_AUTH_HINT = "Set SECONDLAYER_API_KEY to your account key (sk-sl_…, from /account/keys), or run `secondlayer login
|
|
2391
|
+
var CliHttpError, REQUEST_TIMEOUT_MS = 30000, ARCHIVE_AUTH_HINT = "Set SECONDLAYER_API_KEY to your account key (sk-sl_…, from /account/keys), or run `secondlayer login`.", ARCHIVE_CREDENTIAL_RE;
|
|
2392
2392
|
var init_http = __esm(() => {
|
|
2393
2393
|
init_api_url();
|
|
2394
2394
|
init_resolve_auth();
|
|
@@ -202692,7 +202692,7 @@ var {
|
|
|
202692
202692
|
// package.json
|
|
202693
202693
|
var package_default = {
|
|
202694
202694
|
name: "@secondlayer/cli",
|
|
202695
|
-
version: "
|
|
202695
|
+
version: "22.0.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",
|
|
@@ -202811,7 +202811,7 @@ var BUY_CREDITS_COMMAND = "secondlayer credits buy";
|
|
|
202811
202811
|
function formatInsufficientMessage(quote) {
|
|
202812
202812
|
const shortfallUsd = ((quote.usdMicros - quote.balanceUsdMicros) / 1e6).toFixed(2);
|
|
202813
202813
|
const balanceUsd = (quote.balanceUsdMicros / 1e6).toFixed(2);
|
|
202814
|
-
return `Insufficient
|
|
202814
|
+
return `Insufficient credits: quote $${quote.usd}, balance $${balanceUsd}, short $${shortfallUsd}. Buy more with \`${BUY_CREDITS_COMMAND}\`.`;
|
|
202815
202815
|
}
|
|
202816
202816
|
var ARCHIVE_GATE_NOT_CONFIGURED_MESSAGE = "the archive gate is not configured on the server; contact the operator";
|
|
202817
202817
|
var ALLOWANCE_MONTHLY_BUNDLES = 6;
|
|
@@ -204986,7 +204986,7 @@ async function runBuy(opts) {
|
|
|
204986
204986
|
human: () => {
|
|
204987
204987
|
success(`Checkout for $${amount} → ${email}`);
|
|
204988
204988
|
console.log(res.url);
|
|
204989
|
-
console.log(dim("After payment: set SECONDLAYER_API_KEY (or run `secondlayer login
|
|
204989
|
+
console.log(dim("After payment: set SECONDLAYER_API_KEY (or run `secondlayer login`), then run `secondlayer credits balance`"));
|
|
204990
204990
|
}
|
|
204991
204991
|
});
|
|
204992
204992
|
}
|
|
@@ -205061,8 +205061,8 @@ async function runUsage(opts) {
|
|
|
205061
205061
|
});
|
|
205062
205062
|
}
|
|
205063
205063
|
function registerCreditsCommand(program) {
|
|
205064
|
-
const credits = program.command("credits").description("Buy and check
|
|
205065
|
-
credits.command("buy").description("Open a one-time Stripe checkout for
|
|
205064
|
+
const credits = program.command("credits").description("Buy and check your credits");
|
|
205065
|
+
credits.command("buy").description("Open a one-time Stripe checkout for credits").requiredOption("--email <email>", "Receipt email; becomes the account").option("--pack <usd>", `One of ${PACKS.join(", ")}`, "25").option("--json", "Output as JSON").action((opts) => runBuy(opts));
|
|
205066
205066
|
credits.command("balance").description("Show prepaid archive credit balance").option("--json", "Output as JSON").action((opts) => runBalance(opts));
|
|
205067
205067
|
credits.command("usage").description("Rows delivered per day: free vs paid, by source").option("--days <n>", "Days to show (max 30)", "30").option("--json", "Output as JSON").action((opts) => runUsage(opts));
|
|
205068
205068
|
credits.command("refill").description("Opt-in auto-refill when the balance drops under a threshold").option("--below <usd>", "Trigger when balance is under this USD amount").option("--pack <usd>", `Pack to buy (${PACKS.join(", ")})`, "25").option("--off", "Turn auto-refill off").option("--json", "Output as JSON").action((opts) => runRefill(opts));
|
|
@@ -207836,16 +207836,16 @@ async function readStdin() {
|
|
|
207836
207836
|
chunks.push(chunk);
|
|
207837
207837
|
return Buffer.concat(chunks).toString("utf8").trim();
|
|
207838
207838
|
}
|
|
207839
|
-
function loginTarget(
|
|
207840
|
-
return
|
|
207839
|
+
function loginTarget() {
|
|
207840
|
+
return resolveArchiveOpsUrl();
|
|
207841
207841
|
}
|
|
207842
|
-
async function runTokenLogin(
|
|
207842
|
+
async function runTokenLogin() {
|
|
207843
207843
|
const token = await readStdin();
|
|
207844
207844
|
if (!token) {
|
|
207845
207845
|
error('No token on stdin. Usage: echo "$KEY" | secondlayer login --with-token');
|
|
207846
207846
|
process.exit(1);
|
|
207847
207847
|
}
|
|
207848
|
-
const target = loginTarget(
|
|
207848
|
+
const target = loginTarget();
|
|
207849
207849
|
let account;
|
|
207850
207850
|
try {
|
|
207851
207851
|
account = await httpAt(target, "/api/accounts/me", { bearer: token });
|
|
@@ -207895,7 +207895,11 @@ async function pollDeviceToken(start, deps) {
|
|
|
207895
207895
|
await deps.sleep(start.interval * 1000);
|
|
207896
207896
|
try {
|
|
207897
207897
|
const res = await deps.post("/api/cli/device/token", { deviceCode: start.deviceCode });
|
|
207898
|
-
return {
|
|
207898
|
+
return {
|
|
207899
|
+
kind: "approved",
|
|
207900
|
+
sessionToken: res.sessionToken,
|
|
207901
|
+
account: res.account
|
|
207902
|
+
};
|
|
207899
207903
|
} catch (err) {
|
|
207900
207904
|
if (err instanceof CliHttpError) {
|
|
207901
207905
|
if (err.status === 428) {
|
|
@@ -207905,9 +207909,6 @@ async function pollDeviceToken(start, deps) {
|
|
|
207905
207909
|
if (err.status === 403 && err.body.error === "access_denied") {
|
|
207906
207910
|
return { kind: "denied" };
|
|
207907
207911
|
}
|
|
207908
|
-
if (err.status === 409 && err.body.error === "key_limit") {
|
|
207909
|
-
return { kind: "key_limit" };
|
|
207910
|
-
}
|
|
207911
207912
|
if (err.status === 410)
|
|
207912
207913
|
return { kind: "expired" };
|
|
207913
207914
|
throw err;
|
|
@@ -207918,12 +207919,11 @@ async function pollDeviceToken(start, deps) {
|
|
|
207918
207919
|
}
|
|
207919
207920
|
return { kind: "expired" };
|
|
207920
207921
|
}
|
|
207921
|
-
var KEY_LIMIT_MESSAGE = "You have 50 keys. Revoke one under Keys, then run secondlayer login again.";
|
|
207922
207922
|
function clientName() {
|
|
207923
207923
|
return hostname().trim().slice(0, 64) || "this machine";
|
|
207924
207924
|
}
|
|
207925
207925
|
async function runDeviceLogin(options = {}) {
|
|
207926
|
-
const target = loginTarget(
|
|
207926
|
+
const target = loginTarget();
|
|
207927
207927
|
if (!await shouldContinueLogin(target, options))
|
|
207928
207928
|
return;
|
|
207929
207929
|
let start;
|
|
@@ -207961,25 +207961,21 @@ async function runDeviceLogin(options = {}) {
|
|
|
207961
207961
|
error("Cancelled in the browser.");
|
|
207962
207962
|
process.exit(1);
|
|
207963
207963
|
}
|
|
207964
|
-
if (outcome.kind === "key_limit") {
|
|
207965
|
-
error(KEY_LIMIT_MESSAGE);
|
|
207966
|
-
process.exit(1);
|
|
207967
|
-
}
|
|
207968
207964
|
if (outcome.kind === "expired") {
|
|
207969
207965
|
error("The code expired. Run secondlayer login again.");
|
|
207970
207966
|
process.exit(1);
|
|
207971
207967
|
}
|
|
207972
207968
|
await writeSession({
|
|
207973
|
-
token: outcome.
|
|
207969
|
+
token: outcome.sessionToken,
|
|
207974
207970
|
email: outcome.account.email,
|
|
207975
207971
|
accountId: outcome.account.id,
|
|
207976
207972
|
expiresAt: sessionExpiry()
|
|
207977
207973
|
}, target);
|
|
207978
207974
|
success(`Logged in as ${outcome.account.email} on ${clientName()}`);
|
|
207979
|
-
info(dim("
|
|
207975
|
+
info(dim("Run 'secondlayer logout' to sign this machine out."));
|
|
207980
207976
|
}
|
|
207981
207977
|
async function runLoginFlow(options = {}) {
|
|
207982
|
-
const target = loginTarget(
|
|
207978
|
+
const target = loginTarget();
|
|
207983
207979
|
if (!await shouldContinueLogin(target, options))
|
|
207984
207980
|
return;
|
|
207985
207981
|
const email = await input({
|
|
@@ -208019,7 +208015,7 @@ async function runLoginFlow(options = {}) {
|
|
|
208019
208015
|
expiresAt: sessionExpiry()
|
|
208020
208016
|
}, target);
|
|
208021
208017
|
success(`Logged in as ${verified.account.email}`);
|
|
208022
|
-
info(dim(
|
|
208018
|
+
info(dim("Run 'secondlayer whoami' to see your account status."));
|
|
208023
208019
|
} catch (err) {
|
|
208024
208020
|
if (err instanceof CliHttpError) {
|
|
208025
208021
|
error(err.message);
|
|
@@ -208030,19 +208026,18 @@ async function runLoginFlow(options = {}) {
|
|
|
208030
208026
|
}
|
|
208031
208027
|
}
|
|
208032
208028
|
function registerLoginCommand(program) {
|
|
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)").
|
|
208029
|
+
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)").addHelpText("after", `
|
|
208034
208030
|
Examples:
|
|
208035
208031
|
$ secondlayer login
|
|
208036
208032
|
$ secondlayer login --email
|
|
208037
|
-
$ secondlayer login --
|
|
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 }));
|
|
208033
|
+
$ echo "$SECONDLAYER_API_KEY" | secondlayer login --with-token`).action((opts) => opts.withToken ? runTokenLogin() : opts.email ? runLoginFlow({ force: opts.force }) : runDeviceLogin({ force: opts.force }));
|
|
208039
208034
|
}
|
|
208040
208035
|
// src/commands/logout.ts
|
|
208041
208036
|
init_http();
|
|
208042
208037
|
init_output();
|
|
208043
208038
|
init_session();
|
|
208044
|
-
async function runLogout(
|
|
208045
|
-
const target = loginTarget(
|
|
208039
|
+
async function runLogout() {
|
|
208040
|
+
const target = loginTarget();
|
|
208046
208041
|
const session = await readSession(target);
|
|
208047
208042
|
if (!session) {
|
|
208048
208043
|
info(`Not logged in (${target}).`);
|
|
@@ -208062,7 +208057,7 @@ async function runLogout(opts = {}) {
|
|
|
208062
208057
|
success(`Logged out (${target}).`);
|
|
208063
208058
|
}
|
|
208064
208059
|
function registerLogoutCommand(program) {
|
|
208065
|
-
program.command("logout").description("
|
|
208060
|
+
program.command("logout").description("Sign this machine out of your Secondlayer account").action(() => runLogout());
|
|
208066
208061
|
}
|
|
208067
208062
|
// src/commands/backup.ts
|
|
208068
208063
|
init_fs();
|
|
@@ -208476,7 +208471,7 @@ function renderInstanceEnv(env) {
|
|
|
208476
208471
|
`SECONDLAYER_API_URL=${env.SECONDLAYER_API_URL}`
|
|
208477
208472
|
];
|
|
208478
208473
|
if (env.SECONDLAYER_API_KEY) {
|
|
208479
|
-
lines.push("# Hosted account key for archive
|
|
208474
|
+
lines.push("# Hosted account key for credits and archive fetches (sk-sl_*).", `SECONDLAYER_API_KEY=${env.SECONDLAYER_API_KEY}`);
|
|
208480
208475
|
}
|
|
208481
208476
|
lines.push("# Archive trust root: bootstrap, verify, and repair check manifests", "# against this key. Replace it to pin a different archive.", `ARCHIVE_SIGNING_PUBLIC_KEY=${escapeEnvValue(env.ARCHIVE_SIGNING_PUBLIC_KEY)}`, "");
|
|
208482
208477
|
return lines.join(`
|
|
@@ -208664,5 +208659,5 @@ registerCreditsCommand(program);
|
|
|
208664
208659
|
registerArchiveCommand(program);
|
|
208665
208660
|
program.parse();
|
|
208666
208661
|
|
|
208667
|
-
//# debugId=
|
|
208662
|
+
//# debugId=32DC3B7BA2B6602D64756E2164756E21
|
|
208668
208663
|
//# sourceMappingURL=cli.js.map
|