@sentio/cli 3.4.2-rc.1 → 3.5.0-rc.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/lib/index.js CHANGED
@@ -1220,7 +1220,7 @@ var require_command = __commonJS({
1220
1220
  var childProcess4 = __require("node:child_process");
1221
1221
  var path16 = __require("node:path");
1222
1222
  var fs20 = __require("node:fs");
1223
- var process24 = __require("node:process");
1223
+ var process25 = __require("node:process");
1224
1224
  var { Argument: Argument7, humanReadableArgName } = require_argument();
1225
1225
  var { CommanderError: CommanderError2 } = require_error();
1226
1226
  var { Help: Help2, stripColor } = require_help();
@@ -1267,13 +1267,13 @@ var require_command = __commonJS({
1267
1267
  this._showSuggestionAfterError = true;
1268
1268
  this._savedState = null;
1269
1269
  this._outputConfiguration = {
1270
- writeOut: (str) => process24.stdout.write(str),
1271
- writeErr: (str) => process24.stderr.write(str),
1270
+ writeOut: (str) => process25.stdout.write(str),
1271
+ writeErr: (str) => process25.stderr.write(str),
1272
1272
  outputError: (str, write) => write(str),
1273
- getOutHelpWidth: () => process24.stdout.isTTY ? process24.stdout.columns : void 0,
1274
- getErrHelpWidth: () => process24.stderr.isTTY ? process24.stderr.columns : void 0,
1275
- getOutHasColors: () => useColor() ?? (process24.stdout.isTTY && process24.stdout.hasColors?.()),
1276
- getErrHasColors: () => useColor() ?? (process24.stderr.isTTY && process24.stderr.hasColors?.()),
1273
+ getOutHelpWidth: () => process25.stdout.isTTY ? process25.stdout.columns : void 0,
1274
+ getErrHelpWidth: () => process25.stderr.isTTY ? process25.stderr.columns : void 0,
1275
+ getOutHasColors: () => useColor() ?? (process25.stdout.isTTY && process25.stdout.hasColors?.()),
1276
+ getErrHasColors: () => useColor() ?? (process25.stderr.isTTY && process25.stderr.hasColors?.()),
1277
1277
  stripColor: (str) => stripColor(str)
1278
1278
  };
1279
1279
  this._hidden = false;
@@ -1668,7 +1668,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1668
1668
  if (this._exitCallback) {
1669
1669
  this._exitCallback(new CommanderError2(exitCode, code, message));
1670
1670
  }
1671
- process24.exit(exitCode);
1671
+ process25.exit(exitCode);
1672
1672
  }
1673
1673
  /**
1674
1674
  * Register callback `fn` for the command.
@@ -2068,16 +2068,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
2068
2068
  }
2069
2069
  parseOptions = parseOptions || {};
2070
2070
  if (argv === void 0 && parseOptions.from === void 0) {
2071
- if (process24.versions?.electron) {
2071
+ if (process25.versions?.electron) {
2072
2072
  parseOptions.from = "electron";
2073
2073
  }
2074
- const execArgv = process24.execArgv ?? [];
2074
+ const execArgv = process25.execArgv ?? [];
2075
2075
  if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
2076
2076
  parseOptions.from = "eval";
2077
2077
  }
2078
2078
  }
2079
2079
  if (argv === void 0) {
2080
- argv = process24.argv;
2080
+ argv = process25.argv;
2081
2081
  }
2082
2082
  this.rawArgs = argv.slice();
2083
2083
  let userArgs;
@@ -2088,7 +2088,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2088
2088
  userArgs = argv.slice(2);
2089
2089
  break;
2090
2090
  case "electron":
2091
- if (process24.defaultApp) {
2091
+ if (process25.defaultApp) {
2092
2092
  this._scriptPath = argv[1];
2093
2093
  userArgs = argv.slice(2);
2094
2094
  } else {
@@ -2275,11 +2275,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
2275
2275
  }
2276
2276
  launchWithNode = sourceExt.includes(path16.extname(executableFile));
2277
2277
  let proc;
2278
- if (process24.platform !== "win32") {
2278
+ if (process25.platform !== "win32") {
2279
2279
  if (launchWithNode) {
2280
2280
  args.unshift(executableFile);
2281
- args = incrementNodeInspectorPort(process24.execArgv).concat(args);
2282
- proc = childProcess4.spawn(process24.argv[0], args, { stdio: "inherit" });
2281
+ args = incrementNodeInspectorPort(process25.execArgv).concat(args);
2282
+ proc = childProcess4.spawn(process25.argv[0], args, { stdio: "inherit" });
2283
2283
  } else {
2284
2284
  proc = childProcess4.spawn(executableFile, args, { stdio: "inherit" });
2285
2285
  }
@@ -2290,13 +2290,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2290
2290
  subcommand._name
2291
2291
  );
2292
2292
  args.unshift(executableFile);
2293
- args = incrementNodeInspectorPort(process24.execArgv).concat(args);
2294
- proc = childProcess4.spawn(process24.execPath, args, { stdio: "inherit" });
2293
+ args = incrementNodeInspectorPort(process25.execArgv).concat(args);
2294
+ proc = childProcess4.spawn(process25.execPath, args, { stdio: "inherit" });
2295
2295
  }
2296
2296
  if (!proc.killed) {
2297
2297
  const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
2298
2298
  signals.forEach((signal) => {
2299
- process24.on(signal, () => {
2299
+ process25.on(signal, () => {
2300
2300
  if (proc.killed === false && proc.exitCode === null) {
2301
2301
  proc.kill(signal);
2302
2302
  }
@@ -2307,7 +2307,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2307
2307
  proc.on("close", (code) => {
2308
2308
  code = code ?? 1;
2309
2309
  if (!exitCallback) {
2310
- process24.exit(code);
2310
+ process25.exit(code);
2311
2311
  } else {
2312
2312
  exitCallback(
2313
2313
  new CommanderError2(
@@ -2329,7 +2329,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2329
2329
  throw new Error(`'${executableFile}' not executable`);
2330
2330
  }
2331
2331
  if (!exitCallback) {
2332
- process24.exit(1);
2332
+ process25.exit(1);
2333
2333
  } else {
2334
2334
  const wrappedError = new CommanderError2(
2335
2335
  1,
@@ -2830,13 +2830,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
2830
2830
  */
2831
2831
  _parseOptionsEnv() {
2832
2832
  this.options.forEach((option2) => {
2833
- if (option2.envVar && option2.envVar in process24.env) {
2833
+ if (option2.envVar && option2.envVar in process25.env) {
2834
2834
  const optionKey = option2.attributeName();
2835
2835
  if (this.getOptionValue(optionKey) === void 0 || ["default", "config", "env"].includes(
2836
2836
  this.getOptionValueSource(optionKey)
2837
2837
  )) {
2838
2838
  if (option2.required || option2.optional) {
2839
- this.emit(`optionEnv:${option2.name()}`, process24.env[option2.envVar]);
2839
+ this.emit(`optionEnv:${option2.name()}`, process25.env[option2.envVar]);
2840
2840
  } else {
2841
2841
  this.emit(`optionEnv:${option2.name()}`);
2842
2842
  }
@@ -3360,7 +3360,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3360
3360
  */
3361
3361
  help(contextOptions) {
3362
3362
  this.outputHelp(contextOptions);
3363
- let exitCode = Number(process24.exitCode ?? 0);
3363
+ let exitCode = Number(process25.exitCode ?? 0);
3364
3364
  if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
3365
3365
  exitCode = 1;
3366
3366
  }
@@ -3450,9 +3450,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3450
3450
  });
3451
3451
  }
3452
3452
  function useColor() {
3453
- if (process24.env.NO_COLOR || process24.env.FORCE_COLOR === "0" || process24.env.FORCE_COLOR === "false")
3453
+ if (process25.env.NO_COLOR || process25.env.FORCE_COLOR === "0" || process25.env.FORCE_COLOR === "false")
3454
3454
  return false;
3455
- if (process24.env.FORCE_COLOR || process24.env.CLICOLOR_FORCE !== void 0)
3455
+ if (process25.env.FORCE_COLOR || process25.env.CLICOLOR_FORCE !== void 0)
3456
3456
  return true;
3457
3457
  return void 0;
3458
3458
  }
@@ -5903,10 +5903,10 @@ var require_directives = __commonJS({
5903
5903
  };
5904
5904
  var escapeTagName = (tn2) => tn2.replace(/[!,[\]{}]/g, (ch) => escapeChars[ch]);
5905
5905
  var Directives = class _Directives {
5906
- constructor(yaml12, tags) {
5906
+ constructor(yaml13, tags) {
5907
5907
  this.docStart = null;
5908
5908
  this.docEnd = false;
5909
- this.yaml = Object.assign({}, _Directives.defaultYaml, yaml12);
5909
+ this.yaml = Object.assign({}, _Directives.defaultYaml, yaml13);
5910
5910
  this.tags = Object.assign({}, _Directives.defaultTags, tags);
5911
5911
  }
5912
5912
  clone() {
@@ -41614,15 +41614,15 @@ var require_streams2 = __commonJS({
41614
41614
  var POOL_SIZE2 = 65536;
41615
41615
  if (!globalThis.ReadableStream) {
41616
41616
  try {
41617
- const process24 = __require("node:process");
41618
- const { emitWarning } = process24;
41617
+ const process25 = __require("node:process");
41618
+ const { emitWarning } = process25;
41619
41619
  try {
41620
- process24.emitWarning = () => {
41620
+ process25.emitWarning = () => {
41621
41621
  };
41622
41622
  Object.assign(globalThis, __require("node:stream/web"));
41623
- process24.emitWarning = emitWarning;
41623
+ process25.emitWarning = emitWarning;
41624
41624
  } catch (error) {
41625
- process24.emitWarning = emitWarning;
41625
+ process25.emitWarning = emitWarning;
41626
41626
  throw error;
41627
41627
  }
41628
41628
  } catch (error) {
@@ -141911,7 +141911,7 @@ var require_sdk_gen = __commonJS({
141911
141911
  }
141912
141912
  };
141913
141913
  exports.DataService = DataService2;
141914
- var WebService = class {
141914
+ var WebService2 = class {
141915
141915
  /**
141916
141916
  * List all dashboards in a project
141917
141917
  */
@@ -142094,7 +142094,7 @@ var require_sdk_gen = __commonJS({
142094
142094
  });
142095
142095
  }
142096
142096
  };
142097
- exports.WebService = WebService;
142097
+ exports.WebService = WebService2;
142098
142098
  var MoveService = class {
142099
142099
  /**
142100
142100
  * Get Aptos transaction call trace
@@ -151941,6 +151941,7 @@ function createProcessorCommand() {
151941
151941
  processorCommand.addCommand(createProcessorPauseCommand());
151942
151942
  processorCommand.addCommand(createProcessorResumeCommand());
151943
151943
  processorCommand.addCommand(createProcessorStopCommand());
151944
+ processorCommand.addCommand(createProcessorLogsCommand());
151944
151945
  return processorCommand;
151945
151946
  }
151946
151947
  function createProcessorStatusCommand() {
@@ -152011,6 +152012,17 @@ function createProcessorStopCommand() {
152011
152012
  }
152012
152013
  });
152013
152014
  }
152015
+ function createProcessorLogsCommand() {
152016
+ return withOutputOptions3(
152017
+ withSharedProjectOptions3(withAuthOptions3(new Command("logs").description("View processor logs")))
152018
+ ).showHelpAfterError().argument("[processorId]", "ID of the processor (defaults to active processor)").option("--limit <count>", "Maximum number of log entries to fetch", parseInteger2, 100).option("-f, --follow", "Poll for new log entries continuously").option("--log-type <type>", "Filter by log type (e.g. execution, system)").option("--level <level>", "Filter by log level: DEBUG, INFO, WARNING, ERROR").option("--query <query>", "Free-text filter query").action(async (processorId, options, command) => {
152019
+ try {
152020
+ await runProcessorLogs(processorId, options);
152021
+ } catch (error) {
152022
+ handleProcessorCommandError(error, command);
152023
+ }
152024
+ });
152025
+ }
152014
152026
  async function runProcessorStatus(options) {
152015
152027
  const context = createApiContext(options);
152016
152028
  const project = await resolveProjectRef(options, context, { ownerSlug: true });
@@ -152164,6 +152176,101 @@ async function runProcessorStop(processorId, options) {
152164
152176
  ...response
152165
152177
  });
152166
152178
  }
152179
+ async function resolveProcessorId(processorId, options) {
152180
+ if (processorId) return processorId;
152181
+ const context = createApiContext(options);
152182
+ const project = await resolveProjectRef(options, context, { ownerSlug: true });
152183
+ const statusResponse = await import_api5.ProcessorService.getProcessorStatusV2({
152184
+ path: { owner: project.owner, slug: project.slug },
152185
+ query: { version: "ACTIVE" },
152186
+ headers: context.headers
152187
+ });
152188
+ const data = unwrapApiResult(statusResponse);
152189
+ const processors = Array.isArray(data.processors) ? data.processors : [];
152190
+ const activeProcessor = processors.find((p7) => asString3(p7.versionState) === "ACTIVE");
152191
+ if (!activeProcessor || !activeProcessor.processorId) {
152192
+ throw new CliError(
152193
+ `No active processor found for project ${project.owner}/${project.slug}. Please specify a processorId.`
152194
+ );
152195
+ }
152196
+ return asString3(activeProcessor.processorId);
152197
+ }
152198
+ async function runProcessorLogs(processorId, options) {
152199
+ const resolvedProcessorId = await resolveProcessorId(processorId, options);
152200
+ const context = createApiContext(options);
152201
+ if (options.follow && !options.json && !options.yaml) {
152202
+ await followProcessorLogs(resolvedProcessorId, context, options);
152203
+ return;
152204
+ }
152205
+ const response = await postApiJson(
152206
+ `/api/v1/processors/${resolvedProcessorId}/logs`,
152207
+ context,
152208
+ buildLogsRequestBody(resolvedProcessorId, options)
152209
+ );
152210
+ printOutput3(options, response);
152211
+ }
152212
+ async function followProcessorLogs(processorId, context, options) {
152213
+ let until;
152214
+ let running = true;
152215
+ const seenIds = /* @__PURE__ */ new Set();
152216
+ process19.on("SIGINT", () => {
152217
+ running = false;
152218
+ });
152219
+ while (running) {
152220
+ try {
152221
+ const body = { ...buildLogsRequestBody(processorId, options), until };
152222
+ const response = await postApiJson(`/api/v1/processors/${processorId}/logs`, context, body);
152223
+ const entries2 = Array.isArray(response.logs) ? response.logs : [];
152224
+ for (const entry of entries2) {
152225
+ const e10 = entry;
152226
+ const id = e10.id ?? "";
152227
+ if (id && seenIds.has(id)) continue;
152228
+ if (id) seenIds.add(id);
152229
+ process19.stdout.write(formatLogEntry(e10) + "\n");
152230
+ }
152231
+ if (response.until) {
152232
+ until = response.until;
152233
+ }
152234
+ } catch {
152235
+ }
152236
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
152237
+ }
152238
+ }
152239
+ function buildLogsRequestBody(processorId, options) {
152240
+ const body = { processorId, limit: options.limit };
152241
+ if (options.logType) {
152242
+ body.logTypeFilters = [options.logType];
152243
+ }
152244
+ if (options.level || options.query) {
152245
+ const parts = [];
152246
+ if (options.level) parts.push(options.level.toUpperCase());
152247
+ if (options.query) parts.push(options.query);
152248
+ body.query = parts.join(" ");
152249
+ }
152250
+ return body;
152251
+ }
152252
+ function formatLogEntry(entry) {
152253
+ const formattedTime = entry.timestamp ? source_default.gray(entry.timestamp.replace("T", " ").replace("Z", "")) : "";
152254
+ const level = (entry.level ?? "INFO").toUpperCase();
152255
+ const logType = entry.logType ? source_default.gray(`[${entry.logType}]`) : "";
152256
+ const coloredLevel = colorSeverity(level);
152257
+ const message = entry.message ?? "";
152258
+ const chain4 = entry.chainId ? source_default.gray(`(chain=${entry.chainId})`) : "";
152259
+ return [formattedTime, coloredLevel, logType, message, chain4].filter(Boolean).join(" ");
152260
+ }
152261
+ function colorSeverity(severity) {
152262
+ switch (severity) {
152263
+ case "ERROR":
152264
+ return source_default.red(`[${severity}]`);
152265
+ case "WARNING":
152266
+ case "WARN":
152267
+ return source_default.yellow(`[${severity}]`);
152268
+ case "DEBUG":
152269
+ return source_default.gray(`[${severity}]`);
152270
+ default:
152271
+ return source_default.cyan(`[${severity}]`);
152272
+ }
152273
+ }
152167
152274
  function withAuthOptions3(command) {
152168
152275
  return command.option("--host <host>", "Override Sentio host").option("--api-key <key>", "Use an explicit API key instead of saved credentials").option("--token <token>", "Use an explicit bearer token instead of saved credentials");
152169
152276
  }
@@ -152207,7 +152314,8 @@ function formatOutput2(data) {
152207
152314
  lines.push(`${group.versionState} (${group.processors.length})`);
152208
152315
  for (const processor of group.processors) {
152209
152316
  const version2 = asNumber(processor.version);
152210
- const statusState = asString3(processor.processorStatus?.state) ?? "UNKNOWN";
152317
+ const processorStatus = processor.processorStatus;
152318
+ const statusState = asString3(processorStatus?.state) ?? "UNKNOWN";
152211
152319
  const uploadedAt = asString3(processor.uploadedAt);
152212
152320
  lines.push(`- v${version2 ?? "?"} status=${statusState}${uploadedAt ? ` uploaded=${uploadedAt}` : ""}`);
152213
152321
  if (asString3(processor.processorId)) {
@@ -152217,9 +152325,17 @@ function formatOutput2(data) {
152217
152325
  for (const stateEntry of states.slice(0, 5)) {
152218
152326
  const state = stateEntry;
152219
152327
  const chainId = asString3(state.chainId) ?? "?";
152220
- const chainState = asString3(state.status?.state) ?? "UNKNOWN";
152328
+ const stateStatus = state.status;
152329
+ const chainState = asString3(stateStatus?.state) ?? "UNKNOWN";
152221
152330
  const block = asString3(state.processedBlockNumber) ?? "?";
152222
152331
  lines.push(` chain ${chainId}: ${chainState} block=${block}`);
152332
+ const errorRecord = stateStatus?.errorRecord;
152333
+ const chainError = asString3(errorRecord?.message);
152334
+ if (chainError) {
152335
+ const createdAt = asString3(errorRecord?.createdAt);
152336
+ const prefix = createdAt ? `[${createdAt}] ` : "";
152337
+ lines.push(` error: ${prefix}${chainError}`);
152338
+ }
152223
152339
  }
152224
152340
  if (states.length > 5) {
152225
152341
  lines.push(` ... ${states.length - 5} more chains`);
@@ -152248,6 +152364,14 @@ function formatOutput2(data) {
152248
152364
  const objectData = data;
152249
152365
  return `Processor ${asString3(objectData.processorId)} successfully ${asString3(objectData.action)}.`;
152250
152366
  }
152367
+ if (data && typeof data === "object" && "logs" in data) {
152368
+ const logsData = data;
152369
+ const entries2 = Array.isArray(logsData.logs) ? logsData.logs : [];
152370
+ if (entries2.length === 0) {
152371
+ return "No logs found.";
152372
+ }
152373
+ return entries2.map((entry) => formatLogEntry(entry)).join("\n");
152374
+ }
152251
152375
  return JSON.stringify(data, null, 2);
152252
152376
  }
152253
152377
  function normalizeVersionSelector(value) {
@@ -154143,6 +154267,347 @@ function parseInteger6(value) {
154143
154267
  return parsedValue;
154144
154268
  }
154145
154269
 
154270
+ // src/commands/dashboard.ts
154271
+ init_cjs_shim();
154272
+ var import_api14 = __toESM(require_src5(), 1);
154273
+ var import_yaml12 = __toESM(require_dist(), 1);
154274
+ import process24 from "process";
154275
+ function createDashboardCommand() {
154276
+ const dashboardCommand = new Command("dashboard").description("Manage Sentio dashboards");
154277
+ dashboardCommand.addCommand(createDashboardListCommand());
154278
+ dashboardCommand.addCommand(createDashboardExportCommand());
154279
+ dashboardCommand.addCommand(createDashboardImportCommand());
154280
+ dashboardCommand.addCommand(createDashboardAddPanelCommand());
154281
+ return dashboardCommand;
154282
+ }
154283
+ function createDashboardListCommand() {
154284
+ return withOutputOptions8(
154285
+ withSharedProjectOptions7(withAuthOptions8(new Command("list").description("List dashboards for a project")))
154286
+ ).showHelpAfterError().action(async (options, command) => {
154287
+ try {
154288
+ await runDashboardList(options);
154289
+ } catch (error) {
154290
+ handleDashboardCommandError(error, command);
154291
+ }
154292
+ });
154293
+ }
154294
+ function createDashboardExportCommand() {
154295
+ return withOutputOptions8(
154296
+ withSharedProjectOptions7(
154297
+ withAuthOptions8(
154298
+ new Command("export").description("Export a dashboard as JSON").argument("<dashboardId>", "Dashboard ID")
154299
+ )
154300
+ )
154301
+ ).showHelpAfterError().action(async (dashboardId, options, command) => {
154302
+ try {
154303
+ await runDashboardExport(dashboardId, options);
154304
+ } catch (error) {
154305
+ handleDashboardCommandError(error, command);
154306
+ }
154307
+ });
154308
+ }
154309
+ function createDashboardImportCommand() {
154310
+ return withOutputOptions8(
154311
+ withSharedProjectOptions7(
154312
+ withAuthOptions8(
154313
+ new Command("import").description("Import dashboard data from a JSON file into an existing dashboard").argument("<dashboardId>", "Target dashboard ID to import into")
154314
+ )
154315
+ )
154316
+ ).showHelpAfterError().option("--file <path>", "Read dashboard JSON from file").option("--stdin", "Read dashboard JSON from stdin").option("--override-layouts", "Override the layout of the target dashboard").action(async (dashboardId, options, command) => {
154317
+ try {
154318
+ await runDashboardImport(dashboardId, options);
154319
+ } catch (error) {
154320
+ handleDashboardCommandError(error, command);
154321
+ }
154322
+ });
154323
+ }
154324
+ function createDashboardAddPanelCommand() {
154325
+ return withOutputOptions8(
154326
+ withSharedProjectOptions7(
154327
+ withAuthOptions8(
154328
+ new Command("add-panel").description("Add a panel to a dashboard (SQL or insights query)").argument("<dashboardId>", "Dashboard ID")
154329
+ )
154330
+ )
154331
+ ).showHelpAfterError().requiredOption("--panel-name <name>", "Panel name").requiredOption("--type <type>", "Chart type: TABLE, LINE, BAR, PIE, QUERY_VALUE, AREA, BAR_GAUGE, SCATTER").option("--sql <query>", "SQL query (plain SQL \u2014 automatically wrapped into the required format)").option("--size <count>", "SQL query result size limit (default: 100)").option("--event <name>", "Event name for an insights panel (mutually exclusive with --sql and --metric)").option("--metric <name>", "Metric name for an insights panel (mutually exclusive with --sql and --event)").option("--alias <alias>", "Alias for the insights query").option("--source-name <name>", "Source name for the insights query").option(
154332
+ "--filter <selector>",
154333
+ "Event filter or metric label selector like field:value or amount>0",
154334
+ collectOption3,
154335
+ []
154336
+ ).option("--group-by <field>", "Group by event property or metric label", collectOption3, []).option("--aggr <aggregation>", "Event: total|unique|AAU|DAU|WAU|MAU. Metric: avg|sum|min|max|count").option("--func <function>", "Function like topk(1), bottomk(1)", collectOption3, []).addHelpText(
154337
+ "after",
154338
+ `
154339
+
154340
+ Data source: use exactly one of --sql, --event, or --metric.
154341
+
154342
+ SQL panel examples:
154343
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154344
+ --panel-name "Top Holders" --type TABLE \\
154345
+ --sql "SELECT * FROM CoinBalance ORDER BY balance DESC LIMIT 50"
154346
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154347
+ --panel-name "Daily Volume" --type LINE \\
154348
+ --sql "SELECT toStartOfDay(timestamp) as date, sum(amount) as volume FROM Transfer GROUP BY date ORDER BY date"
154349
+
154350
+ Event insights panel examples:
154351
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154352
+ --panel-name "Transfer Count" --type LINE \\
154353
+ --event Transfer --aggr total
154354
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154355
+ --panel-name "Large Transfers" --type TABLE \\
154356
+ --event Transfer --filter amount>1000 --aggr total --group-by meta.address
154357
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154358
+ --panel-name "Top 5 Senders" --type BAR \\
154359
+ --event Transfer --aggr unique --group-by from --func 'topk(5)'
154360
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154361
+ --panel-name "DAU" --type LINE \\
154362
+ --event Transfer --aggr DAU
154363
+
154364
+ Metric insights panel examples:
154365
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154366
+ --panel-name "ETH Price" --type LINE \\
154367
+ --metric cbETH_price
154368
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154369
+ --panel-name "Avg Burn by Chain" --type BAR \\
154370
+ --metric burn --filter meta.chain=1 --aggr avg --group-by meta.address
154371
+ $ sentio dashboard add-panel abc123 --project owner/slug \\
154372
+ --panel-name "Burn Rate Delta" --type LINE \\
154373
+ --metric burn --aggr sum
154374
+ `
154375
+ ).action(async (dashboardId, options, command) => {
154376
+ try {
154377
+ await runDashboardAddPanel(dashboardId, options);
154378
+ } catch (error) {
154379
+ handleDashboardCommandError(error, command);
154380
+ }
154381
+ });
154382
+ }
154383
+ async function runDashboardList(options) {
154384
+ const context = createApiContext(options);
154385
+ const project = await resolveProjectRef(options, context, { ownerSlug: true });
154386
+ const response = await import_api14.WebService.listDashboards2({
154387
+ path: { owner: project.owner, slug: project.slug },
154388
+ headers: context.headers
154389
+ });
154390
+ const data = unwrapApiResult(response);
154391
+ printOutput8(options, data);
154392
+ }
154393
+ async function runDashboardExport(dashboardId, options) {
154394
+ const context = createApiContext(options);
154395
+ const response = await import_api14.WebService.exportDashboard({
154396
+ path: { dashboardId },
154397
+ headers: context.headers
154398
+ });
154399
+ const data = unwrapApiResult(response);
154400
+ console.log(JSON.stringify(data.dashboardJson ?? data, null, 2));
154401
+ }
154402
+ async function runDashboardImport(dashboardId, options) {
154403
+ const context = createApiContext(options);
154404
+ const input = loadJsonInput(options);
154405
+ if (!input) {
154406
+ throw new CliError("Provide --file or --stdin with the dashboard JSON to import.");
154407
+ }
154408
+ const dashboardJson = typeof input === "object" ? input : {};
154409
+ const response = await import_api14.WebService.importDashboard({
154410
+ body: {
154411
+ dashboardId,
154412
+ dashboardJson,
154413
+ overrideLayouts: options.overrideLayouts
154414
+ },
154415
+ headers: context.headers
154416
+ });
154417
+ const data = unwrapApiResult(response);
154418
+ printOutput8(options, { message: `Dashboard imported into ${dashboardId}`, dashboard: data.dashboard });
154419
+ }
154420
+ async function runDashboardAddPanel(dashboardId, options) {
154421
+ const context = createApiContext(options);
154422
+ const selectedSources = [Boolean(options.sql), Boolean(options.event), Boolean(options.metric)].filter(Boolean).length;
154423
+ if (selectedSources === 0) {
154424
+ throw new CliError("Provide exactly one data source: --sql, --event, or --metric.");
154425
+ }
154426
+ if (selectedSources > 1) {
154427
+ throw new CliError("Use exactly one of --sql, --event, or --metric.");
154428
+ }
154429
+ const getResponse = await import_api14.WebService.getDashboard({
154430
+ path: { dashboardId },
154431
+ headers: context.headers
154432
+ });
154433
+ const dashboardData = unwrapApiResult(getResponse);
154434
+ const dashboard = dashboardData.dashboards?.[0];
154435
+ if (!dashboard) {
154436
+ throw new CliError(`Dashboard ${dashboardId} not found.`);
154437
+ }
154438
+ const chartType = normalizeChartType(options.type);
154439
+ const panelId = generatePanelId();
154440
+ const chart = buildPanelChart(chartType, options);
154441
+ const newPanel = {
154442
+ id: panelId,
154443
+ name: options.panelName,
154444
+ dashboardId,
154445
+ chart
154446
+ };
154447
+ const existingLayouts = dashboard.layouts?.responsiveLayouts?.lg?.layouts ?? [];
154448
+ let maxBottom = 0;
154449
+ for (const layout of existingLayouts) {
154450
+ const bottom = (layout.y ?? 0) + (layout.h ?? 0);
154451
+ if (bottom > maxBottom) {
154452
+ maxBottom = bottom;
154453
+ }
154454
+ }
154455
+ const newLayout = {
154456
+ i: panelId,
154457
+ x: 0,
154458
+ y: maxBottom,
154459
+ w: 12,
154460
+ h: 6
154461
+ };
154462
+ const panels = { ...dashboard.panels ?? {} };
154463
+ panels[panelId] = newPanel;
154464
+ const updatedLayouts = [...existingLayouts, newLayout];
154465
+ const dashboardJson = {
154466
+ ...dashboard,
154467
+ panels,
154468
+ layouts: {
154469
+ responsiveLayouts: {
154470
+ ...dashboard.layouts?.responsiveLayouts ?? {},
154471
+ lg: { layouts: updatedLayouts }
154472
+ }
154473
+ }
154474
+ };
154475
+ const importResponse = await import_api14.WebService.importDashboard({
154476
+ body: {
154477
+ dashboardId,
154478
+ dashboardJson,
154479
+ overrideLayouts: true
154480
+ },
154481
+ headers: context.headers
154482
+ });
154483
+ const importData = unwrapApiResult(importResponse);
154484
+ printOutput8(options, {
154485
+ message: `Panel "${options.panelName}" added to dashboard ${dashboardId}`,
154486
+ panelId,
154487
+ dashboard: importData.dashboard
154488
+ });
154489
+ }
154490
+ function buildPanelChart(chartType, options) {
154491
+ if (options.sql) {
154492
+ const sqlSize = Number.parseInt(String(options.size ?? "100"), 10) || 100;
154493
+ return {
154494
+ type: chartType,
154495
+ datasourceType: "SQL",
154496
+ sqlQuery: JSON.stringify({ sql: options.sql, size: sqlSize })
154497
+ };
154498
+ }
154499
+ if (options.event) {
154500
+ const queryBody = buildEventsInsightQueryBody(options.event, {
154501
+ alias: options.alias,
154502
+ sourceName: options.sourceName,
154503
+ filter: options.filter,
154504
+ groupBy: options.groupBy,
154505
+ aggr: options.aggr,
154506
+ func: options.func
154507
+ });
154508
+ return {
154509
+ type: chartType,
154510
+ datasourceType: "INSIGHTS",
154511
+ insightsQueries: queryBody.queries
154512
+ };
154513
+ }
154514
+ if (options.metric) {
154515
+ const queryBody = buildMetricsInsightQueryBody(options.metric, {
154516
+ alias: options.alias,
154517
+ sourceName: options.sourceName,
154518
+ filter: options.filter,
154519
+ groupBy: options.groupBy,
154520
+ aggr: options.aggr,
154521
+ func: options.func
154522
+ });
154523
+ return {
154524
+ type: chartType,
154525
+ datasourceType: "INSIGHTS",
154526
+ insightsQueries: queryBody.queries
154527
+ };
154528
+ }
154529
+ throw new CliError("Provide exactly one data source: --sql, --event, or --metric.");
154530
+ }
154531
+ function normalizeChartType(value) {
154532
+ const normalized = value.toUpperCase();
154533
+ const valid = ["LINE", "AREA", "BAR", "BAR_GAUGE", "TABLE", "QUERY_VALUE", "PIE", "NOTE", "SCATTER"];
154534
+ if (valid.includes(normalized)) {
154535
+ return normalized;
154536
+ }
154537
+ throw new CliError(`Invalid chart type "${value}". Use one of: ${valid.join(", ")}`);
154538
+ }
154539
+ function generatePanelId() {
154540
+ return `panel_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
154541
+ }
154542
+ function collectOption3(value, previous = []) {
154543
+ previous.push(value);
154544
+ return previous;
154545
+ }
154546
+ function withAuthOptions8(command) {
154547
+ return command.option("--host <host>", "Override Sentio host").option("--api-key <key>", "Use an explicit API key instead of saved credentials").option("--token <token>", "Use an explicit bearer token instead of saved credentials");
154548
+ }
154549
+ function withSharedProjectOptions7(command) {
154550
+ return command.option("--project <project>", "Sentio project as <owner>/<slug> or <slug>").option("--owner <owner>", "Sentio project owner").option("--name <name>", "Sentio project name").option("--project-id <id>", "Sentio project id");
154551
+ }
154552
+ function withOutputOptions8(command) {
154553
+ return command.option("--json", "Print raw JSON response").option("--yaml", "Print raw YAML response");
154554
+ }
154555
+ function handleDashboardCommandError(error, command) {
154556
+ if (error instanceof CliError && (error.message.startsWith("Project is required.") || error.message.startsWith("Invalid project ") || error.message.startsWith("Dashboard ") || error.message.startsWith("Provide --file or --stdin") || error.message.startsWith("Provide exactly one data source") || error.message.startsWith("Use exactly one of --sql") || error.message.startsWith("Invalid chart type") || error.message.startsWith("Invalid aggregation") || error.message.startsWith("Invalid metric aggregation") || error.message.startsWith("Invalid filter") || error.message.startsWith("Invalid metric selector"))) {
154557
+ console.error(error.message);
154558
+ if (command) {
154559
+ console.error();
154560
+ command.outputHelp();
154561
+ }
154562
+ process24.exit(1);
154563
+ }
154564
+ handleCommandError(error);
154565
+ }
154566
+ function printOutput8(options, data) {
154567
+ if (options.json && options.yaml) {
154568
+ throw new CliError("Choose only one structured output format: --json or --yaml.");
154569
+ }
154570
+ if (options.json) {
154571
+ console.log(JSON.stringify(data, null, 2));
154572
+ return;
154573
+ }
154574
+ if (options.yaml) {
154575
+ console.log(import_yaml12.default.stringify(data).trimEnd());
154576
+ return;
154577
+ }
154578
+ console.log(formatOutput7(data));
154579
+ }
154580
+ function formatOutput7(data) {
154581
+ if (data && typeof data === "object" && "message" in data) {
154582
+ return String(data.message ?? "");
154583
+ }
154584
+ if (data && typeof data === "object" && "dashboards" in data) {
154585
+ const dashboards = data.dashboards ?? [];
154586
+ const lines = [`Dashboards (${dashboards.length})`];
154587
+ for (const db of dashboards) {
154588
+ const id = db.id ?? "<id>";
154589
+ const name = db.name ?? "<unnamed>";
154590
+ const panelCount = db.panels ? Object.keys(db.panels).length : 0;
154591
+ const visibility = db.visibility ?? "";
154592
+ const updated = formatTimestamp3(db.updatedAt);
154593
+ lines.push(
154594
+ `- ${id} "${name}" [${panelCount} panels]${visibility ? ` ${visibility}` : ""}${updated ? ` updated ${updated}` : ""}`
154595
+ );
154596
+ }
154597
+ return lines.join("\n");
154598
+ }
154599
+ return JSON.stringify(data, null, 2);
154600
+ }
154601
+ function formatTimestamp3(value) {
154602
+ if (!value) {
154603
+ return "";
154604
+ }
154605
+ if (/^\d{13}$/.test(value)) {
154606
+ return new Date(Number.parseInt(value, 10)).toISOString();
154607
+ }
154608
+ return value;
154609
+ }
154610
+
154146
154611
  // src/index.ts
154147
154612
  var program2 = new Command();
154148
154613
  program2.name("sentio").description("Login & Manage your project files to Sentio.");
@@ -154169,6 +154634,7 @@ program2.addCommand(createAlertCommand());
154169
154634
  program2.addCommand(createPriceCommand());
154170
154635
  program2.addCommand(createSimulationCommand());
154171
154636
  program2.addCommand(createEndpointCommand());
154637
+ program2.addCommand(createDashboardCommand());
154172
154638
  program2.parse();
154173
154639
  /*! Bundled license information:
154174
154640