@secondlayer/cli 1.6.0 → 1.6.2
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 +163 -149
- package/dist/cli.js.map +20 -20
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2229,8 +2229,8 @@ function migrateConfig(raw) {
|
|
|
2229
2229
|
if (typeof old.dataDir === "string") {
|
|
2230
2230
|
migrated.dataDir = old.dataDir;
|
|
2231
2231
|
}
|
|
2232
|
-
if (typeof old.
|
|
2233
|
-
migrated.
|
|
2232
|
+
if (typeof old.defaultEndpointUrl === "string") {
|
|
2233
|
+
migrated.defaultEndpointUrl = old.defaultEndpointUrl;
|
|
2234
2234
|
}
|
|
2235
2235
|
if (typeof old.nodeInstallPath === "string" || typeof old.nodeNetwork === "string") {
|
|
2236
2236
|
migrated.node = {
|
|
@@ -2270,8 +2270,8 @@ async function loadConfig() {
|
|
|
2270
2270
|
}
|
|
2271
2271
|
}
|
|
2272
2272
|
config = applyEnvOverrides(config);
|
|
2273
|
-
if (!config.
|
|
2274
|
-
config.
|
|
2273
|
+
if (!config.defaultEndpointUrl && config.network === "local") {
|
|
2274
|
+
config.defaultEndpointUrl = LOCAL_ENDPOINT_URL;
|
|
2275
2275
|
}
|
|
2276
2276
|
return config;
|
|
2277
2277
|
}
|
|
@@ -2301,12 +2301,15 @@ function applyEnvOverrides(config) {
|
|
|
2301
2301
|
result.ports = { ...result.ports, indexer: port };
|
|
2302
2302
|
}
|
|
2303
2303
|
}
|
|
2304
|
-
if (process.env.
|
|
2305
|
-
const port = parseInt(process.env.
|
|
2304
|
+
if (process.env.SL_RECEIVER_PORT) {
|
|
2305
|
+
const port = parseInt(process.env.SL_RECEIVER_PORT, 10);
|
|
2306
2306
|
if (!isNaN(port) && port > 0 && port <= 65535) {
|
|
2307
|
-
result.ports = { ...result.ports,
|
|
2307
|
+
result.ports = { ...result.ports, receiver: port };
|
|
2308
2308
|
}
|
|
2309
2309
|
}
|
|
2310
|
+
if (process.env.STACKS_NODE_RPC_URL) {
|
|
2311
|
+
result.nodeRpcUrl = process.env.STACKS_NODE_RPC_URL;
|
|
2312
|
+
}
|
|
2310
2313
|
if (process.env.DATABASE_URL) {
|
|
2311
2314
|
result.database = { type: "external", url: process.env.DATABASE_URL };
|
|
2312
2315
|
}
|
|
@@ -2395,13 +2398,13 @@ function isDefaultValue(config, key) {
|
|
|
2395
2398
|
const defaultValue = getConfigValue(DEFAULT_CONFIG, key);
|
|
2396
2399
|
return JSON.stringify(currentValue) === JSON.stringify(defaultValue);
|
|
2397
2400
|
}
|
|
2398
|
-
var PortsSchema, NodeSchema, DatabaseSchema, NetworkSchema, API_URLS, ConfigSchema, CONFIG_DIR, CONFIG_PATH,
|
|
2401
|
+
var PortsSchema, NodeSchema, DatabaseSchema, NetworkSchema, API_URLS, ConfigSchema, CONFIG_DIR, CONFIG_PATH, LOCAL_ENDPOINT_URL = "http://localhost:3900/receiver", DEFAULT_CONFIG;
|
|
2399
2402
|
var init_config = __esm(() => {
|
|
2400
2403
|
init_fs();
|
|
2401
2404
|
PortsSchema = z.object({
|
|
2402
2405
|
api: z.number().int().min(1).max(65535).default(3800),
|
|
2403
2406
|
indexer: z.number().int().min(1).max(65535).default(3700),
|
|
2404
|
-
|
|
2407
|
+
receiver: z.number().int().min(1).max(65535).default(3900)
|
|
2405
2408
|
});
|
|
2406
2409
|
NodeSchema = z.object({
|
|
2407
2410
|
installPath: z.string().min(1),
|
|
@@ -2421,8 +2424,9 @@ var init_config = __esm(() => {
|
|
|
2421
2424
|
network: NetworkSchema.default("mainnet"),
|
|
2422
2425
|
apiUrl: z.string().url().optional(),
|
|
2423
2426
|
apiKey: z.string().optional(),
|
|
2427
|
+
nodeRpcUrl: z.string().url().optional(),
|
|
2424
2428
|
dataDir: z.string().default("~/.secondlayer/data"),
|
|
2425
|
-
|
|
2429
|
+
defaultEndpointUrl: z.string().url().optional(),
|
|
2426
2430
|
node: NodeSchema.optional(),
|
|
2427
2431
|
ports: PortsSchema.default({}),
|
|
2428
2432
|
database: DatabaseSchema.default({})
|
|
@@ -2432,7 +2436,7 @@ var init_config = __esm(() => {
|
|
|
2432
2436
|
DEFAULT_CONFIG = {
|
|
2433
2437
|
network: "mainnet",
|
|
2434
2438
|
dataDir: "~/.secondlayer/data",
|
|
2435
|
-
ports: { api: 3800, indexer: 3700,
|
|
2439
|
+
ports: { api: 3800, indexer: 3700, receiver: 3900 },
|
|
2436
2440
|
database: { type: "docker" }
|
|
2437
2441
|
};
|
|
2438
2442
|
});
|
|
@@ -12429,19 +12433,26 @@ function parseContractId(contractId) {
|
|
|
12429
12433
|
|
|
12430
12434
|
// src/utils/api.ts
|
|
12431
12435
|
class StacksApiClient {
|
|
12432
|
-
static hasWarnedAboutApiKey = false;
|
|
12433
12436
|
baseUrl;
|
|
12434
12437
|
headers;
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
this.
|
|
12438
|
-
if (
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12438
|
+
useProxy;
|
|
12439
|
+
constructor(network = "mainnet", apiKey, apiUrl, slApiUrl) {
|
|
12440
|
+
this.useProxy = !apiUrl && network !== "devnet";
|
|
12441
|
+
if (this.useProxy) {
|
|
12442
|
+
this.baseUrl = slApiUrl || "";
|
|
12443
|
+
this.headers = {};
|
|
12444
|
+
} else {
|
|
12445
|
+
this.baseUrl = apiUrl || process.env.STACKS_NODE_RPC_URL || "http://localhost:3999";
|
|
12446
|
+
this.headers = apiKey ? { "x-api-key": apiKey } : {};
|
|
12443
12447
|
}
|
|
12444
12448
|
}
|
|
12449
|
+
async ensureProxy() {
|
|
12450
|
+
if (!this.useProxy || this.baseUrl)
|
|
12451
|
+
return;
|
|
12452
|
+
const config = await loadConfig();
|
|
12453
|
+
this.baseUrl = resolveApiUrl(config);
|
|
12454
|
+
this.headers = authHeaders(config);
|
|
12455
|
+
}
|
|
12445
12456
|
async fetchWithErrorHandling(url, resourceType, resourceId) {
|
|
12446
12457
|
try {
|
|
12447
12458
|
const response2 = await gotWithRetry(url, {
|
|
@@ -12450,30 +12461,38 @@ class StacksApiClient {
|
|
|
12450
12461
|
});
|
|
12451
12462
|
return response2.body;
|
|
12452
12463
|
} catch (error2) {
|
|
12464
|
+
if (error2.response?.statusCode === 401) {
|
|
12465
|
+
throw new Error("Authentication required. Run: secondlayer auth login");
|
|
12466
|
+
}
|
|
12453
12467
|
if (error2.response?.statusCode === 404) {
|
|
12454
12468
|
throw new Error(`${resourceType} not found: ${resourceId}`);
|
|
12455
12469
|
}
|
|
12456
|
-
if (error2.response?.statusCode === 429) {
|
|
12457
|
-
throw new Error("Rate limited. Please provide an API key in your config.");
|
|
12458
|
-
}
|
|
12459
12470
|
throw new Error(`Failed to fetch ${resourceType.toLowerCase()}: ${error2.message}`);
|
|
12460
12471
|
}
|
|
12461
12472
|
}
|
|
12462
12473
|
async getContractInfo(contractId) {
|
|
12474
|
+
await this.ensureProxy();
|
|
12475
|
+
if (this.useProxy) {
|
|
12476
|
+
const url2 = `${this.baseUrl}/api/node/contracts/${contractId}/abi`;
|
|
12477
|
+
return this.fetchWithErrorHandling(url2, "Contract", contractId);
|
|
12478
|
+
}
|
|
12463
12479
|
const { address, contractName } = parseContractId(contractId);
|
|
12464
12480
|
const url = `${this.baseUrl}/v2/contracts/interface/${address}/${contractName}`;
|
|
12465
12481
|
return this.fetchWithErrorHandling(url, "Contract", contractId);
|
|
12466
12482
|
}
|
|
12467
12483
|
async getContractSource(contractId) {
|
|
12468
12484
|
const { address, contractName } = parseContractId(contractId);
|
|
12469
|
-
const
|
|
12485
|
+
const rpcUrl = process.env.STACKS_NODE_RPC_URL || this.baseUrl;
|
|
12486
|
+
const url = `${rpcUrl}/v2/contracts/source/${address}/${contractName}`;
|
|
12470
12487
|
const data = await this.fetchWithErrorHandling(url, "Contract source", contractId);
|
|
12471
12488
|
return data.source;
|
|
12472
12489
|
}
|
|
12473
12490
|
}
|
|
12474
|
-
var gotWithRetry
|
|
12491
|
+
var gotWithRetry;
|
|
12475
12492
|
var init_api = __esm(() => {
|
|
12476
12493
|
init_source3();
|
|
12494
|
+
init_config();
|
|
12495
|
+
init_api_client();
|
|
12477
12496
|
gotWithRetry = source_default2.extend({
|
|
12478
12497
|
timeout: { request: 30000 },
|
|
12479
12498
|
retry: {
|
|
@@ -12483,11 +12502,6 @@ var init_api = __esm(() => {
|
|
|
12483
12502
|
calculateDelay: ({ attemptCount }) => attemptCount * 1000
|
|
12484
12503
|
}
|
|
12485
12504
|
});
|
|
12486
|
-
API_URLS2 = {
|
|
12487
|
-
mainnet: "https://api.hiro.so",
|
|
12488
|
-
testnet: "https://api.testnet.hiro.so",
|
|
12489
|
-
devnet: "http://localhost:3999"
|
|
12490
|
-
};
|
|
12491
12505
|
});
|
|
12492
12506
|
|
|
12493
12507
|
// src/utils/network.ts
|
|
@@ -13189,9 +13203,9 @@ var init_api2 = __esm(() => {
|
|
|
13189
13203
|
init_manager();
|
|
13190
13204
|
});
|
|
13191
13205
|
|
|
13192
|
-
// src/services/
|
|
13206
|
+
// src/services/receiver-server.ts
|
|
13193
13207
|
import { verifySignatureHeader } from "@secondlayer/shared/crypto";
|
|
13194
|
-
function
|
|
13208
|
+
function startReceiverServer(options2 = {}) {
|
|
13195
13209
|
const port = options2.port ?? 3900;
|
|
13196
13210
|
const responseCode = options2.responseCode ?? 200;
|
|
13197
13211
|
server = Bun.serve({
|
|
@@ -13230,27 +13244,27 @@ function startWebhookServer(options2 = {}) {
|
|
|
13230
13244
|
body,
|
|
13231
13245
|
signatureValid
|
|
13232
13246
|
};
|
|
13233
|
-
if (options2.
|
|
13234
|
-
options2.
|
|
13247
|
+
if (options2.onDelivery) {
|
|
13248
|
+
options2.onDelivery(event);
|
|
13235
13249
|
} else {
|
|
13236
|
-
|
|
13250
|
+
logDelivery(event);
|
|
13237
13251
|
}
|
|
13238
13252
|
return new Response("OK", { status: responseCode });
|
|
13239
13253
|
}
|
|
13240
13254
|
});
|
|
13241
13255
|
return port;
|
|
13242
13256
|
}
|
|
13243
|
-
function
|
|
13257
|
+
function stopReceiverServer() {
|
|
13244
13258
|
if (server) {
|
|
13245
13259
|
server.stop();
|
|
13246
13260
|
server = null;
|
|
13247
13261
|
}
|
|
13248
13262
|
}
|
|
13249
|
-
function
|
|
13263
|
+
function logDelivery(event) {
|
|
13250
13264
|
const time = event.timestamp.toISOString();
|
|
13251
13265
|
console.log("");
|
|
13252
13266
|
console.log(blue("━".repeat(60)));
|
|
13253
|
-
console.log(green("⚡
|
|
13267
|
+
console.log(green("⚡ Delivery received"));
|
|
13254
13268
|
console.log(dim(` ${time}`));
|
|
13255
13269
|
console.log(dim(` ${event.method} ${event.path}`));
|
|
13256
13270
|
if (event.signatureValid === true) {
|
|
@@ -13272,7 +13286,7 @@ function logWebhook(event) {
|
|
|
13272
13286
|
console.log(blue("━".repeat(60)));
|
|
13273
13287
|
}
|
|
13274
13288
|
var server = null;
|
|
13275
|
-
var
|
|
13289
|
+
var init_receiver_server = __esm(() => {
|
|
13276
13290
|
init_output();
|
|
13277
13291
|
});
|
|
13278
13292
|
|
|
@@ -13300,7 +13314,7 @@ var init_services = __esm(() => {
|
|
|
13300
13314
|
init_indexer();
|
|
13301
13315
|
init_worker();
|
|
13302
13316
|
init_api2();
|
|
13303
|
-
|
|
13317
|
+
init_receiver_server();
|
|
13304
13318
|
init_subgraph_processor();
|
|
13305
13319
|
});
|
|
13306
13320
|
|
|
@@ -13344,7 +13358,7 @@ async function runBackground(options2) {
|
|
|
13344
13358
|
const dataDir = getDataDir(config);
|
|
13345
13359
|
const indexerPort = options2.stacksNode ? 3701 : parseInt(options2.indexerPort) || config.ports.indexer;
|
|
13346
13360
|
const apiPort = parseInt(options2.apiPort) || config.ports.api;
|
|
13347
|
-
const
|
|
13361
|
+
const receiverPort = parseInt(options2.receiverPort) || config.ports.receiver;
|
|
13348
13362
|
if (options2.stacksNode && config.node) {
|
|
13349
13363
|
const validation = await validateNetworkConsistency(config);
|
|
13350
13364
|
if (!validation.valid) {
|
|
@@ -13454,24 +13468,24 @@ async function runBackground(options2) {
|
|
|
13454
13468
|
};
|
|
13455
13469
|
console.log(green(" ✓ Subgraph processor"), dim("processing subgraphs"));
|
|
13456
13470
|
}
|
|
13457
|
-
if (options2.
|
|
13458
|
-
const
|
|
13459
|
-
const
|
|
13460
|
-
const
|
|
13471
|
+
if (options2.receiver) {
|
|
13472
|
+
const receiverLogFile = getLogFile("receiver");
|
|
13473
|
+
const receiverArgs = ["bun", "run", resolve6(packagesDir, "packages/cli/src/services/receiver-standalone.ts")];
|
|
13474
|
+
const receiverEnv = { ...process.env, PORT: String(receiverPort) };
|
|
13461
13475
|
if (options2.secret)
|
|
13462
|
-
|
|
13463
|
-
const
|
|
13464
|
-
env:
|
|
13465
|
-
stdout: Bun.file(
|
|
13466
|
-
stderr: Bun.file(
|
|
13476
|
+
receiverEnv.SIGNING_SECRET = options2.secret;
|
|
13477
|
+
const receiverProc = Bun.spawn(receiverArgs, {
|
|
13478
|
+
env: receiverEnv,
|
|
13479
|
+
stdout: Bun.file(receiverLogFile),
|
|
13480
|
+
stderr: Bun.file(receiverLogFile)
|
|
13467
13481
|
});
|
|
13468
|
-
state.services.
|
|
13469
|
-
pid:
|
|
13470
|
-
port:
|
|
13482
|
+
state.services.receiver = {
|
|
13483
|
+
pid: receiverProc.pid,
|
|
13484
|
+
port: receiverPort,
|
|
13471
13485
|
startedAt: new Date().toISOString(),
|
|
13472
|
-
logFile:
|
|
13486
|
+
logFile: receiverLogFile
|
|
13473
13487
|
};
|
|
13474
|
-
console.log(green(" ✓
|
|
13488
|
+
console.log(green(" ✓ Receiver server"), dim(`http://localhost:${receiverPort}`));
|
|
13475
13489
|
}
|
|
13476
13490
|
await Bun.sleep(500);
|
|
13477
13491
|
for (const [name, service] of Object.entries(state.services)) {
|
|
@@ -13481,7 +13495,7 @@ async function runBackground(options2) {
|
|
|
13481
13495
|
}
|
|
13482
13496
|
await saveDevState(state);
|
|
13483
13497
|
console.log("");
|
|
13484
|
-
printUrls(indexerPort, apiPort,
|
|
13498
|
+
printUrls(indexerPort, apiPort, receiverPort, options2.receiver);
|
|
13485
13499
|
console.log("");
|
|
13486
13500
|
success("Dev environment started in background");
|
|
13487
13501
|
console.log("");
|
|
@@ -13519,14 +13533,14 @@ async function runForeground(options2) {
|
|
|
13519
13533
|
const dataDir = getDataDir(config);
|
|
13520
13534
|
const indexerPort = options2.stacksNode ? 3701 : parseInt(options2.indexerPort) || config.ports.indexer;
|
|
13521
13535
|
const apiPort = parseInt(options2.apiPort) || config.ports.api;
|
|
13522
|
-
const
|
|
13536
|
+
const receiverPort = parseInt(options2.receiverPort) || config.ports.receiver;
|
|
13523
13537
|
let devPostgresStarted = false;
|
|
13524
13538
|
const shutdown = async () => {
|
|
13525
13539
|
console.log(`
|
|
13526
13540
|
`);
|
|
13527
13541
|
info("Shutting down services...");
|
|
13528
|
-
if (options2.
|
|
13529
|
-
|
|
13542
|
+
if (options2.receiver) {
|
|
13543
|
+
stopReceiverServer();
|
|
13530
13544
|
}
|
|
13531
13545
|
await serviceManager.stopAll();
|
|
13532
13546
|
if (devPostgresStarted) {
|
|
@@ -13573,9 +13587,9 @@ async function runForeground(options2) {
|
|
|
13573
13587
|
console.log("");
|
|
13574
13588
|
}
|
|
13575
13589
|
process.env.DEV_MODE = "true";
|
|
13576
|
-
if (options2.
|
|
13577
|
-
|
|
13578
|
-
console.log(green(" ✓
|
|
13590
|
+
if (options2.receiver) {
|
|
13591
|
+
startReceiverServer({ port: receiverPort, secret: options2.secret });
|
|
13592
|
+
console.log(green(" ✓ Receiver server"), dim(`http://localhost:${receiverPort}`));
|
|
13579
13593
|
}
|
|
13580
13594
|
await startApi({ port: apiPort, onLog: (line) => logService("api", line) });
|
|
13581
13595
|
console.log(green(" ✓ API"), dim(`http://localhost:${apiPort}`));
|
|
@@ -13588,7 +13602,7 @@ async function runForeground(options2) {
|
|
|
13588
13602
|
await startSubgraphProcessor({ onLog: (line) => logService("subgraphs", line) });
|
|
13589
13603
|
console.log(green(" ✓ Subgraph processor"), dim("processing subgraphs"));
|
|
13590
13604
|
console.log("");
|
|
13591
|
-
printUrls(indexerPort, apiPort,
|
|
13605
|
+
printUrls(indexerPort, apiPort, receiverPort, options2.receiver);
|
|
13592
13606
|
console.log("");
|
|
13593
13607
|
info("Press Ctrl+C to stop all services");
|
|
13594
13608
|
console.log("");
|
|
@@ -13596,8 +13610,8 @@ async function runForeground(options2) {
|
|
|
13596
13610
|
} catch (err) {
|
|
13597
13611
|
error(`Failed to start services: ${err}`);
|
|
13598
13612
|
await serviceManager.stopAll();
|
|
13599
|
-
if (options2.
|
|
13600
|
-
|
|
13613
|
+
if (options2.receiver) {
|
|
13614
|
+
stopReceiverServer();
|
|
13601
13615
|
}
|
|
13602
13616
|
process.exit(1);
|
|
13603
13617
|
}
|
|
@@ -13628,10 +13642,10 @@ async function showLogs(options2) {
|
|
|
13628
13642
|
await showStaticLogs(serviceEntries, lines, verbose);
|
|
13629
13643
|
}
|
|
13630
13644
|
}
|
|
13631
|
-
function
|
|
13645
|
+
function formatDeliverySummary(jsonStr) {
|
|
13632
13646
|
try {
|
|
13633
13647
|
const data = JSON.parse(jsonStr);
|
|
13634
|
-
if (data.type !== "
|
|
13648
|
+
if (data.type !== "delivery" || !data.body)
|
|
13635
13649
|
return null;
|
|
13636
13650
|
const { body, method, path, timestamp } = data;
|
|
13637
13651
|
const streamName = body.streamName ?? body.streamId?.slice(0, 8) ?? "unknown";
|
|
@@ -13661,8 +13675,8 @@ function formatLogLine2(service, line, verbose) {
|
|
|
13661
13675
|
return `${prefix} ${dimTimestamp} ${dim(level + ":")} ${dim(message)}`;
|
|
13662
13676
|
}
|
|
13663
13677
|
}
|
|
13664
|
-
if (service === "
|
|
13665
|
-
const summary =
|
|
13678
|
+
if (service === "receiver" && !verbose) {
|
|
13679
|
+
const summary = formatDeliverySummary(line);
|
|
13666
13680
|
if (summary)
|
|
13667
13681
|
return `${prefix} ${summary}`;
|
|
13668
13682
|
}
|
|
@@ -13838,21 +13852,21 @@ async function restartDev() {
|
|
|
13838
13852
|
};
|
|
13839
13853
|
console.log(green(" ✓ Worker"), dim("processing jobs"));
|
|
13840
13854
|
}
|
|
13841
|
-
if (state.services.
|
|
13842
|
-
const
|
|
13843
|
-
const
|
|
13844
|
-
const
|
|
13845
|
-
env: { ...process.env, PORT: String(
|
|
13846
|
-
stdout: Bun.file(
|
|
13847
|
-
stderr: Bun.file(
|
|
13855
|
+
if (state.services.receiver) {
|
|
13856
|
+
const receiverPort = config.ports.receiver;
|
|
13857
|
+
const receiverLogFile = getLogFile("receiver");
|
|
13858
|
+
const receiverProc = Bun.spawn(["bun", "run", resolve6(packagesDir, "packages/cli/src/services/receiver-standalone.ts")], {
|
|
13859
|
+
env: { ...process.env, PORT: String(receiverPort) },
|
|
13860
|
+
stdout: Bun.file(receiverLogFile),
|
|
13861
|
+
stderr: Bun.file(receiverLogFile)
|
|
13848
13862
|
});
|
|
13849
|
-
newState.services.
|
|
13850
|
-
pid:
|
|
13851
|
-
port:
|
|
13863
|
+
newState.services.receiver = {
|
|
13864
|
+
pid: receiverProc.pid,
|
|
13865
|
+
port: receiverPort,
|
|
13852
13866
|
startedAt: new Date().toISOString(),
|
|
13853
|
-
logFile:
|
|
13867
|
+
logFile: receiverLogFile
|
|
13854
13868
|
};
|
|
13855
|
-
console.log(green(" ✓
|
|
13869
|
+
console.log(green(" ✓ Receiver server"), dim(`http://localhost:${receiverPort}`));
|
|
13856
13870
|
}
|
|
13857
13871
|
if (state.services.subgraphs) {
|
|
13858
13872
|
const subgraphsLogFile = getLogFile("subgraphs");
|
|
@@ -13928,7 +13942,7 @@ function printBanner2() {
|
|
|
13928
13942
|
console.log(dim(" Starting services..."));
|
|
13929
13943
|
console.log("");
|
|
13930
13944
|
}
|
|
13931
|
-
function printUrls(indexerPort, apiPort,
|
|
13945
|
+
function printUrls(indexerPort, apiPort, receiverPort, receiverEnabled) {
|
|
13932
13946
|
console.log(dim(" ─────────────────────────────────────────"));
|
|
13933
13947
|
console.log("");
|
|
13934
13948
|
console.log(" " + blue("API:"));
|
|
@@ -13939,9 +13953,9 @@ function printUrls(indexerPort, apiPort, webhookPort, webhookEnabled) {
|
|
|
13939
13953
|
console.log(` Health check: curl http://localhost:${indexerPort}/health`);
|
|
13940
13954
|
console.log(` Send block: curl -X POST http://localhost:${indexerPort}/new_block -d @block.json`);
|
|
13941
13955
|
console.log("");
|
|
13942
|
-
if (
|
|
13943
|
-
console.log(" " + blue("Test
|
|
13944
|
-
console.log(` Receives
|
|
13956
|
+
if (receiverEnabled) {
|
|
13957
|
+
console.log(" " + blue("Test Receiver:"));
|
|
13958
|
+
console.log(` Receives deliveries at http://localhost:${receiverPort}/`);
|
|
13945
13959
|
console.log(` Use this URL when creating streams for testing`);
|
|
13946
13960
|
console.log("");
|
|
13947
13961
|
}
|
|
@@ -14018,7 +14032,7 @@ var init_dev_impl = __esm(() => {
|
|
|
14018
14032
|
indexer: cyan,
|
|
14019
14033
|
worker: yellow,
|
|
14020
14034
|
subgraphs: magenta,
|
|
14021
|
-
|
|
14035
|
+
receiver: green
|
|
14022
14036
|
};
|
|
14023
14037
|
});
|
|
14024
14038
|
|
|
@@ -32538,7 +32552,7 @@ var {
|
|
|
32538
32552
|
// package.json
|
|
32539
32553
|
var package_default = {
|
|
32540
32554
|
name: "@secondlayer/cli",
|
|
32541
|
-
version: "1.6.
|
|
32555
|
+
version: "1.6.2",
|
|
32542
32556
|
description: "CLI for streams, subgraphs, and real-time blockchain indexing on Stacks",
|
|
32543
32557
|
type: "module",
|
|
32544
32558
|
bin: {
|
|
@@ -32930,7 +32944,7 @@ async function printConfigTree(cfg) {
|
|
|
32930
32944
|
console.log(blue("ports:"));
|
|
32931
32945
|
printValue(" api", cfg.ports.api, cfg.ports.api === defaults.ports.api, 2);
|
|
32932
32946
|
printValue(" indexer", cfg.ports.indexer, cfg.ports.indexer === defaults.ports.indexer, 2);
|
|
32933
|
-
printValue("
|
|
32947
|
+
printValue(" receiver", cfg.ports.receiver, cfg.ports.receiver === defaults.ports.receiver, 2);
|
|
32934
32948
|
console.log("");
|
|
32935
32949
|
console.log(blue("database:"));
|
|
32936
32950
|
printValue(" type", cfg.database.type, cfg.database.type === "docker", 2);
|
|
@@ -32976,13 +32990,13 @@ import { select as select2, input, confirm } from "@inquirer/prompts";
|
|
|
32976
32990
|
init_config();
|
|
32977
32991
|
var STREAMS_DIR = "streams";
|
|
32978
32992
|
function registerSetupCommand(program2) {
|
|
32979
|
-
program2.command("setup").description("Set up a streams project and configure settings").option("--detect-only", "Only detect existing Stacks nodes, don't initialize").option("-y, --yes", "Use defaults without prompts").option("--data-dir <path>", "Data directory path").option("--node-path <path>", "Path to Stacks node").option("--network <network>", "Network (local, testnet, or mainnet)").option("--
|
|
32993
|
+
program2.command("setup").description("Set up a streams project and configure settings").option("--detect-only", "Only detect existing Stacks nodes, don't initialize").option("-y, --yes", "Use defaults without prompts").option("--data-dir <path>", "Data directory path").option("--node-path <path>", "Path to Stacks node").option("--network <network>", "Network (local, testnet, or mainnet)").option("--endpoint-url <url>", "Default endpoint URL for new streams").action(async (options) => {
|
|
32980
32994
|
try {
|
|
32981
32995
|
if (options.detectOnly) {
|
|
32982
32996
|
await runDetection();
|
|
32983
32997
|
return;
|
|
32984
32998
|
}
|
|
32985
|
-
const hasFlags = options.yes || options.dataDir || options.nodePath || options.network || options.
|
|
32999
|
+
const hasFlags = options.yes || options.dataDir || options.nodePath || options.network || options.endpointUrl;
|
|
32986
33000
|
if (hasFlags) {
|
|
32987
33001
|
await runNonInteractive(options);
|
|
32988
33002
|
return;
|
|
@@ -33011,7 +33025,7 @@ async function runNonInteractive(options) {
|
|
|
33011
33025
|
return;
|
|
33012
33026
|
}
|
|
33013
33027
|
config.dataDir = options.dataDir || config.dataDir || "~/.secondlayer/data";
|
|
33014
|
-
config.
|
|
33028
|
+
config.defaultEndpointUrl = options.endpointUrl || config.defaultEndpointUrl;
|
|
33015
33029
|
if (options.nodePath) {
|
|
33016
33030
|
config.node = {
|
|
33017
33031
|
installPath: options.nodePath,
|
|
@@ -33055,8 +33069,8 @@ async function runWizard() {
|
|
|
33055
33069
|
if (nodeConfig) {
|
|
33056
33070
|
config.node = nodeConfig;
|
|
33057
33071
|
}
|
|
33058
|
-
const
|
|
33059
|
-
config.
|
|
33072
|
+
const endpointUrl = await promptEndpointUrl(config);
|
|
33073
|
+
config.defaultEndpointUrl = endpointUrl;
|
|
33060
33074
|
await saveConfig(config);
|
|
33061
33075
|
await Bun.$`mkdir -p ${STREAMS_DIR}`.quiet();
|
|
33062
33076
|
await Bun.write(`${STREAMS_DIR}/.gitkeep`, "");
|
|
@@ -33183,10 +33197,10 @@ async function promptNetwork() {
|
|
|
33183
33197
|
});
|
|
33184
33198
|
return network;
|
|
33185
33199
|
}
|
|
33186
|
-
async function
|
|
33187
|
-
const internalUrl = "http://localhost:3900/
|
|
33200
|
+
async function promptEndpointUrl(config) {
|
|
33201
|
+
const internalUrl = "http://localhost:3900/receiver";
|
|
33188
33202
|
const choice = await select2({
|
|
33189
|
-
message: "Default
|
|
33203
|
+
message: "Default endpoint URL for new streams?",
|
|
33190
33204
|
choices: [
|
|
33191
33205
|
{ name: `Internal test server (${internalUrl})`, value: "internal" },
|
|
33192
33206
|
{ name: "Custom URL...", value: "custom" }
|
|
@@ -33196,8 +33210,8 @@ async function promptWebhookUrl(config) {
|
|
|
33196
33210
|
return internalUrl;
|
|
33197
33211
|
}
|
|
33198
33212
|
const customUrl = await input({
|
|
33199
|
-
message: "Enter
|
|
33200
|
-
default: config.
|
|
33213
|
+
message: "Enter endpoint URL:",
|
|
33214
|
+
default: config.defaultEndpointUrl !== internalUrl ? config.defaultEndpointUrl : undefined,
|
|
33201
33215
|
validate: (value) => {
|
|
33202
33216
|
if (!value.trim())
|
|
33203
33217
|
return "URL cannot be empty";
|
|
@@ -33295,8 +33309,8 @@ function printSummary(config) {
|
|
|
33295
33309
|
console.log();
|
|
33296
33310
|
console.log(" Settings:");
|
|
33297
33311
|
console.log(` Data directory: ${config.dataDir}`);
|
|
33298
|
-
if (config.
|
|
33299
|
-
console.log(`
|
|
33312
|
+
if (config.defaultEndpointUrl) {
|
|
33313
|
+
console.log(` Endpoint URL: ${config.defaultEndpointUrl}`);
|
|
33300
33314
|
}
|
|
33301
33315
|
if (config.node) {
|
|
33302
33316
|
console.log(` Node path: ${config.node.installPath}`);
|
|
@@ -33345,10 +33359,10 @@ function printNodeInfo(node) {
|
|
|
33345
33359
|
import { join as join3 } from "node:path";
|
|
33346
33360
|
|
|
33347
33361
|
// src/templates/stream.ts
|
|
33348
|
-
function generateStreamTemplate(name,
|
|
33362
|
+
function generateStreamTemplate(name, endpointUrl) {
|
|
33349
33363
|
return {
|
|
33350
33364
|
name,
|
|
33351
|
-
|
|
33365
|
+
endpointUrl: endpointUrl || "https://example.com/endpoint",
|
|
33352
33366
|
filters: [
|
|
33353
33367
|
{
|
|
33354
33368
|
type: "contract_call",
|
|
@@ -33384,12 +33398,12 @@ function registerNewCommand(program2) {
|
|
|
33384
33398
|
if (dir) {
|
|
33385
33399
|
await ensureDir(dir);
|
|
33386
33400
|
}
|
|
33387
|
-
const template = generateStreamTemplate(name, config.
|
|
33401
|
+
const template = generateStreamTemplate(name, config.defaultEndpointUrl);
|
|
33388
33402
|
await writeTextFile(outputPath, JSON.stringify(template, null, 2) + `
|
|
33389
33403
|
`);
|
|
33390
33404
|
success(`Created ${outputPath}`);
|
|
33391
|
-
if (!config.
|
|
33392
|
-
warn("Edit the
|
|
33405
|
+
if (!config.defaultEndpointUrl) {
|
|
33406
|
+
warn("Edit the endpointUrl before registering — it must be a reachable HTTPS endpoint");
|
|
33393
33407
|
}
|
|
33394
33408
|
console.log(`
|
|
33395
33409
|
Edit the file to configure your stream, then run:`);
|
|
@@ -33452,7 +33466,7 @@ function registerGetCommand(program2) {
|
|
|
33452
33466
|
["ID", stream.id],
|
|
33453
33467
|
["Name", stream.name],
|
|
33454
33468
|
["Status", statusColor(stream.status)],
|
|
33455
|
-
["
|
|
33469
|
+
["Endpoint URL", stream.endpointUrl],
|
|
33456
33470
|
["Total Deliveries", stream.totalDeliveries.toString()],
|
|
33457
33471
|
["Failed Deliveries", stream.failedDeliveries.toString()],
|
|
33458
33472
|
["Last Triggered", stream.lastTriggeredAt || dim("never")],
|
|
@@ -33520,10 +33534,10 @@ function registerRegisterCommand(program2) {
|
|
|
33520
33534
|
console.log(formatKeyValue([
|
|
33521
33535
|
["ID", result.stream.id],
|
|
33522
33536
|
["Name", result.stream.name],
|
|
33523
|
-
["
|
|
33537
|
+
["Signing Secret", result.signingSecret]
|
|
33524
33538
|
]));
|
|
33525
33539
|
console.log(dim(`
|
|
33526
|
-
Save the
|
|
33540
|
+
Save the signing secret - it won't be shown again!`));
|
|
33527
33541
|
} catch (err) {
|
|
33528
33542
|
handleApiError(err, "register stream");
|
|
33529
33543
|
}
|
|
@@ -34019,12 +34033,12 @@ init_api_client();
|
|
|
34019
34033
|
init_output();
|
|
34020
34034
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
34021
34035
|
function registerRotateSecretCommand(program2) {
|
|
34022
|
-
program2.command("rotate-secret <id>").description("Generate a new
|
|
34036
|
+
program2.command("rotate-secret <id>").description("Generate a new signing secret for a stream").option("-y, --yes", "Skip confirmation prompt").action(async (id, options) => {
|
|
34023
34037
|
try {
|
|
34024
34038
|
const stream = await getStream(id);
|
|
34025
34039
|
if (!options.yes) {
|
|
34026
34040
|
const confirmed = await confirm3({
|
|
34027
|
-
message: `Rotate
|
|
34041
|
+
message: `Rotate signing secret for "${stream.name}"? The current secret will be invalidated.`,
|
|
34028
34042
|
default: false
|
|
34029
34043
|
});
|
|
34030
34044
|
if (!confirmed) {
|
|
@@ -34033,13 +34047,13 @@ function registerRotateSecretCommand(program2) {
|
|
|
34033
34047
|
}
|
|
34034
34048
|
}
|
|
34035
34049
|
const result = await rotateSecret(stream.id);
|
|
34036
|
-
success(`Rotated
|
|
34050
|
+
success(`Rotated signing secret for: ${stream.name}`);
|
|
34037
34051
|
console.log(formatKeyValue([
|
|
34038
34052
|
["Stream", stream.name],
|
|
34039
|
-
["
|
|
34053
|
+
["Signing Secret", result.secret]
|
|
34040
34054
|
]));
|
|
34041
34055
|
console.log(dim(`
|
|
34042
|
-
Save the
|
|
34056
|
+
Save the signing secret - it won't be shown again!`));
|
|
34043
34057
|
} catch (err) {
|
|
34044
34058
|
handleApiError(err, "rotate secret");
|
|
34045
34059
|
}
|
|
@@ -34722,15 +34736,15 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
34722
34736
|
process.exit(1);
|
|
34723
34737
|
}
|
|
34724
34738
|
}
|
|
34725
|
-
// src/commands/
|
|
34739
|
+
// src/commands/receiver.ts
|
|
34726
34740
|
init_output();
|
|
34727
34741
|
init_config();
|
|
34728
34742
|
import { join as join5 } from "node:path";
|
|
34729
|
-
function
|
|
34730
|
-
const
|
|
34743
|
+
function registerReceiverCommand(program2) {
|
|
34744
|
+
const receiver = program2.command("receiver").description("Receiver development tools").hook("preAction", async () => {
|
|
34731
34745
|
await requireLocalNetwork();
|
|
34732
34746
|
});
|
|
34733
|
-
|
|
34747
|
+
receiver.command("init <directory>").description("Scaffold a receiver handler with types and signature verification").option("-n, --name <name>", "Stream name", "my-stream").option("--network <network>", "Network (mainnet/testnet)", "mainnet").option("-p, --port <port>", "Server port", "4000").action(async (directory, options) => {
|
|
34734
34748
|
try {
|
|
34735
34749
|
const config = await loadConfig();
|
|
34736
34750
|
const port = parseInt(options.port);
|
|
@@ -34744,13 +34758,13 @@ function registerWebhookCommand(program2) {
|
|
|
34744
34758
|
await Bun.$`mkdir -p ${dir}`.quiet();
|
|
34745
34759
|
await generateServerFile(dir, port);
|
|
34746
34760
|
await generateTypesFile(dir);
|
|
34747
|
-
await generateStreamJson(dir, options.name, network, port, config.
|
|
34761
|
+
await generateStreamJson(dir, options.name, network, port, config.defaultEndpointUrl);
|
|
34748
34762
|
await generateEnvFile(dir);
|
|
34749
34763
|
await generatePackageJson(dir, options.name);
|
|
34750
|
-
success(`Created
|
|
34764
|
+
success(`Created receiver handler in ${directory}/`);
|
|
34751
34765
|
console.log("");
|
|
34752
34766
|
console.log(" Files created:");
|
|
34753
|
-
console.log(` ${dim("server.ts")}
|
|
34767
|
+
console.log(` ${dim("server.ts")} Receiver server with HMAC verification`);
|
|
34754
34768
|
console.log(` ${dim("types.ts")} Payload type definitions`);
|
|
34755
34769
|
console.log(` ${dim("stream.json")} Stream configuration`);
|
|
34756
34770
|
console.log(` ${dim(".env")} Environment variables`);
|
|
@@ -34765,26 +34779,26 @@ function registerWebhookCommand(program2) {
|
|
|
34765
34779
|
console.log(` sl streams register ${directory}/stream.json`);
|
|
34766
34780
|
console.log("");
|
|
34767
34781
|
} catch (err) {
|
|
34768
|
-
error(`Failed to scaffold
|
|
34782
|
+
error(`Failed to scaffold receiver: ${err}`);
|
|
34769
34783
|
process.exit(1);
|
|
34770
34784
|
}
|
|
34771
34785
|
});
|
|
34772
34786
|
}
|
|
34773
34787
|
async function generateServerFile(dir, port) {
|
|
34774
|
-
const content = `import type {
|
|
34788
|
+
const content = `import type { DeliveryPayload } from "./types.ts";
|
|
34775
34789
|
|
|
34776
|
-
const
|
|
34790
|
+
const SIGNING_SECRET = process.env.STREAMS_SIGNING_SECRET;
|
|
34777
34791
|
|
|
34778
34792
|
/**
|
|
34779
34793
|
* Verify HMAC signature from Stacks Streams
|
|
34780
34794
|
*/
|
|
34781
34795
|
async function verifySignature(body: string, signature: string | null): Promise<boolean> {
|
|
34782
|
-
if (!
|
|
34796
|
+
if (!SIGNING_SECRET || !signature) return false;
|
|
34783
34797
|
|
|
34784
34798
|
const encoder = new TextEncoder();
|
|
34785
34799
|
const key = await crypto.subtle.importKey(
|
|
34786
34800
|
"raw",
|
|
34787
|
-
encoder.encode(
|
|
34801
|
+
encoder.encode(SIGNING_SECRET),
|
|
34788
34802
|
{ name: "HMAC", hash: "SHA-256" },
|
|
34789
34803
|
false,
|
|
34790
34804
|
["sign"]
|
|
@@ -34797,9 +34811,9 @@ async function verifySignature(body: string, signature: string | null): Promise<
|
|
|
34797
34811
|
}
|
|
34798
34812
|
|
|
34799
34813
|
/**
|
|
34800
|
-
* Handle incoming
|
|
34814
|
+
* Handle incoming delivery payload
|
|
34801
34815
|
*/
|
|
34802
|
-
async function handlePayload(payload:
|
|
34816
|
+
async function handlePayload(payload: DeliveryPayload): Promise<void> {
|
|
34803
34817
|
console.log(\`Block \${payload.block.height}: \${payload.matches.events.length} events\`);
|
|
34804
34818
|
|
|
34805
34819
|
for (const event of payload.matches.events) {
|
|
@@ -34838,13 +34852,13 @@ Bun.serve({
|
|
|
34838
34852
|
return new Response("ok");
|
|
34839
34853
|
}
|
|
34840
34854
|
|
|
34841
|
-
//
|
|
34855
|
+
// Receiver endpoint
|
|
34842
34856
|
if (req.method === "POST" && url.pathname === "/payload") {
|
|
34843
34857
|
const body = await req.text();
|
|
34844
34858
|
const signature = req.headers.get("x-streams-signature");
|
|
34845
34859
|
|
|
34846
34860
|
// Verify signature
|
|
34847
|
-
if (
|
|
34861
|
+
if (SIGNING_SECRET) {
|
|
34848
34862
|
const valid = await verifySignature(body, signature);
|
|
34849
34863
|
if (!valid) {
|
|
34850
34864
|
console.error("Invalid signature");
|
|
@@ -34853,7 +34867,7 @@ Bun.serve({
|
|
|
34853
34867
|
}
|
|
34854
34868
|
|
|
34855
34869
|
try {
|
|
34856
|
-
const payload:
|
|
34870
|
+
const payload: DeliveryPayload = JSON.parse(body);
|
|
34857
34871
|
await handlePayload(payload);
|
|
34858
34872
|
return new Response("ok");
|
|
34859
34873
|
} catch (err) {
|
|
@@ -34866,18 +34880,18 @@ Bun.serve({
|
|
|
34866
34880
|
},
|
|
34867
34881
|
});
|
|
34868
34882
|
|
|
34869
|
-
console.log(\`
|
|
34883
|
+
console.log(\`Receiver server listening on http://localhost:${port}/payload\`);
|
|
34870
34884
|
`;
|
|
34871
34885
|
await Bun.write(join5(dir, "server.ts"), content);
|
|
34872
34886
|
}
|
|
34873
34887
|
async function generateTypesFile(dir) {
|
|
34874
34888
|
const content = `/**
|
|
34875
|
-
* Stacks Streams
|
|
34889
|
+
* Stacks Streams Delivery Payload Types
|
|
34876
34890
|
*
|
|
34877
34891
|
* These types match the payload structure sent by Stacks Streams.
|
|
34878
34892
|
*/
|
|
34879
34893
|
|
|
34880
|
-
export interface
|
|
34894
|
+
export interface DeliveryPayload {
|
|
34881
34895
|
streamId: string;
|
|
34882
34896
|
streamName: string;
|
|
34883
34897
|
network: "mainnet" | "testnet";
|
|
@@ -34999,11 +35013,11 @@ export function isPrintEvent(event: EventMatch): event is PrintEvent {
|
|
|
34999
35013
|
`;
|
|
35000
35014
|
await Bun.write(join5(dir, "types.ts"), content);
|
|
35001
35015
|
}
|
|
35002
|
-
async function generateStreamJson(dir, name, network, port,
|
|
35016
|
+
async function generateStreamJson(dir, name, network, port, _defaultEndpointUrl) {
|
|
35003
35017
|
const content = {
|
|
35004
35018
|
name,
|
|
35005
35019
|
network,
|
|
35006
|
-
|
|
35020
|
+
endpointUrl: `http://localhost:${port}/payload`,
|
|
35007
35021
|
filters: [
|
|
35008
35022
|
{
|
|
35009
35023
|
type: "stx_transfer",
|
|
@@ -35023,9 +35037,9 @@ async function generateStreamJson(dir, name, network, port, _defaultWebhookUrl)
|
|
|
35023
35037
|
`);
|
|
35024
35038
|
}
|
|
35025
35039
|
async function generateEnvFile(dir) {
|
|
35026
|
-
const content = `# Stacks Streams
|
|
35040
|
+
const content = `# Stacks Streams Signing Secret
|
|
35027
35041
|
# Get this from: sl streams register stream.json
|
|
35028
|
-
|
|
35042
|
+
STREAMS_SIGNING_SECRET=
|
|
35029
35043
|
|
|
35030
35044
|
# Add your database connection, etc.
|
|
35031
35045
|
# DATABASE_URL=postgres://...
|
|
@@ -35034,7 +35048,7 @@ STREAMS_WEBHOOK_SECRET=
|
|
|
35034
35048
|
}
|
|
35035
35049
|
async function generatePackageJson(dir, name) {
|
|
35036
35050
|
const content = {
|
|
35037
|
-
name: `${name}-
|
|
35051
|
+
name: `${name}-receiver`,
|
|
35038
35052
|
version: "0.1.0",
|
|
35039
35053
|
type: "module",
|
|
35040
35054
|
scripts: {
|
|
@@ -35941,7 +35955,7 @@ async function checkHealth() {
|
|
|
35941
35955
|
const portsToCheck = [
|
|
35942
35956
|
{ port: config.ports.api, name: "API" },
|
|
35943
35957
|
{ port: config.ports.indexer, name: "Indexer" },
|
|
35944
|
-
{ port: config.ports.
|
|
35958
|
+
{ port: config.ports.receiver, name: "Receiver" },
|
|
35945
35959
|
{ port: 20443, name: "Node RPC" }
|
|
35946
35960
|
];
|
|
35947
35961
|
for (const { port, name } of portsToCheck) {
|
|
@@ -36413,14 +36427,14 @@ init_config();
|
|
|
36413
36427
|
init_dev_state();
|
|
36414
36428
|
init_node_manager();
|
|
36415
36429
|
init_output();
|
|
36416
|
-
var DEV_SERVICES = ["api", "indexer", "worker", "
|
|
36430
|
+
var DEV_SERVICES = ["api", "indexer", "worker", "receiver", "subgraphs"];
|
|
36417
36431
|
function registerLocalCommand(program2) {
|
|
36418
36432
|
const local = program2.command("local").description("Manage local development environment and Stacks node").hook("preAction", async (_thisCommand, actionCommand) => {
|
|
36419
36433
|
if (actionCommand.name() === "help")
|
|
36420
36434
|
return;
|
|
36421
36435
|
await requireLocalNetwork();
|
|
36422
36436
|
});
|
|
36423
|
-
local.command("start").description("Start all local dev services (API, indexer, worker,
|
|
36437
|
+
local.command("start").description("Start all local dev services (API, indexer, worker, receiver)").option("--indexer-port <port>", "Indexer port", "3700").option("--api-port <port>", "API port", "3800").option("--receiver-port <port>", "Test receiver server port", "3900").option("--no-receiver", "Skip test receiver server").option("--no-worker", "Skip worker service").option("--secret <secret>", "Signing secret for signature verification").option("--stacks-node", "Use port 3701 for indexer (avoids conflict with stacks-blockchain-api)").option("-f, --foreground", "Run in foreground (blocking)").action(async (options2) => {
|
|
36424
36438
|
const { runBackground: runBackground2, runForeground: runForeground2, isDevAlreadyRunning: isDevAlreadyRunning2 } = await Promise.resolve().then(() => (init_dev_impl(), exports_dev_impl));
|
|
36425
36439
|
if (await isDevAlreadyRunning2()) {
|
|
36426
36440
|
return;
|
|
@@ -36442,7 +36456,7 @@ function registerLocalCommand(program2) {
|
|
|
36442
36456
|
local.command("status").description("Show local environment status").action(async () => {
|
|
36443
36457
|
await showLocalStatus();
|
|
36444
36458
|
});
|
|
36445
|
-
local.command("logs").description("View local service logs (dev + node)").option("-s, --service <name>", "Filter by service (api, indexer, worker,
|
|
36459
|
+
local.command("logs").description("View local service logs (dev + node)").option("-s, --service <name>", "Filter by service (api, indexer, worker, receiver, subgraphs, node)").option("-f, --follow", "Follow log output").option("-n, --lines <n>", "Number of lines to show", "50").option("-q, --quiet", "Filter out common noise").option("-v, --verbose", "Show full payloads").action(async (options2) => {
|
|
36446
36460
|
await showLocalLogs(options2);
|
|
36447
36461
|
});
|
|
36448
36462
|
const node = local.command("node").description("Manage local Stacks node");
|
|
@@ -36519,7 +36533,7 @@ var serviceColors2 = {
|
|
|
36519
36533
|
indexer: cyan,
|
|
36520
36534
|
worker: yellow,
|
|
36521
36535
|
subgraphs: magenta,
|
|
36522
|
-
|
|
36536
|
+
receiver: green,
|
|
36523
36537
|
node: red
|
|
36524
36538
|
};
|
|
36525
36539
|
async function showLocalLogs(options2) {
|
|
@@ -36671,17 +36685,17 @@ function formatLogLine3(service, line, verbose) {
|
|
|
36671
36685
|
return `${prefix} ${dimTimestamp} ${dim(level + ":")} ${dim(message)}`;
|
|
36672
36686
|
}
|
|
36673
36687
|
}
|
|
36674
|
-
if (service === "
|
|
36675
|
-
const summary =
|
|
36688
|
+
if (service === "receiver" && !verbose) {
|
|
36689
|
+
const summary = formatDeliverySummary2(line);
|
|
36676
36690
|
if (summary)
|
|
36677
36691
|
return `${prefix} ${summary}`;
|
|
36678
36692
|
}
|
|
36679
36693
|
return `${prefix} ${line}`;
|
|
36680
36694
|
}
|
|
36681
|
-
function
|
|
36695
|
+
function formatDeliverySummary2(jsonStr) {
|
|
36682
36696
|
try {
|
|
36683
36697
|
const data = JSON.parse(jsonStr);
|
|
36684
|
-
if (data.type !== "
|
|
36698
|
+
if (data.type !== "delivery" || !data.body)
|
|
36685
36699
|
return null;
|
|
36686
36700
|
const { body, method, path, timestamp } = data;
|
|
36687
36701
|
const streamName = body.streamName ?? body.streamId?.slice(0, 8) ?? "unknown";
|
|
@@ -36765,8 +36779,8 @@ registerSetupCommand(program);
|
|
|
36765
36779
|
registerConfigCommand(program);
|
|
36766
36780
|
registerAuthCommand(program);
|
|
36767
36781
|
registerWhoamiCommand(program);
|
|
36768
|
-
|
|
36782
|
+
registerReceiverCommand(program);
|
|
36769
36783
|
program.parse();
|
|
36770
36784
|
|
|
36771
|
-
//# debugId=
|
|
36785
|
+
//# debugId=2EB552BA8CA7A84564756E2164756E21
|
|
36772
36786
|
//# sourceMappingURL=cli.js.map
|