@compforge/harness-toolbox 0.4.5 → 0.4.8

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.
@@ -2,13 +2,13 @@ import {
2
2
  findPodsForService,
3
3
  findService,
4
4
  listServiceNetwork
5
- } from "./chunk-j46x7j7c.js";
5
+ } from "./chunk-xgnz10sr.js";
6
6
  import {
7
7
  findPod
8
8
  } from "./chunk-6fnhzhdb.js";
9
9
  import {
10
10
  PortForwardScope
11
- } from "./chunk-631vce5z.js";
11
+ } from "./chunk-nftzckdy.js";
12
12
 
13
13
  // src/kubernetes/service-port-forward.ts
14
14
  class ServicePortForwarder {
@@ -24,13 +24,14 @@ class ServicePortForwarder {
24
24
  this.#scope = new PortForwardScope(starter);
25
25
  }
26
26
  static async create(executor, opts, starter) {
27
- const network = await listServiceNetwork(executor, opts.namespace);
27
+ const network = await listServiceNetwork(executor, opts.namespace, opts.signal);
28
28
  return new ServicePortForwarder(opts, network.services, network.pods, starter);
29
29
  }
30
30
  get activeForwards() {
31
31
  return this.#scope.active;
32
32
  }
33
33
  forward(endpoint) {
34
+ this.opts.signal?.throwIfAborted();
34
35
  const key = `${endpoint.host}:${endpoint.port}`;
35
36
  let pending = this.#cache.get(key);
36
37
  if (!pending) {
@@ -24,7 +24,9 @@ function spawnProcess(argv, opts) {
24
24
  stdout: Readable.toWeb(child.stdout),
25
25
  stderr: Readable.toWeb(child.stderr),
26
26
  exited,
27
- kill: () => child.kill()
27
+ kill: (signal) => {
28
+ child.kill(signal);
29
+ }
28
30
  };
29
31
  }
30
32
  function sleep(ms) {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  startPortForward
3
- } from "./chunk-631vce5z.js";
3
+ } from "./chunk-nftzckdy.js";
4
4
  import {
5
5
  KubectlExecutor
6
- } from "./chunk-hmah9t8e.js";
6
+ } from "./chunk-rq5fc007.js";
7
7
  import {
8
8
  POD_RELAY_SCRIPT
9
9
  } from "./chunk-ssj93brx.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ae84rzq5.js";
4
4
  import {
5
5
  ServicePortForwarder
6
- } from "./chunk-2171tajs.js";
6
+ } from "./chunk-1ts7pswj.js";
7
7
  import {
8
8
  KubernetesResourceTransport
9
9
  } from "./chunk-x0yhfg29.js";
@@ -15,7 +15,7 @@ import {
15
15
  } from "./chunk-rkt41za2.js";
16
16
  import {
17
17
  KubectlExecutor
18
- } from "./chunk-hmah9t8e.js";
18
+ } from "./chunk-rq5fc007.js";
19
19
 
20
20
  // src/kubernetes/client.ts
21
21
  class KubernetesClient {
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  buildKubectlArgs
3
- } from "./chunk-hmah9t8e.js";
3
+ } from "./chunk-rq5fc007.js";
4
4
  import {
5
5
  spawnProcess
6
- } from "./chunk-mn6dwsvh.js";
6
+ } from "./chunk-9shz0bw1.js";
7
7
 
8
8
  // src/kubernetes/port-forward.ts
9
9
  async function startPortForward(opts) {
10
+ opts.signal?.throwIfAborted();
10
11
  const target = opts.target ?? (opts.service ? { kind: "service", name: opts.service } : undefined);
11
12
  if (!target)
12
13
  return { ok: false, reason: "port-forward 缺少 Service/Pod 目标" };
@@ -24,8 +25,51 @@ async function startPortForward(opts) {
24
25
  return { ok: false, reason: err instanceof Error ? err.message : String(err) };
25
26
  }
26
27
  const timeoutMs = opts.timeoutMs ?? 15000;
27
- const stderrPromise = new Response(proc.stderr).text();
28
+ const log = opts.onDiagnostic ?? (() => {});
29
+ const started = Date.now();
30
+ log(`port-forward start target=${target.kind}/${target.name} namespace=${opts.namespace ?? "default"} remote_port=${opts.remotePort} timeout_ms=${timeoutMs}`);
31
+ let stderr = "";
32
+ let loggedBytes = 0;
33
+ const stderrReader = proc.stderr.getReader();
34
+ const stderrDone = (async () => {
35
+ const decoder2 = new TextDecoder;
36
+ for (;; ) {
37
+ const chunk = await stderrReader.read();
38
+ if (chunk.done)
39
+ break;
40
+ const text = decoder2.decode(chunk.value, { stream: true }).replace(/(https?:\/\/)[^\s/@]+:[^\s/@]+@/g, "$1[redacted]@").replace(/([?&](?:token|password|secret|key)=)[^&\s]+/gi, "$1[redacted]").replace(/((?:authorization|password|token)[:=]\s*)[^\r\n]+/gi, "$1[redacted]");
41
+ stderr = (stderr + text).slice(-8192);
42
+ if (loggedBytes < 8192) {
43
+ const diagnostic = text.slice(0, 8192 - loggedBytes);
44
+ loggedBytes += diagnostic.length;
45
+ log(`port-forward stderr: ${diagnostic.trim()}`);
46
+ }
47
+ }
48
+ })().catch(() => {});
49
+ let stopped = false;
50
+ let cancelWait;
51
+ const cancelled = new Promise((resolve) => {
52
+ cancelWait = () => resolve("cancelled");
53
+ });
54
+ const abort = () => {
55
+ log(`port-forward cancelled elapsed_ms=${Date.now() - started}`);
56
+ stop();
57
+ cancelWait();
58
+ };
59
+ const stop = () => {
60
+ if (stopped)
61
+ return;
62
+ stopped = true;
63
+ opts.signal?.removeEventListener("abort", abort);
64
+ proc.kill("SIGKILL");
65
+ stderrReader.cancel().catch(() => {});
66
+ reader.cancel().catch(() => {});
67
+ };
28
68
  const reader = proc.stdout.getReader();
69
+ opts.signal?.addEventListener("abort", abort, { once: true });
70
+ if (opts.signal?.aborted)
71
+ abort();
72
+ proc.exited.then(() => opts.signal?.removeEventListener("abort", abort), () => opts.signal?.removeEventListener("abort", abort));
29
73
  const decoder = new TextDecoder;
30
74
  const deadline = Date.now() + timeoutMs;
31
75
  let out = "";
@@ -36,6 +80,7 @@ async function startPortForward(opts) {
36
80
  let timer;
37
81
  const chunk = await Promise.race([
38
82
  reader.read(),
83
+ cancelled,
39
84
  new Promise((resolve) => {
40
85
  timer = setTimeout(() => resolve("timeout"), remain);
41
86
  }),
@@ -43,10 +88,13 @@ async function startPortForward(opts) {
43
88
  ]).finally(() => {
44
89
  clearTimeout(timer);
45
90
  });
91
+ opts.signal?.throwIfAborted();
92
+ if (chunk === "cancelled")
93
+ throw opts.signal?.reason;
46
94
  if (chunk === "timeout")
47
95
  break;
48
96
  if (typeof chunk === "object" && "error" in chunk) {
49
- proc.kill();
97
+ stop();
50
98
  return { ok: false, reason: chunk.error instanceof Error ? chunk.error.message : String(chunk.error) };
51
99
  }
52
100
  if (chunk === "exited" || chunk.done)
@@ -54,16 +102,18 @@ async function startPortForward(opts) {
54
102
  out += decoder.decode(chunk.value);
55
103
  const m = out.match(/Forwarding from 127\.0\.0\.1:(\d+)/);
56
104
  if (m) {
105
+ log(`port-forward listening local=127.0.0.1:${m[1]} elapsed_ms=${Date.now() - started}`);
57
106
  return {
58
107
  ok: true,
59
- value: { target, localPort: Number(m[1]), command: argv, stop: () => proc.kill() }
108
+ value: { target, localPort: Number(m[1]), command: argv, stop }
60
109
  };
61
110
  }
62
111
  }
63
- proc.kill();
64
- const stderr = await stderrPromise.catch(() => "");
112
+ await Promise.resolve();
113
+ stop();
65
114
  const reason = stderr.trim().split(`
66
115
  `)[0] || `port-forward 未就绪(${timeoutMs}ms 超时)`;
116
+ log(`port-forward failed elapsed_ms=${Date.now() - started} reason=${reason}`);
67
117
  return { ok: false, reason };
68
118
  }
69
119
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  spawnProcess
3
- } from "./chunk-mn6dwsvh.js";
3
+ } from "./chunk-9shz0bw1.js";
4
4
 
5
5
  // src/kubernetes/executor.ts
6
6
  function buildKubectlArgs(opts, sub) {
@@ -3,6 +3,7 @@ import {
3
3
  awaitWithSignal
4
4
  } from "./chunk-gm4swndx.js";
5
5
  import {
6
+ TimeoutError,
6
7
  ToolboxError
7
8
  } from "./chunk-rkt41za2.js";
8
9
  import {
@@ -11,6 +12,25 @@ import {
11
12
 
12
13
  // src/opensearch/client.ts
13
14
  import { Client, Connection, errors } from "@opensearch-project/opensearch";
15
+ function describeOpenSearchError(error) {
16
+ const parts = [];
17
+ const seen = new Set;
18
+ while (error && typeof error === "object" && !seen.has(error) && parts.length < 4) {
19
+ seen.add(error);
20
+ const value = error;
21
+ const safe = (value2) => typeof value2 === "number" ? String(value2) : typeof value2 === "string" && /^[a-zA-Z0-9_.-]{1,80}$/.test(value2) ? value2 : undefined;
22
+ const argument = (value.code === "ERR_INVALID_ARG_VALUE" || value.code === "ERR_INVALID_ARG_TYPE") && typeof value.message === "string" ? value.message.match(/^The ["']([a-zA-Z][a-zA-Z0-9_.]{0,79})["'] (?:argument|option|property)/)?.[1] ?? value.message.match(/^The (?:argument|option|property) ["']([a-zA-Z][a-zA-Z0-9_.]{0,79})["']/)?.[1] : undefined;
23
+ parts.push([
24
+ `error=${safe(value.name) ?? "Error"}`,
25
+ argument && `argument=${argument}`,
26
+ safe(value.code) && `code=${safe(value.code)}`,
27
+ safe(value.kind) && `kind=${safe(value.kind)}`,
28
+ safe(value.statusCode ?? value.meta?.statusCode) && `status=${safe(value.statusCode ?? value.meta?.statusCode)}`
29
+ ].filter(Boolean).join(" "));
30
+ error = value.cause;
31
+ }
32
+ return parts.join(" cause=") || "error=UnknownError";
33
+ }
14
34
  function isOpenSearchReadApi(search) {
15
35
  return typeof search.request === "function";
16
36
  }
@@ -33,8 +53,10 @@ function createClient(options) {
33
53
  }
34
54
 
35
55
  class OpenSearchEngine {
56
+ options;
36
57
  client;
37
58
  constructor(options, client) {
59
+ this.options = options;
38
60
  this.client = client ?? createClient(options);
39
61
  }
40
62
  async count(index, query) {
@@ -55,21 +77,39 @@ class OpenSearchEngine {
55
77
  });
56
78
  return response.body;
57
79
  }
58
- async ping(signal, timeoutMs) {
80
+ async ping(signal, timeoutMs = this.options.requestTimeoutMs ?? 60000) {
59
81
  signal?.throwIfAborted();
60
- const request = this.client.ping({}, timeoutMs === undefined ? undefined : { requestTimeout: timeoutMs });
61
- const abort = () => {
62
- request.abort?.();
63
- };
64
- signal?.addEventListener("abort", abort, { once: true });
82
+ const started = Date.now();
83
+ const url = new URL(this.options.node);
84
+ const target = `${url.protocol}//${url.host}`;
85
+ const log = this.options.onDiagnostic ?? (() => {});
86
+ log(`OpenSearch probe start target=${target} timeout_ms=${timeoutMs}`);
87
+ const controller = new AbortController;
88
+ const timer = setTimeout(() => controller.abort(new TimeoutError(`OpenSearch probe timed out after ${timeoutMs}ms`)), timeoutMs);
89
+ const active = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
65
90
  try {
66
- return await request;
91
+ const request = this.client.ping({}, { requestTimeout: timeoutMs });
92
+ const result = await awaitWithSignal(request, active, () => request.abort?.());
93
+ log(`OpenSearch probe ok target=${target} elapsed_ms=${Date.now() - started}`);
94
+ return result;
95
+ } catch (error) {
96
+ log(`OpenSearch probe failed target=${target} elapsed_ms=${Date.now() - started} ${describeOpenSearchError(error)}`);
97
+ throw error;
67
98
  } finally {
68
- signal?.removeEventListener("abort", abort);
99
+ clearTimeout(timer);
69
100
  }
70
101
  }
71
- close() {
72
- return this.client.close();
102
+ async close() {
103
+ const controller = new AbortController;
104
+ const timer = setTimeout(() => controller.abort(new TimeoutError("OpenSearch close timed out after 2000ms")), 2000);
105
+ try {
106
+ await awaitWithSignal(this.client.close(), controller.signal);
107
+ } catch (error) {
108
+ this.options.onDiagnostic?.(`OpenSearch close failed ${describeOpenSearchError(error)}`);
109
+ throw error;
110
+ } finally {
111
+ clearTimeout(timer);
112
+ }
73
113
  }
74
114
  }
75
115
  function openSearchRetryReason(error) {
@@ -112,6 +152,7 @@ class OpenSearchClient {
112
152
  open: async (transport, attempt) => {
113
153
  if (transport.kind !== "tcp")
114
154
  throw new Error("OpenSearch requires a TCP transport");
155
+ this.lifecycle.onDiagnostic?.(`OpenSearch route start transport=${transport.name} target=${original.protocol}//${original.host} timeout_ms=${attempt.remainingMs()}`);
115
156
  const endpoint = await transport.connect({
116
157
  host: original.hostname,
117
158
  port: Number(original.port || (original.protocol === "https:" ? 443 : 80)),
@@ -121,12 +162,14 @@ class OpenSearchClient {
121
162
  const url = new URL(original);
122
163
  url.hostname = endpoint.host;
123
164
  url.port = String(endpoint.port);
124
- const engine = new OpenSearchEngine({ ...target, node: url.toString(), servername: endpoint.servername ?? target.servername ?? original.hostname });
165
+ const engine = new OpenSearchEngine({ ...target, onDiagnostic: this.lifecycle.onDiagnostic, node: url.toString(), servername: endpoint.servername ?? target.servername ?? original.hostname });
125
166
  try {
126
167
  await engine.ping(attempt.signal, attempt.remainingMs());
127
168
  return { connection: engine, transport: transport.name };
128
169
  } catch (error) {
129
- await engine.close();
170
+ try {
171
+ await engine.close();
172
+ } catch {}
130
173
  throw error;
131
174
  }
132
175
  },
@@ -134,6 +177,7 @@ class OpenSearchClient {
134
177
  retryReason: openSearchRetryReason
135
178
  });
136
179
  } catch (error) {
180
+ this.lifecycle.onDiagnostic?.(`OpenSearch connect failed ${describeOpenSearchError(error)}`);
137
181
  this.signal.throwIfAborted();
138
182
  if (error instanceof ToolboxError && error.kind === "timeout")
139
183
  throw error;
@@ -193,4 +237,4 @@ async function openOpenSearch(source, lifecycle = {}) {
193
237
  return client;
194
238
  }
195
239
 
196
- export { isOpenSearchReadApi, OpenSearchEngine, OpenSearchClient, openOpenSearch };
240
+ export { describeOpenSearchError, isOpenSearchReadApi, OpenSearchEngine, OpenSearchClient, openOpenSearch };
@@ -53,11 +53,13 @@ function findPodsForService(services, pods, serviceName, namespace) {
53
53
  return [];
54
54
  return pods.filter((pod) => pod.namespace === namespace && pod.phase === "Running" && selector.every(([name, value]) => pod.labels[name] === value)).sort((left, right) => left.name.localeCompare(right.name));
55
55
  }
56
- async function listServiceNetwork(executor, namespace) {
56
+ async function listServiceNetwork(executor, namespace, signal) {
57
+ signal?.throwIfAborted();
57
58
  const [serviceResult, podResult] = await Promise.all([
58
- executor.run(["get", "services", "-o", "json"], { timeoutMs: 20000 }),
59
- executor.run(["get", "pods", "-o", "json"], { timeoutMs: 20000 })
59
+ executor.run(["get", "services", "-o", "json"], { timeoutMs: 20000, signal }),
60
+ executor.run(["get", "pods", "-o", "json"], { timeoutMs: 20000, signal })
60
61
  ]);
62
+ signal?.throwIfAborted();
61
63
  if (!serviceResult.ok) {
62
64
  throw new Error(`读取 Service 失败:${serviceResult.stderr.trim() || `exit=${serviceResult.exitCode}`}`);
63
65
  }
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  KubernetesClient
3
- } from "../chunk-g2bac2jd.js";
3
+ } from "../chunk-m391jmpw.js";
4
4
  import"../chunk-ae84rzq5.js";
5
- import"../chunk-2171tajs.js";
6
- import"../chunk-j46x7j7c.js";
5
+ import"../chunk-1ts7pswj.js";
6
+ import"../chunk-xgnz10sr.js";
7
7
  import"../chunk-6fnhzhdb.js";
8
8
  import"../chunk-x0yhfg29.js";
9
9
  import"../chunk-dpcge1xt.js";
@@ -11,9 +11,9 @@ import"../chunk-r3rnsvwv.js";
11
11
  import"../chunk-a9htb6cr.js";
12
12
  import"../chunk-rkt41za2.js";
13
13
  import"../chunk-v3hxvnrc.js";
14
- import"../chunk-631vce5z.js";
15
- import"../chunk-hmah9t8e.js";
16
- import"../chunk-mn6dwsvh.js";
14
+ import"../chunk-nftzckdy.js";
15
+ import"../chunk-rq5fc007.js";
16
+ import"../chunk-9shz0bw1.js";
17
17
  export {
18
18
  KubernetesClient
19
19
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  KubernetesClient
3
- } from "../chunk-g2bac2jd.js";
3
+ } from "../chunk-m391jmpw.js";
4
4
  import"../chunk-ae84rzq5.js";
5
- import"../chunk-2171tajs.js";
6
- import"../chunk-j46x7j7c.js";
5
+ import"../chunk-1ts7pswj.js";
6
+ import"../chunk-xgnz10sr.js";
7
7
  import"../chunk-6fnhzhdb.js";
8
8
  import"../chunk-x0yhfg29.js";
9
9
  import"../chunk-dpcge1xt.js";
@@ -13,9 +13,9 @@ import {
13
13
  } from "../chunk-a9htb6cr.js";
14
14
  import"../chunk-rkt41za2.js";
15
15
  import"../chunk-v3hxvnrc.js";
16
- import"../chunk-631vce5z.js";
17
- import"../chunk-hmah9t8e.js";
18
- import"../chunk-mn6dwsvh.js";
16
+ import"../chunk-nftzckdy.js";
17
+ import"../chunk-rq5fc007.js";
18
+ import"../chunk-9shz0bw1.js";
19
19
 
20
20
  // src/kubernetes/environment.ts
21
21
  class KubernetesEnvironment {
@@ -3,8 +3,8 @@ import {
3
3
  buildExecArgs,
4
4
  buildKubectlArgs,
5
5
  runArgv
6
- } from "../chunk-hmah9t8e.js";
7
- import"../chunk-mn6dwsvh.js";
6
+ } from "../chunk-rq5fc007.js";
7
+ import"../chunk-9shz0bw1.js";
8
8
  export {
9
9
  runArgv,
10
10
  buildKubectlArgs,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  findPodsForService,
3
3
  parseServices
4
- } from "../chunk-j46x7j7c.js";
4
+ } from "../chunk-xgnz10sr.js";
5
5
  import {
6
6
  parsePods
7
7
  } from "../chunk-6fnhzhdb.js";
@@ -17,6 +17,7 @@ export interface PortForwardResult {
17
17
  }
18
18
  export type StartPortForward = typeof startPortForward;
19
19
  /**
20
+ * @spec Caller cancellation stops both startup and an active forward, preserving the original abort reason.
20
21
  * 起 `kubectl port-forward svc/<service> 0:<remotePort>` 并等待就绪。
21
22
  * 本地端口让 kubectl 自选(0:),从 stdout 的 "Forwarding from 127.0.0.1:<port>" 解析,
22
23
  * 避免固定端口在运维机上撞占用。调用方负责在采集结束后 stop()。
@@ -26,6 +27,8 @@ export declare function startPortForward(opts: KubectlOptions & {
26
27
  target?: PortForwardTarget;
27
28
  remotePort: number;
28
29
  timeoutMs?: number;
30
+ signal?: AbortSignal;
31
+ onDiagnostic?: (line: string) => void;
29
32
  }): Promise<PortForwardResult>;
30
33
  /** 同一次诊断可能按拓扑建立多个 forward;scope 保证异常路径也能一次性回收。 */
31
34
  export declare class PortForwardScope {
@@ -37,6 +40,8 @@ export declare class PortForwardScope {
37
40
  target: PortForwardTarget;
38
41
  remotePort: number;
39
42
  timeoutMs?: number;
43
+ signal?: AbortSignal;
44
+ onDiagnostic?: (line: string) => void;
40
45
  }): Promise<PortForwardResult>;
41
46
  stop(): void;
42
47
  }
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  PortForwardScope,
3
3
  startPortForward
4
- } from "../chunk-631vce5z.js";
5
- import"../chunk-hmah9t8e.js";
6
- import"../chunk-mn6dwsvh.js";
4
+ } from "../chunk-nftzckdy.js";
5
+ import"../chunk-rq5fc007.js";
6
+ import"../chunk-9shz0bw1.js";
7
7
  export {
8
8
  startPortForward,
9
9
  PortForwardScope
@@ -20,6 +20,8 @@ export declare class ServicePortForwarder {
20
20
  private constructor();
21
21
  static create(executor: Executor, opts: KubectlOptions & {
22
22
  namespace: string;
23
+ signal?: AbortSignal;
24
+ onDiagnostic?: (line: string) => void;
23
25
  }, starter?: StartPortForward): Promise<ServicePortForwarder>;
24
26
  get activeForwards(): readonly import("./port-forward").PortForward[];
25
27
  forward(endpoint: KubernetesEndpoint): Promise<ForwardedEndpoint>;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  ServicePortForwarder
3
- } from "../chunk-2171tajs.js";
4
- import"../chunk-j46x7j7c.js";
3
+ } from "../chunk-1ts7pswj.js";
4
+ import"../chunk-xgnz10sr.js";
5
5
  import"../chunk-6fnhzhdb.js";
6
- import"../chunk-631vce5z.js";
7
- import"../chunk-hmah9t8e.js";
8
- import"../chunk-mn6dwsvh.js";
6
+ import"../chunk-nftzckdy.js";
7
+ import"../chunk-rq5fc007.js";
8
+ import"../chunk-9shz0bw1.js";
9
9
  export {
10
10
  ServicePortForwarder
11
11
  };
@@ -25,7 +25,7 @@ export declare function findService(services: readonly KubernetesService[], endp
25
25
  export declare function findServicesForPod(services: readonly KubernetesService[], pod: KubernetesPod): KubernetesService[];
26
26
  /** Service → Pod 由 Kubernetes selector 决定,不让上层用 Pod 名称前缀猜测。 */
27
27
  export declare function findPodsForService(services: readonly KubernetesService[], pods: readonly KubernetesPod[], serviceName: string, namespace: string): KubernetesPod[];
28
- export declare function listServiceNetwork(executor: Executor, namespace: string): Promise<{
28
+ export declare function listServiceNetwork(executor: Executor, namespace: string, signal?: AbortSignal): Promise<{
29
29
  services: KubernetesService[];
30
30
  pods: KubernetesPod[];
31
31
  }>;
@@ -5,7 +5,7 @@ import {
5
5
  listServiceNetwork,
6
6
  parseServices,
7
7
  serviceIdentity
8
- } from "../chunk-j46x7j7c.js";
8
+ } from "../chunk-xgnz10sr.js";
9
9
  import"../chunk-6fnhzhdb.js";
10
10
  export {
11
11
  serviceIdentity,
@@ -10,10 +10,10 @@ import"../chunk-gm4swndx.js";
10
10
  import"../chunk-rkt41za2.js";
11
11
  import"../chunk-v3hxvnrc.js";
12
12
  import"../chunk-h8fwx0k7.js";
13
- import"../chunk-wv4jwhvj.js";
14
- import"../chunk-631vce5z.js";
15
- import"../chunk-hmah9t8e.js";
16
- import"../chunk-mn6dwsvh.js";
13
+ import"../chunk-fqrknvr8.js";
14
+ import"../chunk-nftzckdy.js";
15
+ import"../chunk-rq5fc007.js";
16
+ import"../chunk-9shz0bw1.js";
17
17
  import"../chunk-ssj93brx.js";
18
18
  export {
19
19
  openMysql,
@@ -22,10 +22,10 @@ import"../chunk-gm4swndx.js";
22
22
  import"../chunk-rkt41za2.js";
23
23
  import"../chunk-v3hxvnrc.js";
24
24
  import"../chunk-h8fwx0k7.js";
25
- import"../chunk-wv4jwhvj.js";
26
- import"../chunk-631vce5z.js";
27
- import"../chunk-hmah9t8e.js";
28
- import"../chunk-mn6dwsvh.js";
25
+ import"../chunk-fqrknvr8.js";
26
+ import"../chunk-nftzckdy.js";
27
+ import"../chunk-rq5fc007.js";
28
+ import"../chunk-9shz0bw1.js";
29
29
  import"../chunk-ssj93brx.js";
30
30
  export {
31
31
  withReadScope,
@@ -7,6 +7,8 @@ export interface OpenSearchAuth {
7
7
  }
8
8
  export interface OpenSearchOptions {
9
9
  node: string;
10
+ /** Bounded operational facts; never protocol bodies or credentials. */
11
+ onDiagnostic?: (line: string) => void;
10
12
  auth: OpenSearchAuth;
11
13
  requestTimeoutMs?: number;
12
14
  /** Per-route mapping and probe budget; query deadlines remain independent. */
@@ -41,6 +43,11 @@ export interface OpenSearchClientApi {
41
43
  };
42
44
  close(): Promise<void>;
43
45
  }
46
+ /** Safe error-chain facts for logs; driver messages/meta can contain credentials and response bodies. */
47
+ export declare function describeOpenSearchError(error: unknown): string;
48
+ export interface OpenSearchLifecycle extends ClientLifecycle {
49
+ onDiagnostic?: (line: string) => void;
50
+ }
44
51
  /** OpenSearch-specific read APIs stay outside the engine-neutral SearchEngine contract. */
45
52
  export interface OpenSearchReadApi extends SearchEngine {
46
53
  request(path: string, query?: SearchQuery): Promise<unknown>;
@@ -48,11 +55,13 @@ export interface OpenSearchReadApi extends SearchEngine {
48
55
  export declare function isOpenSearchReadApi(search: SearchEngine): search is OpenSearchReadApi;
49
56
  /** Official OpenSearch client behind the engine-neutral SearchEngine contract. */
50
57
  export declare class OpenSearchEngine implements OpenSearchReadApi {
58
+ private readonly options;
51
59
  private readonly client;
52
60
  constructor(options: OpenSearchOptions, client?: OpenSearchClientApi);
53
61
  count(index: string, query: SearchQuery): Promise<number>;
54
62
  search(index: string, body: SearchQuery): Promise<SearchResult>;
55
63
  request(path: string, query?: SearchQuery): Promise<unknown>;
64
+ /** @spec Probe deadlines abort the underlying request even when the driver stalls. */
56
65
  ping(signal?: AbortSignal, timeoutMs?: number): Promise<unknown>;
57
66
  close(): Promise<void>;
58
67
  }
@@ -66,7 +75,7 @@ export declare class OpenSearchClient implements ManagedClient, OpenSearchReadAp
66
75
  private readonly source;
67
76
  private readonly lifecycle;
68
77
  readonly signal: AbortSignal;
69
- constructor(source: ConnectionSource<OpenSearchOptions>, lifecycle?: ClientLifecycle);
78
+ constructor(source: ConnectionSource<OpenSearchOptions>, lifecycle?: OpenSearchLifecycle);
70
79
  initialize(): Promise<void>;
71
80
  count(index: string, query: SearchQuery): Promise<number>;
72
81
  search(index: string, body: SearchQuery): Promise<SearchResult>;
@@ -75,4 +84,4 @@ export declare class OpenSearchClient implements ManagedClient, OpenSearchReadAp
75
84
  close(): Promise<void>;
76
85
  dispose(): Promise<void>;
77
86
  }
78
- export declare function openOpenSearch(source: ConnectionSource<OpenSearchOptions>, lifecycle?: ClientLifecycle): Promise<OpenSearchClient>;
87
+ export declare function openOpenSearch(source: ConnectionSource<OpenSearchOptions>, lifecycle?: OpenSearchLifecycle): Promise<OpenSearchClient>;
@@ -1,20 +1,22 @@
1
1
  import {
2
2
  OpenSearchClient,
3
3
  OpenSearchEngine,
4
+ describeOpenSearchError,
4
5
  isOpenSearchReadApi,
5
6
  openOpenSearch
6
- } from "../chunk-sbt20n84.js";
7
+ } from "../chunk-vymm4g9h.js";
7
8
  import"../chunk-gm4swndx.js";
8
9
  import"../chunk-rkt41za2.js";
9
10
  import"../chunk-h8fwx0k7.js";
10
- import"../chunk-wv4jwhvj.js";
11
- import"../chunk-631vce5z.js";
12
- import"../chunk-hmah9t8e.js";
13
- import"../chunk-mn6dwsvh.js";
11
+ import"../chunk-fqrknvr8.js";
12
+ import"../chunk-nftzckdy.js";
13
+ import"../chunk-rq5fc007.js";
14
+ import"../chunk-9shz0bw1.js";
14
15
  import"../chunk-ssj93brx.js";
15
16
  export {
16
17
  openOpenSearch,
17
18
  isOpenSearchReadApi,
19
+ describeOpenSearchError,
18
20
  OpenSearchEngine,
19
21
  OpenSearchClient
20
22
  };
@@ -8,22 +8,24 @@ import"../chunk-djk4kmxb.js";
8
8
  import {
9
9
  OpenSearchClient,
10
10
  OpenSearchEngine,
11
+ describeOpenSearchError,
11
12
  isOpenSearchReadApi,
12
13
  openOpenSearch
13
- } from "../chunk-sbt20n84.js";
14
+ } from "../chunk-vymm4g9h.js";
14
15
  import"../chunk-gm4swndx.js";
15
16
  import"../chunk-rkt41za2.js";
16
17
  import"../chunk-h8fwx0k7.js";
17
- import"../chunk-wv4jwhvj.js";
18
- import"../chunk-631vce5z.js";
19
- import"../chunk-hmah9t8e.js";
20
- import"../chunk-mn6dwsvh.js";
18
+ import"../chunk-fqrknvr8.js";
19
+ import"../chunk-nftzckdy.js";
20
+ import"../chunk-rq5fc007.js";
21
+ import"../chunk-9shz0bw1.js";
21
22
  import"../chunk-ssj93brx.js";
22
23
  export {
23
24
  searchAfterPages,
24
25
  parseOpenSearchEndpoint,
25
26
  openOpenSearch,
26
27
  isOpenSearchReadApi,
28
+ describeOpenSearchError,
27
29
  OpenSearchEngine,
28
30
  OpenSearchClient
29
31
  };
@@ -2,7 +2,7 @@ export interface RuntimeProcess {
2
2
  stdout: ReadableStream<Uint8Array>;
3
3
  stderr: ReadableStream<Uint8Array>;
4
4
  exited: Promise<number>;
5
- kill(): void;
5
+ kill(signal?: NodeJS.Signals): void;
6
6
  }
7
7
  export interface SpawnProcessOptions {
8
8
  stdin?: string | Uint8Array | ReadableStream<Uint8Array>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  sleep,
3
3
  spawnProcess
4
- } from "../chunk-mn6dwsvh.js";
4
+ } from "../chunk-9shz0bw1.js";
5
5
  export {
6
6
  spawnProcess,
7
7
  sleep
@@ -9,10 +9,10 @@ import"../chunk-gm4swndx.js";
9
9
  import"../chunk-5tbzf9wd.js";
10
10
  import"../chunk-rkt41za2.js";
11
11
  import"../chunk-h8fwx0k7.js";
12
- import"../chunk-wv4jwhvj.js";
13
- import"../chunk-631vce5z.js";
14
- import"../chunk-hmah9t8e.js";
15
- import"../chunk-mn6dwsvh.js";
12
+ import"../chunk-fqrknvr8.js";
13
+ import"../chunk-nftzckdy.js";
14
+ import"../chunk-rq5fc007.js";
15
+ import"../chunk-9shz0bw1.js";
16
16
  import"../chunk-ssj93brx.js";
17
17
  export {
18
18
  parseRedisInfo,
@@ -15,10 +15,10 @@ import {
15
15
  } from "../chunk-5tbzf9wd.js";
16
16
  import"../chunk-rkt41za2.js";
17
17
  import"../chunk-h8fwx0k7.js";
18
- import"../chunk-wv4jwhvj.js";
19
- import"../chunk-631vce5z.js";
20
- import"../chunk-hmah9t8e.js";
21
- import"../chunk-mn6dwsvh.js";
18
+ import"../chunk-fqrknvr8.js";
19
+ import"../chunk-nftzckdy.js";
20
+ import"../chunk-rq5fc007.js";
21
+ import"../chunk-9shz0bw1.js";
22
22
  import"../chunk-ssj93brx.js";
23
23
  export {
24
24
  redisGroupedSampleSizes,
@@ -7,10 +7,10 @@ import"../chunk-zp1s833x.js";
7
7
  import"../chunk-v3hxvnrc.js";
8
8
  import"../chunk-x4ntb898.js";
9
9
  import"../chunk-h8fwx0k7.js";
10
- import"../chunk-wv4jwhvj.js";
11
- import"../chunk-631vce5z.js";
12
- import"../chunk-hmah9t8e.js";
13
- import"../chunk-mn6dwsvh.js";
10
+ import"../chunk-fqrknvr8.js";
11
+ import"../chunk-nftzckdy.js";
12
+ import"../chunk-rq5fc007.js";
13
+ import"../chunk-9shz0bw1.js";
14
14
  import"../chunk-ssj93brx.js";
15
15
  export {
16
16
  S3DataSource
package/dist/s3/index.js CHANGED
@@ -9,10 +9,10 @@ import {
9
9
  import"../chunk-v3hxvnrc.js";
10
10
  import"../chunk-x4ntb898.js";
11
11
  import"../chunk-h8fwx0k7.js";
12
- import"../chunk-wv4jwhvj.js";
13
- import"../chunk-631vce5z.js";
14
- import"../chunk-hmah9t8e.js";
15
- import"../chunk-mn6dwsvh.js";
12
+ import"../chunk-fqrknvr8.js";
13
+ import"../chunk-nftzckdy.js";
14
+ import"../chunk-rq5fc007.js";
15
+ import"../chunk-9shz0bw1.js";
16
16
  import"../chunk-ssj93brx.js";
17
17
  export {
18
18
  S3DataSource,
@@ -6,10 +6,10 @@ import {
6
6
  } from "../chunk-h8fwx0k7.js";
7
7
  import {
8
8
  PodRelayTransport
9
- } from "../chunk-wv4jwhvj.js";
10
- import"../chunk-631vce5z.js";
11
- import"../chunk-hmah9t8e.js";
12
- import"../chunk-mn6dwsvh.js";
9
+ } from "../chunk-fqrknvr8.js";
10
+ import"../chunk-nftzckdy.js";
11
+ import"../chunk-rq5fc007.js";
12
+ import"../chunk-9shz0bw1.js";
13
13
  import"../chunk-ssj93brx.js";
14
14
  export {
15
15
  isConnectionNetworkError,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  PodRelayTransport
3
- } from "../chunk-wv4jwhvj.js";
4
- import"../chunk-631vce5z.js";
5
- import"../chunk-hmah9t8e.js";
6
- import"../chunk-mn6dwsvh.js";
3
+ } from "../chunk-fqrknvr8.js";
4
+ import"../chunk-nftzckdy.js";
5
+ import"../chunk-rq5fc007.js";
6
+ import"../chunk-9shz0bw1.js";
7
7
  import"../chunk-ssj93brx.js";
8
8
  export {
9
9
  PodRelayTransport
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compforge/harness-toolbox",
3
- "version": "0.4.5",
3
+ "version": "0.4.8",
4
4
  "description": "Shared infrastructure clients, transports and bounded data capture",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -116,9 +116,6 @@
116
116
  "@types/node": "^22",
117
117
  "@types/ws": "^8.18.1"
118
118
  },
119
- "overrides": {
120
- "@compforge/harness-common": "file:../common"
121
- },
122
119
  "publishConfig": {
123
120
  "access": "public"
124
121
  },