@wavehouse/chtypes 0.1.0 → 0.1.2
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/CHANGELOG.md +27 -16
- package/README.md +46 -408
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +24 -4
- package/dist/cli.js.map +1 -1
- package/dist/discover.d.ts +2 -2
- package/dist/discover.js +2 -2
- package/dist/errors.d.ts +30 -9
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +35 -7
- package/dist/errors.js.map +1 -1
- package/dist/fetch.d.ts +17 -8
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +140 -16
- package/dist/fetch.js.map +1 -1
- package/dist/ffi.d.ts +15 -15
- package/dist/ffi.js +26 -26
- package/dist/ffi.js.map +1 -1
- package/dist/format.d.ts +5 -5
- package/dist/format.js +5 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +3 -3
- package/dist/json.js +5 -5
- package/dist/json.js.map +1 -1
- package/dist/library.d.ts +11 -11
- package/dist/library.js +9 -9
- package/dist/numeric.js +1 -1
- package/dist/paths.d.ts +1 -1
- package/dist/paths.js +1 -1
- package/dist/registry.d.ts +6 -6
- package/dist/registry.js +6 -6
- package/dist/registry.js.map +1 -1
- package/dist/results.d.ts +46 -13
- package/dist/results.d.ts.map +1 -1
- package/dist/results.js +85 -4
- package/dist/results.js.map +1 -1
- package/dist/schema.d.ts +18 -18
- package/dist/schema.js +11 -11
- package/dist/settings.d.ts +4 -4
- package/dist/settings.js +2 -2
- package/dist/settings.js.map +1 -1
- package/dist/transform.d.ts +2 -2
- package/dist/transform.js +5 -5
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,24 +1,35 @@
|
|
|
1
1
|
# Changelog — `@wavehouse/chtypes`
|
|
2
2
|
|
|
3
|
-
All notable changes to the ts binding. The format is
|
|
4
|
-
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this package follows
|
|
5
|
-
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
3
|
+
All notable changes to the ts binding. The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this package follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
4
|
|
|
7
|
-
The four bindings in this repository are released together and give one answer,
|
|
8
|
-
|
|
5
|
+
The four bindings in this repository are released together and give one answer, so an entry here has a counterpart in the other three.
|
|
6
|
+
|
|
7
|
+
## [0.1.2] — 2026-09-11
|
|
8
|
+
|
|
9
|
+
### Changed — BREAKING
|
|
10
|
+
|
|
11
|
+
- **The transform reason for a materialized DEFAULT is now `default_materialized`** — previously the same word spelled with an `s` — and the exported constant naming it is now `DEFAULT_MATERIALIZED`. ClickHouse's own keyword is `MATERIALIZED`; its parser rejects the `s` spelling outright with a syntax error, so the reason naming that concept now matches the system it describes. Code comparing against the old string or the old constant name must be updated.
|
|
12
|
+
- This is an SDK-only change and **the ABI is untouched: it remains revision 4, and no artifact needs relinking.** The reason is derived in the binding, not received from the artifact — the library emits `default_substituted`, which each binding translates. That wire value is unchanged.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **The per-language README is now an orientation page, not a manual.** It carries install, a quickstart that runs, the three outcomes and the error model, and then points at `docs/` for the rest — roughly 450 lines of reference prose moved to `docs/guides/` and `docs/reference/` rather than being repeated four times and drifting four ways.
|
|
17
|
+
- **The published packages no longer cite a repository you cannot open.** 148 source comments — in every binding and in `include/chtypes.h`, all of which ship inside the crate, the sdist and the module — attributed the contract they implement to a private repository's specification. They now cite **the C ABI contract**, with `include/chtypes.h` as the public authority for it. Alongside those, 14 dead paths into that repository, the examples' instruction to build an artifact there, and two descriptions of the signing infrastructure are gone. What remains naming it is the handful of places where the two-repository split is the actual subject — the README, `SECURITY.md`, and `docs/reference/README.md`, which says plainly that the full normative specification is not public.
|
|
18
|
+
- `scripts/lint-public.sh` is new and blocking in CI, because the sweep this replaces reported itself complete while 148 of its targets survived in a different shape. It refuses both the private repository's name and that exact prose pointer, and its `--selftest` proves each rule fires rather than assuming it.
|
|
19
|
+
|
|
20
|
+
## [0.1.1] — 2026-09-11
|
|
21
|
+
|
|
22
|
+
- **The golden set is served, not tracked.** `goldens/cases.json` no longer exists in this repository. Core publishes `sdk-goldens.json` in the rolling release as a row in the signed `SHA256SUMS`; `scripts/fetch.sh` installs it at `<registry>/sdk-goldens.json` and the golden test reads it offline from there (`CHTYPES_GOLDENS` overrides). A case runs only against the exact ClickHouse version `generated.exact` names for its line and skips loudly otherwise, so the set shrinks as lines are added rather than recording an answer twice.
|
|
23
|
+
- **Artifact identity gained a wrapper build.** Assets are `chtypes-<version>-<os>-<arch>-b<N>.tar.gz`, where `<N>` is the core commit's UNIX timestamp; an absent suffix means build 0 and stays valid. Line resolution ranks by `(version, build)`, so a rebuild of a line supersedes the older build.
|
|
24
|
+
- Fetching now retries the publish window, so a fetch that races a release no longer fails on sums naming a file the host has not finished serving.
|
|
25
|
+
- README install instructions name the published package rather than a path dependency.
|
|
26
|
+
- Two errors in the published README, both found by running the snippets rather than reading them: Python's `substituted` is on `RowResult`, not `BatchResult`, and TypeScript's `using schema = …` is a syntax error on Node 22, this package's own `engines` floor (`schema.close()` is portable).
|
|
27
|
+
- `docs/support.md` is new: which language versions, platforms and ClickHouse lines are supported, generated from the manifests and the release's own index.
|
|
9
28
|
|
|
10
29
|
## [0.1.0] — 2026-09-10
|
|
11
30
|
|
|
12
31
|
First release, published to npm from the tag `ts/v0.1.0`.
|
|
13
32
|
|
|
14
|
-
- Speaks **ABI revision 4** of the frozen `chs_*` C ABI
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
derived result.
|
|
18
|
-
- Verified against the public golden set (`goldens/cases.json`, schema 1,
|
|
19
|
-
31 cases), whose expectations were generated on ClickHouse
|
|
20
|
-
24.8, 25.3, 25.8, 25.10, 26.5, 26.6 and 26.7 — every case answered
|
|
21
|
-
identically on all seven lines, and any case that did not was refused by
|
|
22
|
-
the generator.
|
|
23
|
-
- Pre-1.0: the artifact name `libchtypes`, the `chs_` prefix and the
|
|
24
|
-
`enum chs_format` numbers are frozen. Function signatures freeze at this tag.
|
|
33
|
+
- Speaks **ABI revision 4** of the frozen `chs_*` C ABI (`include/chtypes.h`, 28 functions). The binding `dlopen`s a per-version artifact and reimplements no ClickHouse semantics; `Transformed` is the one derived result.
|
|
34
|
+
- Verified against the public golden set (`goldens/cases.json`, schema 1, 31 cases), whose expectations were generated on ClickHouse 24.8, 25.3, 25.8, 25.10, 26.5, 26.6 and 26.7 — every case answered identically on all seven lines, and any case that did not was refused by the generator.
|
|
35
|
+
- Pre-1.0: the artifact name `libchtypes`, the `chs_` prefix and the `enum chs_format` numbers are frozen. Function signatures freeze at this tag.
|
package/README.md
CHANGED
|
@@ -1,442 +1,80 @@
|
|
|
1
1
|
# chtypes — TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
DEFAULT/TTL logic and coercion, per ClickHouse version, behind the
|
|
5
|
-
`chs_*` C ABI (pre-1.0 only the names and the format integers are frozen —
|
|
6
|
-
signatures can still change by deliberate cycle, which is why the loader
|
|
7
|
-
checks `chs_abi_revision` before trusting them). One peer binding among
|
|
8
|
-
`{go,python,ts,rust}`; no
|
|
9
|
-
language is privileged. Nothing here reimplements a coercion rule — every
|
|
10
|
-
verdict comes from real ClickHouse code compiled from the pinned release; the
|
|
11
|
-
one derived answer is `transformed`, the silent-change report the product
|
|
12
|
-
exists for.
|
|
3
|
+
**If this row were inserted into this table on this ClickHouse version, what would happen?** chtypes answers with ClickHouse's own code: the real C++ type machinery, vendored per release into a native library behind the frozen `chs_*` C ABI and reached here through `ffi-rs`. Nothing semantic is reimplemented, so _"what does ClickHouse do with `256` into a `UInt8`?"_ is answered by ClickHouse rather than by a model of it. One peer binding among `{go, python, ts, rust}` — no language is privileged, and all four give one answer.
|
|
13
4
|
|
|
14
|
-
Node ≥ 22, ESM only.
|
|
15
|
-
darwin-arm64/x64 and linux arm64/x64, gnu and musl — no build step).
|
|
5
|
+
Node ≥ 22, ESM only. `ffi-rs` ships prebuilt for darwin arm64/x64 and linux arm64/x64 (gnu and musl), so there is **no build step**.
|
|
16
6
|
|
|
17
|
-
## Install
|
|
7
|
+
## Install
|
|
18
8
|
|
|
19
|
-
|
|
20
|
-
package manager):
|
|
21
|
-
|
|
22
|
-
```jsonc
|
|
23
|
-
// your app's package.json
|
|
24
|
-
{ "dependencies": { "@wavehouse/chtypes": "file:../chtypes/ts" } }
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
or `pnpm link <repo>/ts`. Either way, build the package's `dist/`
|
|
28
|
-
first — that is what `package.json#exports` serves:
|
|
29
|
-
|
|
30
|
-
```sh
|
|
31
|
-
cd <repo>/ts
|
|
32
|
-
pnpm install && pnpm build
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
(If a linked copy goes stale, note `pnpm install --force` does **not** relink;
|
|
36
|
-
remove `node_modules` and reinstall.)
|
|
37
|
-
|
|
38
|
-
**Artifact prerequisite.** The SDK loads per-version native artifacts; it does
|
|
39
|
-
nothing without them. Fetch a published one — verified, into the per-user cache
|
|
40
|
-
every SDK here defaults to — with the package's own command, or build one in
|
|
41
|
-
the core repository, which lands it in the same place:
|
|
9
|
+
Two things: this package, and at least one **artifact** — the per-version native library it `dlopen`s at runtime.
|
|
42
10
|
|
|
43
11
|
```sh
|
|
44
|
-
|
|
12
|
+
pnpm add @wavehouse/chtypes
|
|
13
|
+
npx @wavehouse/chtypes fetch 25.8
|
|
45
14
|
```
|
|
46
15
|
|
|
47
|
-
|
|
48
|
-
the same contract, `docs/fetch.md`; the command, the function and the lazy
|
|
49
|
-
fetch are in [Artifacts: fetch, verify, autofetch](#artifacts-fetch-verify-autofetch).)
|
|
50
|
-
|
|
51
|
-
A registry holds one subdirectory per version:
|
|
52
|
-
|
|
53
|
-
<registry>/25.8/
|
|
54
|
-
manifest.json # names the library file — the loader reads this, never guesses
|
|
55
|
-
libchtypes.dylib # (.so on Linux; the name comes from manifest.json)
|
|
56
|
-
CH_VERSION
|
|
57
|
-
unsafe_families.txt # the build's own refuse-list; empty is a valid list
|
|
58
|
-
|
|
59
|
-
`new Registry(dir?)` scans such a directory. Where it looks is the search path
|
|
60
|
-
of `docs/fetch.md` §1, in order: the explicit `dir`, `$CHTYPES_REGISTRY`, the
|
|
61
|
-
per-user cache (`defaultRegistryDir()`), then the reserved system locations
|
|
62
|
-
`/usr/local/share/chtypes/artifacts/<os>-<arch>` and `/opt/chtypes/artifacts/<os>-<arch>`.
|
|
63
|
-
The first directory holding artifacts is loaded at construction; a line it
|
|
64
|
-
lacks is loaded from the first later directory that has it when first asked
|
|
65
|
-
for (`registry.searchPath` lists every candidate; a named directory — the
|
|
66
|
-
argument or the variable — that does not exist is an error naming it, never a
|
|
67
|
-
silent fallback). For each artifact the
|
|
68
|
-
loader dlopens the file `manifest.json#library` names, asks the library to name
|
|
69
|
-
itself (`chs_clickhouse_version()` — nothing is inferred from paths), and
|
|
70
|
-
checks the ABI revision: `chs_abi_revision()` must equal this binding's
|
|
71
|
-
`ABI_REVISION` (currently 4). A different nonzero revision is **refused** —
|
|
72
|
-
calling through mismatched declarations is undefined; `0` means the artifact
|
|
73
|
-
predates the probe and individual missing symbols degrade to
|
|
74
|
-
`UnsupportedError` at call time, never to a load failure.
|
|
75
|
-
|
|
76
|
-
## Artifacts: fetch, verify, autofetch
|
|
77
|
-
|
|
78
|
-
The fetch/verify contract every SDK implements identically is
|
|
79
|
-
[`docs/fetch.md`](../docs/fetch.md); this package carries it as a `bin` and
|
|
80
|
-
as a function.
|
|
81
|
-
|
|
82
|
-
```sh
|
|
83
|
-
npx @wavehouse/chtypes fetch 25.8 # one line, verified, into the per-user cache
|
|
84
|
-
npx @wavehouse/chtypes fetch --all # every line the release publishes for this host
|
|
85
|
-
npx @wavehouse/chtypes fetch 25.8 --platform linux-arm64 --dest /opt/chtypes/artifacts/linux-arm64
|
|
86
|
-
npx @wavehouse/chtypes fetch 25.8 --lock chtypes.lock # record what was installed (file + sha256)
|
|
87
|
-
npx @wavehouse/chtypes fetch 25.8 --frozen # refuse anything chtypes.lock does not pin
|
|
88
|
-
npx @wavehouse/chtypes verify # re-hash every installed line against its manifest
|
|
89
|
-
npx @wavehouse/chtypes list # what is installed, and what the release offers
|
|
90
|
-
npx @wavehouse/chtypes where # the registry directory fetch writes to
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
`fetch` prints the installed directory alone on stdout (progress on stderr),
|
|
94
|
-
so `dir="$(npx @wavehouse/chtypes fetch 25.8)"` composes. Exit codes: 0 ok ·
|
|
95
|
-
1 verification failed · 2 usage · 3 source unreachable · 4 not published for
|
|
96
|
-
this platform/line. A line (`25.8`) resolves to the one patch the release
|
|
97
|
-
publishes for it; an exact patch (`25.8.28.1-lts`) is a hard requirement.
|
|
98
|
-
Sources: `--tag v1.2.0` picks a frozen release on `CHTYPES_ARTIFACTS_URL`
|
|
99
|
-
(default `https://artifacts.wavehouse.dev`; the rolling `artifacts` release
|
|
100
|
-
otherwise); `--url <base>` is any other base — a mirror, a `file://` path or
|
|
101
|
-
a plain directory. `--offline` never touches the source: installed and
|
|
102
|
-
verified is fine, anything else is `CHTYPES_SOURCE_UNREACHABLE`. Fetch writes
|
|
103
|
-
to the first of `--dest`, `$CHTYPES_REGISTRY`, the per-user cache; never to a
|
|
104
|
-
system location.
|
|
105
|
-
|
|
106
|
-
**The verification chain**, in order — nothing else is a verdict, not an exit
|
|
107
|
-
code, not a `Content-Length`: (0) `SHA256SUMS.sig`, an ed25519 signature over
|
|
108
|
-
the bytes of `SHA256SUMS`, verified with the embedded release key
|
|
109
|
-
(`RELEASE_PUBLIC_KEYS`, key id `deb275922dbff76e`) or with the keys in
|
|
110
|
-
`CHTYPES_TRUSTED_KEYS=<hex>[,<hex>…]`, which *replace* it — an unsigned or
|
|
111
|
-
mis-signed release is `CHTYPES_ARTIFACT_UNTRUSTED` and nothing is downloaded
|
|
112
|
-
around it (`CHTYPES_ALLOW_UNSIGNED=1` skips this step with one loud warning
|
|
113
|
-
naming the source, never silently); (1) `index.json` names the asset and its
|
|
114
|
-
sha256; (2) the now-authentic `SHA256SUMS` must agree; (3) the tarball is
|
|
115
|
-
hashed before it is unpacked; (4) `manifest.json` inside must agree with the
|
|
116
|
-
index, and the installed library is re-hashed in place after the atomic
|
|
117
|
-
rename. Any mismatch is `CHTYPES_ARTIFACT_CORRUPT` and nothing is installed.
|
|
118
|
-
Installed-and-verified is a no-op (`--force` re-downloads). Once files are in
|
|
119
|
-
a registry directory the loader trusts the directory, as a runtime trusts
|
|
120
|
-
`node_modules` — pass `verifyChecksums: true` to re-hash at load.
|
|
121
|
-
|
|
122
|
-
The same thing as a function:
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
import { ensure } from '@wavehouse/chtypes';
|
|
126
|
-
|
|
127
|
-
const r = await ensure('25.8'); // idempotent; r.dir is <registry>/25.8, r.installed says whether bytes moved
|
|
128
|
-
await ensure('25.8', { lock: 'chtypes.lock', frozen: true }); // CHTYPES_ARTIFACT_PINNED on drift
|
|
129
|
-
await ensure('25.8', { url: 'file:///srv/mirror', trustedKeys: [hex] }); // a mirror signed by someone else
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Every flag is a property of `EnsureOptions` (`dest`, `platform`, `tag`, `url`,
|
|
133
|
-
`lock`, `frozen`, `force`, `offline`, `trustedKeys`, `allowUnsigned`,
|
|
134
|
-
`onProgress`, `signal`); `ensureAll`, `verifyInstalled` and `listArtifacts`
|
|
135
|
-
are `--all`, `verify` and `list`. Concurrent `ensure`s of one line in one
|
|
136
|
-
process share one fetch.
|
|
137
|
-
|
|
138
|
-
**Lazy fetch on first open is opt-in** — `new Registry(dir, { autofetch: true })`
|
|
139
|
-
or `CHTYPES_AUTOFETCH=1` — because a production process must not begin a
|
|
140
|
-
250 MB download inside a request. `Registry#for()` is synchronous and never
|
|
141
|
-
fetches; `Registry#open()` is its async twin: with autofetch on, a line no
|
|
142
|
-
directory on the search path holds is fetched through `ensure` first (into the
|
|
143
|
-
directory fetch writes to, once per process per line even under concurrent
|
|
144
|
-
opens), then loaded.
|
|
145
|
-
|
|
146
|
-
```ts
|
|
147
|
-
const registry = new Registry(undefined, { autofetch: true, fetch: { tag: 'v1.2.0' } });
|
|
148
|
-
const lib = await registry.open('25.8'); // fetched on first use, loaded from then on
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
**The one error.** A line no directory on the search path holds is an
|
|
152
|
-
`ArtifactMissingError` — a `RegistryError` with `code === 'CHTYPES_ARTIFACT_MISSING'`
|
|
153
|
-
and this message, verbatim apart from the bracketed parts:
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
chtypes: no artifact for ClickHouse <line> (<os>-<arch>). Looked in: <dir1>, <dir2>, ….
|
|
157
|
-
Install it: npx @wavehouse/chtypes fetch <line>
|
|
158
|
-
or set CHTYPES_AUTOFETCH=1 to fetch on first use.
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
The fetch verdicts are `FetchError` subclasses carrying the shared codes:
|
|
162
|
-
`ArtifactUntrustedError` (`CHTYPES_ARTIFACT_UNTRUSTED`), `ArtifactCorruptError`
|
|
163
|
-
(`CHTYPES_ARTIFACT_CORRUPT`), `ArtifactPinnedError` (`CHTYPES_ARTIFACT_PINNED`),
|
|
164
|
-
`ArtifactUnpublishedError` (`CHTYPES_ARTIFACT_UNPUBLISHED`) and
|
|
165
|
-
`SourceUnreachableError` (`CHTYPES_SOURCE_UNREACHABLE`). Artifacts are Elastic
|
|
166
|
-
License 2.0, separate from this package's Apache 2.0; `LICENSE` and `NOTICE`
|
|
167
|
-
ship in every release and `fetch` says so once.
|
|
16
|
+
The fetch lands in `~/.cache/chtypes/artifacts/<os>-<arch>/25.8/` — the per-user cache every chtypes binding reads by default — after checking an ed25519 signature over the release and the sha256 of every byte. `$CHTYPES_REGISTRY` overrides it.
|
|
168
17
|
|
|
169
18
|
## Quickstart
|
|
170
19
|
|
|
171
20
|
```ts
|
|
172
|
-
import { Format, Registry
|
|
173
|
-
|
|
174
|
-
const registry = new Registry(); // $CHTYPES_REGISTRY, else the per-user cache
|
|
175
|
-
const lib = registry.for('25.8'); // minor line or exact patch both resolve
|
|
21
|
+
import { Format, Registry } from '@wavehouse/chtypes';
|
|
176
22
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
settings: { allow_suspicious_low_cardinality_types: '1' },
|
|
181
|
-
});
|
|
23
|
+
const registry = new Registry(); // walks the search path
|
|
24
|
+
const lib = registry.for('25.8'); // a line or an exact patch; never a nearest match
|
|
25
|
+
const schema = lib.compileDdl('x UInt8, ts DateTime DEFAULT now()');
|
|
182
26
|
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
console.log(
|
|
186
|
-
console.log(
|
|
27
|
+
const batch = schema.rows(Format.JSONEachRow, Buffer.from('{"x":256}'));
|
|
28
|
+
const row = batch.rows[0];
|
|
29
|
+
console.log(batch.outcome); // accepted
|
|
30
|
+
console.log(row.values[0].text); // 0 — what would actually be stored
|
|
31
|
+
console.log(row.transformed[0]?.reason); // overflow_wrap — which is the product
|
|
32
|
+
console.log(row.substituted[0]?.column); // ts — send it explicitly in the real INSERT
|
|
187
33
|
|
|
188
|
-
|
|
189
|
-
console.log(bad.outcome, bad.errCode, bad.errMsg); // rejected <ClickHouse's own code + message>
|
|
34
|
+
schema.close();
|
|
190
35
|
```
|
|
191
36
|
|
|
192
|
-
|
|
193
|
-
(`accepted` | `rejected` | `accepted_poisoned` | `unsupported`). Exceptions are
|
|
194
|
-
for schema-level answers (`compileDdl`, `setEngine`, `setTtl`,
|
|
195
|
-
`validateType`), and there the class *is* the verdict: `SchemaError` = the
|
|
196
|
-
server refused (a real ClickHouse code), `UnsupportedError` = chtypes declines
|
|
197
|
-
to guess — fall back to the server. The two are peers; a decline never
|
|
198
|
-
satisfies `instanceof SchemaError`.
|
|
37
|
+
The row is **accepted** and `256` is silently stored as `0`. That report — `transformed` — is the one derived answer in the system and the reason it exists.
|
|
199
38
|
|
|
200
|
-
|
|
39
|
+
`ts` was substituted rather than stored: send every substituted column as an explicit value in the real INSERT, or the server re-evaluates `now()` at its own instant and your preview is not what landed.
|
|
201
40
|
|
|
202
|
-
|
|
203
|
-
cross-SDK shape):
|
|
41
|
+
## Three outcomes, and conflating any two is a bug
|
|
204
42
|
|
|
205
|
-
|
|
206
|
-
|---|---|---|---|---|
|
|
207
|
-
| `new Registry(dir?, options?)` | per artifact: dlopen, `chs_clickhouse_version`, `chs_abi_revision`, `chs_init` | registry dir — the head of the search path (it, `$CHTYPES_REGISTRY`, the per-user cache, the system locations); `{timezone='UTC', verifyChecksums, autofetch, fetch}` | `Registry` | `RegistryError` (a named directory that does not exist, no artifacts anywhere, unreadable directory, checksum, manifest mismatch, load failure); `ChtypesError` (ABI-revision mismatch, `chs_init` failure) |
|
|
208
|
-
| `Registry#versions()` | — derived | — | minor lines, oldest first | never throws |
|
|
209
|
-
| `Registry#libraries()` | — derived | — | every loaded `Library`, in release order | never throws |
|
|
210
|
-
| `Registry#for(version)` | — derived (lookup; loads a line from a later search-path directory on demand) | minor line or exact patch | `Library` | `ArtifactMissingError` (a `RegistryError`, `code` `CHTYPES_ARTIFACT_MISSING`, names every directory looked in); `RegistryError` (a directory holds the line but it does not load); never a nearest-version fallback, never a fetch |
|
|
211
|
-
| `Registry#open(version)` | — `for()` behind a promise; with `autofetch`, `ensure` first | minor line or exact patch | `Promise<Library>` | `ArtifactMissingError` (autofetch off); the `FetchError` verdicts; `RegistryError` (fetched, does not load) |
|
|
212
|
-
| `Registry#has(version)` | — derived | version string | `boolean` | never throws |
|
|
213
|
-
| `Registry#close()` / `Symbol.dispose` | `chs_shutdown` per library | — | — | see `Library#shutdown` |
|
|
214
|
-
| `Library#validateType(expr)` | `chs_validate_type` | type expression | canonical spelling (use verbatim) | `SchemaError` (server refusal, e.g. 50); `UnsupportedError` (unsafe family / missing symbol) |
|
|
215
|
-
| `Library#compileDdl(ddl, {settings, mode}?)` | `chs_schema_compile` + the six `chs_schema_column_*` getters | column-declaration list (not a CREATE TABLE); optional declared profile; `mode` default `CompileMode.Declared` | `Schema` | `SchemaError` (positive code: bad DDL, unknown setting name 115, declared gate refusing 455/44, Enum-DEFAULT domain 691); `UnsupportedError` (mode ≠ 0, refused DEFAULT, admission budget) |
|
|
216
|
-
| `Library#hasCompileSettings()` | probe via `chs_schema_compile` | — | `boolean` (true on every artifact this repo builds) | passes through unexpected errors |
|
|
217
|
-
| `Library#setDefaultSettings(settings)` | `chs_set_default_settings` | process-wide seed | — | `ChtypesError` (refused wholesale with the server's 115 + hint; reentrancy; JS `number` value); `UnsupportedError` (missing symbol) |
|
|
218
|
-
| `Library#referenceType(expr)` | `chs_reference_type` | type expression | widened reference type, `''` if none | `UnsupportedError` (missing symbol) |
|
|
219
|
-
| `Library#registeredFamilies()` | `chs_registered_families` | — | family names | `UnsupportedError` (missing symbol) |
|
|
220
|
-
| `Library#functionFlags()` | `chs_function_flags` | — | the volatility TSV audit, verbatim | `UnsupportedError` (missing symbol) |
|
|
221
|
-
| `Library#shutdown()` | `chs_shutdown` | — | — | `ChtypesError` (reentrancy); missing symbol ignored |
|
|
222
|
-
| `Schema#columns` | `chs_schema_column_count/_name/_type/_default_kind/_default_expr/_default_is_literal` (at compile) | — | `ColumnInfo[]`, canonicalised, declaration order | — |
|
|
223
|
-
| `Schema#setEngine(engine, orderBy, {mergeTreeSettings}?)` | `chs_schema_engine` | engine, sorting key, MergeTree-namespace `SETTINGS` | — | sign of rc decides: `SchemaError` (rc > 0 — server refused, today 115 unknown MergeTree setting name); `UnsupportedError` (rc < 0 — unmodelled engine/key, non-default MergeTree value, guarded exception, missing symbol) |
|
|
224
|
-
| `Schema#setTtl(ttl)` | `chs_schema_ttl` | rows-TTL expression | — | `UnsupportedError` (any nonzero rc: refused TTL form, guarded exception, missing symbol) |
|
|
225
|
-
| `Schema#row(format, raw, settings?)` | `chs_row` | format code, row **bytes**, per-call settings | `RowResult` (verdict in `outcome`, never thrown) | `ChtypesError` (closed schema, `number` setting); `UnsupportedError` (missing symbol) |
|
|
226
|
-
| `Schema#rows(format, body, settings?)` | `chs_rows` | format code, body **bytes**, per-call settings | `BatchResult` (`engineRows` is the stored truth when present) | `ChtypesError` (closed schema, `number` setting); `UnsupportedError` (missing symbol — same degradation as `row`) |
|
|
227
|
-
| `Schema#compileFilter(expr, {params}?)` | `chs_filter_compile` | one boolean expression; `params` binds `{name:Type}` — values are STRINGS, never hand-escaped | `Filter` (WHERE-side semantics by construction) | `SchemaError` (47 unknown identifier, **456** unbound param, **457** unparseable param value); `UnsupportedError` (clock reads, missing symbol) |
|
|
228
|
-
| `Filter#rows(format, body, settings?)` | `chs_filter_rows` | same contract as `Schema#rows` | `FilterResult` — per-row verdicts; `'error'`/`'decline'` are NOT answers, fail closed | `ChtypesError` (closed filter, `number` setting) |
|
|
229
|
-
| `Schema#parseBlock(format, body, settings?)` | `chs_block_parse` | parse a body ONCE; per-row parse failures live IN the block | `Block`, evaluable by K filters with no re-parse | `SchemaError` (115 unknown setting, framing, decode fault — no block, no partial answers); `UnsupportedError` (missing symbol) |
|
|
230
|
-
| `Filter#eval(block)` | `chs_filter_eval` | an already-parsed `Block` | the same `FilterResult` `rows` answers — `eval(parseBlock(body))` ≡ `rows(body)`; a cross-schema pair answers `'rejected'`/1002 | `ChtypesError` (closed handles, cross-library pair) |
|
|
231
|
-
| `Filter#close()` / `Block#close()` / `Symbol.dispose` | `chs_filter_free` / `chs_block_free` | — | — (`Schema#close` frees open filters and blocks FIRST — the C-required order) | never throw; idempotent |
|
|
232
|
-
| `Schema#close()` / `Symbol.dispose` | `chs_schema_free` | — | — | never throws; idempotent |
|
|
233
|
-
| `minorOf(version)` | — derived | version string | minor line | never throws |
|
|
234
|
-
| `compareMinor(a, b)` | — derived | two minor lines | numeric order (25.10 > 25.8) | never throws |
|
|
235
|
-
| `ensure(line, opts?)` / `ensureAll(opts?)` | — no C call (the `docs/fetch.md` chain) | line or exact patch; `EnsureOptions` | `Promise<EnsureResult>` / `Promise<EnsureResult[]>` | `ArtifactUntrustedError`, `ArtifactCorruptError`, `ArtifactPinnedError`, `ArtifactUnpublishedError`, `SourceUnreachableError` (each with its `code`); `ChtypesError` (bad spelling, platform key, conflicting options) |
|
|
236
|
-
| `verifyInstalled(dest?, platform?)` / `listArtifacts(opts?)` | — no C call | registry dir / `EnsureOptions` | `Promise<InstalledArtifact[]>` / `Promise<ListResult>` | `verifyInstalled` never throws; `listArtifacts` the `FetchError` verdicts unless `offline` |
|
|
237
|
-
| `registrySearchPath(explicit?, platform?)` / `fetchDestination(explicit?, platform?)` / `hostPlatform()` | — derived (`docs/fetch.md` §1) | path/env probing | `string[]` / `string` / `string` | never throw |
|
|
238
|
-
| `resolveRegistryDir(explicit?)` / `defaultRegistryDir()` / `looksLikeRegistry(dir)` | — derived | path/env probing | resolved dir / `string` / `boolean` | never throw |
|
|
239
|
-
| `formatName(f)` | — derived | format code | constant name | never throws |
|
|
240
|
-
| `encodeSettings(settings?)` | — derived | settings map | `settings_json` text | `ChtypesError` (a JS `number` value) |
|
|
241
|
-
| `parseVersionResult` / `parseChangedSettingsResult` / `parseColumnsResult` / `reconstructDdl` | — no C call (discovery kit) | query result bytes / discovered columns | version / settings map / columns / DDL string | `ChtypesError` on malformed input |
|
|
242
|
-
| `isLossyReason(reason)` | — derived | reason string | `boolean` (false for exactly 4 reasons) | never throws |
|
|
243
|
-
| `parseDocument` / `parseJsonValue` / `repairBareDenormals` / `rawBytes` / `rawText` / `isValidUtf8` | — derived (byte-exact JSON kit) | bytes | `Json` / `Json\|null` / repaired bytes / `Buffer` / `string` / `boolean` | `parseDocument` throws `ChtypesError` on a malformed document; the rest never throw |
|
|
244
|
-
| `nativeStats()` | — diagnostic | — | `{stringsTaken, stringsFreed}` | never throws |
|
|
43
|
+
A bad **row** is a verdict, not an exception: `outcome` becomes `'rejected'` with ClickHouse's own code and message. Exceptions are for schema-level answers — `compileDdl`, `setEngine`, `setTtl`, `validateType` — and there the class _is_ the verdict.
|
|
245
44
|
|
|
246
|
-
|
|
247
|
-
`
|
|
248
|
-
|
|
249
|
-
`ABI_REVISION` (4), `Outcome`, `RowResult`, `BatchResult`, `FilterResult`,
|
|
250
|
-
`Verdict`, `Value`, `Transform`, `Substitution`, `Computed`, `ColumnDoc`,
|
|
251
|
-
`ColumnInfo`, `EngineOptions`, `CompileOptions`, `CompileFilterOptions`,
|
|
252
|
-
`Settings`, `SettingValue`, `Reason`, `ServerProfile`, `DiscoveredColumn`,
|
|
253
|
-
`Manifest`, `RegistryOptions`, `EnsureOptions`, `EnsureResult`, `FetchEvent`,
|
|
254
|
-
`InstalledArtifact`, `ListResult`, `LockFile`, `ArtifactErrorCode`,
|
|
255
|
-
`RELEASE_PUBLIC_KEYS`, `Json`, `JsonKind`, and the error classes
|
|
256
|
-
`ChtypesError` (base), `RegistryError`, `ArtifactMissingError` (a
|
|
257
|
-
`RegistryError` with `code`), `FetchError` and its five verdict subclasses,
|
|
258
|
-
`SchemaError`, `UnsupportedError` (a **peer** of `SchemaError`, deliberately
|
|
259
|
-
not a subclass).
|
|
45
|
+
- `SchemaError` — the server refused, and `code` is a real ClickHouse code.
|
|
46
|
+
- `UnsupportedError` — chtypes declines to guess, and a real server might well have accepted. **Fall back to the server.**
|
|
47
|
+
- The two are **peers**: a decline never satisfies `instanceof SchemaError`.
|
|
260
48
|
|
|
261
|
-
##
|
|
49
|
+
## Documentation
|
|
262
50
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
every
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
(
|
|
51
|
+
| | |
|
|
52
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
53
|
+
| [Quickstart](https://github.com/wave-rf/chtypes/blob/main/docs/quickstart.md) | the same program in all four languages |
|
|
54
|
+
| [TypeScript API reference](https://github.com/wave-rf/chtypes/blob/main/docs/reference/ts.md) | every symbol, the C entry point under it, what it returns and what it throws |
|
|
55
|
+
| [Artifacts](https://github.com/wave-rf/chtypes/blob/main/docs/guides/artifacts.md) | getting one, where it lands, verifying and pinning it |
|
|
56
|
+
| [Batches](https://github.com/wave-rf/chtypes/blob/main/docs/guides/batches.md) | always `rows`, and the two bad-row policies |
|
|
57
|
+
| [Transformations](https://github.com/wave-rf/chtypes/blob/main/docs/guides/transformations.md) | the silent-change report, and the DEFAULTs you must echo back |
|
|
58
|
+
| [Settings](https://github.com/wave-rf/chtypes/blob/main/docs/guides/settings.md) · [Discovery](https://github.com/wave-rf/chtypes/blob/main/docs/guides/discovery.md) | the four channels; asking a real server what profile to validate under |
|
|
59
|
+
| [Filters](https://github.com/wave-rf/chtypes/blob/main/docs/guides/filters.md) · [Multi-version](https://github.com/wave-rf/chtypes/blob/main/docs/guides/multi-version.md) | boolean expressions over rows; several ClickHouse versions in one process |
|
|
60
|
+
| [Support matrix](https://github.com/wave-rf/chtypes/blob/main/docs/support.md) · [Limitations](https://github.com/wave-rf/chtypes/blob/main/docs/limitations.md) | what works where; what chtypes declines to answer |
|
|
273
61
|
|
|
274
|
-
|
|
275
|
-
parameters, bound with `compileFilter(expr, { params: { name: 'value' } })`
|
|
276
|
-
— values are **strings**, exactly as the server's own parameter channels
|
|
277
|
-
carry them. Substitution is the server's own `ReplaceQueryParameterVisitor`:
|
|
278
|
-
each value is deserialized by the DECLARED type's own reader and injected as
|
|
279
|
-
a typed literal AFTER SQL parsing, so a value is never SQL text and **must
|
|
280
|
-
never be hand-escaped into the expression** — injection safety is by
|
|
281
|
-
construction, and a hostile value (`' OR 1=1 --`) compares as exactly that
|
|
282
|
-
literal. An UNBOUND parameter is the server's own **456** ("Substitution
|
|
283
|
-
`name` is not set"), an unparseable value the server's own **457** — both
|
|
284
|
-
`SchemaError`, verbatim; a bound name the expression never uses is ignored.
|
|
285
|
-
The compiled handle bakes the values in — identity is per
|
|
286
|
-
(schema, expr, params) — so **a caller compiling filters from
|
|
287
|
-
tenant-influenced values MUST bound its cache and its compile rate**: a
|
|
288
|
-
bounded LRU keyed on (schema generation, expr, params-hash) plus a
|
|
289
|
-
per-principal compile throttle; an unbounded cache is a memory DoS and an
|
|
290
|
-
unmetered compile path is a CPU DoS (`spec/c-abi.md` §Filters, normative).
|
|
62
|
+
## Four things specific to this binding
|
|
291
63
|
|
|
292
|
-
|
|
293
|
-
deserialized by the brace type's OWN reader (`deserializeTextEscaped`),
|
|
294
|
-
which **wraps** an out-of-domain integer — `{p:UInt8}` given `"256"` binds
|
|
295
|
-
`0` and matches every genuine zero (measured, uniform 24.8–26.7,
|
|
296
|
-
server-matched) — while the same constant written as a literal in the
|
|
297
|
-
expression PROMOTES (`x = 256` over `UInt8` is simply never true). A
|
|
298
|
-
too-narrow parameter type therefore silently matches the wrong rows: size
|
|
299
|
-
the type for the tenant-supplied domain (`{p:UInt64}`, `{p:String}`) or
|
|
300
|
-
validate the value before binding it. Malformed integer spellings refuse
|
|
301
|
-
loudly with the server's own **457** (`"-1"`, `"+7"`, `"007"` as `UInt8`);
|
|
302
|
-
an empty string refuses with **32**. If one name is bound twice at the C
|
|
303
|
-
boundary, the LAST binding wins — the server's own `insert_or_assign` rule
|
|
304
|
-
(unreachable through this SDK's unique-keyed object, stated for
|
|
305
|
-
completeness).
|
|
64
|
+
**`using` is a syntax error on Node 22**, this package's own floor. Explicit resource management needs TypeScript to downlevel it for you, or plain JavaScript on Node ≥ 24. `close()` works everywhere and every disposable here has both, so portable examples use `close()`.
|
|
306
65
|
|
|
307
|
-
|
|
308
|
-
server's **TCP** channel a parameter *named* `limit` or `offset` fails at
|
|
309
|
-
the protocol layer with code 26 even when unused (params ride in a Settings
|
|
310
|
-
block there); HTTP is fine, and this library matches the HTTP/substitution
|
|
311
|
-
semantics. Avoid those two names for anything that will ever cross TCP.
|
|
66
|
+
**A settings value may be a `string` or a `bigint`, never a `number`.** The runtime rejects a `number`, because TypeScript is not present at a JS consumer's call site and a 19-digit `chtypes_now_epoch_nanos` does not survive an IEEE double — sent as a JSON number the setting would be silently ignored.
|
|
312
67
|
|
|
313
|
-
|
|
314
|
-
parses a body ONCE into a `Block` — the parse half of `Filter#rows` — and
|
|
315
|
-
`Filter#eval(block)` answers the same `FilterResult` with no re-parse: the
|
|
316
|
-
live-SSE hot path is K filters × 1 event, and the re-parse is shed.
|
|
317
|
-
Normative equivalence: `eval(parseBlock(body))` ≡ `rows(body)` for every
|
|
318
|
-
verdict class (volatile DEFAULTs resolve against the PARSE call's clock
|
|
319
|
-
instant — pin `chtypes_now_epoch_nanos` for cross-call identity).
|
|
320
|
-
Evaluation is a pure function of (filter, block), takes no settings, and
|
|
321
|
-
never consumes or mutates the block. Filter and block MUST come from the
|
|
322
|
-
SAME schema: a mismatched same-library pair answers `'rejected'`/1002
|
|
323
|
-
loudly, and a cross-library pair throws `ChtypesError` before any C call. A
|
|
324
|
-
`Block` follows the filter's lifetime rules exactly (`Schema#close` frees
|
|
325
|
-
open blocks first, and `using` nests naturally: block, filter, schema).
|
|
326
|
-
Parse-once does not open enforcement earlier: the twin is under the same
|
|
327
|
-
enforcement gate.
|
|
68
|
+
**`for()` never fetches; `open()` can.** `Registry#for(v)` is synchronous and resolves from the search path alone. `await registry.open(v)` is its async twin, and with `{ autofetch: true }` (or `CHTYPES_AUTOFETCH=1`) it fetches a missing line first. Off by default: a production process must not begin a 250 MB download inside a request.
|
|
328
69
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
Settings ride four channels; on the row path the leftmost channel that names a
|
|
332
|
-
setting wins:
|
|
333
|
-
|
|
334
|
-
per-call map > handle compile profile > library defaults (setDefaultSettings) > ClickHouse defaults
|
|
335
|
-
|
|
336
|
-
One documented exception: a **type gate** named in the compile profile
|
|
337
|
-
(`allow_suspicious_low_cardinality_types`, `allow_experimental_json_type`, …)
|
|
338
|
-
binds at compile and then **outranks the per-call map** for that handle's life
|
|
339
|
-
— exactly as a real server checks a gate at CREATE and never re-reads it per
|
|
340
|
-
INSERT.
|
|
341
|
-
|
|
342
|
-
Rules that cost real bugs:
|
|
343
|
-
|
|
344
|
-
- **Values are strings (or bigints).** A JS `number` is rejected at runtime:
|
|
345
|
-
`chtypes_now_epoch_nanos` is a 19-digit nanosecond epoch, which does not
|
|
346
|
-
survive an IEEE double — sent as a JSON number the setting is *silently
|
|
347
|
-
ignored*. Use `BigInt(…)` or a string; `bigint` crosses via `toString()`.
|
|
348
|
-
- **An unknown setting name rejects the whole call with the server's own
|
|
349
|
-
code 115** (with its did-you-mean hint), on every channel.
|
|
350
|
-
`setDefaultSettings` refuses **wholesale** — nothing committed.
|
|
351
|
-
- The six `chtypes_*` keys are the whole reserved namespace; anything else
|
|
352
|
-
spelled `chtypes_*` is an unknown name (115). Per-call:
|
|
353
|
-
`chtypes_now_epoch_nanos` (pin the batch instant),
|
|
354
|
-
`chtypes_clock_offset_nanos` (measured server−client offset),
|
|
355
|
-
`chtypes_max_clock_skew_nanos` (refuse volatile-DEFAULT substitution past
|
|
356
|
-
the budget). Process-wide, via `setDefaultSettings` only:
|
|
357
|
-
`chtypes_default_eval_memory_bytes` (default 256 MiB),
|
|
358
|
-
`chtypes_default_eval_wall_nanos` (default 1 s),
|
|
359
|
-
`chtypes_custom_settings_prefixes` (mirror of the server's
|
|
360
|
-
`custom_settings_prefixes`; ships as `SQL_`).
|
|
361
|
-
- A row whose `unsupportedSettings` list is non-empty is promoted to
|
|
362
|
-
`unsupported` (a KNOWN name whose value this build declines) — never scored
|
|
363
|
-
as agreement.
|
|
364
|
-
|
|
365
|
-
## Discovery
|
|
366
|
-
|
|
367
|
-
**The library never connects to ClickHouse.** It ships three SQL query
|
|
368
|
-
constants; your app runs them at connect time with whatever client it already
|
|
369
|
-
has, and declares what it learned. Never ask the customer — ask their server.
|
|
370
|
-
|
|
371
|
-
| constant | feeds |
|
|
372
|
-
|---|---|
|
|
373
|
-
| `QUERY_SERVER_VERSION` | `parseVersionResult` → `registry.for(version)` |
|
|
374
|
-
| `QUERY_CHANGED_SETTINGS` | `parseChangedSettingsResult` → the compile profile AND per-call settings |
|
|
375
|
-
| `QUERY_TABLE_COLUMNS` | `parseColumnsResult` → `reconstructDdl` → `compileDdl` (send `param_db`/`param_table`) |
|
|
376
|
-
|
|
377
|
-
```ts
|
|
378
|
-
const profile: ServerProfile = {
|
|
379
|
-
version: parseVersionResult(await run(QUERY_SERVER_VERSION)),
|
|
380
|
-
settings: parseChangedSettingsResult(await run(QUERY_CHANGED_SETTINGS)),
|
|
381
|
-
};
|
|
382
|
-
// cache per deployment/tenant, then:
|
|
383
|
-
const lib = registry.for(profile.version);
|
|
384
|
-
const schema = lib.compileDdl(ddl, { settings: profile.settings }); // CREATE-time
|
|
385
|
-
const res = schema.rows(Format.JSONEachRow, body, profile.settings); // per-call
|
|
386
|
-
```
|
|
70
|
+
**`worker_threads` is the boundary.** Two JS threads share one dlopen'd image and one set of C globals, which no per-isolate counter can see. Seed default settings before starting workers, and do not share a `Schema` across them.
|
|
387
71
|
|
|
388
|
-
|
|
389
|
-
reader — `position` survives quoted and bare spellings without a float
|
|
390
|
-
round-trip, and `default_kind`/`default_expression` are carried (dropping them
|
|
391
|
-
silently loses DEFAULT/MATERIALIZED semantics). A typo'd setting name in the
|
|
392
|
-
declared profile fails the **compile** with the server's own 115 — caught at
|
|
393
|
-
declare time, not swallowed.
|
|
72
|
+
## Tests
|
|
394
73
|
|
|
395
|
-
|
|
74
|
+
`pnpm test`. Tests that need an artifact **skip loudly by name** without a registry on the search path, and a suite that ran nothing fails. The fetch suite runs offline against the miniature releases in `tests/fixtures/fetch/`.
|
|
396
75
|
|
|
397
|
-
|
|
398
|
-
`RTLD_LOCAL` (that is the whole mechanism letting two builds that both
|
|
399
|
-
define `DB::DataTypeFactory` share a process); cost ≈ 120 MB resident per
|
|
400
|
-
loaded version.
|
|
401
|
-
- `for()` resolves a minor line (`"25.8"`) or an exact patch
|
|
402
|
-
(`"25.8.28.1-lts"`); an unknown patch inside a loaded minor resolves to the
|
|
403
|
-
line. Failure is `ArtifactMissingError`, naming every directory looked in
|
|
404
|
-
— never a fallback to the nearest version. Version behaviour is
|
|
405
|
-
non-monotonic; never infer one version's answer from another's.
|
|
406
|
-
- Every call is **synchronous on the JS thread**; ordinary single-threaded
|
|
407
|
-
Node code needs no locking. `setDefaultSettings` and `shutdown` carry a
|
|
408
|
-
reentrancy tripwire (the `NativeLibrary#inCall` counter) and refuse loudly
|
|
409
|
-
if another chtypes call is on the stack — they replace process-global state
|
|
410
|
-
the row path reads by reference.
|
|
411
|
-
- **`worker_threads` is the boundary.** Two JS threads share one dlopen'd
|
|
412
|
-
image and one set of C globals, which no per-isolate counter can see. Seed
|
|
413
|
-
default settings BEFORE starting workers, or serialise the seed yourself;
|
|
414
|
-
do not share a `Schema` across workers.
|
|
415
|
-
- Teardown: `registry.close()` / `library.shutdown()` (or `using` /
|
|
416
|
-
`Symbol.dispose`) join the DEFAULT evaluator's background threads —
|
|
417
|
-
required before any explicit unload; an ordinary process is covered by
|
|
418
|
-
`atexit`.
|
|
76
|
+
Working against a checkout: build `dist/` first (`pnpm install && pnpm build`) — that is what `package.json#exports` serves. If a linked copy goes stale, note that `pnpm install --force` does **not** relink; remove `node_modules` and reinstall.
|
|
419
77
|
|
|
420
|
-
##
|
|
78
|
+
## License
|
|
421
79
|
|
|
422
|
-
|
|
423
|
-
server might well have accepted this; chtypes will not guess" — fall back
|
|
424
|
-
to the server (`spec/c-abi.md` §Error model). Unmodelled engines, sorting
|
|
425
|
-
keys and TTL forms (WHERE/GROUP BY TTLs, TO DISK/VOLUME, RECOMPRESS,
|
|
426
|
-
clock-reading TTLs) decline rather than guess.
|
|
427
|
-
- **EPHEMERAL columns:** a format stream carries no column list, so an INSERT
|
|
428
|
-
that names an EPHEMERAL column in an explicit column list cannot be
|
|
429
|
-
previewed here — detect via `Schema#columns` (`defaultKind ===
|
|
430
|
-
'EPHEMERAL'`) and decline that intersection, never mispreview
|
|
431
|
-
(`spec/bindings.md` §EPHEMERAL).
|
|
432
|
-
- **macOS artifacts are a dev floor, not an oracle:** `long double` is
|
|
433
|
-
53-bit, so float parses diverge from real servers (Linux matches 395/395 of
|
|
434
|
-
the float corpus; macOS 0/395). Float expectations must come from a Linux
|
|
435
|
-
artifact or a live server.
|
|
436
|
-
- Everything here is **insert-side** coercion. Never fold a `WHERE`-clause
|
|
437
|
-
constant through `row`/`rows` — comparison rules differ; refuse an operand
|
|
438
|
-
outside the column type's domain instead (`spec/bindings.md` §Constants are
|
|
439
|
-
not payloads).
|
|
440
|
-
- Binary formats (`RowBinary` family, `Native`, `Buffers`) parse only on
|
|
441
|
-
artifacts new enough to carry the reader — probe the artifact; earlier ones
|
|
442
|
-
answer 73/117 exactly as their servers do.
|
|
80
|
+
Apache 2.0. The artifacts this package loads are **Elastic License 2.0** — a separate license, shipped inside each artifact release, and `fetch` says so once.
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* `chtypes` — the one CLI surface every SDK carries (docs/fetch.md §6),
|
|
3
|
+
* `chtypes` — the one CLI surface every SDK carries (docs/guides/fetch.md §6),
|
|
4
4
|
* spelled identically in all four:
|
|
5
5
|
*
|
|
6
6
|
* chtypes fetch <line>... [--all] [--platform <os-arch>] [--dest <dir>]
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,yBAAyB;AACzB,eAAO,MAAM,IAAI;aACf,EAAE,EAAE,CAAC;aACL,kBAAkB,EAAE,CAAC;aACrB,KAAK,EAAE,CAAC;aACR,iBAAiB,EAAE,CAAC;aACpB,WAAW,EAAE,CAAC;CACN,CAAC;AAEX,yDAAyD;AACzD,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpC;AAmCD;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAE,KAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuC5F"}
|