@xplane/utils 1.4.0 → 1.5.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.mjs +34 -98
- package/dist/cli.mjs.map +1 -1
- package/dist/{xr-watcher-EiWHVp3o.d.mts → index-Dp92t3xP.d.mts} +94 -2
- package/dist/index-Dp92t3xP.d.mts.map +1 -0
- package/dist/index.d.mts +64 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +80 -3
- package/dist/index.mjs.map +1 -0
- package/dist/{xr-watcher-1etyvp-6.mjs → kubeconfig-BO2X-qXU.mjs} +234 -147
- package/dist/kubeconfig-BO2X-qXU.mjs.map +1 -0
- package/dist/render/index.d.mts +2 -85
- package/dist/render/index.mjs +1 -1
- package/dist/{render-Cnhpyf1X.mjs → render-BMhfzOc2.mjs} +105 -4
- package/dist/render-BMhfzOc2.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/render/index.d.mts.map +0 -1
- package/dist/render-Cnhpyf1X.mjs.map +0 -1
- package/dist/tree-DaHkojq8.mjs +0 -96
- package/dist/tree-DaHkojq8.mjs.map +0 -1
- package/dist/xr-watcher-1etyvp-6.mjs.map +0 -1
- package/dist/xr-watcher-EiWHVp3o.d.mts.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { t as buildTree } from "./tree-DaHkojq8.mjs";
|
|
2
1
|
import chalk from "chalk";
|
|
3
2
|
import { createLogUpdate } from "log-update";
|
|
4
3
|
//#region src/render/format.ts
|
|
@@ -41,6 +40,13 @@ function formatAge(from) {
|
|
|
41
40
|
}
|
|
42
41
|
//#endregion
|
|
43
42
|
//#region src/render/ci.ts
|
|
43
|
+
const ANSI_RE$1 = /\x1B\[[0-9;]*[A-Za-z]/g;
|
|
44
|
+
function wrapStripAnsi(target) {
|
|
45
|
+
return { write(chunk, ...rest) {
|
|
46
|
+
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
47
|
+
return target.write(text.replace(ANSI_RE$1, ""), ...rest);
|
|
48
|
+
} };
|
|
49
|
+
}
|
|
44
50
|
/**
|
|
45
51
|
* Append-only CI renderer.
|
|
46
52
|
*
|
|
@@ -50,7 +56,8 @@ function formatAge(from) {
|
|
|
50
56
|
* 4. If nothing is printed within `heartbeatMs`, emit a single liveness line.
|
|
51
57
|
*/
|
|
52
58
|
async function renderCI(watcher, opts) {
|
|
53
|
-
const
|
|
59
|
+
const base = opts.out ?? process.stdout;
|
|
60
|
+
const out = opts.noColor ? wrapStripAnsi(base) : base;
|
|
54
61
|
const heartbeatMs = opts.heartbeatMs ?? 3e4;
|
|
55
62
|
const showEvents = opts.showEvents ?? false;
|
|
56
63
|
const snapshotEvery = opts.snapshotEveryHeartbeats ?? 10;
|
|
@@ -207,6 +214,99 @@ function formatWaiting(waiting) {
|
|
|
207
214
|
return chalk.dim(` waiting ${waiting.join(", ")}`);
|
|
208
215
|
}
|
|
209
216
|
//#endregion
|
|
217
|
+
//#region src/watcher/tree.ts
|
|
218
|
+
/** Build a `ResourceTree` from a snapshot, preferring `status.xplane` when present. */
|
|
219
|
+
function buildTree(snapshot) {
|
|
220
|
+
if (snapshot.xplane) return fromXplane(snapshot.xplane.emittedResources, snapshot.xplane.blockedResources);
|
|
221
|
+
if (snapshot.resourceRefs.length > 0) return fromResourceRefs(snapshot.resourceRefs);
|
|
222
|
+
return {
|
|
223
|
+
roots: [],
|
|
224
|
+
stats: {
|
|
225
|
+
total: 0,
|
|
226
|
+
ready: 0,
|
|
227
|
+
blocked: 0
|
|
228
|
+
},
|
|
229
|
+
source: "empty"
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function fromXplane(emitted, blocked) {
|
|
233
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
234
|
+
const ownEntry = /* @__PURE__ */ new Set();
|
|
235
|
+
const roots = [];
|
|
236
|
+
const ensureNode = (path) => {
|
|
237
|
+
const existing = byPath.get(path);
|
|
238
|
+
if (existing) return existing;
|
|
239
|
+
const segments = path.split("/");
|
|
240
|
+
const node = {
|
|
241
|
+
label: segments[segments.length - 1] ?? path,
|
|
242
|
+
path,
|
|
243
|
+
ready: false,
|
|
244
|
+
blocked: false,
|
|
245
|
+
children: []
|
|
246
|
+
};
|
|
247
|
+
byPath.set(path, node);
|
|
248
|
+
if (segments.length === 1) roots.push(node);
|
|
249
|
+
else ensureNode(segments.slice(0, -1).join("/")).children.push(node);
|
|
250
|
+
return node;
|
|
251
|
+
};
|
|
252
|
+
for (const r of emitted) {
|
|
253
|
+
const node = ensureNode(r.nodePath);
|
|
254
|
+
node.ready = r.ready;
|
|
255
|
+
node.apiVersion = r.apiVersion;
|
|
256
|
+
node.kind = r.kind;
|
|
257
|
+
if (r.name) node.name = r.name;
|
|
258
|
+
if (r.namespace) node.namespace = r.namespace;
|
|
259
|
+
ownEntry.add(r.nodePath);
|
|
260
|
+
}
|
|
261
|
+
for (const b of blocked) {
|
|
262
|
+
const node = ensureNode(b.nodePath);
|
|
263
|
+
node.blocked = true;
|
|
264
|
+
if (b.waitingFor) node.waitingFor = b.waitingFor;
|
|
265
|
+
if (!node.apiVersion) node.apiVersion = b.apiVersion;
|
|
266
|
+
if (!node.kind) node.kind = b.kind;
|
|
267
|
+
if (!node.name && b.name) node.name = b.name;
|
|
268
|
+
if (!node.namespace && b.namespace) node.namespace = b.namespace;
|
|
269
|
+
ownEntry.add(b.nodePath);
|
|
270
|
+
}
|
|
271
|
+
const aggregate = (node) => {
|
|
272
|
+
for (const child of node.children) aggregate(child);
|
|
273
|
+
if (!ownEntry.has(node.path) && node.children.length > 0) {
|
|
274
|
+
node.ready = node.children.every((c) => c.ready);
|
|
275
|
+
node.blocked = node.children.some((c) => c.blocked);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
for (const root of roots) aggregate(root);
|
|
279
|
+
const readyCount = emitted.reduce((n, r) => n + (r.ready ? 1 : 0), 0);
|
|
280
|
+
return {
|
|
281
|
+
roots,
|
|
282
|
+
stats: {
|
|
283
|
+
total: emitted.length,
|
|
284
|
+
ready: readyCount,
|
|
285
|
+
blocked: blocked.length
|
|
286
|
+
},
|
|
287
|
+
source: "xplane"
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function fromResourceRefs(refs) {
|
|
291
|
+
return {
|
|
292
|
+
roots: refs.map((r) => ({
|
|
293
|
+
label: r.name,
|
|
294
|
+
path: r.name,
|
|
295
|
+
ready: false,
|
|
296
|
+
blocked: false,
|
|
297
|
+
apiVersion: r.apiVersion,
|
|
298
|
+
kind: r.kind,
|
|
299
|
+
children: []
|
|
300
|
+
})),
|
|
301
|
+
stats: {
|
|
302
|
+
total: refs.length,
|
|
303
|
+
ready: 0,
|
|
304
|
+
blocked: 0
|
|
305
|
+
},
|
|
306
|
+
source: "resourceRefs"
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
210
310
|
//#region src/render/tty.ts
|
|
211
311
|
/**
|
|
212
312
|
* Live full-screen renderer using `log-update` to repaint a single frame.
|
|
@@ -356,9 +456,10 @@ async function runRenderer(watcher, opts) {
|
|
|
356
456
|
if (opts.heartbeatMs !== void 0) ciOpts.heartbeatMs = opts.heartbeatMs;
|
|
357
457
|
if (opts.showEvents !== void 0) ciOpts.showEvents = opts.showEvents;
|
|
358
458
|
if (opts.snapshotEveryHeartbeats !== void 0) ciOpts.snapshotEveryHeartbeats = opts.snapshotEveryHeartbeats;
|
|
459
|
+
if (opts.noColor !== void 0) ciOpts.noColor = opts.noColor;
|
|
359
460
|
return renderCI(watcher, ciOpts);
|
|
360
461
|
}
|
|
361
462
|
//#endregion
|
|
362
|
-
export {
|
|
463
|
+
export { renderCI as a, formatProgress as c, buildTree as i, statusGlyph as l, selectRenderer as n, formatEvent as o, renderTTY as r, formatHeader as s, runRenderer as t };
|
|
363
464
|
|
|
364
|
-
//# sourceMappingURL=render-
|
|
465
|
+
//# sourceMappingURL=render-BMhfzOc2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-BMhfzOc2.mjs","names":["ANSI_RE","tty"],"sources":["../src/render/format.ts","../src/render/ci.ts","../src/watcher/tree.ts","../src/render/tty.ts","../src/render/index.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { KubernetesEvent, XrSnapshot } from '../watcher/types.js';\n\n/** Single-character glyph for the status of a tree node. */\nexport function statusGlyph(state: 'ready' | 'pending' | 'blocked'): string {\n switch (state) {\n case 'ready':\n return chalk.green('✔');\n case 'blocked':\n return chalk.red('✖');\n case 'pending':\n return chalk.yellow('⏳');\n }\n}\n\n/** Compact header line summarising the XR. */\nexport function formatHeader(\n snapshot: XrSnapshot,\n ref: { kind: string; name: string; namespace?: string },\n): string {\n const obj = snapshot.object;\n const fqdn = ref.namespace\n ? `${ref.kind}/${ref.name} (${ref.namespace})`\n : `${ref.kind}/${ref.name}`;\n const readyState = snapshot.ready\n ? chalk.green('Ready')\n : chalk.yellow(snapshot.readyReason ?? 'NotReady');\n const ts = obj.metadata?.creationTimestamp as unknown as string | Date | undefined;\n const age = ts ? formatAge(new Date(ts)) : '?';\n const throttled = snapshot.updatesThrottled ? ` ${chalk.yellow('⚠ Updates Throttled')}` : '';\n return `${chalk.bold(fqdn)} age=${age} ${readyState}${throttled}`;\n}\n\n/** Inline progress representation, e.g. `5/12 ready · 3 blocked`. */\nexport function formatProgress(ready: number, total: number, blocked: number): string {\n const parts: string[] = [`${ready}/${total} ready`];\n if (blocked > 0) parts.push(chalk.red(`${blocked} blocked`));\n return parts.join(chalk.dim(' · '));\n}\n\n/** Format a Kubernetes Event as a single line. */\nexport function formatEvent(ev: KubernetesEvent): string {\n const color = ev.type === 'Warning' ? chalk.yellow : chalk.dim;\n const target = ev.involvedKind && ev.involvedName ? `${ev.involvedKind}/${ev.involvedName} ` : '';\n return color(`${ev.lastTimestamp ?? ''} ${target}${ev.reason}: ${ev.message}`.trim());\n}\n\nfunction formatAge(from: Date): string {\n const ms = Date.now() - from.getTime();\n if (ms < 60_000) return `${Math.floor(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m`;\n if (ms < 86_400_000) return `${Math.floor(ms / 3_600_000)}h`;\n return `${Math.floor(ms / 86_400_000)}d`;\n}\n","import chalk from 'chalk';\nimport type {\n KubernetesEvent,\n XplaneStatus,\n XrEvent,\n XrRef,\n XrSnapshot,\n} from '../watcher/types.js';\nimport type { XrWatcher } from '../watcher/xr-watcher.js';\nimport { formatEvent } from './format.js';\n\nexport interface CiRendererOptions {\n ref: XrRef;\n /** Destination stream. Defaults to `process.stdout`. */\n out?: NodeJS.WritableStream;\n /** Heartbeat interval (ms). When no changes are observed within this window, emit a \"no change\" line so CI can see the job is alive. Defaults to 30000. Set to 0 to disable. */\n heartbeatMs?: number;\n /** When true, K8s Events are echoed inline. Defaults to false in CI (too noisy). */\n showEvents?: boolean;\n /** Every N consecutive idle heartbeats, expand the heartbeat line into a snapshot of unready + blocked resources. Defaults to 10. Set to 0 to disable. */\n snapshotEveryHeartbeats?: number;\n /**\n * Strip ANSI colour escapes from the rendered output. Useful when piping\n * into log collectors that don't understand colour codes. Defaults to false.\n */\n noColor?: boolean;\n}\n\n// biome-ignore lint/suspicious/noControlCharactersInRegex: CSI sequence stripping requires ESC.\nconst ANSI_RE = /\\x1B\\[[0-9;]*[A-Za-z]/g;\n\nfunction wrapStripAnsi(target: NodeJS.WritableStream): NodeJS.WritableStream {\n return {\n write(chunk: string | Uint8Array, ...rest: unknown[]): boolean {\n const text = typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8');\n // biome-ignore lint/suspicious/noExplicitAny: forwarding variadic write overloads.\n return (target.write as any)(text.replace(ANSI_RE, ''), ...rest);\n },\n } as NodeJS.WritableStream;\n}\n\n/**\n * Append-only CI renderer.\n *\n * 1. Print a one-line \"watching …\" header on startup.\n * 2. On the first snapshot, print a full snapshot block.\n * 3. On every subsequent snapshot, print only the delta.\n * 4. If nothing is printed within `heartbeatMs`, emit a single liveness line.\n */\nexport async function renderCI(watcher: XrWatcher, opts: CiRendererOptions): Promise<void> {\n const base = opts.out ?? process.stdout;\n const out = opts.noColor ? wrapStripAnsi(base) : base;\n const heartbeatMs = opts.heartbeatMs ?? 30_000;\n const showEvents = opts.showEvents ?? false;\n const snapshotEvery = opts.snapshotEveryHeartbeats ?? 10;\n const write = (line: string) => out.write(`${line}\\n`);\n const stamp = () => new Date().toISOString().slice(11, 19);\n let lastWriteAt = Date.now();\n /** Warning (and worse) K8s events buffered since the last flush — always surfaced even when `showEvents` is off. */\n const pendingWarnings: KubernetesEvent[] = [];\n const flushPendingWarnings = () => {\n if (pendingWarnings.length === 0) return;\n for (const e of pendingWarnings) write(formatEvent(e));\n pendingWarnings.length = 0;\n lastWriteAt = Date.now();\n };\n const emit = (line: string) => {\n flushPendingWarnings();\n write(line);\n lastWriteAt = Date.now();\n };\n\n let prev: SnapshotSummary | undefined;\n let idleHeartbeats = 0;\n let heartbeat: NodeJS.Timeout | undefined;\n if (heartbeatMs > 0) {\n heartbeat = setInterval(() => {\n // Surface any buffered warnings first, even if the snapshot itself hasn't changed.\n const hadWarnings = pendingWarnings.length > 0;\n flushPendingWarnings();\n if (!prev) return;\n if (!hadWarnings && Date.now() - lastWriteAt < heartbeatMs) return;\n idleHeartbeats += 1;\n const expand = snapshotEvery > 0 && idleHeartbeats % snapshotEvery === 0;\n const ts = stamp();\n const counts = formatCounts(prev.readyCount, prev.total, prev.blockedCount);\n const headline = `${chalk.dim(ts)} ${chalk.dim('→')} ${counts} ${chalk.dim('(no change)')}`;\n if (!expand) {\n emit(headline);\n return;\n }\n emit([headline, ...renderPendingBlock(prev)].join('\\n'));\n }, heartbeatMs);\n heartbeat.unref?.();\n }\n\n emit(\n `${chalk.dim(stamp())} ${chalk.bold(`watching ${opts.ref.kind}/${opts.ref.name}${opts.ref.namespace ? ` -n ${opts.ref.namespace}` : ''}`)}`,\n );\n\n try {\n for await (const ev of watcher as AsyncIterable<XrEvent>) {\n if (ev.type === 'snapshot') {\n const next = summarise(ev.snapshot);\n if (!prev) {\n emit(renderFullSnapshot(opts.ref, ev.snapshot, next, stamp()));\n idleHeartbeats = 0;\n } else {\n const delta = renderDelta(prev, next, stamp());\n if (delta) {\n emit(delta);\n idleHeartbeats = 0;\n }\n }\n prev = next;\n } else if (ev.type === 'k8s-event') {\n if (showEvents) {\n emit(formatEvent(ev.event));\n } else if (ev.event.type !== 'Normal') {\n // Warnings (and any future non-Normal severities) are always surfaced —\n // buffered here and flushed on the next emit / heartbeat.\n pendingWarnings.push(ev.event);\n }\n } else if (ev.type === 'ready') {\n emit(\n `${chalk.dim(stamp())} ${chalk.green('✔')} ${opts.ref.kind}/${opts.ref.name} ${chalk.green('is Ready')}`,\n );\n } else if (ev.type === 'error') {\n emit(`${chalk.dim(stamp())} ${chalk.red('error:')} ${ev.error.message}`);\n } else if (ev.type === 'end') {\n flushPendingWarnings();\n return;\n }\n }\n } finally {\n if (heartbeat) clearInterval(heartbeat);\n }\n}\n\ninterface SnapshotSummary {\n reason: string | undefined;\n readyCount: number;\n blockedCount: number;\n total: number;\n ready: Set<string>;\n unready: string[];\n blocked: Map<string, string[]>;\n}\n\nfunction summarise(snapshot: XrSnapshot): SnapshotSummary {\n const x: XplaneStatus | undefined = snapshot.xplane;\n const ready = new Set<string>();\n const unready: string[] = [];\n const blocked = new Map<string, string[]>();\n if (x) {\n for (const r of x.emittedResources) {\n if (r.ready) ready.add(r.nodePath);\n else unready.push(r.nodePath);\n }\n for (const b of x.blockedResources) blocked.set(b.nodePath, b.waitingFor ?? []);\n }\n return {\n reason: snapshot.readyReason ?? (snapshot.ready ? 'Available' : undefined),\n readyCount: ready.size || (snapshot.ready ? 1 : 0),\n blockedCount: blocked.size,\n total: x?.emittedResources.length ?? snapshot.resourceRefs.length,\n ready,\n unready,\n blocked,\n };\n}\n\nfunction renderPendingBlock(s: SnapshotSummary): string[] {\n const lines: string[] = [];\n if (s.unready.length > 0) {\n lines.push(chalk.dim(' unready:'));\n for (const path of s.unready) lines.push(` ${chalk.dim('⏳')} ${path}`);\n }\n if (s.blocked.size > 0) {\n lines.push(chalk.dim(' blocked:'));\n for (const [path, waiting] of s.blocked) {\n lines.push(` ${chalk.yellow('-')} ${path}${formatWaiting(waiting)}`);\n }\n }\n return lines;\n}\n\nfunction renderFullSnapshot(\n ref: XrRef,\n snapshot: XrSnapshot,\n s: SnapshotSummary,\n ts: string,\n): string {\n const lines: string[] = [];\n const reason = s.reason ?? 'Pending';\n const target = `${ref.kind}/${ref.name}${ref.namespace ? ` (${ref.namespace})` : ''}`;\n const counts = formatCounts(s.readyCount, s.total, s.blockedCount);\n lines.push(\n `${chalk.dim(ts)} ${chalk.bold(target)} ${chalk.dim('·')} ${reason} ${chalk.dim('·')} ${counts}`,\n );\n if (snapshot.updatesThrottled) {\n lines.push(` ${chalk.yellow('⚠ Updates Throttled')}`);\n }\n if (s.blocked.size > 0) {\n lines.push(chalk.dim(' blocked:'));\n for (const [path, waiting] of s.blocked) {\n lines.push(` ${chalk.yellow('-')} ${path}${formatWaiting(waiting)}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction renderDelta(prev: SnapshotSummary, next: SnapshotSummary, ts: string): string | undefined {\n const becameReady: string[] = [];\n const becameBlocked: string[] = [];\n const waitingChanged: string[] = [];\n\n for (const path of next.ready) if (!prev.ready.has(path)) becameReady.push(path);\n for (const [path, waiting] of next.blocked) {\n if (!prev.blocked.has(path)) {\n becameBlocked.push(path);\n } else {\n const a = (prev.blocked.get(path) ?? []).join('|');\n const b = waiting.join('|');\n if (a !== b) waitingChanged.push(path);\n }\n }\n const reasonChanged = next.reason !== prev.reason;\n const totalsChanged =\n next.readyCount !== prev.readyCount ||\n next.blockedCount !== prev.blockedCount ||\n next.total !== prev.total;\n\n if (\n becameReady.length === 0 &&\n becameBlocked.length === 0 &&\n waitingChanged.length === 0 &&\n !reasonChanged &&\n !totalsChanged\n ) {\n return undefined;\n }\n\n const lines: string[] = [];\n const tsd = chalk.dim(ts);\n for (const path of becameReady) lines.push(`${tsd} ${chalk.green('+')} ${path}`);\n for (const path of becameBlocked) {\n const waiting = next.blocked.get(path) ?? [];\n lines.push(`${tsd} ${chalk.yellow('-')} ${path}${formatWaiting(waiting)}`);\n }\n for (const path of waitingChanged) {\n const waiting = next.blocked.get(path) ?? [];\n lines.push(`${tsd} ${chalk.yellow('~')} ${path}${formatWaiting(waiting)}`);\n }\n if (reasonChanged && next.reason) {\n lines.push(\n `${tsd} ${chalk.yellow('~')} reason: ${chalk.dim(prev.reason ?? '?')} → ${next.reason}`,\n );\n }\n lines.push(\n `${tsd} ${chalk.dim('→')} ${formatCounts(next.readyCount, next.total, next.blockedCount)}`,\n );\n return lines.join('\\n');\n}\n\nfunction formatCounts(ready: number, total: number, blocked: number): string {\n const unready = Math.max(0, total - ready);\n const grand = total + blocked;\n const pct = grand > 0 ? Math.round((ready / grand) * 100) : 0;\n const readyText = `✅ ${ready} ready`;\n const readyPart = total > 0 && ready === total ? chalk.green(readyText) : readyText;\n const unreadyPart = `⏳ ${unready} unready`;\n const blockedPart = `🚧 ${blocked} blocked`;\n const pctPart = `📈 ${pct}%`;\n const dot = '·';\n return `${readyPart} ${dot} ${unreadyPart} ${dot} ${blockedPart} ${dot} ${pctPart}`;\n}\n\nfunction formatWaiting(waiting: string[]): string {\n if (waiting.length === 0) return '';\n return chalk.dim(` waiting ${waiting.join(', ')}`);\n}\n","import type { BlockedResource, EmittedResource, XrSnapshot } from './types.js';\n\n/**\n * A node in the construct-derived resource tree.\n *\n * Resource names emitted by compositions encode their construct path with `/` as\n * the separator (e.g. `\"CMS Database/Security Group\"`). The tree mirrors that\n * hierarchy so renderers can indent each branch.\n */\nexport interface TreeNode {\n /** Last segment of the construct path (display label). */\n label: string;\n /** Full construct path (joined with `/`). */\n path: string;\n /** Kubernetes `metadata.name` of the leaf resource, when known. */\n name?: string;\n /** Kubernetes `metadata.namespace` of the leaf resource, when present. */\n namespace?: string;\n /** True when an emitted resource at this exact path is ready. */\n ready: boolean;\n /** True when this exact path appears in `blockedResources`. */\n blocked: boolean;\n /** Unresolved dependencies copied from the blocked entry. */\n waitingFor?: string[];\n /** API version of the leaf resource (if any). */\n apiVersion?: string;\n /** Kind of the leaf resource (if any). */\n kind?: string;\n /** Child nodes keyed by path segment. */\n children: TreeNode[];\n}\n\n/** Aggregate counts derived from `status.xplane`. */\nexport interface TreeStats {\n /** Total emitted resources. */\n total: number;\n /** Emitted resources marked ready. */\n ready: number;\n /** Blocked resources. */\n blocked: number;\n}\n\nexport interface ResourceTree {\n /** Root-level nodes. */\n roots: TreeNode[];\n /** Aggregate counts. Zero values when no xplane status is available. */\n stats: TreeStats;\n /** Source used to build the tree. */\n source: 'xplane' | 'resourceRefs' | 'empty';\n}\n\n/** Build a `ResourceTree` from a snapshot, preferring `status.xplane` when present. */\nexport function buildTree(snapshot: XrSnapshot): ResourceTree {\n if (snapshot.xplane) {\n return fromXplane(snapshot.xplane.emittedResources, snapshot.xplane.blockedResources);\n }\n if (snapshot.resourceRefs.length > 0) {\n return fromResourceRefs(snapshot.resourceRefs);\n }\n return { roots: [], stats: { total: 0, ready: 0, blocked: 0 }, source: 'empty' };\n}\n\nfunction fromXplane(emitted: EmittedResource[], blocked: BlockedResource[]): ResourceTree {\n const byPath = new Map<string, TreeNode>();\n const ownEntry = new Set<string>();\n const roots: TreeNode[] = [];\n\n const ensureNode = (path: string): TreeNode => {\n const existing = byPath.get(path);\n if (existing) return existing;\n const segments = path.split('/');\n const label = segments[segments.length - 1] ?? path;\n const node: TreeNode = { label, path, ready: false, blocked: false, children: [] };\n byPath.set(path, node);\n if (segments.length === 1) {\n roots.push(node);\n } else {\n const parentPath = segments.slice(0, -1).join('/');\n ensureNode(parentPath).children.push(node);\n }\n return node;\n };\n\n for (const r of emitted) {\n const node = ensureNode(r.nodePath);\n node.ready = r.ready;\n node.apiVersion = r.apiVersion;\n node.kind = r.kind;\n if (r.name) node.name = r.name;\n if (r.namespace) node.namespace = r.namespace;\n ownEntry.add(r.nodePath);\n }\n for (const b of blocked) {\n const node = ensureNode(b.nodePath);\n node.blocked = true;\n if (b.waitingFor) node.waitingFor = b.waitingFor;\n if (!node.apiVersion) node.apiVersion = b.apiVersion;\n if (!node.kind) node.kind = b.kind;\n if (!node.name && b.name) node.name = b.name;\n if (!node.namespace && b.namespace) node.namespace = b.namespace;\n ownEntry.add(b.nodePath);\n }\n\n // Container nodes (synthesised parents with no resource of their own) aggregate\n // readiness from their descendants: ready iff every descendant is ready and\n // none are blocked.\n const aggregate = (node: TreeNode): void => {\n for (const child of node.children) aggregate(child);\n if (!ownEntry.has(node.path) && node.children.length > 0) {\n node.ready = node.children.every((c) => c.ready);\n node.blocked = node.children.some((c) => c.blocked);\n }\n };\n for (const root of roots) aggregate(root);\n\n const readyCount = emitted.reduce((n, r) => n + (r.ready ? 1 : 0), 0);\n return {\n roots,\n stats: { total: emitted.length, ready: readyCount, blocked: blocked.length },\n source: 'xplane',\n };\n}\n\nfunction fromResourceRefs(refs: XrSnapshot['resourceRefs']): ResourceTree {\n const roots = refs.map<TreeNode>((r) => ({\n label: r.name,\n path: r.name,\n ready: false,\n blocked: false,\n apiVersion: r.apiVersion,\n kind: r.kind,\n children: [],\n }));\n return {\n roots,\n stats: { total: refs.length, ready: 0, blocked: 0 },\n source: 'resourceRefs',\n };\n}\n","import chalk from 'chalk';\nimport { createLogUpdate } from 'log-update';\nimport { buildTree, type ResourceTree, type TreeNode } from '../watcher/tree.js';\nimport type { KubernetesEvent, XrEvent, XrRef, XrSnapshot } from '../watcher/types.js';\nimport type { XrWatcher } from '../watcher/xr-watcher.js';\nimport { formatHeader, formatProgress, statusGlyph } from './format.js';\n\nexport interface TtyRendererOptions {\n ref: XrRef;\n /** Destination stream. Defaults to `process.stdout`. */\n out?: NodeJS.WriteStream;\n /** Maximum number of recent Kubernetes events shown in the tail. Defaults to 5. */\n eventTailSize?: number;\n /** Allows callers (and tests) to provide a custom `log-update` instance. */\n logger?: { (frame: string): void; clear: () => void; done: () => void };\n}\n\n/**\n * Live full-screen renderer using `log-update` to repaint a single frame.\n * Resolves when the watcher ends.\n */\nexport async function renderTTY(watcher: XrWatcher, opts: TtyRendererOptions): Promise<void> {\n const out = opts.out ?? process.stdout;\n const logger = opts.logger ?? createLogUpdate(out);\n const tailSize = opts.eventTailSize ?? 5;\n const events: KubernetesEvent[] = [];\n let snapshot: XrSnapshot | undefined;\n let lastError: Error | undefined;\n\n const repaint = () => {\n logger(renderFrame(opts.ref, snapshot, events, lastError, out.rows, out.columns));\n };\n repaint();\n\n for await (const ev of watcher as AsyncIterable<XrEvent>) {\n if (ev.type === 'snapshot') {\n snapshot = ev.snapshot;\n repaint();\n } else if (ev.type === 'k8s-event') {\n events.push(ev.event);\n if (events.length > tailSize) events.splice(0, events.length - tailSize);\n repaint();\n } else if (ev.type === 'error') {\n lastError = ev.error;\n repaint();\n } else if (ev.type === 'ready') {\n snapshot = ev.snapshot;\n repaint();\n } else if (ev.type === 'end') {\n logger.done();\n return;\n }\n }\n logger.done();\n}\n\nfunction renderFrame(\n ref: XrRef,\n snapshot: XrSnapshot | undefined,\n events: KubernetesEvent[],\n err: Error | undefined,\n rows: number | undefined,\n columns: number | undefined,\n): string {\n const lines: string[] = [];\n if (snapshot) {\n lines.push(formatHeader(snapshot, ref));\n const tree = buildTree(snapshot);\n if (tree.stats.total > 0) {\n lines.push(\n ` ${formatProgress(tree.stats.ready, tree.stats.total, tree.stats.blocked)} ${chalk.dim(`(source: ${tree.source})`)}`,\n );\n }\n if (snapshot.readyMessage) {\n lines.push(chalk.dim(` ${snapshot.readyMessage}`));\n }\n if (tree.roots.length > 0) {\n lines.push('');\n lines.push(chalk.bold('Resources'));\n renderTreeLines(tree, lines);\n }\n } else {\n lines.push(chalk.dim(`waiting for first observation of ${ref.kind}/${ref.name}…`));\n }\n\n const errLines: string[] = [];\n if (err) {\n errLines.push('');\n errLines.push(chalk.red(`error: ${err.message}`));\n }\n\n const eventLines: string[] = [];\n if (events.length > 0) {\n eventLines.push('');\n eventLines.push(chalk.bold('Recent events'));\n for (const e of events) eventLines.push(` ${formatEventLine(e)}`);\n }\n\n // When the terminal height is known, ensure the snapshot header + tree are\n // always visible by trimming the event tail (oldest first) to whatever rows\n // remain after reserving space for the snapshot block and error footer.\n if (rows && rows > 0 && eventLines.length > 0) {\n const reserved = lines.length + errLines.length;\n const available = rows - reserved;\n if (available <= 2) {\n // No room for events at all — drop them entirely.\n eventLines.length = 0;\n } else if (eventLines.length > available) {\n // Keep the heading + blank line, drop the oldest events to fit.\n const keep = available - 2;\n const kept = eventLines.slice(eventLines.length - keep);\n eventLines.length = 0;\n eventLines.push('', chalk.bold('Recent events'), ...kept);\n }\n }\n\n const all = [...lines, ...eventLines, ...errLines];\n if (columns && columns > 0) {\n for (let i = 0; i < all.length; i++) {\n const line = all[i] as string;\n if (visibleWidth(line) > columns) all[i] = truncateAnsi(line, columns);\n }\n }\n return all.join('\\n');\n}\n\n// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape sequences require ESC (0x1B).\nconst ANSI_RE = /\\u001b\\[[0-9;]*m/g;\n\nfunction visibleWidth(s: string): number {\n return s.replace(ANSI_RE, '').length;\n}\n\n/** Truncate a string with embedded ANSI escapes to `maxVisible` visible chars,\n * appending an ellipsis and a reset code. */\nfunction truncateAnsi(s: string, maxVisible: number): string {\n if (maxVisible <= 1) return '\\u2026';\n let visible = 0;\n let out = '';\n const limit = maxVisible - 1;\n let i = 0;\n while (i < s.length && visible < limit) {\n ANSI_RE.lastIndex = i;\n const m = ANSI_RE.exec(s);\n if (m && m.index === i) {\n out += m[0];\n i = m.index + m[0].length;\n continue;\n }\n out += s[i];\n visible++;\n i++;\n }\n return `${out}\\u2026\\u001b[0m`;\n}\n\nfunction renderTreeLines(tree: ResourceTree, out: string[]): void {\n for (const root of tree.roots) renderNode(root, '', true, out);\n}\n\nfunction renderNode(node: TreeNode, prefix: string, isLast: boolean, out: string[]): void {\n const branch = prefix === '' ? '' : isLast ? '└─ ' : '├─ ';\n const state = node.blocked ? 'blocked' : node.ready ? 'ready' : 'pending';\n const meta = node.kind ? chalk.dim(` (${node.kind})`) : '';\n const nameDetail = node.name\n ? chalk.dim(node.namespace ? ` ${node.namespace}/${node.name}` : ` ${node.name}`)\n : '';\n const waiting =\n node.waitingFor && node.waitingFor.length > 0\n ? chalk.dim(` waiting for ${node.waitingFor.join(', ')}`)\n : '';\n out.push(`${prefix}${branch}${statusGlyph(state)} ${node.label}${meta}${nameDetail}${waiting}`);\n const childPrefix = prefix + (prefix === '' ? ' ' : isLast ? ' ' : '│ ');\n for (let i = 0; i < node.children.length; i++) {\n renderNode(node.children[i] as TreeNode, childPrefix, i === node.children.length - 1, out);\n }\n}\n\nfunction formatEventLine(ev: KubernetesEvent): string {\n const color = ev.type === 'Warning' ? chalk.yellow : chalk.dim;\n const t = ev.lastTimestamp ? new Date(ev.lastTimestamp).toISOString().slice(11, 19) : '';\n const target = ev.involvedKind ? `${ev.involvedKind}/${ev.involvedName ?? '?'} ` : '';\n return color(`${t} ${target}${ev.reason}: ${ev.message}`).trim();\n}\n","import type { XrRef } from '../watcher/types.js';\nimport type { XrWatcher } from '../watcher/xr-watcher.js';\nimport { renderCI } from './ci.js';\nimport { renderTTY } from './tty.js';\n\nexport { type CiRendererOptions, renderCI } from './ci.js';\nexport { formatEvent, formatHeader, formatProgress, statusGlyph } from './format.js';\nexport { renderTTY, type TtyRendererOptions } from './tty.js';\n\nexport type RendererMode = 'tty' | 'ci';\n\n/** Auto-select a renderer based on whether the destination is an interactive TTY. */\nexport function selectRenderer(stream: NodeJS.WriteStream | NodeJS.WritableStream): RendererMode {\n const tty = stream as Partial<NodeJS.WriteStream>;\n return tty.isTTY ? 'tty' : 'ci';\n}\n\nexport interface RunRendererOptions {\n ref: XrRef;\n /** Forces a renderer instead of auto-detecting. */\n mode?: RendererMode;\n /**\n * Destination stream. Defaults to `process.stdout`.\n * TTY mode requires a `NodeJS.WriteStream` (for `.rows`/`.columns`); pass\n * `mode: 'ci'` explicitly when piping to a plain `WritableStream`.\n */\n out?: NodeJS.WritableStream;\n /** Max number of recent events kept in the TTY tail. */\n eventTailSize?: number;\n /** CI: heartbeat interval (ms) for liveness lines. 0 disables. */\n heartbeatMs?: number;\n /** CI: include K8s Events inline. Off by default. */\n showEvents?: boolean;\n /** CI: every N idle heartbeats, expand into a snapshot of unready + blocked resources. 0 disables. */\n snapshotEveryHeartbeats?: number;\n /** CI: strip ANSI colour escapes from the rendered output. */\n noColor?: boolean;\n}\n\n/**\n * Drive either renderer against the supplied watcher. Resolves when the\n * watcher's event stream ends.\n */\nexport async function runRenderer(watcher: XrWatcher, opts: RunRendererOptions): Promise<void> {\n const out = opts.out ?? process.stdout;\n const mode = opts.mode ?? selectRenderer(out);\n if (mode === 'tty') {\n const ttyOpts: Parameters<typeof renderTTY>[1] = {\n ref: opts.ref,\n out: out as NodeJS.WriteStream,\n };\n if (opts.eventTailSize !== undefined) ttyOpts.eventTailSize = opts.eventTailSize;\n return renderTTY(watcher, ttyOpts);\n }\n const ciOpts: Parameters<typeof renderCI>[1] = { ref: opts.ref, out };\n if (opts.heartbeatMs !== undefined) ciOpts.heartbeatMs = opts.heartbeatMs;\n if (opts.showEvents !== undefined) ciOpts.showEvents = opts.showEvents;\n if (opts.snapshotEveryHeartbeats !== undefined)\n ciOpts.snapshotEveryHeartbeats = opts.snapshotEveryHeartbeats;\n if (opts.noColor !== undefined) ciOpts.noColor = opts.noColor;\n return renderCI(watcher, ciOpts);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/render/ci.ts","../../src/render/format.ts","../../src/render/tty.ts","../../src/render/index.ts"],"mappings":";;;UAWiB,iBAAA;EACf,GAAA,EAAK,KAAA;EAD2B;EAGhC,GAAA,GAAM,MAAA,CAAO,cAAc;EAAA;EAE3B,WAAA;EAJK;EAML,UAAA;EAJM;EAMN,uBAAA;AAAA;;;;AAAuB;AAWzB;;;;iBAAsB,QAAA,CAAS,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,iBAAA,GAAoB,OAAA;;;;iBC3B7D,WAAA,CAAY,KAAsC;ADOlE;AAAA,iBCKgB,YAAA,CACd,QAAA,EAAU,UAAU,EACpB,GAAA;EAAO,IAAA;EAAc,IAAA;EAAc,SAAA;AAAA;;iBAgBrB,cAAA,CAAe,KAAA,UAAe,KAAA,UAAe,OAAA;;iBAO7C,WAAA,CAAY,EAAmB,EAAf,eAAe;;;UClC9B,kBAAA;EACf,GAAA,EAAK,KAAA;EFG2B;EEDhC,GAAA,GAAM,MAAA,CAAO,WAAW;EFIG;EEF3B,aAAA;EFAK;EEEL,MAAA;IAAA,CAAY,KAAA;IAAsB,KAAA;IAAmB,IAAA;EAAA;AAAA;;AFM9B;AAWzB;;iBEVsB,SAAA,CAAU,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,kBAAA,GAAqB,OAAA;;;KCZnE,YAAA;;iBAGI,cAAA,CAAe,MAAA,EAAQ,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,cAAA,GAAiB,YAAA;AAAA,UAKnE,kBAAA;EACf,GAAA,EAAK,KAAA;EHJC;EGMN,IAAA,GAAO,YAAA;EHJP;EGMA,GAAA,GAAM,MAAA,CAAO,WAAA;EHFb;EGIA,aAAA;EHJuB;EGMvB,WAAA;EHK4B;EGH5B,UAAA;EHGsC;EGDtC,uBAAA;AAAA;;;;;iBAOoB,WAAA,CAAY,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,kBAAA,GAAqB,OAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"render-Cnhpyf1X.mjs","names":["tty"],"sources":["../src/render/format.ts","../src/render/ci.ts","../src/render/tty.ts","../src/render/index.ts"],"sourcesContent":["import chalk from 'chalk';\nimport type { KubernetesEvent, XrSnapshot } from '../watcher/types.js';\n\n/** Single-character glyph for the status of a tree node. */\nexport function statusGlyph(state: 'ready' | 'pending' | 'blocked'): string {\n switch (state) {\n case 'ready':\n return chalk.green('✔');\n case 'blocked':\n return chalk.red('✖');\n case 'pending':\n return chalk.yellow('⏳');\n }\n}\n\n/** Compact header line summarising the XR. */\nexport function formatHeader(\n snapshot: XrSnapshot,\n ref: { kind: string; name: string; namespace?: string },\n): string {\n const obj = snapshot.object;\n const fqdn = ref.namespace\n ? `${ref.kind}/${ref.name} (${ref.namespace})`\n : `${ref.kind}/${ref.name}`;\n const readyState = snapshot.ready\n ? chalk.green('Ready')\n : chalk.yellow(snapshot.readyReason ?? 'NotReady');\n const ts = obj.metadata?.creationTimestamp as unknown as string | Date | undefined;\n const age = ts ? formatAge(new Date(ts)) : '?';\n const throttled = snapshot.updatesThrottled ? ` ${chalk.yellow('⚠ Updates Throttled')}` : '';\n return `${chalk.bold(fqdn)} age=${age} ${readyState}${throttled}`;\n}\n\n/** Inline progress representation, e.g. `5/12 ready · 3 blocked`. */\nexport function formatProgress(ready: number, total: number, blocked: number): string {\n const parts: string[] = [`${ready}/${total} ready`];\n if (blocked > 0) parts.push(chalk.red(`${blocked} blocked`));\n return parts.join(chalk.dim(' · '));\n}\n\n/** Format a Kubernetes Event as a single line. */\nexport function formatEvent(ev: KubernetesEvent): string {\n const color = ev.type === 'Warning' ? chalk.yellow : chalk.dim;\n const target = ev.involvedKind && ev.involvedName ? `${ev.involvedKind}/${ev.involvedName} ` : '';\n return color(`${ev.lastTimestamp ?? ''} ${target}${ev.reason}: ${ev.message}`.trim());\n}\n\nfunction formatAge(from: Date): string {\n const ms = Date.now() - from.getTime();\n if (ms < 60_000) return `${Math.floor(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.floor(ms / 60_000)}m`;\n if (ms < 86_400_000) return `${Math.floor(ms / 3_600_000)}h`;\n return `${Math.floor(ms / 86_400_000)}d`;\n}\n","import chalk from 'chalk';\nimport type {\n KubernetesEvent,\n XplaneStatus,\n XrEvent,\n XrRef,\n XrSnapshot,\n} from '../watcher/types.js';\nimport type { XrWatcher } from '../watcher/xr-watcher.js';\nimport { formatEvent } from './format.js';\n\nexport interface CiRendererOptions {\n ref: XrRef;\n /** Destination stream. Defaults to `process.stdout`. */\n out?: NodeJS.WritableStream;\n /** Heartbeat interval (ms). When no changes are observed within this window, emit a \"no change\" line so CI can see the job is alive. Defaults to 30000. Set to 0 to disable. */\n heartbeatMs?: number;\n /** When true, K8s Events are echoed inline. Defaults to false in CI (too noisy). */\n showEvents?: boolean;\n /** Every N consecutive idle heartbeats, expand the heartbeat line into a snapshot of unready + blocked resources. Defaults to 10. Set to 0 to disable. */\n snapshotEveryHeartbeats?: number;\n}\n\n/**\n * Append-only CI renderer.\n *\n * 1. Print a one-line \"watching …\" header on startup.\n * 2. On the first snapshot, print a full snapshot block.\n * 3. On every subsequent snapshot, print only the delta.\n * 4. If nothing is printed within `heartbeatMs`, emit a single liveness line.\n */\nexport async function renderCI(watcher: XrWatcher, opts: CiRendererOptions): Promise<void> {\n const out = opts.out ?? process.stdout;\n const heartbeatMs = opts.heartbeatMs ?? 30_000;\n const showEvents = opts.showEvents ?? false;\n const snapshotEvery = opts.snapshotEveryHeartbeats ?? 10;\n const write = (line: string) => out.write(`${line}\\n`);\n const stamp = () => new Date().toISOString().slice(11, 19);\n let lastWriteAt = Date.now();\n /** Warning (and worse) K8s events buffered since the last flush — always surfaced even when `showEvents` is off. */\n const pendingWarnings: KubernetesEvent[] = [];\n const flushPendingWarnings = () => {\n if (pendingWarnings.length === 0) return;\n for (const e of pendingWarnings) write(formatEvent(e));\n pendingWarnings.length = 0;\n lastWriteAt = Date.now();\n };\n const emit = (line: string) => {\n flushPendingWarnings();\n write(line);\n lastWriteAt = Date.now();\n };\n\n let prev: SnapshotSummary | undefined;\n let idleHeartbeats = 0;\n let heartbeat: NodeJS.Timeout | undefined;\n if (heartbeatMs > 0) {\n heartbeat = setInterval(() => {\n // Surface any buffered warnings first, even if the snapshot itself hasn't changed.\n const hadWarnings = pendingWarnings.length > 0;\n flushPendingWarnings();\n if (!prev) return;\n if (!hadWarnings && Date.now() - lastWriteAt < heartbeatMs) return;\n idleHeartbeats += 1;\n const expand = snapshotEvery > 0 && idleHeartbeats % snapshotEvery === 0;\n const ts = stamp();\n const counts = formatCounts(prev.readyCount, prev.total, prev.blockedCount);\n const headline = `${chalk.dim(ts)} ${chalk.dim('→')} ${counts} ${chalk.dim('(no change)')}`;\n if (!expand) {\n emit(headline);\n return;\n }\n emit([headline, ...renderPendingBlock(prev)].join('\\n'));\n }, heartbeatMs);\n heartbeat.unref?.();\n }\n\n emit(\n `${chalk.dim(stamp())} ${chalk.bold(`watching ${opts.ref.kind}/${opts.ref.name}${opts.ref.namespace ? ` -n ${opts.ref.namespace}` : ''}`)}`,\n );\n\n try {\n for await (const ev of watcher as AsyncIterable<XrEvent>) {\n if (ev.type === 'snapshot') {\n const next = summarise(ev.snapshot);\n if (!prev) {\n emit(renderFullSnapshot(opts.ref, ev.snapshot, next, stamp()));\n idleHeartbeats = 0;\n } else {\n const delta = renderDelta(prev, next, stamp());\n if (delta) {\n emit(delta);\n idleHeartbeats = 0;\n }\n }\n prev = next;\n } else if (ev.type === 'k8s-event') {\n if (showEvents) {\n emit(formatEvent(ev.event));\n } else if (ev.event.type !== 'Normal') {\n // Warnings (and any future non-Normal severities) are always surfaced —\n // buffered here and flushed on the next emit / heartbeat.\n pendingWarnings.push(ev.event);\n }\n } else if (ev.type === 'ready') {\n emit(\n `${chalk.dim(stamp())} ${chalk.green('✔')} ${opts.ref.kind}/${opts.ref.name} ${chalk.green('is Ready')}`,\n );\n } else if (ev.type === 'error') {\n emit(`${chalk.dim(stamp())} ${chalk.red('error:')} ${ev.error.message}`);\n } else if (ev.type === 'end') {\n flushPendingWarnings();\n return;\n }\n }\n } finally {\n if (heartbeat) clearInterval(heartbeat);\n }\n}\n\ninterface SnapshotSummary {\n reason: string | undefined;\n readyCount: number;\n blockedCount: number;\n total: number;\n ready: Set<string>;\n unready: string[];\n blocked: Map<string, string[]>;\n}\n\nfunction summarise(snapshot: XrSnapshot): SnapshotSummary {\n const x: XplaneStatus | undefined = snapshot.xplane;\n const ready = new Set<string>();\n const unready: string[] = [];\n const blocked = new Map<string, string[]>();\n if (x) {\n for (const r of x.emittedResources) {\n if (r.ready) ready.add(r.nodePath);\n else unready.push(r.nodePath);\n }\n for (const b of x.blockedResources) blocked.set(b.nodePath, b.waitingFor ?? []);\n }\n return {\n reason: snapshot.readyReason ?? (snapshot.ready ? 'Available' : undefined),\n readyCount: ready.size || (snapshot.ready ? 1 : 0),\n blockedCount: blocked.size,\n total: x?.emittedResources.length ?? snapshot.resourceRefs.length,\n ready,\n unready,\n blocked,\n };\n}\n\nfunction renderPendingBlock(s: SnapshotSummary): string[] {\n const lines: string[] = [];\n if (s.unready.length > 0) {\n lines.push(chalk.dim(' unready:'));\n for (const path of s.unready) lines.push(` ${chalk.dim('⏳')} ${path}`);\n }\n if (s.blocked.size > 0) {\n lines.push(chalk.dim(' blocked:'));\n for (const [path, waiting] of s.blocked) {\n lines.push(` ${chalk.yellow('-')} ${path}${formatWaiting(waiting)}`);\n }\n }\n return lines;\n}\n\nfunction renderFullSnapshot(\n ref: XrRef,\n snapshot: XrSnapshot,\n s: SnapshotSummary,\n ts: string,\n): string {\n const lines: string[] = [];\n const reason = s.reason ?? 'Pending';\n const target = `${ref.kind}/${ref.name}${ref.namespace ? ` (${ref.namespace})` : ''}`;\n const counts = formatCounts(s.readyCount, s.total, s.blockedCount);\n lines.push(\n `${chalk.dim(ts)} ${chalk.bold(target)} ${chalk.dim('·')} ${reason} ${chalk.dim('·')} ${counts}`,\n );\n if (snapshot.updatesThrottled) {\n lines.push(` ${chalk.yellow('⚠ Updates Throttled')}`);\n }\n if (s.blocked.size > 0) {\n lines.push(chalk.dim(' blocked:'));\n for (const [path, waiting] of s.blocked) {\n lines.push(` ${chalk.yellow('-')} ${path}${formatWaiting(waiting)}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction renderDelta(prev: SnapshotSummary, next: SnapshotSummary, ts: string): string | undefined {\n const becameReady: string[] = [];\n const becameBlocked: string[] = [];\n const waitingChanged: string[] = [];\n\n for (const path of next.ready) if (!prev.ready.has(path)) becameReady.push(path);\n for (const [path, waiting] of next.blocked) {\n if (!prev.blocked.has(path)) {\n becameBlocked.push(path);\n } else {\n const a = (prev.blocked.get(path) ?? []).join('|');\n const b = waiting.join('|');\n if (a !== b) waitingChanged.push(path);\n }\n }\n const reasonChanged = next.reason !== prev.reason;\n const totalsChanged =\n next.readyCount !== prev.readyCount ||\n next.blockedCount !== prev.blockedCount ||\n next.total !== prev.total;\n\n if (\n becameReady.length === 0 &&\n becameBlocked.length === 0 &&\n waitingChanged.length === 0 &&\n !reasonChanged &&\n !totalsChanged\n ) {\n return undefined;\n }\n\n const lines: string[] = [];\n const tsd = chalk.dim(ts);\n for (const path of becameReady) lines.push(`${tsd} ${chalk.green('+')} ${path}`);\n for (const path of becameBlocked) {\n const waiting = next.blocked.get(path) ?? [];\n lines.push(`${tsd} ${chalk.yellow('-')} ${path}${formatWaiting(waiting)}`);\n }\n for (const path of waitingChanged) {\n const waiting = next.blocked.get(path) ?? [];\n lines.push(`${tsd} ${chalk.yellow('~')} ${path}${formatWaiting(waiting)}`);\n }\n if (reasonChanged && next.reason) {\n lines.push(\n `${tsd} ${chalk.yellow('~')} reason: ${chalk.dim(prev.reason ?? '?')} → ${next.reason}`,\n );\n }\n lines.push(\n `${tsd} ${chalk.dim('→')} ${formatCounts(next.readyCount, next.total, next.blockedCount)}`,\n );\n return lines.join('\\n');\n}\n\nfunction formatCounts(ready: number, total: number, blocked: number): string {\n const unready = Math.max(0, total - ready);\n const grand = total + blocked;\n const pct = grand > 0 ? Math.round((ready / grand) * 100) : 0;\n const readyText = `✅ ${ready} ready`;\n const readyPart = total > 0 && ready === total ? chalk.green(readyText) : readyText;\n const unreadyPart = `⏳ ${unready} unready`;\n const blockedPart = `🚧 ${blocked} blocked`;\n const pctPart = `📈 ${pct}%`;\n const dot = '·';\n return `${readyPart} ${dot} ${unreadyPart} ${dot} ${blockedPart} ${dot} ${pctPart}`;\n}\n\nfunction formatWaiting(waiting: string[]): string {\n if (waiting.length === 0) return '';\n return chalk.dim(` waiting ${waiting.join(', ')}`);\n}\n","import chalk from 'chalk';\nimport { createLogUpdate } from 'log-update';\nimport { buildTree, type ResourceTree, type TreeNode } from '../watcher/tree.js';\nimport type { KubernetesEvent, XrEvent, XrRef, XrSnapshot } from '../watcher/types.js';\nimport type { XrWatcher } from '../watcher/xr-watcher.js';\nimport { formatHeader, formatProgress, statusGlyph } from './format.js';\n\nexport interface TtyRendererOptions {\n ref: XrRef;\n /** Destination stream. Defaults to `process.stdout`. */\n out?: NodeJS.WriteStream;\n /** Maximum number of recent Kubernetes events shown in the tail. Defaults to 5. */\n eventTailSize?: number;\n /** Allows callers (and tests) to provide a custom `log-update` instance. */\n logger?: { (frame: string): void; clear: () => void; done: () => void };\n}\n\n/**\n * Live full-screen renderer using `log-update` to repaint a single frame.\n * Resolves when the watcher ends.\n */\nexport async function renderTTY(watcher: XrWatcher, opts: TtyRendererOptions): Promise<void> {\n const out = opts.out ?? process.stdout;\n const logger = opts.logger ?? createLogUpdate(out);\n const tailSize = opts.eventTailSize ?? 5;\n const events: KubernetesEvent[] = [];\n let snapshot: XrSnapshot | undefined;\n let lastError: Error | undefined;\n\n const repaint = () => {\n logger(renderFrame(opts.ref, snapshot, events, lastError, out.rows, out.columns));\n };\n repaint();\n\n for await (const ev of watcher as AsyncIterable<XrEvent>) {\n if (ev.type === 'snapshot') {\n snapshot = ev.snapshot;\n repaint();\n } else if (ev.type === 'k8s-event') {\n events.push(ev.event);\n if (events.length > tailSize) events.splice(0, events.length - tailSize);\n repaint();\n } else if (ev.type === 'error') {\n lastError = ev.error;\n repaint();\n } else if (ev.type === 'ready') {\n snapshot = ev.snapshot;\n repaint();\n } else if (ev.type === 'end') {\n logger.done();\n return;\n }\n }\n logger.done();\n}\n\nfunction renderFrame(\n ref: XrRef,\n snapshot: XrSnapshot | undefined,\n events: KubernetesEvent[],\n err: Error | undefined,\n rows: number | undefined,\n columns: number | undefined,\n): string {\n const lines: string[] = [];\n if (snapshot) {\n lines.push(formatHeader(snapshot, ref));\n const tree = buildTree(snapshot);\n if (tree.stats.total > 0) {\n lines.push(\n ` ${formatProgress(tree.stats.ready, tree.stats.total, tree.stats.blocked)} ${chalk.dim(`(source: ${tree.source})`)}`,\n );\n }\n if (snapshot.readyMessage) {\n lines.push(chalk.dim(` ${snapshot.readyMessage}`));\n }\n if (tree.roots.length > 0) {\n lines.push('');\n lines.push(chalk.bold('Resources'));\n renderTreeLines(tree, lines);\n }\n } else {\n lines.push(chalk.dim(`waiting for first observation of ${ref.kind}/${ref.name}…`));\n }\n\n const errLines: string[] = [];\n if (err) {\n errLines.push('');\n errLines.push(chalk.red(`error: ${err.message}`));\n }\n\n const eventLines: string[] = [];\n if (events.length > 0) {\n eventLines.push('');\n eventLines.push(chalk.bold('Recent events'));\n for (const e of events) eventLines.push(` ${formatEventLine(e)}`);\n }\n\n // When the terminal height is known, ensure the snapshot header + tree are\n // always visible by trimming the event tail (oldest first) to whatever rows\n // remain after reserving space for the snapshot block and error footer.\n if (rows && rows > 0 && eventLines.length > 0) {\n const reserved = lines.length + errLines.length;\n const available = rows - reserved;\n if (available <= 2) {\n // No room for events at all — drop them entirely.\n eventLines.length = 0;\n } else if (eventLines.length > available) {\n // Keep the heading + blank line, drop the oldest events to fit.\n const keep = available - 2;\n const kept = eventLines.slice(eventLines.length - keep);\n eventLines.length = 0;\n eventLines.push('', chalk.bold('Recent events'), ...kept);\n }\n }\n\n const all = [...lines, ...eventLines, ...errLines];\n if (columns && columns > 0) {\n for (let i = 0; i < all.length; i++) {\n const line = all[i] as string;\n if (visibleWidth(line) > columns) all[i] = truncateAnsi(line, columns);\n }\n }\n return all.join('\\n');\n}\n\n// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape sequences require ESC (0x1B).\nconst ANSI_RE = /\\u001b\\[[0-9;]*m/g;\n\nfunction visibleWidth(s: string): number {\n return s.replace(ANSI_RE, '').length;\n}\n\n/** Truncate a string with embedded ANSI escapes to `maxVisible` visible chars,\n * appending an ellipsis and a reset code. */\nfunction truncateAnsi(s: string, maxVisible: number): string {\n if (maxVisible <= 1) return '\\u2026';\n let visible = 0;\n let out = '';\n const limit = maxVisible - 1;\n let i = 0;\n while (i < s.length && visible < limit) {\n ANSI_RE.lastIndex = i;\n const m = ANSI_RE.exec(s);\n if (m && m.index === i) {\n out += m[0];\n i = m.index + m[0].length;\n continue;\n }\n out += s[i];\n visible++;\n i++;\n }\n return `${out}\\u2026\\u001b[0m`;\n}\n\nfunction renderTreeLines(tree: ResourceTree, out: string[]): void {\n for (const root of tree.roots) renderNode(root, '', true, out);\n}\n\nfunction renderNode(node: TreeNode, prefix: string, isLast: boolean, out: string[]): void {\n const branch = prefix === '' ? '' : isLast ? '└─ ' : '├─ ';\n const state = node.blocked ? 'blocked' : node.ready ? 'ready' : 'pending';\n const meta = node.kind ? chalk.dim(` (${node.kind})`) : '';\n const nameDetail = node.name\n ? chalk.dim(node.namespace ? ` ${node.namespace}/${node.name}` : ` ${node.name}`)\n : '';\n const waiting =\n node.waitingFor && node.waitingFor.length > 0\n ? chalk.dim(` waiting for ${node.waitingFor.join(', ')}`)\n : '';\n out.push(`${prefix}${branch}${statusGlyph(state)} ${node.label}${meta}${nameDetail}${waiting}`);\n const childPrefix = prefix + (prefix === '' ? ' ' : isLast ? ' ' : '│ ');\n for (let i = 0; i < node.children.length; i++) {\n renderNode(node.children[i] as TreeNode, childPrefix, i === node.children.length - 1, out);\n }\n}\n\nfunction formatEventLine(ev: KubernetesEvent): string {\n const color = ev.type === 'Warning' ? chalk.yellow : chalk.dim;\n const t = ev.lastTimestamp ? new Date(ev.lastTimestamp).toISOString().slice(11, 19) : '';\n const target = ev.involvedKind ? `${ev.involvedKind}/${ev.involvedName ?? '?'} ` : '';\n return color(`${t} ${target}${ev.reason}: ${ev.message}`).trim();\n}\n","import type { XrRef } from '../watcher/types.js';\nimport type { XrWatcher } from '../watcher/xr-watcher.js';\nimport { renderCI } from './ci.js';\nimport { renderTTY } from './tty.js';\n\nexport { type CiRendererOptions, renderCI } from './ci.js';\nexport { formatEvent, formatHeader, formatProgress, statusGlyph } from './format.js';\nexport { renderTTY, type TtyRendererOptions } from './tty.js';\n\nexport type RendererMode = 'tty' | 'ci';\n\n/** Auto-select a renderer based on whether the destination is an interactive TTY. */\nexport function selectRenderer(stream: NodeJS.WriteStream | NodeJS.WritableStream): RendererMode {\n const tty = stream as Partial<NodeJS.WriteStream>;\n return tty.isTTY ? 'tty' : 'ci';\n}\n\nexport interface RunRendererOptions {\n ref: XrRef;\n /** Forces a renderer instead of auto-detecting. */\n mode?: RendererMode;\n /** Destination stream. Defaults to `process.stdout`. */\n out?: NodeJS.WriteStream;\n /** Max number of recent events kept in the TTY tail. */\n eventTailSize?: number;\n /** CI: heartbeat interval (ms) for liveness lines. 0 disables. */\n heartbeatMs?: number;\n /** CI: include K8s Events inline. Off by default. */\n showEvents?: boolean;\n /** CI: every N idle heartbeats, expand into a snapshot of unready + blocked resources. 0 disables. */\n snapshotEveryHeartbeats?: number;\n}\n\n/**\n * Drive either renderer against the supplied watcher. Resolves when the\n * watcher's event stream ends.\n */\nexport async function runRenderer(watcher: XrWatcher, opts: RunRendererOptions): Promise<void> {\n const out = opts.out ?? process.stdout;\n const mode = opts.mode ?? selectRenderer(out);\n if (mode === 'tty') {\n const ttyOpts: Parameters<typeof renderTTY>[1] = { ref: opts.ref, out };\n if (opts.eventTailSize !== undefined) ttyOpts.eventTailSize = opts.eventTailSize;\n return renderTTY(watcher, ttyOpts);\n }\n const ciOpts: Parameters<typeof renderCI>[1] = { ref: opts.ref, out };\n if (opts.heartbeatMs !== undefined) ciOpts.heartbeatMs = opts.heartbeatMs;\n if (opts.showEvents !== undefined) ciOpts.showEvents = opts.showEvents;\n if (opts.snapshotEveryHeartbeats !== undefined)\n ciOpts.snapshotEveryHeartbeats = opts.snapshotEveryHeartbeats;\n return renderCI(watcher, ciOpts);\n}\n"],"mappings":"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"}
|
package/dist/tree-DaHkojq8.mjs
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
//#region src/watcher/tree.ts
|
|
2
|
-
/** Build a `ResourceTree` from a snapshot, preferring `status.xplane` when present. */
|
|
3
|
-
function buildTree(snapshot) {
|
|
4
|
-
if (snapshot.xplane) return fromXplane(snapshot.xplane.emittedResources, snapshot.xplane.blockedResources);
|
|
5
|
-
if (snapshot.resourceRefs.length > 0) return fromResourceRefs(snapshot.resourceRefs);
|
|
6
|
-
return {
|
|
7
|
-
roots: [],
|
|
8
|
-
stats: {
|
|
9
|
-
total: 0,
|
|
10
|
-
ready: 0,
|
|
11
|
-
blocked: 0
|
|
12
|
-
},
|
|
13
|
-
source: "empty"
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function fromXplane(emitted, blocked) {
|
|
17
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
18
|
-
const ownEntry = /* @__PURE__ */ new Set();
|
|
19
|
-
const roots = [];
|
|
20
|
-
const ensureNode = (path) => {
|
|
21
|
-
const existing = byPath.get(path);
|
|
22
|
-
if (existing) return existing;
|
|
23
|
-
const segments = path.split("/");
|
|
24
|
-
const node = {
|
|
25
|
-
label: segments[segments.length - 1] ?? path,
|
|
26
|
-
path,
|
|
27
|
-
ready: false,
|
|
28
|
-
blocked: false,
|
|
29
|
-
children: []
|
|
30
|
-
};
|
|
31
|
-
byPath.set(path, node);
|
|
32
|
-
if (segments.length === 1) roots.push(node);
|
|
33
|
-
else ensureNode(segments.slice(0, -1).join("/")).children.push(node);
|
|
34
|
-
return node;
|
|
35
|
-
};
|
|
36
|
-
for (const r of emitted) {
|
|
37
|
-
const node = ensureNode(r.nodePath);
|
|
38
|
-
node.ready = r.ready;
|
|
39
|
-
node.apiVersion = r.apiVersion;
|
|
40
|
-
node.kind = r.kind;
|
|
41
|
-
if (r.name) node.name = r.name;
|
|
42
|
-
if (r.namespace) node.namespace = r.namespace;
|
|
43
|
-
ownEntry.add(r.nodePath);
|
|
44
|
-
}
|
|
45
|
-
for (const b of blocked) {
|
|
46
|
-
const node = ensureNode(b.nodePath);
|
|
47
|
-
node.blocked = true;
|
|
48
|
-
if (b.waitingFor) node.waitingFor = b.waitingFor;
|
|
49
|
-
if (!node.apiVersion) node.apiVersion = b.apiVersion;
|
|
50
|
-
if (!node.kind) node.kind = b.kind;
|
|
51
|
-
if (!node.name && b.name) node.name = b.name;
|
|
52
|
-
if (!node.namespace && b.namespace) node.namespace = b.namespace;
|
|
53
|
-
ownEntry.add(b.nodePath);
|
|
54
|
-
}
|
|
55
|
-
const aggregate = (node) => {
|
|
56
|
-
for (const child of node.children) aggregate(child);
|
|
57
|
-
if (!ownEntry.has(node.path) && node.children.length > 0) {
|
|
58
|
-
node.ready = node.children.every((c) => c.ready);
|
|
59
|
-
node.blocked = node.children.some((c) => c.blocked);
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
for (const root of roots) aggregate(root);
|
|
63
|
-
const readyCount = emitted.reduce((n, r) => n + (r.ready ? 1 : 0), 0);
|
|
64
|
-
return {
|
|
65
|
-
roots,
|
|
66
|
-
stats: {
|
|
67
|
-
total: emitted.length,
|
|
68
|
-
ready: readyCount,
|
|
69
|
-
blocked: blocked.length
|
|
70
|
-
},
|
|
71
|
-
source: "xplane"
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function fromResourceRefs(refs) {
|
|
75
|
-
return {
|
|
76
|
-
roots: refs.map((r) => ({
|
|
77
|
-
label: r.name,
|
|
78
|
-
path: r.name,
|
|
79
|
-
ready: false,
|
|
80
|
-
blocked: false,
|
|
81
|
-
apiVersion: r.apiVersion,
|
|
82
|
-
kind: r.kind,
|
|
83
|
-
children: []
|
|
84
|
-
})),
|
|
85
|
-
stats: {
|
|
86
|
-
total: refs.length,
|
|
87
|
-
ready: 0,
|
|
88
|
-
blocked: 0
|
|
89
|
-
},
|
|
90
|
-
source: "resourceRefs"
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
export { buildTree as t };
|
|
95
|
-
|
|
96
|
-
//# sourceMappingURL=tree-DaHkojq8.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tree-DaHkojq8.mjs","names":[],"sources":["../src/watcher/tree.ts"],"sourcesContent":["import type { BlockedResource, EmittedResource, XrSnapshot } from './types.js';\n\n/**\n * A node in the construct-derived resource tree.\n *\n * Resource names emitted by compositions encode their construct path with `/` as\n * the separator (e.g. `\"CMS Database/Security Group\"`). The tree mirrors that\n * hierarchy so renderers can indent each branch.\n */\nexport interface TreeNode {\n /** Last segment of the construct path (display label). */\n label: string;\n /** Full construct path (joined with `/`). */\n path: string;\n /** Kubernetes `metadata.name` of the leaf resource, when known. */\n name?: string;\n /** Kubernetes `metadata.namespace` of the leaf resource, when present. */\n namespace?: string;\n /** True when an emitted resource at this exact path is ready. */\n ready: boolean;\n /** True when this exact path appears in `blockedResources`. */\n blocked: boolean;\n /** Unresolved dependencies copied from the blocked entry. */\n waitingFor?: string[];\n /** API version of the leaf resource (if any). */\n apiVersion?: string;\n /** Kind of the leaf resource (if any). */\n kind?: string;\n /** Child nodes keyed by path segment. */\n children: TreeNode[];\n}\n\n/** Aggregate counts derived from `status.xplane`. */\nexport interface TreeStats {\n /** Total emitted resources. */\n total: number;\n /** Emitted resources marked ready. */\n ready: number;\n /** Blocked resources. */\n blocked: number;\n}\n\nexport interface ResourceTree {\n /** Root-level nodes. */\n roots: TreeNode[];\n /** Aggregate counts. Zero values when no xplane status is available. */\n stats: TreeStats;\n /** Source used to build the tree. */\n source: 'xplane' | 'resourceRefs' | 'empty';\n}\n\n/** Build a `ResourceTree` from a snapshot, preferring `status.xplane` when present. */\nexport function buildTree(snapshot: XrSnapshot): ResourceTree {\n if (snapshot.xplane) {\n return fromXplane(snapshot.xplane.emittedResources, snapshot.xplane.blockedResources);\n }\n if (snapshot.resourceRefs.length > 0) {\n return fromResourceRefs(snapshot.resourceRefs);\n }\n return { roots: [], stats: { total: 0, ready: 0, blocked: 0 }, source: 'empty' };\n}\n\nfunction fromXplane(emitted: EmittedResource[], blocked: BlockedResource[]): ResourceTree {\n const byPath = new Map<string, TreeNode>();\n const ownEntry = new Set<string>();\n const roots: TreeNode[] = [];\n\n const ensureNode = (path: string): TreeNode => {\n const existing = byPath.get(path);\n if (existing) return existing;\n const segments = path.split('/');\n const label = segments[segments.length - 1] ?? path;\n const node: TreeNode = { label, path, ready: false, blocked: false, children: [] };\n byPath.set(path, node);\n if (segments.length === 1) {\n roots.push(node);\n } else {\n const parentPath = segments.slice(0, -1).join('/');\n ensureNode(parentPath).children.push(node);\n }\n return node;\n };\n\n for (const r of emitted) {\n const node = ensureNode(r.nodePath);\n node.ready = r.ready;\n node.apiVersion = r.apiVersion;\n node.kind = r.kind;\n if (r.name) node.name = r.name;\n if (r.namespace) node.namespace = r.namespace;\n ownEntry.add(r.nodePath);\n }\n for (const b of blocked) {\n const node = ensureNode(b.nodePath);\n node.blocked = true;\n if (b.waitingFor) node.waitingFor = b.waitingFor;\n if (!node.apiVersion) node.apiVersion = b.apiVersion;\n if (!node.kind) node.kind = b.kind;\n if (!node.name && b.name) node.name = b.name;\n if (!node.namespace && b.namespace) node.namespace = b.namespace;\n ownEntry.add(b.nodePath);\n }\n\n // Container nodes (synthesised parents with no resource of their own) aggregate\n // readiness from their descendants: ready iff every descendant is ready and\n // none are blocked.\n const aggregate = (node: TreeNode): void => {\n for (const child of node.children) aggregate(child);\n if (!ownEntry.has(node.path) && node.children.length > 0) {\n node.ready = node.children.every((c) => c.ready);\n node.blocked = node.children.some((c) => c.blocked);\n }\n };\n for (const root of roots) aggregate(root);\n\n const readyCount = emitted.reduce((n, r) => n + (r.ready ? 1 : 0), 0);\n return {\n roots,\n stats: { total: emitted.length, ready: readyCount, blocked: blocked.length },\n source: 'xplane',\n };\n}\n\nfunction fromResourceRefs(refs: XrSnapshot['resourceRefs']): ResourceTree {\n const roots = refs.map<TreeNode>((r) => ({\n label: r.name,\n path: r.name,\n ready: false,\n blocked: false,\n apiVersion: r.apiVersion,\n kind: r.kind,\n children: [],\n }));\n return {\n roots,\n stats: { total: refs.length, ready: 0, blocked: 0 },\n source: 'resourceRefs',\n };\n}\n"],"mappings":";;AAoDA,SAAgB,UAAU,UAAoC;CAC5D,IAAI,SAAS,QACX,OAAO,WAAW,SAAS,OAAO,kBAAkB,SAAS,OAAO,gBAAgB;CAEtF,IAAI,SAAS,aAAa,SAAS,GACjC,OAAO,iBAAiB,SAAS,YAAY;CAE/C,OAAO;EAAE,OAAO,CAAC;EAAG,OAAO;GAAE,OAAO;GAAG,OAAO;GAAG,SAAS;EAAE;EAAG,QAAQ;CAAQ;AACjF;AAEA,SAAS,WAAW,SAA4B,SAA0C;CACxF,MAAM,yBAAS,IAAI,IAAsB;CACzC,MAAM,2BAAW,IAAI,IAAY;CACjC,MAAM,QAAoB,CAAC;CAE3B,MAAM,cAAc,SAA2B;EAC7C,MAAM,WAAW,OAAO,IAAI,IAAI;EAChC,IAAI,UAAU,OAAO;EACrB,MAAM,WAAW,KAAK,MAAM,GAAG;EAE/B,MAAM,OAAiB;GAAE,OADX,SAAS,SAAS,SAAS,MAAM;GACf;GAAM,OAAO;GAAO,SAAS;GAAO,UAAU,CAAC;EAAE;EACjF,OAAO,IAAI,MAAM,IAAI;EACrB,IAAI,SAAS,WAAW,GACtB,MAAM,KAAK,IAAI;OAGf,WADmB,SAAS,MAAM,GAAG,EAAE,EAAE,KAAK,GAC1B,CAAC,EAAE,SAAS,KAAK,IAAI;EAE3C,OAAO;CACT;CAEA,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,OAAO,WAAW,EAAE,QAAQ;EAClC,KAAK,QAAQ,EAAE;EACf,KAAK,aAAa,EAAE;EACpB,KAAK,OAAO,EAAE;EACd,IAAI,EAAE,MAAM,KAAK,OAAO,EAAE;EAC1B,IAAI,EAAE,WAAW,KAAK,YAAY,EAAE;EACpC,SAAS,IAAI,EAAE,QAAQ;CACzB;CACA,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,OAAO,WAAW,EAAE,QAAQ;EAClC,KAAK,UAAU;EACf,IAAI,EAAE,YAAY,KAAK,aAAa,EAAE;EACtC,IAAI,CAAC,KAAK,YAAY,KAAK,aAAa,EAAE;EAC1C,IAAI,CAAC,KAAK,MAAM,KAAK,OAAO,EAAE;EAC9B,IAAI,CAAC,KAAK,QAAQ,EAAE,MAAM,KAAK,OAAO,EAAE;EACxC,IAAI,CAAC,KAAK,aAAa,EAAE,WAAW,KAAK,YAAY,EAAE;EACvD,SAAS,IAAI,EAAE,QAAQ;CACzB;CAKA,MAAM,aAAa,SAAyB;EAC1C,KAAK,MAAM,SAAS,KAAK,UAAU,UAAU,KAAK;EAClD,IAAI,CAAC,SAAS,IAAI,KAAK,IAAI,KAAK,KAAK,SAAS,SAAS,GAAG;GACxD,KAAK,QAAQ,KAAK,SAAS,OAAO,MAAM,EAAE,KAAK;GAC/C,KAAK,UAAU,KAAK,SAAS,MAAM,MAAM,EAAE,OAAO;EACpD;CACF;CACA,KAAK,MAAM,QAAQ,OAAO,UAAU,IAAI;CAExC,MAAM,aAAa,QAAQ,QAAQ,GAAG,MAAM,KAAK,EAAE,QAAQ,IAAI,IAAI,CAAC;CACpE,OAAO;EACL;EACA,OAAO;GAAE,OAAO,QAAQ;GAAQ,OAAO;GAAY,SAAS,QAAQ;EAAO;EAC3E,QAAQ;CACV;AACF;AAEA,SAAS,iBAAiB,MAAgD;CAUxE,OAAO;EACL,OAVY,KAAK,KAAe,OAAO;GACvC,OAAO,EAAE;GACT,MAAM,EAAE;GACR,OAAO;GACP,SAAS;GACT,YAAY,EAAE;GACd,MAAM,EAAE;GACR,UAAU,CAAC;EACb,EAEM;EACJ,OAAO;GAAE,OAAO,KAAK;GAAQ,OAAO;GAAG,SAAS;EAAE;EAClD,QAAQ;CACV;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"xr-watcher-1etyvp-6.mjs","names":[],"sources":["../src/client/kubeconfig.ts","../src/watcher/await-ready.ts","../src/watcher/readiness.ts","../src/watcher/target.ts","../src/client/lists.ts","../src/client/watch.ts","../src/watcher/queue.ts","../src/watcher/xr-watcher.ts"],"sourcesContent":["import { KubeConfig } from '@kubernetes/client-node';\n\nexport interface LoadKubeConfigOptions {\n /** Explicit kubeconfig file path. Falls back to `KUBECONFIG` / default discovery. */\n kubeconfig?: string;\n /** Override the active context. */\n context?: string;\n}\n\n/**\n * Load a `KubeConfig` from disk using `client-node`'s default rules (with\n * optional explicit overrides). The returned config has its current context\n * applied.\n */\nexport function loadKubeConfig(opts: LoadKubeConfigOptions = {}): KubeConfig {\n const kc = new KubeConfig();\n if (opts.kubeconfig) {\n kc.loadFromFile(opts.kubeconfig);\n } else {\n kc.loadFromDefault();\n }\n if (opts.context) {\n kc.setCurrentContext(opts.context);\n }\n return kc;\n}\n","import type { XrSnapshot } from './types.js';\nimport type { XrWatcher } from './xr-watcher.js';\n\nexport interface AwaitReadyOptions {\n /** Maximum time in ms to wait for `Ready=True` before rejecting. */\n timeoutMs?: number;\n}\n\n/**\n * Resolve when the watcher observes its first `Ready=True` snapshot. Rejects on\n * the watcher's first error, if the stream ends without becoming ready, or on\n * `timeoutMs`.\n *\n * Uses the watcher's dedicated `ready` promise — it does NOT consume queue\n * events, so it composes safely with a concurrent renderer iterating the\n * watcher.\n *\n * The watcher itself is not stopped on resolution — call `watcher.stop()` from\n * a `.finally()` if you want the underlying connections torn down.\n */\nexport async function awaitReady(\n watcher: XrWatcher,\n opts: AwaitReadyOptions = {},\n): Promise<XrSnapshot> {\n if (opts.timeoutMs === undefined) return watcher.ready;\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Timed out after ${opts.timeoutMs}ms waiting for Ready`)),\n opts.timeoutMs,\n );\n });\n try {\n return await Promise.race([watcher.ready, timeout]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n","import type { KubernetesObject } from '@kubernetes/client-node';\nimport type { ResourceRef, XplaneStatus, XrSnapshot } from './types.js';\n\ninterface Condition {\n type?: string;\n status?: string;\n reason?: string;\n message?: string;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n\n/**\n * Build an `XrSnapshot` from a raw Kubernetes object. Parses the `Ready` condition,\n * the optional `status.xplane` payload and `status.resourceRefs`.\n */\nexport function buildSnapshot(object: KubernetesObject): XrSnapshot {\n const status = isRecord((object as { status?: unknown }).status)\n ? (object as { status: Record<string, unknown> }).status\n : undefined;\n\n const conditions: Condition[] = [];\n if (status && Array.isArray(status.conditions)) {\n for (const c of status.conditions as unknown[]) {\n if (isRecord(c)) {\n conditions.push({\n type: asString(c.type),\n status: asString(c.status),\n reason: asString(c.reason),\n message: asString(c.message),\n });\n }\n }\n }\n const ready = conditions.find((c) => c.type === 'Ready');\n const responsive = conditions.find((c) => c.type === 'Responsive');\n const synced = conditions.find((c) => c.type === 'Synced');\n\n const snapshot: XrSnapshot = {\n object,\n ready: ready?.status === 'True',\n resourceRefs: parseResourceRefs(status),\n };\n if (ready?.reason !== undefined) snapshot.readyReason = ready.reason;\n if (ready?.message !== undefined) snapshot.readyMessage = ready.message;\n if (responsive?.status === 'False' && responsive.reason === 'WatchCircuitOpen') {\n snapshot.updatesThrottled = true;\n }\n if (synced?.status === 'False' && synced.reason === 'ReconcileError') {\n snapshot.syncError = {\n reason: synced.reason,\n message: synced.message ?? '',\n };\n }\n\n const xplane = parseXplane(status);\n if (xplane) snapshot.xplane = xplane;\n\n return snapshot;\n}\n\nfunction parseResourceRefs(status: Record<string, unknown> | undefined): ResourceRef[] {\n const out: ResourceRef[] = [];\n if (!status) return out;\n const refs = status.resourceRefs;\n if (!Array.isArray(refs)) return out;\n for (const r of refs as unknown[]) {\n if (!isRecord(r)) continue;\n const apiVersion = asString(r.apiVersion) ?? '';\n const kind = asString(r.kind) ?? '';\n const name = asString(r.name) ?? '';\n if (name) out.push({ apiVersion, kind, name });\n }\n return out;\n}\n\nfunction parseXplane(status: Record<string, unknown> | undefined): XplaneStatus | undefined {\n if (!status || !isRecord(status.xplane)) return undefined;\n const x = status.xplane;\n const emitted: XplaneStatus['emittedResources'] = [];\n if (Array.isArray(x.emittedResources)) {\n for (const r of x.emittedResources as unknown[]) {\n if (!isRecord(r)) continue;\n const nodePath = asString(r.nodePath);\n if (!nodePath) continue;\n const name = asString(r.name);\n const namespace = asString(r.namespace);\n emitted.push({\n apiVersion: asString(r.apiVersion) ?? '',\n kind: asString(r.kind) ?? '',\n nodePath,\n ...(name ? { name } : {}),\n ...(namespace ? { namespace } : {}),\n ready: r.ready === true,\n });\n }\n }\n const blocked: XplaneStatus['blockedResources'] = [];\n if (Array.isArray(x.blockedResources)) {\n for (const r of x.blockedResources as unknown[]) {\n if (!isRecord(r)) continue;\n const nodePath = asString(r.nodePath);\n if (!nodePath) continue;\n const name = asString(r.name);\n const namespace = asString(r.namespace);\n const entry: XplaneStatus['blockedResources'][number] = {\n apiVersion: asString(r.apiVersion) ?? '',\n kind: asString(r.kind) ?? '',\n nodePath,\n ...(name ? { name } : {}),\n ...(namespace ? { namespace } : {}),\n };\n if (Array.isArray(r.waitingFor)) {\n const wf = (r.waitingFor as unknown[]).filter((s): s is string => typeof s === 'string');\n if (wf.length > 0) entry.waitingFor = wf;\n }\n blocked.push(entry);\n }\n }\n return { emittedResources: emitted, blockedResources: blocked };\n}\n","/**\n * Parse a kubectl-style resource target of the form:\n * <resource>/<name>\n * where `<resource>` is one of:\n * - `kind` (e.g. `xprojects`, `XProject`)\n * - `kind.group` (e.g. `xprojects.platform.example.com`)\n * - `kind.version.group` (e.g. `xprojects.v1alpha1.platform.example.com`)\n *\n * The `kind` token is returned as-is; resolving it to an API group/version/plural\n * is the discovery layer's responsibility (see `client/discovery.ts`).\n */\nexport interface ParsedTarget {\n /** Resource hint: kind, plural, or short name as typed by the user. */\n resource: string;\n /** Optional API group hint extracted from `kind.group` or `kind.version.group`. */\n group?: string;\n /** Optional API version hint extracted from `kind.version.group`. */\n version?: string;\n /** Object name. */\n name: string;\n}\n\nexport function parseTarget(input: string): ParsedTarget {\n const slash = input.indexOf('/');\n if (slash < 0) {\n throw new Error(\n `Invalid target \"${input}\": expected kubectl-style \"<resource>/<name>\" (e.g. \"xprojects/foo\" or \"xprojects.platform.example.com/foo\").`,\n );\n }\n const left = input.slice(0, slash);\n const name = input.slice(slash + 1);\n if (left.length === 0 || name.length === 0) {\n throw new Error(`Invalid target \"${input}\": both resource and name are required.`);\n }\n\n const dot = left.indexOf('.');\n if (dot < 0) return { resource: left, name };\n\n const resource = left.slice(0, dot);\n const rest = left.slice(dot + 1);\n\n // Heuristic: a Kubernetes API version token starts with `v` followed by a digit\n // (`v1`, `v1alpha1`, `v2beta3`). If the first segment of `rest` matches, treat\n // it as the version and the remainder as the group.\n const restDot = rest.indexOf('.');\n if (restDot > 0) {\n const maybeVersion = rest.slice(0, restDot);\n if (/^v\\d/.test(maybeVersion)) {\n return { resource, version: maybeVersion, group: rest.slice(restDot + 1), name };\n }\n }\n return { resource, group: rest, name };\n}\n","import {\n CoreV1Api,\n CustomObjectsApi,\n type KubeConfig,\n type KubernetesObject,\n} from '@kubernetes/client-node';\nimport type { XrRef } from '../watcher/types.js';\nimport type { ListResult } from './watch.js';\n\ninterface CustomObjectList {\n metadata?: { resourceVersion?: string };\n items?: KubernetesObject[];\n}\n\n/** Initial-list for a single XR via `CustomObjectsApi`, filtered by name. */\nexport async function listXrCollection(kc: KubeConfig, ref: XrRef): Promise<ListResult> {\n const api = kc.makeApiClient(CustomObjectsApi);\n const fieldSelector = `metadata.name=${ref.name}`;\n const res = (await (ref.namespaced && ref.namespace\n ? api.listNamespacedCustomObject({\n group: ref.group,\n version: ref.version,\n namespace: ref.namespace,\n plural: ref.plural,\n fieldSelector,\n })\n : api.listClusterCustomObject({\n group: ref.group,\n version: ref.version,\n plural: ref.plural,\n fieldSelector,\n }))) as CustomObjectList;\n return {\n resourceVersion: res.metadata?.resourceVersion ?? '',\n items: res.items ?? [],\n };\n}\n\n/** Initial-list of Kubernetes Events scoped to a namespace + field selector. */\nexport async function listXrEvents(\n kc: KubeConfig,\n namespace: string,\n fieldSelector: string,\n): Promise<ListResult> {\n const api = kc.makeApiClient(CoreV1Api);\n const res = await api.listNamespacedEvent({ namespace, fieldSelector });\n return {\n resourceVersion: res.metadata?.resourceVersion ?? '',\n items: (res.items ?? []) as unknown as KubernetesObject[],\n };\n}\n","import type { KubeConfig, KubernetesObject } from '@kubernetes/client-node';\nimport { Watch } from '@kubernetes/client-node';\n\n/** Watch event phase as published by the Kubernetes watch protocol. */\nexport type WatchPhase = 'ADDED' | 'MODIFIED' | 'DELETED' | 'BOOKMARK' | 'ERROR';\n\n/** Result of an initial list call. */\nexport interface ListResult<T extends KubernetesObject = KubernetesObject> {\n resourceVersion: string;\n items: T[];\n}\n\nexport interface ListWatchOptions {\n /** Watch URL path, e.g. `/apis/group/v1/namespaces/ns/plural`. */\n path: string;\n /** Optional field selector applied to the watch stream. */\n fieldSelector?: string;\n /** Optional label selector applied to the watch stream. */\n labelSelector?: string;\n /** Aborts both the initial list and any subsequent watch streams. */\n signal: AbortSignal;\n /** Caller-provided initial list. Use a typed client (`CoreV1Api`, `CustomObjectsApi`, …). */\n list: () => Promise<ListResult>;\n /** Invoked for each observed object (after the initial list and on each watch event). */\n onEvent: (phase: WatchPhase, obj: KubernetesObject) => void;\n /** Invoked when a stream ends in error and a reconnect is about to be attempted. */\n onError?: (err: Error) => void;\n}\n\ninterface ReconnectableState {\n resourceVersion: string;\n}\n\n/**\n * Run a robust list-then-watch loop. The initial list is supplied by the caller\n * (so it can use a typed Kubernetes client); the watch stream uses the raw\n * `Watch` class because it is the only API surface that supports a\n * `fieldSelector` for a single named object.\n *\n * Behaviour:\n * 1. Call `opts.list()` and emit each item as `ADDED`.\n * 2. Start a `Watch` stream from the returned `resourceVersion`. Each event is forwarded.\n * 3. When the stream ends with an error or the server closes it, sleep briefly and reconnect.\n * 4. The loop exits cleanly when the supplied `AbortSignal` fires.\n */\nexport async function listAndWatch(kc: KubeConfig, opts: ListWatchOptions): Promise<void> {\n const state: ReconnectableState = { resourceVersion: '' };\n const watcher = new Watch(kc);\n\n while (!opts.signal.aborted) {\n try {\n const list = await opts.list();\n state.resourceVersion = list.resourceVersion;\n for (const item of list.items) opts.onEvent('ADDED', item);\n\n await runWatchOnce(watcher, opts, state);\n } catch (err) {\n if (opts.signal.aborted) return;\n const e = err instanceof Error ? err : new Error(String(err));\n opts.onError?.(e);\n await sleep(1000, opts.signal);\n }\n }\n}\n\nfunction runWatchOnce(\n watcher: Watch,\n opts: ListWatchOptions,\n state: ReconnectableState,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const queryParams: Record<string, string | boolean> = { watch: true };\n if (opts.fieldSelector) queryParams.fieldSelector = opts.fieldSelector;\n if (opts.labelSelector) queryParams.labelSelector = opts.labelSelector;\n if (state.resourceVersion) queryParams.resourceVersion = state.resourceVersion;\n queryParams.allowWatchBookmarks = true;\n\n let controllerRef: AbortController | undefined;\n let settled = false;\n const resolveOnce = () => {\n if (settled) return;\n settled = true;\n opts.signal.removeEventListener('abort', onAbort);\n resolve();\n };\n const rejectOnce = (err: unknown) => {\n if (settled) return;\n settled = true;\n opts.signal.removeEventListener('abort', onAbort);\n reject(err instanceof Error ? err : new Error(String(err)));\n };\n const onAbort = () => {\n controllerRef?.abort();\n resolveOnce();\n };\n opts.signal.addEventListener('abort', onAbort, { once: true });\n\n watcher\n .watch(\n opts.path,\n queryParams,\n (phase, apiObj) => {\n const obj = apiObj as KubernetesObject;\n const objRv = (obj.metadata?.resourceVersion as string | undefined) ?? '';\n if (objRv) state.resourceVersion = objRv;\n opts.onEvent(phase as WatchPhase, obj);\n },\n (err) => {\n if (err) rejectOnce(err);\n else resolveOnce();\n },\n )\n .then((controller) => {\n controllerRef = controller;\n if (opts.signal.aborted) {\n controller.abort();\n resolveOnce();\n }\n })\n .catch((err) => rejectOnce(err));\n });\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n const t = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n resolve();\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * Single-consumer async queue used by the XR watcher to expose its event\n * stream as both a callback API and a `for await` async iterable.\n *\n * Memory-bounded only by the producer. Designed for low-frequency control-plane\n * events (Kubernetes watch + status reconciliations), not high-throughput data.\n */\nexport class AsyncQueue<T> implements AsyncIterable<T> {\n private buffer: T[] = [];\n private waiters: Array<(r: IteratorResult<T>) => void> = [];\n private closed = false;\n\n push(value: T): void {\n if (this.closed) return;\n const waiter = this.waiters.shift();\n if (waiter) waiter({ value, done: false });\n else this.buffer.push(value);\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n for (const w of this.waiters.splice(0)) w({ value: undefined, done: true });\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n const v = this.buffer.shift();\n if (v !== undefined) return Promise.resolve({ value: v, done: false });\n if (this.closed) return Promise.resolve({ value: undefined, done: true });\n return new Promise<IteratorResult<T>>((resolve) => this.waiters.push(resolve));\n },\n return: (): Promise<IteratorResult<T>> => {\n this.close();\n return Promise.resolve({ value: undefined, done: true });\n },\n };\n }\n}\n","import type { KubeConfig, KubernetesObject } from '@kubernetes/client-node';\nimport { listXrCollection, listXrEvents } from '../client/lists.js';\nimport { listAndWatch } from '../client/watch.js';\nimport { AsyncQueue } from './queue.js';\nimport { buildSnapshot } from './readiness.js';\nimport type { KubernetesEvent, XrEvent, XrRef, XrSnapshot } from './types.js';\n\nexport interface CreateXrWatcherOptions {\n kubeConfig: KubeConfig;\n ref: XrRef;\n /** Disable subscribing to Kubernetes Events for the XR. Defaults to `false`. */\n disableEvents?: boolean;\n /** Aborts both the XR and Events watches and closes the iterable. */\n signal?: AbortSignal;\n}\n\nexport interface XrWatcher extends AsyncIterable<XrEvent> {\n /** Resolves with the first ready snapshot. Rejects on error or end-before-ready. */\n readonly ready: Promise<XrSnapshot>;\n /** Resolves when the watcher's background tasks have all settled. */\n readonly done: Promise<void>;\n /** Aborts the watcher and closes the iterable. Idempotent. */\n stop(): void;\n}\n\n/**\n * Subscribe to live updates of a single XR. Emits a `snapshot` on every observed\n * change, a one-shot `ready` when the XR's `Ready` condition first becomes True,\n * and (unless disabled) `k8s-event` items for Kubernetes Events targeting the XR.\n *\n * The watcher uses list-then-watch with auto-reconnect — no polling.\n */\nexport function createXrWatcher(opts: CreateXrWatcherOptions): XrWatcher {\n const queue = new AsyncQueue<XrEvent>();\n const controller = new AbortController();\n const userSignal = opts.signal;\n if (userSignal) {\n if (userSignal.aborted) controller.abort();\n else userSignal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n let readyEmitted = false;\n let uid: string | undefined;\n let eventsStarted = false;\n let eventsTask: Promise<void> = Promise.resolve();\n const seenEventUids = new Set<string>();\n\n let resolveReady!: (snap: XrSnapshot) => void;\n let rejectReady!: (err: Error) => void;\n let readySettled = false;\n const ready = new Promise<XrSnapshot>((res, rej) => {\n resolveReady = (s) => {\n if (readySettled) return;\n readySettled = true;\n res(s);\n };\n rejectReady = (e) => {\n if (readySettled) return;\n readySettled = true;\n rej(e);\n };\n });\n // Avoid unhandled rejection if nobody awaits `ready`.\n ready.catch(() => undefined);\n\n const handleXrEvent = (phase: string, obj: KubernetesObject) => {\n if (phase === 'DELETED') {\n const err = new Error(`XR ${opts.ref.kind}/${opts.ref.name} was deleted`);\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n controller.abort();\n return;\n }\n if (phase === 'BOOKMARK' || phase === 'ERROR') return;\n const snapshot = buildSnapshot(obj);\n queue.push({ type: 'snapshot', snapshot });\n if (snapshot.syncError) {\n const err = new Error(\n `XR ${opts.ref.kind}/${opts.ref.name} reconcile failed: ${snapshot.syncError.message || snapshot.syncError.reason}`,\n );\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n controller.abort();\n return;\n }\n if (!readyEmitted && snapshot.ready) {\n readyEmitted = true;\n queue.push({ type: 'ready', snapshot });\n resolveReady(snapshot);\n }\n const newUid = obj.metadata?.uid as string | undefined;\n if (newUid && !uid) {\n uid = newUid;\n if (!opts.disableEvents && opts.ref.namespaced && opts.ref.namespace) {\n eventsStarted = true;\n eventsTask = startEventsWatch(opts, uid, controller.signal, queue, seenEventUids);\n }\n }\n };\n\n const xrPath = buildResourcePath(opts.ref);\n let firstListSeenItem = false;\n const xrTask = listAndWatch(opts.kubeConfig, {\n path: xrPath,\n fieldSelector: `metadata.name=${opts.ref.name}`,\n signal: controller.signal,\n list: async () => {\n const result = await listXrCollection(opts.kubeConfig, opts.ref);\n if (!firstListSeenItem) {\n if (result.items.length > 0) {\n firstListSeenItem = true;\n } else {\n const where = opts.ref.namespace ? ` in namespace ${opts.ref.namespace}` : '';\n const err = new Error(`XR ${opts.ref.kind}/${opts.ref.name} not found${where}`);\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n controller.abort();\n }\n }\n return result;\n },\n onEvent: handleXrEvent,\n onError: (err) => {\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n },\n });\n\n const done = (async () => {\n try {\n await xrTask;\n } finally {\n if (eventsStarted) {\n try {\n await eventsTask;\n } catch {\n /* already surfaced via onError */\n }\n }\n rejectReady(new Error('Watcher ended before XR became Ready'));\n queue.push({ type: 'end' });\n queue.close();\n }\n })();\n\n return {\n ready,\n done,\n stop: () => controller.abort(),\n [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator](),\n };\n}\n\nfunction buildResourcePath(ref: XrRef): string {\n const base = ref.group ? `/apis/${ref.group}/${ref.version}` : `/api/${ref.version}`;\n if (ref.namespaced) {\n if (!ref.namespace) {\n throw new Error(`Namespace is required for namespaced resource ${ref.kind}/${ref.name}`);\n }\n return `${base}/namespaces/${ref.namespace}/${ref.plural}`;\n }\n return `${base}/${ref.plural}`;\n}\n\nasync function startEventsWatch(\n opts: CreateXrWatcherOptions,\n uid: string,\n signal: AbortSignal,\n queue: AsyncQueue<XrEvent>,\n seen: Set<string>,\n): Promise<void> {\n if (!opts.ref.namespace) return;\n const namespace = opts.ref.namespace;\n const path = `/api/v1/namespaces/${namespace}/events`;\n const fieldSelector = `involvedObject.uid=${uid}`;\n await listAndWatch(opts.kubeConfig, {\n path,\n fieldSelector,\n signal,\n list: () => listXrEvents(opts.kubeConfig, namespace, fieldSelector),\n onEvent: (phase, obj) => {\n if (phase !== 'ADDED' && phase !== 'MODIFIED') return;\n const eventUid = obj.metadata?.uid as string | undefined;\n if (eventUid && seen.has(eventUid)) return;\n if (eventUid) seen.add(eventUid);\n const event = toKubernetesEvent(obj);\n if (event) queue.push({ type: 'k8s-event', event });\n },\n onError: (err) => queue.push({ type: 'error', error: err }),\n });\n}\n\nfunction toKubernetesEvent(obj: KubernetesObject): KubernetesEvent | undefined {\n const raw = obj as KubernetesObject & {\n type?: string;\n reason?: string;\n message?: string;\n count?: number;\n firstTimestamp?: string;\n lastTimestamp?: string;\n eventTime?: string;\n involvedObject?: { kind?: string; name?: string };\n };\n if (!raw.message && !raw.reason) return undefined;\n const event: KubernetesEvent = {\n type: raw.type ?? 'Normal',\n reason: raw.reason ?? '',\n message: raw.message ?? '',\n count: raw.count ?? 1,\n };\n const first = raw.firstTimestamp ?? raw.eventTime;\n const last = raw.lastTimestamp ?? raw.eventTime ?? first;\n if (first) event.firstTimestamp = first;\n if (last) event.lastTimestamp = last;\n if (raw.involvedObject?.kind) event.involvedKind = raw.involvedObject.kind;\n if (raw.involvedObject?.name) event.involvedName = raw.involvedObject.name;\n return event;\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"xr-watcher-EiWHVp3o.d.mts","names":[],"sources":["../src/watcher/types.ts","../src/watcher/xr-watcher.ts"],"mappings":";;;;;AAKA;UAAiB,KAAA;;EAEf,KAAA;EAAA;EAEA,OAAA;EAEA;EAAA,MAAA;EAIA;EAFA,IAAA;EAMA;EAJA,UAAA;EAIS;EAFT,IAAA;EAM8B;EAJ9B,SAAA;AAAA;;UAIe,eAAA;EACf,UAAA;EACA,IAAA;EAMA;EAJA,QAAA;EAKK;EAHL,IAAA;EAOe;EALf,SAAA;EACA,KAAA;AAAA;;UAIe,eAAA;EACf,UAAA;EACA,IAAA;EAMA;EAJA,QAAA;EAKU;EAHV,IAAA;EAOe;EALf,SAAA;EACA,UAAA;AAAA;;UAIe,YAAA;EACf,gBAAA,EAAkB,eAAA;EAClB,gBAAA,EAAkB,eAAe;AAAA;AAAA;AAAA,UAIlB,WAAA;EACf,UAAA;EACA,IAAA;EACA,IAAA;AAAA;;UAIe,UAAA;EAJX;EAMJ,MAAA,EAAQ,gBAAA;EAFO;EAIf,KAAA;;EAEA,WAAA;EAQS;EANT,YAAA;EAQyB;EANzB,gBAAA;EARA;EAUA,SAAA;IAAc,MAAA;IAAgB,OAAA;EAAA;EAF9B;EAIA,MAAA,GAAS,YAAA;EAFK;EAId,YAAA,EAAc,WAAA;AAAA;;UAIC,eAAA;EACf,IAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,cAAA;EACA,aAAA;EACA,YAAA;EACA,YAAA;AAAA;;KAIU,OAAA;EACN,IAAA;EAAkB,QAAA,EAAU,UAAA;AAAA;EAC5B,IAAA;EAAmB,KAAA,EAAO,eAAA;AAAA;EAC1B,IAAA;EAAe,QAAA,EAAU,UAAA;AAAA;EACzB,IAAA;EAAe,KAAA,EAAO,KAAA;AAAA;EACtB,IAAA;AAAA;;;UC5FW,sBAAA;EACf,UAAA,EAAY,UAAA;EACZ,GAAA,EAAK,KAAA;;EAEL,aAAA;EDJA;ECMA,MAAA,GAAS,WAAA;AAAA;AAAA,UAGM,SAAA,SAAkB,aAAA,CAAc,OAAA;EDD/C;EAAA,SCGS,KAAA,EAAO,OAAA,CAAQ,UAAA;EDCxB;EAAA,SCCS,IAAA,EAAM,OAAA;EDDN;ECGT,IAAA;AAAA;;;;;;;;iBAUc,eAAA,CAAgB,IAAA,EAAM,sBAAA,GAAyB,SAAS"}
|