@compforge/harness-toolbox 0.1.1 → 0.3.1
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/README.md +79 -4
- package/dist/{chunk-9j36zvn4.js → chunk-0cq1gx86.js} +5 -5
- package/dist/chunk-1kpbvat9.js +89 -0
- package/dist/chunk-4pdwsfcx.js +111 -0
- package/dist/chunk-a9htb6cr.js +4 -0
- package/dist/{chunk-sry9e02n.js → chunk-jkpwa8tb.js} +17 -0
- package/dist/chunk-kbewz29a.js +95 -0
- package/dist/{chunk-1at7zs0z.js → chunk-mnad4zkp.js} +3 -3
- package/dist/chunk-ntfm5e85.js +27 -0
- package/dist/chunk-y3dx8jh6.js +94 -0
- package/dist/chunk-z5pm2emz.js +4 -0
- package/dist/client-manager.d.ts +1 -14
- package/dist/client-manager.js +2 -3
- package/dist/client.d.ts +1 -5
- package/dist/client.js +6 -0
- package/dist/datasource.d.ts +2 -11
- package/dist/datasource.js +11 -5
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +10 -0
- package/dist/kubernetes/client.d.ts +6 -1
- package/dist/kubernetes/client.js +9 -85
- package/dist/kubernetes/environment.d.ts +19 -0
- package/dist/kubernetes/environment.js +43 -0
- package/dist/kubernetes/pod-log-client.js +2 -3
- package/dist/kubernetes/pod-log-datasource.d.ts +3 -3
- package/dist/kubernetes/pod-log-datasource.js +8 -7
- package/dist/kubernetes/resources.d.ts +23 -0
- package/dist/kubernetes/resources.js +8 -0
- package/dist/kubernetes/service-port-forward.js +2 -2
- package/dist/kubernetes/workload.d.ts +7 -0
- package/dist/kubernetes/workload.js +7 -0
- package/dist/mysql/client.d.ts +4 -2
- package/dist/mysql/client.js +2 -1
- package/dist/mysql/index.js +2 -1
- package/dist/mysql/readonly.d.ts +9 -0
- package/dist/mysql/readonly.js +8 -0
- package/dist/mysql/types.d.ts +13 -0
- package/dist/redis/index.js +3 -3
- package/dist/s3/datasource.d.ts +3 -3
- package/dist/s3/datasource.js +3 -3
- package/dist/s3/index.js +3 -3
- package/package.json +6 -1
- package/dist/chunk-3dt25p98.js +0 -59
- package/dist/chunk-hqx7j9xe.js +0 -14
- package/dist/{chunk-p097seg7.js → chunk-205a4vma.js} +3 -3
package/dist/datasource.d.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export { ClientManager, type ClientProvider } from "./client-manager";
|
|
3
|
-
import type { Client } from "./client";
|
|
1
|
+
export { clientKey, ClientManager, EnvironmentContext, type Client, type ClientProvider, type DataSource, type ServiceDataSource } from "@compforge/harness-common";
|
|
4
2
|
import type { Transport } from "./transport";
|
|
5
|
-
|
|
6
|
-
export interface DataSource<C extends Client> {
|
|
7
|
-
readonly key: string;
|
|
8
|
-
/** Construct only; Client.initialize owns external work. */
|
|
9
|
-
createClient(signal: AbortSignal): C;
|
|
10
|
-
}
|
|
3
|
+
export { ToolboxError, KubernetesError, type ErrorKind } from "./errors";
|
|
11
4
|
/** Resolution owns configuration semantics; transports preserve the resolved target and identity. */
|
|
12
5
|
export interface ConnectionSource<Target> {
|
|
13
6
|
resolve(): Promise<Target>;
|
|
@@ -22,5 +15,3 @@ export interface ClientLifecycle {
|
|
|
22
15
|
reason?: string;
|
|
23
16
|
}) => void;
|
|
24
17
|
}
|
|
25
|
-
/** Stable in-memory identity; connection credentials must not appear in observable cache keys. */
|
|
26
|
-
export declare function dataSourceKey(protocol: string, configuration: unknown): string;
|
package/dist/datasource.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
ClientManager,
|
|
3
|
+
EnvironmentContext,
|
|
4
|
+
clientKey
|
|
5
|
+
} from "./chunk-z5pm2emz.js";
|
|
4
6
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
KubernetesError,
|
|
8
|
+
ToolboxError
|
|
9
|
+
} from "./chunk-ntfm5e85.js";
|
|
7
10
|
export {
|
|
8
|
-
|
|
11
|
+
clientKey,
|
|
12
|
+
ToolboxError,
|
|
13
|
+
KubernetesError,
|
|
14
|
+
EnvironmentContext,
|
|
9
15
|
ClientManager
|
|
10
16
|
};
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Stable toolbox failure semantics; native causes are for debugging, not user reports. */
|
|
2
|
+
export type ErrorKind = "connection_failed" | "connection_lost" | "tls_verification_failed" | "authentication_failed" | "permission_denied" | "resource_not_found" | "timeout" | "limit_exceeded" | "invalid_response" | "operation_failed" | "invalid_argument" | "unsupported_operation";
|
|
3
|
+
export declare class ToolboxError extends Error {
|
|
4
|
+
readonly kind: ErrorKind;
|
|
5
|
+
readonly code?: number | string;
|
|
6
|
+
constructor(message: string, options: {
|
|
7
|
+
kind: ErrorKind;
|
|
8
|
+
code?: number | string;
|
|
9
|
+
cause?: unknown;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export declare class KubernetesError extends ToolboxError {
|
|
13
|
+
}
|
|
14
|
+
export declare function kubernetesHttpError(status: number): KubernetesError;
|
package/dist/errors.js
ADDED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import type { Client } from "../client";
|
|
2
2
|
import { type Executor, type KubectlOptions, type ExecTarget, type RunOptions } from "./executor";
|
|
3
3
|
import type { KubernetesEndpoint } from "./endpoint";
|
|
4
|
+
import type { Workload, WorkloadInstance } from "@compforge/harness-common";
|
|
5
|
+
import { type ResourceAccess, type ResourceLimits } from "./resources";
|
|
4
6
|
/** Owns cluster transports; protocol callers borrow this client without closing it. */
|
|
5
7
|
export declare class KubernetesClient implements Client {
|
|
6
8
|
#private;
|
|
7
9
|
private readonly kube;
|
|
10
|
+
private readonly resourceLimits;
|
|
8
11
|
readonly signal: AbortSignal;
|
|
9
12
|
constructor(kube: KubectlOptions & {
|
|
10
13
|
namespace: string;
|
|
11
|
-
}, signal?: AbortSignal, executor?: Executor);
|
|
14
|
+
}, signal?: AbortSignal, executor?: Executor, resourceLimits?: ResourceLimits, resources?: ResourceAccess);
|
|
12
15
|
initialize(): Promise<void>;
|
|
16
|
+
/** environment is a stable target ID from the caller's registry, not access configuration. */
|
|
17
|
+
resolveWorkload(workload: Workload, environment: string): Promise<WorkloadInstance[]>;
|
|
13
18
|
run(namespace: string, command: string[], options?: RunOptions): Promise<import("./executor").ExecResult>;
|
|
14
19
|
exec(namespace: string, target: ExecTarget, command: string[], options?: RunOptions): Promise<import("./executor").ExecResult>;
|
|
15
20
|
forward(namespace: string, target: KubernetesEndpoint): Promise<import("./service-port-forward").ForwardedEndpoint>;
|
|
@@ -1,92 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "../chunk-
|
|
2
|
+
KubernetesClient
|
|
3
|
+
} from "../chunk-4pdwsfcx.js";
|
|
4
|
+
import"../chunk-205a4vma.js";
|
|
5
|
+
import"../chunk-hv2kx47y.js";
|
|
4
6
|
import"../chunk-j46x7j7c.js";
|
|
5
7
|
import"../chunk-6fnhzhdb.js";
|
|
6
|
-
import"../chunk-
|
|
7
|
-
import {
|
|
8
|
-
KubectlExecutor
|
|
9
|
-
} from "../chunk-0rs1aacd.js";
|
|
8
|
+
import"../chunk-0rs1aacd.js";
|
|
10
9
|
import"../chunk-ztenxgjv.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#controller = new AbortController;
|
|
16
|
-
signal;
|
|
17
|
-
#executors = new Map;
|
|
18
|
-
#forwarders = new Map;
|
|
19
|
-
#operations = new Set;
|
|
20
|
-
#disposal;
|
|
21
|
-
constructor(kube, signal, executor) {
|
|
22
|
-
this.kube = kube;
|
|
23
|
-
this.signal = signal ? AbortSignal.any([signal, this.#controller.signal]) : this.#controller.signal;
|
|
24
|
-
if (executor)
|
|
25
|
-
this.#executors.set(kube.namespace, executor);
|
|
26
|
-
}
|
|
27
|
-
async initialize() {
|
|
28
|
-
this.signal.throwIfAborted();
|
|
29
|
-
}
|
|
30
|
-
#executor(namespace) {
|
|
31
|
-
let executor = this.#executors.get(namespace);
|
|
32
|
-
if (!executor) {
|
|
33
|
-
executor = new KubectlExecutor({ ...this.kube, namespace });
|
|
34
|
-
this.#executors.set(namespace, executor);
|
|
35
|
-
}
|
|
36
|
-
return executor;
|
|
37
|
-
}
|
|
38
|
-
#track(work) {
|
|
39
|
-
this.signal.throwIfAborted();
|
|
40
|
-
const pending = Promise.resolve().then(() => {
|
|
41
|
-
this.signal.throwIfAborted();
|
|
42
|
-
return work();
|
|
43
|
-
});
|
|
44
|
-
this.#operations.add(pending);
|
|
45
|
-
pending.then(() => this.#operations.delete(pending), () => this.#operations.delete(pending));
|
|
46
|
-
return pending;
|
|
47
|
-
}
|
|
48
|
-
#options(options) {
|
|
49
|
-
return { ...options, signal: options?.signal ? AbortSignal.any([this.signal, options.signal]) : this.signal };
|
|
50
|
-
}
|
|
51
|
-
run(namespace, command, options) {
|
|
52
|
-
return this.#track(() => this.#executor(namespace).run(command, this.#options(options)));
|
|
53
|
-
}
|
|
54
|
-
exec(namespace, target, command, options) {
|
|
55
|
-
return this.#track(() => this.#executor(namespace).exec(target, command, this.#options(options)));
|
|
56
|
-
}
|
|
57
|
-
forward(namespace, target) {
|
|
58
|
-
return this.#track(async () => {
|
|
59
|
-
let pending = this.#forwarders.get(namespace);
|
|
60
|
-
if (!pending) {
|
|
61
|
-
pending = ServicePortForwarder.create(this.#executor(namespace), { ...this.kube, namespace });
|
|
62
|
-
this.#forwarders.set(namespace, pending);
|
|
63
|
-
pending.catch(() => {
|
|
64
|
-
if (this.#forwarders.get(namespace) === pending)
|
|
65
|
-
this.#forwarders.delete(namespace);
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
const forwarder = await pending;
|
|
69
|
-
this.signal.throwIfAborted();
|
|
70
|
-
return forwarder.forward(target);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
dispose() {
|
|
74
|
-
return this.#disposal ??= (async () => {
|
|
75
|
-
this.#controller.abort(new Error("Kubernetes client disposed"));
|
|
76
|
-
await Promise.allSettled(this.#operations);
|
|
77
|
-
const results = await Promise.allSettled([...this.#forwarders.values()].map(async (pending) => {
|
|
78
|
-
const forwarder = await pending.catch(() => {
|
|
79
|
-
return;
|
|
80
|
-
});
|
|
81
|
-
forwarder?.stop();
|
|
82
|
-
}));
|
|
83
|
-
this.#forwarders.clear();
|
|
84
|
-
const errors = results.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
85
|
-
if (errors.length)
|
|
86
|
-
throw new AggregateError(errors, "Kubernetes client cleanup failed");
|
|
87
|
-
})();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
10
|
+
import"../chunk-1kpbvat9.js";
|
|
11
|
+
import"../chunk-y3dx8jh6.js";
|
|
12
|
+
import"../chunk-v3hxvnrc.js";
|
|
13
|
+
import"../chunk-ntfm5e85.js";
|
|
90
14
|
export {
|
|
91
15
|
KubernetesClient
|
|
92
16
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ClientProvider, type ClientManager } from "../client";
|
|
2
|
+
import type { Environment } from "@compforge/harness-common";
|
|
3
|
+
import { KubernetesClient } from "./client";
|
|
4
|
+
import type { KubectlOptions } from "./executor";
|
|
5
|
+
import type { ResourceLimits } from "./resources";
|
|
6
|
+
/** Cluster access is a client provider; the execution owns client lifetime. */
|
|
7
|
+
export declare class KubernetesEnvironment implements Environment, ClientProvider<KubernetesClient> {
|
|
8
|
+
#private;
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly kind = "kubernetes";
|
|
11
|
+
readonly clientKey: string;
|
|
12
|
+
/** Deployment metadata only; not part of client reuse or access configuration. */
|
|
13
|
+
readonly imageRegistry?: string;
|
|
14
|
+
constructor(name: string, kube: KubectlOptions & {
|
|
15
|
+
namespace: string;
|
|
16
|
+
imageRegistry?: string;
|
|
17
|
+
}, limits: ResourceLimits);
|
|
18
|
+
createClient(_clients: Pick<ClientManager, "get">, signal: AbortSignal): KubernetesClient;
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KubernetesClient
|
|
3
|
+
} from "../chunk-4pdwsfcx.js";
|
|
4
|
+
import"../chunk-205a4vma.js";
|
|
5
|
+
import"../chunk-hv2kx47y.js";
|
|
6
|
+
import"../chunk-j46x7j7c.js";
|
|
7
|
+
import"../chunk-6fnhzhdb.js";
|
|
8
|
+
import"../chunk-0rs1aacd.js";
|
|
9
|
+
import"../chunk-ztenxgjv.js";
|
|
10
|
+
import"../chunk-1kpbvat9.js";
|
|
11
|
+
import"../chunk-y3dx8jh6.js";
|
|
12
|
+
import {
|
|
13
|
+
clientKey
|
|
14
|
+
} from "../chunk-a9htb6cr.js";
|
|
15
|
+
import"../chunk-v3hxvnrc.js";
|
|
16
|
+
import"../chunk-ntfm5e85.js";
|
|
17
|
+
|
|
18
|
+
// src/kubernetes/environment.ts
|
|
19
|
+
class KubernetesEnvironment {
|
|
20
|
+
name;
|
|
21
|
+
kind = "kubernetes";
|
|
22
|
+
clientKey;
|
|
23
|
+
imageRegistry;
|
|
24
|
+
#kube;
|
|
25
|
+
#limits;
|
|
26
|
+
constructor(name, kube, limits) {
|
|
27
|
+
this.name = name;
|
|
28
|
+
this.imageRegistry = kube.imageRegistry;
|
|
29
|
+
this.#kube = Object.freeze({
|
|
30
|
+
namespace: kube.namespace,
|
|
31
|
+
kubeconfig: kube.kubeconfig,
|
|
32
|
+
context: kube.context
|
|
33
|
+
});
|
|
34
|
+
this.#limits = Object.freeze({ ...limits });
|
|
35
|
+
this.clientKey = clientKey("kubernetes-client", [this.#kube, this.#limits]);
|
|
36
|
+
}
|
|
37
|
+
createClient(_clients, signal) {
|
|
38
|
+
return new KubernetesClient(this.#kube, signal, undefined, this.#limits);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
KubernetesEnvironment
|
|
43
|
+
};
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PodLogClient
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-mnad4zkp.js";
|
|
4
4
|
import"../chunk-8nm9f0hh.js";
|
|
5
5
|
import"../chunk-mp88s7r7.js";
|
|
6
6
|
import"../chunk-1vfwvgkj.js";
|
|
7
|
-
import"../chunk-
|
|
8
|
-
import"../chunk-3dt25p98.js";
|
|
7
|
+
import"../chunk-a9htb6cr.js";
|
|
9
8
|
import"../chunk-v3hxvnrc.js";
|
|
10
9
|
export {
|
|
11
10
|
PodLogClient
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DataSource } from "../datasource";
|
|
1
|
+
import { type DataSource, type ClientManager } from "../datasource";
|
|
2
2
|
import type { ConcurrencyPool } from "../concurrency";
|
|
3
3
|
import { PodLogClient } from "./pod-log-client";
|
|
4
4
|
import type { PodLogByteBudget, PodLogCapturePolicy } from "./log-capture-plan";
|
|
@@ -7,11 +7,11 @@ export declare class PodLogDataSource implements DataSource<PodLogClient> {
|
|
|
7
7
|
private readonly pool;
|
|
8
8
|
private readonly budget;
|
|
9
9
|
private readonly policy;
|
|
10
|
-
readonly
|
|
10
|
+
readonly clientKey: string;
|
|
11
11
|
constructor(target: {
|
|
12
12
|
kubeconfig?: string;
|
|
13
13
|
context?: string;
|
|
14
14
|
namespace: string;
|
|
15
15
|
}, pool: ConcurrencyPool, budget: PodLogByteBudget, policy: PodLogCapturePolicy);
|
|
16
|
-
createClient(signal: AbortSignal): PodLogClient;
|
|
16
|
+
createClient(_clients: Pick<ClientManager, "get">, signal: AbortSignal): PodLogClient;
|
|
17
17
|
}
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PodLogClient
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-mnad4zkp.js";
|
|
4
4
|
import"../chunk-8nm9f0hh.js";
|
|
5
5
|
import"../chunk-mp88s7r7.js";
|
|
6
6
|
import"../chunk-1vfwvgkj.js";
|
|
7
|
+
import"../chunk-a9htb6cr.js";
|
|
7
8
|
import {
|
|
8
|
-
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import"../chunk-3dt25p98.js";
|
|
9
|
+
clientKey
|
|
10
|
+
} from "../chunk-z5pm2emz.js";
|
|
11
11
|
import"../chunk-v3hxvnrc.js";
|
|
12
|
+
import"../chunk-ntfm5e85.js";
|
|
12
13
|
|
|
13
14
|
// src/kubernetes/pod-log-datasource.ts
|
|
14
15
|
class PodLogDataSource {
|
|
15
16
|
pool;
|
|
16
17
|
budget;
|
|
17
18
|
policy;
|
|
18
|
-
|
|
19
|
+
clientKey;
|
|
19
20
|
constructor(target, pool, budget, policy) {
|
|
20
21
|
this.pool = pool;
|
|
21
22
|
this.budget = budget;
|
|
22
23
|
this.policy = policy;
|
|
23
|
-
this.
|
|
24
|
+
this.clientKey = clientKey("pod-log", target);
|
|
24
25
|
}
|
|
25
|
-
createClient(signal) {
|
|
26
|
+
createClient(_clients, signal) {
|
|
26
27
|
return new PodLogClient(this.pool, signal, this.policy, this.budget);
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { KubectlOptions } from "./executor";
|
|
2
|
+
export interface Resource {
|
|
3
|
+
metadata?: {
|
|
4
|
+
name?: string;
|
|
5
|
+
namespace?: string;
|
|
6
|
+
uid?: string;
|
|
7
|
+
};
|
|
8
|
+
spec?: {
|
|
9
|
+
selector?: unknown;
|
|
10
|
+
};
|
|
11
|
+
items?: Resource[];
|
|
12
|
+
kind?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ResourceAccess {
|
|
15
|
+
get(namespace: string, resource: string, name?: string, selector?: string): Promise<Resource>;
|
|
16
|
+
}
|
|
17
|
+
export interface ResourceLimits {
|
|
18
|
+
timeoutMs: number;
|
|
19
|
+
concurrency: number;
|
|
20
|
+
maxBytes: number;
|
|
21
|
+
}
|
|
22
|
+
/** Native JSON reads use the same client-node auth/TLS path as native Pod logs. */
|
|
23
|
+
export declare function resourceAccess(options: KubectlOptions, signal: AbortSignal, limits: ResourceLimits): ResourceAccess;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ServicePortForwarder
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-205a4vma.js";
|
|
4
|
+
import"../chunk-hv2kx47y.js";
|
|
4
5
|
import"../chunk-j46x7j7c.js";
|
|
5
6
|
import"../chunk-6fnhzhdb.js";
|
|
6
|
-
import"../chunk-hv2kx47y.js";
|
|
7
7
|
import"../chunk-0rs1aacd.js";
|
|
8
8
|
import"../chunk-ztenxgjv.js";
|
|
9
9
|
export {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Workload, WorkloadInstance } from "@compforge/harness-common";
|
|
2
|
+
import type { ResourceAccess } from "./resources";
|
|
3
|
+
/**
|
|
4
|
+
* No readiness filter or replica selection; consumers own collection policy.
|
|
5
|
+
* @rule environment is the caller's stable, non-secret target ID, independent of access routes.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveWorkload(access: ResourceAccess, workload: Workload, namespace: string, environment: string): Promise<WorkloadInstance[]>;
|
package/dist/mysql/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Client } from "../client";
|
|
2
2
|
import { type Connection, type ConnectionOptions } from "mysql2/promise";
|
|
3
|
-
import type { Database, DatabaseTarget, DatabaseRow } from "./types";
|
|
3
|
+
import type { Database, DatabaseTarget, DatabaseRow, DatabaseQueryLimits, DatabaseQueryResult } from "./types";
|
|
4
4
|
import type { ConnectionSource, ClientLifecycle } from "../datasource";
|
|
5
5
|
import { type Transport } from "../transport";
|
|
6
6
|
export interface MysqlDatabaseOptions extends ClientLifecycle {
|
|
@@ -16,6 +16,8 @@ export declare class MysqlDatabase implements Database {
|
|
|
16
16
|
private readonly connect;
|
|
17
17
|
constructor(transports: readonly Transport[], options: MysqlDatabaseOptions, connect?: ConnectionFactory);
|
|
18
18
|
query(target: DatabaseTarget, sql: string, values: readonly unknown[]): Promise<DatabaseRow[]>;
|
|
19
|
+
/** Bounded, single-statement prepared execution on an isolated READ ONLY session (native only). */
|
|
20
|
+
queryReadonly(target: DatabaseTarget, sql: string, values: readonly unknown[], limits: DatabaseQueryLimits): Promise<DatabaseQueryResult>;
|
|
19
21
|
initialize(target: DatabaseTarget): Promise<void>;
|
|
20
22
|
queryOne(target: DatabaseTarget, sql: string, values: readonly unknown[]): Promise<DatabaseRow | undefined>;
|
|
21
23
|
close(): Promise<void>;
|
|
@@ -28,7 +30,7 @@ export declare class MysqlClient<Target extends DatabaseTarget = DatabaseTarget>
|
|
|
28
30
|
readonly signal: AbortSignal;
|
|
29
31
|
constructor(source: ConnectionSource<Target>, options: MysqlDatabaseOptions);
|
|
30
32
|
initialize(): Promise<void>;
|
|
31
|
-
get database():
|
|
33
|
+
get database(): MysqlDatabase;
|
|
32
34
|
get target(): Target;
|
|
33
35
|
dispose(): Promise<void>;
|
|
34
36
|
}
|
package/dist/mysql/client.js
CHANGED
package/dist/mysql/index.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Connection } from "mysql2/promise";
|
|
2
|
+
import type { DatabaseQueryLimits, DatabaseQueryResult } from "./types";
|
|
3
|
+
export declare function validateQueryLimits(limits: DatabaseQueryLimits): void;
|
|
4
|
+
/**
|
|
5
|
+
* Owns a disposable session: setup, execution and cancellation cannot affect another borrower.
|
|
6
|
+
* Caller must classify SQL and use a least-privilege identity. READ ONLY is not a SQL sandbox
|
|
7
|
+
* (for example routines and temporary tables need additional caller policy).
|
|
8
|
+
*/
|
|
9
|
+
export declare function queryReadonlySession(connection: Connection, sql: string, values: readonly unknown[], limits: DatabaseQueryLimits, signal?: AbortSignal): Promise<DatabaseQueryResult>;
|
package/dist/mysql/types.d.ts
CHANGED
|
@@ -8,6 +8,19 @@ export interface DatabaseTarget extends DatabaseIdentity {
|
|
|
8
8
|
database: string;
|
|
9
9
|
}
|
|
10
10
|
export type DatabaseRow = Record<string, unknown>;
|
|
11
|
+
export interface DatabaseQueryLimits {
|
|
12
|
+
timeoutMs: number;
|
|
13
|
+
maxRows: number;
|
|
14
|
+
/** Maximum retained UTF-8 JSON row bytes, not a limit on an individual wire packet. */
|
|
15
|
+
maxBytes: number;
|
|
16
|
+
}
|
|
17
|
+
export interface DatabaseQueryResult {
|
|
18
|
+
rows: DatabaseRow[];
|
|
19
|
+
columns: string[];
|
|
20
|
+
bytes: number;
|
|
21
|
+
truncated: boolean;
|
|
22
|
+
truncation?: "rows" | "bytes";
|
|
23
|
+
}
|
|
11
24
|
/** Storage-neutral operations shared by infrastructure consumers. */
|
|
12
25
|
export interface Database {
|
|
13
26
|
query(target: DatabaseTarget, sql: string, values: readonly unknown[]): Promise<DatabaseRow[]>;
|
package/dist/redis/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
discoverRedisTopology
|
|
3
|
+
} from "../chunk-c6z919qb.js";
|
|
1
4
|
import {
|
|
2
5
|
RedisAccess,
|
|
3
6
|
RedisClient,
|
|
@@ -9,9 +12,6 @@ import {
|
|
|
9
12
|
collectRedisKeyStats,
|
|
10
13
|
redisGroupedSampleSizes
|
|
11
14
|
} from "../chunk-jr9y0ghr.js";
|
|
12
|
-
import {
|
|
13
|
-
discoverRedisTopology
|
|
14
|
-
} from "../chunk-c6z919qb.js";
|
|
15
15
|
export {
|
|
16
16
|
redisGroupedSampleSizes,
|
|
17
17
|
parseRedisInfo,
|
package/dist/s3/datasource.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { type DataSource } from "../datasource";
|
|
1
|
+
import { type DataSource, type ClientManager } from "../datasource";
|
|
2
2
|
import { type TcpTransport } from "../transport";
|
|
3
3
|
import { S3Client } from "./client";
|
|
4
4
|
import type { S3Limits, S3Target } from "./types";
|
|
5
5
|
/** Connection details are resolved by the caller; route identity includes the cluster/context, not just a transport name. */
|
|
6
6
|
export declare class S3DataSource implements DataSource<S3Client> {
|
|
7
7
|
#private;
|
|
8
|
-
readonly
|
|
8
|
+
readonly clientKey: string;
|
|
9
9
|
constructor(target: S3Target, limits: S3Limits, route?: {
|
|
10
10
|
key: string;
|
|
11
11
|
transport: TcpTransport;
|
|
12
12
|
});
|
|
13
|
-
createClient(signal: AbortSignal): S3Client;
|
|
13
|
+
createClient(_clients: Pick<ClientManager, "get">, signal: AbortSignal): S3Client;
|
|
14
14
|
}
|
package/dist/s3/datasource.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
S3DataSource
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import"../chunk-
|
|
5
|
-
import"../chunk-3dt25p98.js";
|
|
3
|
+
} from "../chunk-0cq1gx86.js";
|
|
4
|
+
import"../chunk-z5pm2emz.js";
|
|
6
5
|
import"../chunk-zp1s833x.js";
|
|
7
6
|
import"../chunk-v3hxvnrc.js";
|
|
8
7
|
import"../chunk-x4ntb898.js";
|
|
9
8
|
import"../chunk-xy4g56g4.js";
|
|
9
|
+
import"../chunk-ntfm5e85.js";
|
|
10
10
|
export {
|
|
11
11
|
S3DataSource
|
|
12
12
|
};
|
package/dist/s3/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
S3DataSource
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import"../chunk-
|
|
5
|
-
import"../chunk-3dt25p98.js";
|
|
3
|
+
} from "../chunk-0cq1gx86.js";
|
|
4
|
+
import"../chunk-z5pm2emz.js";
|
|
6
5
|
import {
|
|
7
6
|
S3Client
|
|
8
7
|
} from "../chunk-zp1s833x.js";
|
|
9
8
|
import"../chunk-v3hxvnrc.js";
|
|
10
9
|
import"../chunk-x4ntb898.js";
|
|
11
10
|
import"../chunk-xy4g56g4.js";
|
|
11
|
+
import"../chunk-ntfm5e85.js";
|
|
12
12
|
export {
|
|
13
13
|
S3DataSource,
|
|
14
14
|
S3Client
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compforge/harness-toolbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Shared infrastructure clients, transports and bounded data capture",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"build": "bun scripts/build.ts && tsc -p tsconfig.build.json"
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
|
+
"./errors": {
|
|
13
|
+
"types": "./dist/errors.d.ts",
|
|
14
|
+
"import": "./dist/errors.js"
|
|
15
|
+
},
|
|
12
16
|
".": {
|
|
13
17
|
"types": "./dist/datasource.d.ts",
|
|
14
18
|
"import": "./dist/datasource.js"
|
|
@@ -83,6 +87,7 @@
|
|
|
83
87
|
"README.md"
|
|
84
88
|
],
|
|
85
89
|
"dependencies": {
|
|
90
|
+
"@compforge/harness-common": "0.3.0",
|
|
86
91
|
"@aws-sdk/client-s3": "3.1133.0",
|
|
87
92
|
"@kubernetes/client-node": "1.4.0",
|
|
88
93
|
"@opensearch-project/opensearch": "3.6.0",
|
package/dist/chunk-3dt25p98.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// src/client-manager.ts
|
|
2
|
-
class ClientManager {
|
|
3
|
-
#controller = new AbortController;
|
|
4
|
-
signal;
|
|
5
|
-
#clients = new Map;
|
|
6
|
-
#ready = [];
|
|
7
|
-
#disposal;
|
|
8
|
-
constructor(signal) {
|
|
9
|
-
this.signal = signal ? AbortSignal.any([signal, this.#controller.signal]) : this.#controller.signal;
|
|
10
|
-
}
|
|
11
|
-
get(source) {
|
|
12
|
-
this.signal.throwIfAborted();
|
|
13
|
-
const existing = this.#clients.get(source.key);
|
|
14
|
-
if (existing)
|
|
15
|
-
return existing;
|
|
16
|
-
const pending = Promise.resolve().then(async () => {
|
|
17
|
-
this.signal.throwIfAborted();
|
|
18
|
-
const client = source.createClient(this.signal);
|
|
19
|
-
try {
|
|
20
|
-
await client.initialize();
|
|
21
|
-
this.signal.throwIfAborted();
|
|
22
|
-
this.#ready.push(client);
|
|
23
|
-
return client;
|
|
24
|
-
} catch (error) {
|
|
25
|
-
try {
|
|
26
|
-
await client.dispose();
|
|
27
|
-
} catch (cleanup) {
|
|
28
|
-
throw new AggregateError([error, cleanup], "Client initialization and cleanup failed");
|
|
29
|
-
}
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
this.#clients.set(source.key, pending);
|
|
34
|
-
pending.catch(() => {
|
|
35
|
-
if (this.#clients.get(source.key) === pending)
|
|
36
|
-
this.#clients.delete(source.key);
|
|
37
|
-
});
|
|
38
|
-
return pending;
|
|
39
|
-
}
|
|
40
|
-
dispose() {
|
|
41
|
-
return this.#disposal ??= (async () => {
|
|
42
|
-
this.#controller.abort(new Error("Client manager disposed"));
|
|
43
|
-
const settled = await Promise.allSettled(this.#clients.values());
|
|
44
|
-
this.#clients.clear();
|
|
45
|
-
const errors = settled.flatMap((result) => result.status === "rejected" && result.reason instanceof AggregateError ? [result.reason] : []);
|
|
46
|
-
for (const client of this.#ready.splice(0).reverse()) {
|
|
47
|
-
try {
|
|
48
|
-
await client.dispose();
|
|
49
|
-
} catch (error) {
|
|
50
|
-
errors.push(error);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (errors.length)
|
|
54
|
-
throw new AggregateError(errors, "Client cleanup failed");
|
|
55
|
-
})();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export { ClientManager };
|