@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 CHANGED
@@ -1,96 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { a as awaitReady, n as listXrCollection, o as loadKubeConfig, r as parseTarget, t as createXrWatcher } from "./xr-watcher-1etyvp-6.mjs";
3
- import { t as runRenderer } from "./render-Cnhpyf1X.mjs";
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
- const kcOpts = {};
105
- if (args.kubeconfig !== void 0) kcOpts.kubeconfig = args.kubeconfig;
106
- if (args.context !== void 0) kcOpts.context = args.context;
107
- const kc = load(kcOpts);
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
- const kcOpts = {};
189
- if (args.kubeconfig !== void 0) kcOpts.kubeconfig = args.kubeconfig;
190
- if (args.context !== void 0) kcOpts.context = args.context;
191
- const kc = load(kcOpts);
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
- export { EmittedResource as a, XplaneStatus as c, XrSnapshot as d, BlockedResource as i, XrEvent as l, XrWatcher as n, KubernetesEvent as o, createXrWatcher as r, ResourceRef as s, CreateXrWatcherOptions as t, XrRef as u };
135
- //# sourceMappingURL=xr-watcher-EiWHVp3o.d.mts.map
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 { a as EmittedResource, c as XplaneStatus, d as XrSnapshot, i as BlockedResource, l as XrEvent, n as XrWatcher, o as KubernetesEvent, r as createXrWatcher, s as ResourceRef, t as CreateXrWatcherOptions, u as XrRef } from "./xr-watcher-EiWHVp3o.mjs";
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
@@ -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":";;;;UAEiB,qBAAA;;EAEf,UAAA;EAFe;EAIf,OAAO;AAAA;;AAAA;AAQT;;;iBAAgB,cAAA,CAAe,IAAA,GAAM,qBAAA,GAA6B,UAAU;;;UCX3D,iBAAA;;EAEf,SAAS;AAAA;;;ADCF;AAQT;;;;;;;;AAA4E;iBCMtD,UAAA,CACpB,OAAA,EAAS,SAAA,EACT,IAAA,GAAM,iBAAA,GACL,OAAA,CAAQ,UAAA;;;;;ADrBX;;iBEiBgB,aAAA,CAAc,MAAA,EAAQ,gBAAA,GAAmB,UAAU;;;;;;;AFjBnE;;;;AAIS;AAQT;;UGHiB,YAAA;EHG2D;EGD1E,QAAA;EHC6B;EGC7B,KAAA;EHD0E;EGG1E,OAAA;;EAEA,IAAA;AAAA;AAAA,iBAGc,WAAA,CAAY,KAAA,WAAgB,YAAY;;;;;;AHpBxD;;;;UIOiB,QAAA;EJKD;EIHd,KAAA;;EAEA,IAAA;EJCmC;EICnC,IAAA;EJDgE;EIGhE,SAAA;EJH0E;EIK1E,KAAA;;EAEA,OAAA;EHlBe;EGoBf,UAAA;;EAEA,UAAA;EHpBS;EGsBT,IAAA;EHP8B;EGS9B,QAAA,EAAU,QAAQ;AAAA;;UAIH,SAAA;EHVd;EGYD,KAAA;EHZQ;EGcR,KAAA;EHhBA;EGkBA,OAAA;AAAA;AAAA,UAGe,YAAA;EHnBN;EGqBT,KAAA,EAAO,QAAA;EHrBY;EGuBnB,KAAA,EAAO,SAAS;;EAEhB,MAAA;AAAA;;iBAIc,SAAA,CAAU,QAAA,EAAU,UAAA,GAAa,YAAY"}
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 buildSnapshot, o as loadKubeConfig, r as parseTarget, t as createXrWatcher } from "./xr-watcher-1etyvp-6.mjs";
2
- import { t as buildTree } from "./tree-DaHkojq8.mjs";
3
- export { awaitReady, buildSnapshot, buildTree, createXrWatcher, loadKubeConfig, parseTarget };
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"}