typekro 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/alchemy/clickhouse-schema/executor.d.ts +25 -0
- package/dist/alchemy/clickhouse-schema/executor.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/executor.js +144 -0
- package/dist/alchemy/clickhouse-schema/executor.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/index.d.ts +12 -0
- package/dist/alchemy/clickhouse-schema/index.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/index.js +11 -0
- package/dist/alchemy/clickhouse-schema/index.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/resource.d.ts +54 -0
- package/dist/alchemy/clickhouse-schema/resource.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/resource.js +158 -0
- package/dist/alchemy/clickhouse-schema/resource.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/runner.d.ts +154 -0
- package/dist/alchemy/clickhouse-schema/runner.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/runner.js +613 -0
- package/dist/alchemy/clickhouse-schema/runner.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/sql.d.ts +109 -0
- package/dist/alchemy/clickhouse-schema/sql.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/sql.js +368 -0
- package/dist/alchemy/clickhouse-schema/sql.js.map +1 -0
- package/dist/alchemy/clickhouse-schema/types.d.ts +394 -0
- package/dist/alchemy/clickhouse-schema/types.d.ts.map +1 -0
- package/dist/alchemy/clickhouse-schema/types.js +370 -0
- package/dist/alchemy/clickhouse-schema/types.js.map +1 -0
- package/dist/alchemy/index.d.ts +1 -0
- package/dist/alchemy/index.d.ts.map +1 -1
- package/dist/alchemy/index.js +2 -0
- package/dist/alchemy/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types, validation schema and errors for the `ClickHouseSchema` alchemy resource.
|
|
3
|
+
*
|
|
4
|
+
* The configurable surface is ArkType-first: {@link ClickHouseSchemaConfigSchema} is the
|
|
5
|
+
* single source of truth and the config types are INFERRED from it, so a field cannot
|
|
6
|
+
* exist in the type without existing in the schema that validates it. Only the two
|
|
7
|
+
* fields ArkType cannot express usefully are declared separately on
|
|
8
|
+
* {@link ClickHouseSchemaProps}: `kubeConfig` (a structural TypeScript type owned by the
|
|
9
|
+
* client provider) and `executor` (a runtime-only injection point, deliberately not
|
|
10
|
+
* serializable — mirroring `TypeKroResourceProps.deployer`).
|
|
11
|
+
*/
|
|
12
|
+
import { TypeKroError } from '../../core/errors.js';
|
|
13
|
+
import type { SerializableKubeConfigOptions } from '../types.js';
|
|
14
|
+
/**
|
|
15
|
+
* A plaintext credential must never be representable in props: it would be persisted
|
|
16
|
+
* verbatim into the alchemy state store. `client` therefore REJECTS undeclared keys, so
|
|
17
|
+
* `password` (and any near-miss spelling of it) fails validation instead of being
|
|
18
|
+
* silently dropped and leaving the author believing they configured authentication.
|
|
19
|
+
*/
|
|
20
|
+
export declare const ClickHouseSchemaClientSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
21
|
+
user?: string;
|
|
22
|
+
passwordEnv?: string;
|
|
23
|
+
database?: string;
|
|
24
|
+
port?: number;
|
|
25
|
+
}, {}>;
|
|
26
|
+
/** How to reach the ClickHouse server: a namespace, a label selector, and a container. */
|
|
27
|
+
export declare const ClickHouseSchemaTargetSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
28
|
+
namespace: string;
|
|
29
|
+
podSelector: Record<string, string>;
|
|
30
|
+
container?: string;
|
|
31
|
+
}, {}>;
|
|
32
|
+
/** Bounded wait for a Ready server pod before the first exec. */
|
|
33
|
+
export declare const ClickHouseSchemaWaitForPodSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
34
|
+
timeoutMs: number;
|
|
35
|
+
}, {}>;
|
|
36
|
+
/** Bounded retry of TRANSIENT exec failures. A SQL error is never retried. */
|
|
37
|
+
export declare const ClickHouseSchemaRetrySchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
38
|
+
maxAttempts?: number;
|
|
39
|
+
backoffMs?: number;
|
|
40
|
+
}, {}>;
|
|
41
|
+
/**
|
|
42
|
+
* How the statements reach EVERY server, not just the one the exec landed on.
|
|
43
|
+
*
|
|
44
|
+
* ClickHouse DDL is server-local by default. `CREATE TABLE …` executed on one pod creates
|
|
45
|
+
* that table on that pod and nowhere else, so on a multi-replica or multi-shard
|
|
46
|
+
* deployment a converge that touches a single pod reports success while the rest of the
|
|
47
|
+
* cluster has no schema — and then never tries again, because the fingerprint says the
|
|
48
|
+
* work is done. Two mechanisms make DDL cluster-wide, and this resource requires one of
|
|
49
|
+
* them to be chosen explicitly:
|
|
50
|
+
*
|
|
51
|
+
* - `fanout` (the default) — TypeKro runs the ordered statement list against EVERY pod
|
|
52
|
+
* matching the selector, in turn. It needs nothing from the cluster (no Keeper, no
|
|
53
|
+
* `Replicated` database engine) and leans on exactly the idempotence the statements
|
|
54
|
+
* already promise. It is ALL OR NOTHING: every matching pod that is not terminating or
|
|
55
|
+
* finished must become Ready within `waitForPod.timeoutMs` and must carry the requested
|
|
56
|
+
* container, or the converge fails — so a StatefulSet mid-rollout makes the resource
|
|
57
|
+
* wait, and then fail, rather than fingerprint a half-applied schema. The pod set is
|
|
58
|
+
* recorded in state, so a scale-out or a replaced pod re-applies even though the
|
|
59
|
+
* statements did not change. A single-replica installation is a one-pod fanout — which
|
|
60
|
+
* is why the default is also the correct setting there.
|
|
61
|
+
* - `onCluster` — the statements distribute themselves and TypeKro runs them ONCE, on the
|
|
62
|
+
* first Ready pod; pods that are still rolling are Keeper's problem, not this converge's,
|
|
63
|
+
* which is what makes this the right mode on a large cluster. That is only true if each
|
|
64
|
+
* statement actually says so, so every statement is validated at construction; see
|
|
65
|
+
* {@link ClickHouseSchemaConfigSchema}.
|
|
66
|
+
*
|
|
67
|
+
* @see https://clickhouse.com/docs/sql-reference/distributed-ddl
|
|
68
|
+
*/
|
|
69
|
+
export declare const ClickHouseSchemaExecutionSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
70
|
+
mode: "fanout";
|
|
71
|
+
} | {
|
|
72
|
+
mode: "onCluster";
|
|
73
|
+
cluster: string;
|
|
74
|
+
}, {}>;
|
|
75
|
+
export type ClickHouseSchemaExecution = typeof ClickHouseSchemaExecutionSchema.infer;
|
|
76
|
+
/** Applied when an author declares no execution model. */
|
|
77
|
+
export declare const DEFAULT_EXECUTION: ClickHouseSchemaExecution;
|
|
78
|
+
/**
|
|
79
|
+
* The configurable (serializable) surface of a `ClickHouseSchema` resource.
|
|
80
|
+
*
|
|
81
|
+
* IDEMPOTENCE IS THE AUTHOR'S CONTRACT. Every statement is re-run whenever the
|
|
82
|
+
* fingerprint changes, so each one must be safe to execute against a database where
|
|
83
|
+
* it has already been executed: `CREATE DATABASE IF NOT EXISTS`, `CREATE TABLE IF NOT
|
|
84
|
+
* EXISTS`, `CREATE OR REPLACE VIEW`, `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`,
|
|
85
|
+
* `DROP ... IF EXISTS`. TypeKro cannot verify that property — it does not parse SQL —
|
|
86
|
+
* so a non-idempotent statement surfaces as a converge that fails the second time.
|
|
87
|
+
*/
|
|
88
|
+
export declare const ClickHouseSchemaConfigSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
89
|
+
target: {
|
|
90
|
+
namespace: string;
|
|
91
|
+
podSelector: Record<string, string>;
|
|
92
|
+
container?: string;
|
|
93
|
+
};
|
|
94
|
+
statements: string[];
|
|
95
|
+
onDelete: import("arktype/internal/attributes.ts").Default<"retain" | "run", "retain">;
|
|
96
|
+
execution: import("arktype/internal/attributes.ts").Default<{
|
|
97
|
+
mode: "fanout";
|
|
98
|
+
} | {
|
|
99
|
+
mode: "onCluster";
|
|
100
|
+
cluster: string;
|
|
101
|
+
}, {
|
|
102
|
+
mode: "fanout";
|
|
103
|
+
}>;
|
|
104
|
+
client?: {
|
|
105
|
+
user?: string;
|
|
106
|
+
passwordEnv?: string;
|
|
107
|
+
database?: string;
|
|
108
|
+
port?: number;
|
|
109
|
+
};
|
|
110
|
+
settings?: Record<string, string | number>;
|
|
111
|
+
deleteStatements?: string[];
|
|
112
|
+
waitForPod?: {
|
|
113
|
+
timeoutMs: number;
|
|
114
|
+
};
|
|
115
|
+
maxReconcilePasses?: number;
|
|
116
|
+
statementTimeoutMs?: number;
|
|
117
|
+
retry?: {
|
|
118
|
+
maxAttempts?: number;
|
|
119
|
+
backoffMs?: number;
|
|
120
|
+
};
|
|
121
|
+
}, {}>;
|
|
122
|
+
/** Author-facing (pre-validation) config: schema defaults are still optional here. */
|
|
123
|
+
export type ClickHouseSchemaConfigInput = typeof ClickHouseSchemaConfigSchema.inferIn;
|
|
124
|
+
/** Validated config: schema defaults have been applied. */
|
|
125
|
+
export type ClickHouseSchemaConfig = typeof ClickHouseSchemaConfigSchema.infer;
|
|
126
|
+
export type ClickHouseSchemaTarget = typeof ClickHouseSchemaTargetSchema.infer;
|
|
127
|
+
export type ClickHouseSchemaClient = typeof ClickHouseSchemaClientSchema.infer;
|
|
128
|
+
/** Non-serializable additions ArkType does not describe. */
|
|
129
|
+
interface ClickHouseSchemaNonSchemaProps {
|
|
130
|
+
/**
|
|
131
|
+
* Durable cluster connection state, exactly as `KroResource` accepts it. Omit to use
|
|
132
|
+
* the ambient kubeconfig.
|
|
133
|
+
*/
|
|
134
|
+
readonly kubeConfig?: SerializableKubeConfigOptions;
|
|
135
|
+
/**
|
|
136
|
+
* Injected transport. Runtime-only — like `TypeKroResourceProps.deployer`, this does
|
|
137
|
+
* not survive alchemy state rehydration, so a resource that relies on it must be
|
|
138
|
+
* reconstructed by the same process. Its purpose is testing and embedding.
|
|
139
|
+
*/
|
|
140
|
+
readonly executor?: ClickHouseExecutor;
|
|
141
|
+
/**
|
|
142
|
+
* Alchemy ordering-only input: the channel that makes "run after the ClickHouse
|
|
143
|
+
* instance is Ready" a real dependency edge rather than a coincidence of statement
|
|
144
|
+
* order in the Stack body. Pass an alchemy `Output` derived from the instance's
|
|
145
|
+
* `KroResource` handle and alchemy deploys that resource first:
|
|
146
|
+
*
|
|
147
|
+
* ```ts
|
|
148
|
+
* readyBarrier: Output.map(Output.all(Output.of(instance)), () => true)
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* Only the resolved scalar is persisted — the same shape as
|
|
152
|
+
* `TypeKroResourceProps.schedulingBarrier` — so the barrier orders the converge
|
|
153
|
+
* without copying an unrelated resource's outputs into this one's state.
|
|
154
|
+
*/
|
|
155
|
+
readonly readyBarrier?: boolean;
|
|
156
|
+
}
|
|
157
|
+
/** What an author passes to `clickHouseSchema(id, props)`. */
|
|
158
|
+
export type ClickHouseSchemaProps = ClickHouseSchemaConfigInput & ClickHouseSchemaNonSchemaProps;
|
|
159
|
+
/** What the provider receives: validated config plus the non-schema additions. */
|
|
160
|
+
export type ClickHouseSchemaResourceProps = ClickHouseSchemaConfig & ClickHouseSchemaNonSchemaProps;
|
|
161
|
+
/**
|
|
162
|
+
* One pod an apply executed against, identified by NAME AND UID.
|
|
163
|
+
*
|
|
164
|
+
* The name alone is not an identity. A StatefulSet replica that is deleted and recreated
|
|
165
|
+
* — a node drain, a CHI template change, a `kubectl delete pod` — comes back as
|
|
166
|
+
* `chi-orders-0-0-0` again, with a fresh empty disk and no schema, and a recorded set of
|
|
167
|
+
* names cannot tell that apart from the pod that was there before. `metadata.uid` can: it
|
|
168
|
+
* is unique per pod OBJECT and never reused.
|
|
169
|
+
*
|
|
170
|
+
* The guarantee this buys, precisely:
|
|
171
|
+
*
|
|
172
|
+
* - a pod whose UID CHANGED is a different pod object — a replacement — and the statements
|
|
173
|
+
* re-apply to it;
|
|
174
|
+
* - a pod that keeps its UID does NOT re-apply, even after a container restart or a server
|
|
175
|
+
* crash-loop, and that is correct: the pod object survived, so either its PersistentVolume
|
|
176
|
+
* survived with it (and the schema with that) or the `Replicated`/`ON CLUSTER` metadata in
|
|
177
|
+
* Keeper did. Re-running the whole ordered list on every container restart would be churn,
|
|
178
|
+
* not safety.
|
|
179
|
+
*/
|
|
180
|
+
export interface ClickHouseSchemaAppliedPod {
|
|
181
|
+
readonly name: string;
|
|
182
|
+
/**
|
|
183
|
+
* `metadata.uid`.
|
|
184
|
+
*
|
|
185
|
+
* `undefined` only when the transport did not report one — an injected executor whose pod
|
|
186
|
+
* summaries omit it. An entry with no UID compares by name alone, which is exactly the
|
|
187
|
+
* pre-UID behaviour, so nothing silently gains a guarantee it cannot keep.
|
|
188
|
+
*/
|
|
189
|
+
readonly uid?: string;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Persisted state / resource outputs.
|
|
193
|
+
*
|
|
194
|
+
* `fingerprint` is what makes the resource diffable: an unchanged fingerprint against an
|
|
195
|
+
* unchanged target is a no-op converge, so a stack that redeploys hourly issues no DDL.
|
|
196
|
+
*/
|
|
197
|
+
export interface ClickHouseSchemaState {
|
|
198
|
+
/** sha256 over the ordered statements, the settings and the client configuration. */
|
|
199
|
+
readonly fingerprint: string;
|
|
200
|
+
/** ISO-8601 instant the statements were last applied. */
|
|
201
|
+
readonly appliedAt: string;
|
|
202
|
+
readonly statementCount: number;
|
|
203
|
+
/** Database the statements ran against (`default` unless `client.database` is set). */
|
|
204
|
+
readonly database: string;
|
|
205
|
+
/** Where the statements ran, so a target change is visible in state and forces a re-apply. */
|
|
206
|
+
readonly target: ClickHouseSchemaTarget;
|
|
207
|
+
/**
|
|
208
|
+
* Sorted NAMES of every pod the last apply executed against.
|
|
209
|
+
*
|
|
210
|
+
* Retained for compatibility and for reading state at a glance; {@link pods} is the
|
|
211
|
+
* load-bearing field and carries the same pods in the same order. A name-only set cannot
|
|
212
|
+
* see a same-name replacement, which is why the comparison moved.
|
|
213
|
+
*/
|
|
214
|
+
readonly podNames: readonly string[];
|
|
215
|
+
/**
|
|
216
|
+
* EVERY pod the last apply executed against, as `{ name, uid }` pairs, sorted by name.
|
|
217
|
+
*
|
|
218
|
+
* Load-bearing under `execution.mode: 'fanout'`, not informational: a converge compares
|
|
219
|
+
* the live matching pod set against this one by name AND UID, so a scale-out, a removed
|
|
220
|
+
* replica, or a pod REPLACED under the same name re-applies the statements even though
|
|
221
|
+
* the fingerprint is unchanged. See {@link ClickHouseSchemaAppliedPod} for exactly what
|
|
222
|
+
* that guarantees. Under `onCluster` it records the single initiating pod.
|
|
223
|
+
*
|
|
224
|
+
* It is always the set the statements ACTUALLY reached, and under `fanout` it is never
|
|
225
|
+
* empty: the reconcile loop keeps going until a re-list observes a NON-EMPTY set in which
|
|
226
|
+
* every pod has been applied to and which matches the observation before it, and fails
|
|
227
|
+
* rather than record a set that does not cover what is live.
|
|
228
|
+
*
|
|
229
|
+
* `undefined` in state written before UIDs were recorded; the comparison then falls back
|
|
230
|
+
* to {@link podNames}, and the first converge to run re-writes state in the new shape.
|
|
231
|
+
*/
|
|
232
|
+
readonly pods?: readonly ClickHouseSchemaAppliedPod[];
|
|
233
|
+
/**
|
|
234
|
+
* Credential-free identity of the cluster the statements were applied to — sha256 over
|
|
235
|
+
* the current context's cluster name, server URL and CA material, the same shape the
|
|
236
|
+
* per-cluster capability cache keys on.
|
|
237
|
+
*
|
|
238
|
+
* Without it, `namespace`/`podSelector`/`container` describe a target that two different
|
|
239
|
+
* kubeconfigs answer to identically: re-pointing the resource at a second cluster would
|
|
240
|
+
* match the recorded target, match the fingerprint, and skip the DDL entirely.
|
|
241
|
+
* `undefined` when the kubeconfig names no current cluster, or when a caller injected an
|
|
242
|
+
* executor and supplied no kubeconfig to identify.
|
|
243
|
+
*/
|
|
244
|
+
readonly clusterId?: string;
|
|
245
|
+
}
|
|
246
|
+
/** One `clickhouse-client` invocation inside a server container. */
|
|
247
|
+
export interface ClickHouseExecCommand {
|
|
248
|
+
readonly namespace: string;
|
|
249
|
+
readonly podName: string;
|
|
250
|
+
readonly container: string;
|
|
251
|
+
readonly command: readonly string[];
|
|
252
|
+
/** Statement text. Passed on stdin so SQL never appears in the container's argv. */
|
|
253
|
+
readonly stdin: string;
|
|
254
|
+
readonly timeoutMs: number;
|
|
255
|
+
}
|
|
256
|
+
export interface ClickHouseExecResult {
|
|
257
|
+
readonly stdout: string;
|
|
258
|
+
readonly stderr: string;
|
|
259
|
+
/** 0 on success. A non-zero code is a SQL/command failure and is NEVER retried. */
|
|
260
|
+
readonly exitCode: number;
|
|
261
|
+
}
|
|
262
|
+
/** A candidate server pod, reduced to what pod selection needs. */
|
|
263
|
+
export interface ClickHousePodSummary {
|
|
264
|
+
readonly name: string;
|
|
265
|
+
/**
|
|
266
|
+
* `metadata.uid` — the identity of the pod OBJECT, unique and never reused.
|
|
267
|
+
*
|
|
268
|
+
* What makes a same-name replacement visible: a StatefulSet replica that is deleted and
|
|
269
|
+
* recreated keeps its name and comes back with an empty disk, so a set of names alone
|
|
270
|
+
* cannot tell "the pod I applied to" from "its replacement". See
|
|
271
|
+
* {@link ClickHouseSchemaAppliedPod}. `undefined` when the transport did not report one.
|
|
272
|
+
*/
|
|
273
|
+
readonly uid?: string;
|
|
274
|
+
readonly ready: boolean;
|
|
275
|
+
readonly containers: readonly string[];
|
|
276
|
+
/**
|
|
277
|
+
* `status.phase` — `Pending`, `Running`, `Succeeded`, `Failed` or `Unknown`.
|
|
278
|
+
*
|
|
279
|
+
* Load-bearing under `fanout`, which waits for every matching pod rather than taking
|
|
280
|
+
* whichever ones are Ready: a pod in a terminal phase can never become Ready, so waiting
|
|
281
|
+
* for it would only burn the whole budget before failing. `undefined` when the transport
|
|
282
|
+
* did not report one, which is treated as "still on its way".
|
|
283
|
+
*/
|
|
284
|
+
readonly phase?: string;
|
|
285
|
+
/**
|
|
286
|
+
* `metadata.deletionTimestamp` is set.
|
|
287
|
+
*
|
|
288
|
+
* A terminating pod still reports Ready for a while; exec'ing into one races the
|
|
289
|
+
* kubelet's SIGTERM, and WAITING for one is worse still — it is leaving, so it will
|
|
290
|
+
* never be Ready again. Either way it is not part of the matching set.
|
|
291
|
+
*/
|
|
292
|
+
readonly terminating?: boolean;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The exec transport.
|
|
296
|
+
*
|
|
297
|
+
* The contract that makes retries safe is the split between the two failure modes:
|
|
298
|
+
*
|
|
299
|
+
* - a REJECTED promise is a transport failure (websocket error, connection reset,
|
|
300
|
+
* API-server hiccup, timeout) and is retried;
|
|
301
|
+
* - a RESOLVED result with a non-zero `exitCode` is a SQL failure and is not.
|
|
302
|
+
*
|
|
303
|
+
* Retrying a failed statement would be wrong in general — a partially applied
|
|
304
|
+
* non-idempotent statement must surface, not be re-issued.
|
|
305
|
+
*/
|
|
306
|
+
export interface ClickHouseExecutor {
|
|
307
|
+
listPods(namespace: string, podSelector: Readonly<Record<string, string>>, abortSignal?: AbortSignal): Promise<readonly ClickHousePodSummary[]>;
|
|
308
|
+
exec(command: ClickHouseExecCommand, abortSignal?: AbortSignal): Promise<ClickHouseExecResult>;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* A statement failed, a pod never became Ready, or the transport gave up.
|
|
312
|
+
*
|
|
313
|
+
* SECURITY: the failing statement's TEXT is never carried on the error — only its
|
|
314
|
+
* INDEX. Statements should not contain credentials (bind them through the server's own
|
|
315
|
+
* configuration, as the S3 storage compiler does), but a `CREATE TABLE ... S3(...,
|
|
316
|
+
* aws_secret_access_key)` would, and ClickHouse echoes the offending fragment back in
|
|
317
|
+
* its own message. Every message that reaches this error is passed through
|
|
318
|
+
* {@link redactClickHouseText} first.
|
|
319
|
+
*/
|
|
320
|
+
export declare class ClickHouseSchemaError extends TypeKroError {
|
|
321
|
+
/** The alchemy resource `id` — the logical name the author gave THIS schema. */
|
|
322
|
+
readonly resourceId: string;
|
|
323
|
+
/** Index into `statements` (or `deleteStatements`), or `undefined` outside statement execution. */
|
|
324
|
+
readonly statementIndex?: number | undefined;
|
|
325
|
+
/** ClickHouse's own error code, parsed from `Code: <n>.`, when the server produced one. */
|
|
326
|
+
readonly clickHouseCode?: number | undefined;
|
|
327
|
+
/** Redacted, length-capped server output — see {@link redactClickHouseOutput}. */
|
|
328
|
+
readonly detail?: string | undefined;
|
|
329
|
+
/** ClickHouse's exception class (`DB::Exception`, `DB::NetException`, …). */
|
|
330
|
+
readonly clickHouseException?: string | undefined;
|
|
331
|
+
constructor(message: string,
|
|
332
|
+
/** The alchemy resource `id` — the logical name the author gave THIS schema. */
|
|
333
|
+
resourceId: string,
|
|
334
|
+
/** Index into `statements` (or `deleteStatements`), or `undefined` outside statement execution. */
|
|
335
|
+
statementIndex?: number | undefined,
|
|
336
|
+
/** ClickHouse's own error code, parsed from `Code: <n>.`, when the server produced one. */
|
|
337
|
+
clickHouseCode?: number | undefined,
|
|
338
|
+
/** Redacted, length-capped server output — see {@link redactClickHouseOutput}. */
|
|
339
|
+
detail?: string | undefined,
|
|
340
|
+
/** ClickHouse's exception class (`DB::Exception`, `DB::NetException`, …). */
|
|
341
|
+
clickHouseException?: string | undefined, options?: ErrorOptions);
|
|
342
|
+
}
|
|
343
|
+
/** Replace every line that could carry a credential with a marker. */
|
|
344
|
+
export declare function redactClickHouseText(text: string): string;
|
|
345
|
+
/**
|
|
346
|
+
* Ceiling on the server text retained on an error (~2 KiB).
|
|
347
|
+
*
|
|
348
|
+
* An echo is a diagnostic aid, not a log sink: a `DESCRIBE`-sized dump or a multi-megabyte
|
|
349
|
+
* parser trace carried into alchemy state and every log line is a liability of its own,
|
|
350
|
+
* independent of whether it contains a secret.
|
|
351
|
+
*/
|
|
352
|
+
export declare const MAX_RETAINED_DETAIL_CHARS = 2048;
|
|
353
|
+
/**
|
|
354
|
+
* What survives from a failed exec's captured output.
|
|
355
|
+
*
|
|
356
|
+
* The contract is NOT "server output with credentials filtered out" — that framing is how
|
|
357
|
+
* the keyword-matching version came to leak. It is: keep what identifies the failure, and
|
|
358
|
+
* treat every value the SUBMITTED statement contained as a secret.
|
|
359
|
+
*
|
|
360
|
+
* In order:
|
|
361
|
+
*
|
|
362
|
+
* 1. The statement text itself is replaced wherever the server echoed it back, so a
|
|
363
|
+
* definition quoted in full cannot smuggle its own literals through.
|
|
364
|
+
* 2. Every literal the statement contains — every single-quoted value, plus whatever
|
|
365
|
+
* follows `PASSWORD` / `IDENTIFIED BY` / `access_key_id` / `secret_access_key` /
|
|
366
|
+
* `aws_access_key_id` / `aws_secret_access_key` / `token` — is replaced with
|
|
367
|
+
* `<redacted>` wherever it appears. This is positional, so it catches the arguments
|
|
368
|
+
* keyword matching cannot name. Each literal is redacted in EVERY spelling it could be
|
|
369
|
+
* echoed in, longest first: the decoded value, the raw source slice between the quotes,
|
|
370
|
+
* and the value re-escaped both ways ClickHouse accepts (`\'` and `''`). A credential
|
|
371
|
+
* containing a quote is one secret with several spellings, and the server frequently
|
|
372
|
+
* quotes back the one it was given rather than the one it decoded.
|
|
373
|
+
* 3. The keyword line filter runs as a second layer, for text the statement did not
|
|
374
|
+
* account for.
|
|
375
|
+
* 4. The result is capped at {@link MAX_RETAINED_DETAIL_CHARS}.
|
|
376
|
+
*
|
|
377
|
+
* ClickHouse's error CODE and exception class are parsed out BEFORE any of this and
|
|
378
|
+
* carried separately on the error, so redaction never costs the caller the one part of
|
|
379
|
+
* the message that says what went wrong.
|
|
380
|
+
*/
|
|
381
|
+
export declare function redactClickHouseOutput(output: string, statement?: string): string;
|
|
382
|
+
/** Parse ClickHouse's `Code: 62. DB::Exception: …` prefix out of server output. */
|
|
383
|
+
export declare function parseClickHouseErrorCode(text: string): number | undefined;
|
|
384
|
+
/**
|
|
385
|
+
* Parse the exception CLASS (`DB::Exception`, `DB::NetException`, `Poco::Exception`) out
|
|
386
|
+
* of server output.
|
|
387
|
+
*
|
|
388
|
+
* Retained alongside the numeric code because the two say different things: the code
|
|
389
|
+
* names the condition, the class says which subsystem raised it — and neither can carry
|
|
390
|
+
* a credential, so both survive redaction intact.
|
|
391
|
+
*/
|
|
392
|
+
export declare function parseClickHouseExceptionName(text: string): string | undefined;
|
|
393
|
+
export {};
|
|
394
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/alchemy/clickhouse-schema/types.ts"],"names":[],"mappings":"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"}
|