@wervt/cli 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +87 -3
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
3
3
  import { dirname, join, relative, resolve } from "node:path";
4
+ import { styleText } from "node:util";
4
5
  import * as p from "@clack/prompts";
5
6
  import { defineCommand, runMain } from "citty";
6
7
  import { detectPackageManager } from "nypm";
@@ -78,7 +79,7 @@ const connection = {
78
79
  },
79
80
  token: {
80
81
  type: "string",
81
- description: "Deploy token (or WERVT_TOKEN)"
82
+ description: "Deploy or read token (or WERVT_TOKEN)"
82
83
  }
83
84
  };
84
85
  async function api(path, flags, init = {}) {
@@ -91,7 +92,12 @@ async function api(path, flags, init = {}) {
91
92
  });
92
93
  if (!res.ok) {
93
94
  const body = await res.text();
94
- throw new Error(`${res.status} ${res.statusText}: ${body}`);
95
+ let message = body;
96
+ try {
97
+ message = JSON.parse(body).error ?? body;
98
+ } catch {}
99
+ console.error(styleText("red", `Error (${res.status}): ${message}`));
100
+ process.exit(1);
95
101
  }
96
102
  return res;
97
103
  }
@@ -409,6 +415,83 @@ const remove = defineCommand({
409
415
  console.log(`Deleted ${args.app}${dropDb ? " and its database" : ""}`);
410
416
  }
411
417
  });
418
+ const LEVEL_COLORS = {
419
+ error: "red",
420
+ warn: "yellow",
421
+ info: "cyan",
422
+ debug: "gray"
423
+ };
424
+ /** `09:07:52.060 error <message>`, or the entry as one JSON line. */
425
+ function printLog(entry, asJson) {
426
+ if (asJson) return console.log(JSON.stringify(entry));
427
+ const time = new Date(entry._time).toISOString().slice(11, 23);
428
+ const level = String(entry.level ?? "info");
429
+ const color = LEVEL_COLORS[level] ?? "white";
430
+ console.log(`${styleText("dim", time)} ${styleText(color, level.padEnd(5))} ${entry._msg ?? ""}`);
431
+ }
432
+ const logs = defineCommand({
433
+ meta: {
434
+ name: "logs",
435
+ description: "Show an app's logs: console output, request events and isolate events"
436
+ },
437
+ args: {
438
+ app: {
439
+ type: "positional",
440
+ required: true,
441
+ description: "App name"
442
+ },
443
+ query: {
444
+ type: "positional",
445
+ required: false,
446
+ description: "LogsQL filter, e.g. 'level:error' or 'status:>=500' (default: all)"
447
+ },
448
+ since: {
449
+ type: "string",
450
+ default: "1h",
451
+ description: "How far back, e.g. 15m, 6h, 2d"
452
+ },
453
+ until: {
454
+ type: "string",
455
+ description: "End of the range (default: now)"
456
+ },
457
+ limit: {
458
+ type: "string",
459
+ default: "100",
460
+ description: "Newest entries to show (max 1000)"
461
+ },
462
+ follow: {
463
+ type: "boolean",
464
+ alias: "f",
465
+ description: "Keep printing new entries"
466
+ },
467
+ json: {
468
+ type: "boolean",
469
+ description: "One JSON object per line, with every field"
470
+ },
471
+ ...connection
472
+ },
473
+ async run({ args }) {
474
+ const params = new URLSearchParams();
475
+ if (args.query) params.set("query", args.query);
476
+ if (args.follow) {
477
+ params.set("since", args.since);
478
+ const res = await api(`/v1/apps/${args.app}/logs/tail?${params.toString()}`, args);
479
+ let rest = "";
480
+ for await (const chunk of res.body.pipeThrough(new TextDecoderStream())) {
481
+ const lines = (rest + chunk).split("\n");
482
+ rest = lines.pop() ?? "";
483
+ for (const line of lines) if (line) printLog(JSON.parse(line), Boolean(args.json));
484
+ }
485
+ return;
486
+ }
487
+ params.set("start", args.since);
488
+ if (args.until) params.set("end", args.until);
489
+ params.set("limit", args.limit);
490
+ const entries = await (await api(`/v1/apps/${args.app}/logs?${params.toString()}`, args)).json();
491
+ if (!entries.length && !args.json) return console.error(`No logs in the last ${args.since}.`);
492
+ for (const entry of entries.reverse()) printLog(entry, Boolean(args.json));
493
+ }
494
+ });
412
495
  const login = defineCommand({
413
496
  meta: {
414
497
  name: "login",
@@ -423,7 +506,7 @@ const login = defineCommand({
423
506
  token: {
424
507
  type: "string",
425
508
  required: true,
426
- description: "Deploy token"
509
+ description: "Deploy token, or the read token"
427
510
  }
428
511
  },
429
512
  async run({ args }) {
@@ -445,6 +528,7 @@ runMain(defineCommand({
445
528
  deploy,
446
529
  apps,
447
530
  releases,
531
+ logs,
448
532
  activate,
449
533
  rollback,
450
534
  reprovision,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wervt/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Deploy and manage apps on wervt.",
5
5
  "keywords": [
6
6
  "agents",