@wavehouse/sdk 0.0.0-dev.h514be5522d89 → 0.0.0-dev.h7362ab3863f6
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 +12 -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 +194 -9
- package/dist/index.d.ts +194 -9
- 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 +7 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/** User-provided database schema mapping table names to row types. */
|
|
2
2
|
type Database = Record<string, Record<string, unknown>>;
|
|
3
3
|
/**
|
|
4
|
-
* Discriminated union for
|
|
4
|
+
* Discriminated union for the async SDK calls that return one. Never throws for
|
|
5
|
+
* anything the server returns; a non-absolute `baseURL` and a rejecting `auth`
|
|
6
|
+
* callback do throw, while a runtime with no `fetch` at all surfaces instead as
|
|
7
|
+
* a retried `NETWORK_ERROR` result.
|
|
8
|
+
*
|
|
9
|
+
* `.stream()` and `.liveQuery()` return no `Result` and report the same three
|
|
10
|
+
* differently: a non-absolute `baseURL` reaches the subscriber's `error`
|
|
11
|
+
* callback as a terminal `SSE_CONNECT_ERROR`, a rejecting `auth` as a retryable
|
|
12
|
+
* `SSE_AUTH_ERROR`, and only a missing `fetch` throws from the call itself.
|
|
5
13
|
*
|
|
6
14
|
* Discriminated on `ok`: `if (result.ok)` narrows to the success arm (and tells
|
|
7
15
|
* the compiler `data` is present), while `error` is always available for
|
|
@@ -47,16 +55,147 @@ interface StreamSubscriber<T = Record<string, unknown>> {
|
|
|
47
55
|
error?: (err: WaveHouseError) => void;
|
|
48
56
|
}
|
|
49
57
|
interface ClientConfig<_DB extends Database = Database> {
|
|
50
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Base URL of the WaveHouse server (e.g. "http://localhost:8080"). May include
|
|
60
|
+
* a path prefix ("https://app.example.com/api/warehouse") for a WaveHouse
|
|
61
|
+
* behind a backend-for-frontend (BFF), app-server route, or path-routed
|
|
62
|
+
* ingress; request paths are appended to it. The proxy in front must strip
|
|
63
|
+
* the prefix before forwarding.
|
|
64
|
+
*
|
|
65
|
+
* Must be **absolute** — scheme and host included. The transports report a
|
|
66
|
+
* relative value such as "/api/warehouse" differently: a REST call rejects
|
|
67
|
+
* with a `TypeError` instead of returning a `Result`, while a stream reports
|
|
68
|
+
* `SSE_CONNECT_ERROR` to the subscriber's `error` callback. Build an absolute
|
|
69
|
+
* one: `` `${location.origin}/api/warehouse` ``.
|
|
70
|
+
*/
|
|
51
71
|
baseURL: string;
|
|
52
72
|
/** Auth token provider. Omit for public/unauthenticated access. */
|
|
53
73
|
auth?: () => Promise<string> | string;
|
|
54
74
|
/** Additional client options. */
|
|
55
75
|
options?: ClientOptions;
|
|
56
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* A `fetch`-compatible function.
|
|
79
|
+
*
|
|
80
|
+
* Spelled out rather than written `typeof fetch`, which resolves differently
|
|
81
|
+
* depending on whether the consumer's TypeScript `lib` includes DOM — the same
|
|
82
|
+
* signature either way, but stable across configurations.
|
|
83
|
+
*
|
|
84
|
+
* The parameter is `string` rather than `typeof fetch`'s wider union because a
|
|
85
|
+
* string URL is all the SDK ever passes. Since parameters are contravariant,
|
|
86
|
+
* narrowing it *widens* what can be assigned: the global `fetch` still fits, and
|
|
87
|
+
* so does hand-written `(url: string, init?: RequestInit) => Promise<Response>`
|
|
88
|
+
* middleware, which the wider spelling rejects at compile time.
|
|
89
|
+
*
|
|
90
|
+
* On REST the SDK reads `.ok` and `.headers` always, `.text()` on success, and
|
|
91
|
+
* `.status`, `.statusText` plus `.json()` when the response is not `ok`. A
|
|
92
|
+
* rejection becomes a `NETWORK_ERROR` result and is retried with backoff —
|
|
93
|
+
* unless the `AbortSignal` you passed has been aborted, in which case the
|
|
94
|
+
* result is `ABORTED` and nothing is retried. That is decided from the signal
|
|
95
|
+
* rather than the rejection's type, so an implementation that throws something
|
|
96
|
+
* other than a `DOMException` named `AbortError` — `AbortSignal.timeout()`,
|
|
97
|
+
* `node-fetch` — is reported the same way.
|
|
98
|
+
*
|
|
99
|
+
* **Streaming needs more.** `.stream()` and `.liveQuery()` read the response as
|
|
100
|
+
* it arrives, via `.body.getReader()`, so an implementation used with them must
|
|
101
|
+
* return a response carrying a live `ReadableStream` — something the type cannot
|
|
102
|
+
* enforce, since `Response.body` is legitimately nullable. A response handed
|
|
103
|
+
* back with an absent or already-consumed body fails fast with
|
|
104
|
+
* `SSE_NO_STREAM_BODY`. What the SDK *cannot* rescue is an implementation that
|
|
105
|
+
* awaits the body before returning — `await res.text()`, or the
|
|
106
|
+
* `res.clone().text()` a logging wrapper reaches for — because on a stream that
|
|
107
|
+
* never ends, that never resolves and your function never returns. Both satisfy
|
|
108
|
+
* every REST call, which is what makes the trap easy to walk into.
|
|
109
|
+
*
|
|
110
|
+
* Implementations shipping their own request/response declarations (undici,
|
|
111
|
+
* `node-fetch`) need casts on the init and the return value, since those types
|
|
112
|
+
* are separate from the ones behind your global `fetch`; the narrow runtime
|
|
113
|
+
* contract above is what makes them safe.
|
|
114
|
+
*/
|
|
115
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
57
116
|
interface ClientOptions {
|
|
58
117
|
/** Maximum retry attempts for failed requests. Default: 2. */
|
|
59
118
|
maxRetries?: number;
|
|
119
|
+
/**
|
|
120
|
+
* HTTP implementation used for every request, REST and streaming alike.
|
|
121
|
+
* Defaults to the global `fetch`.
|
|
122
|
+
*
|
|
123
|
+
* Provide one to route through a proxy, attach client certificates, add
|
|
124
|
+
* middleware (logging, tracing, circuit breaking), or bypass a transport bug
|
|
125
|
+
* in the runtime's bundled HTTP stack by routing through an implementation
|
|
126
|
+
* you install yourself — e.g. an undici new enough to be free of
|
|
127
|
+
* {@link https://github.com/nodejs/undici/issues/5600 | undici #5600}:
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* import { Agent, fetch as undiciFetch } from "undici"; // npm install undici — 8.10.0+
|
|
131
|
+
* // Pass the dispatcher explicitly: undici's pool lives on a shared
|
|
132
|
+
* // globalThis symbol claimed by whichever copy loaded first, so an implied
|
|
133
|
+
* // dispatcher can still be the runtime's affected one.
|
|
134
|
+
* const dispatcher = new Agent();
|
|
135
|
+
* createClient({
|
|
136
|
+
* baseURL,
|
|
137
|
+
* options: {
|
|
138
|
+
* fetch: (url, init) =>
|
|
139
|
+
* undiciFetch(url, { ...init, dispatcher } as never) as unknown as Promise<Response>,
|
|
140
|
+
* },
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* `.stream()` and `.liveQuery()` go through it too, which imposes the extra
|
|
145
|
+
* streaming requirement described on {@link FetchLike} — read that before
|
|
146
|
+
* supplying a wrapper that touches the response body.
|
|
147
|
+
*/
|
|
148
|
+
fetch?: FetchLike;
|
|
149
|
+
/**
|
|
150
|
+
* Headers added to every request, REST and streaming alike — for a
|
|
151
|
+
* header-gated proxy in front of WaveHouse, such as a Cloudflare Access
|
|
152
|
+
* service token.
|
|
153
|
+
*
|
|
154
|
+
* Matched case-insensitively, as HTTP headers are. Applied underneath the
|
|
155
|
+
* SDK's own headers: `auth` still owns `Authorization`, and the
|
|
156
|
+
* `Content-Type` and `Accept` a given request needs are not overridable
|
|
157
|
+
* here — a global `Content-Type` that outranked the request's own is a
|
|
158
|
+
* documented way to break uploads.
|
|
159
|
+
*
|
|
160
|
+
* In a browser these are subject to CORS: a header outside the safelist adds
|
|
161
|
+
* it to the preflight, which the origin must allow. WaveHouse's own CORS
|
|
162
|
+
* advertises a fixed set, so custom headers reach it cross-origin only when
|
|
163
|
+
* a proxy in front terminates the preflight — which is the deployment they
|
|
164
|
+
* exist for. Server-side callers never preflight.
|
|
165
|
+
*/
|
|
166
|
+
headers?: Record<string, string>;
|
|
167
|
+
/**
|
|
168
|
+
* Extra `RequestInit` fields merged into every request — `credentials` for a
|
|
169
|
+
* cookie-authenticated origin, `mode`, `cache`, `keepalive`, or a
|
|
170
|
+
* runtime-specific extension such as Next.js's `next: { tags }`.
|
|
171
|
+
*
|
|
172
|
+
* Fields the SDK controls (`method`, `headers`, `body`, `signal`) always
|
|
173
|
+
* win, so this cannot corrupt the request itself. Non-standard fields may
|
|
174
|
+
* need a cast, since `RequestInit` only declares the standard ones.
|
|
175
|
+
*
|
|
176
|
+
* The streaming transport additionally owns `cache` and `redirect`, where the
|
|
177
|
+
* values are load-bearing rather than preference: a `Cache-Control` header
|
|
178
|
+
* would fail cross-origin preflight, and following a redirect would strip the
|
|
179
|
+
* `Authorization` header on a cross-origin hop and silently downgrade the
|
|
180
|
+
* stream to the default role instead of failing. So a request carrying an
|
|
181
|
+
* `auth` token, or configured `headers` that may hold a proxy secret, refuses
|
|
182
|
+
* redirects (`SSE_REDIRECT`); without either it follows them, so CDN
|
|
183
|
+
* canonicalization and an http→https upgrade still work. Note the test is
|
|
184
|
+
* that concrete pair, not "is this authenticated" — **cookies are invisible
|
|
185
|
+
* to it**. A cookie is re-derived from the cookie store at each hop rather
|
|
186
|
+
* than carried, so under the default `same-origin` credentials mode a
|
|
187
|
+
* redirect keeps the stream authenticated only while the hop stays inside
|
|
188
|
+
* both the request's origin and the cookie's `Path`; a hop outside either
|
|
189
|
+
* arrives with no cookie and gets a `default_role` view rather than an error.
|
|
190
|
+
* With `credentials: "include"` the origin half is replaced rather than
|
|
191
|
+
* lifted: ordinary cookie scoping decides, so the cookie crosses a
|
|
192
|
+
* CORS-allowed cross-origin hop only if its own `Domain` covers the target —
|
|
193
|
+
* a host-only cookie, the default, still stops at its host. Spelled out
|
|
194
|
+
* under "Supplying your own `fetch`" in the SDK guide; see #478.
|
|
195
|
+
* `credentials` itself is honored in browsers and dropped elsewhere, since
|
|
196
|
+
* some runtimes throw if it is set.
|
|
197
|
+
*/
|
|
198
|
+
fetchOptions?: RequestInit;
|
|
60
199
|
}
|
|
61
200
|
interface StructuredQuery {
|
|
62
201
|
/**
|
|
@@ -172,8 +311,22 @@ interface RolePermissions {
|
|
|
172
311
|
check?: Record<string, PolicyFilter>;
|
|
173
312
|
allowed_aggregations?: string[];
|
|
174
313
|
denied_aggregations?: string[];
|
|
314
|
+
/** Caps the query result LIMIT. 0 = no limit. */
|
|
175
315
|
max_rows?: number;
|
|
176
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Max query execution time, enforced server-side by ClickHouse. Set it as a
|
|
318
|
+
* duration string ("5s", "500ms") or a number of milliseconds; reads always
|
|
319
|
+
* return the number of milliseconds.
|
|
320
|
+
*/
|
|
321
|
+
max_execution_time?: number | string;
|
|
322
|
+
/** Max rows scanned from storage, enforced server-side by ClickHouse. 0 = no limit. */
|
|
323
|
+
max_rows_to_read?: number;
|
|
324
|
+
/**
|
|
325
|
+
* Max peak query memory, enforced server-side by ClickHouse. Set it as a size
|
|
326
|
+
* string ("4GiB", "512MiB") or a number of bytes; reads always return the
|
|
327
|
+
* number of bytes.
|
|
328
|
+
*/
|
|
329
|
+
max_memory_usage?: number | string;
|
|
177
330
|
}
|
|
178
331
|
interface PolicyFilter {
|
|
179
332
|
_eq?: string;
|
|
@@ -185,10 +338,32 @@ interface PolicyFilter {
|
|
|
185
338
|
interface ValidationResult {
|
|
186
339
|
valid: boolean;
|
|
187
340
|
}
|
|
188
|
-
|
|
341
|
+
/**
|
|
342
|
+
* Options for a single call, passed to `.fetch()`.
|
|
343
|
+
*
|
|
344
|
+
* Note that `await`ing a builder directly (`await wh.from("t").select("*")`)
|
|
345
|
+
* takes no options — use the explicit `.fetch({ … })` form for those.
|
|
346
|
+
*/
|
|
347
|
+
interface RequestOptions {
|
|
189
348
|
signal?: AbortSignal;
|
|
190
349
|
limit?: number;
|
|
191
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Options for a single `PipeRef.fetch()` call.
|
|
353
|
+
*
|
|
354
|
+
* `limit` is declared `never` rather than simply left out. Omitting it would
|
|
355
|
+
* still admit a `RequestOptions` value that carries one — excess-property
|
|
356
|
+
* checking only rejects fresh object literals, so a variable would pass and the
|
|
357
|
+
* limit would be silently dropped, which is the whole defect this prevents.
|
|
358
|
+
*
|
|
359
|
+
* A pipe's row cap belongs in its SQL as a `{{limit}}` parameter, supplied via
|
|
360
|
+
* `wh.pipe(name, { limit })`.
|
|
361
|
+
*/
|
|
362
|
+
interface PipeRequestOptions {
|
|
363
|
+
signal?: AbortSignal;
|
|
364
|
+
/** Not supported on pipes — pass `limit` as a pipe parameter instead. */
|
|
365
|
+
limit?: never;
|
|
366
|
+
}
|
|
192
367
|
interface StreamOptions {
|
|
193
368
|
since?: string;
|
|
194
369
|
signal?: AbortSignal;
|
|
@@ -199,6 +374,9 @@ interface HttpContext {
|
|
|
199
374
|
auth?: () => Promise<string> | string;
|
|
200
375
|
options: {
|
|
201
376
|
maxRetries: number;
|
|
377
|
+
fetch?: FetchLike;
|
|
378
|
+
headers?: Record<string, string>;
|
|
379
|
+
fetchOptions?: RequestInit;
|
|
202
380
|
};
|
|
203
381
|
}
|
|
204
382
|
|
|
@@ -275,8 +453,15 @@ declare class PipeRef<Row = Record<string, unknown>> implements PromiseLike<Resu
|
|
|
275
453
|
private readonly _params?;
|
|
276
454
|
private readonly _createStream;
|
|
277
455
|
constructor(ctx: HttpContext, name: string, params: Record<string, unknown> | undefined, createStream: CreateStreamFn$2<Row>);
|
|
278
|
-
/**
|
|
279
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Execute the pipe and return results.
|
|
458
|
+
*
|
|
459
|
+
* Takes only `signal` — deliberately narrower than the `RequestOptions` the
|
|
460
|
+
* query builder accepts. The pipes endpoint binds the body as the pipe's
|
|
461
|
+
* parameters, so there is no row cap to forward; give the pipe a `{{limit}}`
|
|
462
|
+
* parameter in its SQL and pass it via `wh.pipe(name, { limit })`.
|
|
463
|
+
*/
|
|
464
|
+
fetch(opts?: PipeRequestOptions): Promise<Result<Row[]>>;
|
|
280
465
|
/** Subscribe to live events from the pipe's underlying query. */
|
|
281
466
|
stream(opts?: StreamOptions): StreamController<Row>;
|
|
282
467
|
then<TResult1 = Result<Row[]>, TResult2 = never>(onfulfilled?: ((value: Result<Row[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
@@ -423,7 +608,7 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
|
|
|
423
608
|
cacheTTL(seconds: number): QueryBuilder<Row>;
|
|
424
609
|
/** Default row limit when none is specified — deliberately tighter than the backend's DefaultMaxRows (10000) safety cap. */
|
|
425
610
|
static readonly DEFAULT_LIMIT = 1000;
|
|
426
|
-
fetch(opts?:
|
|
611
|
+
fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
|
|
427
612
|
stream(opts?: StreamOptions): StreamController<Row>;
|
|
428
613
|
/**
|
|
429
614
|
* Start a live query: fetches historical data, then streams live updates.
|
|
@@ -459,7 +644,7 @@ declare class TableRef<Row = Record<string, unknown>> {
|
|
|
459
644
|
private readonly _createStream;
|
|
460
645
|
constructor(ctx: HttpContext, table: string, createStream: CreateStreamFn<Row>);
|
|
461
646
|
/** SELECT * shortcut — fetches rows with optional pagination. */
|
|
462
|
-
fetch(opts?:
|
|
647
|
+
fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
|
|
463
648
|
/** Start building a typed query. Returns an immutable, PromiseLike QueryBuilder. */
|
|
464
649
|
select(...columns: string[]): QueryBuilder<Row>;
|
|
465
650
|
/**
|
|
@@ -549,4 +734,4 @@ declare class WaveHouseClient<DB extends Database = Database> {
|
|
|
549
734
|
/** Create a new WaveHouse client instance. */
|
|
550
735
|
declare function createClient<DB extends Database = Database>(config: ClientConfig<DB>): WaveHouseClient<DB>;
|
|
551
736
|
|
|
552
|
-
export { type Aggregation, type ClientConfig, type ClientOptions, type Column, DLQNamespace, type DLQStats, type Database, type
|
|
737
|
+
export { type Aggregation, type ClientConfig, type ClientOptions, type Column, DLQNamespace, type DLQStats, type Database, type FetchLike, type FilterOp, type InsertRecordResult, type InsertResult, LiveQuery, type NDJSONSource, type OrderClause, type ParamDef, type Pipe, PipeRef, type PipeRequestOptions, PipesNamespace, type Policy, type PolicyFilter, PolicyNamespace, QueryBuilder, type QueryFilter, type RequestOptions, type Result, type RolePermissions, SchemaNamespace, type Schemas, StreamController, type StreamEvent, type StreamOptions, type StreamStatus, type StreamSubscriber, type StructuredQuery, SysNamespace, type TablePolicy, TableRef, type TableSchema, type TimeRange, type ValidationResult, WaveHouseClient, type WaveHouseError, createClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/** User-provided database schema mapping table names to row types. */
|
|
2
2
|
type Database = Record<string, Record<string, unknown>>;
|
|
3
3
|
/**
|
|
4
|
-
* Discriminated union for
|
|
4
|
+
* Discriminated union for the async SDK calls that return one. Never throws for
|
|
5
|
+
* anything the server returns; a non-absolute `baseURL` and a rejecting `auth`
|
|
6
|
+
* callback do throw, while a runtime with no `fetch` at all surfaces instead as
|
|
7
|
+
* a retried `NETWORK_ERROR` result.
|
|
8
|
+
*
|
|
9
|
+
* `.stream()` and `.liveQuery()` return no `Result` and report the same three
|
|
10
|
+
* differently: a non-absolute `baseURL` reaches the subscriber's `error`
|
|
11
|
+
* callback as a terminal `SSE_CONNECT_ERROR`, a rejecting `auth` as a retryable
|
|
12
|
+
* `SSE_AUTH_ERROR`, and only a missing `fetch` throws from the call itself.
|
|
5
13
|
*
|
|
6
14
|
* Discriminated on `ok`: `if (result.ok)` narrows to the success arm (and tells
|
|
7
15
|
* the compiler `data` is present), while `error` is always available for
|
|
@@ -47,16 +55,147 @@ interface StreamSubscriber<T = Record<string, unknown>> {
|
|
|
47
55
|
error?: (err: WaveHouseError) => void;
|
|
48
56
|
}
|
|
49
57
|
interface ClientConfig<_DB extends Database = Database> {
|
|
50
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Base URL of the WaveHouse server (e.g. "http://localhost:8080"). May include
|
|
60
|
+
* a path prefix ("https://app.example.com/api/warehouse") for a WaveHouse
|
|
61
|
+
* behind a backend-for-frontend (BFF), app-server route, or path-routed
|
|
62
|
+
* ingress; request paths are appended to it. The proxy in front must strip
|
|
63
|
+
* the prefix before forwarding.
|
|
64
|
+
*
|
|
65
|
+
* Must be **absolute** — scheme and host included. The transports report a
|
|
66
|
+
* relative value such as "/api/warehouse" differently: a REST call rejects
|
|
67
|
+
* with a `TypeError` instead of returning a `Result`, while a stream reports
|
|
68
|
+
* `SSE_CONNECT_ERROR` to the subscriber's `error` callback. Build an absolute
|
|
69
|
+
* one: `` `${location.origin}/api/warehouse` ``.
|
|
70
|
+
*/
|
|
51
71
|
baseURL: string;
|
|
52
72
|
/** Auth token provider. Omit for public/unauthenticated access. */
|
|
53
73
|
auth?: () => Promise<string> | string;
|
|
54
74
|
/** Additional client options. */
|
|
55
75
|
options?: ClientOptions;
|
|
56
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* A `fetch`-compatible function.
|
|
79
|
+
*
|
|
80
|
+
* Spelled out rather than written `typeof fetch`, which resolves differently
|
|
81
|
+
* depending on whether the consumer's TypeScript `lib` includes DOM — the same
|
|
82
|
+
* signature either way, but stable across configurations.
|
|
83
|
+
*
|
|
84
|
+
* The parameter is `string` rather than `typeof fetch`'s wider union because a
|
|
85
|
+
* string URL is all the SDK ever passes. Since parameters are contravariant,
|
|
86
|
+
* narrowing it *widens* what can be assigned: the global `fetch` still fits, and
|
|
87
|
+
* so does hand-written `(url: string, init?: RequestInit) => Promise<Response>`
|
|
88
|
+
* middleware, which the wider spelling rejects at compile time.
|
|
89
|
+
*
|
|
90
|
+
* On REST the SDK reads `.ok` and `.headers` always, `.text()` on success, and
|
|
91
|
+
* `.status`, `.statusText` plus `.json()` when the response is not `ok`. A
|
|
92
|
+
* rejection becomes a `NETWORK_ERROR` result and is retried with backoff —
|
|
93
|
+
* unless the `AbortSignal` you passed has been aborted, in which case the
|
|
94
|
+
* result is `ABORTED` and nothing is retried. That is decided from the signal
|
|
95
|
+
* rather than the rejection's type, so an implementation that throws something
|
|
96
|
+
* other than a `DOMException` named `AbortError` — `AbortSignal.timeout()`,
|
|
97
|
+
* `node-fetch` — is reported the same way.
|
|
98
|
+
*
|
|
99
|
+
* **Streaming needs more.** `.stream()` and `.liveQuery()` read the response as
|
|
100
|
+
* it arrives, via `.body.getReader()`, so an implementation used with them must
|
|
101
|
+
* return a response carrying a live `ReadableStream` — something the type cannot
|
|
102
|
+
* enforce, since `Response.body` is legitimately nullable. A response handed
|
|
103
|
+
* back with an absent or already-consumed body fails fast with
|
|
104
|
+
* `SSE_NO_STREAM_BODY`. What the SDK *cannot* rescue is an implementation that
|
|
105
|
+
* awaits the body before returning — `await res.text()`, or the
|
|
106
|
+
* `res.clone().text()` a logging wrapper reaches for — because on a stream that
|
|
107
|
+
* never ends, that never resolves and your function never returns. Both satisfy
|
|
108
|
+
* every REST call, which is what makes the trap easy to walk into.
|
|
109
|
+
*
|
|
110
|
+
* Implementations shipping their own request/response declarations (undici,
|
|
111
|
+
* `node-fetch`) need casts on the init and the return value, since those types
|
|
112
|
+
* are separate from the ones behind your global `fetch`; the narrow runtime
|
|
113
|
+
* contract above is what makes them safe.
|
|
114
|
+
*/
|
|
115
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
57
116
|
interface ClientOptions {
|
|
58
117
|
/** Maximum retry attempts for failed requests. Default: 2. */
|
|
59
118
|
maxRetries?: number;
|
|
119
|
+
/**
|
|
120
|
+
* HTTP implementation used for every request, REST and streaming alike.
|
|
121
|
+
* Defaults to the global `fetch`.
|
|
122
|
+
*
|
|
123
|
+
* Provide one to route through a proxy, attach client certificates, add
|
|
124
|
+
* middleware (logging, tracing, circuit breaking), or bypass a transport bug
|
|
125
|
+
* in the runtime's bundled HTTP stack by routing through an implementation
|
|
126
|
+
* you install yourself — e.g. an undici new enough to be free of
|
|
127
|
+
* {@link https://github.com/nodejs/undici/issues/5600 | undici #5600}:
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* import { Agent, fetch as undiciFetch } from "undici"; // npm install undici — 8.10.0+
|
|
131
|
+
* // Pass the dispatcher explicitly: undici's pool lives on a shared
|
|
132
|
+
* // globalThis symbol claimed by whichever copy loaded first, so an implied
|
|
133
|
+
* // dispatcher can still be the runtime's affected one.
|
|
134
|
+
* const dispatcher = new Agent();
|
|
135
|
+
* createClient({
|
|
136
|
+
* baseURL,
|
|
137
|
+
* options: {
|
|
138
|
+
* fetch: (url, init) =>
|
|
139
|
+
* undiciFetch(url, { ...init, dispatcher } as never) as unknown as Promise<Response>,
|
|
140
|
+
* },
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* `.stream()` and `.liveQuery()` go through it too, which imposes the extra
|
|
145
|
+
* streaming requirement described on {@link FetchLike} — read that before
|
|
146
|
+
* supplying a wrapper that touches the response body.
|
|
147
|
+
*/
|
|
148
|
+
fetch?: FetchLike;
|
|
149
|
+
/**
|
|
150
|
+
* Headers added to every request, REST and streaming alike — for a
|
|
151
|
+
* header-gated proxy in front of WaveHouse, such as a Cloudflare Access
|
|
152
|
+
* service token.
|
|
153
|
+
*
|
|
154
|
+
* Matched case-insensitively, as HTTP headers are. Applied underneath the
|
|
155
|
+
* SDK's own headers: `auth` still owns `Authorization`, and the
|
|
156
|
+
* `Content-Type` and `Accept` a given request needs are not overridable
|
|
157
|
+
* here — a global `Content-Type` that outranked the request's own is a
|
|
158
|
+
* documented way to break uploads.
|
|
159
|
+
*
|
|
160
|
+
* In a browser these are subject to CORS: a header outside the safelist adds
|
|
161
|
+
* it to the preflight, which the origin must allow. WaveHouse's own CORS
|
|
162
|
+
* advertises a fixed set, so custom headers reach it cross-origin only when
|
|
163
|
+
* a proxy in front terminates the preflight — which is the deployment they
|
|
164
|
+
* exist for. Server-side callers never preflight.
|
|
165
|
+
*/
|
|
166
|
+
headers?: Record<string, string>;
|
|
167
|
+
/**
|
|
168
|
+
* Extra `RequestInit` fields merged into every request — `credentials` for a
|
|
169
|
+
* cookie-authenticated origin, `mode`, `cache`, `keepalive`, or a
|
|
170
|
+
* runtime-specific extension such as Next.js's `next: { tags }`.
|
|
171
|
+
*
|
|
172
|
+
* Fields the SDK controls (`method`, `headers`, `body`, `signal`) always
|
|
173
|
+
* win, so this cannot corrupt the request itself. Non-standard fields may
|
|
174
|
+
* need a cast, since `RequestInit` only declares the standard ones.
|
|
175
|
+
*
|
|
176
|
+
* The streaming transport additionally owns `cache` and `redirect`, where the
|
|
177
|
+
* values are load-bearing rather than preference: a `Cache-Control` header
|
|
178
|
+
* would fail cross-origin preflight, and following a redirect would strip the
|
|
179
|
+
* `Authorization` header on a cross-origin hop and silently downgrade the
|
|
180
|
+
* stream to the default role instead of failing. So a request carrying an
|
|
181
|
+
* `auth` token, or configured `headers` that may hold a proxy secret, refuses
|
|
182
|
+
* redirects (`SSE_REDIRECT`); without either it follows them, so CDN
|
|
183
|
+
* canonicalization and an http→https upgrade still work. Note the test is
|
|
184
|
+
* that concrete pair, not "is this authenticated" — **cookies are invisible
|
|
185
|
+
* to it**. A cookie is re-derived from the cookie store at each hop rather
|
|
186
|
+
* than carried, so under the default `same-origin` credentials mode a
|
|
187
|
+
* redirect keeps the stream authenticated only while the hop stays inside
|
|
188
|
+
* both the request's origin and the cookie's `Path`; a hop outside either
|
|
189
|
+
* arrives with no cookie and gets a `default_role` view rather than an error.
|
|
190
|
+
* With `credentials: "include"` the origin half is replaced rather than
|
|
191
|
+
* lifted: ordinary cookie scoping decides, so the cookie crosses a
|
|
192
|
+
* CORS-allowed cross-origin hop only if its own `Domain` covers the target —
|
|
193
|
+
* a host-only cookie, the default, still stops at its host. Spelled out
|
|
194
|
+
* under "Supplying your own `fetch`" in the SDK guide; see #478.
|
|
195
|
+
* `credentials` itself is honored in browsers and dropped elsewhere, since
|
|
196
|
+
* some runtimes throw if it is set.
|
|
197
|
+
*/
|
|
198
|
+
fetchOptions?: RequestInit;
|
|
60
199
|
}
|
|
61
200
|
interface StructuredQuery {
|
|
62
201
|
/**
|
|
@@ -172,8 +311,22 @@ interface RolePermissions {
|
|
|
172
311
|
check?: Record<string, PolicyFilter>;
|
|
173
312
|
allowed_aggregations?: string[];
|
|
174
313
|
denied_aggregations?: string[];
|
|
314
|
+
/** Caps the query result LIMIT. 0 = no limit. */
|
|
175
315
|
max_rows?: number;
|
|
176
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Max query execution time, enforced server-side by ClickHouse. Set it as a
|
|
318
|
+
* duration string ("5s", "500ms") or a number of milliseconds; reads always
|
|
319
|
+
* return the number of milliseconds.
|
|
320
|
+
*/
|
|
321
|
+
max_execution_time?: number | string;
|
|
322
|
+
/** Max rows scanned from storage, enforced server-side by ClickHouse. 0 = no limit. */
|
|
323
|
+
max_rows_to_read?: number;
|
|
324
|
+
/**
|
|
325
|
+
* Max peak query memory, enforced server-side by ClickHouse. Set it as a size
|
|
326
|
+
* string ("4GiB", "512MiB") or a number of bytes; reads always return the
|
|
327
|
+
* number of bytes.
|
|
328
|
+
*/
|
|
329
|
+
max_memory_usage?: number | string;
|
|
177
330
|
}
|
|
178
331
|
interface PolicyFilter {
|
|
179
332
|
_eq?: string;
|
|
@@ -185,10 +338,32 @@ interface PolicyFilter {
|
|
|
185
338
|
interface ValidationResult {
|
|
186
339
|
valid: boolean;
|
|
187
340
|
}
|
|
188
|
-
|
|
341
|
+
/**
|
|
342
|
+
* Options for a single call, passed to `.fetch()`.
|
|
343
|
+
*
|
|
344
|
+
* Note that `await`ing a builder directly (`await wh.from("t").select("*")`)
|
|
345
|
+
* takes no options — use the explicit `.fetch({ … })` form for those.
|
|
346
|
+
*/
|
|
347
|
+
interface RequestOptions {
|
|
189
348
|
signal?: AbortSignal;
|
|
190
349
|
limit?: number;
|
|
191
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Options for a single `PipeRef.fetch()` call.
|
|
353
|
+
*
|
|
354
|
+
* `limit` is declared `never` rather than simply left out. Omitting it would
|
|
355
|
+
* still admit a `RequestOptions` value that carries one — excess-property
|
|
356
|
+
* checking only rejects fresh object literals, so a variable would pass and the
|
|
357
|
+
* limit would be silently dropped, which is the whole defect this prevents.
|
|
358
|
+
*
|
|
359
|
+
* A pipe's row cap belongs in its SQL as a `{{limit}}` parameter, supplied via
|
|
360
|
+
* `wh.pipe(name, { limit })`.
|
|
361
|
+
*/
|
|
362
|
+
interface PipeRequestOptions {
|
|
363
|
+
signal?: AbortSignal;
|
|
364
|
+
/** Not supported on pipes — pass `limit` as a pipe parameter instead. */
|
|
365
|
+
limit?: never;
|
|
366
|
+
}
|
|
192
367
|
interface StreamOptions {
|
|
193
368
|
since?: string;
|
|
194
369
|
signal?: AbortSignal;
|
|
@@ -199,6 +374,9 @@ interface HttpContext {
|
|
|
199
374
|
auth?: () => Promise<string> | string;
|
|
200
375
|
options: {
|
|
201
376
|
maxRetries: number;
|
|
377
|
+
fetch?: FetchLike;
|
|
378
|
+
headers?: Record<string, string>;
|
|
379
|
+
fetchOptions?: RequestInit;
|
|
202
380
|
};
|
|
203
381
|
}
|
|
204
382
|
|
|
@@ -275,8 +453,15 @@ declare class PipeRef<Row = Record<string, unknown>> implements PromiseLike<Resu
|
|
|
275
453
|
private readonly _params?;
|
|
276
454
|
private readonly _createStream;
|
|
277
455
|
constructor(ctx: HttpContext, name: string, params: Record<string, unknown> | undefined, createStream: CreateStreamFn$2<Row>);
|
|
278
|
-
/**
|
|
279
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Execute the pipe and return results.
|
|
458
|
+
*
|
|
459
|
+
* Takes only `signal` — deliberately narrower than the `RequestOptions` the
|
|
460
|
+
* query builder accepts. The pipes endpoint binds the body as the pipe's
|
|
461
|
+
* parameters, so there is no row cap to forward; give the pipe a `{{limit}}`
|
|
462
|
+
* parameter in its SQL and pass it via `wh.pipe(name, { limit })`.
|
|
463
|
+
*/
|
|
464
|
+
fetch(opts?: PipeRequestOptions): Promise<Result<Row[]>>;
|
|
280
465
|
/** Subscribe to live events from the pipe's underlying query. */
|
|
281
466
|
stream(opts?: StreamOptions): StreamController<Row>;
|
|
282
467
|
then<TResult1 = Result<Row[]>, TResult2 = never>(onfulfilled?: ((value: Result<Row[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
@@ -423,7 +608,7 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
|
|
|
423
608
|
cacheTTL(seconds: number): QueryBuilder<Row>;
|
|
424
609
|
/** Default row limit when none is specified — deliberately tighter than the backend's DefaultMaxRows (10000) safety cap. */
|
|
425
610
|
static readonly DEFAULT_LIMIT = 1000;
|
|
426
|
-
fetch(opts?:
|
|
611
|
+
fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
|
|
427
612
|
stream(opts?: StreamOptions): StreamController<Row>;
|
|
428
613
|
/**
|
|
429
614
|
* Start a live query: fetches historical data, then streams live updates.
|
|
@@ -459,7 +644,7 @@ declare class TableRef<Row = Record<string, unknown>> {
|
|
|
459
644
|
private readonly _createStream;
|
|
460
645
|
constructor(ctx: HttpContext, table: string, createStream: CreateStreamFn<Row>);
|
|
461
646
|
/** SELECT * shortcut — fetches rows with optional pagination. */
|
|
462
|
-
fetch(opts?:
|
|
647
|
+
fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
|
|
463
648
|
/** Start building a typed query. Returns an immutable, PromiseLike QueryBuilder. */
|
|
464
649
|
select(...columns: string[]): QueryBuilder<Row>;
|
|
465
650
|
/**
|
|
@@ -549,4 +734,4 @@ declare class WaveHouseClient<DB extends Database = Database> {
|
|
|
549
734
|
/** Create a new WaveHouse client instance. */
|
|
550
735
|
declare function createClient<DB extends Database = Database>(config: ClientConfig<DB>): WaveHouseClient<DB>;
|
|
551
736
|
|
|
552
|
-
export { type Aggregation, type ClientConfig, type ClientOptions, type Column, DLQNamespace, type DLQStats, type Database, type
|
|
737
|
+
export { type Aggregation, type ClientConfig, type ClientOptions, type Column, DLQNamespace, type DLQStats, type Database, type FetchLike, type FilterOp, type InsertRecordResult, type InsertResult, LiveQuery, type NDJSONSource, type OrderClause, type ParamDef, type Pipe, PipeRef, type PipeRequestOptions, PipesNamespace, type Policy, type PolicyFilter, PolicyNamespace, QueryBuilder, type QueryFilter, type RequestOptions, type Result, type RolePermissions, SchemaNamespace, type Schemas, StreamController, type StreamEvent, type StreamOptions, type StreamStatus, type StreamSubscriber, type StructuredQuery, SysNamespace, type TablePolicy, TableRef, type TableSchema, type TimeRange, type ValidationResult, WaveHouseClient, type WaveHouseError, createClient };
|