@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
package/dist/cli.mjs
CHANGED
|
@@ -1,96 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as awaitReady, n as
|
|
3
|
-
import { t as runRenderer } from "./render-
|
|
2
|
+
import { a as awaitReady, i as parseTarget, n as createXrWatcher, o as listXrCollection, s as resolveResource, t as loadKubeConfig } from "./kubeconfig-BO2X-qXU.mjs";
|
|
3
|
+
import { t as runRenderer } from "./render-BMhfzOc2.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
|
-
import { ApiextensionsV1Api } from "@kubernetes/client-node";
|
|
6
5
|
import { defineCommand, runMain } from "citty";
|
|
7
|
-
//#region src/cli/discovery.ts
|
|
8
|
-
let crdCache;
|
|
9
|
-
/**
|
|
10
|
-
* Fetch the cluster's CRDs and project them into a flat list of resolved
|
|
11
|
-
* resources (one entry per served version). Cached per `KubeConfig` instance.
|
|
12
|
-
*/
|
|
13
|
-
async function listCrdResources(kc) {
|
|
14
|
-
crdCache ??= /* @__PURE__ */ new WeakMap();
|
|
15
|
-
const cached = crdCache.get(kc);
|
|
16
|
-
if (cached) return cached;
|
|
17
|
-
const promise = fetchCrdResources(kc).catch((err) => {
|
|
18
|
-
crdCache?.delete(kc);
|
|
19
|
-
throw err;
|
|
20
|
-
});
|
|
21
|
-
crdCache.set(kc, promise);
|
|
22
|
-
return promise;
|
|
23
|
-
}
|
|
24
|
-
async function fetchCrdResources(kc) {
|
|
25
|
-
const list = await kc.makeApiClient(ApiextensionsV1Api).listCustomResourceDefinition();
|
|
26
|
-
const out = [];
|
|
27
|
-
for (const item of list.items ?? []) {
|
|
28
|
-
const spec = item.spec;
|
|
29
|
-
if (!spec?.group || !spec.names?.kind || !spec.names.plural) continue;
|
|
30
|
-
const namespaced = spec.scope === "Namespaced";
|
|
31
|
-
for (const v of spec.versions ?? []) {
|
|
32
|
-
if (!v.name || v.served === false) continue;
|
|
33
|
-
out.push({
|
|
34
|
-
group: spec.group,
|
|
35
|
-
version: v.name,
|
|
36
|
-
kind: spec.names.kind,
|
|
37
|
-
plural: spec.names.plural,
|
|
38
|
-
namespaced
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return out;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Resolve a `<resource>[.group][.version]` user hint to a single CRD-backed
|
|
46
|
-
* resource. Throws when nothing matches or when the hint is ambiguous.
|
|
47
|
-
*/
|
|
48
|
-
async function resolveResource(kc, hint) {
|
|
49
|
-
const all = await listCrdResources(kc);
|
|
50
|
-
const r = hint.resource.toLowerCase();
|
|
51
|
-
const matches = all.filter((c) => {
|
|
52
|
-
const kindLc = c.kind.toLowerCase();
|
|
53
|
-
const pluralLc = c.plural.toLowerCase();
|
|
54
|
-
if (kindLc !== r && pluralLc !== r) return false;
|
|
55
|
-
if (hint.group !== void 0 && c.group !== hint.group) return false;
|
|
56
|
-
if (hint.version !== void 0 && c.version !== hint.version) return false;
|
|
57
|
-
return true;
|
|
58
|
-
});
|
|
59
|
-
if (matches.length === 0) {
|
|
60
|
-
const detail = [
|
|
61
|
-
hint.resource,
|
|
62
|
-
hint.group,
|
|
63
|
-
hint.version
|
|
64
|
-
].filter(Boolean).join(".");
|
|
65
|
-
throw new Error(`No CRD found matching "${detail}". Available kinds: ${summarise(all)}.`);
|
|
66
|
-
}
|
|
67
|
-
if (matches.length > 1) {
|
|
68
|
-
if (hint.version === void 0) {
|
|
69
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
70
|
-
for (const m of matches) grouped.set(`${m.group}/${m.kind}`, [...grouped.get(`${m.group}/${m.kind}`) ?? [], m]);
|
|
71
|
-
if (grouped.size === 1) return [...matches].sort((a, b) => b.version.localeCompare(a.version))[0];
|
|
72
|
-
}
|
|
73
|
-
const candidates = matches.map((m) => `${m.plural}.${m.version}.${m.group}`).join(", ");
|
|
74
|
-
throw new Error(`Ambiguous resource hint "${hint.resource}". Candidates: ${candidates}. Disambiguate with .group or .version.group.`);
|
|
75
|
-
}
|
|
76
|
-
return matches[0];
|
|
77
|
-
}
|
|
78
|
-
function summarise(all) {
|
|
79
|
-
const seen = /* @__PURE__ */ new Set();
|
|
80
|
-
const out = [];
|
|
81
|
-
for (const r of all) {
|
|
82
|
-
const k = `${r.plural}.${r.group}`;
|
|
83
|
-
if (seen.has(k)) continue;
|
|
84
|
-
seen.add(k);
|
|
85
|
-
out.push(k);
|
|
86
|
-
if (out.length >= 20) {
|
|
87
|
-
out.push("…");
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return out.join(", ");
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
6
|
//#region src/cli/get-status.ts
|
|
95
7
|
/**
|
|
96
8
|
* Headless implementation of the `xplane-utils get-status` subcommand.
|
|
@@ -101,10 +13,19 @@ async function runGetStatusCommand(args, deps = {}) {
|
|
|
101
13
|
const resolve = deps.resolveResource ?? resolveResource;
|
|
102
14
|
const list = deps.listXrCollection ?? listXrCollection;
|
|
103
15
|
const out = deps.out ?? process.stdout;
|
|
104
|
-
|
|
105
|
-
if (args.
|
|
106
|
-
|
|
107
|
-
|
|
16
|
+
let kc;
|
|
17
|
+
if (args.kubeConfig) {
|
|
18
|
+
if (args.kubeconfig !== void 0 || args.context !== void 0) return {
|
|
19
|
+
code: 1,
|
|
20
|
+
error: "pass either kubeConfig or kubeconfig+context, not both"
|
|
21
|
+
};
|
|
22
|
+
kc = args.kubeConfig;
|
|
23
|
+
} else {
|
|
24
|
+
const kcOpts = {};
|
|
25
|
+
if (args.kubeconfig !== void 0) kcOpts.kubeconfig = args.kubeconfig;
|
|
26
|
+
if (args.context !== void 0) kcOpts.context = args.context;
|
|
27
|
+
kc = load(kcOpts);
|
|
28
|
+
}
|
|
108
29
|
const parsed = parseTarget(args.target);
|
|
109
30
|
const resolved = await resolve(kc, {
|
|
110
31
|
resource: parsed.resource,
|
|
@@ -185,10 +106,19 @@ async function runWatchCommand(args, deps = {}) {
|
|
|
185
106
|
const factory = deps.createXrWatcher ?? createXrWatcher;
|
|
186
107
|
const render = deps.runRenderer ?? runRenderer;
|
|
187
108
|
const wait = deps.awaitReady ?? awaitReady;
|
|
188
|
-
|
|
189
|
-
if (args.
|
|
190
|
-
|
|
191
|
-
|
|
109
|
+
let kc;
|
|
110
|
+
if (args.kubeConfig) {
|
|
111
|
+
if (args.kubeconfig !== void 0 || args.context !== void 0) return {
|
|
112
|
+
code: 1,
|
|
113
|
+
error: "pass either kubeConfig or kubeconfig+context, not both"
|
|
114
|
+
};
|
|
115
|
+
kc = args.kubeConfig;
|
|
116
|
+
} else {
|
|
117
|
+
const kcOpts = {};
|
|
118
|
+
if (args.kubeconfig !== void 0) kcOpts.kubeconfig = args.kubeconfig;
|
|
119
|
+
if (args.context !== void 0) kcOpts.context = args.context;
|
|
120
|
+
kc = load(kcOpts);
|
|
121
|
+
}
|
|
192
122
|
const parsed = parseTarget(args.target);
|
|
193
123
|
const resolved = await resolve(kc, {
|
|
194
124
|
resource: parsed.resource,
|
|
@@ -222,6 +152,7 @@ async function runWatchCommand(args, deps = {}) {
|
|
|
222
152
|
if (heartbeatMs !== void 0) renderOpts.heartbeatMs = heartbeatMs;
|
|
223
153
|
if (args.showEvents !== void 0) renderOpts.showEvents = args.showEvents;
|
|
224
154
|
if (args.snapshotEveryHeartbeats !== void 0) renderOpts.snapshotEveryHeartbeats = args.snapshotEveryHeartbeats;
|
|
155
|
+
if (args.noColor !== void 0) renderOpts.noColor = args.noColor;
|
|
225
156
|
const renderPromise = render(watcher, renderOpts);
|
|
226
157
|
const timeoutMs = parseDuration(args.timeout);
|
|
227
158
|
try {
|
|
@@ -285,6 +216,10 @@ const watch = defineCommand({
|
|
|
285
216
|
"snapshot-every": {
|
|
286
217
|
type: "string",
|
|
287
218
|
description: "CI mode: every N idle heartbeats, expand the liveness line into a snapshot of unready + blocked resources (default 10, 0 to disable)"
|
|
219
|
+
},
|
|
220
|
+
"no-color": {
|
|
221
|
+
type: "boolean",
|
|
222
|
+
description: "CI mode: strip ANSI colour escapes from rendered output"
|
|
288
223
|
}
|
|
289
224
|
},
|
|
290
225
|
async run({ args }) {
|
|
@@ -304,6 +239,7 @@ const watch = defineCommand({
|
|
|
304
239
|
const n = Number.parseInt(args["snapshot-every"], 10);
|
|
305
240
|
if (Number.isFinite(n) && n >= 0) cmdArgs.snapshotEveryHeartbeats = n;
|
|
306
241
|
}
|
|
242
|
+
if (args["no-color"]) cmdArgs.noColor = true;
|
|
307
243
|
const result = await runWatchCommand(cmdArgs, { signal: controller.signal });
|
|
308
244
|
if (result.code !== 0) {
|
|
309
245
|
if (result.error) process.stderr.write(`${result.error}\n`);
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli/discovery.ts","../src/cli/get-status.ts","../src/cli/duration.ts","../src/cli/watch.ts","../src/cli.ts"],"sourcesContent":["import { ApiextensionsV1Api, type KubeConfig } from '@kubernetes/client-node';\n\n/** Resolved API resource metadata. */\nexport interface ResolvedResource {\n group: string;\n version: string;\n kind: string;\n plural: string;\n namespaced: boolean;\n}\n\nlet crdCache: WeakMap<KubeConfig, Promise<ResolvedResource[]>> | undefined;\n\n/**\n * Fetch the cluster's CRDs and project them into a flat list of resolved\n * resources (one entry per served version). Cached per `KubeConfig` instance.\n */\nexport async function listCrdResources(kc: KubeConfig): Promise<ResolvedResource[]> {\n crdCache ??= new WeakMap();\n const cached = crdCache.get(kc);\n if (cached) return cached;\n const promise = fetchCrdResources(kc).catch((err) => {\n crdCache?.delete(kc);\n throw err;\n });\n crdCache.set(kc, promise);\n return promise;\n}\n\nasync function fetchCrdResources(kc: KubeConfig): Promise<ResolvedResource[]> {\n const api = kc.makeApiClient(ApiextensionsV1Api);\n const list = await api.listCustomResourceDefinition();\n const out: ResolvedResource[] = [];\n for (const item of list.items ?? []) {\n const spec = item.spec;\n if (!spec?.group || !spec.names?.kind || !spec.names.plural) continue;\n const namespaced = spec.scope === 'Namespaced';\n for (const v of spec.versions ?? []) {\n if (!v.name || v.served === false) continue;\n out.push({\n group: spec.group,\n version: v.name,\n kind: spec.names.kind,\n plural: spec.names.plural,\n namespaced,\n });\n }\n }\n return out;\n}\n\n/**\n * Resolve a `<resource>[.group][.version]` user hint to a single CRD-backed\n * resource. Throws when nothing matches or when the hint is ambiguous.\n */\nexport async function resolveResource(\n kc: KubeConfig,\n hint: { resource: string; group?: string; version?: string },\n): Promise<ResolvedResource> {\n const all = await listCrdResources(kc);\n const r = hint.resource.toLowerCase();\n const matches = all.filter((c) => {\n const kindLc = c.kind.toLowerCase();\n const pluralLc = c.plural.toLowerCase();\n if (kindLc !== r && pluralLc !== r) return false;\n if (hint.group !== undefined && c.group !== hint.group) return false;\n if (hint.version !== undefined && c.version !== hint.version) return false;\n return true;\n });\n if (matches.length === 0) {\n const detail = [hint.resource, hint.group, hint.version].filter(Boolean).join('.');\n throw new Error(`No CRD found matching \"${detail}\". Available kinds: ${summarise(all)}.`);\n }\n if (matches.length > 1) {\n if (hint.version === undefined) {\n const grouped = new Map<string, ResolvedResource[]>();\n for (const m of matches)\n grouped.set(`${m.group}/${m.kind}`, [...(grouped.get(`${m.group}/${m.kind}`) ?? []), m]);\n if (grouped.size === 1) {\n // Multiple served versions of the same kind/group — pick the lexicographically highest.\n const sorted = [...matches].sort((a, b) => b.version.localeCompare(a.version));\n return sorted[0] as ResolvedResource;\n }\n }\n const candidates = matches.map((m) => `${m.plural}.${m.version}.${m.group}`).join(', ');\n throw new Error(\n `Ambiguous resource hint \"${hint.resource}\". Candidates: ${candidates}. Disambiguate with .group or .version.group.`,\n );\n }\n return matches[0] as ResolvedResource;\n}\n\nfunction summarise(all: ResolvedResource[]): string {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of all) {\n const k = `${r.plural}.${r.group}`;\n if (seen.has(k)) continue;\n seen.add(k);\n out.push(k);\n if (out.length >= 20) {\n out.push('…');\n break;\n }\n }\n return out.join(', ');\n}\n","import type { KubeConfig } from '@kubernetes/client-node';\nimport { type LoadKubeConfigOptions, loadKubeConfig } from '../client/kubeconfig.js';\nimport { listXrCollection } from '../client/lists.js';\nimport { parseTarget } from '../watcher/target.js';\nimport type { XrRef } from '../watcher/types.js';\nimport { resolveResource } from './discovery.js';\n\nexport type GetStatusFormat = 'dot' | 'json';\n\nexport interface GetStatusCommandArgs {\n target: string;\n namespace?: string;\n kubeconfig?: string;\n context?: string;\n /** Output format. Defaults to \"dot\". */\n format?: GetStatusFormat;\n /** Pretty-print JSON output. Ignored for `dot`. Defaults to true. */\n pretty?: boolean;\n /** Include the framework-managed `status.xplane` subtree. Defaults to false. */\n includeXplane?: boolean;\n /** Include `status.conditions`. Defaults to false. */\n includeConditions?: boolean;\n}\n\nexport interface GetStatusCommandDeps {\n loadKubeConfig?: (opts: LoadKubeConfigOptions) => KubeConfig;\n resolveResource?: typeof resolveResource;\n listXrCollection?: typeof listXrCollection;\n /** Destination stream for the rendered output. */\n out?: NodeJS.WritableStream;\n}\n\nexport type GetStatusResult = { code: 0 } | { code: 1; error: string };\n\n/**\n * Headless implementation of the `xplane-utils get-status` subcommand.\n * Fetches a single XR and prints its `.status` to `out` in the requested format.\n */\nexport async function runGetStatusCommand(\n args: GetStatusCommandArgs,\n deps: GetStatusCommandDeps = {},\n): Promise<GetStatusResult> {\n const load = deps.loadKubeConfig ?? loadKubeConfig;\n const resolve = deps.resolveResource ?? resolveResource;\n const list = deps.listXrCollection ?? listXrCollection;\n const out = deps.out ?? process.stdout;\n\n const kcOpts: LoadKubeConfigOptions = {};\n if (args.kubeconfig !== undefined) kcOpts.kubeconfig = args.kubeconfig;\n if (args.context !== undefined) kcOpts.context = args.context;\n const kc = load(kcOpts);\n\n const parsed = parseTarget(args.target);\n const resolved = await resolve(kc, {\n resource: parsed.resource,\n ...(parsed.group !== undefined ? { group: parsed.group } : {}),\n ...(parsed.version !== undefined ? { version: parsed.version } : {}),\n });\n const ref: XrRef = {\n group: resolved.group,\n version: resolved.version,\n plural: resolved.plural,\n kind: resolved.kind,\n namespaced: resolved.namespaced,\n name: parsed.name,\n ...(args.namespace !== undefined ? { namespace: args.namespace } : {}),\n };\n if (ref.namespaced && !ref.namespace) {\n return { code: 1, error: `${ref.kind} is namespaced — pass --namespace/-n` };\n }\n\n const result = await list(kc, ref);\n const item = result.items[0] as Record<string, unknown> | undefined;\n if (!item) {\n const target = `${ref.kind}/${ref.name}${ref.namespace ? ` -n ${ref.namespace}` : ''}`;\n return { code: 1, error: `${target} not found` };\n }\n const status = (item.status ?? {}) as Record<string, unknown>;\n const excluded = new Set<string>();\n if (!args.includeXplane) excluded.add('xplane');\n if (!args.includeConditions) excluded.add('conditions');\n const filtered =\n excluded.size === 0\n ? status\n : Object.fromEntries(Object.entries(status).filter(([k]) => !excluded.has(k)));\n\n const format: GetStatusFormat = args.format ?? 'dot';\n const text =\n format === 'json'\n ? JSON.stringify(filtered, null, args.pretty === false ? 0 : 2)\n : toDotLines(filtered).join('\\n');\n out.write(text.length > 0 ? `${text}\\n` : '');\n return { code: 0 };\n}\n\n/**\n * Flatten an arbitrary JSON value into `path=value` lines. Object keys are\n * joined with `.`; array indices use `[n]`. Leaf values are JSON-encoded so\n * strings retain their quoting and special characters are preserved.\n */\nexport function toDotLines(value: unknown, prefix = ''): string[] {\n if (value === undefined) return [];\n if (value === null) return [`${prefix || '.'}=null`];\n if (Array.isArray(value)) {\n if (value.length === 0) return [`${prefix || '.'}=[]`];\n return value.flatMap((v, i) => toDotLines(v, `${prefix}[${i}]`));\n }\n if (typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>);\n if (entries.length === 0) return [`${prefix || '.'}={}`];\n return entries.flatMap(([k, v]) => toDotLines(v, prefix ? `${prefix}.${k}` : k));\n }\n return [`${prefix || '.'}=${JSON.stringify(value)}`];\n}\n","/** Parse a duration like `30s`, `5m`, `2h`, `100ms`, or a bare integer (milliseconds). */\nexport function parseDuration(input: string | undefined): number | undefined {\n if (input === undefined || input === '') return undefined;\n const m = /^(\\d+)(ms|s|m|h)?$/.exec(input);\n if (!m)\n throw new Error(`Invalid duration \"${input}\". Use e.g. \"30s\", \"5m\", \"1h\", or a number of ms.`);\n const n = Number(m[1]);\n switch (m[2]) {\n case undefined:\n case 'ms':\n return n;\n case 's':\n return n * 1000;\n case 'm':\n return n * 60_000;\n case 'h':\n return n * 3_600_000;\n }\n // Unreachable — regex guarantees one of the cases above matches.\n /* c8 ignore next */\n return undefined;\n}\n","import type { KubeConfig } from '@kubernetes/client-node';\nimport { type LoadKubeConfigOptions, loadKubeConfig } from '../client/kubeconfig.js';\nimport { type RendererMode, runRenderer } from '../render/index.js';\nimport { awaitReady } from '../watcher/await-ready.js';\nimport { parseTarget } from '../watcher/target.js';\nimport type { XrRef } from '../watcher/types.js';\nimport { createXrWatcher, type XrWatcher } from '../watcher/xr-watcher.js';\nimport { resolveResource } from './discovery.js';\nimport { parseDuration } from './duration.js';\n\nexport interface WatchCommandArgs {\n target: string;\n namespace?: string;\n kubeconfig?: string;\n context?: string;\n timeout?: string;\n mode?: string;\n disableEvents?: boolean;\n /** CI: heartbeat interval (e.g. \"30s\"). 0 disables. */\n heartbeat?: string;\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\nexport interface WatchCommandDeps {\n /** Override KubeConfig loader (for tests). */\n loadKubeConfig?: (opts: LoadKubeConfigOptions) => KubeConfig;\n /** Override discovery (for tests). */\n resolveResource?: typeof resolveResource;\n /** Override watcher factory (for tests). */\n createXrWatcher?: typeof createXrWatcher;\n /** Override renderer (for tests). */\n runRenderer?: typeof runRenderer;\n /** Override awaitReady (for tests). */\n awaitReady?: typeof awaitReady;\n /** Destination stream for the renderer. */\n out?: NodeJS.WriteStream;\n /** Signal that aborts both the watcher and renderer. */\n signal?: AbortSignal;\n}\n\nexport type WatchResult = { code: 0 } | { code: 1; error?: string };\n\n/**\n * Headless implementation of the `xplane-utils watch` subcommand.\n * Returns the exit code instead of calling `process.exit` so it is unit-testable.\n */\nexport async function runWatchCommand(\n args: WatchCommandArgs,\n deps: WatchCommandDeps = {},\n): Promise<WatchResult> {\n const load = deps.loadKubeConfig ?? loadKubeConfig;\n const resolve = deps.resolveResource ?? resolveResource;\n const factory = deps.createXrWatcher ?? createXrWatcher;\n const render = deps.runRenderer ?? runRenderer;\n const wait = deps.awaitReady ?? awaitReady;\n\n const kcOpts: LoadKubeConfigOptions = {};\n if (args.kubeconfig !== undefined) kcOpts.kubeconfig = args.kubeconfig;\n if (args.context !== undefined) kcOpts.context = args.context;\n const kc = load(kcOpts);\n\n const parsed = parseTarget(args.target);\n const resolved = await resolve(kc, {\n resource: parsed.resource,\n ...(parsed.group !== undefined ? { group: parsed.group } : {}),\n ...(parsed.version !== undefined ? { version: parsed.version } : {}),\n });\n const ref: XrRef = {\n group: resolved.group,\n version: resolved.version,\n plural: resolved.plural,\n kind: resolved.kind,\n namespaced: resolved.namespaced,\n name: parsed.name,\n ...(args.namespace !== undefined ? { namespace: args.namespace } : {}),\n };\n if (ref.namespaced && !ref.namespace) {\n return { code: 1, error: `${ref.kind} is namespaced — pass --namespace/-n` };\n }\n\n const watcher: XrWatcher = factory({\n kubeConfig: kc,\n ref,\n ...(deps.signal !== undefined ? { signal: deps.signal } : {}),\n ...(args.disableEvents ? { disableEvents: true } : {}),\n });\n\n const mode: RendererMode | undefined =\n args.mode === 'tty' || args.mode === 'ci' ? args.mode : undefined;\n const renderOpts: Parameters<typeof runRenderer>[1] = { ref };\n if (mode) renderOpts.mode = mode;\n if (deps.out) renderOpts.out = deps.out;\n const heartbeatMs = parseDuration(args.heartbeat);\n if (heartbeatMs !== undefined) renderOpts.heartbeatMs = heartbeatMs;\n if (args.showEvents !== undefined) renderOpts.showEvents = args.showEvents;\n if (args.snapshotEveryHeartbeats !== undefined)\n renderOpts.snapshotEveryHeartbeats = args.snapshotEveryHeartbeats;\n const renderPromise = render(watcher, renderOpts);\n\n const timeoutMs = parseDuration(args.timeout);\n try {\n await wait(watcher, timeoutMs !== undefined ? { timeoutMs } : {});\n watcher.stop();\n await renderPromise;\n return { code: 0 };\n } catch (_err) {\n watcher.stop();\n await renderPromise.catch(() => undefined);\n // The renderer already surfaced the error inline — omit it here to avoid duplication.\n return { code: 1 };\n }\n}\n","#!/usr/bin/env node\nimport { createRequire } from 'node:module';\nimport { defineCommand, runMain } from 'citty';\nimport {\n type GetStatusCommandArgs,\n type GetStatusFormat,\n runGetStatusCommand,\n} from './cli/get-status.js';\nimport { runWatchCommand, type WatchCommandArgs } from './cli/watch.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json') as { version: string };\n\nconst watch = defineCommand({\n meta: {\n name: 'watch',\n description: 'Subscribe to a Crossplane XR and block until it becomes Ready',\n },\n args: {\n target: {\n type: 'positional',\n required: true,\n description: 'kubectl-style target: <resource[.group][.version]>/<name>',\n },\n namespace: {\n type: 'string',\n alias: 'n',\n description: 'Namespace (required for namespaced XRs)',\n },\n kubeconfig: { type: 'string', description: 'Path to kubeconfig' },\n context: { type: 'string', description: 'Override the active kubeconfig context' },\n timeout: {\n type: 'string',\n description: 'Maximum time to wait for Ready, e.g. \"30s\", \"5m\", \"1h\"',\n },\n mode: { type: 'string', description: 'Force renderer mode: \"tty\" or \"ci\" (default: auto)' },\n 'no-events': {\n type: 'boolean',\n description: 'Disable subscribing to Kubernetes Events for the XR',\n },\n heartbeat: {\n type: 'string',\n description: 'CI mode: heartbeat interval for liveness lines (default \"30s\", \"0\" to disable)',\n },\n 'show-events': {\n type: 'boolean',\n description: 'CI mode: include Kubernetes Events inline (off by default)',\n },\n 'snapshot-every': {\n type: 'string',\n description:\n 'CI mode: every N idle heartbeats, expand the liveness line into a snapshot of unready + blocked resources (default 10, 0 to disable)',\n },\n },\n async run({ args }) {\n const controller = new AbortController();\n process.on('SIGINT', () => controller.abort());\n process.on('SIGTERM', () => controller.abort());\n\n const cmdArgs: WatchCommandArgs = { target: String(args.target) };\n if (typeof args.namespace === 'string') cmdArgs.namespace = args.namespace;\n if (typeof args.kubeconfig === 'string') cmdArgs.kubeconfig = args.kubeconfig;\n if (typeof args.context === 'string') cmdArgs.context = args.context;\n if (typeof args.timeout === 'string') cmdArgs.timeout = args.timeout;\n if (typeof args.mode === 'string') cmdArgs.mode = args.mode;\n if (args['no-events']) cmdArgs.disableEvents = true;\n if (typeof args.heartbeat === 'string') cmdArgs.heartbeat = args.heartbeat;\n if (args['show-events']) cmdArgs.showEvents = true;\n if (typeof args['snapshot-every'] === 'string') {\n const n = Number.parseInt(args['snapshot-every'], 10);\n if (Number.isFinite(n) && n >= 0) cmdArgs.snapshotEveryHeartbeats = n;\n }\n\n const result = await runWatchCommand(cmdArgs, { signal: controller.signal });\n if (result.code !== 0) {\n if (result.error) process.stderr.write(`${result.error}\\n`);\n process.exit(result.code);\n }\n process.exit(0);\n },\n});\n\nconst getStatus = defineCommand({\n meta: {\n name: 'get-status',\n description: 'Fetch a Crossplane XR and print its .status',\n },\n args: {\n target: {\n type: 'positional',\n required: true,\n description: 'kubectl-style target: <resource[.group][.version]>/<name>',\n },\n namespace: {\n type: 'string',\n alias: 'n',\n description: 'Namespace (required for namespaced XRs)',\n },\n kubeconfig: { type: 'string', description: 'Path to kubeconfig' },\n context: { type: 'string', description: 'Override the active kubeconfig context' },\n format: {\n type: 'string',\n alias: 'o',\n description: 'Output format: \"dot\" (default) or \"json\"',\n },\n compact: {\n type: 'boolean',\n description: 'JSON mode: emit compact (single-line) JSON instead of pretty-printed',\n },\n 'include-xplane': {\n type: 'boolean',\n description: 'Include the framework-managed status.xplane subtree (excluded by default)',\n },\n 'include-conditions': {\n type: 'boolean',\n description: 'Include status.conditions (excluded by default)',\n },\n },\n async run({ args }) {\n const cmdArgs: GetStatusCommandArgs = { target: String(args.target) };\n if (typeof args.namespace === 'string') cmdArgs.namespace = args.namespace;\n if (typeof args.kubeconfig === 'string') cmdArgs.kubeconfig = args.kubeconfig;\n if (typeof args.context === 'string') cmdArgs.context = args.context;\n if (typeof args.format === 'string') {\n if (args.format !== 'dot' && args.format !== 'json') {\n process.stderr.write(`Invalid --format \"${args.format}\" (expected \"dot\" or \"json\")\\n`);\n process.exit(2);\n }\n cmdArgs.format = args.format as GetStatusFormat;\n }\n if (args.compact) cmdArgs.pretty = false;\n if (args['include-xplane']) cmdArgs.includeXplane = true;\n if (args['include-conditions']) cmdArgs.includeConditions = true;\n\n const result = await runGetStatusCommand(cmdArgs);\n if (result.code !== 0) {\n process.stderr.write(`${result.error}\\n`);\n process.exit(result.code);\n }\n process.exit(0);\n },\n});\n\nconst main = defineCommand({\n meta: {\n name: 'xplane-utils',\n version,\n description: 'Utilities for Crossplane compositions built with xplane',\n },\n subCommands: { watch, 'get-status': getStatus },\n});\n\nvoid runMain(main);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli/get-status.ts","../src/cli/duration.ts","../src/cli/watch.ts","../src/cli.ts"],"sourcesContent":["import type { KubeConfig } from '@kubernetes/client-node';\nimport { type LoadKubeConfigOptions, loadKubeConfig } from '../client/kubeconfig.js';\nimport { listXrCollection } from '../client/lists.js';\nimport { parseTarget } from '../watcher/target.js';\nimport type { XrRef } from '../watcher/types.js';\nimport { resolveResource } from './discovery.js';\n\nexport type GetStatusFormat = 'dot' | 'json';\n\nexport interface GetStatusCommandArgs {\n target: string;\n namespace?: string;\n /**\n * Pre-built `KubeConfig`. When supplied, `kubeconfig` and `context` are\n * ignored (and rejected when used together) — the caller owns auth.\n */\n kubeConfig?: KubeConfig;\n kubeconfig?: string;\n context?: string;\n /** Output format. Defaults to \"dot\". */\n format?: GetStatusFormat;\n /** Pretty-print JSON output. Ignored for `dot`. Defaults to true. */\n pretty?: boolean;\n /** Include the framework-managed `status.xplane` subtree. Defaults to false. */\n includeXplane?: boolean;\n /** Include `status.conditions`. Defaults to false. */\n includeConditions?: boolean;\n}\n\nexport interface GetStatusCommandDeps {\n loadKubeConfig?: (opts: LoadKubeConfigOptions) => KubeConfig;\n resolveResource?: typeof resolveResource;\n listXrCollection?: typeof listXrCollection;\n /** Destination stream for the rendered output. */\n out?: NodeJS.WritableStream;\n}\n\nexport type GetStatusResult = { code: 0 } | { code: 1; error: string };\n\n/**\n * Headless implementation of the `xplane-utils get-status` subcommand.\n * Fetches a single XR and prints its `.status` to `out` in the requested format.\n */\nexport async function runGetStatusCommand(\n args: GetStatusCommandArgs,\n deps: GetStatusCommandDeps = {},\n): Promise<GetStatusResult> {\n const load = deps.loadKubeConfig ?? loadKubeConfig;\n const resolve = deps.resolveResource ?? resolveResource;\n const list = deps.listXrCollection ?? listXrCollection;\n const out = deps.out ?? process.stdout;\n\n let kc: KubeConfig;\n if (args.kubeConfig) {\n if (args.kubeconfig !== undefined || args.context !== undefined) {\n return {\n code: 1,\n error: 'pass either kubeConfig or kubeconfig+context, not both',\n };\n }\n kc = args.kubeConfig;\n } else {\n const kcOpts: LoadKubeConfigOptions = {};\n if (args.kubeconfig !== undefined) kcOpts.kubeconfig = args.kubeconfig;\n if (args.context !== undefined) kcOpts.context = args.context;\n kc = load(kcOpts);\n }\n\n const parsed = parseTarget(args.target);\n const resolved = await resolve(kc, {\n resource: parsed.resource,\n ...(parsed.group !== undefined ? { group: parsed.group } : {}),\n ...(parsed.version !== undefined ? { version: parsed.version } : {}),\n });\n const ref: XrRef = {\n group: resolved.group,\n version: resolved.version,\n plural: resolved.plural,\n kind: resolved.kind,\n namespaced: resolved.namespaced,\n name: parsed.name,\n ...(args.namespace !== undefined ? { namespace: args.namespace } : {}),\n };\n if (ref.namespaced && !ref.namespace) {\n return { code: 1, error: `${ref.kind} is namespaced — pass --namespace/-n` };\n }\n\n const result = await list(kc, ref);\n const item = result.items[0] as Record<string, unknown> | undefined;\n if (!item) {\n const target = `${ref.kind}/${ref.name}${ref.namespace ? ` -n ${ref.namespace}` : ''}`;\n return { code: 1, error: `${target} not found` };\n }\n const status = (item.status ?? {}) as Record<string, unknown>;\n const excluded = new Set<string>();\n if (!args.includeXplane) excluded.add('xplane');\n if (!args.includeConditions) excluded.add('conditions');\n const filtered =\n excluded.size === 0\n ? status\n : Object.fromEntries(Object.entries(status).filter(([k]) => !excluded.has(k)));\n\n const format: GetStatusFormat = args.format ?? 'dot';\n const text =\n format === 'json'\n ? JSON.stringify(filtered, null, args.pretty === false ? 0 : 2)\n : toDotLines(filtered).join('\\n');\n out.write(text.length > 0 ? `${text}\\n` : '');\n return { code: 0 };\n}\n\n/**\n * Flatten an arbitrary JSON value into `path=value` lines. Object keys are\n * joined with `.`; array indices use `[n]`. Leaf values are JSON-encoded so\n * strings retain their quoting and special characters are preserved.\n */\nexport function toDotLines(value: unknown, prefix = ''): string[] {\n if (value === undefined) return [];\n if (value === null) return [`${prefix || '.'}=null`];\n if (Array.isArray(value)) {\n if (value.length === 0) return [`${prefix || '.'}=[]`];\n return value.flatMap((v, i) => toDotLines(v, `${prefix}[${i}]`));\n }\n if (typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>);\n if (entries.length === 0) return [`${prefix || '.'}={}`];\n return entries.flatMap(([k, v]) => toDotLines(v, prefix ? `${prefix}.${k}` : k));\n }\n return [`${prefix || '.'}=${JSON.stringify(value)}`];\n}\n","/** Parse a duration like `30s`, `5m`, `2h`, `100ms`, or a bare integer (milliseconds). */\nexport function parseDuration(input: string | undefined): number | undefined {\n if (input === undefined || input === '') return undefined;\n const m = /^(\\d+)(ms|s|m|h)?$/.exec(input);\n if (!m)\n throw new Error(`Invalid duration \"${input}\". Use e.g. \"30s\", \"5m\", \"1h\", or a number of ms.`);\n const n = Number(m[1]);\n switch (m[2]) {\n case undefined:\n case 'ms':\n return n;\n case 's':\n return n * 1000;\n case 'm':\n return n * 60_000;\n case 'h':\n return n * 3_600_000;\n }\n // Unreachable — regex guarantees one of the cases above matches.\n /* c8 ignore next */\n return undefined;\n}\n","import type { KubeConfig } from '@kubernetes/client-node';\nimport { type LoadKubeConfigOptions, loadKubeConfig } from '../client/kubeconfig.js';\nimport { type RendererMode, runRenderer } from '../render/index.js';\nimport { awaitReady } from '../watcher/await-ready.js';\nimport { parseTarget } from '../watcher/target.js';\nimport type { XrRef } from '../watcher/types.js';\nimport { createXrWatcher, type XrWatcher } from '../watcher/xr-watcher.js';\nimport { resolveResource } from './discovery.js';\nimport { parseDuration } from './duration.js';\n\nexport interface WatchCommandArgs {\n target: string;\n namespace?: string;\n /**\n * Pre-built `KubeConfig`. When supplied, `kubeconfig` and `context` are\n * ignored (and rejected when used together) — the caller owns auth.\n */\n kubeConfig?: KubeConfig;\n kubeconfig?: string;\n context?: string;\n timeout?: string;\n mode?: string;\n disableEvents?: boolean;\n /** CI: heartbeat interval (e.g. \"30s\"). 0 disables. */\n heartbeat?: string;\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 rendered output. */\n noColor?: boolean;\n}\n\nexport interface WatchCommandDeps {\n /** Override KubeConfig loader (for tests). */\n loadKubeConfig?: (opts: LoadKubeConfigOptions) => KubeConfig;\n /** Override discovery (for tests). */\n resolveResource?: typeof resolveResource;\n /** Override watcher factory (for tests). */\n createXrWatcher?: typeof createXrWatcher;\n /** Override renderer (for tests). */\n runRenderer?: typeof runRenderer;\n /** Override awaitReady (for tests). */\n awaitReady?: typeof awaitReady;\n /** Destination stream for the renderer. */\n out?: NodeJS.WriteStream;\n /** Signal that aborts both the watcher and renderer. */\n signal?: AbortSignal;\n}\n\nexport type WatchResult = { code: 0 } | { code: 1; error?: string };\n\n/**\n * Headless implementation of the `xplane-utils watch` subcommand.\n * Returns the exit code instead of calling `process.exit` so it is unit-testable.\n */\nexport async function runWatchCommand(\n args: WatchCommandArgs,\n deps: WatchCommandDeps = {},\n): Promise<WatchResult> {\n const load = deps.loadKubeConfig ?? loadKubeConfig;\n const resolve = deps.resolveResource ?? resolveResource;\n const factory = deps.createXrWatcher ?? createXrWatcher;\n const render = deps.runRenderer ?? runRenderer;\n const wait = deps.awaitReady ?? awaitReady;\n\n let kc: KubeConfig;\n if (args.kubeConfig) {\n if (args.kubeconfig !== undefined || args.context !== undefined) {\n return {\n code: 1,\n error: 'pass either kubeConfig or kubeconfig+context, not both',\n };\n }\n kc = args.kubeConfig;\n } else {\n const kcOpts: LoadKubeConfigOptions = {};\n if (args.kubeconfig !== undefined) kcOpts.kubeconfig = args.kubeconfig;\n if (args.context !== undefined) kcOpts.context = args.context;\n kc = load(kcOpts);\n }\n\n const parsed = parseTarget(args.target);\n const resolved = await resolve(kc, {\n resource: parsed.resource,\n ...(parsed.group !== undefined ? { group: parsed.group } : {}),\n ...(parsed.version !== undefined ? { version: parsed.version } : {}),\n });\n const ref: XrRef = {\n group: resolved.group,\n version: resolved.version,\n plural: resolved.plural,\n kind: resolved.kind,\n namespaced: resolved.namespaced,\n name: parsed.name,\n ...(args.namespace !== undefined ? { namespace: args.namespace } : {}),\n };\n if (ref.namespaced && !ref.namespace) {\n return { code: 1, error: `${ref.kind} is namespaced — pass --namespace/-n` };\n }\n\n const watcher: XrWatcher = factory({\n kubeConfig: kc,\n ref,\n ...(deps.signal !== undefined ? { signal: deps.signal } : {}),\n ...(args.disableEvents ? { disableEvents: true } : {}),\n });\n\n const mode: RendererMode | undefined =\n args.mode === 'tty' || args.mode === 'ci' ? args.mode : undefined;\n const renderOpts: Parameters<typeof runRenderer>[1] = { ref };\n if (mode) renderOpts.mode = mode;\n if (deps.out) renderOpts.out = deps.out;\n const heartbeatMs = parseDuration(args.heartbeat);\n if (heartbeatMs !== undefined) renderOpts.heartbeatMs = heartbeatMs;\n if (args.showEvents !== undefined) renderOpts.showEvents = args.showEvents;\n if (args.snapshotEveryHeartbeats !== undefined)\n renderOpts.snapshotEveryHeartbeats = args.snapshotEveryHeartbeats;\n if (args.noColor !== undefined) renderOpts.noColor = args.noColor;\n const renderPromise = render(watcher, renderOpts);\n\n const timeoutMs = parseDuration(args.timeout);\n try {\n await wait(watcher, timeoutMs !== undefined ? { timeoutMs } : {});\n watcher.stop();\n await renderPromise;\n return { code: 0 };\n } catch (_err) {\n watcher.stop();\n await renderPromise.catch(() => undefined);\n // The renderer already surfaced the error inline — omit it here to avoid duplication.\n return { code: 1 };\n }\n}\n","#!/usr/bin/env node\nimport { createRequire } from 'node:module';\nimport { defineCommand, runMain } from 'citty';\nimport {\n type GetStatusCommandArgs,\n type GetStatusFormat,\n runGetStatusCommand,\n} from './cli/get-status.js';\nimport { runWatchCommand, type WatchCommandArgs } from './cli/watch.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json') as { version: string };\n\nconst watch = defineCommand({\n meta: {\n name: 'watch',\n description: 'Subscribe to a Crossplane XR and block until it becomes Ready',\n },\n args: {\n target: {\n type: 'positional',\n required: true,\n description: 'kubectl-style target: <resource[.group][.version]>/<name>',\n },\n namespace: {\n type: 'string',\n alias: 'n',\n description: 'Namespace (required for namespaced XRs)',\n },\n kubeconfig: { type: 'string', description: 'Path to kubeconfig' },\n context: { type: 'string', description: 'Override the active kubeconfig context' },\n timeout: {\n type: 'string',\n description: 'Maximum time to wait for Ready, e.g. \"30s\", \"5m\", \"1h\"',\n },\n mode: { type: 'string', description: 'Force renderer mode: \"tty\" or \"ci\" (default: auto)' },\n 'no-events': {\n type: 'boolean',\n description: 'Disable subscribing to Kubernetes Events for the XR',\n },\n heartbeat: {\n type: 'string',\n description: 'CI mode: heartbeat interval for liveness lines (default \"30s\", \"0\" to disable)',\n },\n 'show-events': {\n type: 'boolean',\n description: 'CI mode: include Kubernetes Events inline (off by default)',\n },\n 'snapshot-every': {\n type: 'string',\n description:\n 'CI mode: every N idle heartbeats, expand the liveness line into a snapshot of unready + blocked resources (default 10, 0 to disable)',\n },\n 'no-color': {\n type: 'boolean',\n description: 'CI mode: strip ANSI colour escapes from rendered output',\n },\n },\n async run({ args }) {\n const controller = new AbortController();\n process.on('SIGINT', () => controller.abort());\n process.on('SIGTERM', () => controller.abort());\n\n const cmdArgs: WatchCommandArgs = { target: String(args.target) };\n if (typeof args.namespace === 'string') cmdArgs.namespace = args.namespace;\n if (typeof args.kubeconfig === 'string') cmdArgs.kubeconfig = args.kubeconfig;\n if (typeof args.context === 'string') cmdArgs.context = args.context;\n if (typeof args.timeout === 'string') cmdArgs.timeout = args.timeout;\n if (typeof args.mode === 'string') cmdArgs.mode = args.mode;\n if (args['no-events']) cmdArgs.disableEvents = true;\n if (typeof args.heartbeat === 'string') cmdArgs.heartbeat = args.heartbeat;\n if (args['show-events']) cmdArgs.showEvents = true;\n if (typeof args['snapshot-every'] === 'string') {\n const n = Number.parseInt(args['snapshot-every'], 10);\n if (Number.isFinite(n) && n >= 0) cmdArgs.snapshotEveryHeartbeats = n;\n }\n if (args['no-color']) cmdArgs.noColor = true;\n\n const result = await runWatchCommand(cmdArgs, { signal: controller.signal });\n if (result.code !== 0) {\n if (result.error) process.stderr.write(`${result.error}\\n`);\n process.exit(result.code);\n }\n process.exit(0);\n },\n});\n\nconst getStatus = defineCommand({\n meta: {\n name: 'get-status',\n description: 'Fetch a Crossplane XR and print its .status',\n },\n args: {\n target: {\n type: 'positional',\n required: true,\n description: 'kubectl-style target: <resource[.group][.version]>/<name>',\n },\n namespace: {\n type: 'string',\n alias: 'n',\n description: 'Namespace (required for namespaced XRs)',\n },\n kubeconfig: { type: 'string', description: 'Path to kubeconfig' },\n context: { type: 'string', description: 'Override the active kubeconfig context' },\n format: {\n type: 'string',\n alias: 'o',\n description: 'Output format: \"dot\" (default) or \"json\"',\n },\n compact: {\n type: 'boolean',\n description: 'JSON mode: emit compact (single-line) JSON instead of pretty-printed',\n },\n 'include-xplane': {\n type: 'boolean',\n description: 'Include the framework-managed status.xplane subtree (excluded by default)',\n },\n 'include-conditions': {\n type: 'boolean',\n description: 'Include status.conditions (excluded by default)',\n },\n },\n async run({ args }) {\n const cmdArgs: GetStatusCommandArgs = { target: String(args.target) };\n if (typeof args.namespace === 'string') cmdArgs.namespace = args.namespace;\n if (typeof args.kubeconfig === 'string') cmdArgs.kubeconfig = args.kubeconfig;\n if (typeof args.context === 'string') cmdArgs.context = args.context;\n if (typeof args.format === 'string') {\n if (args.format !== 'dot' && args.format !== 'json') {\n process.stderr.write(`Invalid --format \"${args.format}\" (expected \"dot\" or \"json\")\\n`);\n process.exit(2);\n }\n cmdArgs.format = args.format as GetStatusFormat;\n }\n if (args.compact) cmdArgs.pretty = false;\n if (args['include-xplane']) cmdArgs.includeXplane = true;\n if (args['include-conditions']) cmdArgs.includeConditions = true;\n\n const result = await runGetStatusCommand(cmdArgs);\n if (result.code !== 0) {\n process.stderr.write(`${result.error}\\n`);\n process.exit(result.code);\n }\n process.exit(0);\n },\n});\n\nconst main = defineCommand({\n meta: {\n name: 'xplane-utils',\n version,\n description: 'Utilities for Crossplane compositions built with xplane',\n },\n subCommands: { watch, 'get-status': getStatus },\n});\n\nvoid runMain(main);\n"],"mappings":"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"}
|
|
@@ -131,5 +131,97 @@ interface XrWatcher extends AsyncIterable<XrEvent> {
|
|
|
131
131
|
*/
|
|
132
132
|
declare function createXrWatcher(opts: CreateXrWatcherOptions): XrWatcher;
|
|
133
133
|
//#endregion
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
//#region src/render/ci.d.ts
|
|
135
|
+
interface CiRendererOptions {
|
|
136
|
+
ref: XrRef;
|
|
137
|
+
/** Destination stream. Defaults to `process.stdout`. */
|
|
138
|
+
out?: NodeJS.WritableStream;
|
|
139
|
+
/** 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. */
|
|
140
|
+
heartbeatMs?: number;
|
|
141
|
+
/** When true, K8s Events are echoed inline. Defaults to false in CI (too noisy). */
|
|
142
|
+
showEvents?: boolean;
|
|
143
|
+
/** Every N consecutive idle heartbeats, expand the heartbeat line into a snapshot of unready + blocked resources. Defaults to 10. Set to 0 to disable. */
|
|
144
|
+
snapshotEveryHeartbeats?: number;
|
|
145
|
+
/**
|
|
146
|
+
* Strip ANSI colour escapes from the rendered output. Useful when piping
|
|
147
|
+
* into log collectors that don't understand colour codes. Defaults to false.
|
|
148
|
+
*/
|
|
149
|
+
noColor?: boolean;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Append-only CI renderer.
|
|
153
|
+
*
|
|
154
|
+
* 1. Print a one-line "watching …" header on startup.
|
|
155
|
+
* 2. On the first snapshot, print a full snapshot block.
|
|
156
|
+
* 3. On every subsequent snapshot, print only the delta.
|
|
157
|
+
* 4. If nothing is printed within `heartbeatMs`, emit a single liveness line.
|
|
158
|
+
*/
|
|
159
|
+
declare function renderCI(watcher: XrWatcher, opts: CiRendererOptions): Promise<void>;
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/render/format.d.ts
|
|
162
|
+
/** Single-character glyph for the status of a tree node. */
|
|
163
|
+
declare function statusGlyph(state: 'ready' | 'pending' | 'blocked'): string;
|
|
164
|
+
/** Compact header line summarising the XR. */
|
|
165
|
+
declare function formatHeader(snapshot: XrSnapshot, ref: {
|
|
166
|
+
kind: string;
|
|
167
|
+
name: string;
|
|
168
|
+
namespace?: string;
|
|
169
|
+
}): string;
|
|
170
|
+
/** Inline progress representation, e.g. `5/12 ready · 3 blocked`. */
|
|
171
|
+
declare function formatProgress(ready: number, total: number, blocked: number): string;
|
|
172
|
+
/** Format a Kubernetes Event as a single line. */
|
|
173
|
+
declare function formatEvent(ev: KubernetesEvent): string;
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/render/tty.d.ts
|
|
176
|
+
interface TtyRendererOptions {
|
|
177
|
+
ref: XrRef;
|
|
178
|
+
/** Destination stream. Defaults to `process.stdout`. */
|
|
179
|
+
out?: NodeJS.WriteStream;
|
|
180
|
+
/** Maximum number of recent Kubernetes events shown in the tail. Defaults to 5. */
|
|
181
|
+
eventTailSize?: number;
|
|
182
|
+
/** Allows callers (and tests) to provide a custom `log-update` instance. */
|
|
183
|
+
logger?: {
|
|
184
|
+
(frame: string): void;
|
|
185
|
+
clear: () => void;
|
|
186
|
+
done: () => void;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Live full-screen renderer using `log-update` to repaint a single frame.
|
|
191
|
+
* Resolves when the watcher ends.
|
|
192
|
+
*/
|
|
193
|
+
declare function renderTTY(watcher: XrWatcher, opts: TtyRendererOptions): Promise<void>;
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/render/index.d.ts
|
|
196
|
+
type RendererMode = 'tty' | 'ci';
|
|
197
|
+
/** Auto-select a renderer based on whether the destination is an interactive TTY. */
|
|
198
|
+
declare function selectRenderer(stream: NodeJS.WriteStream | NodeJS.WritableStream): RendererMode;
|
|
199
|
+
interface RunRendererOptions {
|
|
200
|
+
ref: XrRef;
|
|
201
|
+
/** Forces a renderer instead of auto-detecting. */
|
|
202
|
+
mode?: RendererMode;
|
|
203
|
+
/**
|
|
204
|
+
* Destination stream. Defaults to `process.stdout`.
|
|
205
|
+
* TTY mode requires a `NodeJS.WriteStream` (for `.rows`/`.columns`); pass
|
|
206
|
+
* `mode: 'ci'` explicitly when piping to a plain `WritableStream`.
|
|
207
|
+
*/
|
|
208
|
+
out?: NodeJS.WritableStream;
|
|
209
|
+
/** Max number of recent events kept in the TTY tail. */
|
|
210
|
+
eventTailSize?: number;
|
|
211
|
+
/** CI: heartbeat interval (ms) for liveness lines. 0 disables. */
|
|
212
|
+
heartbeatMs?: number;
|
|
213
|
+
/** CI: include K8s Events inline. Off by default. */
|
|
214
|
+
showEvents?: boolean;
|
|
215
|
+
/** CI: every N idle heartbeats, expand into a snapshot of unready + blocked resources. 0 disables. */
|
|
216
|
+
snapshotEveryHeartbeats?: number;
|
|
217
|
+
/** CI: strip ANSI colour escapes from the rendered output. */
|
|
218
|
+
noColor?: boolean;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Drive either renderer against the supplied watcher. Resolves when the
|
|
222
|
+
* watcher's event stream ends.
|
|
223
|
+
*/
|
|
224
|
+
declare function runRenderer(watcher: XrWatcher, opts: RunRendererOptions): Promise<void>;
|
|
225
|
+
//#endregion
|
|
226
|
+
export { XrSnapshot as C, XrRef as S, EmittedResource as _, TtyRendererOptions as a, XplaneStatus as b, formatHeader as c, CiRendererOptions as d, renderCI as f, BlockedResource as g, createXrWatcher as h, selectRenderer as i, formatProgress as l, XrWatcher as m, RunRendererOptions as n, renderTTY as o, CreateXrWatcherOptions as p, runRenderer as r, formatEvent as s, RendererMode as t, statusGlyph as u, KubernetesEvent as v, XrEvent as x, ResourceRef as y };
|
|
227
|
+
//# sourceMappingURL=index-Dp92t3xP.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Dp92t3xP.d.mts","names":[],"sources":["../src/watcher/types.ts","../src/watcher/xr-watcher.ts","../src/render/ci.ts","../src/render/format.ts","../src/render/tty.ts","../src/render/index.ts"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as XrSnapshot, S as XrRef, _ as EmittedResource, b as XplaneStatus, g as BlockedResource, h as createXrWatcher, m as XrWatcher, n as RunRendererOptions, p as CreateXrWatcherOptions, v as KubernetesEvent, x as XrEvent, y as ResourceRef } from "./index-Dp92t3xP.mjs";
|
|
2
2
|
import { KubeConfig, KubernetesObject } from "@kubernetes/client-node";
|
|
3
3
|
|
|
4
|
+
//#region src/api.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Parse a kubectl-style target string, resolve its CRD against the cluster,
|
|
7
|
+
* and return a fully-populated `XrRef`. Throws if the resolved kind is
|
|
8
|
+
* namespaced and no namespace was supplied.
|
|
9
|
+
*/
|
|
10
|
+
declare function resolveTarget(kc: KubeConfig, target: string, namespace?: string): Promise<XrRef>;
|
|
11
|
+
interface GetStatusOptions {
|
|
12
|
+
/** Include the framework-managed `status.xplane` subtree. Defaults to false. */
|
|
13
|
+
includeXplane?: boolean;
|
|
14
|
+
/** Include `status.conditions`. Defaults to false. */
|
|
15
|
+
includeConditions?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Fetch a single XR and return its filtered `.status` object. Throws when the
|
|
19
|
+
* XR cannot be found.
|
|
20
|
+
*/
|
|
21
|
+
declare function getStatus(kc: KubeConfig, ref: XrRef, opts?: GetStatusOptions): Promise<Record<string, unknown>>;
|
|
22
|
+
interface WatchUntilReadyOptions {
|
|
23
|
+
kubeConfig: KubeConfig;
|
|
24
|
+
ref: XrRef;
|
|
25
|
+
/** Aborts the underlying watcher and renderer. */
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
/** Maximum time to wait for Ready before rejecting. */
|
|
28
|
+
timeoutMs?: number;
|
|
29
|
+
/** Disable subscribing to Kubernetes Events for the XR. */
|
|
30
|
+
disableEvents?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Renderer configuration. Pass `false` to skip rendering entirely (silent
|
|
33
|
+
* mode). When omitted, the default renderer runs against `process.stdout`.
|
|
34
|
+
*/
|
|
35
|
+
renderer?: Omit<RunRendererOptions, 'ref'> | false;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One-shot watch-and-wait: builds an `XrWatcher`, optionally drives a renderer
|
|
39
|
+
* against it, awaits the first Ready snapshot (with optional timeout), and
|
|
40
|
+
* guarantees cleanup of the watcher + renderer in both success and failure
|
|
41
|
+
* paths.
|
|
42
|
+
*
|
|
43
|
+
* Returns the snapshot at the moment of readiness.
|
|
44
|
+
*/
|
|
45
|
+
declare function watchUntilReady(opts: WatchUntilReadyOptions): Promise<XrSnapshot>;
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/cli/discovery.d.ts
|
|
48
|
+
/** Resolved API resource metadata. */
|
|
49
|
+
interface ResolvedResource {
|
|
50
|
+
group: string;
|
|
51
|
+
version: string;
|
|
52
|
+
kind: string;
|
|
53
|
+
plural: string;
|
|
54
|
+
namespaced: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a `<resource>[.group][.version]` user hint to a single CRD-backed
|
|
58
|
+
* resource. Throws when nothing matches or when the hint is ambiguous.
|
|
59
|
+
*/
|
|
60
|
+
declare function resolveResource(kc: KubeConfig, hint: {
|
|
61
|
+
resource: string;
|
|
62
|
+
group?: string;
|
|
63
|
+
version?: string;
|
|
64
|
+
}): Promise<ResolvedResource>;
|
|
65
|
+
//#endregion
|
|
4
66
|
//#region src/client/kubeconfig.d.ts
|
|
5
67
|
interface LoadKubeConfigOptions {
|
|
6
68
|
/** Explicit kubeconfig file path. Falls back to `KUBECONFIG` / default discovery. */
|
|
@@ -115,5 +177,5 @@ interface ResourceTree {
|
|
|
115
177
|
/** Build a `ResourceTree` from a snapshot, preferring `status.xplane` when present. */
|
|
116
178
|
declare function buildTree(snapshot: XrSnapshot): ResourceTree;
|
|
117
179
|
//#endregion
|
|
118
|
-
export { type AwaitReadyOptions, type BlockedResource, type CreateXrWatcherOptions, type EmittedResource, type KubernetesEvent, type LoadKubeConfigOptions, type ParsedTarget, type ResourceRef, type ResourceTree, type TreeNode, type TreeStats, type XplaneStatus, type XrEvent, type XrRef, type XrSnapshot, type XrWatcher, awaitReady, buildSnapshot, buildTree, createXrWatcher, loadKubeConfig, parseTarget };
|
|
180
|
+
export { type AwaitReadyOptions, type BlockedResource, type CreateXrWatcherOptions, type EmittedResource, type GetStatusOptions, type KubernetesEvent, type LoadKubeConfigOptions, type ParsedTarget, type ResolvedResource, type ResourceRef, type ResourceTree, type TreeNode, type TreeStats, type WatchUntilReadyOptions, type XplaneStatus, type XrEvent, type XrRef, type XrSnapshot, type XrWatcher, awaitReady, buildSnapshot, buildTree, createXrWatcher, getStatus, loadKubeConfig, parseTarget, resolveResource, resolveTarget, watchUntilReady };
|
|
119
181
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/client/kubeconfig.ts","../src/watcher/await-ready.ts","../src/watcher/readiness.ts","../src/watcher/target.ts","../src/watcher/tree.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/api.ts","../src/cli/discovery.ts","../src/client/kubeconfig.ts","../src/watcher/await-ready.ts","../src/watcher/readiness.ts","../src/watcher/target.ts","../src/watcher/tree.ts"],"mappings":";;;;;AAcA;;;;iBAAsB,aAAA,CACpB,EAAA,EAAI,UAAA,EACJ,MAAA,UACA,SAAA,YACC,OAAA,CAAQ,KAAA;AAAA,UAsBM,gBAAA;EAtBP;EAwBR,aAAA;EA3BI;EA6BJ,iBAAiB;AAAA;;;;;iBAOG,SAAA,CACpB,EAAA,EAAI,UAAA,EACJ,GAAA,EAAK,KAAA,EACL,IAAA,GAAM,gBAAA,GACL,OAAA,CAAQ,MAAA;AAAA,UAeM,sBAAA;EACf,UAAA,EAAY,UAAA;EACZ,GAAA,EAAK,KAAA;EA9BL;EAgCA,MAAA,GAAS,WAAA;EAvBW;EAyBpB,SAAA;;EAEA,aAAA;EAzBK;;;;EA8BL,QAAA,GAAW,IAAA,CAAK,kBAAA;AAAA;;;;;;;;;iBAWI,eAAA,CAAgB,IAAA,EAAM,sBAAA,GAAyB,OAAA,CAAQ,UAAA;;;;UC3F5D,gBAAA;EACf,KAAA;EACA,OAAA;EACA,IAAA;EACA,MAAA;EACA,UAAA;AAAA;;;;;iBA+CoB,eAAA,CACpB,EAAA,EAAI,UAAA,EACJ,IAAA;EAAQ,QAAA;EAAkB,KAAA;EAAgB,OAAA;AAAA,IACzC,OAAA,CAAQ,gBAAA;;;UCxDM,qBAAA;;EAEf,UAAA;EFUoB;EERpB,OAAO;AAAA;;;;;;iBAQO,cAAA,CAAe,IAAA,GAAM,qBAAA,GAA6B,UAAU;;;UCX3D,iBAAA;;EAEf,SAAS;AAAA;;;;;;;;;;;;;iBAeW,UAAA,CACpB,OAAA,EAAS,SAAA,EACT,IAAA,GAAM,iBAAA,GACL,OAAA,CAAQ,UAAA;;;;;AHTX;;iBIKgB,aAAA,CAAc,MAAA,EAAQ,gBAAA,GAAmB,UAAU;;;;;;;AJLnE;;;;;;;UKHiB,YAAA;ELIX;EKFJ,QAAA;ELGA;EKDA,KAAA;ELGC;EKDD,OAAA;ELCc;EKCd,IAAA;AAAA;AAAA,iBAGc,WAAA,CAAY,KAAA,WAAgB,YAAY;;;;;;ALRxD;;;;UMLiB,QAAA;ENSd;EMPD,KAAA;ENOQ;EMLR,IAAA;ENEA;EMAA,IAAA;ENEA;EMAA,SAAA;ENCS;EMCT,KAAA;ENDc;EMGd,OAAA;ENmB+B;EMjB/B,UAAA;ENmBA;EMjBA,UAAA;EN0BoB;EMxBpB,IAAA;;EAEA,QAAA,EAAU,QAAQ;AAAA;;UAIH,SAAA;ENsBd;EMpBD,KAAA;ENoBQ;EMlBR,KAAA;ENeA;EMbA,OAAA;AAAA;AAAA,UAGe,YAAA;ENYf;EMVA,KAAA,EAAO,QAAA;ENWE;EMTT,KAAA,EAAO,SAAS;ENSD;EMPf,MAAA;AAAA;;iBAIc,SAAA,CAAU,QAAA,EAAU,UAAA,GAAa,YAAY"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,80 @@
|
|
|
1
|
-
import { a as awaitReady, i as
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { a as awaitReady, i as parseTarget, n as createXrWatcher, o as listXrCollection, r as buildSnapshot, s as resolveResource, t as loadKubeConfig } from "./kubeconfig-BO2X-qXU.mjs";
|
|
2
|
+
import { i as buildTree, t as runRenderer } from "./render-BMhfzOc2.mjs";
|
|
3
|
+
//#region src/api.ts
|
|
4
|
+
/**
|
|
5
|
+
* Parse a kubectl-style target string, resolve its CRD against the cluster,
|
|
6
|
+
* and return a fully-populated `XrRef`. Throws if the resolved kind is
|
|
7
|
+
* namespaced and no namespace was supplied.
|
|
8
|
+
*/
|
|
9
|
+
async function resolveTarget(kc, target, namespace) {
|
|
10
|
+
const parsed = parseTarget(target);
|
|
11
|
+
const resolved = await resolveResource(kc, {
|
|
12
|
+
resource: parsed.resource,
|
|
13
|
+
group: parsed.group,
|
|
14
|
+
version: parsed.version
|
|
15
|
+
});
|
|
16
|
+
const ref = {
|
|
17
|
+
group: resolved.group,
|
|
18
|
+
version: resolved.version,
|
|
19
|
+
plural: resolved.plural,
|
|
20
|
+
kind: resolved.kind,
|
|
21
|
+
namespaced: resolved.namespaced,
|
|
22
|
+
name: parsed.name,
|
|
23
|
+
namespace
|
|
24
|
+
};
|
|
25
|
+
if (ref.namespaced && !ref.namespace) throw new Error(`${ref.kind} is namespaced — pass a namespace`);
|
|
26
|
+
return ref;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Fetch a single XR and return its filtered `.status` object. Throws when the
|
|
30
|
+
* XR cannot be found.
|
|
31
|
+
*/
|
|
32
|
+
async function getStatus(kc, ref, opts = {}) {
|
|
33
|
+
const item = (await listXrCollection(kc, ref)).items[0];
|
|
34
|
+
if (!item) {
|
|
35
|
+
const t = `${ref.kind}/${ref.name}${ref.namespace ? ` -n ${ref.namespace}` : ""}`;
|
|
36
|
+
throw new Error(`${t} not found`);
|
|
37
|
+
}
|
|
38
|
+
const status = item.status ?? {};
|
|
39
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
40
|
+
if (!opts.includeXplane) excluded.add("xplane");
|
|
41
|
+
if (!opts.includeConditions) excluded.add("conditions");
|
|
42
|
+
if (excluded.size === 0) return status;
|
|
43
|
+
return Object.fromEntries(Object.entries(status).filter(([k]) => !excluded.has(k)));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* One-shot watch-and-wait: builds an `XrWatcher`, optionally drives a renderer
|
|
47
|
+
* against it, awaits the first Ready snapshot (with optional timeout), and
|
|
48
|
+
* guarantees cleanup of the watcher + renderer in both success and failure
|
|
49
|
+
* paths.
|
|
50
|
+
*
|
|
51
|
+
* Returns the snapshot at the moment of readiness.
|
|
52
|
+
*/
|
|
53
|
+
async function watchUntilReady(opts) {
|
|
54
|
+
const watcher = createXrWatcher({
|
|
55
|
+
kubeConfig: opts.kubeConfig,
|
|
56
|
+
ref: opts.ref,
|
|
57
|
+
signal: opts.signal,
|
|
58
|
+
disableEvents: opts.disableEvents
|
|
59
|
+
});
|
|
60
|
+
const renderPromise = opts.renderer === false ? Promise.resolve() : runRenderer(watcher, {
|
|
61
|
+
ref: opts.ref,
|
|
62
|
+
...opts.renderer
|
|
63
|
+
});
|
|
64
|
+
const waitOpts = {};
|
|
65
|
+
if (opts.timeoutMs !== void 0) waitOpts.timeoutMs = opts.timeoutMs;
|
|
66
|
+
try {
|
|
67
|
+
const snapshot = await awaitReady(watcher, waitOpts);
|
|
68
|
+
watcher.stop();
|
|
69
|
+
await renderPromise;
|
|
70
|
+
return snapshot;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
watcher.stop();
|
|
73
|
+
await renderPromise.catch(() => void 0);
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { awaitReady, buildSnapshot, buildTree, createXrWatcher, getStatus, loadKubeConfig, parseTarget, resolveResource, resolveTarget, watchUntilReady };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/api.ts"],"sourcesContent":["import type { KubeConfig } from '@kubernetes/client-node';\nimport { resolveResource } from './cli/discovery.js';\nimport { listXrCollection } from './client/lists.js';\nimport { type RunRendererOptions, runRenderer } from './render/index.js';\nimport { type AwaitReadyOptions, awaitReady } from './watcher/await-ready.js';\nimport { parseTarget } from './watcher/target.js';\nimport type { XrRef, XrSnapshot } from './watcher/types.js';\nimport { createXrWatcher } from './watcher/xr-watcher.js';\n\n/**\n * Parse a kubectl-style target string, resolve its CRD against the cluster,\n * and return a fully-populated `XrRef`. Throws if the resolved kind is\n * namespaced and no namespace was supplied.\n */\nexport async function resolveTarget(\n kc: KubeConfig,\n target: string,\n namespace?: string,\n): Promise<XrRef> {\n const parsed = parseTarget(target);\n const resolved = await resolveResource(kc, {\n resource: parsed.resource,\n group: parsed.group,\n version: parsed.version,\n });\n const ref: XrRef = {\n group: resolved.group,\n version: resolved.version,\n plural: resolved.plural,\n kind: resolved.kind,\n namespaced: resolved.namespaced,\n name: parsed.name,\n namespace,\n };\n if (ref.namespaced && !ref.namespace) {\n throw new Error(`${ref.kind} is namespaced — pass a namespace`);\n }\n return ref;\n}\n\nexport interface GetStatusOptions {\n /** Include the framework-managed `status.xplane` subtree. Defaults to false. */\n includeXplane?: boolean;\n /** Include `status.conditions`. Defaults to false. */\n includeConditions?: boolean;\n}\n\n/**\n * Fetch a single XR and return its filtered `.status` object. Throws when the\n * XR cannot be found.\n */\nexport async function getStatus(\n kc: KubeConfig,\n ref: XrRef,\n opts: GetStatusOptions = {},\n): Promise<Record<string, unknown>> {\n const result = await listXrCollection(kc, ref);\n const item = result.items[0] as Record<string, unknown> | undefined;\n if (!item) {\n const t = `${ref.kind}/${ref.name}${ref.namespace ? ` -n ${ref.namespace}` : ''}`;\n throw new Error(`${t} not found`);\n }\n const status = (item.status ?? {}) as Record<string, unknown>;\n const excluded = new Set<string>();\n if (!opts.includeXplane) excluded.add('xplane');\n if (!opts.includeConditions) excluded.add('conditions');\n if (excluded.size === 0) return status;\n return Object.fromEntries(Object.entries(status).filter(([k]) => !excluded.has(k)));\n}\n\nexport interface WatchUntilReadyOptions {\n kubeConfig: KubeConfig;\n ref: XrRef;\n /** Aborts the underlying watcher and renderer. */\n signal?: AbortSignal;\n /** Maximum time to wait for Ready before rejecting. */\n timeoutMs?: number;\n /** Disable subscribing to Kubernetes Events for the XR. */\n disableEvents?: boolean;\n /**\n * Renderer configuration. Pass `false` to skip rendering entirely (silent\n * mode). When omitted, the default renderer runs against `process.stdout`.\n */\n renderer?: Omit<RunRendererOptions, 'ref'> | false;\n}\n\n/**\n * One-shot watch-and-wait: builds an `XrWatcher`, optionally drives a renderer\n * against it, awaits the first Ready snapshot (with optional timeout), and\n * guarantees cleanup of the watcher + renderer in both success and failure\n * paths.\n *\n * Returns the snapshot at the moment of readiness.\n */\nexport async function watchUntilReady(opts: WatchUntilReadyOptions): Promise<XrSnapshot> {\n const watcher = createXrWatcher({\n kubeConfig: opts.kubeConfig,\n ref: opts.ref,\n signal: opts.signal,\n disableEvents: opts.disableEvents,\n });\n const renderPromise: Promise<void> =\n opts.renderer === false\n ? Promise.resolve()\n : runRenderer(watcher, { ref: opts.ref, ...opts.renderer });\n const waitOpts: AwaitReadyOptions = {};\n if (opts.timeoutMs !== undefined) waitOpts.timeoutMs = opts.timeoutMs;\n try {\n const snapshot = await awaitReady(watcher, waitOpts);\n watcher.stop();\n await renderPromise;\n return snapshot;\n } catch (err) {\n watcher.stop();\n await renderPromise.catch(() => undefined);\n throw err;\n }\n}\n"],"mappings":";;;;;;;;AAcA,eAAsB,cACpB,IACA,QACA,WACgB;CAChB,MAAM,SAAS,YAAY,MAAM;CACjC,MAAM,WAAW,MAAM,gBAAgB,IAAI;EACzC,UAAU,OAAO;EACjB,OAAO,OAAO;EACd,SAAS,OAAO;CAClB,CAAC;CACD,MAAM,MAAa;EACjB,OAAO,SAAS;EAChB,SAAS,SAAS;EAClB,QAAQ,SAAS;EACjB,MAAM,SAAS;EACf,YAAY,SAAS;EACrB,MAAM,OAAO;EACb;CACF;CACA,IAAI,IAAI,cAAc,CAAC,IAAI,WACzB,MAAM,IAAI,MAAM,GAAG,IAAI,KAAK,kCAAkC;CAEhE,OAAO;AACT;;;;;AAaA,eAAsB,UACpB,IACA,KACA,OAAyB,CAAC,GACQ;CAElC,MAAM,QAAO,MADQ,iBAAiB,IAAI,GAAG,GACzB,MAAM;CAC1B,IAAI,CAAC,MAAM;EACT,MAAM,IAAI,GAAG,IAAI,KAAK,GAAG,IAAI,OAAO,IAAI,YAAY,OAAO,IAAI,cAAc;EAC7E,MAAM,IAAI,MAAM,GAAG,EAAE,WAAW;CAClC;CACA,MAAM,SAAU,KAAK,UAAU,CAAC;CAChC,MAAM,2BAAW,IAAI,IAAY;CACjC,IAAI,CAAC,KAAK,eAAe,SAAS,IAAI,QAAQ;CAC9C,IAAI,CAAC,KAAK,mBAAmB,SAAS,IAAI,YAAY;CACtD,IAAI,SAAS,SAAS,GAAG,OAAO;CAChC,OAAO,OAAO,YAAY,OAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;AACpF;;;;;;;;;AA0BA,eAAsB,gBAAgB,MAAmD;CACvF,MAAM,UAAU,gBAAgB;EAC9B,YAAY,KAAK;EACjB,KAAK,KAAK;EACV,QAAQ,KAAK;EACb,eAAe,KAAK;CACtB,CAAC;CACD,MAAM,gBACJ,KAAK,aAAa,QACd,QAAQ,QAAQ,IAChB,YAAY,SAAS;EAAE,KAAK,KAAK;EAAK,GAAG,KAAK;CAAS,CAAC;CAC9D,MAAM,WAA8B,CAAC;CACrC,IAAI,KAAK,cAAc,KAAA,GAAW,SAAS,YAAY,KAAK;CAC5D,IAAI;EACF,MAAM,WAAW,MAAM,WAAW,SAAS,QAAQ;EACnD,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;CACT,SAAS,KAAK;EACZ,QAAQ,KAAK;EACb,MAAM,cAAc,YAAY,KAAA,CAAS;EACzC,MAAM;CACR;AACF"}
|