@secondlayer/cli 14.1.2 → 14.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/README.md +3 -2
- package/dist/cli.js +320 -280
- package/dist/cli.js.map +24 -25
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -2483,11 +2483,24 @@ var require_commander = __commonJS((exports) => {
|
|
|
2483
2483
|
|
|
2484
2484
|
// src/lib/api-url.ts
|
|
2485
2485
|
function resolveApiUrl() {
|
|
2486
|
-
return (process.env.SL_API_URL ?? process.env.SL_PLATFORM_API_URL ?? LOCAL_API_URL).replace(/\/+$/, "");
|
|
2486
|
+
return (process.env.SECONDLAYER_API_URL ?? process.env.SL_API_URL ?? process.env.SL_PLATFORM_API_URL ?? LOCAL_API_URL).replace(/\/+$/, "");
|
|
2487
2487
|
}
|
|
2488
2488
|
function resolveArchiveOpsUrl() {
|
|
2489
2489
|
return (process.env.SL_CREDITS_API_URL ?? ARCHIVE_OPS_API_URL).replace(/\/+$/, "");
|
|
2490
2490
|
}
|
|
2491
|
+
function isMerchantUrl(url = resolveApiUrl()) {
|
|
2492
|
+
try {
|
|
2493
|
+
return new URL(url).hostname === "api.secondlayer.tools";
|
|
2494
|
+
} catch {
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
function assertInstanceUrl(url = resolveApiUrl()) {
|
|
2499
|
+
if (!isMerchantUrl(url))
|
|
2500
|
+
return;
|
|
2501
|
+
throw new Error(`this command runs on your instance, not api.secondlayer.tools.
|
|
2502
|
+
unset SECONDLAYER_API_URL, or pass --api-url http://127.0.0.1:3800`);
|
|
2503
|
+
}
|
|
2491
2504
|
var LOCAL_API_URL = "http://127.0.0.1:3800", ARCHIVE_OPS_API_URL = "https://api.secondlayer.tools";
|
|
2492
2505
|
|
|
2493
2506
|
// src/lib/session.ts
|
|
@@ -2578,10 +2591,18 @@ var init_session = __esm(() => {
|
|
|
2578
2591
|
});
|
|
2579
2592
|
|
|
2580
2593
|
// src/lib/resolve-auth.ts
|
|
2581
|
-
import { resolveApiKey } from "@secondlayer/sdk";
|
|
2594
|
+
import { resolveAccountKey, resolveApiKey } from "@secondlayer/sdk";
|
|
2582
2595
|
function resolveEnvKey() {
|
|
2583
2596
|
return resolveApiKey();
|
|
2584
2597
|
}
|
|
2598
|
+
function applyApiKeyFlag(apiKey) {
|
|
2599
|
+
if (/^s[ks]-sl_/.test(apiKey)) {
|
|
2600
|
+
process.env.SECONDLAYER_API_KEY = apiKey;
|
|
2601
|
+
process.env.SL_API_KEY = apiKey;
|
|
2602
|
+
} else {
|
|
2603
|
+
process.env.INSTANCE_TOKEN = apiKey;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2585
2606
|
async function resolveAuth() {
|
|
2586
2607
|
const apiUrl = resolveApiUrl();
|
|
2587
2608
|
const envKey = resolveEnvKey();
|
|
@@ -2600,17 +2621,19 @@ async function resolveAuth() {
|
|
|
2600
2621
|
return { apiUrl, ephemeralKey: session.token, fromEnv: false };
|
|
2601
2622
|
}
|
|
2602
2623
|
function isOssMode() {
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2624
|
+
return !isMerchantUrl();
|
|
2625
|
+
}
|
|
2626
|
+
function resolveDataPlaneKey() {
|
|
2627
|
+
if (isMerchantUrl())
|
|
2628
|
+
return resolveAccountKey();
|
|
2629
|
+
return resolveApiKey();
|
|
2608
2630
|
}
|
|
2609
2631
|
var init_resolve_auth = __esm(() => {
|
|
2610
2632
|
init_session();
|
|
2611
2633
|
});
|
|
2612
2634
|
|
|
2613
2635
|
// src/lib/http.ts
|
|
2636
|
+
import { resolveAccountKey as resolveAccountKey2, resolveApiKey as resolveApiKey2 } from "@secondlayer/sdk";
|
|
2614
2637
|
async function request(url, opts) {
|
|
2615
2638
|
const headers = {
|
|
2616
2639
|
"content-type": "application/json",
|
|
@@ -2649,7 +2672,7 @@ async function httpArchiveOpsAnon(path2, opts = {}) {
|
|
|
2649
2672
|
return httpAt(resolveArchiveOpsUrl(), path2, opts);
|
|
2650
2673
|
}
|
|
2651
2674
|
async function resolveArchiveOpsBearer() {
|
|
2652
|
-
const envKey =
|
|
2675
|
+
const envKey = resolveAccountKey2();
|
|
2653
2676
|
const session = await readSession(resolveArchiveOpsUrl());
|
|
2654
2677
|
if (session) {
|
|
2655
2678
|
return {
|
|
@@ -2664,7 +2687,7 @@ async function resolveArchiveOpsBearer() {
|
|
|
2664
2687
|
return {
|
|
2665
2688
|
bearer: undefined,
|
|
2666
2689
|
source: null,
|
|
2667
|
-
ignoredEnvKey:
|
|
2690
|
+
ignoredEnvKey: resolveApiKey2() !== undefined && envKey === undefined
|
|
2668
2691
|
};
|
|
2669
2692
|
}
|
|
2670
2693
|
function ignoredEnvKeyNote(ignored) {
|
|
@@ -16318,7 +16341,7 @@ class StacksApiClient {
|
|
|
16318
16341
|
const statusCode = typeof error2 === "object" && error2 !== null && "response" in error2 && typeof error2.response === "object" && error2.response !== null && "statusCode" in error2.response ? error2.response.statusCode : undefined;
|
|
16319
16342
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
16320
16343
|
if (statusCode === 401) {
|
|
16321
|
-
throw new Error(isOssMode() ? "Authentication required. Set INSTANCE_TOKEN from `secondlayer init
|
|
16344
|
+
throw new Error(isOssMode() ? "Authentication required. Set INSTANCE_TOKEN from `secondlayer init`." : "Authentication required. Run: secondlayer login");
|
|
16322
16345
|
}
|
|
16323
16346
|
if (statusCode === 404) {
|
|
16324
16347
|
throw new Error(`${resourceType} not found: ${resourceId}`);
|
|
@@ -28610,7 +28633,7 @@ function handleApiError(err, action2) {
|
|
|
28610
28633
|
const status = err instanceof ApiError || err instanceof CliHttpError ? err.status : undefined;
|
|
28611
28634
|
if (err instanceof CliHttpError && err.code === "SESSION_EXPIRED" || status === 401) {
|
|
28612
28635
|
printError("Authentication required.", {
|
|
28613
|
-
hint: isOssMode() ? "Set INSTANCE_TOKEN from `secondlayer init
|
|
28636
|
+
hint: isOssMode() ? "Set INSTANCE_TOKEN from `secondlayer init`." : "Run `secondlayer login` to re-authenticate."
|
|
28614
28637
|
});
|
|
28615
28638
|
process.exit(1);
|
|
28616
28639
|
}
|
|
@@ -29097,143 +29120,6 @@ function inspectSourceGitState(absPath) {
|
|
|
29097
29120
|
}
|
|
29098
29121
|
var init_git_status = () => {};
|
|
29099
29122
|
|
|
29100
|
-
// src/commands/login.ts
|
|
29101
|
-
import { confirm as confirm2, input } from "@inquirer/prompts";
|
|
29102
|
-
function sessionExpiry() {
|
|
29103
|
-
return new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString();
|
|
29104
|
-
}
|
|
29105
|
-
async function readStdin() {
|
|
29106
|
-
const chunks = [];
|
|
29107
|
-
for await (const chunk of process.stdin)
|
|
29108
|
-
chunks.push(chunk);
|
|
29109
|
-
return Buffer.concat(chunks).toString("utf8").trim();
|
|
29110
|
-
}
|
|
29111
|
-
function loginTarget(opts) {
|
|
29112
|
-
return opts.credits ? resolveArchiveOpsUrl() : resolveApiUrl();
|
|
29113
|
-
}
|
|
29114
|
-
async function runTokenLogin(opts) {
|
|
29115
|
-
const token = await readStdin();
|
|
29116
|
-
if (!token) {
|
|
29117
|
-
error('No token on stdin. Usage: echo "$KEY" | secondlayer login --with-token');
|
|
29118
|
-
process.exit(1);
|
|
29119
|
-
}
|
|
29120
|
-
const target = loginTarget(opts);
|
|
29121
|
-
let account;
|
|
29122
|
-
try {
|
|
29123
|
-
account = await httpAt(target, "/api/accounts/me", { bearer: token });
|
|
29124
|
-
} catch (err) {
|
|
29125
|
-
error(err instanceof CliHttpError ? `Token rejected by ${target}: ${err.message}` : err instanceof Error ? err.message : String(err));
|
|
29126
|
-
process.exit(1);
|
|
29127
|
-
}
|
|
29128
|
-
await writeSession({
|
|
29129
|
-
token,
|
|
29130
|
-
email: account.email,
|
|
29131
|
-
accountId: account.id,
|
|
29132
|
-
expiresAt: sessionExpiry()
|
|
29133
|
-
}, target);
|
|
29134
|
-
success(`Logged in as ${account.email} (${target})`);
|
|
29135
|
-
}
|
|
29136
|
-
async function runLoginFlow(options3 = {}) {
|
|
29137
|
-
const target = loginTarget(options3);
|
|
29138
|
-
if (!options3.force) {
|
|
29139
|
-
const existing = await readSession(target);
|
|
29140
|
-
if (existing) {
|
|
29141
|
-
info(`Already logged in as ${existing.email} (${target}).`);
|
|
29142
|
-
if (!process.stdin.isTTY) {
|
|
29143
|
-
info(dim("Run 'secondlayer logout' first, or re-run with --force to switch accounts."));
|
|
29144
|
-
return;
|
|
29145
|
-
}
|
|
29146
|
-
try {
|
|
29147
|
-
const proceed = await confirm2({
|
|
29148
|
-
message: "Log in as a different user?",
|
|
29149
|
-
default: false
|
|
29150
|
-
});
|
|
29151
|
-
if (!proceed) {
|
|
29152
|
-
info(dim("Run 'secondlayer logout' to sign out."));
|
|
29153
|
-
return;
|
|
29154
|
-
}
|
|
29155
|
-
} catch {
|
|
29156
|
-
info(dim("Run 'secondlayer logout' first, or re-run with --force to switch accounts."));
|
|
29157
|
-
return;
|
|
29158
|
-
}
|
|
29159
|
-
}
|
|
29160
|
-
}
|
|
29161
|
-
const email = await input({
|
|
29162
|
-
message: "Email",
|
|
29163
|
-
validate: (v2) => /^.+@.+\..+$/.test(v2) ? true : "Invalid email"
|
|
29164
|
-
});
|
|
29165
|
-
try {
|
|
29166
|
-
const res = await httpAt(target, "/api/auth/magic-link", {
|
|
29167
|
-
method: "POST",
|
|
29168
|
-
body: { email }
|
|
29169
|
-
});
|
|
29170
|
-
info("Check your inbox for a 6-digit code.");
|
|
29171
|
-
if (res.code) {
|
|
29172
|
-
info(dim(`(DEV_MODE code: ${res.code})`));
|
|
29173
|
-
}
|
|
29174
|
-
} catch (err) {
|
|
29175
|
-
if (err instanceof CliHttpError) {
|
|
29176
|
-
error(err.message);
|
|
29177
|
-
} else {
|
|
29178
|
-
error(err instanceof Error ? err.message : String(err));
|
|
29179
|
-
}
|
|
29180
|
-
process.exit(1);
|
|
29181
|
-
}
|
|
29182
|
-
const code = await input({
|
|
29183
|
-
message: "Enter the 6-digit code",
|
|
29184
|
-
validate: (v2) => /^\d{6}$/.test(v2) ? true : "Expected 6 digits"
|
|
29185
|
-
});
|
|
29186
|
-
try {
|
|
29187
|
-
const verified = await httpAt(target, "/api/auth/verify", {
|
|
29188
|
-
method: "POST",
|
|
29189
|
-
body: { email, code }
|
|
29190
|
-
});
|
|
29191
|
-
await writeSession({
|
|
29192
|
-
token: verified.sessionToken,
|
|
29193
|
-
email: verified.account.email,
|
|
29194
|
-
accountId: verified.account.id,
|
|
29195
|
-
expiresAt: sessionExpiry()
|
|
29196
|
-
}, target);
|
|
29197
|
-
success(`Logged in as ${verified.account.email}`);
|
|
29198
|
-
info(dim(options3.credits ? "Run 'secondlayer credits balance' to see your archive credits." : "Run 'secondlayer whoami' to see your account status."));
|
|
29199
|
-
} catch (err) {
|
|
29200
|
-
if (err instanceof CliHttpError) {
|
|
29201
|
-
error(err.message);
|
|
29202
|
-
} else {
|
|
29203
|
-
error(err instanceof Error ? err.message : String(err));
|
|
29204
|
-
}
|
|
29205
|
-
process.exit(1);
|
|
29206
|
-
}
|
|
29207
|
-
}
|
|
29208
|
-
function registerLoginCommand(program2) {
|
|
29209
|
-
program2.command("login", { hidden: true }).description("Log in to Secondlayer (magic-link email)").option("--force", "Skip the already-logged-in check and re-run the flow").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", `
|
|
29210
|
-
Examples:
|
|
29211
|
-
$ secondlayer login --credits
|
|
29212
|
-
$ echo "$INSTANCE_TOKEN" | secondlayer login --with-token`).action((opts) => opts.withToken ? runTokenLogin({ credits: opts.credits }) : runLoginFlow({ force: opts.force, credits: opts.credits }));
|
|
29213
|
-
}
|
|
29214
|
-
var init_login = __esm(() => {
|
|
29215
|
-
init_http();
|
|
29216
|
-
init_output();
|
|
29217
|
-
init_session();
|
|
29218
|
-
});
|
|
29219
|
-
|
|
29220
|
-
// src/lib/require-auth.ts
|
|
29221
|
-
async function requireAuth() {
|
|
29222
|
-
if (isOssMode())
|
|
29223
|
-
return;
|
|
29224
|
-
const session = await readSession();
|
|
29225
|
-
if (session)
|
|
29226
|
-
return;
|
|
29227
|
-
info("You're not logged in. Starting login flow.");
|
|
29228
|
-
await runLoginFlow();
|
|
29229
|
-
}
|
|
29230
|
-
var init_require_auth = __esm(() => {
|
|
29231
|
-
init_login();
|
|
29232
|
-
init_output();
|
|
29233
|
-
init_resolve_auth();
|
|
29234
|
-
init_session();
|
|
29235
|
-
});
|
|
29236
|
-
|
|
29237
29123
|
// src/templates/subgraph.ts
|
|
29238
29124
|
function generateSubgraphStarter(name) {
|
|
29239
29125
|
return `${nextStepsHeader(name)}${starter(name)}`;
|
|
@@ -29323,7 +29209,7 @@ __export(exports_subgraph_test, {
|
|
|
29323
29209
|
import { createHash as createHash2 } from "node:crypto";
|
|
29324
29210
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
29325
29211
|
import { dirname as dirname4, resolve as resolve2 } from "node:path";
|
|
29326
|
-
import { Index, resolveApiKey as
|
|
29212
|
+
import { Index, resolveApiKey as resolveApiKey3, resolveBaseUrl } from "@secondlayer/sdk";
|
|
29327
29213
|
import {
|
|
29328
29214
|
DECODED_EVENT_TYPES
|
|
29329
29215
|
} from "@secondlayer/stacks/filters";
|
|
@@ -29376,7 +29262,7 @@ function indexReadFailure(err, ctx) {
|
|
|
29376
29262
|
};
|
|
29377
29263
|
}
|
|
29378
29264
|
if (status === 401 || status === 403) {
|
|
29379
|
-
const credential =
|
|
29265
|
+
const credential = resolveApiKey3() ? "INSTANCE_TOKEN is set in this shell" : "no INSTANCE_TOKEN is set in this shell";
|
|
29380
29266
|
return {
|
|
29381
29267
|
message: `Index read rejected (HTTP ${status}) while ${where}.`,
|
|
29382
29268
|
hint: `${credential}. This read uses the same SL_API_URL + INSTANCE_TOKEN pair as \`secondlayer subgraphs deploy\` — confirm both point at the instance you deployed to (\`secondlayer status\`), then retry. ${offlineHint}`
|
|
@@ -29611,7 +29497,7 @@ import {
|
|
|
29611
29497
|
} from "node:fs";
|
|
29612
29498
|
import { basename, dirname as dirname5, extname, join as join4, resolve as resolve3 } from "node:path";
|
|
29613
29499
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
29614
|
-
import { confirm as
|
|
29500
|
+
import { confirm as confirm2 } from "@inquirer/prompts";
|
|
29615
29501
|
import {
|
|
29616
29502
|
generatePrintPayloadTypes,
|
|
29617
29503
|
generatePrintSchemaSubgraph
|
|
@@ -29627,7 +29513,7 @@ async function loadSubgraphWithDepCheck(absPath) {
|
|
|
29627
29513
|
if (!missingSdk)
|
|
29628
29514
|
throw err;
|
|
29629
29515
|
warn("Missing dependency: @secondlayer/subgraphs");
|
|
29630
|
-
const install = await
|
|
29516
|
+
const install = await confirm2({
|
|
29631
29517
|
message: "Install with `bun add @secondlayer/subgraphs`?",
|
|
29632
29518
|
default: true
|
|
29633
29519
|
});
|
|
@@ -29797,9 +29683,9 @@ async function specFromLocalFile(absPath, format2, specOptions) {
|
|
|
29797
29683
|
});
|
|
29798
29684
|
return format2 === "openapi" ? generateSubgraphOpenApi(detail, specOptions) : format2 === "agent" ? generateSubgraphAgentSchema(detail, specOptions) : generateSubgraphMarkdown(detail, specOptions);
|
|
29799
29685
|
}
|
|
29800
|
-
function createLocalSubgraphDetail(
|
|
29686
|
+
function createLocalSubgraphDetail(input) {
|
|
29801
29687
|
const tables = {};
|
|
29802
|
-
for (const [tableName, rawTable] of Object.entries(
|
|
29688
|
+
for (const [tableName, rawTable] of Object.entries(input.schema)) {
|
|
29803
29689
|
const table = rawTable;
|
|
29804
29690
|
const columns = {};
|
|
29805
29691
|
for (const [columnName, column] of Object.entries(table.columns ?? {})) {
|
|
@@ -29816,22 +29702,22 @@ function createLocalSubgraphDetail(input2) {
|
|
|
29816
29702
|
columns._tx_id = { type: "text" };
|
|
29817
29703
|
columns._created_at = { type: "timestamp" };
|
|
29818
29704
|
tables[tableName] = {
|
|
29819
|
-
endpoint: `/subgraphs/${
|
|
29705
|
+
endpoint: `/subgraphs/${input.name}/${tableName}`,
|
|
29820
29706
|
columns,
|
|
29821
29707
|
rowCount: 0,
|
|
29822
|
-
example: `/subgraphs/${
|
|
29708
|
+
example: `/subgraphs/${input.name}/${tableName}?_sort=_block_height&_order=desc&_limit=10`,
|
|
29823
29709
|
...table.indexes && { indexes: table.indexes },
|
|
29824
29710
|
...table.uniqueKeys && { uniqueKeys: table.uniqueKeys }
|
|
29825
29711
|
};
|
|
29826
29712
|
}
|
|
29827
29713
|
return {
|
|
29828
|
-
name:
|
|
29829
|
-
version:
|
|
29830
|
-
schemaHash:
|
|
29714
|
+
name: input.name,
|
|
29715
|
+
version: input.version ?? "0.0.0",
|
|
29716
|
+
schemaHash: input.schemaHash,
|
|
29831
29717
|
status: "local",
|
|
29832
29718
|
lastProcessedBlock: 0,
|
|
29833
|
-
...
|
|
29834
|
-
sources:
|
|
29719
|
+
...input.description && { description: input.description },
|
|
29720
|
+
sources: input.sources,
|
|
29835
29721
|
health: {
|
|
29836
29722
|
totalProcessed: 0,
|
|
29837
29723
|
totalErrors: 0,
|
|
@@ -30050,6 +29936,7 @@ function formatSubgraphSync(sync) {
|
|
|
30050
29936
|
}
|
|
30051
29937
|
function registerSubgraphsCommand(program2) {
|
|
30052
29938
|
const subgraphs = program2.command("subgraphs").description("Manage materialized subgraphs");
|
|
29939
|
+
subgraphs.hook("preAction", () => assertInstanceUrl());
|
|
30053
29940
|
subgraphs.command("create <name>").description("Start here: create a new subgraph definition file (see also: subgraphs scaffold)").option("--from-contract <contractId>", "Generate sources/schema/handlers from the contract's observed print events (requires network)").option("--table-per-topic", "With --from-contract: one table per print topic instead of a single wide table").addHelpText("after", `
|
|
30054
29941
|
create is the default way to start a subgraph. It writes subgraphs/<name>.ts —
|
|
30055
29942
|
an empty starter, or with --from-contract a schema inferred from the print
|
|
@@ -30186,7 +30073,7 @@ otherwise the deployed definition's only copy is the row in the database. Pass
|
|
|
30186
30073
|
const message = `${file} is ${reason}. Deploy it and the only copy of this definition is a row in the database.`;
|
|
30187
30074
|
if (process.stdin.isTTY) {
|
|
30188
30075
|
warn(message);
|
|
30189
|
-
const confirmed = await
|
|
30076
|
+
const confirmed = await confirm2({
|
|
30190
30077
|
message: "Deploy anyway?",
|
|
30191
30078
|
default: false
|
|
30192
30079
|
});
|
|
@@ -30202,9 +30089,6 @@ otherwise the deployed definition's only copy is the row in the database. Pass
|
|
|
30202
30089
|
}
|
|
30203
30090
|
}
|
|
30204
30091
|
const config = await loadConfig2();
|
|
30205
|
-
if (config.network !== "local" && !isOssMode()) {
|
|
30206
|
-
await requireAuth();
|
|
30207
|
-
}
|
|
30208
30092
|
const dryRun = options3.dryRun;
|
|
30209
30093
|
const startBlock = parseStartBlockOption(options3.startBlock);
|
|
30210
30094
|
if (startBlock !== undefined) {
|
|
@@ -30927,8 +30811,6 @@ var init_subgraphs2 = __esm(() => {
|
|
|
30927
30811
|
init_fs();
|
|
30928
30812
|
init_git_status();
|
|
30929
30813
|
init_output();
|
|
30930
|
-
init_require_auth();
|
|
30931
|
-
init_resolve_auth();
|
|
30932
30814
|
init_resolve_auth();
|
|
30933
30815
|
init_clarity();
|
|
30934
30816
|
init_api();
|
|
@@ -30973,14 +30855,14 @@ function parseIndexEventType(eventType, types5) {
|
|
|
30973
30855
|
function client() {
|
|
30974
30856
|
return new Index2({
|
|
30975
30857
|
baseUrl: resolveApiUrl(),
|
|
30976
|
-
apiKey:
|
|
30858
|
+
apiKey: resolveDataPlaneKey()
|
|
30977
30859
|
});
|
|
30978
30860
|
}
|
|
30979
30861
|
function fail(action2, err) {
|
|
30980
30862
|
const message = err instanceof Error ? err.message : String(err);
|
|
30981
30863
|
error(`Failed to ${action2}: ${message}`);
|
|
30982
30864
|
if (/\b403\b/.test(message) || /forbidden/i.test(message)) {
|
|
30983
|
-
note("The local API refused this read. Check INSTANCE_TOKEN.");
|
|
30865
|
+
note(isMerchantUrl() ? "The API refused this read. Check SECONDLAYER_API_KEY." : "The local API refused this read. Check INSTANCE_TOKEN.");
|
|
30984
30866
|
}
|
|
30985
30867
|
process.exit(1);
|
|
30986
30868
|
}
|
|
@@ -34578,7 +34460,7 @@ __export(exports_node_impl, {
|
|
|
34578
34460
|
runSetupWizard: () => runSetupWizard,
|
|
34579
34461
|
restartNode: () => restartNode
|
|
34580
34462
|
});
|
|
34581
|
-
import { confirm as
|
|
34463
|
+
import { confirm as confirm4, input as input2, select as select4 } from "@inquirer/prompts";
|
|
34582
34464
|
async function runSetupWizard() {
|
|
34583
34465
|
console.log("");
|
|
34584
34466
|
console.log(blue("Stacks Node Setup Wizard"));
|
|
@@ -34596,7 +34478,7 @@ async function runSetupWizard() {
|
|
|
34596
34478
|
}
|
|
34597
34479
|
success("Docker is running");
|
|
34598
34480
|
console.log("");
|
|
34599
|
-
const installPath = await
|
|
34481
|
+
const installPath = await input2({
|
|
34600
34482
|
message: "Where is stacks-blockchain-docker installed?",
|
|
34601
34483
|
validate: async (value) => {
|
|
34602
34484
|
if (!value.trim())
|
|
@@ -34615,18 +34497,18 @@ async function runSetupWizard() {
|
|
|
34615
34497
|
],
|
|
34616
34498
|
default: "mainnet"
|
|
34617
34499
|
});
|
|
34618
|
-
const autoStartIndexer = await
|
|
34500
|
+
const autoStartIndexer = await confirm4({
|
|
34619
34501
|
message: "Auto-start indexer when node starts?",
|
|
34620
34502
|
default: true
|
|
34621
34503
|
});
|
|
34622
34504
|
let indexerPort = 3700;
|
|
34623
34505
|
if (autoStartIndexer) {
|
|
34624
|
-
const customPort = await
|
|
34506
|
+
const customPort = await confirm4({
|
|
34625
34507
|
message: "Use default indexer port (3700)?",
|
|
34626
34508
|
default: true
|
|
34627
34509
|
});
|
|
34628
34510
|
if (!customPort) {
|
|
34629
|
-
const portInput = await
|
|
34511
|
+
const portInput = await input2({
|
|
34630
34512
|
message: "Enter custom indexer port:",
|
|
34631
34513
|
default: "3700",
|
|
34632
34514
|
validate: (value) => {
|
|
@@ -34727,7 +34609,7 @@ async function stopNode(_pathOverride, force, _wait) {
|
|
|
34727
34609
|
return;
|
|
34728
34610
|
}
|
|
34729
34611
|
if (!force) {
|
|
34730
|
-
const proceed = await
|
|
34612
|
+
const proceed = await confirm4({
|
|
34731
34613
|
message: "Stop the Stacks node?",
|
|
34732
34614
|
default: false
|
|
34733
34615
|
});
|
|
@@ -34757,7 +34639,7 @@ async function restartNode(pathOverride, force, _wait) {
|
|
|
34757
34639
|
const wasRunning = await isNodeRunning();
|
|
34758
34640
|
if (wasRunning) {
|
|
34759
34641
|
if (!force) {
|
|
34760
|
-
const proceed = await
|
|
34642
|
+
const proceed = await confirm4({
|
|
34761
34643
|
message: "Restart the Stacks node?",
|
|
34762
34644
|
default: false
|
|
34763
34645
|
});
|
|
@@ -35105,6 +34987,9 @@ import { resolve as resolve14 } from "node:path";
|
|
|
35105
34987
|
import { ARCHIVE_ROOT_PUBLIC_KEY_PEM } from "@secondlayer/shared/archive/root-key";
|
|
35106
34988
|
import { generateEd25519KeyPair } from "@secondlayer/shared/crypto/ed25519";
|
|
35107
34989
|
import { INSTANCE_NETWORKS } from "@secondlayer/shared/db/queries/instance";
|
|
34990
|
+
function isHostedAccountKey(value) {
|
|
34991
|
+
return value.startsWith("sk-sl_") || value.startsWith("ss-sl_");
|
|
34992
|
+
}
|
|
35108
34993
|
function parseInstanceNetwork(value) {
|
|
35109
34994
|
const network = value.trim().toLowerCase();
|
|
35110
34995
|
if (INSTANCE_NETWORKS.includes(network)) {
|
|
@@ -35152,11 +35037,15 @@ function readEnvValue(envPath, key) {
|
|
|
35152
35037
|
return match ? unescapeEnvValue(match[1]) : null;
|
|
35153
35038
|
}
|
|
35154
35039
|
function buildInstanceEnv(input4) {
|
|
35155
|
-
const
|
|
35040
|
+
const existingAlias = input4.existing?.SL_API_KEY;
|
|
35041
|
+
const aliasIsHex = existingAlias && !existingAlias.startsWith("sk-sl_") && !existingAlias.startsWith("ss-sl_");
|
|
35042
|
+
const token = input4.existing?.INSTANCE_TOKEN || (aliasIsHex ? existingAlias : undefined) || generateInstanceToken();
|
|
35156
35043
|
const secrets = input4.existing?.SECONDLAYER_SECRETS_KEY || generateSecretsKey();
|
|
35157
35044
|
const signing = input4.existing?.STREAMS_SIGNING_PRIVATE_KEY || input4.existing?.SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY || generateSigningPrivateKey();
|
|
35158
|
-
const apiUrl = input4.apiUrl
|
|
35045
|
+
const apiUrl = input4.existing?.SECONDLAYER_API_URL || input4.existing?.SL_API_URL || input4.apiUrl || "http://127.0.0.1:3800";
|
|
35159
35046
|
const archiveKey = input4.existing?.ARCHIVE_SIGNING_PUBLIC_KEY || input4.archivePublicKeyPem || ARCHIVE_ROOT_PUBLIC_KEY_PEM;
|
|
35047
|
+
const hostedCandidate = input4.existing?.SECONDLAYER_API_KEY || input4.existing?.SL_API_KEY || undefined;
|
|
35048
|
+
const hostedKey = hostedCandidate && isHostedAccountKey(hostedCandidate) ? hostedCandidate : undefined;
|
|
35160
35049
|
return {
|
|
35161
35050
|
INSTANCE_MODE: "oss",
|
|
35162
35051
|
STACKS_NETWORK: input4.network,
|
|
@@ -35165,8 +35054,9 @@ function buildInstanceEnv(input4) {
|
|
|
35165
35054
|
STREAMS_SIGNING_PRIVATE_KEY: signing,
|
|
35166
35055
|
SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY: signing,
|
|
35167
35056
|
ALLOW_UNSIGNED_WEBHOOKS: "false",
|
|
35168
|
-
|
|
35169
|
-
|
|
35057
|
+
SECONDLAYER_API_URL: apiUrl,
|
|
35058
|
+
SL_API_URL: apiUrl,
|
|
35059
|
+
...hostedKey ? { SECONDLAYER_API_KEY: hostedKey, SL_API_KEY: hostedKey } : {},
|
|
35170
35060
|
ARCHIVE_SIGNING_PUBLIC_KEY: archiveKey
|
|
35171
35061
|
};
|
|
35172
35062
|
}
|
|
@@ -35182,11 +35072,12 @@ function renderInstanceEnv(env2) {
|
|
|
35182
35072
|
`STREAMS_SIGNING_PRIVATE_KEY=${escapeEnvValue(env2.STREAMS_SIGNING_PRIVATE_KEY)}`,
|
|
35183
35073
|
`SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY=${escapeEnvValue(env2.SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY)}`,
|
|
35184
35074
|
`ALLOW_UNSIGNED_WEBHOOKS=${env2.ALLOW_UNSIGNED_WEBHOOKS}`,
|
|
35185
|
-
`
|
|
35186
|
-
|
|
35187
|
-
"# INSTANCE_TOKEN wins if the two ever disagree.",
|
|
35188
|
-
`SL_API_KEY=${env2.SL_API_KEY}`
|
|
35075
|
+
`SECONDLAYER_API_URL=${env2.SECONDLAYER_API_URL}`,
|
|
35076
|
+
`SL_API_URL=${env2.SL_API_URL}`
|
|
35189
35077
|
];
|
|
35078
|
+
if (env2.SECONDLAYER_API_KEY) {
|
|
35079
|
+
lines2.push("# Hosted account key for archive credits (sk-sl_*).", `SECONDLAYER_API_KEY=${env2.SECONDLAYER_API_KEY}`, `SL_API_KEY=${env2.SL_API_KEY ?? env2.SECONDLAYER_API_KEY}`);
|
|
35080
|
+
}
|
|
35190
35081
|
lines2.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(env2.ARCHIVE_SIGNING_PUBLIC_KEY)}`, "");
|
|
35191
35082
|
return lines2.join(`
|
|
35192
35083
|
`);
|
|
@@ -35203,7 +35094,9 @@ function loadExistingInstanceEnv(cwd, file = INSTANCE_ENV_FILE) {
|
|
|
35203
35094
|
SECONDLAYER_SECRETS_KEY: readEnvValue(path11, "SECONDLAYER_SECRETS_KEY"),
|
|
35204
35095
|
STREAMS_SIGNING_PRIVATE_KEY: readEnvValue(path11, "STREAMS_SIGNING_PRIVATE_KEY"),
|
|
35205
35096
|
SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY: readEnvValue(path11, "SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY"),
|
|
35097
|
+
SECONDLAYER_API_URL: readEnvValue(path11, "SECONDLAYER_API_URL"),
|
|
35206
35098
|
SL_API_URL: readEnvValue(path11, "SL_API_URL"),
|
|
35099
|
+
SECONDLAYER_API_KEY: readEnvValue(path11, "SECONDLAYER_API_KEY"),
|
|
35207
35100
|
SL_API_KEY: readEnvValue(path11, "SL_API_KEY"),
|
|
35208
35101
|
ARCHIVE_SIGNING_PUBLIC_KEY: readEnvValue(path11, "ARCHIVE_SIGNING_PUBLIC_KEY")
|
|
35209
35102
|
};
|
|
@@ -35588,7 +35481,9 @@ function resolveSecrets(config) {
|
|
|
35588
35481
|
SECONDLAYER_SECRETS_KEY: existing.SECONDLAYER_SECRETS_KEY,
|
|
35589
35482
|
STREAMS_SIGNING_PRIVATE_KEY: existing.STREAMS_SIGNING_PRIVATE_KEY,
|
|
35590
35483
|
SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY: existing.SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY,
|
|
35484
|
+
SECONDLAYER_API_URL: existing.SECONDLAYER_API_URL,
|
|
35591
35485
|
SL_API_URL: existing.SL_API_URL,
|
|
35486
|
+
SECONDLAYER_API_KEY: existing.SECONDLAYER_API_KEY,
|
|
35592
35487
|
SL_API_KEY: existing.SL_API_KEY,
|
|
35593
35488
|
ARCHIVE_SIGNING_PUBLIC_KEY: existing.ARCHIVE_SIGNING_PUBLIC_KEY
|
|
35594
35489
|
},
|
|
@@ -35656,10 +35551,12 @@ function renderSetupEnv(config, secrets) {
|
|
|
35656
35551
|
`STREAMS_SIGNING_PRIVATE_KEY=${escapeEnvValue(i3.STREAMS_SIGNING_PRIVATE_KEY)}`,
|
|
35657
35552
|
`SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY=${escapeEnvValue(i3.SECONDLAYER_WEBHOOK_SIGNING_PRIVATE_KEY)}`,
|
|
35658
35553
|
`ALLOW_UNSIGNED_WEBHOOKS=${i3.ALLOW_UNSIGNED_WEBHOOKS}`,
|
|
35659
|
-
|
|
35660
|
-
`SL_API_KEY=${i3.SL_API_KEY}`,
|
|
35554
|
+
`SECONDLAYER_API_URL=${i3.SECONDLAYER_API_URL}`,
|
|
35661
35555
|
`SL_API_URL=${i3.SL_API_URL}`
|
|
35662
35556
|
];
|
|
35557
|
+
if (i3.SECONDLAYER_API_KEY) {
|
|
35558
|
+
lines2.push("# Hosted account key for archive credits (sk-sl_*).", `SECONDLAYER_API_KEY=${i3.SECONDLAYER_API_KEY}`, `SL_API_KEY=${i3.SL_API_KEY ?? i3.SECONDLAYER_API_KEY}`);
|
|
35559
|
+
}
|
|
35663
35560
|
lines2.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(i3.ARCHIVE_SIGNING_PUBLIC_KEY)}`);
|
|
35664
35561
|
if (config.nodeMode === "full") {
|
|
35665
35562
|
lines2.push("BITCOIN_RPC_USER=stacks", `BITCOIN_RPC_PASSWORD=${secrets.bitcoinRpcPassword}`);
|
|
@@ -36687,7 +36584,7 @@ var {
|
|
|
36687
36584
|
// package.json
|
|
36688
36585
|
var package_default = {
|
|
36689
36586
|
name: "@secondlayer/cli",
|
|
36690
|
-
version: "14.
|
|
36587
|
+
version: "14.2.0",
|
|
36691
36588
|
description: "Run a Stacks index on your own hardware — set it up, restore verified history, and keep it current.",
|
|
36692
36589
|
repository: {
|
|
36693
36590
|
type: "git",
|
|
@@ -36732,8 +36629,8 @@ var package_default = {
|
|
|
36732
36629
|
"@opentui/react": "^0.5.3",
|
|
36733
36630
|
"@secondlayer/bundler": "^0.5.1",
|
|
36734
36631
|
"@secondlayer/scaffold": "^1.5.5",
|
|
36735
|
-
"@secondlayer/sdk": "^10.
|
|
36736
|
-
"@secondlayer/shared": "^11.
|
|
36632
|
+
"@secondlayer/sdk": "^10.3.0",
|
|
36633
|
+
"@secondlayer/shared": "^11.4.0",
|
|
36737
36634
|
"@secondlayer/stacks": "^5.1.0",
|
|
36738
36635
|
"@secondlayer/subgraphs": "^4.1.5",
|
|
36739
36636
|
esbuild: "^0.27.4",
|
|
@@ -37326,6 +37223,7 @@ function openBrowser(url) {
|
|
|
37326
37223
|
}
|
|
37327
37224
|
function registerConsoleCommand(program2) {
|
|
37328
37225
|
program2.command("console").description("Open the console UI in a browser").option("--url <url>", `Console URL (default ${DEFAULT_CONSOLE_URL})`).option("--no-open", "Print the console URL instead of opening a browser").action(async (options3) => {
|
|
37226
|
+
assertInstanceUrl();
|
|
37329
37227
|
const url = resolveConsoleUrl(options3.url);
|
|
37330
37228
|
if (options3.open === false) {
|
|
37331
37229
|
writeData(url);
|
|
@@ -37502,18 +37400,19 @@ function printPublicStatus(status, diagnosis) {
|
|
|
37502
37400
|
init_api_client();
|
|
37503
37401
|
init_filter_params();
|
|
37504
37402
|
init_output();
|
|
37403
|
+
init_resolve_auth();
|
|
37505
37404
|
import { sign } from "@secondlayer/shared/crypto/standard-webhooks";
|
|
37506
37405
|
|
|
37507
37406
|
// src/lib/subscription-validation.ts
|
|
37508
37407
|
import {
|
|
37509
37408
|
validateSubscriptionFilterForTable
|
|
37510
37409
|
} from "@secondlayer/shared/schemas/subscriptions";
|
|
37511
|
-
async function validateSubscriptionTargetFromApi(client2,
|
|
37512
|
-
const subgraph = await client2.subgraphs.status(
|
|
37410
|
+
async function validateSubscriptionTargetFromApi(client2, input) {
|
|
37411
|
+
const subgraph = await client2.subgraphs.status(input.subgraphName);
|
|
37513
37412
|
const errors2 = validateSubscriptionFilterForTable({
|
|
37514
|
-
subgraphName:
|
|
37515
|
-
tableName:
|
|
37516
|
-
filter:
|
|
37413
|
+
subgraphName: input.subgraphName,
|
|
37414
|
+
tableName: input.tableName,
|
|
37415
|
+
filter: input.filter,
|
|
37517
37416
|
tables: subgraph.tables
|
|
37518
37417
|
});
|
|
37519
37418
|
if (errors2.length > 0) {
|
|
@@ -37538,7 +37437,7 @@ import {
|
|
|
37538
37437
|
} from "node:fs";
|
|
37539
37438
|
import { dirname as dirname6, join as join6, relative, resolve as resolve5 } from "node:path";
|
|
37540
37439
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
37541
|
-
import { input
|
|
37440
|
+
import { input, select as select3 } from "@inquirer/prompts";
|
|
37542
37441
|
import { SecondLayer as SecondLayer3 } from "@secondlayer/sdk";
|
|
37543
37442
|
import {
|
|
37544
37443
|
ChainTriggerSchema
|
|
@@ -37632,7 +37531,7 @@ async function promptFor(_name, opts) {
|
|
|
37632
37531
|
let subgraph = opts.subgraph;
|
|
37633
37532
|
if (subgraph === undefined) {
|
|
37634
37533
|
requireTtyFor("--subgraph");
|
|
37635
|
-
subgraph = await
|
|
37534
|
+
subgraph = await input({
|
|
37636
37535
|
message: "Subgraph name (must already be deployed):",
|
|
37637
37536
|
validate: (v2) => v2.trim().length > 0 ? true : "required"
|
|
37638
37537
|
});
|
|
@@ -37640,7 +37539,7 @@ async function promptFor(_name, opts) {
|
|
|
37640
37539
|
let table = opts.table;
|
|
37641
37540
|
if (table === undefined) {
|
|
37642
37541
|
requireTtyFor("--table");
|
|
37643
|
-
table = await
|
|
37542
|
+
table = await input({
|
|
37644
37543
|
message: "Table to subscribe to:",
|
|
37645
37544
|
validate: (v2) => v2.trim().length > 0 ? true : "required"
|
|
37646
37545
|
});
|
|
@@ -37648,7 +37547,7 @@ async function promptFor(_name, opts) {
|
|
|
37648
37547
|
let url = opts.url;
|
|
37649
37548
|
if (url === undefined) {
|
|
37650
37549
|
requireTtyFor("--url");
|
|
37651
|
-
url = await
|
|
37550
|
+
url = await input({
|
|
37652
37551
|
message: runtime === "inngest" ? "Inngest event endpoint URL (e.g. https://inn.gs/e/<KEY> or http://localhost:8288/e/<KEY>):" : runtime === "trigger" ? "Trigger.dev task URL (e.g. https://api.trigger.dev/api/v1/tasks/<TASK_ID>/trigger):" : runtime === "cloudflare" ? "Cloudflare Workflows instances URL:" : "Your HTTP receiver URL (e.g. https://yourapp.example/webhook):",
|
|
37653
37552
|
validate: (v2) => v2.startsWith("http://") || v2.startsWith("https://") ? true : "must be http(s) URL"
|
|
37654
37553
|
});
|
|
@@ -37981,52 +37880,52 @@ Auth config:`));
|
|
|
37981
37880
|
console.log(JSON.stringify(sub.authConfig, null, 2));
|
|
37982
37881
|
}
|
|
37983
37882
|
}
|
|
37984
|
-
function buildDoctorReport(
|
|
37985
|
-
const successful =
|
|
37986
|
-
const failed =
|
|
37987
|
-
const subgraph =
|
|
37988
|
-
name:
|
|
37989
|
-
status:
|
|
37990
|
-
syncStatus:
|
|
37991
|
-
lastProcessedBlock:
|
|
37992
|
-
chainTip:
|
|
37993
|
-
gapCount:
|
|
37994
|
-
integrity:
|
|
37883
|
+
function buildDoctorReport(input2) {
|
|
37884
|
+
const successful = input2.deliveries.filter(isSuccessDelivery).length;
|
|
37885
|
+
const failed = input2.deliveries.length - successful;
|
|
37886
|
+
const subgraph = input2.subgraph ? {
|
|
37887
|
+
name: input2.subgraph.name,
|
|
37888
|
+
status: input2.subgraph.status,
|
|
37889
|
+
syncStatus: input2.subgraph.sync.status,
|
|
37890
|
+
lastProcessedBlock: input2.subgraph.sync.lastProcessedBlock,
|
|
37891
|
+
chainTip: input2.subgraph.sync.chainTip,
|
|
37892
|
+
gapCount: input2.subgraph.sync.gaps.count,
|
|
37893
|
+
integrity: input2.subgraph.sync.integrity
|
|
37995
37894
|
} : null;
|
|
37996
37895
|
const hints = [];
|
|
37997
|
-
if (
|
|
37998
|
-
hints.push(`Resume when the receiver is healthy: secondlayer subscriptions resume ${
|
|
37896
|
+
if (input2.subscription.status === "paused") {
|
|
37897
|
+
hints.push(`Resume when the receiver is healthy: secondlayer subscriptions resume ${input2.subscription.id}`);
|
|
37999
37898
|
}
|
|
38000
|
-
if (
|
|
37899
|
+
if (input2.subscription.lastError) {
|
|
38001
37900
|
hints.push("Run secondlayer subscriptions test to reproduce the receiver request.");
|
|
38002
37901
|
}
|
|
38003
|
-
if (
|
|
37902
|
+
if (input2.subscription.circuitOpenedAt || input2.subscription.circuitFailures > 0) {
|
|
38004
37903
|
hints.push("Circuit breaker has failures; inspect receiver logs and delivery status codes.");
|
|
38005
37904
|
}
|
|
38006
|
-
if (
|
|
38007
|
-
hints.push(`Dead-letter rows exist; inspect with secondlayer subscriptions dead ${
|
|
37905
|
+
if (input2.dead.length > 0) {
|
|
37906
|
+
hints.push(`Dead-letter rows exist; inspect with secondlayer subscriptions dead ${input2.subscription.id} and requeue selected rows.`);
|
|
38008
37907
|
}
|
|
38009
37908
|
if (subgraph?.gapCount && subgraph.gapCount > 0) {
|
|
38010
|
-
hints.push(`Linked subgraph has gaps; run secondlayer subgraphs gaps ${
|
|
37909
|
+
hints.push(`Linked subgraph has gaps; run secondlayer subgraphs gaps ${input2.subscription.subgraphName}.`);
|
|
38011
37910
|
}
|
|
38012
37911
|
if (subgraph?.syncStatus === "catching_up") {
|
|
38013
37912
|
hints.push("Linked subgraph is still catching up; new matching rows may arrive later.");
|
|
38014
37913
|
}
|
|
38015
|
-
if (
|
|
37914
|
+
if (input2.deliveries.length === 0) {
|
|
38016
37915
|
hints.push("No deliveries yet; confirm the table is receiving inserted rows that match the filter.");
|
|
38017
37916
|
}
|
|
38018
37917
|
if (hints.length === 0) {
|
|
38019
37918
|
hints.push("No immediate action needed.");
|
|
38020
37919
|
}
|
|
38021
37920
|
return {
|
|
38022
|
-
subscription:
|
|
37921
|
+
subscription: input2.subscription,
|
|
38023
37922
|
deliverySummary: {
|
|
38024
|
-
total:
|
|
37923
|
+
total: input2.deliveries.length,
|
|
38025
37924
|
successful,
|
|
38026
37925
|
failed,
|
|
38027
|
-
last:
|
|
37926
|
+
last: input2.deliveries[0] ?? null
|
|
38028
37927
|
},
|
|
38029
|
-
deadCount:
|
|
37928
|
+
deadCount: input2.dead.length,
|
|
38030
37929
|
subgraph,
|
|
38031
37930
|
hints
|
|
38032
37931
|
};
|
|
@@ -38119,9 +38018,9 @@ function resolveSigningSecret(options3, env2 = process.env) {
|
|
|
38119
38018
|
function shellQuote(value) {
|
|
38120
38019
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
38121
38020
|
}
|
|
38122
|
-
function buildSubscriptionTestFixture(
|
|
38123
|
-
const nowSeconds =
|
|
38124
|
-
const sub =
|
|
38021
|
+
function buildSubscriptionTestFixture(input2) {
|
|
38022
|
+
const nowSeconds = input2.nowSeconds ?? Math.floor(Date.now() / 1000);
|
|
38023
|
+
const sub = input2.subscription;
|
|
38125
38024
|
const isChain = sub.kind === "chain";
|
|
38126
38025
|
const type = isChain ? `chain.${sub.triggers?.[0]?.type ?? "event"}.apply` : `${sub.subgraphName}.${sub.tableName}.created`;
|
|
38127
38026
|
const data = isChain ? {
|
|
@@ -38129,10 +38028,10 @@ function buildSubscriptionTestFixture(input3) {
|
|
|
38129
38028
|
canonical: true,
|
|
38130
38029
|
block_hash: "0xexampleblock",
|
|
38131
38030
|
block_height: 0,
|
|
38132
|
-
tx_id:
|
|
38031
|
+
tx_id: input2.row.tx_id ?? "0xexampletransaction",
|
|
38133
38032
|
trigger: sub.triggers?.[0]?.type ?? "event",
|
|
38134
|
-
event:
|
|
38135
|
-
} :
|
|
38033
|
+
event: input2.row
|
|
38034
|
+
} : input2.row;
|
|
38136
38035
|
const body = JSON.stringify({
|
|
38137
38036
|
type,
|
|
38138
38037
|
timestamp: new Date(nowSeconds * 1000).toISOString(),
|
|
@@ -38140,15 +38039,15 @@ function buildSubscriptionTestFixture(input3) {
|
|
|
38140
38039
|
});
|
|
38141
38040
|
const headers = {
|
|
38142
38041
|
"content-type": "application/json",
|
|
38143
|
-
...sign(body,
|
|
38144
|
-
id:
|
|
38042
|
+
...sign(body, input2.signingSecret, {
|
|
38043
|
+
id: input2.id ?? `test-${input2.subscription.id}`,
|
|
38145
38044
|
timestampSeconds: nowSeconds
|
|
38146
38045
|
})
|
|
38147
38046
|
};
|
|
38148
38047
|
const headerArgs = Object.entries(headers).map(([key, value]) => ` -H ${shellQuote(`${key}: ${value}`)} \\`).join(`
|
|
38149
38048
|
`);
|
|
38150
38049
|
const curl = [
|
|
38151
|
-
`curl -X POST ${shellQuote(
|
|
38050
|
+
`curl -X POST ${shellQuote(input2.subscription.url)} \\`,
|
|
38152
38051
|
headerArgs,
|
|
38153
38052
|
` --data ${shellQuote(body)}`
|
|
38154
38053
|
].join(`
|
|
@@ -38211,6 +38110,7 @@ async function confirmOrExit(message, yes) {
|
|
|
38211
38110
|
}
|
|
38212
38111
|
function registerSubscriptionsCommand(program2) {
|
|
38213
38112
|
const subscriptions = program2.command("subscriptions").alias("subs").description("Manage subgraph table subscriptions");
|
|
38113
|
+
subscriptions.hook("preAction", () => assertInstanceUrl());
|
|
38214
38114
|
addSubscriptionsCreateCommand(subscriptions);
|
|
38215
38115
|
subscriptions.command("list").alias("ls").description("List subscriptions").option("--json", "Output as JSON").action(async (options3) => {
|
|
38216
38116
|
try {
|
|
@@ -38946,7 +38846,7 @@ var VALID_TYPES = STREAMS_EVENT_TYPES;
|
|
|
38946
38846
|
function client2() {
|
|
38947
38847
|
return createStreamsClient({
|
|
38948
38848
|
baseUrl: resolveApiUrl(),
|
|
38949
|
-
apiKey:
|
|
38849
|
+
apiKey: resolveDataPlaneKey() ?? ""
|
|
38950
38850
|
});
|
|
38951
38851
|
}
|
|
38952
38852
|
function dumpsClient(dumpsUrl) {
|
|
@@ -38957,7 +38857,7 @@ function dumpsClient(dumpsUrl) {
|
|
|
38957
38857
|
}
|
|
38958
38858
|
return createStreamsClient({
|
|
38959
38859
|
baseUrl: resolveApiUrl(),
|
|
38960
|
-
apiKey:
|
|
38860
|
+
apiKey: resolveDataPlaneKey() ?? "",
|
|
38961
38861
|
dumpsBaseUrl
|
|
38962
38862
|
});
|
|
38963
38863
|
}
|
|
@@ -39586,7 +39486,7 @@ function markFrozen(cmd) {
|
|
|
39586
39486
|
init_config2();
|
|
39587
39487
|
init_dev_state();
|
|
39588
39488
|
init_output();
|
|
39589
|
-
import { confirm as
|
|
39489
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
39590
39490
|
import { getDb, sql } from "@secondlayer/shared/db";
|
|
39591
39491
|
import {
|
|
39592
39492
|
countMissingBlocks,
|
|
@@ -39806,7 +39706,7 @@ async function resetDatabase(skipConfirm) {
|
|
|
39806
39706
|
console.log(dim("Note: Subgraph configurations will be preserved."));
|
|
39807
39707
|
console.log("");
|
|
39808
39708
|
if (!skipConfirm) {
|
|
39809
|
-
const confirmed = await
|
|
39709
|
+
const confirmed = await confirm3({
|
|
39810
39710
|
message: "Are you sure you want to reset the database?",
|
|
39811
39711
|
default: false
|
|
39812
39712
|
});
|
|
@@ -39843,7 +39743,7 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
39843
39743
|
console.log(dim("Note: Subgraph configurations will be preserved."));
|
|
39844
39744
|
console.log("");
|
|
39845
39745
|
if (!skipConfirm) {
|
|
39846
|
-
const confirmed = await
|
|
39746
|
+
const confirmed = await confirm3({
|
|
39847
39747
|
message: "Are you sure you want to resync?",
|
|
39848
39748
|
default: false
|
|
39849
39749
|
});
|
|
@@ -40411,6 +40311,7 @@ function formatLogLine3(service, line) {
|
|
|
40411
40311
|
init_config2();
|
|
40412
40312
|
init_http();
|
|
40413
40313
|
init_output();
|
|
40314
|
+
import { resolveApiKey as resolveApiKey4 } from "@secondlayer/sdk";
|
|
40414
40315
|
|
|
40415
40316
|
// src/lib/project-file.ts
|
|
40416
40317
|
import { existsSync as existsSync7 } from "node:fs";
|
|
@@ -40455,58 +40356,188 @@ async function readActiveProject(cwd, globalDefault) {
|
|
|
40455
40356
|
}
|
|
40456
40357
|
|
|
40457
40358
|
// src/commands/whoami.ts
|
|
40359
|
+
async function runWhoami() {
|
|
40360
|
+
const instanceUrl = resolveApiUrl();
|
|
40361
|
+
const merchantUrl = resolveArchiveOpsUrl();
|
|
40362
|
+
const instanceSet = resolveApiKey4() !== undefined;
|
|
40363
|
+
const { source } = await resolveArchiveOpsBearer();
|
|
40364
|
+
let email = null;
|
|
40365
|
+
let merchantOk = false;
|
|
40366
|
+
try {
|
|
40367
|
+
const account = await httpArchiveOps("/api/accounts/me");
|
|
40368
|
+
email = account.email;
|
|
40369
|
+
merchantOk = true;
|
|
40370
|
+
} catch {
|
|
40371
|
+
merchantOk = false;
|
|
40372
|
+
}
|
|
40373
|
+
const merchantCredential = source === "env" ? "SECONDLAYER_API_KEY" : source === "session" ? "session" : null;
|
|
40374
|
+
const config = await loadConfig2();
|
|
40375
|
+
const active = await readActiveProject(process.cwd(), config.defaultProject);
|
|
40376
|
+
return {
|
|
40377
|
+
instance: {
|
|
40378
|
+
url: instanceUrl,
|
|
40379
|
+
credential: "INSTANCE_TOKEN",
|
|
40380
|
+
status: instanceSet ? "set" : "missing"
|
|
40381
|
+
},
|
|
40382
|
+
merchant: {
|
|
40383
|
+
url: merchantUrl,
|
|
40384
|
+
credential: merchantCredential,
|
|
40385
|
+
status: merchantOk ? "set" : "missing",
|
|
40386
|
+
email
|
|
40387
|
+
},
|
|
40388
|
+
project: active ? { slug: active.slug, source: active.resolvedFrom } : null
|
|
40389
|
+
};
|
|
40390
|
+
}
|
|
40458
40391
|
function registerWhoamiCommand(program2) {
|
|
40459
|
-
program2.command("whoami"
|
|
40460
|
-
const
|
|
40461
|
-
const { source } = await resolveArchiveOpsBearer();
|
|
40462
|
-
let account;
|
|
40463
|
-
try {
|
|
40464
|
-
account = await httpArchiveOps("/api/accounts/me");
|
|
40465
|
-
} catch (err) {
|
|
40466
|
-
if (err instanceof CliHttpError) {
|
|
40467
|
-
error(err.message);
|
|
40468
|
-
process.exit(1);
|
|
40469
|
-
}
|
|
40470
|
-
throw err;
|
|
40471
|
-
}
|
|
40472
|
-
const config = await loadConfig2();
|
|
40473
|
-
const active = await readActiveProject(process.cwd(), config.defaultProject);
|
|
40474
|
-
const authSource = source === "env" ? "API key (env)" : `session (${ARCHIVE_LOGIN_COMMAND})`;
|
|
40392
|
+
program2.command("whoami").description("Show instance and merchant targets.").option("--json", "Output as JSON").action(async (options3) => {
|
|
40393
|
+
const result = await runWhoami();
|
|
40475
40394
|
output({
|
|
40476
40395
|
json: options3.json,
|
|
40477
|
-
data:
|
|
40478
|
-
email: account.email,
|
|
40479
|
-
creditsUrl,
|
|
40480
|
-
apiUrl: resolveApiUrl(),
|
|
40481
|
-
authSource,
|
|
40482
|
-
project: active ? { slug: active.slug, source: active.resolvedFrom } : null
|
|
40483
|
-
},
|
|
40396
|
+
data: result,
|
|
40484
40397
|
human: () => {
|
|
40485
40398
|
const rows = [];
|
|
40486
|
-
rows.push([
|
|
40487
|
-
|
|
40488
|
-
|
|
40489
|
-
|
|
40490
|
-
|
|
40491
|
-
|
|
40492
|
-
|
|
40399
|
+
rows.push([
|
|
40400
|
+
"instance",
|
|
40401
|
+
`${result.instance.url} ${result.instance.credential} ${result.instance.status}`
|
|
40402
|
+
]);
|
|
40403
|
+
const merchantCred = result.merchant.credential ?? "SECONDLAYER_API_KEY|session";
|
|
40404
|
+
const merchantValue = result.merchant.email ? `${result.merchant.url} ${merchantCred} ${result.merchant.status} (${result.merchant.email})` : `${result.merchant.url} ${merchantCred} ${result.merchant.status}`;
|
|
40405
|
+
rows.push(["merchant", merchantValue]);
|
|
40406
|
+
if (result.project) {
|
|
40407
|
+
rows.push(["project", result.project.slug]);
|
|
40408
|
+
rows.push(["project source", dim(result.project.source)]);
|
|
40493
40409
|
} else {
|
|
40494
|
-
rows.push(["
|
|
40410
|
+
rows.push(["project", dim("(none)")]);
|
|
40495
40411
|
}
|
|
40496
40412
|
console.log(formatKeyValue(rows));
|
|
40413
|
+
if (result.merchant.status === "missing") {
|
|
40414
|
+
note(`merchant identity missing - run \`${ARCHIVE_LOGIN_COMMAND}\``);
|
|
40415
|
+
}
|
|
40497
40416
|
}
|
|
40498
40417
|
});
|
|
40499
40418
|
});
|
|
40500
40419
|
}
|
|
40501
|
-
|
|
40502
|
-
|
|
40503
|
-
|
|
40504
|
-
|
|
40420
|
+
// src/commands/login.ts
|
|
40421
|
+
init_http();
|
|
40422
|
+
init_output();
|
|
40423
|
+
init_session();
|
|
40424
|
+
import { confirm as confirm5, input as input3 } from "@inquirer/prompts";
|
|
40425
|
+
function sessionExpiry() {
|
|
40426
|
+
return new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString();
|
|
40427
|
+
}
|
|
40428
|
+
async function readStdin() {
|
|
40429
|
+
const chunks = [];
|
|
40430
|
+
for await (const chunk of process.stdin)
|
|
40431
|
+
chunks.push(chunk);
|
|
40432
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
40433
|
+
}
|
|
40434
|
+
function loginTarget(opts) {
|
|
40435
|
+
return opts.credits ? resolveArchiveOpsUrl() : resolveApiUrl();
|
|
40436
|
+
}
|
|
40437
|
+
async function runTokenLogin(opts) {
|
|
40438
|
+
const token = await readStdin();
|
|
40439
|
+
if (!token) {
|
|
40440
|
+
error('No token on stdin. Usage: echo "$KEY" | secondlayer login --with-token');
|
|
40441
|
+
process.exit(1);
|
|
40442
|
+
}
|
|
40443
|
+
const target = loginTarget(opts);
|
|
40444
|
+
let account;
|
|
40445
|
+
try {
|
|
40446
|
+
account = await httpAt(target, "/api/accounts/me", { bearer: token });
|
|
40447
|
+
} catch (err) {
|
|
40448
|
+
error(err instanceof CliHttpError ? `Token rejected by ${target}: ${err.message}` : err instanceof Error ? err.message : String(err));
|
|
40449
|
+
process.exit(1);
|
|
40450
|
+
}
|
|
40451
|
+
await writeSession({
|
|
40452
|
+
token,
|
|
40453
|
+
email: account.email,
|
|
40454
|
+
accountId: account.id,
|
|
40455
|
+
expiresAt: sessionExpiry()
|
|
40456
|
+
}, target);
|
|
40457
|
+
success(`Logged in as ${account.email} (${target})`);
|
|
40458
|
+
}
|
|
40459
|
+
async function runLoginFlow(options3 = {}) {
|
|
40460
|
+
const target = loginTarget(options3);
|
|
40461
|
+
if (!options3.force) {
|
|
40462
|
+
const existing = await readSession(target);
|
|
40463
|
+
if (existing) {
|
|
40464
|
+
info(`Already logged in as ${existing.email} (${target}).`);
|
|
40465
|
+
if (!process.stdin.isTTY) {
|
|
40466
|
+
info(dim("Run 'secondlayer logout' first, or re-run with --force to switch accounts."));
|
|
40467
|
+
return;
|
|
40468
|
+
}
|
|
40469
|
+
try {
|
|
40470
|
+
const proceed = await confirm5({
|
|
40471
|
+
message: "Log in as a different user?",
|
|
40472
|
+
default: false
|
|
40473
|
+
});
|
|
40474
|
+
if (!proceed) {
|
|
40475
|
+
info(dim("Run 'secondlayer logout' to sign out."));
|
|
40476
|
+
return;
|
|
40477
|
+
}
|
|
40478
|
+
} catch {
|
|
40479
|
+
info(dim("Run 'secondlayer logout' first, or re-run with --force to switch accounts."));
|
|
40480
|
+
return;
|
|
40481
|
+
}
|
|
40482
|
+
}
|
|
40483
|
+
}
|
|
40484
|
+
const email = await input3({
|
|
40485
|
+
message: "Email",
|
|
40486
|
+
validate: (v2) => /^.+@.+\..+$/.test(v2) ? true : "Invalid email"
|
|
40487
|
+
});
|
|
40488
|
+
try {
|
|
40489
|
+
const res = await httpAt(target, "/api/auth/magic-link", {
|
|
40490
|
+
method: "POST",
|
|
40491
|
+
body: { email }
|
|
40492
|
+
});
|
|
40493
|
+
info("Check your inbox for a 6-digit code.");
|
|
40494
|
+
if (res.code) {
|
|
40495
|
+
info(dim(`(DEV_MODE code: ${res.code})`));
|
|
40496
|
+
}
|
|
40497
|
+
} catch (err) {
|
|
40498
|
+
if (err instanceof CliHttpError) {
|
|
40499
|
+
error(err.message);
|
|
40500
|
+
} else {
|
|
40501
|
+
error(err instanceof Error ? err.message : String(err));
|
|
40502
|
+
}
|
|
40503
|
+
process.exit(1);
|
|
40504
|
+
}
|
|
40505
|
+
const code = await input3({
|
|
40506
|
+
message: "Enter the 6-digit code",
|
|
40507
|
+
validate: (v2) => /^\d{6}$/.test(v2) ? true : "Expected 6 digits"
|
|
40508
|
+
});
|
|
40509
|
+
try {
|
|
40510
|
+
const verified = await httpAt(target, "/api/auth/verify", {
|
|
40511
|
+
method: "POST",
|
|
40512
|
+
body: { email, code }
|
|
40513
|
+
});
|
|
40514
|
+
await writeSession({
|
|
40515
|
+
token: verified.sessionToken,
|
|
40516
|
+
email: verified.account.email,
|
|
40517
|
+
accountId: verified.account.id,
|
|
40518
|
+
expiresAt: sessionExpiry()
|
|
40519
|
+
}, target);
|
|
40520
|
+
success(`Logged in as ${verified.account.email}`);
|
|
40521
|
+
info(dim(options3.credits ? "Run 'secondlayer credits balance' to see your archive credits." : "Run 'secondlayer whoami' to see your account status."));
|
|
40522
|
+
} catch (err) {
|
|
40523
|
+
if (err instanceof CliHttpError) {
|
|
40524
|
+
error(err.message);
|
|
40525
|
+
} else {
|
|
40526
|
+
error(err instanceof Error ? err.message : String(err));
|
|
40527
|
+
}
|
|
40528
|
+
process.exit(1);
|
|
40529
|
+
}
|
|
40530
|
+
}
|
|
40531
|
+
function registerLoginCommand(program2) {
|
|
40532
|
+
program2.command("login", { hidden: true }).description("Log in to Secondlayer (magic-link email)").option("--force", "Skip the already-logged-in check and re-run the flow").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", `
|
|
40533
|
+
Examples:
|
|
40534
|
+
$ secondlayer login --credits
|
|
40535
|
+
$ echo "$SECONDLAYER_API_KEY" | secondlayer login --with-token`).action((opts) => opts.withToken ? runTokenLogin({ credits: opts.credits }) : runLoginFlow({ force: opts.force, credits: opts.credits }));
|
|
40536
|
+
}
|
|
40505
40537
|
// src/commands/logout.ts
|
|
40506
40538
|
init_http();
|
|
40507
40539
|
init_output();
|
|
40508
40540
|
init_session();
|
|
40509
|
-
init_login();
|
|
40510
40541
|
async function runLogout(opts = {}) {
|
|
40511
40542
|
const target = loginTarget(opts);
|
|
40512
40543
|
const session = await readSession(target);
|
|
@@ -41785,6 +41816,7 @@ function registerBootstrapCommand(program2) {
|
|
|
41785
41816
|
// src/commands/uninstall.ts
|
|
41786
41817
|
init_instance_init();
|
|
41787
41818
|
init_output();
|
|
41819
|
+
init_resolve_auth();
|
|
41788
41820
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
41789
41821
|
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
|
|
41790
41822
|
import { join as join16, resolve as resolve15 } from "node:path";
|
|
@@ -41839,6 +41871,7 @@ function composeDownArgs(plan, layout) {
|
|
|
41839
41871
|
}
|
|
41840
41872
|
function registerUninstallCommand(program2) {
|
|
41841
41873
|
program2.command("uninstall").description("Stop the stack; the index, chainstate, and keys survive").option("--compose <file>", `compose file to tear down (default: ./docker-compose.yml from setup, else ${REPO_COMPOSE})`).option("--purge", "also destroy the volumes (wipes the index)").option("--yes", "confirm a purge").option("--backup <dir>", "a bundle proving the keys exist elsewhere (required to purge)").option("--apply", "actually run it (default is a dry run)").option("--json", "Output as JSON").action(async (opts) => {
|
|
41874
|
+
assertInstanceUrl();
|
|
41842
41875
|
const dataDir = process.env.DATA_DIR ?? "./data";
|
|
41843
41876
|
const layout = resolveUninstallLayout(process.cwd(), opts.compose);
|
|
41844
41877
|
const secretsPresent = !!process.env.SECONDLAYER_SECRETS_KEY || !!layout.secretsFile;
|
|
@@ -41913,6 +41946,7 @@ function registerUninstallCommand(program2) {
|
|
|
41913
41946
|
// src/commands/backup.ts
|
|
41914
41947
|
init_fs();
|
|
41915
41948
|
init_output();
|
|
41949
|
+
init_resolve_auth();
|
|
41916
41950
|
import {
|
|
41917
41951
|
chmodSync as chmodSync2,
|
|
41918
41952
|
existsSync as existsSync10,
|
|
@@ -42222,10 +42256,10 @@ async function runRestore(opts) {
|
|
|
42222
42256
|
});
|
|
42223
42257
|
}
|
|
42224
42258
|
function registerBackupCommand(program2) {
|
|
42225
|
-
attachBackupCommand(program2.command("backup").description("Write a restorable bundle: index, keys, and scope"));
|
|
42259
|
+
attachBackupCommand(program2.command("backup").description("Write a restorable bundle: index, keys, and scope").hook("preAction", () => assertInstanceUrl()));
|
|
42226
42260
|
}
|
|
42227
42261
|
function registerRestoreCommand(program2) {
|
|
42228
|
-
attachRestoreCommand(program2.command("restore").description("Restore an instance from a backup bundle"));
|
|
42262
|
+
attachRestoreCommand(program2.command("restore").description("Restore an instance from a backup bundle").hook("preAction", () => assertInstanceUrl()));
|
|
42229
42263
|
}
|
|
42230
42264
|
// src/commands/init.ts
|
|
42231
42265
|
init_archive_reference();
|
|
@@ -42238,6 +42272,7 @@ function registerInitCommand(program2) {
|
|
|
42238
42272
|
--network <mainnet|testnet|devnet> and --api-url <url> are top-level global
|
|
42239
42273
|
flags (see \`secondlayer --help\`). Defaults: mainnet, http://127.0.0.1:3800.
|
|
42240
42274
|
`).action(async (opts) => {
|
|
42275
|
+
assertInstanceUrl();
|
|
42241
42276
|
const network = instanceNetworkFromEnv();
|
|
42242
42277
|
const existing = opts.force ? {} : loadExistingInstanceEnv(process.cwd());
|
|
42243
42278
|
const env2 = buildInstanceEnv({
|
|
@@ -42263,11 +42298,13 @@ flags (see \`secondlayer --help\`). Defaults: mainnet, http://127.0.0.1:3800.
|
|
|
42263
42298
|
init_instance_init();
|
|
42264
42299
|
init_observer_stanza();
|
|
42265
42300
|
init_output();
|
|
42301
|
+
init_resolve_auth();
|
|
42266
42302
|
function registerObserverCommand(program2) {
|
|
42267
42303
|
program2.command("observer").description("Print the Stacks events_observer stanza for this node mode").option("--mode <mode>", "indexer (retry) or signer-shared (no retry)", "indexer").option("--endpoint <host:port>", "Observer callback the node will POST to").option("--recovery <source>", "Required for signer-shared: journal or archive").addHelpText("after", `
|
|
42268
42304
|
--network <mainnet|testnet|devnet> is the top-level global flag (see
|
|
42269
42305
|
\`secondlayer --help\`) — default mainnet, same as before.
|
|
42270
42306
|
`).action((opts) => {
|
|
42307
|
+
assertInstanceUrl();
|
|
42271
42308
|
const mode = parseObserverMode(opts.mode);
|
|
42272
42309
|
const network = instanceNetworkFromEnv();
|
|
42273
42310
|
const endpoint = opts.endpoint ?? defaultObserverEndpoint(network);
|
|
@@ -42280,6 +42317,7 @@ function registerObserverCommand(program2) {
|
|
|
42280
42317
|
}
|
|
42281
42318
|
// src/commands/setup.ts
|
|
42282
42319
|
init_output();
|
|
42320
|
+
init_resolve_auth();
|
|
42283
42321
|
|
|
42284
42322
|
// src/lib/setup-prompts.ts
|
|
42285
42323
|
init_instance_init();
|
|
@@ -42486,6 +42524,7 @@ Without a TTY (piped, CI, an agent), or with --yes, the TUI is skipped: every
|
|
|
42486
42524
|
decision with no safe default (--network, --node-mode, and --against unless
|
|
42487
42525
|
--skip-bootstrap) must come from a flag or the command fails fast naming it.
|
|
42488
42526
|
`).action(async (opts) => {
|
|
42527
|
+
assertInstanceUrl();
|
|
42489
42528
|
const flags = {
|
|
42490
42529
|
...opts,
|
|
42491
42530
|
network: opts.network ?? process.env.STACKS_NETWORK
|
|
@@ -42509,18 +42548,19 @@ decision with no safe default (--network, --node-mode, and --against unless
|
|
|
42509
42548
|
});
|
|
42510
42549
|
}
|
|
42511
42550
|
// src/cli.ts
|
|
42551
|
+
init_resolve_auth();
|
|
42512
42552
|
var { version } = package_default;
|
|
42513
|
-
program.name("secondlayer").alias("sl").description("Secondlayer CLI — run a Stacks index on your own hardware").version(version).option("--network <network>", "Override network (mainnet, testnet, devnet)").option("--api-key <key>", "
|
|
42553
|
+
program.name("secondlayer").alias("sl").description("Secondlayer CLI — run a Stacks index on your own hardware").version(version).option("--network <network>", "Override network (mainnet, testnet, devnet)").option("--api-key <key>", "Credential for this invocation: INSTANCE_TOKEN (hex) for the instance, or sk-sl_* for hosted/archive. Prefer env. A flag lands in shell history and ps").option("--api-url <url>", "API endpoint (overrides SECONDLAYER_API_URL)").showSuggestionAfterError(true).showHelpAfterError("(run `secondlayer --help` to see available commands)");
|
|
42514
42554
|
program.hook("preAction", (thisCommand) => {
|
|
42515
42555
|
const { network, apiKey, apiUrl } = thisCommand.opts();
|
|
42516
42556
|
if (network)
|
|
42517
42557
|
process.env.STACKS_NETWORK = network;
|
|
42518
|
-
if (apiKey)
|
|
42519
|
-
|
|
42520
|
-
|
|
42521
|
-
|
|
42522
|
-
if (apiUrl)
|
|
42558
|
+
if (apiKey)
|
|
42559
|
+
applyApiKeyFlag(apiKey);
|
|
42560
|
+
if (apiUrl) {
|
|
42561
|
+
process.env.SECONDLAYER_API_URL = apiUrl;
|
|
42523
42562
|
process.env.SL_API_URL = apiUrl;
|
|
42563
|
+
}
|
|
42524
42564
|
});
|
|
42525
42565
|
program.addHelpText("after", `
|
|
42526
42566
|
Quickstart:
|
|
@@ -42566,5 +42606,5 @@ program.commandsGroup("Archive:");
|
|
|
42566
42606
|
registerCreditsCommand(program);
|
|
42567
42607
|
program.parse();
|
|
42568
42608
|
|
|
42569
|
-
//# debugId=
|
|
42609
|
+
//# debugId=CAE75BE93848EF8E64756E2164756E21
|
|
42570
42610
|
//# sourceMappingURL=cli.js.map
|