@thingd/cli 0.58.1 → 0.59.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/interactive.d.ts.map +1 -1
- package/dist/interactive.js +74 -13
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AAoxGA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA0FvD"}
|
package/dist/interactive.js
CHANGED
|
@@ -69,6 +69,7 @@ let collections = [];
|
|
|
69
69
|
let streams = [];
|
|
70
70
|
let queues = [];
|
|
71
71
|
let objectsByCollection = new Map();
|
|
72
|
+
const collectionCounts = new Map();
|
|
72
73
|
const collectionOptions = new Map();
|
|
73
74
|
const expandedSet = new Set(["cat:collections", "cat:streams", "cat:queues"]);
|
|
74
75
|
let cursorIndex = 0;
|
|
@@ -217,6 +218,35 @@ function formatUptime(ms) {
|
|
|
217
218
|
const h = Math.floor(m / 60);
|
|
218
219
|
return `${h}h ${m % 60}m`;
|
|
219
220
|
}
|
|
221
|
+
function formatRelativeTime(iso) {
|
|
222
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
223
|
+
const s = Math.floor(ms / 1000);
|
|
224
|
+
if (s < 0) {
|
|
225
|
+
return "now";
|
|
226
|
+
}
|
|
227
|
+
if (s < 5) {
|
|
228
|
+
return "now";
|
|
229
|
+
}
|
|
230
|
+
if (s < 60) {
|
|
231
|
+
return `${s}s ago`;
|
|
232
|
+
}
|
|
233
|
+
const m = Math.floor(s / 60);
|
|
234
|
+
if (m < 60) {
|
|
235
|
+
return `${m}m ago`;
|
|
236
|
+
}
|
|
237
|
+
const h = Math.floor(m / 60);
|
|
238
|
+
if (h < 24) {
|
|
239
|
+
return `${h}h ago`;
|
|
240
|
+
}
|
|
241
|
+
const d = Math.floor(h / 24);
|
|
242
|
+
return `${d}d ago`;
|
|
243
|
+
}
|
|
244
|
+
function formatCount(n) {
|
|
245
|
+
if (n >= 1000) {
|
|
246
|
+
return `${(n / 1000).toFixed(1).replace(/\.0$/, "")}k`;
|
|
247
|
+
}
|
|
248
|
+
return String(n);
|
|
249
|
+
}
|
|
220
250
|
async function fetchResourcesFallback() {
|
|
221
251
|
cloudError = null;
|
|
222
252
|
// Collections and streams — parallel fetch
|
|
@@ -276,7 +306,7 @@ async function fetchResourcesFallback() {
|
|
|
276
306
|
listOpts.filter = opts.filter;
|
|
277
307
|
}
|
|
278
308
|
const list = await db.listObjects(col, Object.keys(listOpts).length > 0 ? listOpts : undefined);
|
|
279
|
-
objectsByCollection.set(col, list.map((o) => o.id));
|
|
309
|
+
objectsByCollection.set(col, list.map((o) => ({ id: o.id, createdAt: o.createdAt })));
|
|
280
310
|
}
|
|
281
311
|
catch {
|
|
282
312
|
objectsByCollection.set(col, []);
|
|
@@ -335,7 +365,7 @@ async function fetchResources() {
|
|
|
335
365
|
listOpts.filter = opts.filter;
|
|
336
366
|
}
|
|
337
367
|
const list = await db.listObjects(col, Object.keys(listOpts).length > 0 ? listOpts : undefined);
|
|
338
|
-
objectsByCollection.set(col, list.map((o) => o.id));
|
|
368
|
+
objectsByCollection.set(col, list.map((o) => ({ id: o.id, createdAt: o.createdAt })));
|
|
339
369
|
}
|
|
340
370
|
catch {
|
|
341
371
|
objectsByCollection.set(col, []);
|
|
@@ -364,6 +394,20 @@ async function fetchResources() {
|
|
|
364
394
|
jobsByQueue.set(q, { active: [], dead: [] });
|
|
365
395
|
}
|
|
366
396
|
}));
|
|
397
|
+
// Fetch per-collection counts from schema
|
|
398
|
+
collectionCounts.clear();
|
|
399
|
+
try {
|
|
400
|
+
const schemas = await db.schema();
|
|
401
|
+
for (const s of schemas) {
|
|
402
|
+
collectionCounts.set(s.name, s.objectCount);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
// Fallback — count from objectsByCollection
|
|
407
|
+
for (const col of collections) {
|
|
408
|
+
collectionCounts.set(col, objectsByCollection.get(col)?.length ?? 0);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
367
411
|
// Calculate Deltas for Operations Throughput Rates
|
|
368
412
|
const prevObjects = objectsHistory.length > 0
|
|
369
413
|
? (objectsHistory[objectsHistory.length - 1] ?? totalObjects)
|
|
@@ -525,11 +569,13 @@ function buildTree() {
|
|
|
525
569
|
for (const col of collections) {
|
|
526
570
|
const colId = `col:${col}`;
|
|
527
571
|
const colOpen = expandedSet.has(colId);
|
|
572
|
+
const colCount = collectionCounts.get(col);
|
|
573
|
+
const colSuffix = colCount !== undefined ? pc.dim(` ${formatCount(colCount)}`) : "";
|
|
528
574
|
nodes.push({
|
|
529
575
|
id: colId,
|
|
530
576
|
parentId: "cat:collections",
|
|
531
577
|
type: "collection",
|
|
532
|
-
label: `${colOpen ? pc.cyan("▾") : pc.dim("▸")} ${pc.cyan(col)}`,
|
|
578
|
+
label: `${colOpen ? pc.cyan("▾") : pc.dim("▸")} ${pc.cyan(col)}${colSuffix}`,
|
|
533
579
|
depth: 1,
|
|
534
580
|
expandable: true,
|
|
535
581
|
ref: { name: col },
|
|
@@ -546,15 +592,16 @@ function buildTree() {
|
|
|
546
592
|
expandable: false,
|
|
547
593
|
});
|
|
548
594
|
}
|
|
549
|
-
for (const
|
|
595
|
+
for (const objData of objs) {
|
|
596
|
+
const objAge = objData.createdAt ? pc.dim(formatRelativeTime(objData.createdAt)) : "";
|
|
550
597
|
nodes.push({
|
|
551
|
-
id: `obj:${col}:${
|
|
598
|
+
id: `obj:${col}:${objData.id}`,
|
|
552
599
|
parentId: colId,
|
|
553
600
|
type: "object",
|
|
554
|
-
label: `${pc.cyan("○")} ${
|
|
601
|
+
label: `${pc.cyan("○")} ${objData.id} ${objAge}`,
|
|
555
602
|
depth: 2,
|
|
556
603
|
expandable: false,
|
|
557
|
-
ref: { collection: col, id:
|
|
604
|
+
ref: { collection: col, id: objData.id },
|
|
558
605
|
});
|
|
559
606
|
}
|
|
560
607
|
}
|
|
@@ -581,11 +628,13 @@ function buildTree() {
|
|
|
581
628
|
}
|
|
582
629
|
for (const stream of streams) {
|
|
583
630
|
const sOpen = expandedSet.has(`stream:${stream}`);
|
|
631
|
+
const evtCount = eventsByStream.get(stream)?.length ?? 0;
|
|
632
|
+
const evtSuffix = evtCount > 0 ? pc.dim(` ${formatCount(evtCount)}`) : "";
|
|
584
633
|
nodes.push({
|
|
585
634
|
id: `stream:${stream}`,
|
|
586
635
|
parentId: "cat:streams",
|
|
587
636
|
type: "stream",
|
|
588
|
-
label: `${sOpen ? pc.cyan("▾") : pc.dim("▸")} ${pc.green(stream)}`,
|
|
637
|
+
label: `${sOpen ? pc.cyan("▾") : pc.dim("▸")} ${pc.green(stream)}${evtSuffix}`,
|
|
589
638
|
depth: 1,
|
|
590
639
|
expandable: true,
|
|
591
640
|
ref: { name: stream },
|
|
@@ -607,7 +656,7 @@ function buildTree() {
|
|
|
607
656
|
id: `evt:${stream}:${evt.id}`,
|
|
608
657
|
parentId: `stream:${stream}`,
|
|
609
658
|
type: "event",
|
|
610
|
-
label: `${pc.dim("·")} ${pc.dim(evt.type || "unknown")}`,
|
|
659
|
+
label: `${pc.dim("·")} ${pc.dim(evt.type || "unknown")} ${pc.dim(formatRelativeTime(evt.createdAt))}`,
|
|
611
660
|
depth: 2,
|
|
612
661
|
expandable: false,
|
|
613
662
|
ref: { stream: stream, eventId: evt.id, eventData: evt },
|
|
@@ -637,11 +686,17 @@ function buildTree() {
|
|
|
637
686
|
}
|
|
638
687
|
for (const q of queues) {
|
|
639
688
|
const qOpen = expandedSet.has(`queue:${q}`);
|
|
689
|
+
const qJobData = jobsByQueue.get(q);
|
|
690
|
+
const qActive = qJobData?.active.length ?? 0;
|
|
691
|
+
const qDead = qJobData?.dead.length ?? 0;
|
|
692
|
+
const qSuffix = qActive > 0 || qDead > 0
|
|
693
|
+
? ` ${qActive > 0 ? pc.cyan(String(qActive)) : pc.dim("0")}${pc.cyan(" ●")} ${qDead > 0 ? pc.red(String(qDead)) : pc.dim("0")}${pc.red(" ○")}`
|
|
694
|
+
: "";
|
|
640
695
|
nodes.push({
|
|
641
696
|
id: `queue:${q}`,
|
|
642
697
|
parentId: "cat:queues",
|
|
643
698
|
type: "queue",
|
|
644
|
-
label: `${qOpen ? pc.cyan("▾") : pc.dim("▸")} ${pc.magenta(q)}`,
|
|
699
|
+
label: `${qOpen ? pc.cyan("▾") : pc.dim("▸")} ${pc.magenta(q)}${qSuffix}`,
|
|
645
700
|
depth: 1,
|
|
646
701
|
expandable: true,
|
|
647
702
|
ref: { name: q },
|
|
@@ -672,11 +727,13 @@ function buildTree() {
|
|
|
672
727
|
});
|
|
673
728
|
}
|
|
674
729
|
for (const job of activeJobs) {
|
|
730
|
+
const jobStatus = pc.cyan(job.status ?? "ready");
|
|
731
|
+
const jobAttempts = pc.dim(`${job.attempts}/${job.maxAttempts}`);
|
|
675
732
|
nodes.push({
|
|
676
733
|
id: `job:${q}:active:${job.id}`,
|
|
677
734
|
parentId: `queue:${q}:active`,
|
|
678
735
|
type: "job",
|
|
679
|
-
label: `${pc.cyan("●")} ${pc.dim(job.id.slice(0, 12))}`,
|
|
736
|
+
label: `${pc.cyan("●")} ${pc.dim(job.id.slice(0, 12))} ${jobAttempts} ${jobStatus}`,
|
|
680
737
|
depth: 3,
|
|
681
738
|
expandable: false,
|
|
682
739
|
ref: { queue: q, jobId: job.id, status: "active", jobData: job },
|
|
@@ -705,11 +762,13 @@ function buildTree() {
|
|
|
705
762
|
});
|
|
706
763
|
}
|
|
707
764
|
for (const job of deadJobs) {
|
|
765
|
+
const jobAttempts = pc.dim(`${job.attempts}/${job.maxAttempts}`);
|
|
766
|
+
const lastErr = job.lastError ? pc.dim(job.lastError.slice(0, 20)) : "";
|
|
708
767
|
nodes.push({
|
|
709
768
|
id: `job:${q}:dead:${job.id}`,
|
|
710
769
|
parentId: `queue:${q}:dead`,
|
|
711
770
|
type: "job",
|
|
712
|
-
label: `${pc.red("○")} ${pc.dim(job.id.slice(0, 12))}`,
|
|
771
|
+
label: `${pc.red("○")} ${pc.dim(job.id.slice(0, 12))} ${jobAttempts}${lastErr ? ` ${pc.red("⚠")} ${lastErr}` : ""}`,
|
|
713
772
|
depth: 3,
|
|
714
773
|
expandable: false,
|
|
715
774
|
ref: { queue: q, jobId: job.id, status: "dead", jobData: job },
|
|
@@ -828,7 +887,7 @@ async function loadContent(node) {
|
|
|
828
887
|
res += pc.dim("No objects in this collection.");
|
|
829
888
|
}
|
|
830
889
|
else {
|
|
831
|
-
const lines = objs.map((
|
|
890
|
+
const lines = objs.map((o) => ` ${pc.cyan("○")} ${o.id}${o.createdAt ? ` ${pc.dim(formatRelativeTime(o.createdAt))}` : ""}`);
|
|
832
891
|
res += lines.join("\n");
|
|
833
892
|
}
|
|
834
893
|
content = res;
|
|
@@ -2843,6 +2902,7 @@ async function handleSwitch() {
|
|
|
2843
2902
|
streams = [];
|
|
2844
2903
|
queues = [];
|
|
2845
2904
|
objectsByCollection = new Map();
|
|
2905
|
+
collectionCounts.clear();
|
|
2846
2906
|
cursorIndex = 0;
|
|
2847
2907
|
scrollOffset = 0;
|
|
2848
2908
|
loadedItemId = "";
|
|
@@ -2876,6 +2936,7 @@ async function handleLogout() {
|
|
|
2876
2936
|
streams = [];
|
|
2877
2937
|
queues = [];
|
|
2878
2938
|
objectsByCollection = new Map();
|
|
2939
|
+
collectionCounts.clear();
|
|
2879
2940
|
cursorIndex = 0;
|
|
2880
2941
|
scrollOffset = 0;
|
|
2881
2942
|
loadedItemId = "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thingd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"description": "CLI, Interactive TUI Dashboard, and MCP server for thingd — a fast object-first data engine for applications and AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://engine.thingd.cloud",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"cli-table3": "^0.6.5",
|
|
46
46
|
"picocolors": "^1.1.1",
|
|
47
47
|
"zod": "^4.4.3",
|
|
48
|
-
"@thingd/sdk": "0.
|
|
48
|
+
"@thingd/sdk": "0.59.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=24.0.0"
|