@wavehouse/chtypes 0.1.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +202 -0
  3. package/README.md +442 -0
  4. package/dist/cli.d.ts +43 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +303 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/discover.d.ts +134 -0
  9. package/dist/discover.d.ts.map +1 -0
  10. package/dist/discover.js +291 -0
  11. package/dist/discover.js.map +1 -0
  12. package/dist/errors.d.ts +204 -0
  13. package/dist/errors.d.ts.map +1 -0
  14. package/dist/errors.js +228 -0
  15. package/dist/errors.js.map +1 -0
  16. package/dist/fetch.d.ts +235 -0
  17. package/dist/fetch.d.ts.map +1 -0
  18. package/dist/fetch.js +842 -0
  19. package/dist/fetch.js.map +1 -0
  20. package/dist/ffi.d.ts +346 -0
  21. package/dist/ffi.d.ts.map +1 -0
  22. package/dist/ffi.js +913 -0
  23. package/dist/ffi.js.map +1 -0
  24. package/dist/format.d.ts +104 -0
  25. package/dist/format.d.ts.map +1 -0
  26. package/dist/format.js +108 -0
  27. package/dist/format.js.map +1 -0
  28. package/dist/index.d.ts +28 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +28 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/json.d.ts +127 -0
  33. package/dist/json.d.ts.map +1 -0
  34. package/dist/json.js +577 -0
  35. package/dist/json.js.map +1 -0
  36. package/dist/library.d.ts +225 -0
  37. package/dist/library.d.ts.map +1 -0
  38. package/dist/library.js +234 -0
  39. package/dist/library.js.map +1 -0
  40. package/dist/numeric.d.ts +20 -0
  41. package/dist/numeric.d.ts.map +1 -0
  42. package/dist/numeric.js +107 -0
  43. package/dist/numeric.js.map +1 -0
  44. package/dist/paths.d.ts +47 -0
  45. package/dist/paths.d.ts.map +1 -0
  46. package/dist/paths.js +78 -0
  47. package/dist/paths.js.map +1 -0
  48. package/dist/registry.d.ts +204 -0
  49. package/dist/registry.d.ts.map +1 -0
  50. package/dist/registry.js +409 -0
  51. package/dist/registry.js.map +1 -0
  52. package/dist/results.d.ts +326 -0
  53. package/dist/results.d.ts.map +1 -0
  54. package/dist/results.js +235 -0
  55. package/dist/results.js.map +1 -0
  56. package/dist/schema.d.ts +444 -0
  57. package/dist/schema.d.ts.map +1 -0
  58. package/dist/schema.js +448 -0
  59. package/dist/schema.js.map +1 -0
  60. package/dist/settings.d.ts +43 -0
  61. package/dist/settings.d.ts.map +1 -0
  62. package/dist/settings.js +33 -0
  63. package/dist/settings.js.map +1 -0
  64. package/dist/tar.d.ts +32 -0
  65. package/dist/tar.d.ts.map +1 -0
  66. package/dist/tar.js +310 -0
  67. package/dist/tar.js.map +1 -0
  68. package/dist/transform.d.ts +73 -0
  69. package/dist/transform.d.ts.map +1 -0
  70. package/dist/transform.js +527 -0
  71. package/dist/transform.js.map +1 -0
  72. package/package.json +62 -0
package/dist/schema.js ADDED
@@ -0,0 +1,448 @@
1
+ /**
2
+ * A compiled schema — one tenant table's column list, compiled inside one
3
+ * version's library, plus the engine and TTL declarations that make `rows()`
4
+ * answer with the storage layer's verdict as well as the type layer's.
5
+ */
6
+ import { ChtypesError } from './errors.js';
7
+ import { DOC_ALL, EXPORT_NONE } from './format.js';
8
+ import { parseDocument } from './json.js';
9
+ import { batchResultOf, filterResultOf, rowResultOf, } from './results.js';
10
+ import { encodeSettings } from './settings.js';
11
+ /**
12
+ * A compiled schema — one tenant table's column list, compiled inside one
13
+ * version's library. Obtained from `Library#compileDdl`; never constructed
14
+ * directly. Release with `close()` (idempotent) or `using` / `Symbol.dispose`.
15
+ *
16
+ * Thread-safety: the C ABI forbids using one `chs_schema *` from two threads
17
+ * at once; on a single JS thread every call here is synchronous, so ordinary
18
+ * Node code satisfies that by construction. Do not share a `Schema` across
19
+ * `worker_threads`.
20
+ */
21
+ export class Schema {
22
+ native;
23
+ ddl;
24
+ /**
25
+ * The declared columns as ClickHouse canonicalised them, in declaration
26
+ * order — flattened under `flatten_nested=1`, DEFAULT-rewritten types
27
+ * (`x Int64 DEFAULT NULL` compiles as `Nullable(Int64)`), ALIAS types
28
+ * inferred. A gateway detects EPHEMERAL columns here, at compile time
29
+ * (`defaultKind === 'EPHEMERAL'`), not per row.
30
+ */
31
+ columns;
32
+ handle;
33
+ /**
34
+ * Every open `Filter` compiled from this handle, so `close()` can free them
35
+ * FIRST — the C layer does not refcount, and freeing the schema under a
36
+ * live filter is use-after-free (spec/c-abi.md §Filters, handle lifetime).
37
+ */
38
+ filters = new Set();
39
+ /**
40
+ * Every open `Block` parsed from this handle — the same non-owning rule,
41
+ * the same free-before-schema order (spec/c-abi.md §Blocks).
42
+ */
43
+ blocks = new Set();
44
+ /** @internal — obtained from `Library#compileDdl`. */
45
+ constructor(native, handle,
46
+ /** The column-declaration list this schema was compiled from, verbatim. */
47
+ ddl) {
48
+ this.native = native;
49
+ this.ddl = ddl;
50
+ this.handle = handle;
51
+ this.columns = native.columns(handle);
52
+ }
53
+ live() {
54
+ if (this.handle === null)
55
+ throw new ChtypesError('chtypes: schema is closed');
56
+ return this.handle;
57
+ }
58
+ /**
59
+ * Declare the table engine, so `rows()` applies the engine's own insert-time
60
+ * merge (`optimize_on_insert = 1`): a CollapsingMergeTree refusing an invalid
61
+ * Sign with code 117 before anything is stored, a SummingMergeTree summing
62
+ * equal keys and dropping all-zero rows, a ReplacingMergeTree deduplicating.
63
+ *
64
+ * `options.mergeTreeSettings` declares the table's MergeTree-namespace
65
+ * settings — see `EngineOptions` for the error contract (unknown name ⇒ the
66
+ * server's 115; non-default declared value ⇒ `unsupported`, never silently
67
+ * ignored). Absent/empty is structurally the plain engine declaration:
68
+ * `chs_schema_engine` takes "{}" either way.
69
+ *
70
+ * The two error classes here are the refusal/decline split and MUST be
71
+ * handled as peers — `UnsupportedError` is deliberately NOT
72
+ * `instanceof SchemaError` (spec/bindings.md rule 12):
73
+ *
74
+ * @param engine - the engine expression, e.g. `"SummingMergeTree"`,
75
+ * `"CollapsingMergeTree(sign)"`.
76
+ * @param orderBy - the sorting key, e.g. `"(day, key)"`.
77
+ * @param options - the MergeTree-namespace `SETTINGS` clause, if any.
78
+ * @throws {SchemaError} when the SERVER refused (positive code): this DDL
79
+ * can never exist and the tenant has to be told. Today that is 115, an
80
+ * unknown MergeTree setting name, with the server's own message verbatim.
81
+ * @throws {UnsupportedError} when this LIBRARY declined: an engine or
82
+ * sorting key this build does not model, a known MergeTree setting
83
+ * declared at a non-default value, or a guarded exception. A real server
84
+ * might well have accepted it — validate cautiously, fall back to the
85
+ * server, and never present the decline as a rejection.
86
+ */
87
+ setEngine(engine, orderBy, options) {
88
+ this.native.schemaEngine(this.live(), engine, orderBy, encodeSettings(options?.mergeTreeSettings));
89
+ }
90
+ /**
91
+ * Declare the table's rows TTL (`ts + INTERVAL 30 DAY`). An expired row is
92
+ * reported NOT STORED through the batch's `transformed` list.
93
+ *
94
+ * Column-level TTLs need no call: they are part of the declaration list.
95
+ *
96
+ * @param ttl - the rows-TTL expression, e.g. `"ts + INTERVAL 30 DAY"`. It is
97
+ * validated under the handle's declared compile profile when one exists.
98
+ * @throws {UnsupportedError} for a TTL form this build refuses rather than
99
+ * guesses: WHERE / GROUP BY TTLs, TO DISK/VOLUME moves, RECOMPRESS, any
100
+ * clock-reading TTL expression, and guarded exceptions. Fall back to the
101
+ * server; do not report a tenant error.
102
+ */
103
+ setTtl(ttl) {
104
+ this.native.schemaTtl(this.live(), ttl);
105
+ }
106
+ /**
107
+ * Validate and coerce ONE row body, answering exactly as this ClickHouse
108
+ * version's insert path would.
109
+ *
110
+ * There is no exception for a bad row: rejection, poisoning and declines all
111
+ * arrive as the `RowResult`'s `outcome` (see `Outcome` for the taxonomy and
112
+ * the caller's obligations per arm).
113
+ *
114
+ * @param format - the wire format code (`Format`). Binary-format support
115
+ * depends on the loaded artifact — probe, don't assume.
116
+ * @param raw - the row's bytes, exactly as they would arrive in an INSERT
117
+ * body. Always bytes, never a JS string: binary formats contain NUL bytes
118
+ * and text rows can carry invalid UTF-8 on purpose.
119
+ * @param settings - per-call settings; they win over the compile profile and
120
+ * the library defaults (except a type gate the profile declared, which the
121
+ * handle has already settled, as a real server's CREATE does).
122
+ * @returns the `RowResult` — verdict, stored values, and every silent change.
123
+ * @throws {ChtypesError} when the schema is closed, or a settings value is a
124
+ * JS `number`.
125
+ * @throws {UnsupportedError} when the artifact predates `chs_row`.
126
+ */
127
+ row(format, raw, settings) {
128
+ const doc = this.native.row(this.live(), format, raw, encodeSettings(settings));
129
+ return rowResultOf(parseDocument(doc));
130
+ }
131
+ /**
132
+ * Validate and coerce a whole request body, which may hold many rows.
133
+ *
134
+ * This is not `row()` in a loop and must never be implemented as one: row
135
+ * separation is format-specific (a quoted CSV field can contain a newline),
136
+ * `input_format_allow_errors_num` / `_ratio` decide whether a bad row is
137
+ * skipped or aborts the batch, and one batch is one clock instant for the
138
+ * volatile-DEFAULT guarantee.
139
+ *
140
+ * @param format - the wire format code (`Format`).
141
+ * @param body - the whole request body as bytes (never a JS string).
142
+ * @param settings - per-call settings; same precedence as `row`.
143
+ * @returns the `BatchResult`. When `engineRows` is present it — not `rows` —
144
+ * is the stored truth, and batch-level storage transforms (`ttl_expired`,
145
+ * `ttl_column_expired`) are folded into `transformed`.
146
+ * With `options.exportFormat` the same ONE call also serializes the batch's
147
+ * accepted rows through the vendored writer: `payload` carries the bytes
148
+ * (zero-length = emitted-empty, an accepted batch with zero accepted rows;
149
+ * `undefined` + `exportDeclined` = withheld, with the reason), and `spans`
150
+ * is index-aligned with `rows` — `payload.subarray(s.off, s.off + s.len)`
151
+ * IS row i's line. With `options.docFlags` the per-row documents are
152
+ * thinned to the selected groups; the verdict channel is never thinned.
153
+ * See `RowsOptions` for the defaults and `BatchResult` for the three
154
+ * payload states.
155
+ *
156
+ * @param format - the wire format code (`Format`).
157
+ * @param body - the whole request body as bytes (never a JS string).
158
+ * @param settings - per-call settings; same precedence as `row`.
159
+ * @param options - the revision-3 export/doc-flag channels; absent =
160
+ * today's full document, byte-identical to revision 2.
161
+ * @returns the `BatchResult`. When `engineRows` is present it — not `rows` —
162
+ * is the stored truth, and batch-level storage transforms (`ttl_expired`,
163
+ * `ttl_column_expired`) are folded into `transformed`.
164
+ * @throws {ChtypesError} when the schema is closed, a settings value is a JS
165
+ * `number`, or the artifact predates `chs_rows` (a mandatory symbol).
166
+ */
167
+ rows(format, body, settings, options) {
168
+ const exportFormat = options?.exportFormat ?? EXPORT_NONE;
169
+ const docFlags = options?.docFlags ?? (options?.exportFormat === undefined ? DOC_ALL : 0);
170
+ const { doc, payload } = this.native.rows(this.live(), format, body, encodeSettings(settings), exportFormat, docFlags);
171
+ return batchResultOf(parseDocument(doc), payload);
172
+ }
173
+ /**
174
+ * Compile one boolean SQL expression over this schema's PHYSICAL columns
175
+ * (ordinary + MATERIALIZED; naming an ALIAS/EPHEMERAL column fails with
176
+ * ClickHouse's own UNKNOWN_IDENTIFIER, exactly where a real CREATE fails) —
177
+ * the same TreeRewriter + ExpressionAnalyzer pipeline the CONSTRAINT CHECK
178
+ * path runs, so comparison semantics are WHERE-side by construction:
179
+ * `x = 256` over UInt8 promotes (false for every row), it never wraps
180
+ * (spec/c-abi.md §Filters).
181
+ *
182
+ * The expression may contain `{name:Type}` query parameters, bound with
183
+ * `options.params` (revision 4) — substitution is the server's own
184
+ * `ReplaceQueryParameterVisitor`, run before analysis, exactly where a
185
+ * real server runs it; see `CompileFilterOptions` for the injection-safety
186
+ * and cache-discipline contract. Close the filter when done (`close()` /
187
+ * `Symbol.dispose`); `schema.close()` also closes every open filter FIRST,
188
+ * so no caller ordering can free the schema under a live filter.
189
+ *
190
+ * ENFORCEMENT GATE: nothing may enforce read-side security on this surface
191
+ * until the WHERE-truth rig gates green (zero over-admit, zero over-hide);
192
+ * until then it is a shadow/replay surface.
193
+ *
194
+ * @param expr - one boolean expression, e.g. `"x = 256"` or
195
+ * `"tenant = {t:String}"`.
196
+ * @param options - the `{name:Type}` bindings, if any.
197
+ * @returns the compiled `Filter`.
198
+ * @throws {SchemaError} when ClickHouse itself refuses the expression —
199
+ * unknown identifier (47), unknown function, an analyzer-raised
200
+ * NO_COMMON_TYPE — and, since revision 4, the server's own parameter
201
+ * refusals: an UNBOUND `{name:Type}` is **456** UNKNOWN_QUERY_PARAMETER
202
+ * ("Substitution `name` is not set"), a value the declared type cannot
203
+ * parse completely is **457** BAD_QUERY_PARAMETER — the server's own
204
+ * code and message, verbatim. A bound name the expression never uses is
205
+ * ignored, as a live server ignores an unused `param_*`.
206
+ * @throws {UnsupportedError} when this build declines: a non-deterministic
207
+ * expression (clock reads — `now() > ts` —, `rand()`, server-constants;
208
+ * the scan runs AFTER substitution, so a value can never smuggle one
209
+ * in), or an artifact that predates the filter trio.
210
+ */
211
+ compileFilter(expr, options) {
212
+ const handle = this.native.filterCompile(this.live(), expr, encodeSettings(options?.params));
213
+ const filter = new Filter(this.native, this, handle, expr);
214
+ this.filters.add(filter);
215
+ return filter;
216
+ }
217
+ /** @internal — `Filter#close` deregisters itself here. */
218
+ forgetFilter(filter) {
219
+ this.filters.delete(filter);
220
+ }
221
+ /**
222
+ * Parse a body ONCE into a `Block` (`chs_block_parse`) — the parse half of
223
+ * `Filter#rows`, exported so K filters can evaluate one event with no
224
+ * re-parse (`Filter#eval`; spec/c-abi.md §Blocks). Same formats and
225
+ * settings contract as `rows` (`settings` is the PARSE-side map: format
226
+ * settings, clock keys; evaluation takes none). Volatile DEFAULTs resolve
227
+ * against THIS call's clock instant, so
228
+ * `filter.eval(schema.parseBlock(...))` ≡ `filter.rows(...)` exactly when
229
+ * the clock is pinned (`chtypes_now_epoch_nanos`) or the schema has no
230
+ * volatile DEFAULT.
231
+ *
232
+ * Per-row parse failures do NOT throw — they are recorded IN the block and
233
+ * answer `'decline'` from every filter, with the recorded error. Release
234
+ * with `close()` / `Symbol.dispose`; `schema.close()` closes open blocks
235
+ * FIRST, the C-required order.
236
+ *
237
+ * @param format - the wire format code (`Format`).
238
+ * @param body - the rows as bytes (never a JS string).
239
+ * @param settings - parse-side settings; same precedence as `Schema#rows`.
240
+ * @returns the parsed `Block`.
241
+ * @throws {SchemaError} on a call-level failure — an unknown setting's
242
+ * 115, an unsplittable body, a binary decode fault, the deferred
243
+ * JSONEachRow framing verdict: a malformed body yields no block and no
244
+ * partial answers.
245
+ * @throws {UnsupportedError} when this build declines the call, or the
246
+ * artifact predates the block twin.
247
+ */
248
+ parseBlock(format, body, settings) {
249
+ const handle = this.native.blockParse(this.live(), format, body, encodeSettings(settings));
250
+ const block = new Block(this.native, this, handle);
251
+ this.blocks.add(block);
252
+ return block;
253
+ }
254
+ /** @internal — `Block#close` deregisters itself here. */
255
+ forgetBlock(block) {
256
+ this.blocks.delete(block);
257
+ }
258
+ /**
259
+ * Release the native schema. Idempotent. After it, `row` / `rows` /
260
+ * `setEngine` / `setTtl` throw `ChtypesError` ("schema is closed").
261
+ * Any `Filter` or `Block` still open on this schema is closed FIRST, in
262
+ * the same call — the handles-before-schema free order the C layer
263
+ * requires, enforced here so no dispose ordering can get it backwards.
264
+ */
265
+ close() {
266
+ for (const filter of this.filters)
267
+ filter.close();
268
+ this.filters.clear();
269
+ for (const block of this.blocks)
270
+ block.close();
271
+ this.blocks.clear();
272
+ if (this.handle === null)
273
+ return;
274
+ this.native.schemaFree(this.handle);
275
+ this.handle = null;
276
+ }
277
+ /** `using schema = lib.compileDdl(...)` releases it at scope exit. */
278
+ [Symbol.dispose]() {
279
+ this.close();
280
+ }
281
+ }
282
+ /**
283
+ * One boolean SQL expression compiled against a `Schema`'s columns
284
+ * (`chs_filter_compile`). Obtained from `Schema#compileFilter`; never
285
+ * constructed directly.
286
+ *
287
+ * LIFETIME: a filter REFERENCES its schema handle — the C layer does not copy
288
+ * and does not refcount (spec/c-abi.md §Filters). This binding enforces the
289
+ * free order structurally, both ways: the `Filter` holds its `Schema` (so the
290
+ * schema stays reachable), and `Schema#close` closes every open filter before
291
+ * freeing the schema. `close()` is idempotent, and `using` / `Symbol.dispose`
292
+ * work on both objects in any nesting — the schema's dispose runs the
293
+ * filter's first when the caller forgot. A filter compiled from a schema
294
+ * answers for THAT handle: recompile filters when the schema is recompiled.
295
+ *
296
+ * THREADS: the header's rule, verbatim — one `chs_filter` "must not be used
297
+ * from two threads at once, and a chs_filter call is ALSO a use of its schema
298
+ * handle" (two filters over ONE schema must not run concurrently either). On
299
+ * a single JS thread every call here is synchronous, so ordinary Node code
300
+ * satisfies both by construction (spec/bindings.md §Concurrency); do not
301
+ * share a `Filter` — or its `Schema` — across `worker_threads`.
302
+ *
303
+ * ENFORCEMENT GATE: `'error'` and `'decline'` verdicts are NOT answers — a
304
+ * caller enforcing visibility MUST fail closed on both — and NO caller may
305
+ * enforce read-side security on this surface until the WHERE-truth rig gates
306
+ * green; until then it is a shadow/replay surface (spec/c-abi.md §Filters).
307
+ */
308
+ export class Filter {
309
+ native;
310
+ schema;
311
+ expr;
312
+ handle;
313
+ /** @internal — obtained from `Schema#compileFilter`. */
314
+ constructor(native, schema, handle,
315
+ /** The expression text as compiled, for logging and cache keys. */
316
+ expr) {
317
+ this.native = native;
318
+ this.schema = schema;
319
+ this.expr = expr;
320
+ this.handle = handle;
321
+ }
322
+ /**
323
+ * Evaluate the filter over a body of rows (`chs_filter_rows`) — the same
324
+ * formats and settings contract as `Schema#rows`, ONE C call. Rows are
325
+ * evaluated INDEPENDENTLY (there is no INSERT to abort):
326
+ * `input_format_allow_errors_*` does not apply, a bad text row declines
327
+ * (`'decline'`) and the tail resyncs so verdict indexes keep matching input
328
+ * rows, and volatile DEFAULTs resolve against one clock instant per call.
329
+ *
330
+ * @param format - the wire format code (`Format`).
331
+ * @param body - the rows as bytes (never a JS string).
332
+ * @param settings - per-call settings; same precedence as `Schema#rows`.
333
+ * @returns the `FilterResult` — the call-level outcome, and one verdict per
334
+ * row when it is `'ok'`.
335
+ * @throws {ChtypesError} when the filter is closed, or a settings value is
336
+ * a JS `number`.
337
+ */
338
+ rows(format, body, settings) {
339
+ if (this.handle === null)
340
+ throw new ChtypesError('chtypes: filter is closed');
341
+ const doc = this.native.filterRows(this.handle, format, body, encodeSettings(settings));
342
+ return filterResultOf(parseDocument(doc));
343
+ }
344
+ /**
345
+ * Evaluate this filter over an already-parsed `Block` (`chs_filter_eval`)
346
+ * — the SAME result document `rows` returns: same `FilterResult` fields,
347
+ * same verdicts, same `errors` rule (a row the parse recorded as
348
+ * unparseable answers `'decline'` with the recorded error). Evaluation is
349
+ * a pure function of (filter, block): no settings, and the block is
350
+ * neither consumed nor mutated, so one block can be evaluated by K filters
351
+ * sequentially with no re-parse — the live-SSE call shape.
352
+ *
353
+ * Filter and block MUST come from the SAME schema: a mismatched pair
354
+ * answers a REJECTED result (code 1002) — the C layer's loud refusal,
355
+ * never undefined behaviour. A pair from two different libraries throws
356
+ * `ChtypesError`: no handle ever crosses a dlopen'd image boundary.
357
+ *
358
+ * @param block - a `Block` from `Schema#parseBlock`.
359
+ * @returns the `FilterResult`, exactly as `rows` would answer it.
360
+ * @throws {ChtypesError} when the filter or block is closed, or they come
361
+ * from two different libraries.
362
+ */
363
+ eval(block) {
364
+ if (this.handle === null)
365
+ throw new ChtypesError('chtypes: filter is closed');
366
+ if (block.nativeLib !== this.native) {
367
+ throw new ChtypesError('chtypes: filter and block come from different libraries');
368
+ }
369
+ const doc = this.native.filterEval(this.handle, block.liveHandle());
370
+ return filterResultOf(parseDocument(doc));
371
+ }
372
+ /**
373
+ * Release the native filter (`chs_filter_free`). Idempotent, and also
374
+ * performed by the schema's own `close()` — filters first, then the schema,
375
+ * the C-required order.
376
+ */
377
+ close() {
378
+ if (this.handle === null)
379
+ return;
380
+ this.native.filterFree(this.handle);
381
+ this.handle = null;
382
+ this.schema.forgetFilter(this);
383
+ }
384
+ /** `using filter = schema.compileFilter(...)` releases it at scope exit. */
385
+ [Symbol.dispose]() {
386
+ this.close();
387
+ }
388
+ }
389
+ /**
390
+ * One body, parsed ONCE under one schema handle and one clock instant
391
+ * (`chs_block_parse`). Obtained from `Schema#parseBlock`; evaluated by
392
+ * `Filter#eval`. The parse-once/eval-many twin of `Filter#rows`
393
+ * (spec/c-abi.md §Blocks): the live-SSE hot path is K filters × 1 event, and
394
+ * the block sheds the re-parse.
395
+ *
396
+ * LIFETIME: a block REFERENCES its schema handle exactly as a filter does —
397
+ * the C layer does not copy and does not refcount. This binding enforces the
398
+ * free order structurally, both ways: the `Block` holds its `Schema` (so the
399
+ * schema stays reachable), and `Schema#close` closes every open block before
400
+ * freeing the schema — `using` / `Symbol.dispose` work on all three objects
401
+ * in any nesting, and the schema's dispose runs the block's first when the
402
+ * caller forgot. A block may be evaluated by MANY filters, sequentially;
403
+ * evaluation does not consume or mutate it. Recompile blocks when the schema
404
+ * is recompiled.
405
+ *
406
+ * THREADS: one block must not be used from two threads at once, and an eval
407
+ * is a use of BOTH handles. On a single JS thread every call here is
408
+ * synchronous, so ordinary Node code satisfies both by construction; do not
409
+ * share a `Block` — or its `Schema` — across `worker_threads`.
410
+ */
411
+ export class Block {
412
+ native;
413
+ schema;
414
+ handle;
415
+ /** @internal — obtained from `Schema#parseBlock`. */
416
+ constructor(native, schema, handle) {
417
+ this.native = native;
418
+ this.schema = schema;
419
+ this.handle = handle;
420
+ }
421
+ /** @internal — the loaded library this block's handle belongs to. */
422
+ get nativeLib() {
423
+ return this.native;
424
+ }
425
+ /** @internal — the live handle, for `Filter#eval`. */
426
+ liveHandle() {
427
+ if (this.handle === null)
428
+ throw new ChtypesError('chtypes: block is closed');
429
+ return this.handle;
430
+ }
431
+ /**
432
+ * Release the native block (`chs_block_free`). Idempotent, and also
433
+ * performed by the schema's own `close()` — blocks first, then the schema,
434
+ * the C-required order.
435
+ */
436
+ close() {
437
+ if (this.handle === null)
438
+ return;
439
+ this.native.blockFree(this.handle);
440
+ this.handle = null;
441
+ this.schema.forgetBlock(this);
442
+ }
443
+ /** `using block = schema.parseBlock(...)` releases it at scope exit. */
444
+ [Symbol.dispose]() {
445
+ this.close();
446
+ }
447
+ }
448
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A setting value crosses the boundary as a JSON **string**, always.
3
+ *
4
+ * This is not cosmetic (spec/c-abi.md §Settings): `chtypes_now_epoch_nanos` is a
5
+ * 19-digit nanosecond epoch, which does not survive an IEEE double. Serialised
6
+ * as a JSON *number* through a JS `number` it arrives as 1.7e+18 and the setting
7
+ * is **silently ignored** — the batch keeps stamping the real wall clock and
8
+ * nothing anywhere says so.
9
+ *
10
+ * The type therefore admits `string` and `bigint` and not `number`, and the
11
+ * runtime rejects a `number` as well, because TypeScript is not present at the
12
+ * call site of a JS consumer.
13
+ */
14
+ export type SettingValue = string | bigint;
15
+ /**
16
+ * A map of ClickHouse query/format settings plus the six `chtypes_*` keys
17
+ * (clock control and admission budgets — spec/c-abi.md §Settings), by name.
18
+ *
19
+ * Accepted everywhere settings travel: the compile profile
20
+ * (`Library#compileDdl`), the per-call map (`Schema#row` / `Schema#rows`), the
21
+ * process seed (`Library#setDefaultSettings`) and the engine's
22
+ * MergeTree-namespace settings (`Schema#setEngine`). Precedence on the row
23
+ * path: per-call > compile profile > library defaults > ClickHouse defaults —
24
+ * except a TYPE GATE declared in the compile profile, which binds at compile
25
+ * and then outranks the per-call map, as a real server's CREATE does.
26
+ *
27
+ * An unknown setting name is refused WHOLESALE with the server's own code 115
28
+ * on every channel — nothing is applied, nothing is silently dropped.
29
+ */
30
+ export type Settings = Readonly<Record<string, SettingValue>>;
31
+ /**
32
+ * Serialise settings to the `settings_json` object the C ABI expects — every
33
+ * value crossing as a JSON string.
34
+ *
35
+ * @param settings - the settings map; `undefined` encodes as `"{}"`, the
36
+ * structurally settings-free path.
37
+ * @returns the JSON text to hand to a `chs_*` entry point.
38
+ * @throws {ChtypesError} when a value is neither `string` nor `bigint` — a JS
39
+ * `number` is rejected at runtime because a 19-digit nanosecond epoch does
40
+ * not survive an IEEE double and the setting would be silently ignored.
41
+ */
42
+ export declare function encodeSettings(settings?: Settings): string;
43
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAkB1D"}
@@ -0,0 +1,33 @@
1
+ import { ChtypesError } from './errors.js';
2
+ /**
3
+ * Serialise settings to the `settings_json` object the C ABI expects — every
4
+ * value crossing as a JSON string.
5
+ *
6
+ * @param settings - the settings map; `undefined` encodes as `"{}"`, the
7
+ * structurally settings-free path.
8
+ * @returns the JSON text to hand to a `chs_*` entry point.
9
+ * @throws {ChtypesError} when a value is neither `string` nor `bigint` — a JS
10
+ * `number` is rejected at runtime because a 19-digit nanosecond epoch does
11
+ * not survive an IEEE double and the setting would be silently ignored.
12
+ */
13
+ export function encodeSettings(settings) {
14
+ if (settings === undefined)
15
+ return '{}';
16
+ const out = {};
17
+ for (const [key, value] of Object.entries(settings)) {
18
+ if (typeof value === 'string') {
19
+ out[key] = value;
20
+ }
21
+ else if (typeof value === 'bigint') {
22
+ out[key] = value.toString();
23
+ }
24
+ else {
25
+ throw new ChtypesError(`chtypes: setting ${JSON.stringify(key)} must be a string or a bigint, got ` +
26
+ `${typeof value}. A JS number cannot carry a 19-digit nanosecond epoch: ` +
27
+ `1700000000123456789 becomes 1.7e+18 and the setting is silently ignored ` +
28
+ `(spec/c-abi.md §Settings).`);
29
+ }
30
+ }
31
+ return JSON.stringify(out);
32
+ }
33
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkC3C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,QAAmB;IAChD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACnB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,YAAY,CACpB,oBAAoB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,qCAAqC;gBAC1E,GAAG,OAAO,KAAK,0DAA0D;gBACzE,0EAA0E;gBAC1E,4BAA4B,CAC/B,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC"}
package/dist/tar.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A streaming reader for the artifact tarballs — ustar, pax extended
3
+ * headers, GNU long names — written here rather than taken from a
4
+ * dependency: this package's one runtime dependency is ffi-rs, and a reader
5
+ * that extracts regular files under one directory is a page of code.
6
+ *
7
+ * Files only. Directories are created; everything else — symlinks, hard
8
+ * links, devices, FIFOs — is skipped without being followed: an artifact is
9
+ * `manifest.json`, one library and two text files, and a link inside one is
10
+ * an attack, not a feature. Every entry name is confined to the destination
11
+ * (no absolute names, no `..` components, no escape once resolved), and a
12
+ * name that escapes is refused as corrupt rather than clamped.
13
+ *
14
+ * The archive is consumed as a stream: a 300 MB library is written to disk
15
+ * as it inflates and never sits in memory whole.
16
+ */
17
+ /** One regular file the extractor wrote. */
18
+ export interface ExtractedEntry {
19
+ /** The entry name as confined under the destination, `/`-separated. */
20
+ readonly name: string;
21
+ readonly size: number;
22
+ }
23
+ /**
24
+ * Inflate and unpack `archive` (a `.tar.gz`) into `dest`, which must already
25
+ * exist. Returns the regular files written, in archive order.
26
+ *
27
+ * @throws {ArtifactCorruptError} when the bytes are not a gzip stream, a
28
+ * header fails its checksum, the archive is truncated, or an entry name
29
+ * would land outside `dest`.
30
+ */
31
+ export declare function extractTarGz(archive: string, dest: string): Promise<ExtractedEntry[]>;
32
+ //# sourceMappingURL=tar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tar.d.ts","sourceRoot":"","sources":["../src/tar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAcH,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAW3F"}