@wavehouse/sdk 0.0.0-dev.h825a5d7fa405 → 0.0.0-dev.h9539004107f0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,15 @@
1
1
  /** User-provided database schema mapping table names to row types. */
2
2
  type Database = Record<string, Record<string, unknown>>;
3
3
  /**
4
- * Discriminated union for all async SDK operations. Never throws.
4
+ * Discriminated union for the async SDK calls that return one. Never throws for
5
+ * anything the server returns; a non-absolute `baseURL` and a rejecting `auth`
6
+ * callback do throw, while a runtime with no `fetch` at all surfaces instead as
7
+ * a retried `NETWORK_ERROR` result.
8
+ *
9
+ * `.stream()` and `.liveQuery()` return no `Result` and report the same three
10
+ * differently: a non-absolute `baseURL` reaches the subscriber's `error`
11
+ * callback as a terminal `SSE_CONNECT_ERROR`, a rejecting `auth` as a retryable
12
+ * `SSE_AUTH_ERROR`, and only a missing `fetch` throws from the call itself.
5
13
  *
6
14
  * Discriminated on `ok`: `if (result.ok)` narrows to the success arm (and tells
7
15
  * the compiler `data` is present), while `error` is always available for
@@ -47,19 +55,162 @@ interface StreamSubscriber<T = Record<string, unknown>> {
47
55
  error?: (err: WaveHouseError) => void;
48
56
  }
49
57
  interface ClientConfig<_DB extends Database = Database> {
50
- /** Base URL of the WaveHouse server (e.g. "http://localhost:8080"). */
58
+ /**
59
+ * Base URL of the WaveHouse server (e.g. "http://localhost:8080"). May include
60
+ * a path prefix ("https://app.example.com/api/warehouse") for a WaveHouse
61
+ * behind a backend-for-frontend (BFF), app-server route, or path-routed
62
+ * ingress; request paths are appended to it. The proxy in front must strip
63
+ * the prefix before forwarding.
64
+ *
65
+ * Must be **absolute** — scheme and host included. The transports report a
66
+ * relative value such as "/api/warehouse" differently: a REST call rejects
67
+ * with a `TypeError` instead of returning a `Result`, while a stream reports
68
+ * `SSE_CONNECT_ERROR` to the subscriber's `error` callback. Build an absolute
69
+ * one: `` `${location.origin}/api/warehouse` ``.
70
+ */
51
71
  baseURL: string;
52
72
  /** Auth token provider. Omit for public/unauthenticated access. */
53
73
  auth?: () => Promise<string> | string;
54
74
  /** Additional client options. */
55
75
  options?: ClientOptions;
56
76
  }
77
+ /**
78
+ * A `fetch`-compatible function.
79
+ *
80
+ * Spelled out rather than written `typeof fetch`, which resolves differently
81
+ * depending on whether the consumer's TypeScript `lib` includes DOM — the same
82
+ * signature either way, but stable across configurations.
83
+ *
84
+ * The parameter is `string` rather than `typeof fetch`'s wider union because a
85
+ * string URL is all the SDK ever passes. Since parameters are contravariant,
86
+ * narrowing it *widens* what can be assigned: the global `fetch` still fits, and
87
+ * so does hand-written `(url: string, init?: RequestInit) => Promise<Response>`
88
+ * middleware, which the wider spelling rejects at compile time.
89
+ *
90
+ * On REST the SDK reads `.ok` and `.headers` always, `.text()` on success, and
91
+ * `.status`, `.statusText` plus `.json()` when the response is not `ok`. A
92
+ * rejection becomes a `NETWORK_ERROR` result and is retried with backoff —
93
+ * unless the `AbortSignal` you passed has been aborted, in which case the
94
+ * result is `ABORTED` and nothing is retried. That is decided from the signal
95
+ * rather than the rejection's type, so an implementation that throws something
96
+ * other than a `DOMException` named `AbortError` — `AbortSignal.timeout()`,
97
+ * `node-fetch` — is reported the same way.
98
+ *
99
+ * **Streaming needs more.** `.stream()` and `.liveQuery()` read the response as
100
+ * it arrives, via `.body.getReader()`, so an implementation used with them must
101
+ * return a response carrying a live `ReadableStream` — something the type cannot
102
+ * enforce, since `Response.body` is legitimately nullable. A response handed
103
+ * back with an absent or already-consumed body fails fast with
104
+ * `SSE_NO_STREAM_BODY`. What the SDK *cannot* rescue is an implementation that
105
+ * awaits the body before returning — `await res.text()`, or the
106
+ * `res.clone().text()` a logging wrapper reaches for — because on a stream that
107
+ * never ends, that never resolves and your function never returns. Both satisfy
108
+ * every REST call, which is what makes the trap easy to walk into.
109
+ *
110
+ * Implementations shipping their own request/response declarations (undici,
111
+ * `node-fetch`) need casts on the init and the return value, since those types
112
+ * are separate from the ones behind your global `fetch`; the narrow runtime
113
+ * contract above is what makes them safe.
114
+ */
115
+ type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
57
116
  interface ClientOptions {
58
117
  /** Maximum retry attempts for failed requests. Default: 2. */
59
118
  maxRetries?: number;
119
+ /**
120
+ * HTTP implementation used for every request, REST and streaming alike.
121
+ * Defaults to the global `fetch`.
122
+ *
123
+ * Provide one to route through a proxy, attach client certificates, add
124
+ * middleware (logging, tracing, circuit breaking), or bypass a transport bug
125
+ * in the runtime's bundled HTTP stack by routing through an implementation
126
+ * you install yourself — e.g. an undici new enough to be free of
127
+ * {@link https://github.com/nodejs/undici/issues/5600 | undici #5600}:
128
+ *
129
+ * ```ts
130
+ * import { Agent, fetch as undiciFetch } from "undici"; // npm install undici — 8.10.0+
131
+ * // Pass the dispatcher explicitly: undici's pool lives on a shared
132
+ * // globalThis symbol claimed by whichever copy loaded first, so an implied
133
+ * // dispatcher can still be the runtime's affected one.
134
+ * const dispatcher = new Agent();
135
+ * createClient({
136
+ * baseURL,
137
+ * options: {
138
+ * fetch: (url, init) =>
139
+ * undiciFetch(url, { ...init, dispatcher } as never) as unknown as Promise<Response>,
140
+ * },
141
+ * });
142
+ * ```
143
+ *
144
+ * `.stream()` and `.liveQuery()` go through it too, which imposes the extra
145
+ * streaming requirement described on {@link FetchLike} — read that before
146
+ * supplying a wrapper that touches the response body.
147
+ */
148
+ fetch?: FetchLike;
149
+ /**
150
+ * Headers added to every request, REST and streaming alike — for a
151
+ * header-gated proxy in front of WaveHouse, such as a Cloudflare Access
152
+ * service token.
153
+ *
154
+ * Matched case-insensitively, as HTTP headers are. Applied underneath the
155
+ * SDK's own headers: `auth` still owns `Authorization`, and the
156
+ * `Content-Type` and `Accept` a given request needs are not overridable
157
+ * here — a global `Content-Type` that outranked the request's own is a
158
+ * documented way to break uploads.
159
+ *
160
+ * In a browser these are subject to CORS: a header outside the safelist adds
161
+ * it to the preflight, which the origin must allow. WaveHouse's own CORS
162
+ * advertises a fixed set, so custom headers reach it cross-origin only when
163
+ * a proxy in front terminates the preflight — which is the deployment they
164
+ * exist for. Server-side callers never preflight.
165
+ */
166
+ headers?: Record<string, string>;
167
+ /**
168
+ * Extra `RequestInit` fields merged into every request — `credentials` for a
169
+ * cookie-authenticated origin, `mode`, `cache`, `keepalive`, or a
170
+ * runtime-specific extension such as Next.js's `next: { tags }`.
171
+ *
172
+ * Fields the SDK controls (`method`, `headers`, `body`, `signal`) always
173
+ * win, so this cannot corrupt the request itself. Non-standard fields may
174
+ * need a cast, since `RequestInit` only declares the standard ones.
175
+ *
176
+ * The streaming transport additionally owns `cache` and `redirect`, where the
177
+ * values are load-bearing rather than preference: a `Cache-Control` header
178
+ * would fail cross-origin preflight, and following a redirect would strip the
179
+ * `Authorization` header on a cross-origin hop and silently downgrade the
180
+ * stream to the default role instead of failing. So a request carrying an
181
+ * `auth` token, or configured `headers` that may hold a proxy secret, refuses
182
+ * redirects (`SSE_REDIRECT`); without either it follows them, so CDN
183
+ * canonicalization and an http→https upgrade still work. Note the test is
184
+ * that concrete pair, not "is this authenticated" — **cookies are invisible
185
+ * to it**. A cookie is re-derived from the cookie store at each hop rather
186
+ * than carried, so under the default `same-origin` credentials mode a
187
+ * redirect keeps the stream authenticated only while the hop stays inside
188
+ * both the request's origin and the cookie's `Path`; a hop outside either
189
+ * arrives with no cookie and gets a `default_role` view rather than an error.
190
+ * With `credentials: "include"` the origin half is replaced rather than
191
+ * lifted: ordinary cookie scoping decides, so the cookie crosses a
192
+ * CORS-allowed cross-origin hop only if its own `Domain` covers the target —
193
+ * a host-only cookie, the default, still stops at its host. Spelled out
194
+ * under "Supplying your own `fetch`" in the SDK guide; see #478.
195
+ * `credentials` itself is honored in browsers and dropped elsewhere, since
196
+ * some runtimes throw if it is set.
197
+ */
198
+ fetchOptions?: RequestInit;
60
199
  }
61
200
  interface StructuredQuery {
201
+ /**
202
+ * Explicit columns to project. A literal "*" is a column named "*", not a
203
+ * wildcard. Omitting columns (with no aggregations and no select_all) selects
204
+ * nothing — use select_all for a full-row read. Mutually exclusive with
205
+ * select_all.
206
+ */
62
207
  columns?: string[];
208
+ /**
209
+ * Request every column the caller's role may read (the all-columns wildcard,
210
+ * expanded server-side to the allowed/denied set). Mutually exclusive with a
211
+ * non-empty columns list.
212
+ */
213
+ select_all?: boolean;
63
214
  aggregations?: Aggregation[];
64
215
  filters?: QueryFilter[];
65
216
  group_by?: string[];
@@ -97,9 +248,36 @@ interface TableSchema {
97
248
  columns: Column[];
98
249
  }
99
250
  type Schemas = Record<string, TableSchema>;
251
+ /**
252
+ * A per-record outcome from a batch (array / NDJSON) insert. Mirrors the
253
+ * single-object response shape plus the record's position. Exactly one of
254
+ * `ok` / `duplicate` / `error` is set.
255
+ */
256
+ interface InsertRecordResult {
257
+ /** 1-based index of the record within the submitted batch. */
258
+ index: number;
259
+ /** Set when the record was validated and published. */
260
+ ok?: boolean;
261
+ /** Set when dedup skipped the record. */
262
+ duplicate?: boolean;
263
+ /** Set (with `ok`/`duplicate` absent) when the record was rejected. */
264
+ error?: string;
265
+ }
100
266
  interface InsertResult {
267
+ /** True for a fully successful insert: a single row, or a batch with no rejected records (`failed === 0`). */
101
268
  ok: boolean;
269
+ /** Single insert only: set when dedup skipped the row. */
102
270
  duplicate?: boolean;
271
+ /** Batch insert (array / NDJSON): number of records submitted. */
272
+ total?: number;
273
+ /** Batch insert: records validated and published. */
274
+ succeeded?: number;
275
+ /** Batch insert: records rejected — see `results`. */
276
+ failed?: number;
277
+ /** Batch insert: records skipped by dedup. */
278
+ duplicates?: number;
279
+ /** Batch insert: per-record outcomes, each `{index, ok|duplicate|error}` (may be truncated for very large batches; the counts stay authoritative). */
280
+ results?: InsertRecordResult[];
103
281
  }
104
282
  interface DLQStats {
105
283
  tables: Record<string, number>;
@@ -133,8 +311,22 @@ interface RolePermissions {
133
311
  check?: Record<string, PolicyFilter>;
134
312
  allowed_aggregations?: string[];
135
313
  denied_aggregations?: string[];
314
+ /** Caps the query result LIMIT. 0 = no limit. */
136
315
  max_rows?: number;
137
- max_execution_time_ms?: number;
316
+ /**
317
+ * Max query execution time, enforced server-side by ClickHouse. Set it as a
318
+ * duration string ("5s", "500ms") or a number of milliseconds; reads always
319
+ * return the number of milliseconds.
320
+ */
321
+ max_execution_time?: number | string;
322
+ /** Max rows scanned from storage, enforced server-side by ClickHouse. 0 = no limit. */
323
+ max_rows_to_read?: number;
324
+ /**
325
+ * Max peak query memory, enforced server-side by ClickHouse. Set it as a size
326
+ * string ("4GiB", "512MiB") or a number of bytes; reads always return the
327
+ * number of bytes.
328
+ */
329
+ max_memory_usage?: number | string;
138
330
  }
139
331
  interface PolicyFilter {
140
332
  _eq?: string;
@@ -146,10 +338,32 @@ interface PolicyFilter {
146
338
  interface ValidationResult {
147
339
  valid: boolean;
148
340
  }
149
- interface FetchOptions {
341
+ /**
342
+ * Options for a single call, passed to `.fetch()`.
343
+ *
344
+ * Note that `await`ing a builder directly (`await wh.from("t").select("*")`)
345
+ * takes no options — use the explicit `.fetch({ … })` form for those.
346
+ */
347
+ interface RequestOptions {
150
348
  signal?: AbortSignal;
151
349
  limit?: number;
152
350
  }
351
+ /**
352
+ * Options for a single `PipeRef.fetch()` call.
353
+ *
354
+ * `limit` is declared `never` rather than simply left out. Omitting it would
355
+ * still admit a `RequestOptions` value that carries one — excess-property
356
+ * checking only rejects fresh object literals, so a variable would pass and the
357
+ * limit would be silently dropped, which is the whole defect this prevents.
358
+ *
359
+ * A pipe's row cap belongs in its SQL as a `{{limit}}` parameter, supplied via
360
+ * `wh.pipe(name, { limit })`.
361
+ */
362
+ interface PipeRequestOptions {
363
+ signal?: AbortSignal;
364
+ /** Not supported on pipes — pass `limit` as a pipe parameter instead. */
365
+ limit?: never;
366
+ }
153
367
  interface StreamOptions {
154
368
  since?: string;
155
369
  signal?: AbortSignal;
@@ -160,6 +374,9 @@ interface HttpContext {
160
374
  auth?: () => Promise<string> | string;
161
375
  options: {
162
376
  maxRetries: number;
377
+ fetch?: FetchLike;
378
+ headers?: Record<string, string>;
379
+ fetchOptions?: RequestInit;
163
380
  };
164
381
  }
165
382
 
@@ -236,8 +453,15 @@ declare class PipeRef<Row = Record<string, unknown>> implements PromiseLike<Resu
236
453
  private readonly _params?;
237
454
  private readonly _createStream;
238
455
  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[]>>;
456
+ /**
457
+ * Execute the pipe and return results.
458
+ *
459
+ * Takes only `signal` — deliberately narrower than the `RequestOptions` the
460
+ * query builder accepts. The pipes endpoint binds the body as the pipe's
461
+ * parameters, so there is no row cap to forward; give the pipe a `{{limit}}`
462
+ * parameter in its SQL and pass it via `wh.pipe(name, { limit })`.
463
+ */
464
+ fetch(opts?: PipeRequestOptions): Promise<Result<Row[]>>;
241
465
  /** Subscribe to live events from the pipe's underlying query. */
242
466
  stream(opts?: StreamOptions): StreamController<Row>;
243
467
  then<TResult1 = Result<Row[]>, TResult2 = never>(onfulfilled?: ((value: Result<Row[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
@@ -339,6 +563,7 @@ declare class LiveQuery<T = Record<string, unknown>> {
339
563
  interface QueryState {
340
564
  table: string;
341
565
  columns: string[];
566
+ selectAll?: boolean;
342
567
  aggregations: Aggregation[];
343
568
  filters: QueryFilter[];
344
569
  groupBy: string[];
@@ -361,6 +586,13 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
361
586
  private readonly _createStream;
362
587
  constructor(ctx: HttpContext, state: QueryState, createStream: CreateStreamFn$1<Row>);
363
588
  select(...columns: string[]): QueryBuilder<Row>;
589
+ /**
590
+ * Select every column the caller's role is allowed to read (the all-columns
591
+ * wildcard). Use this instead of `.select(...)` when you want a full-row read;
592
+ * a bare `.fetch()` with no `.select()` does this implicitly. Mutually
593
+ * exclusive with `.select(...)`.
594
+ */
595
+ selectAll(): QueryBuilder<Row>;
364
596
  where(column: string, op: FilterOp, value: unknown): QueryBuilder<Row>;
365
597
  count(column?: string, alias?: string): QueryBuilder<Row>;
366
598
  sum(column: string, alias?: string): QueryBuilder<Row>;
@@ -374,9 +606,9 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
374
606
  limit(n: number): QueryBuilder<Row>;
375
607
  timeRange(column: string, since: string, until?: string): QueryBuilder<Row>;
376
608
  cacheTTL(seconds: number): QueryBuilder<Row>;
377
- /** Default row limit when none is specified. Matches backend DefaultMaxRows. */
609
+ /** Default row limit when none is specified — deliberately tighter than the backend's DefaultMaxRows (10000) safety cap. */
378
610
  static readonly DEFAULT_LIMIT = 1000;
379
- fetch(opts?: FetchOptions): Promise<Result<Row[]>>;
611
+ fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
380
612
  stream(opts?: StreamOptions): StreamController<Row>;
381
613
  /**
382
614
  * Start a live query: fetches historical data, then streams live updates.
@@ -396,6 +628,12 @@ declare class QueryBuilder<Row = Record<string, unknown>> implements PromiseLike
396
628
  }
397
629
 
398
630
  type CreateStreamFn<Row> = (table: string, opts?: StreamOptions) => StreamController<Row>;
631
+ /**
632
+ * Accepted sources for {@link TableRef.insertNDJSON}: a string, raw bytes, a
633
+ * Blob/File (browser file inputs), or a byte stream. Non-string sources are
634
+ * read fully before sending.
635
+ */
636
+ type NDJSONSource = string | Uint8Array | Blob | ReadableStream<Uint8Array>;
399
637
  /**
400
638
  * Reference to a table. NOT thenable — safe to pass around without triggering requests.
401
639
  * Use `.fetch()`, `.select()`, `.insert()`, `.schema()`, or `.stream()` to act on it.
@@ -406,13 +644,51 @@ declare class TableRef<Row = Record<string, unknown>> {
406
644
  private readonly _createStream;
407
645
  constructor(ctx: HttpContext, table: string, createStream: CreateStreamFn<Row>);
408
646
  /** SELECT * shortcut — fetches rows with optional pagination. */
409
- fetch(opts?: FetchOptions): Promise<Result<Row[]>>;
647
+ fetch(opts?: RequestOptions): Promise<Result<Row[]>>;
410
648
  /** Start building a typed query. Returns an immutable, PromiseLike QueryBuilder. */
411
649
  select(...columns: string[]): QueryBuilder<Row>;
412
- /** Insert one or more rows into this table. */
650
+ /**
651
+ * Start a query that selects every column the caller's role is allowed to read
652
+ * (the all-columns wildcard). Use instead of `.select(...)` for an explicit
653
+ * full-row read; `.fetch()` does this implicitly.
654
+ */
655
+ selectAll(): QueryBuilder<Row>;
656
+ /**
657
+ * Insert one or more rows into this table.
658
+ *
659
+ * A single object is sent as a JSON `POST /v1/ingest`. An **array** is
660
+ * serialized to NDJSON (one record per line) and sent as a single
661
+ * `application/x-ndjson` request: a bad record no longer fails or hides the
662
+ * rest of the batch — per-record outcomes come back in the result
663
+ * (`failed` / `results`), and `ok` is true only when every record succeeded.
664
+ *
665
+ * The array path sends one request regardless of size; bounded-concurrency
666
+ * chunking of very large arrays is tracked separately (#196). For NDJSON you
667
+ * already have (a file or stream), use {@link insertNDJSON}.
668
+ */
413
669
  insert(data: Partial<Row> | Partial<Row>[], opts?: {
414
670
  signal?: AbortSignal;
415
671
  }): Promise<Result<InsertResult>>;
672
+ /**
673
+ * Insert pre-formatted NDJSON (newline-delimited JSON, one record per line)
674
+ * from a string, raw bytes, a Blob/File, or a byte stream — e.g. a `.ndjson`
675
+ * file or a stream produced by another system. For in-memory rows, prefer
676
+ * {@link insert}.
677
+ *
678
+ * Non-string sources are read fully into memory before sending (the server
679
+ * streams the parse). Returns the same per-record batch summary as an array
680
+ * `insert`.
681
+ */
682
+ insertNDJSON(source: NDJSONSource, opts?: {
683
+ signal?: AbortSignal;
684
+ }): Promise<Result<InsertResult>>;
685
+ /**
686
+ * @internal Send an NDJSON body and map the server's batch response onto an
687
+ * {@link InsertResult}. A transport / whole-request failure surfaces as the
688
+ * Result error arm; a processed batch (even with rejected records) surfaces
689
+ * as the success arm with `ok = failed === 0`.
690
+ */
691
+ private _sendNDJSON;
416
692
  /** Fetch the schema for this table. */
417
693
  schema(opts?: {
418
694
  signal?: AbortSignal;
@@ -458,4 +734,4 @@ declare class WaveHouseClient<DB extends Database = Database> {
458
734
  /** Create a new WaveHouse client instance. */
459
735
  declare function createClient<DB extends Database = Database>(config: ClientConfig<DB>): WaveHouseClient<DB>;
460
736
 
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 };
737
+ export { type Aggregation, type ClientConfig, type ClientOptions, type Column, DLQNamespace, type DLQStats, type Database, type FetchLike, type FilterOp, type InsertRecordResult, type InsertResult, LiveQuery, type NDJSONSource, type OrderClause, type ParamDef, type Pipe, PipeRef, type PipeRequestOptions, PipesNamespace, type Policy, type PolicyFilter, PolicyNamespace, QueryBuilder, type QueryFilter, type RequestOptions, type Result, type RolePermissions, SchemaNamespace, type Schemas, StreamController, type StreamEvent, type StreamOptions, type StreamStatus, type StreamSubscriber, type StructuredQuery, SysNamespace, type TablePolicy, TableRef, type TableSchema, type TimeRange, type ValidationResult, WaveHouseClient, type WaveHouseError, createClient };
@@ -0,0 +1,12 @@
1
+ "use strict";var WaveHouse=(()=>{var z=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var Re=(n,e)=>{for(var t in e)z(n,t,{get:e[t],enumerable:!0})},Se=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of _e(e))!ye.call(n,s)&&s!==t&&z(n,s,{get:()=>e[s],enumerable:!(r=ge(e,s))||r.enumerable});return n};var we=n=>Se(z({},"__esModule",{value:!0}),n);var ke={};Re(ke,{DLQNamespace:()=>E,LiveQuery:()=>D,PipeRef:()=>C,PipesNamespace:()=>A,PolicyNamespace:()=>P,QueryBuilder:()=>k,SchemaNamespace:()=>O,StreamController:()=>v,SysNamespace:()=>B,TableRef:()=>H,WaveHouseClient:()=>q,createClient:()=>ce});async function F(n){let e;try{e=await n.json()}catch{e=void 0}let t=typeof e?.error=="string"?e.error:typeof e?.message=="string"?e.message:n.statusText,r=n.status===503||n.status>=500;return{status:n.status,code:`HTTP_${n.status}`,message:t,details:e,retryable:r}}function te(n){return{status:0,code:"NETWORK_ERROR",message:n instanceof Error?n.message:String(n),retryable:!0}}function h(n){return{ok:!0,data:n,error:null}}function L(n,e,t){return{ok:!0,data:n,error:null,hasMore:e,next:t}}function m(n){return{ok:!1,data:null,error:n}}function j(n,e,t){let r=new URL(n);r.search="",r.hash="",r.pathname.endsWith("/")||(r.pathname+="/");let s=new URL(e.replace(/^\/+/,""),r);if(t)for(let[o,a]of Object.entries(t))s.searchParams.set(o,a);return s}function G(n,e){if(!e)return n;let t=new Set(Object.keys(n).map(o=>o.toLowerCase())),r={...n},s=new Map;for(let[o,a]of Object.entries(e)){let d=o.toLowerCase();if(t.has(d))continue;let u=s.get(d);u!==void 0&&delete r[u],r[o]=a,s.set(d,o)}return r}function re(){return{data:null,error:{status:0,code:"ABORTED",message:"Request aborted",retryable:!1},headers:new Headers}}async function p(n,e){let t=j(n.baseURL,e.path,e.params).toString(),r={"Content-Type":e.contentType??"application/json",Accept:"application/json"},s=e.rawBody!==void 0?e.rawBody:e.body!==void 0?JSON.stringify(e.body):void 0;if(n.auth){let u=await n.auth();u&&(r.Authorization=`Bearer ${u}`)}let o=G(r,n.options.headers),a=null,d=n.options.maxRetries+1;for(let u=0;u<d;u++)try{let R={...n.options.fetchOptions,method:e.method,headers:o,body:s,signal:e.signal},g=n.options.fetch,f=g?await g(t,R):await fetch(t,R);if(f.ok){let w=await f.text();return{data:w?JSON.parse(w):void 0,error:null,headers:f.headers}}let S=await F(f);if(f.status===503){let w=f.headers.get("Retry-After");if(w&&u<d-1){let Q=parseInt(w,10)*1e3||3e4;await J(Q,e.signal),a=S;continue}}if(S.retryable&&u<d-1){await J(se(u),e.signal),a=S;continue}return{data:null,error:S,headers:f.headers}}catch(R){if(e.signal?.aborted)return re();if(a=te(R),u<d-1)try{await J(se(u),e.signal)}catch(g){if(e.signal?.aborted)return re();throw g}}return{data:null,error:a,headers:new Headers}}function se(n){return Math.min(1e3*2**n,3e4)}function J(n,e){return new Promise((t,r)=>{if(e?.aborted){r(new DOMException("Aborted","AbortError"));return}let s=setTimeout(t,n);e?.addEventListener("abort",()=>{clearTimeout(s),r(new DOMException("Aborted","AbortError"))},{once:!0})})}var E=class{_ctx;_createStream;constructor(e,t){this._ctx=e,this._createStream=t}async list(e){let{data:t,error:r}=await p(this._ctx,{method:"GET",path:"/v1/ops/dlq/stats",signal:e?.signal});return r?m(r):h(t)}async table(e,t){let{data:r,error:s}=await p(this._ctx,{method:"GET",path:"/v1/ops/dlq/stats",params:{table:e},signal:t?.signal});return s?m(s):h(r)}stream(e){return this._createStream("dlq",e)}};var C=class{_ctx;_name;_params;_createStream;constructor(e,t,r,s){this._ctx=e,this._name=t,this._params=r,this._createStream=s}async fetch(e){let{data:t,error:r}=await p(this._ctx,{method:"POST",path:`/v1/pipes/${encodeURIComponent(this._name)}`,body:this._params??{},signal:e?.signal});return r?m(r):h(t)}stream(e){return this._createStream(this._name,e)}then(e,t){return this.fetch().then(e,t)}},A=class{_ctx;constructor(e){this._ctx=e}async list(e){let{data:t,error:r}=await p(this._ctx,{method:"GET",path:"/v1/ops/pipes",signal:e?.signal});return r?m(r):h(t)}async get(e,t){let{data:r,error:s}=await p(this._ctx,{method:"GET",path:`/v1/ops/pipes/${encodeURIComponent(e)}`,signal:t?.signal});return s?m(s):h(r)}async set(e,t,r){let{error:s}=await p(this._ctx,{method:"PUT",path:`/v1/ops/pipes/${encodeURIComponent(e)}`,body:t,signal:r?.signal});return s?m(s):h(void 0)}async delete(e,t){let{error:r}=await p(this._ctx,{method:"DELETE",path:`/v1/ops/pipes/${encodeURIComponent(e)}`,signal:t?.signal});return r?m(r):h(void 0)}};var P=class{_ctx;constructor(e){this._ctx=e}async get(e){let{data:t,error:r}=await p(this._ctx,{method:"GET",path:"/v1/ops/policy",signal:e?.signal});return r?m(r):h(t)}async set(e,t){let{error:r}=await p(this._ctx,{method:"PUT",path:"/v1/ops/policy",body:e,signal:t?.signal});return r?m(r):h(void 0)}async validate(e,t){let{data:r,error:s}=await p(this._ctx,{method:"POST",path:"/v1/ops/policy/validate",body:e,signal:t?.signal});return s?m(s):h(r)}};var O=class{_ctx;constructor(e){this._ctx=e}async list(e){let{data:t,error:r}=await p(this._ctx,{method:"GET",path:"/v1/ops/schema",signal:e?.signal});if(r)return m(r);let s;if(Array.isArray(t)){s={};for(let o of t)o&&typeof o=="object"&&"name"in o&&(s[o.name]=o)}else s=t;return h(s)}async refresh(e){let{error:t}=await p(this._ctx,{method:"POST",path:"/v1/ops/schema/refresh",signal:e?.signal});return t?m(t):h(void 0)}};async function ne(n,e,t){let{data:r,error:s}=await p(n,{method:"POST",path:"/v1/ops/query",body:{sql:e},signal:t?.signal});return s?m(s):h(r)}var v=class{_transport;_subscribers=new Set;_status="connecting";_buffer=[];_waiters=[];_done=!1;constructor(e){this._transport=e,this._transport.onEvent=t=>{for(let s of this._subscribers)s.next(t);let r=this._waiters.shift();r?r.resolve({value:t,done:!1}):this._buffer.push(t)},this._transport.onStatus=t=>{if(t!==this._status){this._status=t;for(let r of this._subscribers)r.status?.(t);if(t==="closed"){this._done=!0;for(let r of this._waiters)r.resolve({value:void 0,done:!0});this._waiters=[]}}},this._transport.onError=t=>{for(let r of this._subscribers)r.error?.(t)},this._transport.connect()}get status(){return this._status}connected(e=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((t,r)=>{let s=!1,o=setTimeout(()=>{s||(s=!0,this._subscribers.delete(a),r(new Error(`Stream did not connect within ${e}ms`)))},e),a={next:()=>{},status:d=>{if(d==="live"){if(s)return;s=!0,clearTimeout(o),this._subscribers.delete(a),t()}else if(d==="closed"){if(s)return;s=!0,clearTimeout(o),this._subscribers.delete(a),r(new Error("Stream closed before connecting"))}}};this._subscribers.add(a)})}subscribe(e){return this._subscribers.add(e),e.status?.(this._status),()=>{this._subscribers.delete(e),this._subscribers.size===0&&this._waiters.length===0&&this.close()}}attachSignal(e){if(e.aborted){this.close();return}e.addEventListener("abort",()=>this.close(),{once:!0})}close(){if(this._transport.disconnect(),this._status!=="closed"){this._status="closed";for(let e of this._subscribers)e.status?.("closed")}this._done=!0;for(let e of this._waiters)e.resolve({value:void 0,done:!0});this._waiters=[]}[Symbol.asyncIterator](){let e=this;return{next(){return e._buffer.length>0?Promise.resolve({value:e._buffer.shift(),done:!1}):e._done?Promise.resolve({value:void 0,done:!0}):new Promise(t=>{e._waiters.push({resolve:t})})},return(){return e.close(),Promise.resolve({value:void 0,done:!0})},[Symbol.asyncIterator](){return this}}}};var I=class extends Error{constructor(e,t){super(e),this.name="ParseError",this.type=t.type,this.field=t.field,this.value=t.value,this.line=t.line}},oe=10,be=13,T=32;function K(n){}function le(n){if(typeof n=="function")throw new TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");let{onEvent:e=K,onError:t=K,onRetry:r=K,onComment:s,maxBufferSize:o}=n,a=[],d=0,u=!0,R,g="",f=0,S,w=!1;function Q(l){if(w)throw new Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");if(u&&(u=!1,l.charCodeAt(0)===239&&l.charCodeAt(1)===187&&l.charCodeAt(2)===191&&(l=l.slice(3))),a.length===0){let _=X(l);_!==""&&(a.push(_),d=_.length),M();return}if(l.indexOf(`
2
+ `)===-1&&l.indexOf("\r")===-1){a.push(l),d+=l.length,M();return}a.push(l);let i=a.join("");a.length=0,d=0;let c=X(i);c!==""&&(a.push(c),d=c.length),M()}function M(){o!==void 0&&(d+g.length<=o||(w=!0,a.length=0,d=0,R=void 0,g="",f=0,S=void 0,t(new I(`Buffered data exceeded max buffer size of ${o} characters`,{type:"max-buffer-size-exceeded"}))))}function X(l){let i=0;if(l.indexOf("\r")===-1){let c=l.indexOf(`
3
+ `,i);for(;c!==-1;){if(i===c){f>0&&e({id:R,event:S,data:g}),R=void 0,g="",f=0,S=void 0,i=c+1,c=l.indexOf(`
4
+ `,i);continue}let _=l.charCodeAt(i);if(ie(l,i,_)){let y=l.charCodeAt(i+5)===T?i+6:i+5,b=l.slice(y,c);if(f===0&&l.charCodeAt(c+1)===oe){e({id:R,event:S,data:b}),R=void 0,g="",S=void 0,i=c+2,c=l.indexOf(`
5
+ `,i);continue}g=f===0?b:`${g}
6
+ ${b}`,f++}else ae(l,i,_)?S=l.slice(l.charCodeAt(i+6)===T?i+7:i+6,c)||void 0:W(l,i,c);i=c+1,c=l.indexOf(`
7
+ `,i)}return l.slice(i)}for(;i<l.length;){let c=l.indexOf("\r",i),_=l.indexOf(`
8
+ `,i),y=-1;if(c!==-1&&_!==-1?y=c<_?c:_:c!==-1?c===l.length-1?y=-1:y=c:_!==-1&&(y=_),y===-1)break;W(l,i,y),i=y+1,l.charCodeAt(i-1)===be&&l.charCodeAt(i)===oe&&i++}return l.slice(i)}function W(l,i,c){if(i===c){de();return}let _=l.charCodeAt(i);if(ie(l,i,_)){let x=l.charCodeAt(i+5)===T?i+6:i+5,ee=l.slice(x,c);g=f===0?ee:`${g}
9
+ ${ee}`,f++;return}if(ae(l,i,_)){S=l.slice(l.charCodeAt(i+6)===T?i+7:i+6,c)||void 0;return}if(_===105&&l.charCodeAt(i+1)===100&&l.charCodeAt(i+2)===58){let x=l.slice(l.charCodeAt(i+3)===T?i+4:i+3,c);R=x.includes("\0")?void 0:x;return}if(_===58){if(s){let x=l.slice(i,c);s(x.slice(l.charCodeAt(i+1)===T?2:1))}return}let y=l.slice(i,c),b=y.indexOf(":");if(b===-1){Z(y,"",y);return}let pe=y.slice(0,b),he=y.charCodeAt(b+1)===T?2:1,fe=y.slice(b+he);Z(pe,fe,y)}function Z(l,i,c){switch(l){case"event":S=i||void 0;break;case"data":g=f===0?i:`${g}
10
+ ${i}`,f++;break;case"id":R=i.includes("\0")?void 0:i;break;case"retry":/^\d+$/.test(i)?r(parseInt(i,10)):t(new I(`Invalid \`retry\` value: "${i}"`,{type:"invalid-retry",value:i,line:c}));break;default:t(new I(`Unknown field "${l.length>20?`${l.slice(0,20)}\u2026`:l}"`,{type:"unknown-field",field:l,value:i,line:c}));break}}function de(){f>0&&e({id:R,event:S,data:g}),R=void 0,g="",f=0,S=void 0}function me(l={}){if(l.consume&&a.length>0){let i=a.join("");W(i,0,i.length)}u=!0,R=void 0,g="",f=0,S=void 0,a.length=0,d=0,w=!1}return{feed:Q,reset:me}}function ie(n,e,t){return t===100&&n.charCodeAt(e+1)===97&&n.charCodeAt(e+2)===116&&n.charCodeAt(e+3)===97&&n.charCodeAt(e+4)===58}function ae(n,e,t){return t===101&&n.charCodeAt(e+1)===118&&n.charCodeAt(e+2)===101&&n.charCodeAt(e+3)===110&&n.charCodeAt(e+4)===116&&n.charCodeAt(e+5)===58}var N=0,ve=5,Te=16*1024*1024,ue=3e4,xe=3e3;function Ee(n,e){let t=Math.max(e,Math.min(1e3*2**n,ue)),r=Math.max(e,t/2);return r+Math.random()*(t-r)}function V(n){n.body&&!n.body.locked&&n.body.cancel().catch(()=>{})}var $=class{_opts;_abort=null;_closed=!1;_started=!1;_counted=!1;_lastEventId=null;_retryFloorMs=0;_wake=null;onEvent=null;onStatus=null;onError=null;constructor(e){this._opts=e}connect(){if(!(this._closed||this._started)){if(this._started=!0,!this._opts.fetch&&typeof fetch>"u")throw new Error("[wavehouse] global fetch is not available in this environment. Upgrade to Node 22+ or supply one via `options.fetch`.");N++,this._counted=!0,N>ve&&console.warn(`[wavehouse] ${N} SSE connections open. Browsers limit HTTP/1.1 to 6 connections per domain.`),this._run().catch(e=>{this._emitError({status:0,code:"SSE_CONNECT_ERROR",message:e instanceof Error?e.message:String(e),retryable:!1}),this.disconnect()})}}disconnect(){if(!this._closed){this._closed=!0,this._abort?.abort(),this._abort=null,this._wake?.(),this._counted&&(N=Math.max(0,N-1),this._counted=!1);try{this.onStatus?.("closed")}catch(e){console.error("[wavehouse] SSE status handler threw:",e)}}}async _run(){await Promise.resolve();let e=0;for(;!this._closed;){let{liveMs:t,terminal:r}=await this._attempt();if(this._closed)return;if(r){this.disconnect();return}t>=xe&&(e=0),this._emitStatus("reconnecting"),await this._sleep(Ee(e,this._retryFloorMs)),e++}}async _attempt(){let e=new AbortController;this._abort=e;let t;try{t=this._url()}catch(u){return this._emitError({status:0,code:"SSE_CONNECT_ERROR",message:u instanceof Error?u.message:String(u),retryable:!1}),{liveMs:0,terminal:!0}}let r;try{r=await this._init(e.signal)}catch(u){return this._closed?{liveMs:0,terminal:!0}:(this._emitError({status:0,code:"SSE_AUTH_ERROR",message:u instanceof Error?u.message:String(u),retryable:!0}),{liveMs:0,terminal:!1})}let s;try{let u=this._opts.fetch;s=u?await u(t,r):await fetch(t,r)}catch(u){return this._closed?{liveMs:0,terminal:!0}:(this._emitError({status:0,code:"SSE_NETWORK_ERROR",message:u instanceof Error?u.message:String(u),retryable:!0}),{liveMs:0,terminal:!1})}if(s.type==="opaqueredirect"||s.status>=300&&s.status<400)return this._emitError({status:s.status,code:"SSE_REDIRECT",message:"The stream endpoint redirected and the SDK did not follow it. Redirects are refused when the request carries a credential \u2014 an `auth` token or configured `headers` \u2014 because a cross-origin hop strips the Authorization header, and this endpoint answers an unauthenticated caller with a reduced view instead of an error, while forwarding any configured headers to wherever the redirect points. If this request carries neither, `fetch` was left to follow the redirect itself, so arriving here means a response it will not follow (a 304, or a 3xx with no Location header) or an `options.fetch` that returned the redirect verbatim. Either way, set `baseURL` to the final URL; most often this is an http\u2192https upgrade or a canonical-host redirect at a proxy. To follow a credentialed redirect anyway, supply an `options.fetch` that overrides `redirect`.",retryable:!1}),V(s),{liveMs:0,terminal:!0};if(!s.ok){let u=await F(s);return this._emitError(u),{liveMs:0,terminal:!u.retryable}}let o=s.headers.get("content-type")??"";if(!o.toLowerCase().split(";")[0].trim().startsWith("text/event-stream"))return this._emitError({status:s.status,code:"SSE_BAD_CONTENT_TYPE",message:`Expected \`text/event-stream\`, got \`${o||"(none)"}\`. Something between the client and WaveHouse answered this request \u2014 an auth gateway's login page is the usual cause.`,retryable:!1}),V(s),{liveMs:0,terminal:!0};let a=s.body;if(!a||typeof a.getReader!="function"||a.locked||s.bodyUsed)return this._emitError({status:s.status,code:"SSE_NO_STREAM_BODY",message:"Streaming requires a response with a readable body. The configured `options.fetch` returned one whose body is absent or already read \u2014 an implementation that buffers or consumes the response cannot be used for `.stream()` or `.liveQuery()`.",retryable:!1}),V(s),{liveMs:0,terminal:!0};this._emitStatus("live");let d=Date.now();return await this._pump(a),{liveMs:Date.now()-d,terminal:!1}}_url(){let e=j(this._opts.baseURL,"/v1/stream");if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`baseURL must use http or https, got "${e.protocol}". Streaming is plain HTTP \u2014 there is no WebSocket endpoint.`);return e.searchParams.set("table",this._opts.table),this._opts.since&&e.searchParams.set("since",this._opts.since),e.toString()}async _init(e){let t={Accept:"text/event-stream"};if(this._opts.auth){let o=await this._opts.auth();o&&(t.Authorization=`Bearer ${o}`)}this._lastEventId&&(t["Last-Event-ID"]=this._lastEventId);let r=t.Authorization!==void 0||Object.keys(this._opts.headers??{}).length>0,s={...this._opts.fetchOptions,method:"GET",headers:G(t,this._opts.headers),signal:e,cache:"no-store",redirect:r?"manual":"follow",body:void 0};return"window"in globalThis||delete s.credentials,s}async _pump(e){let t=!1,r=le({onEvent:a=>{a.id&&(this._lastEventId=a.id),a.data&&this._dispatch(a.data)},onRetry:a=>{this._retryFloorMs=Math.min(Math.max(a,0),ue)},onError:a=>{a.type==="max-buffer-size-exceeded"&&(t=!0),this._emitError({status:0,code:"SSE_PARSE_ERROR",message:a.message,retryable:!0})},maxBufferSize:Te}),s=e.getReader(),o=new TextDecoder;try{for(;;){let{done:a,value:d}=await s.read();if(a||(r.feed(o.decode(d,{stream:!0})),t))return}}catch(a){if(this._closed)return;this._emitError({status:0,code:"SSE_READ_ERROR",message:a instanceof Error?a.message:String(a),retryable:!0})}finally{s.cancel().catch(()=>{})}}_dispatch(e){if(this._closed)return;let t;try{let r=JSON.parse(e);t={table:r.table_name,timestamp:r.received_timestamp,data:r.data}}catch{console.warn("[wavehouse] SSE received malformed message:",e);return}try{this.onEvent?.(t)}catch(r){console.error("[wavehouse] SSE event handler threw:",r)}}_emitError(e){if(!this._closed)try{this.onError?.(e)}catch(t){console.error("[wavehouse] SSE error handler threw:",t)}}_emitStatus(e){if(!this._closed)try{this.onStatus?.(e)}catch(t){console.error("[wavehouse] SSE status handler threw:",t)}}_sleep(e){return this._closed?Promise.resolve():new Promise(t=>{let r=setTimeout(()=>{this._wake=null,t()},e);this._wake=()=>{clearTimeout(r),this._wake=null,t()}})}};var B=class{_ctx;constructor(e){this._ctx=e}async health(e){let{error:t}=await p(this._ctx,{method:"GET",path:"/v1/health",signal:e?.signal});return t?m(t):h(void 0)}};var D=class{_stream;_subscriber;_buffer=[];_buffering=!0;_unsubStream=null;_closed=!1;constructor(e,t,r,s){this._stream=e,this._subscriber=r,this._unsubStream=e.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(t)}async _runBackfill(e){try{let t=await e();if(this._closed)return;if(this._subscriber.initial?.(t),t.error){this._buffering=!1;return}let r=t.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 Ce={"=":"eq","!=":"neq",">":"gt",">=":"gte","<":"lt","<=":"lte",in:"in",like:"like",not_like:"not_like"},k=class n{_state;_ctx;_createStream;constructor(e,t,r){this._ctx=e,this._state=Object.freeze({...t}),this._createStream=r}select(...e){return this._clone({columns:[...this._state.columns,...e]})}selectAll(){return this._clone({selectAll:!0})}where(e,t,r){let s={column:e,op:Ce[t],value:r};return this._clone({filters:[...this._state.filters,s]})}count(e="*",t="count"){return this._addAgg("count",e,t)}sum(e,t=`sum_${e}`){return this._addAgg("sum",e,t)}avg(e,t=`avg_${e}`){return this._addAgg("avg",e,t)}min(e,t=`min_${e}`){return this._addAgg("min",e,t)}max(e,t=`max_${e}`){return this._addAgg("max",e,t)}countDistinct(e,t=`count_distinct_${e}`){return this._addAgg("countDistinct",e,t)}aggregate(e,t,r){return this._addAgg(e,t,r)}groupBy(...e){return this._clone({groupBy:[...this._state.groupBy,...e]})}orderBy(e,t="asc"){return this._clone({orderBy:[...this._state.orderBy,{column:e,dir:t}]})}limit(e){return this._clone({limit:e})}timeRange(e,t,r){return this._clone({timeRange:{column:e,since:t,until:r}})}cacheTTL(e){return this._clone({cacheTTL:e})}static DEFAULT_LIMIT=1e3;async fetch(e){let t=e?.limit??this._state.limit??n.DEFAULT_LIMIT,r=this._buildAST(t),{data:s,error:o}=await p(this._ctx,{method:"POST",path:`/v1/query?table=${encodeURIComponent(this._state.table)}`,body:r,signal:e?.signal});if(o)return m(o);let a=s,d=t!=null&&a.length>=t;return d&&this._state.orderBy.length>0?L(a,!0,()=>this._fetchNext(a,t,e)):L(a,d)}stream(e){let t=this._createStream(this._state.table,e),r=this._state.filters,s=this._state.columns;return r.length===0&&s.length===0?t:new Y(t,r,s)}liveQuery(e,t){let r=this.stream(t),s=()=>this.fetch();return new D(r,s,e,this._state.filters)}then(e,t){return this.fetch().then(e,t)}_clone(e){return new n(this._ctx,{...this._state,...e},this._createStream)}_addAgg(e,t,r){let s={fn:e,column:t,alias:r};return this._clone({aggregations:[...this._state.aggregations,s]})}_buildAST(e){let t={},r=this._state.columns.length>0,s=this._state.aggregations.length>0;return this._state.selectAll?t.select_all=!0:r?t.columns=this._state.columns:s||(t.select_all=!0),s&&(t.aggregations=this._state.aggregations),this._state.filters.length>0&&(t.filters=this._state.filters),this._state.groupBy.length>0&&(t.group_by=this._state.groupBy),this._state.orderBy.length>0&&(t.order_by=this._state.orderBy),e!=null&&(t.limit=e),this._state.timeRange&&(t.time_range=this._state.timeRange),t}async _fetchNext(e,t,r){let s=this._state.orderBy[0];if(s==null)return L([],!1);let{column:o,dir:a}=s,u=e[e.length-1]?.[o];if(u===void 0)return L([],!1);let g={column:o,op:a==="desc"?"lt":"gt",value:u};return this._clone({filters:[...this._state.filters,g],orderBy:this._state.orderBy}).fetch(r)}},Y=class extends v{constructor(e,t,r){let s={onEvent:null,onStatus:null,onError:null,connect(){e.subscribe({next:o=>{if(!Ae(o.data,t))return;let a=r.length>0?{...o,data:Oe(o.data,r)}:o;this.onEvent?.(a)},status:o=>this.onStatus?.(o),error:o=>this.onError?.(o)})},disconnect(){e.close()}};super(s)}};function Ae(n,e){for(let t of e){let r=n[t.column];if(!Pe(r,t.op,t.value))return!1}return!0}function Pe(n,e,t){switch(e){case"eq":return n===t;case"neq":return n!==t;case"gt":return U(n,t,(r,s)=>r>s);case"gte":return U(n,t,(r,s)=>r>=s);case"lt":return U(n,t,(r,s)=>r<s);case"lte":return U(n,t,(r,s)=>r<=s);case"in":return Array.isArray(t)&&t.includes(n);case"like":{if(typeof n!="string"||typeof t!="string")return!1;let s=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return new RegExp(`^${s}$`,"i").test(n)}case"not_like":{if(typeof n!="string"||typeof t!="string")return!1;let s=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,".");return!new RegExp(`^${s}$`,"i").test(n)}default:return!0}}function U(n,e,t){return typeof n=="number"&&typeof e=="number"||typeof n=="string"&&typeof e=="string"?t(n,e):!1}function Oe(n,e){let t={};for(let r of e)r in n&&(t[r]=n[r]);return t}var Be="application/x-ndjson";async function De(n){return typeof n=="string"?n:n instanceof Uint8Array?new TextDecoder().decode(n):new Response(n).text()}var H=class{_ctx;_table;_createStream;constructor(e,t,r){this._ctx=e,this._table=t,this._createStream=r}async fetch(e){return this.select().limit(e?.limit??1e3).fetch(e)}select(...e){return new k(this._ctx,{table:this._table,columns:e,aggregations:[],filters:[],groupBy:[],orderBy:[]},this._createStream)}selectAll(){return this.select().selectAll()}async insert(e,t){if(Array.isArray(e)){if(e.length===0)return h({ok:!0,total:0,succeeded:0,failed:0,duplicates:0,results:[]});let a=e.map(d=>JSON.stringify(d)).join(`
11
+ `);return this._sendNDJSON(a,t)}let{data:r,error:s}=await p(this._ctx,{method:"POST",path:`/v1/ingest?table=${encodeURIComponent(this._table)}`,body:e,signal:t?.signal});if(s)return m(s);let o={ok:r?.ok??!0};return r?.duplicate!=null&&(o.duplicate=r.duplicate),h(o)}async insertNDJSON(e,t){let r=await De(e);return this._sendNDJSON(r,t)}async _sendNDJSON(e,t){let{data:r,error:s}=await p(this._ctx,{method:"POST",path:`/v1/ingest?table=${encodeURIComponent(this._table)}`,rawBody:e,contentType:Be,signal:t?.signal});if(s)return m(s);let o=r??{total:0,succeeded:0,failed:0,duplicates:0},a={ok:o.failed===0,total:o.total,succeeded:o.succeeded,failed:o.failed,duplicates:o.duplicates};return o.results&&o.results.length>0&&(a.results=o.results),h(a)}async schema(e){let{data:t,error:r}=await p(this._ctx,{method:"GET",path:`/v1/ops/schema?table=${encodeURIComponent(this._table)}`,signal:e?.signal});return r?m(r):h(t)}stream(e){return this._createStream(this._table,e)}};var q=class{_ctx;schema;policy;dlq;sys;pipes;constructor(e){this._ctx={baseURL:e.baseURL.replace(/\/+$/,""),auth:e.auth,options:{maxRetries:e.options?.maxRetries??2,fetch:e.options?.fetch,headers:e.options?.headers,fetchOptions:e.options?.fetchOptions}},this.schema=new O(this._ctx),this.policy=new P(this._ctx),this.dlq=new E(this._ctx,(t,r)=>this._createStream(t,r)),this.sys=new B(this._ctx),this.pipes=new A(this._ctx)}from(e){return new H(this._ctx,e,(t,r)=>this._createStream(t,r))}pipe(e,t){return new C(this._ctx,e,t,(r,s)=>this._createStream(r,s))}sql(e,t){if(Array.isArray(t))throw new Error("[WaveHouse SDK] client.sql(sql, params) was removed. The /v1/ops/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 ne(this._ctx,e,t)}_createStream(e,t){let r=new $({baseURL:this._ctx.baseURL,table:e,since:t?.since,auth:this._ctx.auth,fetch:this._ctx.options.fetch,headers:this._ctx.options.headers,fetchOptions:this._ctx.options.fetchOptions}),s=new v(r);return t?.signal&&s.attachSignal(t.signal),s}};function ce(n){return new q(n)}return we(ke);})();
12
+ //# sourceMappingURL=index.global.js.map