@secondlayer/cli 5.7.0 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +574 -153
- package/dist/cli.js.map +10 -6
- package/package.json +4 -3
package/dist/cli.js
CHANGED
|
@@ -2565,6 +2565,9 @@ function cyan(text) {
|
|
|
2565
2565
|
function dim(text) {
|
|
2566
2566
|
return `${colors.dim}${text}${colors.reset}`;
|
|
2567
2567
|
}
|
|
2568
|
+
function bold(text) {
|
|
2569
|
+
return `${colors.bold}${text}${colors.reset}`;
|
|
2570
|
+
}
|
|
2568
2571
|
function success(message) {
|
|
2569
2572
|
console.log(green(`✓ ${message}`));
|
|
2570
2573
|
}
|
|
@@ -5906,8 +5909,8 @@ var require_source = __commonJS((exports, module) => {
|
|
|
5906
5909
|
var deferToConnect = (socket, fn) => {
|
|
5907
5910
|
let listeners;
|
|
5908
5911
|
if (typeof fn === "function") {
|
|
5909
|
-
const
|
|
5910
|
-
listeners = { connect };
|
|
5912
|
+
const connect2 = fn;
|
|
5913
|
+
listeners = { connect: connect2 };
|
|
5911
5914
|
} else {
|
|
5912
5915
|
listeners = fn;
|
|
5913
5916
|
}
|
|
@@ -9808,7 +9811,7 @@ var require_client_request = __commonJS((exports, module) => {
|
|
|
9808
9811
|
// ../../node_modules/resolve-alpn/index.js
|
|
9809
9812
|
var require_resolve_alpn = __commonJS((exports, module) => {
|
|
9810
9813
|
var tls2 = __require("tls");
|
|
9811
|
-
module.exports = (options = {},
|
|
9814
|
+
module.exports = (options = {}, connect2 = tls2.connect) => new Promise((resolve2, reject) => {
|
|
9812
9815
|
let timeout = false;
|
|
9813
9816
|
let socket;
|
|
9814
9817
|
const callback = async () => {
|
|
@@ -9832,7 +9835,7 @@ var require_resolve_alpn = __commonJS((exports, module) => {
|
|
|
9832
9835
|
};
|
|
9833
9836
|
const socketPromise = (async () => {
|
|
9834
9837
|
try {
|
|
9835
|
-
socket = await
|
|
9838
|
+
socket = await connect2(options, callback);
|
|
9836
9839
|
socket.on("error", reject);
|
|
9837
9840
|
socket.once("timeout", onTimeout);
|
|
9838
9841
|
} catch (error2) {
|
|
@@ -9910,7 +9913,7 @@ var require_auto = __commonJS((exports, module) => {
|
|
|
9910
9913
|
socket.on("agentRemove", onRemove);
|
|
9911
9914
|
agent.emit("free", socket, options);
|
|
9912
9915
|
};
|
|
9913
|
-
var createResolveProtocol = (cache2, queue2 = new Map,
|
|
9916
|
+
var createResolveProtocol = (cache2, queue2 = new Map, connect2 = undefined) => {
|
|
9914
9917
|
return async (options) => {
|
|
9915
9918
|
const name = `${options.host}:${options.port}:${options.ALPNProtocols.sort()}`;
|
|
9916
9919
|
if (!cache2.has(name)) {
|
|
@@ -9920,7 +9923,7 @@ var require_auto = __commonJS((exports, module) => {
|
|
|
9920
9923
|
}
|
|
9921
9924
|
const { path: path2 } = options;
|
|
9922
9925
|
options.path = options.socketPath;
|
|
9923
|
-
const resultPromise = resolveALPN(options,
|
|
9926
|
+
const resultPromise = resolveALPN(options, connect2);
|
|
9924
9927
|
queue2.set(name, resultPromise);
|
|
9925
9928
|
try {
|
|
9926
9929
|
const result = await resultPromise;
|
|
@@ -13345,10 +13348,10 @@ var init_manager = __esm(() => {
|
|
|
13345
13348
|
});
|
|
13346
13349
|
|
|
13347
13350
|
// src/services/indexer.ts
|
|
13348
|
-
import { dirname as
|
|
13351
|
+
import { dirname as dirname6, resolve as resolve3 } from "node:path";
|
|
13349
13352
|
async function startIndexer(options2) {
|
|
13350
13353
|
const port = options2.port ?? 3700;
|
|
13351
|
-
const rootDir =
|
|
13354
|
+
const rootDir = dirname6(dirname6(dirname6(dirname6(import.meta.dir))));
|
|
13352
13355
|
const indexerPath = resolve3(rootDir, "packages/indexer/src/index.ts");
|
|
13353
13356
|
await serviceManager.start(SERVICE_NAME, ["bun", "run", "--watch", indexerPath], {
|
|
13354
13357
|
port,
|
|
@@ -13365,9 +13368,9 @@ var init_indexer = __esm(() => {
|
|
|
13365
13368
|
});
|
|
13366
13369
|
|
|
13367
13370
|
// src/services/worker.ts
|
|
13368
|
-
import { dirname as
|
|
13371
|
+
import { dirname as dirname7, resolve as resolve4 } from "node:path";
|
|
13369
13372
|
async function startWorker(options2) {
|
|
13370
|
-
const rootDir =
|
|
13373
|
+
const rootDir = dirname7(dirname7(dirname7(dirname7(import.meta.dir))));
|
|
13371
13374
|
const workerPath = resolve4(rootDir, "packages/worker/src/index.ts");
|
|
13372
13375
|
await serviceManager.start(SERVICE_NAME2, ["bun", "run", "--watch", workerPath], {
|
|
13373
13376
|
onStdout: options2.onLog,
|
|
@@ -13380,10 +13383,10 @@ var init_worker = __esm(() => {
|
|
|
13380
13383
|
});
|
|
13381
13384
|
|
|
13382
13385
|
// src/services/api.ts
|
|
13383
|
-
import { dirname as
|
|
13386
|
+
import { dirname as dirname8, resolve as resolve5 } from "node:path";
|
|
13384
13387
|
async function startApi(options2) {
|
|
13385
13388
|
const port = options2.port ?? 3800;
|
|
13386
|
-
const rootDir =
|
|
13389
|
+
const rootDir = dirname8(dirname8(dirname8(dirname8(import.meta.dir))));
|
|
13387
13390
|
const apiPath = resolve5(rootDir, "packages/api/src/index.ts");
|
|
13388
13391
|
await serviceManager.start(SERVICE_NAME3, ["bun", "run", "--watch", apiPath], {
|
|
13389
13392
|
port,
|
|
@@ -13400,9 +13403,9 @@ var init_api2 = __esm(() => {
|
|
|
13400
13403
|
});
|
|
13401
13404
|
|
|
13402
13405
|
// src/services/subgraph-processor.ts
|
|
13403
|
-
import { dirname as
|
|
13406
|
+
import { dirname as dirname9, resolve as resolve6 } from "node:path";
|
|
13404
13407
|
async function startSubgraphProcessor(options2) {
|
|
13405
|
-
const rootDir =
|
|
13408
|
+
const rootDir = dirname9(dirname9(dirname9(dirname9(import.meta.dir))));
|
|
13406
13409
|
const servicePath = resolve6(rootDir, "packages/subgraphs/src/service.ts");
|
|
13407
13410
|
await serviceManager.start(SERVICE_NAME4, ["bun", "run", "--watch", servicePath], {
|
|
13408
13411
|
env: {
|
|
@@ -13437,8 +13440,8 @@ __export(exports_dev_impl, {
|
|
|
13437
13440
|
restartDev: () => restartDev,
|
|
13438
13441
|
isDevAlreadyRunning: () => isDevAlreadyRunning
|
|
13439
13442
|
});
|
|
13440
|
-
import { mkdirSync as
|
|
13441
|
-
import { dirname as
|
|
13443
|
+
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
13444
|
+
import { dirname as dirname10, join as join9, resolve as resolve7 } from "node:path";
|
|
13442
13445
|
async function isDevAlreadyRunning() {
|
|
13443
13446
|
if (await isDevRunning()) {
|
|
13444
13447
|
const running = await getRunningServices();
|
|
@@ -13516,7 +13519,7 @@ async function runBackground(options2) {
|
|
|
13516
13519
|
startedAt: new Date().toISOString()
|
|
13517
13520
|
};
|
|
13518
13521
|
try {
|
|
13519
|
-
const packagesDir =
|
|
13522
|
+
const packagesDir = dirname10(dirname10(dirname10(dirname10(import.meta.dir))));
|
|
13520
13523
|
const env = { DATABASE_URL: databaseUrl, DEV_MODE: "true" };
|
|
13521
13524
|
const apiLogFile = getLogFile("api");
|
|
13522
13525
|
const apiProc = Bun.spawn(["bun", "run", resolve7(packagesDir, "packages/api/src/index.ts")], {
|
|
@@ -13866,7 +13869,7 @@ async function restartDev() {
|
|
|
13866
13869
|
await clearDevState();
|
|
13867
13870
|
await clearLogs();
|
|
13868
13871
|
const config = await loadConfig();
|
|
13869
|
-
const packagesDir =
|
|
13872
|
+
const packagesDir = dirname10(dirname10(dirname10(dirname10(import.meta.dir))));
|
|
13870
13873
|
const env = state.env;
|
|
13871
13874
|
const newState = {
|
|
13872
13875
|
services: {},
|
|
@@ -14047,8 +14050,8 @@ async function ensureDevPostgres(dataDir) {
|
|
|
14047
14050
|
if (check.stdout.toString().trim()) {
|
|
14048
14051
|
return false;
|
|
14049
14052
|
}
|
|
14050
|
-
const pgDataDir =
|
|
14051
|
-
|
|
14053
|
+
const pgDataDir = join9(dataDir, "postgres");
|
|
14054
|
+
mkdirSync4(pgDataDir, { recursive: true });
|
|
14052
14055
|
const stopped = await Bun.$`docker ps -aq -f name=secondlayer-dev-postgres`.quiet().nothrow();
|
|
14053
14056
|
if (stopped.stdout.toString().trim()) {
|
|
14054
14057
|
await Bun.$`docker rm secondlayer-dev-postgres`.quiet().nothrow();
|
|
@@ -14063,7 +14066,7 @@ async function ensureDevPostgres(dataDir) {
|
|
|
14063
14066
|
throw new Error("PostgreSQL failed to start");
|
|
14064
14067
|
}
|
|
14065
14068
|
async function runMigrations(databaseUrl) {
|
|
14066
|
-
const packagesDir =
|
|
14069
|
+
const packagesDir = dirname10(dirname10(dirname10(dirname10(import.meta.dir))));
|
|
14067
14070
|
const migrateScript = resolve7(packagesDir, "packages/shared/src/db/migrate.ts");
|
|
14068
14071
|
const result = await Bun.$`DATABASE_URL=${databaseUrl} bun run ${migrateScript}`.quiet().nothrow();
|
|
14069
14072
|
if (result.exitCode !== 0) {
|
|
@@ -15419,8 +15422,8 @@ var require_to_regex_range = __commonJS((exports, module) => {
|
|
|
15419
15422
|
let relax = String(opts.relaxZeros);
|
|
15420
15423
|
let shorthand = String(opts.shorthand);
|
|
15421
15424
|
let capture = String(opts.capture);
|
|
15422
|
-
let
|
|
15423
|
-
let cacheKey = min + ":" + max + "=" + relax + shorthand + capture +
|
|
15425
|
+
let wrap2 = String(opts.wrap);
|
|
15426
|
+
let cacheKey = min + ":" + max + "=" + relax + shorthand + capture + wrap2;
|
|
15424
15427
|
if (toRegexRange.cache.hasOwnProperty(cacheKey)) {
|
|
15425
15428
|
return toRegexRange.cache[cacheKey].result;
|
|
15426
15429
|
}
|
|
@@ -15700,9 +15703,9 @@ var require_fill_range = __commonJS((exports, module) => {
|
|
|
15700
15703
|
};
|
|
15701
15704
|
var toRegex = (start, end, options2) => {
|
|
15702
15705
|
if (Array.isArray(start)) {
|
|
15703
|
-
let
|
|
15706
|
+
let wrap2 = options2.wrap === true;
|
|
15704
15707
|
let prefix = options2.capture ? "" : "?:";
|
|
15705
|
-
return
|
|
15708
|
+
return wrap2 ? `(${prefix}${start.join("|")})` : start.join("|");
|
|
15706
15709
|
}
|
|
15707
15710
|
return toRegexRange(start, end, options2);
|
|
15708
15711
|
};
|
|
@@ -21791,11 +21794,11 @@ var init_commands = __esm(() => {
|
|
|
21791
21794
|
});
|
|
21792
21795
|
|
|
21793
21796
|
// ../../node_modules/@antfu/ni/dist/shared/ni.B5qNAuoI.mjs
|
|
21794
|
-
import path3, { join as
|
|
21797
|
+
import path3, { join as join11, dirname as dirname12, resolve as resolve9 } from "node:path";
|
|
21795
21798
|
import process$1 from "node:process";
|
|
21796
21799
|
import require$$0 from "readline";
|
|
21797
21800
|
import require$$2 from "events";
|
|
21798
|
-
import fs5, { promises, existsSync as
|
|
21801
|
+
import fs5, { promises, existsSync as existsSync6 } from "node:fs";
|
|
21799
21802
|
import require$$0$1 from "os";
|
|
21800
21803
|
import require$$1 from "tty";
|
|
21801
21804
|
import os4 from "node:os";
|
|
@@ -22353,9 +22356,9 @@ function requireLines() {
|
|
|
22353
22356
|
}
|
|
22354
22357
|
function requireWrap() {
|
|
22355
22358
|
if (hasRequiredWrap)
|
|
22356
|
-
return
|
|
22359
|
+
return wrap2;
|
|
22357
22360
|
hasRequiredWrap = 1;
|
|
22358
|
-
|
|
22361
|
+
wrap2 = (msg, opts = {}) => {
|
|
22359
22362
|
const tab = Number.isSafeInteger(parseInt(opts.margin)) ? new Array(parseInt(opts.margin)).fill(" ").join("") : opts.margin || "";
|
|
22360
22363
|
const width = opts.width;
|
|
22361
22364
|
return (msg || "").split(/\r?\n/g).map((line) => line.split(/\s+/g).reduce((arr, w2) => {
|
|
@@ -22368,7 +22371,7 @@ function requireWrap() {
|
|
|
22368
22371
|
`)).join(`
|
|
22369
22372
|
`);
|
|
22370
22373
|
};
|
|
22371
|
-
return
|
|
22374
|
+
return wrap2;
|
|
22372
22375
|
}
|
|
22373
22376
|
function requireEntriesToDisplay() {
|
|
22374
22377
|
if (hasRequiredEntriesToDisplay)
|
|
@@ -22660,7 +22663,7 @@ function requireSelect() {
|
|
|
22660
22663
|
hasRequiredSelect = 1;
|
|
22661
22664
|
const color = requireKleur();
|
|
22662
22665
|
const Prompt = requirePrompt();
|
|
22663
|
-
const { style: style2, clear: clear2, figures, wrap:
|
|
22666
|
+
const { style: style2, clear: clear2, figures, wrap: wrap3, entriesToDisplay: entriesToDisplay2 } = requireUtil();
|
|
22664
22667
|
const { cursor } = requireSrc();
|
|
22665
22668
|
|
|
22666
22669
|
class SelectPrompt extends Prompt {
|
|
@@ -22791,7 +22794,7 @@ function requireSelect() {
|
|
|
22791
22794
|
desc = ` - ${v2.description}`;
|
|
22792
22795
|
if (prefix.length + title.length + desc.length >= this.out.columns || v2.description.split(/\r?\n/).length > 1) {
|
|
22793
22796
|
desc = `
|
|
22794
|
-
` +
|
|
22797
|
+
` + wrap3(v2.description, { margin: 3, width: this.out.columns });
|
|
22795
22798
|
}
|
|
22796
22799
|
}
|
|
22797
22800
|
}
|
|
@@ -23557,7 +23560,7 @@ function requireMultiselect() {
|
|
|
23557
23560
|
const color = requireKleur();
|
|
23558
23561
|
const { cursor } = requireSrc();
|
|
23559
23562
|
const Prompt = requirePrompt();
|
|
23560
|
-
const { clear: clear2, figures, style: style2, wrap:
|
|
23563
|
+
const { clear: clear2, figures, style: style2, wrap: wrap3, entriesToDisplay: entriesToDisplay2 } = requireUtil();
|
|
23561
23564
|
|
|
23562
23565
|
class MultiselectPrompt extends Prompt {
|
|
23563
23566
|
constructor(opts = {}) {
|
|
@@ -23715,7 +23718,7 @@ Instructions:
|
|
|
23715
23718
|
desc = ` - ${v2.description}`;
|
|
23716
23719
|
if (prefix.length + title.length + desc.length >= this.out.columns || v2.description.split(/\r?\n/).length > 1) {
|
|
23717
23720
|
desc = `
|
|
23718
|
-
` +
|
|
23721
|
+
` + wrap3(v2.description, { margin: prefix.length, width: this.out.columns });
|
|
23719
23722
|
}
|
|
23720
23723
|
}
|
|
23721
23724
|
}
|
|
@@ -23788,7 +23791,7 @@ function requireAutocomplete() {
|
|
|
23788
23791
|
const color = requireKleur();
|
|
23789
23792
|
const Prompt = requirePrompt();
|
|
23790
23793
|
const { erase, cursor } = requireSrc();
|
|
23791
|
-
const { style: style2, clear: clear2, figures, wrap:
|
|
23794
|
+
const { style: style2, clear: clear2, figures, wrap: wrap3, entriesToDisplay: entriesToDisplay2 } = requireUtil();
|
|
23792
23795
|
const getVal = (arr, i2) => arr[i2] && (arr[i2].value || arr[i2].title || arr[i2]);
|
|
23793
23796
|
const getTitle = (arr, i2) => arr[i2] && (arr[i2].title || arr[i2].value || arr[i2]);
|
|
23794
23797
|
const getIndex = (arr, valOrTitle) => {
|
|
@@ -23975,7 +23978,7 @@ function requireAutocomplete() {
|
|
|
23975
23978
|
desc = ` - ${v2.description}`;
|
|
23976
23979
|
if (prefix.length + title.length + desc.length >= this.out.columns || v2.description.split(/\r?\n/).length > 1) {
|
|
23977
23980
|
desc = `
|
|
23978
|
-
` +
|
|
23981
|
+
` + wrap3(v2.description, { margin: 3, width: this.out.columns });
|
|
23979
23982
|
}
|
|
23980
23983
|
}
|
|
23981
23984
|
return prefix + " " + title + color.gray(desc || "");
|
|
@@ -24806,7 +24809,7 @@ function requireLib() {
|
|
|
24806
24809
|
return lib;
|
|
24807
24810
|
hasRequiredLib = 1;
|
|
24808
24811
|
const { isexe, sync: isexeSync } = requireCjs();
|
|
24809
|
-
const { join:
|
|
24812
|
+
const { join: join12, delimiter, sep, posix: posix2 } = require$$1$2;
|
|
24810
24813
|
const isWindows = process.platform === "win32";
|
|
24811
24814
|
const rSlash = new RegExp(`[${posix2.sep}${sep === posix2.sep ? "" : sep}]`.replace(/(\\)/g, "\\$1"));
|
|
24812
24815
|
const rRel = new RegExp(`^\\.${rSlash.source}`);
|
|
@@ -24833,7 +24836,7 @@ function requireLib() {
|
|
|
24833
24836
|
const getPathPart = (raw, cmd) => {
|
|
24834
24837
|
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
|
|
24835
24838
|
const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : "";
|
|
24836
|
-
return prefix +
|
|
24839
|
+
return prefix + join12(pathPart, cmd);
|
|
24837
24840
|
};
|
|
24838
24841
|
const which = async (cmd, opt = {}) => {
|
|
24839
24842
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
@@ -24929,7 +24932,7 @@ async function detect2({ autoInstall, programmatic, cwd } = {}) {
|
|
|
24929
24932
|
}
|
|
24930
24933
|
return agent;
|
|
24931
24934
|
}
|
|
24932
|
-
var ini$1, hasRequiredIni, iniExports, prompts$2, kleur, hasRequiredKleur, action, hasRequiredAction, strip, hasRequiredStrip, src, hasRequiredSrc, clear, hasRequiredClear, figures_1, hasRequiredFigures, style, hasRequiredStyle, lines, hasRequiredLines,
|
|
24935
|
+
var ini$1, hasRequiredIni, iniExports, prompts$2, kleur, hasRequiredKleur, action, hasRequiredAction, strip, hasRequiredStrip, src, hasRequiredSrc, clear, hasRequiredClear, figures_1, hasRequiredFigures, style, hasRequiredStyle, lines, hasRequiredLines, wrap2, hasRequiredWrap, entriesToDisplay, hasRequiredEntriesToDisplay, util, hasRequiredUtil, prompt, hasRequiredPrompt, text, hasRequiredText, select4, hasRequiredSelect, toggle, hasRequiredToggle, datepart, hasRequiredDatepart, meridiem, hasRequiredMeridiem, day, hasRequiredDay, hours, hasRequiredHours, milliseconds, hasRequiredMilliseconds, minutes, hasRequiredMinutes, month, hasRequiredMonth, seconds, hasRequiredSeconds, year, hasRequiredYear, dateparts, hasRequiredDateparts, date, hasRequiredDate, number, hasRequiredNumber, multiselect, hasRequiredMultiselect, autocomplete, hasRequiredAutocomplete, autocompleteMultiselect, hasRequiredAutocompleteMultiselect, confirm6, hasRequiredConfirm, elements, hasRequiredElements, hasRequiredPrompts$1, lib$1, hasRequiredLib$1, prompts$1, hasRequiredPrompts, promptsExports, prompts, isBrowser, platform, OSC = "\x1B]", BEL = "\x07", SEP = ";", link = (text2, url) => [
|
|
24933
24936
|
OSC,
|
|
24934
24937
|
"8",
|
|
24935
24938
|
SEP,
|
|
@@ -24982,7 +24985,7 @@ var init_ni_B5qNAuoI = __esm(() => {
|
|
|
24982
24985
|
options2 = {};
|
|
24983
24986
|
libExports = requireLib();
|
|
24984
24987
|
which = /* @__PURE__ */ getDefaultExportFromCjs(libExports);
|
|
24985
|
-
CLI_TEMP_DIR =
|
|
24988
|
+
CLI_TEMP_DIR = join11(os4.tmpdir(), "antfu-ni");
|
|
24986
24989
|
customRcPath = process$1.env.NI_CONFIG_FILE;
|
|
24987
24990
|
home = process$1.platform === "win32" ? process$1.env.USERPROFILE : process$1.env.HOME;
|
|
24988
24991
|
defaultRcPath = path3.join(home || "~/", ".nirc");
|
|
@@ -25635,11 +25638,11 @@ var hasColors, format = (open, close) => {
|
|
|
25635
25638
|
result += string.slice(lastIndex) + closeCode;
|
|
25636
25639
|
return result;
|
|
25637
25640
|
};
|
|
25638
|
-
}, reset2,
|
|
25641
|
+
}, reset2, bold2, dim2, italic, underline, overline, inverse, hidden, strikethrough, black, red2, green2, yellow2, blue2, magenta2, cyan2, white, gray, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bgGray, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright, bgRedBright, bgGreenBright, bgYellowBright, bgBlueBright, bgMagentaBright, bgCyanBright, bgWhiteBright;
|
|
25639
25642
|
var init_base = __esm(() => {
|
|
25640
25643
|
hasColors = tty2?.WriteStream?.prototype?.hasColors?.() ?? false;
|
|
25641
25644
|
reset2 = format(0, 0);
|
|
25642
|
-
|
|
25645
|
+
bold2 = format(1, 22);
|
|
25643
25646
|
dim2 = format(2, 22);
|
|
25644
25647
|
italic = format(3, 23);
|
|
25645
25648
|
underline = format(4, 24);
|
|
@@ -25717,7 +25720,7 @@ var init_default = __esm(() => {
|
|
|
25717
25720
|
duration: getFinalIcon
|
|
25718
25721
|
};
|
|
25719
25722
|
COLORS = {
|
|
25720
|
-
command: () =>
|
|
25723
|
+
command: () => bold2,
|
|
25721
25724
|
output: () => identity,
|
|
25722
25725
|
ipc: () => identity,
|
|
25723
25726
|
error: ({ reject }) => reject ? redBright : yellowBright,
|
|
@@ -26294,7 +26297,7 @@ var require_cross_spawn = __commonJS((exports, module) => {
|
|
|
26294
26297
|
enoent.hookChildProcess(spawned, parsed);
|
|
26295
26298
|
return spawned;
|
|
26296
26299
|
}
|
|
26297
|
-
function
|
|
26300
|
+
function spawnSync2(command, args, options3) {
|
|
26298
26301
|
const parsed = parse2(command, args, options3);
|
|
26299
26302
|
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
|
|
26300
26303
|
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
|
|
@@ -26302,7 +26305,7 @@ var require_cross_spawn = __commonJS((exports, module) => {
|
|
|
26302
26305
|
}
|
|
26303
26306
|
module.exports = spawn2;
|
|
26304
26307
|
module.exports.spawn = spawn2;
|
|
26305
|
-
module.exports.sync =
|
|
26308
|
+
module.exports.sync = spawnSync2;
|
|
26306
26309
|
module.exports._parse = parse2;
|
|
26307
26310
|
module.exports._enoent = enoent;
|
|
26308
26311
|
});
|
|
@@ -28706,7 +28709,7 @@ var init_stdio_option = __esm(() => {
|
|
|
28706
28709
|
});
|
|
28707
28710
|
|
|
28708
28711
|
// ../../node_modules/execa/lib/stdio/native.js
|
|
28709
|
-
import { readFileSync as
|
|
28712
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
28710
28713
|
import tty3 from "node:tty";
|
|
28711
28714
|
var handleNativeStream = ({ stdioItem, stdioItem: { type }, isStdioArray, fdNumber, direction, isSync }) => {
|
|
28712
28715
|
if (!isStdioArray || type !== "native") {
|
|
@@ -28738,7 +28741,7 @@ var handleNativeStream = ({ stdioItem, stdioItem: { type }, isStdioArray, fdNumb
|
|
|
28738
28741
|
if (tty3.isatty(targetFdNumber)) {
|
|
28739
28742
|
throw new TypeError(`The \`${optionName}: ${serializeOptionValue(value)}\` option is invalid: it cannot be a TTY with synchronous methods.`);
|
|
28740
28743
|
}
|
|
28741
|
-
return { type: "uint8Array", value: bufferToUint8Array(
|
|
28744
|
+
return { type: "uint8Array", value: bufferToUint8Array(readFileSync4(targetFdNumber)), optionName };
|
|
28742
28745
|
}, getTargetFdNumber = (value, fdNumber) => {
|
|
28743
28746
|
if (value === "inherit") {
|
|
28744
28747
|
return fdNumber;
|
|
@@ -29041,7 +29044,7 @@ var init_handle = __esm(() => {
|
|
|
29041
29044
|
});
|
|
29042
29045
|
|
|
29043
29046
|
// ../../node_modules/execa/lib/stdio/handle-sync.js
|
|
29044
|
-
import { readFileSync as
|
|
29047
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
29045
29048
|
var handleStdioSync = (options3, verboseInfo) => handleStdio(addPropertiesSync, options3, verboseInfo, true), forbiddenIfSync = ({ type, optionName }) => {
|
|
29046
29049
|
throwInvalidSyncValue(optionName, TYPE_TO_MESSAGE[type]);
|
|
29047
29050
|
}, forbiddenNativeIfSync = ({ optionName, value }) => {
|
|
@@ -29069,8 +29072,8 @@ var init_handle_sync = __esm(() => {
|
|
|
29069
29072
|
addPropertiesSync = {
|
|
29070
29073
|
input: {
|
|
29071
29074
|
...addProperties,
|
|
29072
|
-
fileUrl: ({ value }) => ({ contents: [bufferToUint8Array(
|
|
29073
|
-
filePath: ({ value: { file } }) => ({ contents: [bufferToUint8Array(
|
|
29075
|
+
fileUrl: ({ value }) => ({ contents: [bufferToUint8Array(readFileSync5(value))] }),
|
|
29076
|
+
filePath: ({ value: { file } }) => ({ contents: [bufferToUint8Array(readFileSync5(file))] }),
|
|
29074
29077
|
fileNumber: forbiddenIfSync,
|
|
29075
29078
|
iterable: ({ value }) => ({ contents: [...value] }),
|
|
29076
29079
|
string: ({ value }) => ({ contents: [value] }),
|
|
@@ -29439,7 +29442,7 @@ var init_output2 = __esm(() => {
|
|
|
29439
29442
|
});
|
|
29440
29443
|
|
|
29441
29444
|
// ../../node_modules/execa/lib/io/output-sync.js
|
|
29442
|
-
import { writeFileSync as
|
|
29445
|
+
import { writeFileSync as writeFileSync5, appendFileSync } from "node:fs";
|
|
29443
29446
|
var transformOutputSync = ({ fileDescriptors, syncResult: { output }, options: options3, isMaxBuffer, verboseInfo }) => {
|
|
29444
29447
|
if (output === null) {
|
|
29445
29448
|
return { output: Array.from({ length: 3 }) };
|
|
@@ -29532,7 +29535,7 @@ var transformOutputSync = ({ fileDescriptors, syncResult: { output }, options: o
|
|
|
29532
29535
|
appendFileSync(path9, serializedResult);
|
|
29533
29536
|
} else {
|
|
29534
29537
|
outputFiles.add(pathString);
|
|
29535
|
-
|
|
29538
|
+
writeFileSync5(path9, serializedResult);
|
|
29536
29539
|
}
|
|
29537
29540
|
}
|
|
29538
29541
|
};
|
|
@@ -29629,7 +29632,7 @@ var init_exit_sync = __esm(() => {
|
|
|
29629
29632
|
});
|
|
29630
29633
|
|
|
29631
29634
|
// ../../node_modules/execa/lib/methods/main-sync.js
|
|
29632
|
-
import { spawnSync } from "node:child_process";
|
|
29635
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
29633
29636
|
var execaCoreSync = (rawFile, rawArguments, rawOptions) => {
|
|
29634
29637
|
const { file, commandArguments, command, escapedCommand, startTime, verboseInfo, options: options3, fileDescriptors } = handleSyncArguments(rawFile, rawArguments, rawOptions);
|
|
29635
29638
|
const result = spawnSubprocessSync({
|
|
@@ -29714,7 +29717,7 @@ var execaCoreSync = (rawFile, rawArguments, rawOptions) => {
|
|
|
29714
29717
|
try {
|
|
29715
29718
|
addInputOptionsSync(fileDescriptors, options3);
|
|
29716
29719
|
const normalizedOptions = normalizeSpawnSyncOptions(options3);
|
|
29717
|
-
return
|
|
29720
|
+
return spawnSync2(...concatenateShell(file, commandArguments, normalizedOptions));
|
|
29718
29721
|
} catch (error2) {
|
|
29719
29722
|
return makeEarlyError({
|
|
29720
29723
|
error: error2,
|
|
@@ -32321,7 +32324,7 @@ var {
|
|
|
32321
32324
|
// package.json
|
|
32322
32325
|
var package_default = {
|
|
32323
32326
|
name: "@secondlayer/cli",
|
|
32324
|
-
version: "5.
|
|
32327
|
+
version: "5.9.0",
|
|
32325
32328
|
repository: {
|
|
32326
32329
|
type: "git",
|
|
32327
32330
|
url: "git+https://github.com/ryanwaits/secondlayer.git",
|
|
@@ -32370,13 +32373,14 @@ var package_default = {
|
|
|
32370
32373
|
dependencies: {
|
|
32371
32374
|
"@inquirer/prompts": "^8.2.0",
|
|
32372
32375
|
"@secondlayer/bundler": "^0.3.7",
|
|
32373
|
-
"@secondlayer/sdk": "^5.
|
|
32376
|
+
"@secondlayer/sdk": "^5.6.0",
|
|
32374
32377
|
"@secondlayer/shared": "^6.9.0",
|
|
32375
32378
|
"@secondlayer/stacks": "^2.3.0",
|
|
32376
|
-
"@secondlayer/subgraphs": "^3.
|
|
32379
|
+
"@secondlayer/subgraphs": "^3.4.0",
|
|
32377
32380
|
"@biomejs/js-api": "^0.7.0",
|
|
32378
32381
|
"@biomejs/wasm-nodejs": "^1.9.0",
|
|
32379
32382
|
esbuild: "^0.19.0",
|
|
32383
|
+
"smol-toml": "^1.6.1",
|
|
32380
32384
|
zod: "^4.3.6"
|
|
32381
32385
|
},
|
|
32382
32386
|
devDependencies: {
|
|
@@ -34429,21 +34433,309 @@ async function resyncDatabase(skipConfirm, backfill) {
|
|
|
34429
34433
|
process.exit(1);
|
|
34430
34434
|
}
|
|
34431
34435
|
}
|
|
34436
|
+
// src/commands/devnet.ts
|
|
34437
|
+
import { spawnSync } from "node:child_process";
|
|
34438
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
34439
|
+
import { dirname as dirname4, join as join7 } from "node:path";
|
|
34440
|
+
|
|
34441
|
+
// src/lib/devnet-compose.ts
|
|
34442
|
+
var DEFAULT_IMAGE_OWNER = "ryanwaits";
|
|
34443
|
+
var DEFAULT_IMAGE_TAG = "latest";
|
|
34444
|
+
function buildDevnetCompose(opts = {}) {
|
|
34445
|
+
const owner = opts.owner ?? DEFAULT_IMAGE_OWNER;
|
|
34446
|
+
const tag = opts.imageTag ?? DEFAULT_IMAGE_TAG;
|
|
34447
|
+
const apiPort = opts.apiPort ?? 3800;
|
|
34448
|
+
const indexerPort = opts.indexerPort ?? 3700;
|
|
34449
|
+
const apiImage = `ghcr.io/${owner}/secondlayer-api:${tag}`;
|
|
34450
|
+
const indexerImage = `ghcr.io/${owner}/secondlayer-indexer:${tag}`;
|
|
34451
|
+
const dbUrl = "postgres://secondlayer:secondlayer@postgres:5432/secondlayer";
|
|
34452
|
+
return `# Generated by \`sl devnet connect\` — do not edit by hand.
|
|
34453
|
+
# Secondlayer app services for local clarinet devnet development.
|
|
34454
|
+
name: secondlayer-devnet
|
|
34455
|
+
|
|
34456
|
+
services:
|
|
34457
|
+
postgres:
|
|
34458
|
+
image: postgres:17-alpine
|
|
34459
|
+
environment:
|
|
34460
|
+
POSTGRES_USER: secondlayer
|
|
34461
|
+
POSTGRES_PASSWORD: secondlayer
|
|
34462
|
+
POSTGRES_DB: secondlayer
|
|
34463
|
+
volumes:
|
|
34464
|
+
- postgres_data:/var/lib/postgresql/data
|
|
34465
|
+
healthcheck:
|
|
34466
|
+
test: ["CMD-SHELL", "pg_isready -U secondlayer"]
|
|
34467
|
+
interval: 5s
|
|
34468
|
+
timeout: 5s
|
|
34469
|
+
retries: 10
|
|
34470
|
+
restart: unless-stopped
|
|
34471
|
+
|
|
34472
|
+
migrate:
|
|
34473
|
+
image: ${apiImage}
|
|
34474
|
+
command: ["bun", "run", "packages/shared/src/db/migrate.ts"]
|
|
34475
|
+
environment:
|
|
34476
|
+
DATABASE_URL: ${dbUrl}
|
|
34477
|
+
depends_on:
|
|
34478
|
+
postgres:
|
|
34479
|
+
condition: service_healthy
|
|
34480
|
+
restart: "no"
|
|
34481
|
+
|
|
34482
|
+
api:
|
|
34483
|
+
image: ${apiImage}
|
|
34484
|
+
environment:
|
|
34485
|
+
INSTANCE_MODE: oss
|
|
34486
|
+
DATABASE_URL: ${dbUrl}
|
|
34487
|
+
PORT: 3800
|
|
34488
|
+
NODE_ENV: production
|
|
34489
|
+
DATA_DIR: /data
|
|
34490
|
+
ports:
|
|
34491
|
+
- "${apiPort}:3800"
|
|
34492
|
+
volumes:
|
|
34493
|
+
- subgraphs_data:/data/subgraphs
|
|
34494
|
+
depends_on:
|
|
34495
|
+
migrate:
|
|
34496
|
+
condition: service_completed_successfully
|
|
34497
|
+
postgres:
|
|
34498
|
+
condition: service_healthy
|
|
34499
|
+
healthcheck:
|
|
34500
|
+
test: ["CMD", "curl", "-f", "http://localhost:3800/health"]
|
|
34501
|
+
interval: 10s
|
|
34502
|
+
timeout: 3s
|
|
34503
|
+
start_period: 10s
|
|
34504
|
+
retries: 5
|
|
34505
|
+
restart: unless-stopped
|
|
34506
|
+
|
|
34507
|
+
indexer:
|
|
34508
|
+
image: ${indexerImage}
|
|
34509
|
+
environment:
|
|
34510
|
+
DATABASE_URL: ${dbUrl}
|
|
34511
|
+
PORT: 3700
|
|
34512
|
+
NODE_ENV: production
|
|
34513
|
+
# Keep every network key aligned: the indexer writes index_progress under
|
|
34514
|
+
# STACKS_NETWORK, the subgraph processor reads it under NETWORK. If they
|
|
34515
|
+
# differ, catch-up finds no progress row and subgraphs never advance.
|
|
34516
|
+
NETWORKS: testnet
|
|
34517
|
+
STACKS_NETWORK: testnet
|
|
34518
|
+
NETWORK: testnet
|
|
34519
|
+
# Fed by the devnet node's event observer — never reach out to Hiro mainnet.
|
|
34520
|
+
AUTO_BACKFILL_ENABLED: "false"
|
|
34521
|
+
TIP_FOLLOWER_ENABLED: "false"
|
|
34522
|
+
# Bind on all interfaces so the devnet's stacks-node container can POST to
|
|
34523
|
+
# host.docker.internal:3700.
|
|
34524
|
+
ports:
|
|
34525
|
+
- "${indexerPort}:3700"
|
|
34526
|
+
extra_hosts:
|
|
34527
|
+
- "host.docker.internal:host-gateway"
|
|
34528
|
+
depends_on:
|
|
34529
|
+
migrate:
|
|
34530
|
+
condition: service_completed_successfully
|
|
34531
|
+
postgres:
|
|
34532
|
+
condition: service_healthy
|
|
34533
|
+
healthcheck:
|
|
34534
|
+
test: ["CMD", "curl", "-f", "http://localhost:3700/health"]
|
|
34535
|
+
interval: 10s
|
|
34536
|
+
timeout: 3s
|
|
34537
|
+
start_period: 10s
|
|
34538
|
+
retries: 5
|
|
34539
|
+
restart: unless-stopped
|
|
34540
|
+
|
|
34541
|
+
subgraph-processor:
|
|
34542
|
+
image: ${apiImage}
|
|
34543
|
+
command: ["bun", "run", "packages/subgraphs/src/service.ts"]
|
|
34544
|
+
environment:
|
|
34545
|
+
DATABASE_URL: ${dbUrl}
|
|
34546
|
+
NODE_ENV: production
|
|
34547
|
+
DATA_DIR: /data
|
|
34548
|
+
# Must match the indexer's network key (see indexer note) — catch-up reads
|
|
34549
|
+
# index_progress under NETWORK.
|
|
34550
|
+
NETWORK: testnet
|
|
34551
|
+
STACKS_NETWORK: testnet
|
|
34552
|
+
volumes:
|
|
34553
|
+
- subgraphs_data:/data/subgraphs
|
|
34554
|
+
depends_on:
|
|
34555
|
+
migrate:
|
|
34556
|
+
condition: service_completed_successfully
|
|
34557
|
+
postgres:
|
|
34558
|
+
condition: service_healthy
|
|
34559
|
+
healthcheck:
|
|
34560
|
+
disable: true
|
|
34561
|
+
restart: unless-stopped
|
|
34562
|
+
|
|
34563
|
+
volumes:
|
|
34564
|
+
postgres_data:
|
|
34565
|
+
subgraphs_data:
|
|
34566
|
+
`;
|
|
34567
|
+
}
|
|
34568
|
+
|
|
34569
|
+
// src/lib/devnet-config.ts
|
|
34570
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
34571
|
+
import { dirname as dirname3, join as join6, parse as parsePath } from "node:path";
|
|
34572
|
+
import { parse as parseToml } from "smol-toml";
|
|
34573
|
+
var DEFAULT_INDEXER_OBSERVER = "host.docker.internal:3700";
|
|
34574
|
+
function findClarinetProject(startDir) {
|
|
34575
|
+
let dir = startDir;
|
|
34576
|
+
const { root } = parsePath(dir);
|
|
34577
|
+
while (true) {
|
|
34578
|
+
if (existsSync2(join6(dir, "Clarinet.toml")))
|
|
34579
|
+
return dir;
|
|
34580
|
+
if (dir === root)
|
|
34581
|
+
return null;
|
|
34582
|
+
dir = dirname3(dir);
|
|
34583
|
+
}
|
|
34584
|
+
}
|
|
34585
|
+
function ensureEventObserver(devnetTomlPath, endpoint = DEFAULT_INDEXER_OBSERVER) {
|
|
34586
|
+
const exists = existsSync2(devnetTomlPath);
|
|
34587
|
+
const original = exists ? readFileSync2(devnetTomlPath, "utf8") : "";
|
|
34588
|
+
if (original.trim()) {
|
|
34589
|
+
const parsed = parseToml(original);
|
|
34590
|
+
const observers = parsed.devnet?.stacks_node_events_observers;
|
|
34591
|
+
if (Array.isArray(observers) && observers.includes(endpoint)) {
|
|
34592
|
+
return { status: "present" };
|
|
34593
|
+
}
|
|
34594
|
+
}
|
|
34595
|
+
const entry = JSON.stringify(endpoint);
|
|
34596
|
+
const arrayStart = original.match(/^[^#\n]*stacks_node_events_observers\s*=\s*\[/m);
|
|
34597
|
+
if (arrayStart) {
|
|
34598
|
+
const at = (arrayStart.index ?? 0) + arrayStart[0].length;
|
|
34599
|
+
const next = original.slice(at).trimStart().startsWith("]") ? entry : `${entry}, `;
|
|
34600
|
+
const patched = original.slice(0, at) + next + original.slice(at);
|
|
34601
|
+
writeFileSync2(devnetTomlPath, patched);
|
|
34602
|
+
return { status: "added" };
|
|
34603
|
+
}
|
|
34604
|
+
const header = original.match(/^\[devnet\]\s*$/m);
|
|
34605
|
+
if (header) {
|
|
34606
|
+
const at = (header.index ?? 0) + header[0].length;
|
|
34607
|
+
const patched = `${original.slice(0, at)}
|
|
34608
|
+
stacks_node_events_observers = [${entry}]${original.slice(at)}`;
|
|
34609
|
+
writeFileSync2(devnetTomlPath, patched);
|
|
34610
|
+
return { status: "added" };
|
|
34611
|
+
}
|
|
34612
|
+
const prefix = original && !original.endsWith(`
|
|
34613
|
+
`) ? `${original}
|
|
34614
|
+
` : original;
|
|
34615
|
+
const block = `${prefix}${original.trim() ? `
|
|
34616
|
+
` : ""}[devnet]
|
|
34617
|
+
stacks_node_events_observers = [${entry}]
|
|
34618
|
+
`;
|
|
34619
|
+
writeFileSync2(devnetTomlPath, block);
|
|
34620
|
+
return { status: exists ? "added" : "created" };
|
|
34621
|
+
}
|
|
34622
|
+
|
|
34623
|
+
// src/commands/devnet.ts
|
|
34624
|
+
init_output();
|
|
34625
|
+
var COMPOSE_REL = join7(".secondlayer", "docker-compose.yml");
|
|
34626
|
+
function ensureDocker() {
|
|
34627
|
+
const probe = spawnSync("docker", ["info"], { stdio: "ignore" });
|
|
34628
|
+
if (probe.error || probe.status !== 0) {
|
|
34629
|
+
error(`Docker isn't available.
|
|
34630
|
+
|
|
34631
|
+
` + `Start Docker Desktop or OrbStack (macOS), or install Docker:
|
|
34632
|
+
` + ` macOS: brew install --cask docker (or https://orbstack.dev)
|
|
34633
|
+
` + " Linux: curl -fsSL https://get.docker.com | sh");
|
|
34634
|
+
process.exit(1);
|
|
34635
|
+
}
|
|
34636
|
+
}
|
|
34637
|
+
function dockerCompose(composePath, args) {
|
|
34638
|
+
const res = spawnSync("docker", ["compose", "-f", composePath, ...args], {
|
|
34639
|
+
stdio: "inherit"
|
|
34640
|
+
});
|
|
34641
|
+
return res.status ?? 1;
|
|
34642
|
+
}
|
|
34643
|
+
function registerDevnetCommand(program2) {
|
|
34644
|
+
const devnet = program2.command("devnet").description("Run Secondlayer services against a local Clarinet devnet");
|
|
34645
|
+
devnet.command("connect").description("Point your clarinet project's devnet at a local Secondlayer stack and start it").option("--project <dir>", "Clarinet project directory (defaults to the nearest Clarinet.toml)").option("--image-tag <tag>", "Published image tag to run", DEFAULT_IMAGE_TAG).option("--owner <owner>", "ghcr image owner (namespace) to pull from").option("--no-up", "Patch config + write compose without starting docker").action(async (options) => {
|
|
34646
|
+
await connect(options);
|
|
34647
|
+
});
|
|
34648
|
+
devnet.command("down").description("Stop the local Secondlayer stack started by `sl devnet connect`").option("--project <dir>", "Clarinet project directory").option("--purge", "Also remove volumes (wipes the local index)").action(async (options) => {
|
|
34649
|
+
await down(options);
|
|
34650
|
+
});
|
|
34651
|
+
}
|
|
34652
|
+
function resolveProject(explicit) {
|
|
34653
|
+
if (explicit) {
|
|
34654
|
+
if (!existsSync3(join7(explicit, "Clarinet.toml"))) {
|
|
34655
|
+
error(`No Clarinet.toml in ${explicit}`);
|
|
34656
|
+
process.exit(1);
|
|
34657
|
+
}
|
|
34658
|
+
return explicit;
|
|
34659
|
+
}
|
|
34660
|
+
const found = findClarinetProject(process.cwd());
|
|
34661
|
+
if (!found) {
|
|
34662
|
+
error(`No Clarinet.toml found in this directory or any parent.
|
|
34663
|
+
` + "Run this from inside a clarinet project, or pass --project <dir>.");
|
|
34664
|
+
process.exit(1);
|
|
34665
|
+
}
|
|
34666
|
+
return found;
|
|
34667
|
+
}
|
|
34668
|
+
async function connect(options) {
|
|
34669
|
+
const project = resolveProject(options.project);
|
|
34670
|
+
const devnetToml = join7(project, "settings", "Devnet.toml");
|
|
34671
|
+
mkdirSync2(dirname4(devnetToml), { recursive: true });
|
|
34672
|
+
const result = ensureEventObserver(devnetToml, DEFAULT_INDEXER_OBSERVER);
|
|
34673
|
+
console.log(`${green("✓")} found Clarinet.toml`);
|
|
34674
|
+
if (result.status === "present") {
|
|
34675
|
+
console.log(dim(` settings/Devnet.toml already forwards to ${DEFAULT_INDEXER_OBSERVER}`));
|
|
34676
|
+
} else {
|
|
34677
|
+
console.log(`${green("✓")} ${result.status === "created" ? "created" : "patched"} settings/Devnet.toml`);
|
|
34678
|
+
console.log(dim(` + stacks_node_events_observers = ["${DEFAULT_INDEXER_OBSERVER}"]`));
|
|
34679
|
+
}
|
|
34680
|
+
const composePath = join7(project, COMPOSE_REL);
|
|
34681
|
+
mkdirSync2(dirname4(composePath), { recursive: true });
|
|
34682
|
+
writeFileSync3(composePath, buildDevnetCompose({ owner: options.owner, imageTag: options.imageTag }));
|
|
34683
|
+
console.log(`${green("✓")} wrote ${COMPOSE_REL}`);
|
|
34684
|
+
if (!options.up) {
|
|
34685
|
+
console.log(dim(`
|
|
34686
|
+
Skipped docker. Start it with:
|
|
34687
|
+
docker compose -f ${COMPOSE_REL} up -d`));
|
|
34688
|
+
return;
|
|
34689
|
+
}
|
|
34690
|
+
ensureDocker();
|
|
34691
|
+
console.log(dim(`
|
|
34692
|
+
Starting Secondlayer stack (docker compose up -d)…`));
|
|
34693
|
+
if (dockerCompose(composePath, ["up", "-d"]) !== 0) {
|
|
34694
|
+
error("docker compose up failed — see output above.");
|
|
34695
|
+
process.exit(1);
|
|
34696
|
+
}
|
|
34697
|
+
console.log(`
|
|
34698
|
+
${bold("Secondlayer stack up")}`);
|
|
34699
|
+
console.log(` api → ${cyan("http://localhost:3800")}`);
|
|
34700
|
+
console.log(` indexer → ${cyan("http://localhost:3700")}`);
|
|
34701
|
+
console.log(`
|
|
34702
|
+
${bold("Next:")}`);
|
|
34703
|
+
console.log(` ${yellow("clarinet devnet start")} ${dim("# auto-deploys + streams to the indexer")}`);
|
|
34704
|
+
console.log(` ${yellow("SL_API_URL=http://localhost:3800 SL_SERVICE_KEY=dummy sl subgraphs deploy ./subgraph.ts")}`);
|
|
34705
|
+
console.log(dim(`
|
|
34706
|
+
Stop with: sl devnet down`));
|
|
34707
|
+
}
|
|
34708
|
+
async function down(options) {
|
|
34709
|
+
const project = resolveProject(options.project);
|
|
34710
|
+
const composePath = join7(project, COMPOSE_REL);
|
|
34711
|
+
if (!existsSync3(composePath)) {
|
|
34712
|
+
error(`No ${COMPOSE_REL} in ${project} — nothing to stop. Run \`sl devnet connect\` first.`);
|
|
34713
|
+
process.exit(1);
|
|
34714
|
+
}
|
|
34715
|
+
ensureDocker();
|
|
34716
|
+
const args = options.purge ? ["down", "-v"] : ["down"];
|
|
34717
|
+
if (dockerCompose(composePath, args) !== 0) {
|
|
34718
|
+
error("docker compose down failed — see output above.");
|
|
34719
|
+
process.exit(1);
|
|
34720
|
+
}
|
|
34721
|
+
console.log(`${green("✓")}${options.purge ? " stack stopped, volumes removed" : " stack stopped"}`);
|
|
34722
|
+
}
|
|
34432
34723
|
// src/commands/subgraphs.ts
|
|
34433
34724
|
import { spawn } from "node:child_process";
|
|
34434
34725
|
import {
|
|
34435
|
-
existsSync as
|
|
34436
|
-
mkdirSync as
|
|
34437
|
-
readFileSync as
|
|
34726
|
+
existsSync as existsSync4,
|
|
34727
|
+
mkdirSync as mkdirSync3,
|
|
34728
|
+
readFileSync as readFileSync3,
|
|
34438
34729
|
watch,
|
|
34439
|
-
writeFileSync as
|
|
34730
|
+
writeFileSync as writeFileSync4
|
|
34440
34731
|
} from "node:fs";
|
|
34441
|
-
import { dirname as
|
|
34732
|
+
import { dirname as dirname5, join as join8, resolve as resolve2 } from "node:path";
|
|
34442
34733
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
34443
34734
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
34444
34735
|
|
|
34445
34736
|
// src/generators/subgraph-scaffold.ts
|
|
34446
34737
|
init_format();
|
|
34738
|
+
import { classifyContract } from "@secondlayer/stacks/clarity";
|
|
34447
34739
|
|
|
34448
34740
|
// src/generators/clarity-to-subgraph.ts
|
|
34449
34741
|
import {
|
|
@@ -34496,65 +34788,121 @@ function mapType(abiType, nullable) {
|
|
|
34496
34788
|
function toCamelCase2(str) {
|
|
34497
34789
|
return str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
34498
34790
|
}
|
|
34499
|
-
|
|
34500
|
-
|
|
34501
|
-
|
|
34502
|
-
|
|
34503
|
-
|
|
34504
|
-
const publicFunctions = functions.filter((f) => f.access === "public");
|
|
34505
|
-
if (publicFunctions.length === 0) {
|
|
34506
|
-
throw new Error(`No public functions found in ${contractId}`);
|
|
34507
|
-
}
|
|
34508
|
-
const sourceEntries = publicFunctions.map((fn) => {
|
|
34509
|
-
const sourceName = toCamelCase2(fn.name);
|
|
34510
|
-
return ` ${sourceName}: { type: 'contract_call', contractId: '${contractId}', functionName: '${fn.name}' }`;
|
|
34511
|
-
});
|
|
34512
|
-
const sourcesBlock = sourceEntries.join(`,
|
|
34513
|
-
`);
|
|
34514
|
-
const tables = publicFunctions.map((fn) => {
|
|
34515
|
-
const columns = fn.args.map((arg) => {
|
|
34516
|
-
const mapped = clarityTypeToSubgraphColumn(arg.type);
|
|
34517
|
-
const nullable = mapped.nullable ? ", nullable: true" : "";
|
|
34518
|
-
return ` ${arg.name.replace(/-/g, "_")}: { type: '${mapped.type}'${nullable} }`;
|
|
34519
|
-
}).join(`,
|
|
34520
|
-
`);
|
|
34521
|
-
const tableName = fn.name.replace(/-/g, "_");
|
|
34522
|
-
return ` ${tableName}: {
|
|
34523
|
-
columns: {
|
|
34524
|
-
${columns || " _placeholder: { type: 'text' }"}
|
|
34525
|
-
}
|
|
34526
|
-
}`;
|
|
34527
|
-
});
|
|
34528
|
-
const schemaBlock = tables.join(`,
|
|
34529
|
-
`);
|
|
34530
|
-
const handlerEntries = publicFunctions.map((fn) => {
|
|
34531
|
-
const sourceName = toCamelCase2(fn.name);
|
|
34532
|
-
return ` ${sourceName}: async (event, ctx) => {
|
|
34533
|
-
// TODO: implement ${fn.name} handler
|
|
34534
|
-
// event.args contains the function arguments
|
|
34535
|
-
// ctx.insert('${fn.name.replace(/-/g, "_")}', { ... })
|
|
34536
|
-
}`;
|
|
34537
|
-
});
|
|
34538
|
-
const handlersBlock = handlerEntries.join(`,
|
|
34539
|
-
|
|
34540
|
-
`);
|
|
34541
|
-
const code = `
|
|
34791
|
+
function snake(str) {
|
|
34792
|
+
return str.replace(/-/g, "_");
|
|
34793
|
+
}
|
|
34794
|
+
function wrap(name, sources, schema, handlers) {
|
|
34795
|
+
return `
|
|
34542
34796
|
import { defineSubgraph } from '@secondlayer/subgraphs';
|
|
34543
34797
|
|
|
34544
34798
|
export default defineSubgraph({
|
|
34545
|
-
name: '${
|
|
34799
|
+
name: '${name}',
|
|
34546
34800
|
sources: {
|
|
34547
|
-
${
|
|
34801
|
+
${sources}
|
|
34548
34802
|
},
|
|
34549
34803
|
schema: {
|
|
34550
|
-
${
|
|
34804
|
+
${schema}
|
|
34551
34805
|
},
|
|
34552
34806
|
handlers: {
|
|
34553
|
-
${
|
|
34807
|
+
${handlers}
|
|
34554
34808
|
}
|
|
34555
34809
|
});
|
|
34556
34810
|
`.trimStart();
|
|
34557
|
-
|
|
34811
|
+
}
|
|
34812
|
+
function tokenScaffold(name, source) {
|
|
34813
|
+
const isFt = source.type === "ft_transfer";
|
|
34814
|
+
const scope = source.trait ? `trait: '${source.trait}'` : `assetIdentifier: '${source.assetIdentifier}'`;
|
|
34815
|
+
const cols = isFt ? ` sender: { type: 'principal' },
|
|
34816
|
+
recipient: { type: 'principal' },
|
|
34817
|
+
amount: { type: 'uint' },
|
|
34818
|
+
asset_identifier: { type: 'principal', indexed: true }` : ` sender: { type: 'principal' },
|
|
34819
|
+
recipient: { type: 'principal' },
|
|
34820
|
+
token_id: { type: 'text' },
|
|
34821
|
+
asset_identifier: { type: 'principal', indexed: true }`;
|
|
34822
|
+
const insert = isFt ? `{ sender: event.sender, recipient: event.recipient, amount: event.amount, asset_identifier: event.assetIdentifier }` : `{ sender: event.sender, recipient: event.recipient, token_id: String(event.tokenId), asset_identifier: event.assetIdentifier }`;
|
|
34823
|
+
return wrap(name, ` transfers: { type: '${source.type}', ${scope} }`, ` transfers: {
|
|
34824
|
+
columns: {
|
|
34825
|
+
${cols}
|
|
34826
|
+
}
|
|
34827
|
+
}`, ` transfers: (event, ctx) => {
|
|
34828
|
+
ctx.insert('transfers', ${insert});
|
|
34829
|
+
}`);
|
|
34830
|
+
}
|
|
34831
|
+
function genericCallsScaffold(name, contractId) {
|
|
34832
|
+
return wrap(name, ` calls: { type: 'contract_call', contractId: '${contractId}' }`, ` calls: {
|
|
34833
|
+
columns: {
|
|
34834
|
+
function_name: { type: 'text', indexed: true },
|
|
34835
|
+
sender: { type: 'principal' },
|
|
34836
|
+
args: { type: 'jsonb' }
|
|
34837
|
+
}
|
|
34838
|
+
}`, ` calls: (event, ctx) => {
|
|
34839
|
+
ctx.insert('calls', { function_name: event.functionName, sender: event.sender, args: { values: event.args } });
|
|
34840
|
+
}`);
|
|
34841
|
+
}
|
|
34842
|
+
function functionsScaffold(name, contractId, abi, fnNames) {
|
|
34843
|
+
const fns = abi.functions.filter((f) => f.access === "public" && fnNames.includes(f.name));
|
|
34844
|
+
if (fns.length === 0) {
|
|
34845
|
+
throw new Error(`none of --functions [${fnNames.join(", ")}] are public functions of ${contractId}`);
|
|
34846
|
+
}
|
|
34847
|
+
const sources = fns.map((f) => ` ${toCamelCase2(f.name)}: { type: 'contract_call', contractId: '${contractId}', functionName: '${f.name}' }`).join(`,
|
|
34848
|
+
`);
|
|
34849
|
+
const schema = fns.map((f) => {
|
|
34850
|
+
const cols = f.args.map((arg) => {
|
|
34851
|
+
const m = clarityTypeToSubgraphColumn(arg.type);
|
|
34852
|
+
return ` ${snake(arg.name)}: { type: '${m.type}'${m.nullable ? ", nullable: true" : ""} }`;
|
|
34853
|
+
}).join(`,
|
|
34854
|
+
`);
|
|
34855
|
+
return ` ${snake(f.name)}: {
|
|
34856
|
+
columns: {
|
|
34857
|
+
${cols || " sender: { type: 'principal' }"}
|
|
34858
|
+
}
|
|
34859
|
+
}`;
|
|
34860
|
+
}).join(`,
|
|
34861
|
+
`);
|
|
34862
|
+
const handlers = fns.map((f) => {
|
|
34863
|
+
const inserts = f.args.map((arg, i) => {
|
|
34864
|
+
const m = clarityTypeToSubgraphColumn(arg.type);
|
|
34865
|
+
const ts = m.type === "uint" || m.type === "int" ? "bigint" : m.type === "boolean" ? "boolean" : "string";
|
|
34866
|
+
return `${snake(arg.name)}: event.args[${i}] as ${ts}`;
|
|
34867
|
+
}).join(", ");
|
|
34868
|
+
return ` ${toCamelCase2(f.name)}: (event, ctx) => {
|
|
34869
|
+
ctx.insert('${snake(f.name)}', { ${inserts} });
|
|
34870
|
+
}`;
|
|
34871
|
+
}).join(`,
|
|
34872
|
+
|
|
34873
|
+
`);
|
|
34874
|
+
return wrap(name, sources, schema, handlers);
|
|
34875
|
+
}
|
|
34876
|
+
async function generateSubgraphScaffold(input2) {
|
|
34877
|
+
if (input2.trait) {
|
|
34878
|
+
const name2 = input2.subgraphName ?? `${input2.trait}-transfers`;
|
|
34879
|
+
const type = input2.trait === "sip-009" ? "nft_transfer" : "ft_transfer";
|
|
34880
|
+
return formatCode(tokenScaffold(name2, { type, trait: input2.trait }));
|
|
34881
|
+
}
|
|
34882
|
+
const { contractId, abi } = input2;
|
|
34883
|
+
if (!contractId || !abi) {
|
|
34884
|
+
throw new Error("scaffold requires a contractId + abi (or --trait)");
|
|
34885
|
+
}
|
|
34886
|
+
const name = input2.subgraphName ?? contractId.split(".").pop() ?? contractId;
|
|
34887
|
+
if (input2.functions && input2.functions.length > 0) {
|
|
34888
|
+
return formatCode(functionsScaffold(name, contractId, abi, input2.functions));
|
|
34889
|
+
}
|
|
34890
|
+
const standards = classifyContract(abi);
|
|
34891
|
+
if (standards.includes("sip-010")) {
|
|
34892
|
+
const asset = abi.fungible_tokens?.[0]?.name;
|
|
34893
|
+
return formatCode(tokenScaffold(name, {
|
|
34894
|
+
type: "ft_transfer",
|
|
34895
|
+
assetIdentifier: asset ? `${contractId}::${asset}` : contractId
|
|
34896
|
+
}));
|
|
34897
|
+
}
|
|
34898
|
+
if (standards.includes("sip-009")) {
|
|
34899
|
+
const asset = abi.non_fungible_tokens?.[0]?.name;
|
|
34900
|
+
return formatCode(tokenScaffold(name, {
|
|
34901
|
+
type: "nft_transfer",
|
|
34902
|
+
assetIdentifier: asset ? `${contractId}::${asset}` : contractId
|
|
34903
|
+
}));
|
|
34904
|
+
}
|
|
34905
|
+
return formatCode(genericCallsScaffold(name, contractId));
|
|
34558
34906
|
}
|
|
34559
34907
|
|
|
34560
34908
|
// src/utils/case-conversion.ts
|
|
@@ -35192,8 +35540,8 @@ async function writeOrPrintSubgraphSpec(spec, format, output) {
|
|
|
35192
35540
|
}
|
|
35193
35541
|
const outPath = resolve2(output);
|
|
35194
35542
|
const dir = resolve2(outPath, "..");
|
|
35195
|
-
if (!
|
|
35196
|
-
|
|
35543
|
+
if (!existsSync4(dir))
|
|
35544
|
+
mkdirSync3(dir, { recursive: true });
|
|
35197
35545
|
await writeTextFile(outPath, text);
|
|
35198
35546
|
success(`Created ${outPath}`);
|
|
35199
35547
|
}
|
|
@@ -35255,15 +35603,15 @@ function createLocalSubgraphDetail(input3) {
|
|
|
35255
35603
|
};
|
|
35256
35604
|
}
|
|
35257
35605
|
function readCliSubgraphsDependency() {
|
|
35258
|
-
const here =
|
|
35606
|
+
const here = dirname5(fileURLToPath2(import.meta.url));
|
|
35259
35607
|
const candidates = [
|
|
35260
35608
|
resolve2(here, "..", "..", "package.json"),
|
|
35261
35609
|
resolve2(here, "..", "package.json")
|
|
35262
35610
|
];
|
|
35263
35611
|
for (const candidate of candidates) {
|
|
35264
|
-
if (!
|
|
35612
|
+
if (!existsSync4(candidate))
|
|
35265
35613
|
continue;
|
|
35266
|
-
const pkg = JSON.parse(
|
|
35614
|
+
const pkg = JSON.parse(readFileSync3(candidate, "utf8"));
|
|
35267
35615
|
const dep = pkg.dependencies?.["@secondlayer/subgraphs"];
|
|
35268
35616
|
if (dep)
|
|
35269
35617
|
return dep;
|
|
@@ -35271,10 +35619,10 @@ function readCliSubgraphsDependency() {
|
|
|
35271
35619
|
return "^1.3.2";
|
|
35272
35620
|
}
|
|
35273
35621
|
function ensureScaffoldPackageJson(dir) {
|
|
35274
|
-
const packagePath =
|
|
35622
|
+
const packagePath = join8(dir, "package.json");
|
|
35275
35623
|
const subgraphsDep = readCliSubgraphsDependency();
|
|
35276
|
-
if (!
|
|
35277
|
-
|
|
35624
|
+
if (!existsSync4(packagePath)) {
|
|
35625
|
+
writeFileSync4(packagePath, `${JSON.stringify({
|
|
35278
35626
|
type: "module",
|
|
35279
35627
|
dependencies: {
|
|
35280
35628
|
"@secondlayer/subgraphs": subgraphsDep
|
|
@@ -35283,14 +35631,14 @@ function ensureScaffoldPackageJson(dir) {
|
|
|
35283
35631
|
`, "utf8");
|
|
35284
35632
|
return;
|
|
35285
35633
|
}
|
|
35286
|
-
const pkg = JSON.parse(
|
|
35634
|
+
const pkg = JSON.parse(readFileSync3(packagePath, "utf8"));
|
|
35287
35635
|
if (pkg.dependencies?.["@secondlayer/subgraphs"])
|
|
35288
35636
|
return;
|
|
35289
35637
|
pkg.dependencies = {
|
|
35290
35638
|
...pkg.dependencies ?? {},
|
|
35291
35639
|
"@secondlayer/subgraphs": subgraphsDep
|
|
35292
35640
|
};
|
|
35293
|
-
|
|
35641
|
+
writeFileSync4(packagePath, `${JSON.stringify(pkg, null, 2)}
|
|
35294
35642
|
`, "utf8");
|
|
35295
35643
|
}
|
|
35296
35644
|
async function runBunInstall(dir) {
|
|
@@ -35399,12 +35747,12 @@ ${SUBGRAPH_TEMPLATE_SLUGS.map((s) => ` ${s.padEnd(20)} ${SUBGRAPH_TEMPLATE_DESC
|
|
|
35399
35747
|
}
|
|
35400
35748
|
const dir = resolve2("subgraphs");
|
|
35401
35749
|
const filePath = resolve2(dir, `${name}.ts`);
|
|
35402
|
-
if (
|
|
35750
|
+
if (existsSync4(filePath)) {
|
|
35403
35751
|
error(`File already exists: ${filePath}`);
|
|
35404
35752
|
process.exit(1);
|
|
35405
35753
|
}
|
|
35406
|
-
if (!
|
|
35407
|
-
|
|
35754
|
+
if (!existsSync4(dir)) {
|
|
35755
|
+
mkdirSync3(dir, { recursive: true });
|
|
35408
35756
|
}
|
|
35409
35757
|
const content = generateSubgraphTemplate(name, slug);
|
|
35410
35758
|
await writeTextFile(filePath, content);
|
|
@@ -35417,7 +35765,7 @@ ${SUBGRAPH_TEMPLATE_SLUGS.map((s) => ` ${s.padEnd(20)} ${SUBGRAPH_TEMPLATE_DESC
|
|
|
35417
35765
|
subgraphs.command("dev <file>").description("Watch a subgraph file and auto-redeploy on change").action(async (file) => {
|
|
35418
35766
|
await requireLocalNetwork();
|
|
35419
35767
|
const absPath = resolve2(file);
|
|
35420
|
-
if (!
|
|
35768
|
+
if (!existsSync4(absPath)) {
|
|
35421
35769
|
error(`File not found: ${absPath}`);
|
|
35422
35770
|
process.exit(1);
|
|
35423
35771
|
}
|
|
@@ -35734,7 +36082,7 @@ Synced — exiting watch.`));
|
|
|
35734
36082
|
try {
|
|
35735
36083
|
const format = parseSubgraphSpecFormat(options2.format);
|
|
35736
36084
|
const absPath = resolve2(file);
|
|
35737
|
-
if (!
|
|
36085
|
+
if (!existsSync4(absPath)) {
|
|
35738
36086
|
error(`File not found: ${absPath}`);
|
|
35739
36087
|
process.exit(1);
|
|
35740
36088
|
}
|
|
@@ -35784,7 +36132,7 @@ Synced — exiting watch.`));
|
|
|
35784
36132
|
process.exit(1);
|
|
35785
36133
|
}
|
|
35786
36134
|
const absPath = resolve2(file);
|
|
35787
|
-
if (!
|
|
36135
|
+
if (!existsSync4(absPath)) {
|
|
35788
36136
|
error(`File not found: ${absPath}`);
|
|
35789
36137
|
process.exit(1);
|
|
35790
36138
|
}
|
|
@@ -36011,27 +36359,44 @@ ${rows.length} row(s)`));
|
|
|
36011
36359
|
handleApiError(err, "delete subgraph");
|
|
36012
36360
|
}
|
|
36013
36361
|
});
|
|
36014
|
-
subgraphs.command("scaffold
|
|
36362
|
+
subgraphs.command("scaffold [contractAddress]").description("Scaffold a defineSubgraph() file. Detects SIP-010/009 → ft/nft source; --functions for typed call tables; --trait for a trait-scoped source (no contract)").option("-o, --output <path>", "Output file path (required)").option("--api-key <key>", "Stacks node API key for direct RPC URLs").option("--functions <names>", "Comma-separated public functions to index as typed contract_call tables").option("--trait <std>", "Scaffold a trait-scoped source (sip-009|sip-010|sip-013) — no contract needed").option("--no-install", "Skip bun install after writing package.json").action(async (contractAddress, options2) => {
|
|
36015
36363
|
try {
|
|
36016
36364
|
if (!options2.output) {
|
|
36017
36365
|
error("--output <path> is required");
|
|
36018
36366
|
process.exit(1);
|
|
36019
36367
|
}
|
|
36368
|
+
const trait = options2.trait;
|
|
36369
|
+
if (trait && !["sip-009", "sip-010", "sip-013"].includes(trait)) {
|
|
36370
|
+
error("--trait must be one of: sip-009, sip-010, sip-013");
|
|
36371
|
+
process.exit(1);
|
|
36372
|
+
}
|
|
36373
|
+
if (!trait && !contractAddress) {
|
|
36374
|
+
error("a <contractAddress> is required (or use --trait)");
|
|
36375
|
+
process.exit(1);
|
|
36376
|
+
}
|
|
36020
36377
|
const outPath = resolve2(options2.output);
|
|
36021
|
-
|
|
36022
|
-
|
|
36023
|
-
|
|
36024
|
-
|
|
36025
|
-
|
|
36026
|
-
|
|
36027
|
-
|
|
36028
|
-
|
|
36029
|
-
|
|
36030
|
-
|
|
36031
|
-
|
|
36378
|
+
let content;
|
|
36379
|
+
if (trait) {
|
|
36380
|
+
info(`Generating trait-scoped scaffold for ${trait}...`);
|
|
36381
|
+
content = await generateSubgraphScaffold({ trait });
|
|
36382
|
+
} else {
|
|
36383
|
+
const address = contractAddress;
|
|
36384
|
+
const network = inferNetwork(address) ?? "mainnet";
|
|
36385
|
+
const apiKey = options2.apiKey ?? process.env.STACKS_NODE_API_KEY ?? process.env.HIRO_API_KEY;
|
|
36386
|
+
const client = new StacksApiClient(network, apiKey);
|
|
36387
|
+
info(`Fetching ABI for ${address} via ${client.describeContractInfoSource()}...`);
|
|
36388
|
+
const contractInfo = await client.getContractInfo(address);
|
|
36389
|
+
const abi = parseApiResponse(contractInfo);
|
|
36390
|
+
info("Generating scaffold...");
|
|
36391
|
+
content = await generateSubgraphScaffold({
|
|
36392
|
+
contractId: address,
|
|
36393
|
+
abi,
|
|
36394
|
+
functions: options2.functions?.split(",").map((f) => f.trim()).filter(Boolean)
|
|
36395
|
+
});
|
|
36396
|
+
}
|
|
36032
36397
|
const dir = resolve2(outPath, "..");
|
|
36033
|
-
if (!
|
|
36034
|
-
|
|
36398
|
+
if (!existsSync4(dir))
|
|
36399
|
+
mkdirSync3(dir, { recursive: true });
|
|
36035
36400
|
await writeTextFile(outPath, content);
|
|
36036
36401
|
ensureScaffoldPackageJson(dir);
|
|
36037
36402
|
success(`Created ${outPath}`);
|
|
@@ -36065,8 +36430,8 @@ ${rows.length} row(s)`));
|
|
|
36065
36430
|
info("Generating typed client...");
|
|
36066
36431
|
const content = await generateSubgraphConsumer(subgraphName, subgraphDetail);
|
|
36067
36432
|
const dir = resolve2(outPath, "..");
|
|
36068
|
-
if (!
|
|
36069
|
-
|
|
36433
|
+
if (!existsSync4(dir))
|
|
36434
|
+
mkdirSync3(dir, { recursive: true });
|
|
36070
36435
|
await writeTextFile(outPath, content);
|
|
36071
36436
|
success(`Created ${outPath}`);
|
|
36072
36437
|
} catch (err) {
|
|
@@ -36399,6 +36764,60 @@ function registerStreamsCommand(program2) {
|
|
|
36399
36764
|
}
|
|
36400
36765
|
});
|
|
36401
36766
|
}
|
|
36767
|
+
// src/commands/datasets.ts
|
|
36768
|
+
init_output();
|
|
36769
|
+
import { CURSOR_SLUGS, Datasets } from "@secondlayer/sdk";
|
|
36770
|
+
var DEFAULT_BASE_URL2 = "https://api.secondlayer.tools";
|
|
36771
|
+
function client2() {
|
|
36772
|
+
return new Datasets({ baseUrl: process.env.SL_API_URL ?? DEFAULT_BASE_URL2 });
|
|
36773
|
+
}
|
|
36774
|
+
function parseFilters(pairs) {
|
|
36775
|
+
const out = {};
|
|
36776
|
+
for (const pair of pairs ?? []) {
|
|
36777
|
+
const eq = pair.indexOf("=");
|
|
36778
|
+
if (eq <= 0) {
|
|
36779
|
+
throw new Error(`invalid --filter "${pair}" (expected key=value)`);
|
|
36780
|
+
}
|
|
36781
|
+
out[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
36782
|
+
}
|
|
36783
|
+
return out;
|
|
36784
|
+
}
|
|
36785
|
+
function registerDatasetsCommand(program2) {
|
|
36786
|
+
const datasets = program2.command("datasets").description("Query Foundation Datasets (sBTC, BNS, PoX-4, STX transfers)");
|
|
36787
|
+
datasets.command("list").description("List the dataset catalog + freshness").action(async () => {
|
|
36788
|
+
try {
|
|
36789
|
+
const catalog = await client2().listDatasets();
|
|
36790
|
+
process.stdout.write(`${JSON.stringify(catalog, null, 2)}
|
|
36791
|
+
`);
|
|
36792
|
+
} catch (err) {
|
|
36793
|
+
error(`Failed to list datasets: ${err}`);
|
|
36794
|
+
process.exit(1);
|
|
36795
|
+
}
|
|
36796
|
+
});
|
|
36797
|
+
datasets.command("query <dataset>").description(`Query a cursor-paginated dataset (${Object.keys(CURSOR_SLUGS).join(", ")})`).option("--filter <key=value...>", "Filter as key=value (e.g. --filter stacker=SP… --filter address=SP…)").option("--limit <n>", "Rows per page").option("--cursor <cursor>", "Resume token from a previous next_cursor").option("--json", "Print the full envelope as JSON").action(async (dataset, options2) => {
|
|
36798
|
+
try {
|
|
36799
|
+
const params = parseFilters(options2.filter);
|
|
36800
|
+
if (options2.limit)
|
|
36801
|
+
params.limit = Number.parseInt(options2.limit, 10);
|
|
36802
|
+
if (options2.cursor)
|
|
36803
|
+
params.cursor = options2.cursor;
|
|
36804
|
+
const env = await client2().query(dataset, params);
|
|
36805
|
+
if (options2.json) {
|
|
36806
|
+
process.stdout.write(`${JSON.stringify(env, null, 2)}
|
|
36807
|
+
`);
|
|
36808
|
+
} else {
|
|
36809
|
+
process.stdout.write(`${JSON.stringify(env.rows, null, 2)}
|
|
36810
|
+
`);
|
|
36811
|
+
if (env.next_cursor) {
|
|
36812
|
+
info(`next_cursor: ${env.next_cursor}`);
|
|
36813
|
+
}
|
|
36814
|
+
}
|
|
36815
|
+
} catch (err) {
|
|
36816
|
+
error(`Failed to query dataset: ${err}`);
|
|
36817
|
+
process.exit(1);
|
|
36818
|
+
}
|
|
36819
|
+
});
|
|
36820
|
+
}
|
|
36402
36821
|
// src/commands/doctor.ts
|
|
36403
36822
|
init_config();
|
|
36404
36823
|
|
|
@@ -37024,10 +37443,10 @@ init_config();
|
|
|
37024
37443
|
init_output();
|
|
37025
37444
|
|
|
37026
37445
|
// src/lib/project-file.ts
|
|
37027
|
-
import { existsSync as
|
|
37446
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
37028
37447
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
37029
37448
|
import { homedir as homedir5 } from "node:os";
|
|
37030
|
-
import { dirname as
|
|
37449
|
+
import { dirname as dirname11, join as join10, parse as parsePath2, resolve as resolve8 } from "node:path";
|
|
37031
37450
|
import { z as z3 } from "zod/v4";
|
|
37032
37451
|
var ProjectFileSchema = z3.object({
|
|
37033
37452
|
slug: z3.string().min(1)
|
|
@@ -37037,21 +37456,21 @@ var DIRNAME = ".secondlayer";
|
|
|
37037
37456
|
async function readActiveProject(cwd, globalDefault) {
|
|
37038
37457
|
let dir = resolve8(cwd);
|
|
37039
37458
|
const home = resolve8(homedir5());
|
|
37040
|
-
const fsRoot =
|
|
37459
|
+
const fsRoot = parsePath2(dir).root;
|
|
37041
37460
|
while (true) {
|
|
37042
|
-
const candidate =
|
|
37043
|
-
if (
|
|
37461
|
+
const candidate = join10(dir, DIRNAME, FILENAME);
|
|
37462
|
+
if (existsSync5(candidate)) {
|
|
37044
37463
|
try {
|
|
37045
37464
|
const raw = await readFile3(candidate, "utf8");
|
|
37046
37465
|
const parsed = ProjectFileSchema.parse(JSON.parse(raw));
|
|
37047
37466
|
return { slug: parsed.slug, resolvedFrom: candidate };
|
|
37048
37467
|
} catch {}
|
|
37049
37468
|
}
|
|
37050
|
-
if (
|
|
37469
|
+
if (existsSync5(join10(dir, ".git")))
|
|
37051
37470
|
break;
|
|
37052
37471
|
if (dir === home || dir === fsRoot)
|
|
37053
37472
|
break;
|
|
37054
|
-
const parent =
|
|
37473
|
+
const parent = dirname11(dir);
|
|
37055
37474
|
if (parent === dir)
|
|
37056
37475
|
break;
|
|
37057
37476
|
dir = parent;
|
|
@@ -37059,15 +37478,15 @@ async function readActiveProject(cwd, globalDefault) {
|
|
|
37059
37478
|
if (globalDefault) {
|
|
37060
37479
|
return {
|
|
37061
37480
|
slug: globalDefault,
|
|
37062
|
-
resolvedFrom:
|
|
37481
|
+
resolvedFrom: join10(homedir5(), ".secondlayer", "config.json")
|
|
37063
37482
|
};
|
|
37064
37483
|
}
|
|
37065
37484
|
return null;
|
|
37066
37485
|
}
|
|
37067
37486
|
async function writeActiveProject(slug, cwd) {
|
|
37068
|
-
const dir =
|
|
37487
|
+
const dir = join10(resolve8(cwd), DIRNAME);
|
|
37069
37488
|
await mkdir3(dir, { recursive: true });
|
|
37070
|
-
const file =
|
|
37489
|
+
const file = join10(dir, FILENAME);
|
|
37071
37490
|
await writeFile3(file, `${JSON.stringify({ slug }, null, 2)}
|
|
37072
37491
|
`, "utf8");
|
|
37073
37492
|
return file;
|
|
@@ -37265,15 +37684,17 @@ registerSubgraphsCommand(program);
|
|
|
37265
37684
|
registerCreateCommand(program);
|
|
37266
37685
|
registerSubscriptionsCommand(program);
|
|
37267
37686
|
registerStreamsCommand(program);
|
|
37687
|
+
registerDatasetsCommand(program);
|
|
37268
37688
|
registerStatusCommand(program);
|
|
37269
37689
|
registerStackCommand(program);
|
|
37270
37690
|
registerDbCommand(program);
|
|
37271
37691
|
registerDoctorCommand(program);
|
|
37272
37692
|
registerConfigCommand(program);
|
|
37273
37693
|
registerLocalCommand(program);
|
|
37694
|
+
registerDevnetCommand(program);
|
|
37274
37695
|
registerAccountCommand(program);
|
|
37275
37696
|
registerBillingCommand(program);
|
|
37276
37697
|
program.parse();
|
|
37277
37698
|
|
|
37278
|
-
//# debugId=
|
|
37699
|
+
//# debugId=FDDBCAB122A19D1564756E2164756E21
|
|
37279
37700
|
//# sourceMappingURL=cli.js.map
|