@wavehouse/sdk 0.0.0-dev.h8ea15a023aa2 → 0.0.0-dev.h9539004107f0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/cli/codegen.js +62 -18
- package/dist/index.cjs +424 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +179 -8
- package/dist/index.d.ts +179 -8
- package/dist/index.global.js +11 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +424 -89
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @wavehouse/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript client for [WaveHouse](https://github.com/Wave-RF/WaveHouse) — schema-aware real-time API gateway for ClickHouse. One runtime dependency (`eventsource-parser`, ~1.4 KB gzipped, itself dependency-free).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,6 +8,8 @@ Zero-dependency TypeScript client for [WaveHouse](https://github.com/Wave-RF/Wav
|
|
|
8
8
|
npm install @wavehouse/sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
Requires Node 22 or newer — the only line this SDK is tested against; Node 18 and 20 are past upstream end-of-life. Neither browsers nor Node need a polyfill: streaming runs on `fetch`, like the rest of the SDK — see [Runtime support](https://wavehouse.dev/sdk/#runtime-support).
|
|
12
|
+
|
|
11
13
|
This works in any framework that uses a bundler — React, Vue, Svelte, Angular, Astro, SolidJS, or plain Vite — with `import { createClient } from '@wavehouse/sdk'`.
|
|
12
14
|
|
|
13
15
|
The package is published with [npm provenance](https://docs.npmjs.com/generating-provenance-statements) — npm shows a verified provenance badge on the [package page](https://www.npmjs.com/package/@wavehouse/sdk), and `npm audit signatures` checks the attestation against this repository's signed build.
|
|
@@ -42,7 +44,7 @@ Pin a version for production (`https://esm.sh/@wavehouse/sdk@0.1.0`). jsDelivr (
|
|
|
42
44
|
|
|
43
45
|
**Versioning.** A bare CDN URL serves the latest published **release**; pin for production (`@wavehouse/sdk@0.1.0`) or float on a range (`@0` for the newest 0.x, `@0.1` for 0.1.x). Builds from `main` are published under the `dev` tag — `@wavehouse/sdk@dev` — for trying unreleased changes.
|
|
44
46
|
|
|
45
|
-
Streaming (`.stream()`)
|
|
47
|
+
Streaming (`.stream()`) runs on `fetch`, so it works in both forms with no polyfill.
|
|
46
48
|
|
|
47
49
|
## Quick Start
|
|
48
50
|
|
|
@@ -55,6 +57,8 @@ const wh = createClient({
|
|
|
55
57
|
});
|
|
56
58
|
```
|
|
57
59
|
|
|
60
|
+
`baseURL` may include a path prefix (`https://app.example.com/api/warehouse`) when WaveHouse is served under one — see [Serving under a path prefix](https://wavehouse.dev/sdk#serving-under-a-path-prefix).
|
|
61
|
+
|
|
58
62
|
### Query Data
|
|
59
63
|
|
|
60
64
|
```ts
|
|
@@ -125,7 +129,9 @@ const { data } = await wh.from('clicks').select('page').limit(10);
|
|
|
125
129
|
|
|
126
130
|
## Error Handling
|
|
127
131
|
|
|
128
|
-
|
|
132
|
+
Async request methods return a `Result<T>` object — destructure it as `{ data, error }` — and never throw for anything the server returns. `.stream()` and `.liveQuery()` return controllers instead, reporting failures through the subscriber's `error` callback.
|
|
133
|
+
|
|
134
|
+
The SDK does throw on caller and environment errors: a non-absolute `baseURL` (REST calls reject with a `TypeError`; streams report a terminal `SSE_CONNECT_ERROR`), `.stream()` / `.liveQuery()` in a runtime with no global `fetch` and no `options.fetch`, and an `auth` callback that rejects — a token-refresh failure propagates out of the REST call, and on a stream is reported as a retryable `SSE_AUTH_ERROR`. A dropped stream *is* re-dialed by the SDK, on a jittered backoff; only non-retryable failures end it. One more exception can escape an SDK call, though it is yours rather than ours: a subscriber's `status` handler throwing on the first, synchronous `.subscribe()` / `.liveQuery()` call — see [Error Handling](https://wavehouse.dev/sdk/reference#error-handling).
|
|
129
135
|
|
|
130
136
|
```ts
|
|
131
137
|
const { data, error } = await wh.from('clicks').fetch();
|
|
@@ -144,7 +150,7 @@ Generate TypeScript types from your live WaveHouse schema. The package ships a `
|
|
|
144
150
|
npx wavehouse-codegen --url http://localhost:8080 --out ./src/db.d.ts
|
|
145
151
|
```
|
|
146
152
|
|
|
147
|
-
This introspects `/v1/schema`, maps ClickHouse column types to TypeScript, and outputs a `Database` interface you can pass to `createClient<Database>()`. `/v1/schema` is **admin-only** — pass an admin-role token with `--auth <jwt>` (or `-a`) against any non-dev policy.
|
|
153
|
+
This introspects `/v1/ops/schema`, maps ClickHouse column types to TypeScript, and outputs a `Database` interface you can pass to `createClient<Database>()`. `/v1/ops/schema` is **admin-only** — pass an admin-role token with `--auth <jwt>` (or `-a`) against any non-dev policy.
|
|
148
154
|
|
|
149
155
|
## Development & Testing
|
|
150
156
|
|
package/dist/cli/codegen.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/cli/codegen.ts
|
|
4
|
+
import { realpathSync } from "fs";
|
|
5
|
+
import { pathToFileURL } from "url";
|
|
6
|
+
|
|
7
|
+
// src/url.ts
|
|
8
|
+
function resolveURL(base, path, params) {
|
|
9
|
+
const root = new URL(base);
|
|
10
|
+
root.search = "";
|
|
11
|
+
root.hash = "";
|
|
12
|
+
if (!root.pathname.endsWith("/")) root.pathname += "/";
|
|
13
|
+
const url = new URL(path.replace(/^\/+/, ""), root);
|
|
14
|
+
if (params) {
|
|
15
|
+
for (const [k, v] of Object.entries(params)) {
|
|
16
|
+
url.searchParams.set(k, v);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return url;
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
// src/cli/codegen.ts
|
|
4
23
|
function parseArgs(argv) {
|
|
5
24
|
const args = { url: "http://localhost:8080", out: "./wavehouse.d.ts" };
|
|
@@ -92,15 +111,29 @@ function findTopLevelComma(s) {
|
|
|
92
111
|
}
|
|
93
112
|
return -1;
|
|
94
113
|
}
|
|
114
|
+
function isColumn(value) {
|
|
115
|
+
if (typeof value !== "object" || value === null) return false;
|
|
116
|
+
const col = value;
|
|
117
|
+
return typeof col.name === "string" && typeof col.type === "string";
|
|
118
|
+
}
|
|
119
|
+
function isTableSchema(value) {
|
|
120
|
+
if (typeof value !== "object" || value === null) return false;
|
|
121
|
+
const table = value;
|
|
122
|
+
return typeof table.name === "string" && Array.isArray(table.columns) && table.columns.every(isColumn);
|
|
123
|
+
}
|
|
95
124
|
async function fetchSchemas(url, auth) {
|
|
96
125
|
const headers = {};
|
|
97
126
|
if (auth) headers.Authorization = `Bearer ${auth}`;
|
|
98
|
-
const res = await fetch(
|
|
127
|
+
const res = await fetch(resolveURL(url, "/v1/ops/schema").toString(), { headers });
|
|
99
128
|
if (!res.ok) {
|
|
100
129
|
const text = await res.text();
|
|
101
130
|
throw new Error(`Schema fetch failed (${res.status}): ${text}`);
|
|
102
131
|
}
|
|
103
|
-
|
|
132
|
+
const body = await res.json();
|
|
133
|
+
if (!Array.isArray(body) || !body.every(isTableSchema)) {
|
|
134
|
+
throw new Error("Unexpected /v1/ops/schema response: expected a JSON array of table schemas");
|
|
135
|
+
}
|
|
136
|
+
return body;
|
|
104
137
|
}
|
|
105
138
|
function generateTypes(schemas) {
|
|
106
139
|
const lines = [
|
|
@@ -110,19 +143,16 @@ function generateTypes(schemas) {
|
|
|
110
143
|
"",
|
|
111
144
|
"export interface Database {"
|
|
112
145
|
];
|
|
113
|
-
const
|
|
114
|
-
for (const
|
|
115
|
-
|
|
116
|
-
const rowType = `${pascalCase(tableName)}Row`;
|
|
117
|
-
lines.push(` ${tableName}: ${rowType};`);
|
|
146
|
+
const tables = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
147
|
+
for (const table of tables) {
|
|
148
|
+
lines.push(` ${table.name}: ${pascalCase(table.name)}Row;`);
|
|
118
149
|
}
|
|
119
150
|
lines.push("}");
|
|
120
151
|
lines.push("");
|
|
121
|
-
for (const
|
|
122
|
-
const
|
|
123
|
-
const rowType = `${pascalCase(tableName)}Row`;
|
|
152
|
+
for (const table of tables) {
|
|
153
|
+
const rowType = `${pascalCase(table.name)}Row`;
|
|
124
154
|
lines.push(`export interface ${rowType} {`);
|
|
125
|
-
for (const col of
|
|
155
|
+
for (const col of table.columns) {
|
|
126
156
|
const tsType = chTypeToTS(col.type);
|
|
127
157
|
const optional = col.has_default ? "?" : "";
|
|
128
158
|
lines.push(` ${col.name}${optional}: ${tsType};`);
|
|
@@ -139,12 +169,11 @@ async function main() {
|
|
|
139
169
|
const args = parseArgs(process.argv);
|
|
140
170
|
console.log(`Fetching schema from ${args.url}...`);
|
|
141
171
|
const schemas = await fetchSchemas(args.url, args.auth);
|
|
142
|
-
|
|
143
|
-
if (tableCount === 0) {
|
|
172
|
+
if (schemas.length === 0) {
|
|
144
173
|
console.warn("No tables found. Is WaveHouse running with tables in ClickHouse?");
|
|
145
174
|
process.exit(1);
|
|
146
175
|
}
|
|
147
|
-
console.log(`Found ${
|
|
176
|
+
console.log(`Found ${schemas.length} table(s): ${schemas.map((t) => t.name).join(", ")}`);
|
|
148
177
|
const output = generateTypes(schemas);
|
|
149
178
|
const { writeFile } = await import("fs/promises");
|
|
150
179
|
const { resolve } = await import("path");
|
|
@@ -152,7 +181,22 @@ async function main() {
|
|
|
152
181
|
await writeFile(outPath, output, "utf-8");
|
|
153
182
|
console.log(`\u2713 Types written to ${outPath}`);
|
|
154
183
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
184
|
+
function isDirectInvocation() {
|
|
185
|
+
if (!process.argv[1]) return false;
|
|
186
|
+
try {
|
|
187
|
+
return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (isDirectInvocation()) {
|
|
193
|
+
main().catch((err) => {
|
|
194
|
+
console.error("Codegen failed:", err.message);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
chTypeToTS,
|
|
200
|
+
fetchSchemas,
|
|
201
|
+
generateTypes
|
|
202
|
+
};
|