@wavehouse/sdk 0.0.0-dev.0f8826c → 0.0.0-dev.h04a85f20bb96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
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 all async SDK operations. Never throws.
4
+ * Discriminated union for all async SDK operations. Never throws for anything
5
+ * the server returns — caller and environment errors (a non-absolute `baseURL`,
6
+ * a missing `EventSource`, a rejecting `auth` callback) do throw.
5
7
  *
6
8
  * Discriminated on `ok`: `if (result.ok)` narrows to the success arm (and tells
7
9
  * the compiler `data` is present), while `error` is always available for
@@ -47,19 +49,117 @@ interface StreamSubscriber<T = Record<string, unknown>> {
47
49
  error?: (err: WaveHouseError) => void;
48
50
  }
49
51
  interface ClientConfig<_DB extends Database = Database> {
50
- /** Base URL of the WaveHouse server (e.g. "http://localhost:8080"). */
52
+ /**
53
+ * Base URL of the WaveHouse server (e.g. "http://localhost:8080"). May include
54
+ * a path prefix ("https://app.example.com/api/warehouse") for a WaveHouse
55
+ * behind a backend-for-frontend (BFF), app-server route, or path-routed
56
+ * ingress; request paths are appended to it. The proxy in front must strip
57
+ * the prefix before forwarding.
58
+ *
59
+ * Must be **absolute** — scheme and host included. The transports report a
60
+ * relative value such as "/api/warehouse" differently: a REST call rejects
61
+ * with a `TypeError` instead of returning a `Result`, while a stream reports
62
+ * `SSE_CONNECT_ERROR` to the subscriber's `error` callback. Build an absolute
63
+ * one: `` `${location.origin}/api/warehouse` ``.
64
+ */
51
65
  baseURL: string;
52
66
  /** Auth token provider. Omit for public/unauthenticated access. */
53
67
  auth?: () => Promise<string> | string;
54
68
  /** Additional client options. */
55
69
  options?: ClientOptions;
56
70
  }
71
+ /**
72
+ * A `fetch`-compatible function.
73
+ *
74
+ * Spelled out rather than written `typeof fetch`, which resolves differently
75
+ * depending on whether the consumer's TypeScript `lib` includes DOM — the same
76
+ * signature either way, but stable across configurations.
77
+ *
78
+ * In practice the SDK only ever calls it with a string URL, and reads `.ok` and
79
+ * `.headers` always, `.text()` on success, and `.status`, `.statusText` plus
80
+ * `.json()` when the response is not `ok`. A rejection becomes a
81
+ * `NETWORK_ERROR` result and is retried with backoff — except a `DOMException`
82
+ * named `AbortError` (what the platform `fetch` and undici throw on abort),
83
+ * which becomes `ABORTED` and is not retried. Implementations that reject with
84
+ * some other abort error, such as `node-fetch`, are retried instead.
85
+ *
86
+ * Implementations shipping their own request/response declarations (undici,
87
+ * `node-fetch`) need casts on the URL, the init and the return value, since
88
+ * those types are separate from the ones behind your global `fetch`; the
89
+ * narrow runtime contract above is what makes them safe.
90
+ */
91
+ type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
57
92
  interface ClientOptions {
58
93
  /** Maximum retry attempts for failed requests. Default: 2. */
59
94
  maxRetries?: number;
95
+ /**
96
+ * HTTP implementation used for every REST request (SSE streams excluded).
97
+ * Defaults to the global `fetch`.
98
+ *
99
+ * Provide one to route through a proxy, attach client certificates, add
100
+ * middleware (logging, tracing, circuit breaking), or bypass a transport bug
101
+ * in the runtime's bundled HTTP stack by routing through an implementation
102
+ * you install yourself — e.g. an undici new enough to be free of
103
+ * {@link https://github.com/nodejs/undici/issues/5600 | undici #5600}:
104
+ *
105
+ * ```ts
106
+ * import { Agent, fetch as undiciFetch } from "undici"; // npm install undici — 8.10.0+
107
+ * // Pass the dispatcher explicitly: undici's pool lives on a shared
108
+ * // globalThis symbol claimed by whichever copy loaded first, so an implied
109
+ * // dispatcher can still be the runtime's affected one.
110
+ * const dispatcher = new Agent();
111
+ * createClient({
112
+ * baseURL,
113
+ * options: {
114
+ * fetch: (url, init) =>
115
+ * undiciFetch(url as string, { ...init, dispatcher } as never) as unknown as Promise<Response>,
116
+ * },
117
+ * });
118
+ * ```
119
+ *
120
+ * Only the SSE transport is exempt: the live connection behind `.stream()`
121
+ * and `.liveQuery()` uses `EventSource`, which this does not replace.
122
+ * `.liveQuery()`'s initial backfill is an ordinary request and does go
123
+ * through your function.
124
+ */
125
+ fetch?: FetchLike;
126
+ /**
127
+ * Headers added to every REST request (SSE streams excluded) — for a
128
+ * header-gated proxy in front of WaveHouse, such as a Cloudflare Access
129
+ * service token.
130
+ *
131
+ * Matched case-insensitively, as HTTP headers are. Applied underneath the
132
+ * SDK's own headers: `auth` still owns `Authorization`, and the
133
+ * `Content-Type` and `Accept` a given request needs are not overridable
134
+ * here — a global `Content-Type` that outranked the request's own is a
135
+ * documented way to break uploads.
136
+ */
137
+ headers?: Record<string, string>;
138
+ /**
139
+ * Extra `RequestInit` fields merged into every REST request — `credentials`
140
+ * for a cookie-authenticated origin, `mode`, `cache`, `keepalive`, or a
141
+ * runtime-specific extension such as Next.js's `next: { tags }`.
142
+ *
143
+ * Fields the SDK controls (`method`, `headers`, `body`, `signal`) always
144
+ * win, so this cannot corrupt the request itself. Non-standard fields may
145
+ * need a cast, since `RequestInit` only declares the standard ones.
146
+ */
147
+ fetchOptions?: RequestInit;
60
148
  }
61
149
  interface StructuredQuery {
150
+ /**
151
+ * Explicit columns to project. A literal "*" is a column named "*", not a
152
+ * wildcard. Omitting columns (with no aggregations and no select_all) selects
153
+ * nothing — use select_all for a full-row read. Mutually exclusive with
154
+ * select_all.
155
+ */
62
156
  columns?: string[];
157
+ /**
158
+ * Request every column the caller's role may read (the all-columns wildcard,
159
+ * expanded server-side to the allowed/denied set). Mutually exclusive with a
160
+ * non-empty columns list.
161
+ */
162
+ select_all?: boolean;
63
163
  aggregations?: Aggregation[];
64
164
  filters?: QueryFilter[];
65
165
  group_by?: string[];
@@ -97,9 +197,36 @@ interface TableSchema {
97
197
  columns: Column[];
98
198
  }
99
199
  type Schemas = Record<string, TableSchema>;
200
+ /**
201
+ * A per-record outcome from a batch (array / NDJSON) insert. Mirrors the
202
+ * single-object response shape plus the record's position. Exactly one of
203
+ * `ok` / `duplicate` / `error` is set.
204
+ */
205
+ interface InsertRecordResult {
206
+ /** 1-based index of the record within the submitted batch. */
207
+ index: number;
208
+ /** Set when the record was validated and published. */
209
+ ok?: boolean;
210
+ /** Set when dedup skipped the record. */
211
+ duplicate?: boolean;
212
+ /** Set (with `ok`/`duplicate` absent) when the record was rejected. */
213
+ error?: string;
214
+ }
100
215
  interface InsertResult {
216
+ /** True for a fully successful insert: a single row, or a batch with no rejected records (`failed === 0`). */
101
217
  ok: boolean;
218
+ /** Single insert only: set when dedup skipped the row. */
102
219
  duplicate?: boolean;
220
+ /** Batch insert (array / NDJSON): number of records submitted. */
221
+ total?: number;
222
+ /** Batch insert: records validated and published. */
223
+ succeeded?: number;
224
+ /** Batch insert: records rejected — see `results`. */
225
+ failed?: number;
226
+ /** Batch insert: records skipped by dedup. */
227
+ duplicates?: number;
228
+ /** Batch insert: per-record outcomes, each `{index, ok|duplicate|error}` (may be truncated for very large batches; the counts stay authoritative). */
229
+ results?: InsertRecordResult[];
103
230
  }
104
231
  interface DLQStats {
105
232
  tables: Record<string, number>;
@@ -133,8 +260,22 @@ interface RolePermissions {
133
260
  check?: Record<string, PolicyFilter>;
134
261
  allowed_aggregations?: string[];
135
262
  denied_aggregations?: string[];
263
+ /** Caps the query result LIMIT. 0 = no limit. */
136
264
  max_rows?: number;
137
- max_execution_time_ms?: number;
265
+ /**
266
+ * Max query execution time, enforced server-side by ClickHouse. Set it as a
267
+ * duration string ("5s", "500ms") or a number of milliseconds; reads always
268
+ * return the number of milliseconds.
269
+ */
270
+ max_execution_time?: number | string;
271
+ /** Max rows scanned from storage, enforced server-side by ClickHouse. 0 = no limit. */
272
+ max_rows_to_read?: number;
273
+ /**
274
+ * Max peak query memory, enforced server-side by ClickHouse. Set it as a size
275
+ * string ("4GiB", "512MiB") or a number of bytes; reads always return the
276
+ * number of bytes.
277
+ */
278
+ max_memory_usage?: number | string;
138
279
  }
139
280
  interface PolicyFilter {
140
281
  _eq?: string;
@@ -146,10 +287,32 @@ interface PolicyFilter {
146
287
  interface ValidationResult {
147
288
  valid: boolean;
148
289
  }
149
- interface FetchOptions {
290
+ /**
291
+ * Options for a single call, passed to `.fetch()`.
292
+ *
293
+ * Note that `await`ing a builder directly (`await wh.from("t").select("*")`)
294
+ * takes no options — use the explicit `.fetch({ … })` form for those.
295
+ */
296
+ interface RequestOptions {
150
297
  signal?: AbortSignal;
151
298
  limit?: number;
152
299
  }
300
+ /**
301
+ * Options for a single `PipeRef.fetch()` call.
302
+ *
303
+ * `limit` is declared `never` rather than simply left out. Omitting it would
304
+ * still admit a `RequestOptions` value that carries one — excess-property
305
+ * checking only rejects fresh object literals, so a variable would pass and the
306
+ * limit would be silently dropped, which is the whole defect this prevents.
307
+ *
308
+ * A pipe's row cap belongs in its SQL as a `{{limit}}` parameter, supplied via
309
+ * `wh.pipe(name, { limit })`.
310
+ */
311
+ interface PipeRequestOptions {
312
+ signal?: AbortSignal;
313
+ /** Not supported on pipes — pass `limit` as a pipe parameter instead. */
314
+ limit?: never;
315
+ }
153
316
  interface StreamOptions {
154
317
  since?: string;
155
318
  signal?: AbortSignal;
@@ -160,6 +323,9 @@ interface HttpContext {
160
323
  auth?: () => Promise<string> | string;
161
324
  options: {
162
325
  maxRetries: number;
326
+ fetch?: FetchLike;
327
+ headers?: Record<string, string>;
328
+ fetchOptions?: RequestInit;
163
329
  };
164
330
  }
165
331
 
@@ -236,8 +402,15 @@ declare class PipeRef<Row = Record<string, unknown>> implements PromiseLike<Resu
236
402
  private readonly _params?;
237
403
  private readonly _createStream;
238
404
  constructor(ctx: HttpContext, name: string, params: Record<string, unknown> | undefined, createStream: CreateStreamFn$2<Row>);
239
- /** Execute the pipe and return results. */
240
- fetch(opts?: FetchOptions): Promise<Result<Row[]>>;
405
+ /**
406
+ * Execute the pipe and return results.
407
+ *
408
+ * Takes only `signal` — deliberately narrower than the `RequestOptions` the
409
+ * query builder accepts. The pipes endpoint binds the body as the pipe's
410
+ * parameters, so there is no row cap to forward; give the pipe a `{{limit}}`
411
+ * parameter in its SQL and pass it via `wh.pipe(name, { limit })`.
412
+ */
413
+ fetch(opts?: PipeRequestOptions): Promise<Result<Row[]>>;
241
414
  /** Subscribe to live events from the pipe's underlying query. */
242
415
  stream(opts?: StreamOptions): StreamController<Row>;
243
416
  then<TResult1 = Result<Row[]>, TResult2 = never>(onfulfilled?: ((value: Result<Row[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
@@ -339,6 +512,7 @@ declare class LiveQuery<T = Record<string, unknown>> {
339
512
  interface QueryState {
340
513
  table: string;
341
514
  columns: string[];
515
+ selectAll?: boolean;
342
516
  aggregations: Aggregation[];
343
517
  filters: QueryFilter[];
344
518
  groupBy: string[];
@@ -361,6 +535,13 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
361
535
  private readonly _createStream;
362
536
  constructor(ctx: HttpContext, state: QueryState, createStream: CreateStreamFn$1<Row>);
363
537
  select(...columns: string[]): QueryBuilder<Row>;
538
+ /**
539
+ * Select every column the caller's role is allowed to read (the all-columns
540
+ * wildcard). Use this instead of `.select(...)` when you want a full-row read;
541
+ * a bare `.fetch()` with no `.select()` does this implicitly. Mutually
542
+ * exclusive with `.select(...)`.
543
+ */
544
+ selectAll(): QueryBuilder<Row>;
364
545
  where(column: string, op: FilterOp, value: unknown): QueryBuilder<Row>;
365
546
  count(column?: string, alias?: string): QueryBuilder<Row>;
366
547
  sum(column: string, alias?: string): QueryBuilder<Row>;
@@ -374,9 +555,9 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
374
555
  limit(n: number): QueryBuilder<Row>;
375
556
  timeRange(column: string, since: string, until?: string): QueryBuilder<Row>;
376
557
  cacheTTL(seconds: number): QueryBuilder<Row>;
377
- /** Default row limit when none is specified. Matches backend DefaultMaxRows. */
558
+ /** Default row limit when none is specified — deliberately tighter than the backend's DefaultMaxRows (10000) safety cap. */
378
559
  static readonly DEFAULT_LIMIT = 1000;
379
- fetch(opts?: FetchOptions): Promise<Result<Row[]>>;
560
+ fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
380
561
  stream(opts?: StreamOptions): StreamController<Row>;
381
562
  /**
382
563
  * Start a live query: fetches historical data, then streams live updates.
@@ -396,6 +577,12 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
396
577
  }
397
578
 
398
579
  type CreateStreamFn<Row> = (table: string, opts?: StreamOptions) => StreamController<Row>;
580
+ /**
581
+ * Accepted sources for {@link TableRef.insertNDJSON}: a string, raw bytes, a
582
+ * Blob/File (browser file inputs), or a byte stream. Non-string sources are
583
+ * read fully before sending.
584
+ */
585
+ type NDJSONSource = string | Uint8Array | Blob | ReadableStream<Uint8Array>;
399
586
  /**
400
587
  * Reference to a table. NOT thenable — safe to pass around without triggering requests.
401
588
  * Use `.fetch()`, `.select()`, `.insert()`, `.schema()`, or `.stream()` to act on it.
@@ -406,13 +593,51 @@ declare class TableRef<Row = Record<string, unknown>> {
406
593
  private readonly _createStream;
407
594
  constructor(ctx: HttpContext, table: string, createStream: CreateStreamFn<Row>);
408
595
  /** SELECT * shortcut — fetches rows with optional pagination. */
409
- fetch(opts?: FetchOptions): Promise<Result<Row[]>>;
596
+ fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
410
597
  /** Start building a typed query. Returns an immutable, PromiseLike QueryBuilder. */
411
598
  select(...columns: string[]): QueryBuilder<Row>;
412
- /** Insert one or more rows into this table. */
599
+ /**
600
+ * Start a query that selects every column the caller's role is allowed to read
601
+ * (the all-columns wildcard). Use instead of `.select(...)` for an explicit
602
+ * full-row read; `.fetch()` does this implicitly.
603
+ */
604
+ selectAll(): QueryBuilder<Row>;
605
+ /**
606
+ * Insert one or more rows into this table.
607
+ *
608
+ * A single object is sent as a JSON `POST /v1/ingest`. An **array** is
609
+ * serialized to NDJSON (one record per line) and sent as a single
610
+ * `application/x-ndjson` request: a bad record no longer fails or hides the
611
+ * rest of the batch — per-record outcomes come back in the result
612
+ * (`failed` / `results`), and `ok` is true only when every record succeeded.
613
+ *
614
+ * The array path sends one request regardless of size; bounded-concurrency
615
+ * chunking of very large arrays is tracked separately (#196). For NDJSON you
616
+ * already have (a file or stream), use {@link insertNDJSON}.
617
+ */
413
618
  insert(data: Partial<Row> | Partial<Row>[], opts?: {
414
619
  signal?: AbortSignal;
415
620
  }): Promise<Result<InsertResult>>;
621
+ /**
622
+ * Insert pre-formatted NDJSON (newline-delimited JSON, one record per line)
623
+ * from a string, raw bytes, a Blob/File, or a byte stream — e.g. a `.ndjson`
624
+ * file or a stream produced by another system. For in-memory rows, prefer
625
+ * {@link insert}.
626
+ *
627
+ * Non-string sources are read fully into memory before sending (the server
628
+ * streams the parse). Returns the same per-record batch summary as an array
629
+ * `insert`.
630
+ */
631
+ insertNDJSON(source: NDJSONSource, opts?: {
632
+ signal?: AbortSignal;
633
+ }): Promise<Result<InsertResult>>;
634
+ /**
635
+ * @internal Send an NDJSON body and map the server's batch response onto an
636
+ * {@link InsertResult}. A transport / whole-request failure surfaces as the
637
+ * Result error arm; a processed batch (even with rejected records) surfaces
638
+ * as the success arm with `ok = failed === 0`.
639
+ */
640
+ private _sendNDJSON;
416
641
  /** Fetch the schema for this table. */
417
642
  schema(opts?: {
418
643
  signal?: AbortSignal;
@@ -458,4 +683,4 @@ declare class WaveHouseClient<DB extends Database = Database> {
458
683
  /** Create a new WaveHouse client instance. */
459
684
  declare function createClient<DB extends Database = Database>(config: ClientConfig<DB>): WaveHouseClient<DB>;
460
685
 
461
- export { type Aggregation, type ClientConfig, type ClientOptions, type Column, DLQNamespace, type DLQStats, type Database, type FetchOptions, type FilterOp, type InsertResult, LiveQuery, type OrderClause, type ParamDef, type Pipe, PipeRef, PipesNamespace, type Policy, type PolicyFilter, PolicyNamespace, QueryBuilder, type QueryFilter, 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 };
686
+ 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 };
@@ -0,0 +1,3 @@
1
+ "use strict";var WaveHouse=(()=>{var D=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var J=(n,t)=>{for(var e in t)D(n,e,{get:t[e],enumerable:!0})},G=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of $(t))!W.call(n,s)&&s!==e&&D(n,s,{get:()=>t[s],enumerable:!(r=U(t,s))||r.enumerable});return n};var M=n=>G(D({},"__esModule",{value:!0}),n);var rt={};J(rt,{DLQNamespace:()=>f,LiveQuery:()=>b,PipeRef:()=>g,PipesNamespace:()=>R,PolicyNamespace:()=>_,QueryBuilder:()=>w,SchemaNamespace:()=>S,StreamController:()=>p,SysNamespace:()=>y,TableRef:()=>v,WaveHouseClient:()=>P,createClient:()=>I});async function L(n){let t;try{t=await n.json()}catch{t=void 0}let e=typeof t?.error=="string"?t.error:typeof t?.message=="string"?t.message:n.statusText,r=n.status===503||n.status>=500;return{status:n.status,code:`HTTP_${n.status}`,message:e,details:t,retryable:r}}function q(n){return{status:0,code:"NETWORK_ERROR",message:n instanceof Error?n.message:String(n),retryable:!0}}function u(n){return{ok:!0,data:n,error:null}}function x(n,t,e){return{ok:!0,data:n,error:null,hasMore:t,next:e}}function a(n){return{ok:!1,data:null,error:n}}function O(n,t,e){let r=new URL(n);r.search="",r.hash="",r.pathname.endsWith("/")||(r.pathname+="/");let s=new URL(t.replace(/^\/+/,""),r);if(e)for(let[o,i]of Object.entries(e))s.searchParams.set(o,i);return s}function V(n,t){if(!t)return n;let e=new Set(Object.keys(n).map(o=>o.toLowerCase())),r={...n},s=new Map;for(let[o,i]of Object.entries(t)){let c=o.toLowerCase();if(e.has(c))continue;let m=s.get(c);m!==void 0&&delete r[m],r[o]=i,s.set(c,o)}return r}async function l(n,t){let e=O(n.baseURL,t.path,t.params).toString(),r={"Content-Type":t.contentType??"application/json",Accept:"application/json"},s=t.rawBody!==void 0?t.rawBody:t.body!==void 0?JSON.stringify(t.body):void 0;if(n.auth){let m=await n.auth();m&&(r.Authorization=`Bearer ${m}`)}let o=V(r,n.options.headers),i=null,c=n.options.maxRetries+1;for(let m=0;m<c;m++)try{let h={...n.options.fetchOptions,method:t.method,headers:o,body:s,signal:t.signal},C=n.options.fetch,d=C?await C(e,h):await fetch(e,h);if(d.ok){let T=await d.text();return{data:T?JSON.parse(T):void 0,error:null,headers:d.headers}}let k=await L(d);if(d.status===503){let T=d.headers.get("Retry-After");if(T&&m<c-1){let N=parseInt(T,10)*1e3||3e4;await H(N,t.signal),i=k;continue}}if(k.retryable&&m<c-1){await H(j(m),t.signal),i=k;continue}return{data:null,error:k,headers:d.headers}}catch(h){if(h instanceof DOMException&&h.name==="AbortError")return{data:null,error:{status:0,code:"ABORTED",message:"Request aborted",retryable:!1},headers:new Headers};i=q(h),m<c-1&&await H(j(m),t.signal)}return{data:null,error:i,headers:new Headers}}function j(n){return Math.min(1e3*2**n,3e4)}function H(n,t){return new Promise((e,r)=>{if(t?.aborted){r(new DOMException("Aborted","AbortError"));return}let s=setTimeout(e,n);t?.addEventListener("abort",()=>{clearTimeout(s),r(new DOMException("Aborted","AbortError"))},{once:!0})})}var f=class{_ctx;_createStream;constructor(t,e){this._ctx=t,this._createStream=e}async list(t){let{data:e,error:r}=await l(this._ctx,{method:"GET",path:"/v1/dlq/stats",signal:t?.signal});return r?a(r):u(e)}async table(t,e){let{data:r,error:s}=await l(this._ctx,{method:"GET",path:"/v1/dlq/stats",params:{table:t},signal:e?.signal});return s?a(s):u(r)}stream(t){return this._createStream("dlq",t)}};var g=class{_ctx;_name;_params;_createStream;constructor(t,e,r,s){this._ctx=t,this._name=e,this._params=r,this._createStream=s}async fetch(t){let{data:e,error:r}=await l(this._ctx,{method:"POST",path:`/v1/pipes/${encodeURIComponent(this._name)}`,body:this._params??{},signal:t?.signal});return r?a(r):u(e)}stream(t){return this._createStream(this._name,t)}then(t,e){return this.fetch().then(t,e)}},R=class{_ctx;constructor(t){this._ctx=t}async list(t){let{data:e,error:r}=await l(this._ctx,{method:"GET",path:"/v1/admin/pipes",signal:t?.signal});return r?a(r):u(e)}async get(t,e){let{data:r,error:s}=await l(this._ctx,{method:"GET",path:`/v1/admin/pipes/${encodeURIComponent(t)}`,signal:e?.signal});return s?a(s):u(r)}async set(t,e,r){let{error:s}=await l(this._ctx,{method:"PUT",path:`/v1/admin/pipes/${encodeURIComponent(t)}`,body:e,signal:r?.signal});return s?a(s):u(void 0)}async delete(t,e){let{error:r}=await l(this._ctx,{method:"DELETE",path:`/v1/admin/pipes/${encodeURIComponent(t)}`,signal:e?.signal});return r?a(r):u(void 0)}};var _=class{_ctx;constructor(t){this._ctx=t}async get(t){let{data:e,error:r}=await l(this._ctx,{method:"GET",path:"/v1/admin/policy",signal:t?.signal});return r?a(r):u(e)}async set(t,e){let{error:r}=await l(this._ctx,{method:"PUT",path:"/v1/admin/policy",body:t,signal:e?.signal});return r?a(r):u(void 0)}async validate(t,e){let{data:r,error:s}=await l(this._ctx,{method:"POST",path:"/v1/admin/policy/validate",body:t,signal:e?.signal});return s?a(s):u(r)}};var S=class{_ctx;constructor(t){this._ctx=t}async list(t){let{data:e,error:r}=await l(this._ctx,{method:"GET",path:"/v1/schema",signal:t?.signal});if(r)return a(r);let s;if(Array.isArray(e)){s={};for(let o of e)o&&typeof o=="object"&&"name"in o&&(s[o.name]=o)}else s=e;return u(s)}async refresh(t){let{error:e}=await l(this._ctx,{method:"POST",path:"/v1/schema/refresh",signal:t?.signal});return e?a(e):u(void 0)}};async function F(n,t,e){let{data:r,error:s}=await l(n,{method:"POST",path:"/v1/admin/query",body:{sql:t},signal:e?.signal});return s?a(s):u(r)}var p=class{_transport;_subscribers=new Set;_status="connecting";_buffer=[];_waiters=[];_done=!1;constructor(t){this._transport=t,this._transport.onEvent=e=>{for(let s of this._subscribers)s.next(e);let r=this._waiters.shift();r?r.resolve({value:e,done:!1}):this._buffer.push(e)},this._transport.onStatus=e=>{if(e!==this._status){this._status=e;for(let r of this._subscribers)r.status?.(e);if(e==="closed"){this._done=!0;for(let r of this._waiters)r.resolve({value:void 0,done:!0});this._waiters=[]}}},this._transport.onError=e=>{for(let r of this._subscribers)r.error?.(e)},this._transport.connect()}get status(){return this._status}connected(t=5e3){return this._status==="live"?Promise.resolve():this._status==="closed"?Promise.reject(new Error("Stream is closed")):this._done?Promise.reject(new Error("Stream closed before connecting")):new Promise((e,r)=>{let s=!1,o=setTimeout(()=>{s||(s=!0,this._subscribers.delete(i),r(new Error(`Stream did not connect within ${t}ms`)))},t),i={next:()=>{},status:c=>{if(c==="live"){if(s)return;s=!0,clearTimeout(o),this._subscribers.delete(i),e()}else if(c==="closed"){if(s)return;s=!0,clearTimeout(o),this._subscribers.delete(i),r(new Error("Stream closed before connecting"))}}};this._subscribers.add(i)})}subscribe(t){return this._subscribers.add(t),t.status?.(this._status),()=>{this._subscribers.delete(t),this._subscribers.size===0&&this._waiters.length===0&&this.close()}}attachSignal(t){if(t.aborted){this.close();return}t.addEventListener("abort",()=>this.close(),{once:!0})}close(){if(this._transport.disconnect(),this._status!=="closed"){this._status="closed";for(let t of this._subscribers)t.status?.("closed")}this._done=!0;for(let t of this._waiters)t.resolve({value:void 0,done:!0});this._waiters=[]}[Symbol.asyncIterator](){let t=this;return{next(){return t._buffer.length>0?Promise.resolve({value:t._buffer.shift(),done:!1}):t._done?Promise.resolve({value:void 0,done:!0}):new Promise(e=>{t._waiters.push({resolve:e})})},return(){return t.close(),Promise.resolve({value:void 0,done:!0})},[Symbol.asyncIterator](){return this}}}};var E=0,z=5,A=class{_opts;_es=null;onEvent=null;onStatus=null;onError=null;constructor(t){this._opts=t}connect(){if(typeof EventSource>"u")throw new Error("[wavehouse] EventSource is not available in this environment. Please provide a global polyfill (e.g., `globalThis.EventSource = require('eventsource')`).");this._doConnect().catch(t=>{this.onError?.({status:0,code:"SSE_CONNECT_ERROR",message:t instanceof Error?t.message:String(t),retryable:!0})})}disconnect(){this._es&&(this._es.close(),this._es=null,E=Math.max(0,E-1)),this.onStatus?.("closed")}async _doConnect(){let t=O(this._opts.baseURL,"/v1/stream");if(t.searchParams.set("table",this._opts.table),this._opts.since&&t.searchParams.set("since",this._opts.since),this._opts.auth){let e=await this._opts.auth();e&&t.searchParams.set("token",e)}E++,E>z&&console.warn(`[wavehouse] ${E} SSE connections open. Browsers limit HTTP/1.1 to 6 connections per domain.`),this._es=new EventSource(t.toString()),this._es.onopen=()=>{this.onStatus?.("live")},this._es.onmessage=e=>{try{let r=JSON.parse(e.data),s={table:r.table_name,timestamp:r.received_timestamp,data:r.data};this.onEvent?.(s)}catch{console.warn("[wavehouse] SSE received malformed message:",e.data)}},this._es.onerror=()=>{this._es?.readyState===EventSource.CONNECTING?this.onStatus?.("reconnecting"):this._es?.readyState===EventSource.CLOSED?this.onStatus?.("closed"):this._es?.readyState===EventSource.OPEN?this.onStatus?.("live"):this.onError?.({status:0,code:"SSE_ERROR",message:"SSE connection error",retryable:!0})}}};var y=class{_ctx;constructor(t){this._ctx=t}async health(t){let{error:e}=await l(this._ctx,{method:"GET",path:"/v1/health",signal:t?.signal});return e?a(e):u(void 0)}};var b=class{_stream;_subscriber;_buffer=[];_buffering=!0;_unsubStream=null;_closed=!1;constructor(t,e,r,s){this._stream=t,this._subscriber=r,this._unsubStream=t.subscribe({next:o=>{this._closed||(this._buffering?this._buffer.push(o):r.next(o))},status:o=>r.status?.(o),error:o=>r.error?.(o)}),this._runBackfill(e)}async _runBackfill(t){try{let e=await t();if(this._closed)return;if(this._subscriber.initial?.(e),e.error){this._buffering=!1;return}let r=e.data,s;r.length>0&&(s=r[r.length-1]?.received_timestamp),this._buffering=!1;for(let o of this._buffer){if(this._closed)break;s&&o.timestamp<=s||this._subscriber.next(o)}this._buffer=[]}catch{this._buffering=!1,this._buffer=[]}}close(){this._closed=!0,this._buffering=!1,this._buffer=[],this._unsubStream?.(),this._stream.close()}};var K={"=":"eq","!=":"neq",">":"gt",">=":"gte","<":"lt","<=":"lte",in:"in",like:"like",not_like:"not_like"},w=class n{_state;_ctx;_createStream;constructor(t,e,r){this._ctx=t,this._state=Object.freeze({...e}),this._createStream=r}select(...t){return this._clone({columns:[...this._state.columns,...t]})}selectAll(){return this._clone({selectAll:!0})}where(t,e,r){let s={column:t,op:K[e],value:r};return this._clone({filters:[...this._state.filters,s]})}count(t="*",e="count"){return this._addAgg("count",t,e)}sum(t,e=`sum_${t}`){return this._addAgg("sum",t,e)}avg(t,e=`avg_${t}`){return this._addAgg("avg",t,e)}min(t,e=`min_${t}`){return this._addAgg("min",t,e)}max(t,e=`max_${t}`){return this._addAgg("max",t,e)}countDistinct(t,e=`count_distinct_${t}`){return this._addAgg("countDistinct",t,e)}aggregate(t,e,r){return this._addAgg(t,e,r)}groupBy(...t){return this._clone({groupBy:[...this._state.groupBy,...t]})}orderBy(t,e="asc"){return this._clone({orderBy:[...this._state.orderBy,{column:t,dir:e}]})}limit(t){return this._clone({limit:t})}timeRange(t,e,r){return this._clone({timeRange:{column:t,since:e,until:r}})}cacheTTL(t){return this._clone({cacheTTL:t})}static DEFAULT_LIMIT=1e3;async fetch(t){let e=t?.limit??this._state.limit??n.DEFAULT_LIMIT,r=this._buildAST(e),{data:s,error:o}=await l(this._ctx,{method:"POST",path:`/v1/query?table=${encodeURIComponent(this._state.table)}`,body:r,signal:t?.signal});if(o)return a(o);let i=s,c=e!=null&&i.length>=e;return c&&this._state.orderBy.length>0?x(i,!0,()=>this._fetchNext(i,e,t)):x(i,c)}stream(t){let e=this._createStream(this._state.table,t),r=this._state.filters,s=this._state.columns;return r.length===0&&s.length===0?e:new Q(e,r,s)}liveQuery(t,e){let r=this.stream(e),s=()=>this.fetch();return new b(r,s,t,this._state.filters)}then(t,e){return this.fetch().then(t,e)}_clone(t){return new n(this._ctx,{...this._state,...t},this._createStream)}_addAgg(t,e,r){let s={fn:t,column:e,alias:r};return this._clone({aggregations:[...this._state.aggregations,s]})}_buildAST(t){let e={},r=this._state.columns.length>0,s=this._state.aggregations.length>0;return this._state.selectAll?e.select_all=!0:r?e.columns=this._state.columns:s||(e.select_all=!0),s&&(e.aggregations=this._state.aggregations),this._state.filters.length>0&&(e.filters=this._state.filters),this._state.groupBy.length>0&&(e.group_by=this._state.groupBy),this._state.orderBy.length>0&&(e.order_by=this._state.orderBy),t!=null&&(e.limit=t),this._state.timeRange&&(e.time_range=this._state.timeRange),e}async _fetchNext(t,e,r){let s=this._state.orderBy[0];if(s==null)return x([],!1);let{column:o,dir:i}=s,m=t[t.length-1]?.[o];if(m===void 0)return x([],!1);let C={column:o,op:i==="desc"?"lt":"gt",value:m};return this._clone({filters:[...this._state.filters,C],orderBy:this._state.orderBy}).fetch(r)}},Q=class extends p{constructor(t,e,r){let s={onEvent:null,onStatus:null,onError:null,connect(){t.subscribe({next:o=>{if(!Y(o.data,e))return;let i=r.length>0?{...o,data:Z(o.data,r)}:o;this.onEvent?.(i)},status:o=>this.onStatus?.(o),error:o=>this.onError?.(o)})},disconnect(){t.close()}};super(s)}};function Y(n,t){for(let e of t){let r=n[e.column];if(!X(r,e.op,e.value))return!1}return!0}function X(n,t,e){switch(t){case"eq":return n===e;case"neq":return n!==e;case"gt":return B(n,e,(r,s)=>r>s);case"gte":return B(n,e,(r,s)=>r>=s);case"lt":return B(n,e,(r,s)=>r<s);case"lte":return B(n,e,(r,s)=>r<=s);case"in":return Array.isArray(e)&&e.includes(n);case"like":{if(typeof n!="string"||typeof e!="string")return!1;let s=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return new RegExp(`^${s}$`,"i").test(n)}case"not_like":{if(typeof n!="string"||typeof e!="string")return!1;let s=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return!new RegExp(`^${s}$`,"i").test(n)}default:return!0}}function B(n,t,e){return typeof n=="number"&&typeof t=="number"||typeof n=="string"&&typeof t=="string"?e(n,t):!1}function Z(n,t){let e={};for(let r of t)r in n&&(e[r]=n[r]);return e}var tt="application/x-ndjson";async function et(n){return typeof n=="string"?n:n instanceof Uint8Array?new TextDecoder().decode(n):new Response(n).text()}var v=class{_ctx;_table;_createStream;constructor(t,e,r){this._ctx=t,this._table=e,this._createStream=r}async fetch(t){return this.select().limit(t?.limit??1e3).fetch(t)}select(...t){return new w(this._ctx,{table:this._table,columns:t,aggregations:[],filters:[],groupBy:[],orderBy:[]},this._createStream)}selectAll(){return this.select().selectAll()}async insert(t,e){if(Array.isArray(t)){if(t.length===0)return u({ok:!0,total:0,succeeded:0,failed:0,duplicates:0,results:[]});let i=t.map(c=>JSON.stringify(c)).join(`
2
+ `);return this._sendNDJSON(i,e)}let{data:r,error:s}=await l(this._ctx,{method:"POST",path:`/v1/ingest?table=${encodeURIComponent(this._table)}`,body:t,signal:e?.signal});if(s)return a(s);let o={ok:r?.ok??!0};return r?.duplicate!=null&&(o.duplicate=r.duplicate),u(o)}async insertNDJSON(t,e){let r=await et(t);return this._sendNDJSON(r,e)}async _sendNDJSON(t,e){let{data:r,error:s}=await l(this._ctx,{method:"POST",path:`/v1/ingest?table=${encodeURIComponent(this._table)}`,rawBody:t,contentType:tt,signal:e?.signal});if(s)return a(s);let o=r??{total:0,succeeded:0,failed:0,duplicates:0},i={ok:o.failed===0,total:o.total,succeeded:o.succeeded,failed:o.failed,duplicates:o.duplicates};return o.results&&o.results.length>0&&(i.results=o.results),u(i)}async schema(t){let{data:e,error:r}=await l(this._ctx,{method:"GET",path:`/v1/schema?table=${encodeURIComponent(this._table)}`,signal:t?.signal});return r?a(r):u(e)}stream(t){return this._createStream(this._table,t)}};var P=class{_ctx;schema;policy;dlq;sys;pipes;constructor(t){this._ctx={baseURL:t.baseURL.replace(/\/+$/,""),auth:t.auth,options:{maxRetries:t.options?.maxRetries??2,fetch:t.options?.fetch,headers:t.options?.headers,fetchOptions:t.options?.fetchOptions}},this.schema=new S(this._ctx),this.policy=new _(this._ctx),this.dlq=new f(this._ctx,(e,r)=>this._createStream(e,r)),this.sys=new y(this._ctx),this.pipes=new R(this._ctx)}from(t){return new v(this._ctx,t,(e,r)=>this._createStream(e,r))}pipe(t,e){return new g(this._ctx,t,e,(r,s)=>this._createStream(r,s))}sql(t,e){if(Array.isArray(e))throw new Error("[WaveHouse SDK] client.sql(sql, params) was removed. The /v1/admin/query endpoint does not accept positional `?` params. Inline literals into the SQL, or use the structured query builder (wh.from(table)\u2026) for safe binding from user input.");return F(this._ctx,t,e)}_createStream(t,e){if(typeof EventSource>"u")throw new Error("[WaveHouse SDK] Native EventSource is not available in this environment. Please provide a global polyfill (e.g., `globalThis.EventSource = require('eventsource')`).");let r=new A({baseURL:this._ctx.baseURL,table:t,since:e?.since,auth:this._ctx.auth}),s=new p(r);return e?.signal&&s.attachSignal(e.signal),s}};function I(n){return new P(n)}return M(rt);})();
3
+ //# sourceMappingURL=index.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/url.ts","../src/http.ts","../src/dlq.ts","../src/pipes.ts","../src/policy.ts","../src/schema.ts","../src/sql.ts","../src/stream/controller.ts","../src/stream/sse.ts","../src/sys.ts","../src/stream/live-query.ts","../src/query-builder.ts","../src/table.ts","../src/client.ts"],"sourcesContent":["// ============================================================================\n// @wavehouse/sdk — Public API\n// ============================================================================\n\n// --- Main entry point ---\nexport { createClient, WaveHouseClient } from \"./client.js\";\nexport { DLQNamespace } from \"./dlq.js\";\nexport { PipeRef, PipesNamespace } from \"./pipes.js\";\nexport { PolicyNamespace } from \"./policy.js\";\nexport { QueryBuilder } from \"./query-builder.js\";\nexport { SchemaNamespace } from \"./schema.js\";\nexport { StreamController } from \"./stream/controller.js\";\nexport { LiveQuery } from \"./stream/live-query.js\";\nexport { SysNamespace } from \"./sys.js\";\nexport type { NDJSONSource } from \"./table.js\";\n// --- Core classes ---\nexport { TableRef } from \"./table.js\";\n\n// --- Types ---\nexport type {\n Aggregation,\n // Config\n ClientConfig,\n ClientOptions,\n // Schema\n Column,\n // Database & result\n Database,\n // DLQ\n DLQStats,\n // HTTP\n FetchLike,\n // Query\n FilterOp,\n // Ingest\n InsertRecordResult,\n InsertResult,\n OrderClause,\n ParamDef,\n // Pipes\n Pipe,\n PipeRequestOptions,\n // Policy\n Policy,\n PolicyFilter,\n QueryFilter,\n RequestOptions,\n Result,\n RolePermissions,\n Schemas,\n StreamEvent,\n StreamOptions,\n // Streaming\n StreamStatus,\n StreamSubscriber,\n StructuredQuery,\n TablePolicy,\n TableSchema,\n TimeRange,\n ValidationResult,\n WaveHouseError,\n} from \"./types.js\";\n","import type { Result, WaveHouseError } from \"./types.js\";\n\n/** Create a WaveHouseError from an HTTP response. */\nexport async function parseErrorResponse(res: Response): Promise<WaveHouseError> {\n let body: Record<string, unknown> | undefined;\n try {\n body = (await res.json()) as Record<string, unknown>;\n } catch {\n body = undefined;\n }\n\n const message =\n typeof body?.error === \"string\"\n ? body.error\n : typeof body?.message === \"string\"\n ? body.message\n : res.statusText;\n\n const retryable = res.status === 503 || res.status >= 500;\n return {\n status: res.status,\n code: `HTTP_${res.status}`,\n message,\n details: body,\n retryable,\n };\n}\n\n/** Create a WaveHouseError from a network/fetch error. */\nexport function networkError(cause: unknown): WaveHouseError {\n const message = cause instanceof Error ? cause.message : String(cause);\n return {\n status: 0,\n code: \"NETWORK_ERROR\",\n message,\n retryable: true,\n };\n}\n\n/** Wrap a successful value in a Result. */\nexport function ok<T>(data: T): Result<T> {\n return { ok: true, data, error: null };\n}\n\n/** Wrap a successful paginated value in a Result. */\nexport function okPage<T>(data: T, hasMore: boolean, next?: () => Promise<Result<T>>): Result<T> {\n return { ok: true, data, error: null, hasMore, next };\n}\n\n/** Wrap an error in a Result. */\nexport function err<T = unknown>(error: WaveHouseError): Result<T> {\n return { ok: false, data: null, error };\n}\n","/**\n * Resolve an SDK request path against the configured `baseURL`.\n *\n * The single URL-construction rule for every transport (REST in `http.ts`, SSE\n * in `stream/sse.ts`, the codegen CLI). Request paths are joined **onto** the\n * base rather than resolved as absolute ones, so a base carrying a path prefix\n * — `https://app.example.com/api/warehouse`, a WaveHouse behind a BFF,\n * app-server route, or path-routed ingress — keeps that prefix. Resolving\n * `/v1/query` against such a base would silently discard it (#428).\n *\n * @internal\n */\nexport function resolveURL(base: string, path: string, params?: Record<string, string>): URL {\n const root = new URL(base);\n // Normalize the base to a directory: a bare last segment (or a query/fragment\n // shadowing one) makes relative resolution *replace* the prefix, not extend it.\n root.search = \"\";\n root.hash = \"\";\n if (!root.pathname.endsWith(\"/\")) root.pathname += \"/\";\n\n const url = new URL(path.replace(/^\\/+/, \"\"), root);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n url.searchParams.set(k, v);\n }\n }\n return url;\n}\n","import { networkError, parseErrorResponse } from \"./errors.js\";\nimport type { HttpContext, WaveHouseError } from \"./types.js\";\nimport { resolveURL } from \"./url.js\";\n\ninterface RequestSpec {\n method: string;\n path: string;\n body?: unknown;\n /**\n * Pre-serialized request body, sent verbatim (no `JSON.stringify`) — e.g.\n * NDJSON text. Takes precedence over `body`. Must be re-sendable so retries\n * work, hence a string rather than a stream.\n */\n rawBody?: string;\n /** Override the request Content-Type (default `application/json`). */\n contentType?: string;\n params?: Record<string, string>;\n signal?: AbortSignal;\n}\n\n/** @internal */\nexport interface HttpResult<T> {\n data: T | null;\n error: WaveHouseError | null;\n headers: Headers;\n}\n\n/**\n * Merge configured headers underneath the SDK's own, matching names\n * case-insensitively so a caller's `authorization` can't sit alongside our\n * `Authorization` and let the server pick. Canonical casing wins, and values\n * replace rather than append — a header joined instead of replaced is a known\n * way to produce `Content-Type: application/json, image/png`.\n */\nfunction mergeHeaders(\n base: Record<string, string>,\n extra: Record<string, string> | undefined,\n): Record<string, string> {\n if (!extra) return base;\n const sdkNames = new Set(Object.keys(base).map((k) => k.toLowerCase()));\n const merged = { ...base };\n // Spelling each configured name was last stored under, so two entries\n // differing only in case replace each other here rather than surviving as\n // separate keys for `Headers` to comma-join at fetch time.\n const configured = new Map<string, string>();\n for (const [name, value] of Object.entries(extra)) {\n const lower = name.toLowerCase();\n // Skip rather than overwrite: `base` is the SDK's own, which outranks.\n if (sdkNames.has(lower)) continue;\n const prior = configured.get(lower);\n if (prior !== undefined) delete merged[prior];\n merged[name] = value;\n configured.set(lower, name);\n }\n return merged;\n}\n\n/**\n * Internal fetch wrapper with auth injection, retry, backoff, and Retry-After.\n * @internal\n */\nexport async function request<T>(ctx: HttpContext, opts: RequestSpec): Promise<HttpResult<T>> {\n const url = resolveURL(ctx.baseURL, opts.path, opts.params).toString();\n const headers: Record<string, string> = {\n \"Content-Type\": opts.contentType ?? \"application/json\",\n Accept: \"application/json\",\n };\n\n // Serialize once so every retry attempt re-sends an identical body.\n const requestBody: string | undefined =\n opts.rawBody !== undefined\n ? opts.rawBody\n : opts.body !== undefined\n ? JSON.stringify(opts.body)\n : undefined;\n\n if (ctx.auth) {\n const token = await ctx.auth();\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n }\n\n // After auth, so `auth` keeps ownership of Authorization, and after the\n // Content-Type/Accept this request needs.\n const finalHeaders = mergeHeaders(headers, ctx.options.headers);\n\n let lastError: WaveHouseError | null = null;\n const maxAttempts = ctx.options.maxRetries + 1;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n // Configured RequestInit first, so the fields the SDK controls overwrite\n // it — a supplied `method` or `body` would otherwise corrupt the request.\n const init: RequestInit = {\n ...ctx.options.fetchOptions,\n method: opts.method,\n headers: finalHeaders,\n body: requestBody,\n signal: opts.signal,\n };\n // Call the global directly when no override is configured, rather than\n // capturing it — a detached `fetch` reference is not universally safe to\n // invoke, and late binding is what lets tests swap `globalThis.fetch`.\n const doFetch = ctx.options.fetch;\n const res = doFetch ? await doFetch(url, init) : await fetch(url, init);\n\n if (res.ok) {\n const text = await res.text();\n const data = text ? (JSON.parse(text) as T) : (undefined as T);\n return { data, error: null, headers: res.headers };\n }\n\n const error = await parseErrorResponse(res);\n\n // 503 with Retry-After: wait the specified duration\n if (res.status === 503) {\n const retryAfter = res.headers.get(\"Retry-After\");\n if (retryAfter && attempt < maxAttempts - 1) {\n const delay = parseInt(retryAfter, 10) * 1000 || 30_000;\n await sleep(delay, opts.signal);\n lastError = error;\n continue;\n }\n }\n\n // Retryable server errors (5xx)\n if (error.retryable && attempt < maxAttempts - 1) {\n await sleep(backoff(attempt), opts.signal);\n lastError = error;\n continue;\n }\n\n return { data: null, error, headers: res.headers };\n } catch (e) {\n // AbortError — return immediately, no retry\n if (e instanceof DOMException && e.name === \"AbortError\") {\n return {\n data: null,\n error: { status: 0, code: \"ABORTED\", message: \"Request aborted\", retryable: false },\n headers: new Headers(),\n };\n }\n\n lastError = networkError(e);\n if (attempt < maxAttempts - 1) {\n await sleep(backoff(attempt), opts.signal);\n }\n }\n }\n\n return { data: null, error: lastError!, headers: new Headers() };\n}\n\nfunction backoff(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 30_000);\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n },\n { once: true },\n );\n });\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { StreamController } from \"./stream/controller.js\";\nimport type { DLQStats, HttpContext, Result, StreamOptions } from \"./types.js\";\n\ntype CreateStreamFn = (table: string, opts?: StreamOptions) => StreamController;\n\n/** Namespace for Dead Letter Queue operations. */\nexport class DLQNamespace {\n private readonly _ctx: HttpContext;\n private readonly _createStream: CreateStreamFn;\n\n constructor(ctx: HttpContext, createStream: CreateStreamFn) {\n this._ctx = ctx;\n this._createStream = createStream;\n }\n\n /** Get DLQ statistics (message counts per table). */\n async list(opts?: { signal?: AbortSignal }): Promise<Result<DLQStats>> {\n const { data, error } = await request<DLQStats>(this._ctx, {\n method: \"GET\",\n path: \"/v1/dlq/stats\",\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Get DLQ stats filtered by table name. */\n async table(name: string, opts?: { signal?: AbortSignal }): Promise<Result<DLQStats>> {\n const { data, error } = await request<DLQStats>(this._ctx, {\n method: \"GET\",\n path: \"/v1/dlq/stats\",\n params: { table: name },\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Subscribe to live DLQ events. */\n stream(opts?: StreamOptions): StreamController {\n return this._createStream(\"dlq\", opts);\n }\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { StreamController } from \"./stream/controller.js\";\nimport type { HttpContext, Pipe, PipeRequestOptions, Result, StreamOptions } from \"./types.js\";\n\ntype CreateStreamFn<Row> = (table: string, opts?: StreamOptions) => StreamController<Row>;\n\n/** Reference to a named query pipe — PromiseLike for convenient `await`. */\nexport class PipeRef<Row = Record<string, unknown>> implements PromiseLike<Result<Row[]>> {\n private readonly _ctx: HttpContext;\n private readonly _name: string;\n private readonly _params?: Record<string, unknown>;\n private readonly _createStream: CreateStreamFn<Row>;\n\n constructor(\n ctx: HttpContext,\n name: string,\n params: Record<string, unknown> | undefined,\n createStream: CreateStreamFn<Row>,\n ) {\n this._ctx = ctx;\n this._name = name;\n this._params = params;\n this._createStream = createStream;\n }\n\n /**\n * Execute the pipe and return results.\n *\n * Takes only `signal` — deliberately narrower than the `RequestOptions` the\n * query builder accepts. The pipes endpoint binds the body as the pipe's\n * parameters, so there is no row cap to forward; give the pipe a `{{limit}}`\n * parameter in its SQL and pass it via `wh.pipe(name, { limit })`.\n */\n async fetch(opts?: PipeRequestOptions): Promise<Result<Row[]>> {\n const { data, error } = await request<Row[]>(this._ctx, {\n method: \"POST\",\n path: `/v1/pipes/${encodeURIComponent(this._name)}`,\n body: this._params ?? {},\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Subscribe to live events from the pipe's underlying query. */\n stream(opts?: StreamOptions): StreamController<Row> {\n return this._createStream(this._name, opts);\n }\n\n then<TResult1 = Result<Row[]>, TResult2 = never>(\n onfulfilled?: ((value: Result<Row[]>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.fetch().then(onfulfilled, onrejected);\n }\n}\n\n/** Admin namespace for managing named query pipes. */\nexport class PipesNamespace {\n private readonly _ctx: HttpContext;\n\n constructor(ctx: HttpContext) {\n this._ctx = ctx;\n }\n\n /** List all registered pipes. */\n async list(opts?: { signal?: AbortSignal }): Promise<Result<Pipe[]>> {\n const { data, error } = await request<Pipe[]>(this._ctx, {\n method: \"GET\",\n path: \"/v1/admin/pipes\",\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Get a single pipe definition by name. */\n async get(name: string, opts?: { signal?: AbortSignal }): Promise<Result<Pipe>> {\n const { data, error } = await request<Pipe>(this._ctx, {\n method: \"GET\",\n path: `/v1/admin/pipes/${encodeURIComponent(name)}`,\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Create or update a pipe. */\n async set(\n name: string,\n def: Omit<Pipe, \"name\">,\n opts?: { signal?: AbortSignal },\n ): Promise<Result<void>> {\n const { error } = await request<{ ok: boolean }>(this._ctx, {\n method: \"PUT\",\n path: `/v1/admin/pipes/${encodeURIComponent(name)}`,\n body: def,\n signal: opts?.signal,\n });\n if (error) return err<void>(error);\n return ok(undefined as undefined);\n }\n\n /** Delete a pipe by name. */\n async delete(name: string, opts?: { signal?: AbortSignal }): Promise<Result<void>> {\n const { error } = await request<{ ok: boolean }>(this._ctx, {\n method: \"DELETE\",\n path: `/v1/admin/pipes/${encodeURIComponent(name)}`,\n signal: opts?.signal,\n });\n if (error) return err<void>(error);\n return ok(undefined as undefined);\n }\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { HttpContext, Policy, Result, ValidationResult } from \"./types.js\";\n\n/** Namespace for access control policy management. Requires the admin role (the configured `admin_role`, `\"admin\"` by default). */\nexport class PolicyNamespace {\n private readonly _ctx: HttpContext;\n\n constructor(ctx: HttpContext) {\n this._ctx = ctx;\n }\n\n /** Get the current access control policy. */\n async get(opts?: { signal?: AbortSignal }): Promise<Result<Policy>> {\n const { data, error } = await request<Policy>(this._ctx, {\n method: \"GET\",\n path: \"/v1/admin/policy\",\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Replace the entire access control policy. */\n async set(policy: Policy, opts?: { signal?: AbortSignal }): Promise<Result<void>> {\n const { error } = await request<{ ok: boolean }>(this._ctx, {\n method: \"PUT\",\n path: \"/v1/admin/policy\",\n body: policy,\n signal: opts?.signal,\n });\n if (error) return err<void>(error);\n return ok(undefined as undefined);\n }\n\n /** Validate a policy without applying it (dry run). */\n async validate(\n policy: Policy,\n opts?: { signal?: AbortSignal },\n ): Promise<Result<ValidationResult>> {\n const { data, error } = await request<ValidationResult>(this._ctx, {\n method: \"POST\",\n path: \"/v1/admin/policy/validate\",\n body: policy,\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { HttpContext, Result, Schemas } from \"./types.js\";\n\n/** Namespace for schema introspection. */\nexport class SchemaNamespace {\n private readonly _ctx: HttpContext;\n\n constructor(ctx: HttpContext) {\n this._ctx = ctx;\n }\n\n /** List all table schemas discovered from ClickHouse. */\n async list(opts?: { signal?: AbortSignal }): Promise<Result<Schemas>> {\n // The backend returns TableSchema[] — transform to Record<string, TableSchema>.\n const { data, error } = await request<unknown>(this._ctx, {\n method: \"GET\",\n path: \"/v1/schema\",\n signal: opts?.signal,\n });\n if (error) return err(error);\n\n let schemas: Schemas;\n if (Array.isArray(data)) {\n schemas = {};\n for (const table of data) {\n if (table && typeof table === \"object\" && \"name\" in table) {\n schemas[(table as { name: string }).name] = table as Schemas[string];\n }\n }\n } else {\n schemas = data as Schemas;\n }\n return ok(schemas);\n }\n\n /** Force a schema refresh from ClickHouse system.columns. */\n async refresh(opts?: { signal?: AbortSignal }): Promise<Result<void>> {\n const { error } = await request<Schemas>(this._ctx, {\n method: \"POST\",\n path: \"/v1/schema/refresh\",\n signal: opts?.signal,\n });\n if (error) return err<void>(error);\n return ok(undefined as undefined);\n }\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { HttpContext, Result } from \"./types.js\";\n\n/**\n * Execute a raw SQL query against ClickHouse.\n *\n * Backed by `POST /v1/admin/query`, which requires the admin role — the same\n * gate as the rest of `/v1/admin/*`. Callers must hold a JWT whose role is the\n * configured `admin_role` (`\"admin\"` by default); there is no separate\n * `service` role. The JWT middleware always runs, so a request with no token\n * or an invalid one is denied, never granted. Non-admin use cases should use\n * the structured query builder (`wh.from(table)...`) instead.\n *\n * The server proxies the SQL string verbatim to ClickHouse's HTTP interface,\n * so any ClickHouse-accepted statement works — including multi-statement\n * input (`SELECT 1; TRUNCATE t`) and arbitrary DDL/DML/SYSTEM verbs.\n *\n * **JSON-row contract.** This helper returns `Result<Row[]>` and assumes the\n * response is the standard `FORMAT JSON` envelope (or an empty body for\n * no-result mutations — coerced to `[]`). Inline non-JSON `FORMAT` overrides\n * (`SELECT 1 FORMAT CSV` / `FORMAT TSV` / `FORMAT Pretty` / etc.) are NOT\n * compatible with `sql()` — the proxy passes the upstream Content-Type\n * through, and the SDK's JSON decoder throws on a non-JSON body, which the\n * retry layer surfaces as a `NETWORK_ERROR` result (not a structured\n * format-mismatch error). For CSV/TSV exports, hit `/v1/admin/query`\n * directly with `fetch()` and read the body as text.\n *\n * **No parameter binding.** Positional `?` substitution is not supported.\n * The SDK has no way to forward ClickHouse-style named params\n * (`WHERE id = {id:UInt32}` with `param_id=42` on the query string) —\n * the proxy doesn't forward arbitrary query-string params to ClickHouse\n * and the SDK doesn't expose a hook to add them. Inline literals into\n * the SQL string, or — for safe binding from user-supplied input — use\n * the structured query builder (`wh.from(...).select(...).where(...)`).\n */\nexport async function sql<Row = Record<string, unknown>>(\n ctx: HttpContext,\n query: string,\n opts?: { signal?: AbortSignal },\n): Promise<Result<Row[]>> {\n const { data, error } = await request<Row[]>(ctx, {\n method: \"POST\",\n path: \"/v1/admin/query\",\n body: { sql: query },\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n}\n","import type { StreamEvent, StreamStatus, StreamSubscriber, WaveHouseError } from \"../types.js\";\n\n/** @internal Transport abstraction for SSE backend. */\nexport interface StreamTransport<T = Record<string, unknown>> {\n connect(): void;\n disconnect(): void;\n onEvent: ((event: StreamEvent<T>) => void) | null;\n onStatus: ((status: StreamStatus) => void) | null;\n onError: ((error: WaveHouseError) => void) | null;\n}\n\n/**\n * Controls a live event stream. NOT thenable.\n * Use `.subscribe()` for callback-based consumption or `for await` for async iteration.\n */\nexport class StreamController<T = Record<string, unknown>> {\n private _transport: StreamTransport<T>;\n private _subscribers = new Set<StreamSubscriber<T>>();\n private _status: StreamStatus = \"connecting\";\n private _buffer: StreamEvent<T>[] = [];\n private _waiters: { resolve: (value: IteratorResult<StreamEvent<T>>) => void }[] = [];\n private _done = false;\n\n constructor(transport: StreamTransport<T>) {\n this._transport = transport;\n\n this._transport.onEvent = (event) => {\n for (const sub of this._subscribers) {\n sub.next(event);\n }\n // Async iterator support\n const waiter = this._waiters.shift();\n if (waiter) {\n waiter.resolve({ value: event, done: false });\n } else {\n this._buffer.push(event);\n }\n };\n\n this._transport.onStatus = (status) => {\n // Deduplicate: skip if status hasn't changed (e.g. transport fires\n // 'connecting' after StreamController already set it as the initial state).\n if (status === this._status) return;\n this._status = status;\n for (const sub of this._subscribers) {\n sub.status?.(status);\n }\n if (status === \"closed\") {\n this._done = true;\n for (const w of this._waiters) {\n w.resolve({ value: undefined as never, done: true });\n }\n this._waiters = [];\n }\n };\n\n this._transport.onError = (error) => {\n for (const sub of this._subscribers) {\n sub.error?.(error);\n }\n };\n\n this._transport.connect();\n }\n\n /** Current connection status. */\n get status(): StreamStatus {\n return this._status;\n }\n\n /**\n * Returns a promise that resolves when the stream status reaches `'live'`,\n * rejects immediately if the stream is already `'closed'`, or rejects after\n * `timeoutMs` milliseconds (default: 5 000) if it never connects.\n *\n * Safe to call before `.subscribe()` — does not trigger auto-close when\n * the internal waiter is removed.\n *\n * `@example`\n * const stream = client.from('events').stream();\n * const unsub = stream.subscribe({ next: (e) => console.log(e) });\n * await stream.connected(); // waits until the transport is live\n * await client.from('events').insert({ ... });\n */\n connected(timeoutMs = 5_000): Promise<void> {\n if (this._status === \"live\") return Promise.resolve();\n if (this._status === \"closed\") return Promise.reject(new Error(\"Stream is closed\"));\n if (this._done) return Promise.reject(new Error(\"Stream closed before connecting\"));\n\n return new Promise((resolve, reject) => {\n let settled = false;\n\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this._subscribers.delete(watcher);\n reject(new Error(`Stream did not connect within ${timeoutMs}ms`));\n }, timeoutMs);\n\n // Use a private subscriber directly to avoid the auto-close side-effect\n // that the public subscribe() triggers when subscriber count drops to zero.\n const watcher: StreamSubscriber<T> = {\n next: () => {\n // no-op: we only care about status transitions here\n },\n status: (s) => {\n if (s === \"live\") {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this._subscribers.delete(watcher);\n resolve();\n } else if (s === \"closed\") {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this._subscribers.delete(watcher);\n reject(new Error(\"Stream closed before connecting\"));\n }\n },\n };\n\n this._subscribers.add(watcher);\n });\n }\n\n /** Subscribe to stream events via callbacks. Returns an unsubscribe function. */\n subscribe(subscriber: StreamSubscriber<T>): () => void {\n this._subscribers.add(subscriber);\n subscriber.status?.(this._status);\n\n return () => {\n this._subscribers.delete(subscriber);\n if (this._subscribers.size === 0 && this._waiters.length === 0) {\n this.close();\n }\n };\n }\n\n /** Attach an AbortSignal — when aborted, the stream is closed. */\n attachSignal(signal: AbortSignal): void {\n if (signal.aborted) {\n this.close();\n return;\n }\n signal.addEventListener(\"abort\", () => this.close(), { once: true });\n }\n\n /** Close the stream and release resources. */\n close(): void {\n this._transport.disconnect();\n if (this._status !== \"closed\") {\n this._status = \"closed\";\n for (const sub of this._subscribers) {\n sub.status?.(\"closed\");\n }\n }\n this._done = true;\n for (const w of this._waiters) {\n w.resolve({ value: undefined as never, done: true });\n }\n this._waiters = [];\n }\n\n /** Async iterator protocol — enables `for await (const event of stream)`. */\n [Symbol.asyncIterator](): AsyncIterableIterator<StreamEvent<T>> {\n const self = this;\n return {\n next(): Promise<IteratorResult<StreamEvent<T>>> {\n if (self._buffer.length > 0) {\n return Promise.resolve({ value: self._buffer.shift()!, done: false });\n }\n if (self._done) {\n return Promise.resolve({ value: undefined as never, done: true });\n }\n return new Promise((resolve) => {\n self._waiters.push({ resolve });\n });\n },\n return(): Promise<IteratorResult<StreamEvent<T>>> {\n self.close();\n return Promise.resolve({ value: undefined as never, done: true });\n },\n [Symbol.asyncIterator]() {\n return this;\n },\n };\n }\n}\n","import type { StreamEvent, StreamStatus, WaveHouseError } from \"../types.js\";\nimport { resolveURL } from \"../url.js\";\nimport type { StreamTransport } from \"./controller.js\";\n\nexport interface SSEOptions {\n baseURL: string;\n table: string;\n since?: string;\n auth?: () => Promise<string> | string;\n}\n\n/** Module-level active SSE connection counter. */\nlet activeSSEConnections = 0;\nconst SSE_WARN_THRESHOLD = 5;\n\n/** SSE transport. Native EventSource auto-reconnects. */\nexport class SSETransport<T = Record<string, unknown>> implements StreamTransport<T> {\n private _opts: SSEOptions;\n private _es: EventSource | null = null;\n\n onEvent: ((event: StreamEvent<T>) => void) | null = null;\n onStatus: ((status: StreamStatus) => void) | null = null;\n onError: ((error: WaveHouseError) => void) | null = null;\n\n constructor(opts: SSEOptions) {\n this._opts = opts;\n }\n\n connect(): void {\n if (typeof EventSource === \"undefined\") {\n throw new Error(\n \"[wavehouse] EventSource is not available in this environment. \" +\n \"Please provide a global polyfill (e.g., `globalThis.EventSource = require('eventsource')`).\",\n );\n }\n\n this._doConnect().catch((err) => {\n this.onError?.({\n status: 0,\n code: \"SSE_CONNECT_ERROR\",\n message: err instanceof Error ? err.message : String(err),\n retryable: true,\n });\n });\n }\n\n disconnect(): void {\n if (this._es) {\n this._es.close();\n this._es = null;\n activeSSEConnections = Math.max(0, activeSSEConnections - 1);\n }\n this.onStatus?.(\"closed\");\n }\n\n private async _doConnect(): Promise<void> {\n const url = resolveURL(this._opts.baseURL, \"/v1/stream\");\n url.searchParams.set(\"table\", this._opts.table);\n if (this._opts.since) {\n url.searchParams.set(\"since\", this._opts.since);\n }\n\n // EventSource can't set request headers, so the JWT goes in ?token=\n // (the server also accepts an Authorization header for non-browser clients)\n if (this._opts.auth) {\n const token = await this._opts.auth();\n if (token) {\n url.searchParams.set(\"token\", token);\n }\n }\n\n activeSSEConnections++;\n if (activeSSEConnections > SSE_WARN_THRESHOLD) {\n console.warn(\n `[wavehouse] ${activeSSEConnections} SSE connections open. ` +\n `Browsers limit HTTP/1.1 to 6 connections per domain.`,\n );\n }\n\n this._es = new EventSource(url.toString());\n\n this._es.onopen = () => {\n this.onStatus?.(\"live\");\n };\n\n this._es.onmessage = (e) => {\n try {\n const msg = JSON.parse(e.data as string) as {\n table_name: string;\n received_timestamp: string;\n data: T;\n };\n const event: StreamEvent<T> = {\n table: msg.table_name,\n timestamp: msg.received_timestamp,\n data: msg.data,\n };\n this.onEvent?.(event);\n } catch {\n console.warn(\"[wavehouse] SSE received malformed message:\", e.data);\n // ignore malformed messages\n }\n };\n\n this._es.onerror = () => {\n if (this._es?.readyState === EventSource.CONNECTING) {\n this.onStatus?.(\"reconnecting\");\n } else if (this._es?.readyState === EventSource.CLOSED) {\n this.onStatus?.(\"closed\");\n } else if (this._es?.readyState === EventSource.OPEN) {\n this.onStatus?.(\"live\");\n } else {\n this.onError?.({\n status: 0,\n code: \"SSE_ERROR\",\n message: \"SSE connection error\",\n retryable: true,\n });\n }\n };\n }\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { HttpContext, Result } from \"./types.js\";\n\n/** Namespace for the SDK's content-free server-online check. */\nexport class SysNamespace {\n private readonly _ctx: HttpContext;\n\n constructor(ctx: HttpContext) {\n this._ctx = ctx;\n }\n\n /**\n * Liveness ping — resolves with no error when the server is reachable and\n * past boot. Hits the public, content-free `/v1/health` route (200/503, no\n * body), kept intentionally distinct from the `/livez` Kubernetes probe so\n * it stays reachable even in deployments that filter probe paths at the\n * reverse proxy. Use it to check a server is online before sending data, or\n * to pick among servers in a distributed setup.\n */\n async health(opts?: { signal?: AbortSignal }): Promise<Result<void>> {\n const { error } = await request<void>(this._ctx, {\n method: \"GET\",\n path: \"/v1/health\",\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok<void>(undefined);\n }\n}\n","import type { QueryFilter, Result, StreamEvent, StreamSubscriber } from \"../types.js\";\nimport type { StreamController } from \"./controller.js\";\n\n/**\n * Stream-first live query orchestrator.\n *\n * 1. Opens a live stream immediately (buffers events).\n * 2. Fetches historical data.\n * 3. Calls `subscriber.initial(result)` with the historical snapshot.\n * 4. Deduplicates buffered events against the fetch result.\n * 5. Flushes remaining buffered events through `subscriber.next()`.\n * 6. Resumes live: pipes stream events directly to `subscriber.next()`.\n */\nexport class LiveQuery<T = Record<string, unknown>> {\n private _stream: StreamController<T>;\n private _subscriber: StreamSubscriber<T>;\n private _buffer: StreamEvent<T>[] = [];\n private _buffering = true;\n private _unsubStream: (() => void) | null = null;\n private _closed = false;\n\n constructor(\n stream: StreamController<T>,\n fetchFn: () => Promise<Result<T[]>>,\n subscriber: StreamSubscriber<T>,\n _filters: QueryFilter[],\n ) {\n this._stream = stream;\n this._subscriber = subscriber;\n\n // Step 1: Subscribe to live events and buffer them.\n this._unsubStream = stream.subscribe({\n next: (event) => {\n if (this._closed) return;\n if (this._buffering) {\n this._buffer.push(event);\n } else {\n subscriber.next(event);\n }\n },\n status: (s) => subscriber.status?.(s),\n error: (e) => subscriber.error?.(e),\n });\n\n // Step 2-5: Fetch historical and flush.\n this._runBackfill(fetchFn);\n }\n\n private async _runBackfill(fetchFn: () => Promise<Result<T[]>>): Promise<void> {\n try {\n const result = await fetchFn();\n\n if (this._closed) return;\n\n // Step 3: Call initial() with the historical snapshot.\n this._subscriber.initial?.(result);\n\n if (result.error) {\n this._buffering = false;\n return;\n }\n\n // Step 4: Deduplicate buffered events against fetched rows.\n // Use received_timestamp as the dedup boundary: only flush events\n // that are newer than the latest row in the fetch result.\n const rows = result.data;\n let lastTimestamp: string | undefined;\n if (rows.length > 0) {\n const lastRow = rows[rows.length - 1] as Record<string, unknown>;\n lastTimestamp = lastRow?.received_timestamp as string | undefined;\n }\n\n // Step 5: Flush buffered events that are newer than the fetch.\n this._buffering = false;\n for (const event of this._buffer) {\n if (this._closed) break;\n if (lastTimestamp && event.timestamp <= lastTimestamp) {\n continue; // already covered by the fetch\n }\n this._subscriber.next(event);\n }\n this._buffer = [];\n } catch {\n // Fetch failed — stop buffering and resume live only.\n this._buffering = false;\n this._buffer = [];\n }\n }\n\n /** Close the live query and the underlying stream. */\n close(): void {\n this._closed = true;\n this._buffering = false;\n this._buffer = [];\n this._unsubStream?.();\n this._stream.close();\n }\n}\n","import { err, okPage } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport type { StreamTransport } from \"./stream/controller.js\";\nimport { StreamController } from \"./stream/controller.js\";\nimport { LiveQuery } from \"./stream/live-query.js\";\nimport type {\n Aggregation,\n FilterOp,\n HttpContext,\n OrderClause,\n QueryFilter,\n RequestOptions,\n Result,\n StreamOptions,\n StreamSubscriber,\n StructuredQuery,\n TimeRange,\n} from \"./types.js\";\n\n/** SDK operator → backend operator mapping. */\nconst OP_MAP: Record<FilterOp, string> = {\n \"=\": \"eq\",\n \"!=\": \"neq\",\n \">\": \"gt\",\n \">=\": \"gte\",\n \"<\": \"lt\",\n \"<=\": \"lte\",\n in: \"in\",\n like: \"like\",\n not_like: \"not_like\",\n};\n\ninterface QueryState {\n table: string;\n columns: string[];\n selectAll?: boolean;\n aggregations: Aggregation[];\n filters: QueryFilter[];\n groupBy: string[];\n orderBy: OrderClause[];\n limit?: number;\n timeRange?: TimeRange;\n cacheTTL?: number;\n}\n\ntype CreateStreamFn<Row> = (table: string, opts?: StreamOptions) => StreamController<Row>;\n\n/**\n * Immutable, PromiseLike query builder.\n * Every chain method returns a new instance. `await builder` auto-executes `.fetch()`.\n */\nexport class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike<Result<Row[]>> {\n /** @internal */\n private readonly _state: Readonly<QueryState>;\n /** @internal */\n private readonly _ctx: HttpContext;\n /** @internal */\n private readonly _createStream: CreateStreamFn<Row>;\n\n constructor(ctx: HttpContext, state: QueryState, createStream: CreateStreamFn<Row>) {\n this._ctx = ctx;\n this._state = Object.freeze({ ...state });\n this._createStream = createStream;\n }\n\n // --- Builder methods (each returns a new QueryBuilder) ---\n\n select(...columns: string[]): QueryBuilder<Row> {\n return this._clone({ columns: [...this._state.columns, ...columns] });\n }\n\n /**\n * Select every column the caller's role is allowed to read (the all-columns\n * wildcard). Use this instead of `.select(...)` when you want a full-row read;\n * a bare `.fetch()` with no `.select()` does this implicitly. Mutually\n * exclusive with `.select(...)`.\n */\n selectAll(): QueryBuilder<Row> {\n return this._clone({ selectAll: true });\n }\n\n where(column: string, op: FilterOp, value: unknown): QueryBuilder<Row> {\n const filter: QueryFilter = { column, op: OP_MAP[op], value };\n return this._clone({ filters: [...this._state.filters, filter] });\n }\n\n count(column = \"*\", alias = \"count\"): QueryBuilder<Row> {\n return this._addAgg(\"count\", column, alias);\n }\n\n sum(column: string, alias = `sum_${column}`): QueryBuilder<Row> {\n return this._addAgg(\"sum\", column, alias);\n }\n\n avg(column: string, alias = `avg_${column}`): QueryBuilder<Row> {\n return this._addAgg(\"avg\", column, alias);\n }\n\n min(column: string, alias = `min_${column}`): QueryBuilder<Row> {\n return this._addAgg(\"min\", column, alias);\n }\n\n max(column: string, alias = `max_${column}`): QueryBuilder<Row> {\n return this._addAgg(\"max\", column, alias);\n }\n\n countDistinct(column: string, alias = `count_distinct_${column}`): QueryBuilder<Row> {\n return this._addAgg(\"countDistinct\", column, alias);\n }\n\n aggregate(fn: string, column: string, alias: string): QueryBuilder<Row> {\n return this._addAgg(fn, column, alias);\n }\n\n groupBy(...columns: string[]): QueryBuilder<Row> {\n return this._clone({ groupBy: [...this._state.groupBy, ...columns] });\n }\n\n orderBy(column: string, dir: \"asc\" | \"desc\" = \"asc\"): QueryBuilder<Row> {\n return this._clone({ orderBy: [...this._state.orderBy, { column, dir }] });\n }\n\n limit(n: number): QueryBuilder<Row> {\n return this._clone({ limit: n });\n }\n\n timeRange(column: string, since: string, until?: string): QueryBuilder<Row> {\n return this._clone({ timeRange: { column, since, until } });\n }\n\n cacheTTL(seconds: number): QueryBuilder<Row> {\n return this._clone({ cacheTTL: seconds });\n }\n\n // --- Execution ---\n\n /** Default row limit when none is specified — deliberately tighter than the backend's DefaultMaxRows (10000) safety cap. */\n static readonly DEFAULT_LIMIT = 1000;\n\n async fetch(opts?: RequestOptions): Promise<Result<Row[]>> {\n const effectiveLimit = opts?.limit ?? this._state.limit ?? QueryBuilder.DEFAULT_LIMIT;\n const ast = this._buildAST(effectiveLimit);\n\n const { data, error } = await request<Row[]>(this._ctx, {\n method: \"POST\",\n path: `/v1/query?table=${encodeURIComponent(this._state.table)}`,\n body: ast,\n signal: opts?.signal,\n });\n\n if (error) return err(error);\n\n const rows = data!;\n const hasMore = effectiveLimit != null && rows.length >= effectiveLimit;\n\n // next() needs an order column for its cursor; with no .orderBy() we still\n // report hasMore honestly from the row count but can't offer a next().\n if (hasMore && this._state.orderBy.length > 0) {\n const nextFn = () => this._fetchNext(rows, effectiveLimit!, opts);\n return okPage(rows, true, nextFn);\n }\n\n return okPage(rows, hasMore);\n }\n\n stream(opts?: StreamOptions): StreamController<Row> {\n const raw = this._createStream(this._state.table, opts);\n const filters = this._state.filters;\n const columns = this._state.columns;\n\n // If no filters or column projection, return the raw stream.\n if (filters.length === 0 && columns.length === 0) {\n return raw;\n }\n\n // Wrap with a filtering transport that applies AST predicates client-side.\n return new FilteredStreamController<Row>(raw, filters, columns);\n }\n\n /**\n * Start a live query: fetches historical data, then streams live updates.\n *\n * The subscriber's `initial()` is called once with the fetch result, then\n * `next()` fires for each live event. Events that arrived during the fetch\n * are deduplicated and flushed automatically.\n *\n * Returns a LiveQuery handle with a `.close()` method.\n */\n liveQuery(subscriber: StreamSubscriber<Row>, opts?: StreamOptions): LiveQuery<Row> {\n const stream = this.stream(opts);\n const fetchFn = () => this.fetch();\n return new LiveQuery<Row>(stream, fetchFn, subscriber, this._state.filters);\n }\n\n // --- PromiseLike implementation ---\n\n then<TResult1 = Result<Row[]>, TResult2 = never>(\n onfulfilled?: ((value: Result<Row[]>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.fetch().then(onfulfilled, onrejected);\n }\n\n // --- Private helpers ---\n\n private _clone(overrides: Partial<QueryState>): QueryBuilder<Row> {\n return new QueryBuilder(this._ctx, { ...this._state, ...overrides }, this._createStream);\n }\n\n private _addAgg(fn: string, column: string, alias: string): QueryBuilder<Row> {\n const agg: Aggregation = { fn, column, alias };\n return this._clone({ aggregations: [...this._state.aggregations, agg] });\n }\n\n private _buildAST(effectiveLimit?: number): StructuredQuery {\n const ast: StructuredQuery = {};\n const hasColumns = this._state.columns.length > 0;\n const hasAggs = this._state.aggregations.length > 0;\n // Projection: an explicit select_all, then explicit columns, else — for a\n // bare query with no projection intent and no aggregations — default to\n // select_all so `from(t).fetch()` returns rows. (The wire default for omitted\n // columns is \"nothing\"; the SDK opts into select_all on the caller's behalf.)\n if (this._state.selectAll) {\n ast.select_all = true;\n } else if (hasColumns) {\n ast.columns = this._state.columns;\n } else if (!hasAggs) {\n ast.select_all = true;\n }\n if (hasAggs) ast.aggregations = this._state.aggregations;\n if (this._state.filters.length > 0) ast.filters = this._state.filters;\n if (this._state.groupBy.length > 0) ast.group_by = this._state.groupBy;\n if (this._state.orderBy.length > 0) ast.order_by = this._state.orderBy;\n if (effectiveLimit != null) ast.limit = effectiveLimit;\n if (this._state.timeRange) ast.time_range = this._state.timeRange;\n return ast;\n }\n\n private async _fetchNext(\n prevRows: Row[],\n _limit: number,\n opts?: RequestOptions,\n ): Promise<Result<Row[]>> {\n // No explicit order → no keyset cursor to build; nothing to page by.\n const cursor = this._state.orderBy[0];\n if (cursor == null) return okPage([] as unknown as Row[], false);\n const { column: orderCol, dir: orderDir } = cursor;\n\n const lastRow = prevRows[prevRows.length - 1] as Record<string, unknown>;\n const lastValue = lastRow?.[orderCol];\n\n if (lastValue === undefined) return okPage([] as unknown as Row[], false);\n\n const cursorOp = orderDir === \"desc\" ? \"lt\" : \"gt\";\n const cursorFilter: QueryFilter = { column: orderCol, op: cursorOp, value: lastValue };\n const nextBuilder = this._clone({\n filters: [...this._state.filters, cursorFilter],\n orderBy: this._state.orderBy,\n });\n\n return nextBuilder.fetch(opts);\n }\n}\n\n// ============================================================================\n// Client-side stream filtering\n// ============================================================================\n\n/**\n * Wraps a StreamController, applying client-side filters and column projection\n * before delivering events to subscribers.\n *\n * Lifecycle: by the time we reach this constructor, `inner` has already been\n * built (and is opening its own SSE connection). The outer transport's\n * `connect()` doesn't open a new connection — it bridges `inner`'s events\n * through a filter into the outer subscriber set. On `disconnect()`, closing\n * `inner` is what actually tears down the SSE socket; the subscription we\n * register on `inner` is left to be garbage-collected with it, which is why\n * we don't bother saving the unsubscribe handle.\n * @internal\n */\nclass FilteredStreamController<T = Record<string, unknown>> extends StreamController<T> {\n constructor(inner: StreamController<T>, filters: QueryFilter[], columns: string[]) {\n const transport: StreamTransport<T> = {\n onEvent: null,\n onStatus: null,\n onError: null,\n connect() {\n inner.subscribe({\n next: (event) => {\n if (!matchesFilters(event.data as Record<string, unknown>, filters)) {\n return;\n }\n const projected =\n columns.length > 0\n ? {\n ...event,\n data: projectColumns(event.data as Record<string, unknown>, columns) as T,\n }\n : event;\n this.onEvent?.(projected);\n },\n status: (s) => this.onStatus?.(s),\n error: (e) => this.onError?.(e),\n });\n },\n disconnect() {\n inner.close();\n },\n };\n super(transport);\n }\n}\n\n/** @internal Evaluate all filters against a data row. All must pass (AND). */\nfunction matchesFilters(row: Record<string, unknown>, filters: QueryFilter[]): boolean {\n for (const f of filters) {\n const val = row[f.column];\n if (!evaluateFilter(val, f.op, f.value)) return false;\n }\n return true;\n}\n\n/** @internal Evaluate a single filter predicate. */\nfunction evaluateFilter(actual: unknown, op: string, expected: unknown): boolean {\n switch (op) {\n case \"eq\":\n return actual === expected;\n case \"neq\":\n return actual !== expected;\n case \"gt\":\n return compareOrdered(actual, expected, (a, b) => a > b);\n case \"gte\":\n return compareOrdered(actual, expected, (a, b) => a >= b);\n case \"lt\":\n return compareOrdered(actual, expected, (a, b) => a < b);\n case \"lte\":\n return compareOrdered(actual, expected, (a, b) => a <= b);\n case \"in\":\n return Array.isArray(expected) && expected.includes(actual);\n case \"like\": {\n if (typeof actual !== \"string\" || typeof expected !== \"string\") return false;\n // Convert SQL LIKE pattern to regex: % → .*, _ → .\n const escaped = expected.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = escaped.replace(/%/g, \".*\").replace(/_/g, \".\");\n return new RegExp(`^${pattern}$`, \"i\").test(actual);\n }\n case \"not_like\": {\n if (typeof actual !== \"string\" || typeof expected !== \"string\") return false;\n const escaped = expected.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const pattern = escaped.replace(/%/g, \".*\").replace(/_/g, \".\");\n return !new RegExp(`^${pattern}$`, \"i\").test(actual);\n }\n default:\n return true; // unknown op — pass through\n }\n}\n\n/**\n * @internal Apply an ordered comparison only when both sides are the same\n * comparable primitive (number-vs-number or string-vs-string — strings are\n * lexicographic, which is correct for ISO-8601 timestamps). Mismatched or\n * unsupported types return false instead of relying on JS coercion.\n */\nfunction compareOrdered(\n actual: unknown,\n expected: unknown,\n cmp: (a: number, b: number) => boolean,\n): boolean {\n if (typeof actual === \"number\" && typeof expected === \"number\") {\n return cmp(actual, expected);\n }\n if (typeof actual === \"string\" && typeof expected === \"string\") {\n // `>`/`<` on strings is lexicographic; reuse the same comparator by\n // casting through `as unknown as number` — the runtime operator works\n // identically on strings.\n return cmp(actual as unknown as number, expected as unknown as number);\n }\n return false;\n}\n\n/** @internal Project a row to only the specified columns. */\nfunction projectColumns(row: Record<string, unknown>, columns: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const col of columns) {\n if (col in row) result[col] = row[col];\n }\n return result;\n}\n","import { err, ok } from \"./errors.js\";\nimport { request } from \"./http.js\";\nimport { QueryBuilder } from \"./query-builder.js\";\nimport type { StreamController } from \"./stream/controller.js\";\nimport type {\n HttpContext,\n InsertRecordResult,\n InsertResult,\n RequestOptions,\n Result,\n StreamOptions,\n TableSchema,\n} from \"./types.js\";\n\ntype CreateStreamFn<Row> = (table: string, opts?: StreamOptions) => StreamController<Row>;\n\n/** Content-Type for the NDJSON batch ingest path. */\nconst NDJSON_CONTENT_TYPE = \"application/x-ndjson\";\n\n/**\n * Accepted sources for {@link TableRef.insertNDJSON}: a string, raw bytes, a\n * Blob/File (browser file inputs), or a byte stream. Non-string sources are\n * read fully before sending.\n */\nexport type NDJSONSource = string | Uint8Array | Blob | ReadableStream<Uint8Array>;\n\n/** Wire shape of the server's batch ingest response (JSON array or NDJSON). */\ninterface BatchIngestResponse {\n total: number;\n succeeded: number;\n failed: number;\n duplicates: number;\n results?: InsertRecordResult[];\n}\n\n/** Read an {@link NDJSONSource} fully into a UTF-8 string. */\nasync function ndjsonSourceToString(source: NDJSONSource): Promise<string> {\n if (typeof source === \"string\") return source;\n if (source instanceof Uint8Array) return new TextDecoder().decode(source);\n // Blob/File and ReadableStream<Uint8Array> are both valid fetch body inits,\n // so let Response drain them to text.\n return new Response(source).text();\n}\n\n/**\n * Reference to a table. NOT thenable — safe to pass around without triggering requests.\n * Use `.fetch()`, `.select()`, `.insert()`, `.schema()`, or `.stream()` to act on it.\n */\nexport class TableRef<Row = Record<string, unknown>> {\n private readonly _ctx: HttpContext;\n private readonly _table: string;\n private readonly _createStream: CreateStreamFn<Row>;\n\n constructor(ctx: HttpContext, table: string, createStream: CreateStreamFn<Row>) {\n this._ctx = ctx;\n this._table = table;\n this._createStream = createStream;\n }\n\n /** SELECT * shortcut — fetches rows with optional pagination. */\n async fetch(opts?: RequestOptions): Promise<Result<Row[]>> {\n return this.select()\n .limit(opts?.limit ?? 1000)\n .fetch(opts);\n }\n\n /** Start building a typed query. Returns an immutable, PromiseLike QueryBuilder. */\n select(...columns: string[]): QueryBuilder<Row> {\n return new QueryBuilder<Row>(\n this._ctx,\n {\n table: this._table,\n columns,\n aggregations: [],\n filters: [],\n groupBy: [],\n orderBy: [],\n },\n this._createStream,\n );\n }\n\n /**\n * Start a query that selects every column the caller's role is allowed to read\n * (the all-columns wildcard). Use instead of `.select(...)` for an explicit\n * full-row read; `.fetch()` does this implicitly.\n */\n selectAll(): QueryBuilder<Row> {\n return this.select().selectAll();\n }\n\n /**\n * Insert one or more rows into this table.\n *\n * A single object is sent as a JSON `POST /v1/ingest`. An **array** is\n * serialized to NDJSON (one record per line) and sent as a single\n * `application/x-ndjson` request: a bad record no longer fails or hides the\n * rest of the batch — per-record outcomes come back in the result\n * (`failed` / `results`), and `ok` is true only when every record succeeded.\n *\n * The array path sends one request regardless of size; bounded-concurrency\n * chunking of very large arrays is tracked separately (#196). For NDJSON you\n * already have (a file or stream), use {@link insertNDJSON}.\n */\n async insert(\n data: Partial<Row> | Partial<Row>[],\n opts?: { signal?: AbortSignal },\n ): Promise<Result<InsertResult>> {\n if (Array.isArray(data)) {\n if (data.length === 0) {\n // Nothing to send — succeed without a round trip.\n return ok({ ok: true, total: 0, succeeded: 0, failed: 0, duplicates: 0, results: [] });\n }\n const ndjson = data.map((row) => JSON.stringify(row)).join(\"\\n\");\n return this._sendNDJSON(ndjson, opts);\n }\n\n const { data: res, error } = await request<{ ok?: boolean; duplicate?: boolean }>(this._ctx, {\n method: \"POST\",\n path: `/v1/ingest?table=${encodeURIComponent(this._table)}`,\n body: data,\n signal: opts?.signal,\n });\n\n if (error) return err(error);\n const result: InsertResult = { ok: res?.ok ?? true };\n if (res?.duplicate != null) result.duplicate = res.duplicate;\n return ok(result);\n }\n\n /**\n * Insert pre-formatted NDJSON (newline-delimited JSON, one record per line)\n * from a string, raw bytes, a Blob/File, or a byte stream — e.g. a `.ndjson`\n * file or a stream produced by another system. For in-memory rows, prefer\n * {@link insert}.\n *\n * Non-string sources are read fully into memory before sending (the server\n * streams the parse). Returns the same per-record batch summary as an array\n * `insert`.\n */\n async insertNDJSON(\n source: NDJSONSource,\n opts?: { signal?: AbortSignal },\n ): Promise<Result<InsertResult>> {\n const ndjson = await ndjsonSourceToString(source);\n return this._sendNDJSON(ndjson, opts);\n }\n\n /**\n * @internal Send an NDJSON body and map the server's batch response onto an\n * {@link InsertResult}. A transport / whole-request failure surfaces as the\n * Result error arm; a processed batch (even with rejected records) surfaces\n * as the success arm with `ok = failed === 0`.\n */\n private async _sendNDJSON(\n ndjson: string,\n opts?: { signal?: AbortSignal },\n ): Promise<Result<InsertResult>> {\n const { data, error } = await request<BatchIngestResponse>(this._ctx, {\n method: \"POST\",\n path: `/v1/ingest?table=${encodeURIComponent(this._table)}`,\n rawBody: ndjson,\n contentType: NDJSON_CONTENT_TYPE,\n signal: opts?.signal,\n });\n\n if (error) return err(error);\n // A 200 with no/empty body (e.g. a record-stripping intermediary) must not\n // throw — mirror the single-object path's optimistic `?? true` and fall back\n // to a zeroed summary so the \"never throws\" Result contract holds.\n const r = data ?? { total: 0, succeeded: 0, failed: 0, duplicates: 0 };\n const result: InsertResult = {\n ok: r.failed === 0,\n total: r.total,\n succeeded: r.succeeded,\n failed: r.failed,\n duplicates: r.duplicates,\n };\n if (r.results && r.results.length > 0) result.results = r.results;\n return ok(result);\n }\n\n /** Fetch the schema for this table. */\n async schema(opts?: { signal?: AbortSignal }): Promise<Result<TableSchema>> {\n const { data, error } = await request<TableSchema>(this._ctx, {\n method: \"GET\",\n path: `/v1/schema?table=${encodeURIComponent(this._table)}`,\n signal: opts?.signal,\n });\n if (error) return err(error);\n return ok(data!);\n }\n\n /** Subscribe to live events for this table. */\n stream(opts?: StreamOptions): StreamController<Row> {\n return this._createStream(this._table, opts);\n }\n}\n","import { DLQNamespace } from \"./dlq.js\";\nimport { PipeRef, PipesNamespace } from \"./pipes.js\";\nimport { PolicyNamespace } from \"./policy.js\";\nimport { SchemaNamespace } from \"./schema.js\";\nimport { sql } from \"./sql.js\";\nimport { StreamController } from \"./stream/controller.js\";\nimport { SSETransport } from \"./stream/sse.js\";\nimport { SysNamespace } from \"./sys.js\";\nimport { TableRef } from \"./table.js\";\nimport type { ClientConfig, Database, HttpContext, Result, StreamOptions } from \"./types.js\";\n\ntype TableName<DB> = DB extends Database ? Extract<keyof DB, string> : string;\ntype RowType<DB, T extends string> = DB extends Database\n ? T extends keyof DB\n ? DB[T]\n : Record<string, unknown>\n : Record<string, unknown>;\n\nexport class WaveHouseClient<DB extends Database = Database> {\n /** @internal */\n readonly _ctx: HttpContext;\n\n /** Schema introspection namespace. */\n readonly schema: SchemaNamespace;\n /** Access control policy namespace (admin). */\n readonly policy: PolicyNamespace;\n /** Dead Letter Queue namespace. */\n readonly dlq: DLQNamespace;\n /** System health/readiness namespace. */\n readonly sys: SysNamespace;\n /** Named query pipes admin namespace. */\n readonly pipes: PipesNamespace;\n\n constructor(config: ClientConfig<DB>) {\n this._ctx = {\n baseURL: config.baseURL.replace(/\\/+$/, \"\"),\n auth: config.auth,\n options: {\n maxRetries: config.options?.maxRetries ?? 2,\n fetch: config.options?.fetch,\n headers: config.options?.headers,\n fetchOptions: config.options?.fetchOptions,\n },\n };\n\n this.schema = new SchemaNamespace(this._ctx);\n this.policy = new PolicyNamespace(this._ctx);\n this.dlq = new DLQNamespace(this._ctx, (table, opts) => this._createStream(table, opts));\n this.sys = new SysNamespace(this._ctx);\n this.pipes = new PipesNamespace(this._ctx);\n }\n\n /** Get a table reference for building queries, inserts, and streams. */\n from<T extends TableName<DB>>(table: T): TableRef<RowType<DB, T>> {\n return new TableRef<RowType<DB, T>>(this._ctx, table, (t, opts) =>\n this._createStream<RowType<DB, T>>(t, opts),\n );\n }\n\n /** Get a reference to a named query pipe. PromiseLike — `await` it to execute. */\n pipe<Row = Record<string, unknown>>(\n name: string,\n params?: Record<string, unknown>,\n ): PipeRef<Row> {\n return new PipeRef<Row>(this._ctx, name, params, (t, opts) => this._createStream<Row>(t, opts));\n }\n\n /**\n * Execute a raw SQL query against ClickHouse. Requires the admin role (the\n * configured `admin_role`, `\"admin\"` by default; there is no separate\n * `service` role). The endpoint proxies straight to ClickHouse's HTTP\n * interface so any ClickHouse-accepted SQL works; positional `?` param\n * binding is NOT supported — inline literals or use the structured query\n * builder for safe binding. See sql.ts for details.\n */\n sql<Row = Record<string, unknown>>(\n query: string,\n opts?: { signal?: AbortSignal },\n ): Promise<Result<Row[]>> {\n // Migration guard: the second argument used to be a positional-`?`\n // params array. TS callers get a compile-time error from the type\n // signature, but JS callers (or `any`-typed callsites) would silently\n // pass an array as `opts` and only discover the break via downstream\n // SQL errors. Throw a clear runtime error pointing at the migration.\n if (Array.isArray(opts)) {\n throw new Error(\n \"[WaveHouse SDK] client.sql(sql, params) was removed. The /v1/admin/query endpoint does not accept positional `?` params. Inline literals into the SQL, or use the structured query builder (wh.from(table)…) for safe binding from user input.\",\n );\n }\n return sql<Row>(this._ctx, query, opts);\n }\n\n /** @internal Create a stream for the given table. */\n private _createStream<T = Record<string, unknown>>(\n table: string,\n opts?: StreamOptions,\n ): StreamController<T> {\n if (typeof EventSource === \"undefined\") {\n // TODO: fallback method? polling?\n throw new Error(\n \"[WaveHouse SDK] Native EventSource is not available in this environment. \" +\n \"Please provide a global polyfill (e.g., `globalThis.EventSource = require('eventsource')`).\",\n );\n }\n\n const transport = new SSETransport<T>({\n baseURL: this._ctx.baseURL,\n table,\n since: opts?.since,\n auth: this._ctx.auth,\n });\n const controller = new StreamController<T>(transport);\n if (opts?.signal) controller.attachSignal(opts.signal);\n return controller;\n }\n}\n\n/** Create a new WaveHouse client instance. */\nexport function createClient<DB extends Database = Database>(\n config: ClientConfig<DB>,\n): WaveHouseClient<DB> {\n return new WaveHouseClient(config);\n}\n"],"mappings":"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","names":["src_exports","__export","DLQNamespace","LiveQuery","PipeRef","PipesNamespace","PolicyNamespace","QueryBuilder","SchemaNamespace","StreamController","SysNamespace","TableRef","WaveHouseClient","createClient","parseErrorResponse","res","body","message","retryable","networkError","cause","ok","data","okPage","hasMore","next","err","error","resolveURL","base","path","params","root","url","k","v","mergeHeaders","base","extra","sdkNames","k","merged","configured","name","value","lower","prior","request","ctx","opts","url","resolveURL","headers","requestBody","token","finalHeaders","lastError","maxAttempts","attempt","init","doFetch","res","text","error","parseErrorResponse","retryAfter","delay","sleep","backoff","e","networkError","ms","signal","resolve","reject","timer","DLQNamespace","ctx","createStream","opts","data","error","request","err","ok","name","PipeRef","ctx","name","params","createStream","opts","data","error","request","err","ok","onfulfilled","onrejected","PipesNamespace","def","PolicyNamespace","ctx","opts","data","error","request","err","ok","policy","SchemaNamespace","ctx","opts","data","error","request","err","schemas","table","ok","sql","ctx","query","opts","data","error","request","err","ok","StreamController","transport","event","sub","waiter","status","w","error","timeoutMs","resolve","reject","settled","timer","watcher","s","subscriber","signal","self","activeSSEConnections","SSE_WARN_THRESHOLD","SSETransport","opts","err","url","resolveURL","token","msg","event","SysNamespace","ctx","opts","error","request","err","ok","LiveQuery","stream","fetchFn","subscriber","_filters","event","s","e","result","rows","lastTimestamp","OP_MAP","QueryBuilder","_QueryBuilder","ctx","state","createStream","columns","column","op","value","filter","alias","fn","dir","n","since","until","seconds","opts","effectiveLimit","ast","data","error","request","err","rows","hasMore","okPage","raw","filters","FilteredStreamController","subscriber","stream","fetchFn","LiveQuery","onfulfilled","onrejected","overrides","agg","hasColumns","hasAggs","prevRows","_limit","cursor","orderCol","orderDir","lastValue","cursorFilter","StreamController","inner","transport","event","matchesFilters","projected","projectColumns","s","e","row","f","val","evaluateFilter","actual","expected","compareOrdered","a","b","pattern","cmp","result","col","NDJSON_CONTENT_TYPE","ndjsonSourceToString","source","TableRef","ctx","table","createStream","opts","columns","QueryBuilder","data","ok","ndjson","row","res","error","request","err","result","r","WaveHouseClient","config","SchemaNamespace","PolicyNamespace","DLQNamespace","table","opts","SysNamespace","PipesNamespace","TableRef","t","name","params","PipeRef","query","sql","transport","SSETransport","controller","StreamController","createClient"]}