@xplane/utils 1.3.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.
@@ -1,16 +1,123 @@
1
- import { CoreV1Api, CustomObjectsApi, KubeConfig, Watch } from "@kubernetes/client-node";
2
- //#region src/client/kubeconfig.ts
1
+ import { ApiextensionsV1Api, CoreV1Api, CustomObjectsApi, KubeConfig, Watch } from "@kubernetes/client-node";
2
+ //#region src/cli/discovery.ts
3
+ let crdCache;
3
4
  /**
4
- * Load a `KubeConfig` from disk using `client-node`'s default rules (with
5
- * optional explicit overrides). The returned config has its current context
6
- * applied.
5
+ * Fetch the cluster's CRDs and project them into a flat list of resolved
6
+ * resources (one entry per served version). Cached per `KubeConfig` instance.
7
7
  */
8
- function loadKubeConfig(opts = {}) {
9
- const kc = new KubeConfig();
10
- if (opts.kubeconfig) kc.loadFromFile(opts.kubeconfig);
11
- else kc.loadFromDefault();
12
- if (opts.context) kc.setCurrentContext(opts.context);
13
- return kc;
8
+ async function listCrdResources(kc) {
9
+ crdCache ??= /* @__PURE__ */ new WeakMap();
10
+ const cached = crdCache.get(kc);
11
+ if (cached) return cached;
12
+ const promise = fetchCrdResources(kc).catch((err) => {
13
+ crdCache?.delete(kc);
14
+ throw err;
15
+ });
16
+ crdCache.set(kc, promise);
17
+ return promise;
18
+ }
19
+ async function fetchCrdResources(kc) {
20
+ const list = await kc.makeApiClient(ApiextensionsV1Api).listCustomResourceDefinition();
21
+ const out = [];
22
+ for (const item of list.items ?? []) {
23
+ const spec = item.spec;
24
+ if (!spec?.group || !spec.names?.kind || !spec.names.plural) continue;
25
+ const namespaced = spec.scope === "Namespaced";
26
+ for (const v of spec.versions ?? []) {
27
+ if (!v.name || v.served === false) continue;
28
+ out.push({
29
+ group: spec.group,
30
+ version: v.name,
31
+ kind: spec.names.kind,
32
+ plural: spec.names.plural,
33
+ namespaced
34
+ });
35
+ }
36
+ }
37
+ return out;
38
+ }
39
+ /**
40
+ * Resolve a `<resource>[.group][.version]` user hint to a single CRD-backed
41
+ * resource. Throws when nothing matches or when the hint is ambiguous.
42
+ */
43
+ async function resolveResource(kc, hint) {
44
+ const all = await listCrdResources(kc);
45
+ const r = hint.resource.toLowerCase();
46
+ const matches = all.filter((c) => {
47
+ const kindLc = c.kind.toLowerCase();
48
+ const pluralLc = c.plural.toLowerCase();
49
+ if (kindLc !== r && pluralLc !== r) return false;
50
+ if (hint.group !== void 0 && c.group !== hint.group) return false;
51
+ if (hint.version !== void 0 && c.version !== hint.version) return false;
52
+ return true;
53
+ });
54
+ if (matches.length === 0) {
55
+ const detail = [
56
+ hint.resource,
57
+ hint.group,
58
+ hint.version
59
+ ].filter(Boolean).join(".");
60
+ throw new Error(`No CRD found matching "${detail}". Available kinds: ${summarise(all)}.`);
61
+ }
62
+ if (matches.length > 1) {
63
+ if (hint.version === void 0) {
64
+ const grouped = /* @__PURE__ */ new Map();
65
+ for (const m of matches) grouped.set(`${m.group}/${m.kind}`, [...grouped.get(`${m.group}/${m.kind}`) ?? [], m]);
66
+ if (grouped.size === 1) return [...matches].sort((a, b) => b.version.localeCompare(a.version))[0];
67
+ }
68
+ const candidates = matches.map((m) => `${m.plural}.${m.version}.${m.group}`).join(", ");
69
+ throw new Error(`Ambiguous resource hint "${hint.resource}". Candidates: ${candidates}. Disambiguate with .group or .version.group.`);
70
+ }
71
+ return matches[0];
72
+ }
73
+ function summarise(all) {
74
+ const seen = /* @__PURE__ */ new Set();
75
+ const out = [];
76
+ for (const r of all) {
77
+ const k = `${r.plural}.${r.group}`;
78
+ if (seen.has(k)) continue;
79
+ seen.add(k);
80
+ out.push(k);
81
+ if (out.length >= 20) {
82
+ out.push("…");
83
+ break;
84
+ }
85
+ }
86
+ return out.join(", ");
87
+ }
88
+ //#endregion
89
+ //#region src/client/lists.ts
90
+ /** Initial-list for a single XR via `CustomObjectsApi`, filtered by name. */
91
+ async function listXrCollection(kc, ref) {
92
+ const api = kc.makeApiClient(CustomObjectsApi);
93
+ const fieldSelector = `metadata.name=${ref.name}`;
94
+ const res = await (ref.namespaced && ref.namespace ? api.listNamespacedCustomObject({
95
+ group: ref.group,
96
+ version: ref.version,
97
+ namespace: ref.namespace,
98
+ plural: ref.plural,
99
+ fieldSelector
100
+ }) : api.listClusterCustomObject({
101
+ group: ref.group,
102
+ version: ref.version,
103
+ plural: ref.plural,
104
+ fieldSelector
105
+ }));
106
+ return {
107
+ resourceVersion: res.metadata?.resourceVersion ?? "",
108
+ items: res.items ?? []
109
+ };
110
+ }
111
+ /** Initial-list of Kubernetes Events scoped to a namespace + field selector. */
112
+ async function listXrEvents(kc, namespace, fieldSelector) {
113
+ const res = await kc.makeApiClient(CoreV1Api).listNamespacedEvent({
114
+ namespace,
115
+ fieldSelector
116
+ });
117
+ return {
118
+ resourceVersion: res.metadata?.resourceVersion ?? "",
119
+ items: res.items ?? []
120
+ };
14
121
  }
15
122
  //#endregion
16
123
  //#region src/watcher/await-ready.ts
@@ -39,106 +146,6 @@ async function awaitReady(watcher, opts = {}) {
39
146
  }
40
147
  }
41
148
  //#endregion
42
- //#region src/watcher/readiness.ts
43
- const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
44
- const asString = (v) => typeof v === "string" ? v : void 0;
45
- /**
46
- * Build an `XrSnapshot` from a raw Kubernetes object. Parses the `Ready` condition,
47
- * the optional `status.xplane` payload and `status.resourceRefs`.
48
- */
49
- function buildSnapshot(object) {
50
- const status = isRecord(object.status) ? object.status : void 0;
51
- const conditions = [];
52
- if (status && Array.isArray(status.conditions)) {
53
- for (const c of status.conditions) if (isRecord(c)) conditions.push({
54
- type: asString(c.type),
55
- status: asString(c.status),
56
- reason: asString(c.reason),
57
- message: asString(c.message)
58
- });
59
- }
60
- const ready = conditions.find((c) => c.type === "Ready");
61
- const responsive = conditions.find((c) => c.type === "Responsive");
62
- const synced = conditions.find((c) => c.type === "Synced");
63
- const snapshot = {
64
- object,
65
- ready: ready?.status === "True",
66
- resourceRefs: parseResourceRefs(status)
67
- };
68
- if (ready?.reason !== void 0) snapshot.readyReason = ready.reason;
69
- if (ready?.message !== void 0) snapshot.readyMessage = ready.message;
70
- if (responsive?.status === "False" && responsive.reason === "WatchCircuitOpen") snapshot.updatesThrottled = true;
71
- if (synced?.status === "False" && synced.reason === "ReconcileError") snapshot.syncError = {
72
- reason: synced.reason,
73
- message: synced.message ?? ""
74
- };
75
- const xplane = parseXplane(status);
76
- if (xplane) snapshot.xplane = xplane;
77
- return snapshot;
78
- }
79
- function parseResourceRefs(status) {
80
- const out = [];
81
- if (!status) return out;
82
- const refs = status.resourceRefs;
83
- if (!Array.isArray(refs)) return out;
84
- for (const r of refs) {
85
- if (!isRecord(r)) continue;
86
- const apiVersion = asString(r.apiVersion) ?? "";
87
- const kind = asString(r.kind) ?? "";
88
- const name = asString(r.name) ?? "";
89
- if (name) out.push({
90
- apiVersion,
91
- kind,
92
- name
93
- });
94
- }
95
- return out;
96
- }
97
- function parseXplane(status) {
98
- if (!status || !isRecord(status.xplane)) return void 0;
99
- const x = status.xplane;
100
- const emitted = [];
101
- if (Array.isArray(x.emittedResources)) for (const r of x.emittedResources) {
102
- if (!isRecord(r)) continue;
103
- const nodePath = asString(r.nodePath);
104
- if (!nodePath) continue;
105
- const name = asString(r.name);
106
- const namespace = asString(r.namespace);
107
- emitted.push({
108
- apiVersion: asString(r.apiVersion) ?? "",
109
- kind: asString(r.kind) ?? "",
110
- nodePath,
111
- ...name ? { name } : {},
112
- ...namespace ? { namespace } : {},
113
- ready: r.ready === true
114
- });
115
- }
116
- const blocked = [];
117
- if (Array.isArray(x.blockedResources)) for (const r of x.blockedResources) {
118
- if (!isRecord(r)) continue;
119
- const nodePath = asString(r.nodePath);
120
- if (!nodePath) continue;
121
- const name = asString(r.name);
122
- const namespace = asString(r.namespace);
123
- const entry = {
124
- apiVersion: asString(r.apiVersion) ?? "",
125
- kind: asString(r.kind) ?? "",
126
- nodePath,
127
- ...name ? { name } : {},
128
- ...namespace ? { namespace } : {}
129
- };
130
- if (Array.isArray(r.waitingFor)) {
131
- const wf = r.waitingFor.filter((s) => typeof s === "string");
132
- if (wf.length > 0) entry.waitingFor = wf;
133
- }
134
- blocked.push(entry);
135
- }
136
- return {
137
- emittedResources: emitted,
138
- blockedResources: blocked
139
- };
140
- }
141
- //#endregion
142
149
  //#region src/watcher/target.ts
143
150
  function parseTarget(input) {
144
151
  const slash = input.indexOf("/");
@@ -170,40 +177,6 @@ function parseTarget(input) {
170
177
  };
171
178
  }
172
179
  //#endregion
173
- //#region src/client/lists.ts
174
- /** Initial-list for a single XR via `CustomObjectsApi`, filtered by name. */
175
- async function listXrCollection(kc, ref) {
176
- const api = kc.makeApiClient(CustomObjectsApi);
177
- const fieldSelector = `metadata.name=${ref.name}`;
178
- const res = await (ref.namespaced && ref.namespace ? api.listNamespacedCustomObject({
179
- group: ref.group,
180
- version: ref.version,
181
- namespace: ref.namespace,
182
- plural: ref.plural,
183
- fieldSelector
184
- }) : api.listClusterCustomObject({
185
- group: ref.group,
186
- version: ref.version,
187
- plural: ref.plural,
188
- fieldSelector
189
- }));
190
- return {
191
- resourceVersion: res.metadata?.resourceVersion ?? "",
192
- items: res.items ?? []
193
- };
194
- }
195
- /** Initial-list of Kubernetes Events scoped to a namespace + field selector. */
196
- async function listXrEvents(kc, namespace, fieldSelector) {
197
- const res = await kc.makeApiClient(CoreV1Api).listNamespacedEvent({
198
- namespace,
199
- fieldSelector
200
- });
201
- return {
202
- resourceVersion: res.metadata?.resourceVersion ?? "",
203
- items: res.items ?? []
204
- };
205
- }
206
- //#endregion
207
180
  //#region src/client/watch.ts
208
181
  /**
209
182
  * Run a robust list-then-watch loop. The initial list is supplied by the caller
@@ -347,6 +320,106 @@ var AsyncQueue = class {
347
320
  }
348
321
  };
349
322
  //#endregion
323
+ //#region src/watcher/readiness.ts
324
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
325
+ const asString = (v) => typeof v === "string" ? v : void 0;
326
+ /**
327
+ * Build an `XrSnapshot` from a raw Kubernetes object. Parses the `Ready` condition,
328
+ * the optional `status.xplane` payload and `status.resourceRefs`.
329
+ */
330
+ function buildSnapshot(object) {
331
+ const status = isRecord(object.status) ? object.status : void 0;
332
+ const conditions = [];
333
+ if (status && Array.isArray(status.conditions)) {
334
+ for (const c of status.conditions) if (isRecord(c)) conditions.push({
335
+ type: asString(c.type),
336
+ status: asString(c.status),
337
+ reason: asString(c.reason),
338
+ message: asString(c.message)
339
+ });
340
+ }
341
+ const ready = conditions.find((c) => c.type === "Ready");
342
+ const responsive = conditions.find((c) => c.type === "Responsive");
343
+ const synced = conditions.find((c) => c.type === "Synced");
344
+ const snapshot = {
345
+ object,
346
+ ready: ready?.status === "True",
347
+ resourceRefs: parseResourceRefs(status)
348
+ };
349
+ if (ready?.reason !== void 0) snapshot.readyReason = ready.reason;
350
+ if (ready?.message !== void 0) snapshot.readyMessage = ready.message;
351
+ if (responsive?.status === "False" && responsive.reason === "WatchCircuitOpen") snapshot.updatesThrottled = true;
352
+ if (synced?.status === "False" && synced.reason === "ReconcileError") snapshot.syncError = {
353
+ reason: synced.reason,
354
+ message: synced.message ?? ""
355
+ };
356
+ const xplane = parseXplane(status);
357
+ if (xplane) snapshot.xplane = xplane;
358
+ return snapshot;
359
+ }
360
+ function parseResourceRefs(status) {
361
+ const out = [];
362
+ if (!status) return out;
363
+ const refs = status.resourceRefs;
364
+ if (!Array.isArray(refs)) return out;
365
+ for (const r of refs) {
366
+ if (!isRecord(r)) continue;
367
+ const apiVersion = asString(r.apiVersion) ?? "";
368
+ const kind = asString(r.kind) ?? "";
369
+ const name = asString(r.name) ?? "";
370
+ if (name) out.push({
371
+ apiVersion,
372
+ kind,
373
+ name
374
+ });
375
+ }
376
+ return out;
377
+ }
378
+ function parseXplane(status) {
379
+ if (!status || !isRecord(status.xplane)) return void 0;
380
+ const x = status.xplane;
381
+ const emitted = [];
382
+ if (Array.isArray(x.emittedResources)) for (const r of x.emittedResources) {
383
+ if (!isRecord(r)) continue;
384
+ const nodePath = asString(r.nodePath);
385
+ if (!nodePath) continue;
386
+ const name = asString(r.name);
387
+ const namespace = asString(r.namespace);
388
+ emitted.push({
389
+ apiVersion: asString(r.apiVersion) ?? "",
390
+ kind: asString(r.kind) ?? "",
391
+ nodePath,
392
+ ...name ? { name } : {},
393
+ ...namespace ? { namespace } : {},
394
+ ready: r.ready === true
395
+ });
396
+ }
397
+ const blocked = [];
398
+ if (Array.isArray(x.blockedResources)) for (const r of x.blockedResources) {
399
+ if (!isRecord(r)) continue;
400
+ const nodePath = asString(r.nodePath);
401
+ if (!nodePath) continue;
402
+ const name = asString(r.name);
403
+ const namespace = asString(r.namespace);
404
+ const entry = {
405
+ apiVersion: asString(r.apiVersion) ?? "",
406
+ kind: asString(r.kind) ?? "",
407
+ nodePath,
408
+ ...name ? { name } : {},
409
+ ...namespace ? { namespace } : {}
410
+ };
411
+ if (Array.isArray(r.waitingFor)) {
412
+ const wf = r.waitingFor.filter((s) => typeof s === "string");
413
+ if (wf.length > 0) entry.waitingFor = wf;
414
+ }
415
+ blocked.push(entry);
416
+ }
417
+ return {
418
+ emittedResources: emitted,
419
+ blockedResources: blocked
420
+ };
421
+ }
422
+ //#endregion
350
423
  //#region src/watcher/xr-watcher.ts
351
424
  /**
352
425
  * Subscribe to live updates of a single XR. Emits a `snapshot` on every observed
@@ -527,6 +600,20 @@ function toKubernetesEvent(obj) {
527
600
  return event;
528
601
  }
529
602
  //#endregion
530
- export { awaitReady as a, buildSnapshot as i, listXrCollection as n, loadKubeConfig as o, parseTarget as r, createXrWatcher as t };
603
+ //#region src/client/kubeconfig.ts
604
+ /**
605
+ * Load a `KubeConfig` from disk using `client-node`'s default rules (with
606
+ * optional explicit overrides). The returned config has its current context
607
+ * applied.
608
+ */
609
+ function loadKubeConfig(opts = {}) {
610
+ const kc = new KubeConfig();
611
+ if (opts.kubeconfig) kc.loadFromFile(opts.kubeconfig);
612
+ else kc.loadFromDefault();
613
+ if (opts.context) kc.setCurrentContext(opts.context);
614
+ return kc;
615
+ }
616
+ //#endregion
617
+ export { awaitReady as a, parseTarget as i, createXrWatcher as n, listXrCollection as o, buildSnapshot as r, resolveResource as s, loadKubeConfig as t };
531
618
 
532
- //# sourceMappingURL=xr-watcher-1etyvp-6.mjs.map
619
+ //# sourceMappingURL=kubeconfig-BO2X-qXU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kubeconfig-BO2X-qXU.mjs","names":[],"sources":["../src/cli/discovery.ts","../src/client/lists.ts","../src/watcher/await-ready.ts","../src/watcher/target.ts","../src/client/watch.ts","../src/watcher/queue.ts","../src/watcher/readiness.ts","../src/watcher/xr-watcher.ts","../src/client/kubeconfig.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 {\n CoreV1Api,\n CustomObjectsApi,\n type KubeConfig,\n type KubernetesObject,\n} from '@kubernetes/client-node';\nimport type { XrRef } from '../watcher/types.js';\nimport type { ListResult } from './watch.js';\n\ninterface CustomObjectList {\n metadata?: { resourceVersion?: string };\n items?: KubernetesObject[];\n}\n\n/** Initial-list for a single XR via `CustomObjectsApi`, filtered by name. */\nexport async function listXrCollection(kc: KubeConfig, ref: XrRef): Promise<ListResult> {\n const api = kc.makeApiClient(CustomObjectsApi);\n const fieldSelector = `metadata.name=${ref.name}`;\n const res = (await (ref.namespaced && ref.namespace\n ? api.listNamespacedCustomObject({\n group: ref.group,\n version: ref.version,\n namespace: ref.namespace,\n plural: ref.plural,\n fieldSelector,\n })\n : api.listClusterCustomObject({\n group: ref.group,\n version: ref.version,\n plural: ref.plural,\n fieldSelector,\n }))) as CustomObjectList;\n return {\n resourceVersion: res.metadata?.resourceVersion ?? '',\n items: res.items ?? [],\n };\n}\n\n/** Initial-list of Kubernetes Events scoped to a namespace + field selector. */\nexport async function listXrEvents(\n kc: KubeConfig,\n namespace: string,\n fieldSelector: string,\n): Promise<ListResult> {\n const api = kc.makeApiClient(CoreV1Api);\n const res = await api.listNamespacedEvent({ namespace, fieldSelector });\n return {\n resourceVersion: res.metadata?.resourceVersion ?? '',\n items: (res.items ?? []) as unknown as KubernetesObject[],\n };\n}\n","import type { XrSnapshot } from './types.js';\nimport type { XrWatcher } from './xr-watcher.js';\n\nexport interface AwaitReadyOptions {\n /** Maximum time in ms to wait for `Ready=True` before rejecting. */\n timeoutMs?: number;\n}\n\n/**\n * Resolve when the watcher observes its first `Ready=True` snapshot. Rejects on\n * the watcher's first error, if the stream ends without becoming ready, or on\n * `timeoutMs`.\n *\n * Uses the watcher's dedicated `ready` promise — it does NOT consume queue\n * events, so it composes safely with a concurrent renderer iterating the\n * watcher.\n *\n * The watcher itself is not stopped on resolution — call `watcher.stop()` from\n * a `.finally()` if you want the underlying connections torn down.\n */\nexport async function awaitReady(\n watcher: XrWatcher,\n opts: AwaitReadyOptions = {},\n): Promise<XrSnapshot> {\n if (opts.timeoutMs === undefined) return watcher.ready;\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Timed out after ${opts.timeoutMs}ms waiting for Ready`)),\n opts.timeoutMs,\n );\n });\n try {\n return await Promise.race([watcher.ready, timeout]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n","/**\n * Parse a kubectl-style resource target of the form:\n * <resource>/<name>\n * where `<resource>` is one of:\n * - `kind` (e.g. `xprojects`, `XProject`)\n * - `kind.group` (e.g. `xprojects.platform.example.com`)\n * - `kind.version.group` (e.g. `xprojects.v1alpha1.platform.example.com`)\n *\n * The `kind` token is returned as-is; resolving it to an API group/version/plural\n * is the discovery layer's responsibility (see `client/discovery.ts`).\n */\nexport interface ParsedTarget {\n /** Resource hint: kind, plural, or short name as typed by the user. */\n resource: string;\n /** Optional API group hint extracted from `kind.group` or `kind.version.group`. */\n group?: string;\n /** Optional API version hint extracted from `kind.version.group`. */\n version?: string;\n /** Object name. */\n name: string;\n}\n\nexport function parseTarget(input: string): ParsedTarget {\n const slash = input.indexOf('/');\n if (slash < 0) {\n throw new Error(\n `Invalid target \"${input}\": expected kubectl-style \"<resource>/<name>\" (e.g. \"xprojects/foo\" or \"xprojects.platform.example.com/foo\").`,\n );\n }\n const left = input.slice(0, slash);\n const name = input.slice(slash + 1);\n if (left.length === 0 || name.length === 0) {\n throw new Error(`Invalid target \"${input}\": both resource and name are required.`);\n }\n\n const dot = left.indexOf('.');\n if (dot < 0) return { resource: left, name };\n\n const resource = left.slice(0, dot);\n const rest = left.slice(dot + 1);\n\n // Heuristic: a Kubernetes API version token starts with `v` followed by a digit\n // (`v1`, `v1alpha1`, `v2beta3`). If the first segment of `rest` matches, treat\n // it as the version and the remainder as the group.\n const restDot = rest.indexOf('.');\n if (restDot > 0) {\n const maybeVersion = rest.slice(0, restDot);\n if (/^v\\d/.test(maybeVersion)) {\n return { resource, version: maybeVersion, group: rest.slice(restDot + 1), name };\n }\n }\n return { resource, group: rest, name };\n}\n","import type { KubeConfig, KubernetesObject } from '@kubernetes/client-node';\nimport { Watch } from '@kubernetes/client-node';\n\n/** Watch event phase as published by the Kubernetes watch protocol. */\nexport type WatchPhase = 'ADDED' | 'MODIFIED' | 'DELETED' | 'BOOKMARK' | 'ERROR';\n\n/** Result of an initial list call. */\nexport interface ListResult<T extends KubernetesObject = KubernetesObject> {\n resourceVersion: string;\n items: T[];\n}\n\nexport interface ListWatchOptions {\n /** Watch URL path, e.g. `/apis/group/v1/namespaces/ns/plural`. */\n path: string;\n /** Optional field selector applied to the watch stream. */\n fieldSelector?: string;\n /** Optional label selector applied to the watch stream. */\n labelSelector?: string;\n /** Aborts both the initial list and any subsequent watch streams. */\n signal: AbortSignal;\n /** Caller-provided initial list. Use a typed client (`CoreV1Api`, `CustomObjectsApi`, …). */\n list: () => Promise<ListResult>;\n /** Invoked for each observed object (after the initial list and on each watch event). */\n onEvent: (phase: WatchPhase, obj: KubernetesObject) => void;\n /** Invoked when a stream ends in error and a reconnect is about to be attempted. */\n onError?: (err: Error) => void;\n}\n\ninterface ReconnectableState {\n resourceVersion: string;\n}\n\n/**\n * Run a robust list-then-watch loop. The initial list is supplied by the caller\n * (so it can use a typed Kubernetes client); the watch stream uses the raw\n * `Watch` class because it is the only API surface that supports a\n * `fieldSelector` for a single named object.\n *\n * Behaviour:\n * 1. Call `opts.list()` and emit each item as `ADDED`.\n * 2. Start a `Watch` stream from the returned `resourceVersion`. Each event is forwarded.\n * 3. When the stream ends with an error or the server closes it, sleep briefly and reconnect.\n * 4. The loop exits cleanly when the supplied `AbortSignal` fires.\n */\nexport async function listAndWatch(kc: KubeConfig, opts: ListWatchOptions): Promise<void> {\n const state: ReconnectableState = { resourceVersion: '' };\n const watcher = new Watch(kc);\n\n while (!opts.signal.aborted) {\n try {\n const list = await opts.list();\n state.resourceVersion = list.resourceVersion;\n for (const item of list.items) opts.onEvent('ADDED', item);\n\n await runWatchOnce(watcher, opts, state);\n } catch (err) {\n if (opts.signal.aborted) return;\n const e = err instanceof Error ? err : new Error(String(err));\n opts.onError?.(e);\n await sleep(1000, opts.signal);\n }\n }\n}\n\nfunction runWatchOnce(\n watcher: Watch,\n opts: ListWatchOptions,\n state: ReconnectableState,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const queryParams: Record<string, string | boolean> = { watch: true };\n if (opts.fieldSelector) queryParams.fieldSelector = opts.fieldSelector;\n if (opts.labelSelector) queryParams.labelSelector = opts.labelSelector;\n if (state.resourceVersion) queryParams.resourceVersion = state.resourceVersion;\n queryParams.allowWatchBookmarks = true;\n\n let controllerRef: AbortController | undefined;\n let settled = false;\n const resolveOnce = () => {\n if (settled) return;\n settled = true;\n opts.signal.removeEventListener('abort', onAbort);\n resolve();\n };\n const rejectOnce = (err: unknown) => {\n if (settled) return;\n settled = true;\n opts.signal.removeEventListener('abort', onAbort);\n reject(err instanceof Error ? err : new Error(String(err)));\n };\n const onAbort = () => {\n controllerRef?.abort();\n resolveOnce();\n };\n opts.signal.addEventListener('abort', onAbort, { once: true });\n\n watcher\n .watch(\n opts.path,\n queryParams,\n (phase, apiObj) => {\n const obj = apiObj as KubernetesObject;\n const objRv = (obj.metadata?.resourceVersion as string | undefined) ?? '';\n if (objRv) state.resourceVersion = objRv;\n opts.onEvent(phase as WatchPhase, obj);\n },\n (err) => {\n if (err) rejectOnce(err);\n else resolveOnce();\n },\n )\n .then((controller) => {\n controllerRef = controller;\n if (opts.signal.aborted) {\n controller.abort();\n resolveOnce();\n }\n })\n .catch((err) => rejectOnce(err));\n });\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise<void>((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n const t = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n resolve();\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * Single-consumer async queue used by the XR watcher to expose its event\n * stream as both a callback API and a `for await` async iterable.\n *\n * Memory-bounded only by the producer. Designed for low-frequency control-plane\n * events (Kubernetes watch + status reconciliations), not high-throughput data.\n */\nexport class AsyncQueue<T> implements AsyncIterable<T> {\n private buffer: T[] = [];\n private waiters: Array<(r: IteratorResult<T>) => void> = [];\n private closed = false;\n\n push(value: T): void {\n if (this.closed) return;\n const waiter = this.waiters.shift();\n if (waiter) waiter({ value, done: false });\n else this.buffer.push(value);\n }\n\n close(): void {\n if (this.closed) return;\n this.closed = true;\n for (const w of this.waiters.splice(0)) w({ value: undefined, done: true });\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return {\n next: (): Promise<IteratorResult<T>> => {\n const v = this.buffer.shift();\n if (v !== undefined) return Promise.resolve({ value: v, done: false });\n if (this.closed) return Promise.resolve({ value: undefined, done: true });\n return new Promise<IteratorResult<T>>((resolve) => this.waiters.push(resolve));\n },\n return: (): Promise<IteratorResult<T>> => {\n this.close();\n return Promise.resolve({ value: undefined, done: true });\n },\n };\n }\n}\n","import type { KubernetesObject } from '@kubernetes/client-node';\nimport type { ResourceRef, XplaneStatus, XrSnapshot } from './types.js';\n\ninterface Condition {\n type?: string;\n status?: string;\n reason?: string;\n message?: string;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst asString = (v: unknown): string | undefined => (typeof v === 'string' ? v : undefined);\n\n/**\n * Build an `XrSnapshot` from a raw Kubernetes object. Parses the `Ready` condition,\n * the optional `status.xplane` payload and `status.resourceRefs`.\n */\nexport function buildSnapshot(object: KubernetesObject): XrSnapshot {\n const status = isRecord((object as { status?: unknown }).status)\n ? (object as { status: Record<string, unknown> }).status\n : undefined;\n\n const conditions: Condition[] = [];\n if (status && Array.isArray(status.conditions)) {\n for (const c of status.conditions as unknown[]) {\n if (isRecord(c)) {\n conditions.push({\n type: asString(c.type),\n status: asString(c.status),\n reason: asString(c.reason),\n message: asString(c.message),\n });\n }\n }\n }\n const ready = conditions.find((c) => c.type === 'Ready');\n const responsive = conditions.find((c) => c.type === 'Responsive');\n const synced = conditions.find((c) => c.type === 'Synced');\n\n const snapshot: XrSnapshot = {\n object,\n ready: ready?.status === 'True',\n resourceRefs: parseResourceRefs(status),\n };\n if (ready?.reason !== undefined) snapshot.readyReason = ready.reason;\n if (ready?.message !== undefined) snapshot.readyMessage = ready.message;\n if (responsive?.status === 'False' && responsive.reason === 'WatchCircuitOpen') {\n snapshot.updatesThrottled = true;\n }\n if (synced?.status === 'False' && synced.reason === 'ReconcileError') {\n snapshot.syncError = {\n reason: synced.reason,\n message: synced.message ?? '',\n };\n }\n\n const xplane = parseXplane(status);\n if (xplane) snapshot.xplane = xplane;\n\n return snapshot;\n}\n\nfunction parseResourceRefs(status: Record<string, unknown> | undefined): ResourceRef[] {\n const out: ResourceRef[] = [];\n if (!status) return out;\n const refs = status.resourceRefs;\n if (!Array.isArray(refs)) return out;\n for (const r of refs as unknown[]) {\n if (!isRecord(r)) continue;\n const apiVersion = asString(r.apiVersion) ?? '';\n const kind = asString(r.kind) ?? '';\n const name = asString(r.name) ?? '';\n if (name) out.push({ apiVersion, kind, name });\n }\n return out;\n}\n\nfunction parseXplane(status: Record<string, unknown> | undefined): XplaneStatus | undefined {\n if (!status || !isRecord(status.xplane)) return undefined;\n const x = status.xplane;\n const emitted: XplaneStatus['emittedResources'] = [];\n if (Array.isArray(x.emittedResources)) {\n for (const r of x.emittedResources as unknown[]) {\n if (!isRecord(r)) continue;\n const nodePath = asString(r.nodePath);\n if (!nodePath) continue;\n const name = asString(r.name);\n const namespace = asString(r.namespace);\n emitted.push({\n apiVersion: asString(r.apiVersion) ?? '',\n kind: asString(r.kind) ?? '',\n nodePath,\n ...(name ? { name } : {}),\n ...(namespace ? { namespace } : {}),\n ready: r.ready === true,\n });\n }\n }\n const blocked: XplaneStatus['blockedResources'] = [];\n if (Array.isArray(x.blockedResources)) {\n for (const r of x.blockedResources as unknown[]) {\n if (!isRecord(r)) continue;\n const nodePath = asString(r.nodePath);\n if (!nodePath) continue;\n const name = asString(r.name);\n const namespace = asString(r.namespace);\n const entry: XplaneStatus['blockedResources'][number] = {\n apiVersion: asString(r.apiVersion) ?? '',\n kind: asString(r.kind) ?? '',\n nodePath,\n ...(name ? { name } : {}),\n ...(namespace ? { namespace } : {}),\n };\n if (Array.isArray(r.waitingFor)) {\n const wf = (r.waitingFor as unknown[]).filter((s): s is string => typeof s === 'string');\n if (wf.length > 0) entry.waitingFor = wf;\n }\n blocked.push(entry);\n }\n }\n return { emittedResources: emitted, blockedResources: blocked };\n}\n","import type { KubeConfig, KubernetesObject } from '@kubernetes/client-node';\nimport { listXrCollection, listXrEvents } from '../client/lists.js';\nimport { listAndWatch } from '../client/watch.js';\nimport { AsyncQueue } from './queue.js';\nimport { buildSnapshot } from './readiness.js';\nimport type { KubernetesEvent, XrEvent, XrRef, XrSnapshot } from './types.js';\n\nexport interface CreateXrWatcherOptions {\n kubeConfig: KubeConfig;\n ref: XrRef;\n /** Disable subscribing to Kubernetes Events for the XR. Defaults to `false`. */\n disableEvents?: boolean;\n /** Aborts both the XR and Events watches and closes the iterable. */\n signal?: AbortSignal;\n}\n\nexport interface XrWatcher extends AsyncIterable<XrEvent> {\n /** Resolves with the first ready snapshot. Rejects on error or end-before-ready. */\n readonly ready: Promise<XrSnapshot>;\n /** Resolves when the watcher's background tasks have all settled. */\n readonly done: Promise<void>;\n /** Aborts the watcher and closes the iterable. Idempotent. */\n stop(): void;\n}\n\n/**\n * Subscribe to live updates of a single XR. Emits a `snapshot` on every observed\n * change, a one-shot `ready` when the XR's `Ready` condition first becomes True,\n * and (unless disabled) `k8s-event` items for Kubernetes Events targeting the XR.\n *\n * The watcher uses list-then-watch with auto-reconnect — no polling.\n */\nexport function createXrWatcher(opts: CreateXrWatcherOptions): XrWatcher {\n const queue = new AsyncQueue<XrEvent>();\n const controller = new AbortController();\n const userSignal = opts.signal;\n if (userSignal) {\n if (userSignal.aborted) controller.abort();\n else userSignal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n let readyEmitted = false;\n let uid: string | undefined;\n let eventsStarted = false;\n let eventsTask: Promise<void> = Promise.resolve();\n const seenEventUids = new Set<string>();\n\n let resolveReady!: (snap: XrSnapshot) => void;\n let rejectReady!: (err: Error) => void;\n let readySettled = false;\n const ready = new Promise<XrSnapshot>((res, rej) => {\n resolveReady = (s) => {\n if (readySettled) return;\n readySettled = true;\n res(s);\n };\n rejectReady = (e) => {\n if (readySettled) return;\n readySettled = true;\n rej(e);\n };\n });\n // Avoid unhandled rejection if nobody awaits `ready`.\n ready.catch(() => undefined);\n\n const handleXrEvent = (phase: string, obj: KubernetesObject) => {\n if (phase === 'DELETED') {\n const err = new Error(`XR ${opts.ref.kind}/${opts.ref.name} was deleted`);\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n controller.abort();\n return;\n }\n if (phase === 'BOOKMARK' || phase === 'ERROR') return;\n const snapshot = buildSnapshot(obj);\n queue.push({ type: 'snapshot', snapshot });\n if (snapshot.syncError) {\n const err = new Error(\n `XR ${opts.ref.kind}/${opts.ref.name} reconcile failed: ${snapshot.syncError.message || snapshot.syncError.reason}`,\n );\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n controller.abort();\n return;\n }\n if (!readyEmitted && snapshot.ready) {\n readyEmitted = true;\n queue.push({ type: 'ready', snapshot });\n resolveReady(snapshot);\n }\n const newUid = obj.metadata?.uid as string | undefined;\n if (newUid && !uid) {\n uid = newUid;\n if (!opts.disableEvents && opts.ref.namespaced && opts.ref.namespace) {\n eventsStarted = true;\n eventsTask = startEventsWatch(opts, uid, controller.signal, queue, seenEventUids);\n }\n }\n };\n\n const xrPath = buildResourcePath(opts.ref);\n let firstListSeenItem = false;\n const xrTask = listAndWatch(opts.kubeConfig, {\n path: xrPath,\n fieldSelector: `metadata.name=${opts.ref.name}`,\n signal: controller.signal,\n list: async () => {\n const result = await listXrCollection(opts.kubeConfig, opts.ref);\n if (!firstListSeenItem) {\n if (result.items.length > 0) {\n firstListSeenItem = true;\n } else {\n const where = opts.ref.namespace ? ` in namespace ${opts.ref.namespace}` : '';\n const err = new Error(`XR ${opts.ref.kind}/${opts.ref.name} not found${where}`);\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n controller.abort();\n }\n }\n return result;\n },\n onEvent: handleXrEvent,\n onError: (err) => {\n queue.push({ type: 'error', error: err });\n rejectReady(err);\n },\n });\n\n const done = (async () => {\n try {\n await xrTask;\n } finally {\n if (eventsStarted) {\n try {\n await eventsTask;\n } catch {\n /* already surfaced via onError */\n }\n }\n rejectReady(new Error('Watcher ended before XR became Ready'));\n queue.push({ type: 'end' });\n queue.close();\n }\n })();\n\n return {\n ready,\n done,\n stop: () => controller.abort(),\n [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator](),\n };\n}\n\nfunction buildResourcePath(ref: XrRef): string {\n const base = ref.group ? `/apis/${ref.group}/${ref.version}` : `/api/${ref.version}`;\n if (ref.namespaced) {\n if (!ref.namespace) {\n throw new Error(`Namespace is required for namespaced resource ${ref.kind}/${ref.name}`);\n }\n return `${base}/namespaces/${ref.namespace}/${ref.plural}`;\n }\n return `${base}/${ref.plural}`;\n}\n\nasync function startEventsWatch(\n opts: CreateXrWatcherOptions,\n uid: string,\n signal: AbortSignal,\n queue: AsyncQueue<XrEvent>,\n seen: Set<string>,\n): Promise<void> {\n if (!opts.ref.namespace) return;\n const namespace = opts.ref.namespace;\n const path = `/api/v1/namespaces/${namespace}/events`;\n const fieldSelector = `involvedObject.uid=${uid}`;\n await listAndWatch(opts.kubeConfig, {\n path,\n fieldSelector,\n signal,\n list: () => listXrEvents(opts.kubeConfig, namespace, fieldSelector),\n onEvent: (phase, obj) => {\n if (phase !== 'ADDED' && phase !== 'MODIFIED') return;\n const eventUid = obj.metadata?.uid as string | undefined;\n if (eventUid && seen.has(eventUid)) return;\n if (eventUid) seen.add(eventUid);\n const event = toKubernetesEvent(obj);\n if (event) queue.push({ type: 'k8s-event', event });\n },\n onError: (err) => queue.push({ type: 'error', error: err }),\n });\n}\n\nfunction toKubernetesEvent(obj: KubernetesObject): KubernetesEvent | undefined {\n const raw = obj as KubernetesObject & {\n type?: string;\n reason?: string;\n message?: string;\n count?: number;\n firstTimestamp?: string;\n lastTimestamp?: string;\n eventTime?: string;\n involvedObject?: { kind?: string; name?: string };\n };\n if (!raw.message && !raw.reason) return undefined;\n const event: KubernetesEvent = {\n type: raw.type ?? 'Normal',\n reason: raw.reason ?? '',\n message: raw.message ?? '',\n count: raw.count ?? 1,\n };\n const first = raw.firstTimestamp ?? raw.eventTime;\n const last = raw.lastTimestamp ?? raw.eventTime ?? first;\n if (first) event.firstTimestamp = first;\n if (last) event.lastTimestamp = last;\n if (raw.involvedObject?.kind) event.involvedKind = raw.involvedObject.kind;\n if (raw.involvedObject?.name) event.involvedName = raw.involvedObject.name;\n return event;\n}\n","import { KubeConfig } from '@kubernetes/client-node';\n\nexport interface LoadKubeConfigOptions {\n /** Explicit kubeconfig file path. Falls back to `KUBECONFIG` / default discovery. */\n kubeconfig?: string;\n /** Override the active context. */\n context?: string;\n}\n\n/**\n * Load a `KubeConfig` from disk using `client-node`'s default rules (with\n * optional explicit overrides). The returned config has its current context\n * applied.\n */\nexport function loadKubeConfig(opts: LoadKubeConfigOptions = {}): KubeConfig {\n const kc = new KubeConfig();\n if (opts.kubeconfig) {\n kc.loadFromFile(opts.kubeconfig);\n } else {\n kc.loadFromDefault();\n }\n if (opts.context) {\n kc.setCurrentContext(opts.context);\n }\n return kc;\n}\n"],"mappings":"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"}
@@ -1,85 +1,2 @@
1
- import { d as XrSnapshot, n as XrWatcher, o as KubernetesEvent, u as XrRef } from "../xr-watcher-EiWHVp3o.mjs";
2
-
3
- //#region src/render/ci.d.ts
4
- interface CiRendererOptions {
5
- ref: XrRef;
6
- /** Destination stream. Defaults to `process.stdout`. */
7
- out?: NodeJS.WritableStream;
8
- /** 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. */
9
- heartbeatMs?: number;
10
- /** When true, K8s Events are echoed inline. Defaults to false in CI (too noisy). */
11
- showEvents?: boolean;
12
- /** Every N consecutive idle heartbeats, expand the heartbeat line into a snapshot of unready + blocked resources. Defaults to 10. Set to 0 to disable. */
13
- snapshotEveryHeartbeats?: number;
14
- }
15
- /**
16
- * Append-only CI renderer.
17
- *
18
- * 1. Print a one-line "watching …" header on startup.
19
- * 2. On the first snapshot, print a full snapshot block.
20
- * 3. On every subsequent snapshot, print only the delta.
21
- * 4. If nothing is printed within `heartbeatMs`, emit a single liveness line.
22
- */
23
- declare function renderCI(watcher: XrWatcher, opts: CiRendererOptions): Promise<void>;
24
- //#endregion
25
- //#region src/render/format.d.ts
26
- /** Single-character glyph for the status of a tree node. */
27
- declare function statusGlyph(state: 'ready' | 'pending' | 'blocked'): string;
28
- /** Compact header line summarising the XR. */
29
- declare function formatHeader(snapshot: XrSnapshot, ref: {
30
- kind: string;
31
- name: string;
32
- namespace?: string;
33
- }): string;
34
- /** Inline progress representation, e.g. `5/12 ready · 3 blocked`. */
35
- declare function formatProgress(ready: number, total: number, blocked: number): string;
36
- /** Format a Kubernetes Event as a single line. */
37
- declare function formatEvent(ev: KubernetesEvent): string;
38
- //#endregion
39
- //#region src/render/tty.d.ts
40
- interface TtyRendererOptions {
41
- ref: XrRef;
42
- /** Destination stream. Defaults to `process.stdout`. */
43
- out?: NodeJS.WriteStream;
44
- /** Maximum number of recent Kubernetes events shown in the tail. Defaults to 5. */
45
- eventTailSize?: number;
46
- /** Allows callers (and tests) to provide a custom `log-update` instance. */
47
- logger?: {
48
- (frame: string): void;
49
- clear: () => void;
50
- done: () => void;
51
- };
52
- }
53
- /**
54
- * Live full-screen renderer using `log-update` to repaint a single frame.
55
- * Resolves when the watcher ends.
56
- */
57
- declare function renderTTY(watcher: XrWatcher, opts: TtyRendererOptions): Promise<void>;
58
- //#endregion
59
- //#region src/render/index.d.ts
60
- type RendererMode = 'tty' | 'ci';
61
- /** Auto-select a renderer based on whether the destination is an interactive TTY. */
62
- declare function selectRenderer(stream: NodeJS.WriteStream | NodeJS.WritableStream): RendererMode;
63
- interface RunRendererOptions {
64
- ref: XrRef;
65
- /** Forces a renderer instead of auto-detecting. */
66
- mode?: RendererMode;
67
- /** Destination stream. Defaults to `process.stdout`. */
68
- out?: NodeJS.WriteStream;
69
- /** Max number of recent events kept in the TTY tail. */
70
- eventTailSize?: number;
71
- /** CI: heartbeat interval (ms) for liveness lines. 0 disables. */
72
- heartbeatMs?: number;
73
- /** CI: include K8s Events inline. Off by default. */
74
- showEvents?: boolean;
75
- /** CI: every N idle heartbeats, expand into a snapshot of unready + blocked resources. 0 disables. */
76
- snapshotEveryHeartbeats?: number;
77
- }
78
- /**
79
- * Drive either renderer against the supplied watcher. Resolves when the
80
- * watcher's event stream ends.
81
- */
82
- declare function runRenderer(watcher: XrWatcher, opts: RunRendererOptions): Promise<void>;
83
- //#endregion
84
- export { type CiRendererOptions, RendererMode, RunRendererOptions, type TtyRendererOptions, formatEvent, formatHeader, formatProgress, renderCI, renderTTY, runRenderer, selectRenderer, statusGlyph };
85
- //# sourceMappingURL=index.d.mts.map
1
+ import { a as TtyRendererOptions, c as formatHeader, d as CiRendererOptions, f as renderCI, i as selectRenderer, l as formatProgress, n as RunRendererOptions, o as renderTTY, r as runRenderer, s as formatEvent, t as RendererMode, u as statusGlyph } from "../index-Dp92t3xP.mjs";
2
+ export { type CiRendererOptions, RendererMode, RunRendererOptions, type TtyRendererOptions, formatEvent, formatHeader, formatProgress, renderCI, renderTTY, runRenderer, selectRenderer, statusGlyph };
@@ -1,2 +1,2 @@
1
- import { a as formatEvent, c as statusGlyph, i as renderCI, n as selectRenderer, o as formatHeader, r as renderTTY, s as formatProgress, t as runRenderer } from "../render-Cnhpyf1X.mjs";
1
+ import { a as renderCI, c as formatProgress, l as statusGlyph, n as selectRenderer, o as formatEvent, r as renderTTY, s as formatHeader, t as runRenderer } from "../render-BMhfzOc2.mjs";
2
2
  export { formatEvent, formatHeader, formatProgress, renderCI, renderTTY, runRenderer, selectRenderer, statusGlyph };