@wavehouse/sdk 0.0.0-dev.h70dbf5d8f5ed → 0.0.0-dev.h7362ab3863f6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/index.cjs +359 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -23
- package/dist/index.d.ts +74 -23
- package/dist/index.global.js +11 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +359 -59
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +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
|
|
5
|
-
* the server returns
|
|
6
|
-
*
|
|
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.
|
|
7
13
|
*
|
|
8
14
|
* Discriminated on `ok`: `if (result.ok)` narrows to the success arm (and tells
|
|
9
15
|
* the compiler `data` is present), while `error` is always available for
|
|
@@ -75,25 +81,43 @@ interface ClientConfig<_DB extends Database = Database> {
|
|
|
75
81
|
* depending on whether the consumer's TypeScript `lib` includes DOM — the same
|
|
76
82
|
* signature either way, but stable across configurations.
|
|
77
83
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
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.
|
|
85
109
|
*
|
|
86
110
|
* Implementations shipping their own request/response declarations (undici,
|
|
87
|
-
* `node-fetch`) need casts on the
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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.
|
|
90
114
|
*/
|
|
91
|
-
type FetchLike = (input: string
|
|
115
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
92
116
|
interface ClientOptions {
|
|
93
117
|
/** Maximum retry attempts for failed requests. Default: 2. */
|
|
94
118
|
maxRetries?: number;
|
|
95
119
|
/**
|
|
96
|
-
* HTTP implementation used for every REST
|
|
120
|
+
* HTTP implementation used for every request, REST and streaming alike.
|
|
97
121
|
* Defaults to the global `fetch`.
|
|
98
122
|
*
|
|
99
123
|
* Provide one to route through a proxy, attach client certificates, add
|
|
@@ -112,19 +136,18 @@ interface ClientOptions {
|
|
|
112
136
|
* baseURL,
|
|
113
137
|
* options: {
|
|
114
138
|
* fetch: (url, init) =>
|
|
115
|
-
* undiciFetch(url
|
|
139
|
+
* undiciFetch(url, { ...init, dispatcher } as never) as unknown as Promise<Response>,
|
|
116
140
|
* },
|
|
117
141
|
* });
|
|
118
142
|
* ```
|
|
119
143
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* through your function.
|
|
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.
|
|
124
147
|
*/
|
|
125
148
|
fetch?: FetchLike;
|
|
126
149
|
/**
|
|
127
|
-
* Headers added to every REST
|
|
150
|
+
* Headers added to every request, REST and streaming alike — for a
|
|
128
151
|
* header-gated proxy in front of WaveHouse, such as a Cloudflare Access
|
|
129
152
|
* service token.
|
|
130
153
|
*
|
|
@@ -133,16 +156,44 @@ interface ClientOptions {
|
|
|
133
156
|
* `Content-Type` and `Accept` a given request needs are not overridable
|
|
134
157
|
* here — a global `Content-Type` that outranked the request's own is a
|
|
135
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.
|
|
136
165
|
*/
|
|
137
166
|
headers?: Record<string, string>;
|
|
138
167
|
/**
|
|
139
|
-
* Extra `RequestInit` fields merged into every
|
|
140
|
-
*
|
|
168
|
+
* Extra `RequestInit` fields merged into every request — `credentials` for a
|
|
169
|
+
* cookie-authenticated origin, `mode`, `cache`, `keepalive`, or a
|
|
141
170
|
* runtime-specific extension such as Next.js's `next: { tags }`.
|
|
142
171
|
*
|
|
143
172
|
* Fields the SDK controls (`method`, `headers`, `body`, `signal`) always
|
|
144
173
|
* win, so this cannot corrupt the request itself. Non-standard fields may
|
|
145
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.
|
|
146
197
|
*/
|
|
147
198
|
fetchOptions?: RequestInit;
|
|
148
199
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +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
|
|
5
|
-
* the server returns
|
|
6
|
-
*
|
|
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.
|
|
7
13
|
*
|
|
8
14
|
* Discriminated on `ok`: `if (result.ok)` narrows to the success arm (and tells
|
|
9
15
|
* the compiler `data` is present), while `error` is always available for
|
|
@@ -75,25 +81,43 @@ interface ClientConfig<_DB extends Database = Database> {
|
|
|
75
81
|
* depending on whether the consumer's TypeScript `lib` includes DOM — the same
|
|
76
82
|
* signature either way, but stable across configurations.
|
|
77
83
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
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.
|
|
85
109
|
*
|
|
86
110
|
* Implementations shipping their own request/response declarations (undici,
|
|
87
|
-
* `node-fetch`) need casts on the
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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.
|
|
90
114
|
*/
|
|
91
|
-
type FetchLike = (input: string
|
|
115
|
+
type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
92
116
|
interface ClientOptions {
|
|
93
117
|
/** Maximum retry attempts for failed requests. Default: 2. */
|
|
94
118
|
maxRetries?: number;
|
|
95
119
|
/**
|
|
96
|
-
* HTTP implementation used for every REST
|
|
120
|
+
* HTTP implementation used for every request, REST and streaming alike.
|
|
97
121
|
* Defaults to the global `fetch`.
|
|
98
122
|
*
|
|
99
123
|
* Provide one to route through a proxy, attach client certificates, add
|
|
@@ -112,19 +136,18 @@ interface ClientOptions {
|
|
|
112
136
|
* baseURL,
|
|
113
137
|
* options: {
|
|
114
138
|
* fetch: (url, init) =>
|
|
115
|
-
* undiciFetch(url
|
|
139
|
+
* undiciFetch(url, { ...init, dispatcher } as never) as unknown as Promise<Response>,
|
|
116
140
|
* },
|
|
117
141
|
* });
|
|
118
142
|
* ```
|
|
119
143
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* through your function.
|
|
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.
|
|
124
147
|
*/
|
|
125
148
|
fetch?: FetchLike;
|
|
126
149
|
/**
|
|
127
|
-
* Headers added to every REST
|
|
150
|
+
* Headers added to every request, REST and streaming alike — for a
|
|
128
151
|
* header-gated proxy in front of WaveHouse, such as a Cloudflare Access
|
|
129
152
|
* service token.
|
|
130
153
|
*
|
|
@@ -133,16 +156,44 @@ interface ClientOptions {
|
|
|
133
156
|
* `Content-Type` and `Accept` a given request needs are not overridable
|
|
134
157
|
* here — a global `Content-Type` that outranked the request's own is a
|
|
135
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.
|
|
136
165
|
*/
|
|
137
166
|
headers?: Record<string, string>;
|
|
138
167
|
/**
|
|
139
|
-
* Extra `RequestInit` fields merged into every
|
|
140
|
-
*
|
|
168
|
+
* Extra `RequestInit` fields merged into every request — `credentials` for a
|
|
169
|
+
* cookie-authenticated origin, `mode`, `cache`, `keepalive`, or a
|
|
141
170
|
* runtime-specific extension such as Next.js's `next: { tags }`.
|
|
142
171
|
*
|
|
143
172
|
* Fields the SDK controls (`method`, `headers`, `body`, `signal`) always
|
|
144
173
|
* win, so this cannot corrupt the request itself. Non-standard fields may
|
|
145
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.
|
|
146
197
|
*/
|
|
147
198
|
fetchOptions?: RequestInit;
|
|
148
199
|
}
|
package/dist/index.global.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
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:()=>d,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,p=C?await C(e,h):await fetch(e,h);if(p.ok){let T=await p.text();return{data:T?JSON.parse(T):void 0,error:null,headers:p.headers}}let k=await L(p);if(p.status===503){let T=p.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:p.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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/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/ops/query",body:{sql:t},signal:e?.signal});return s?a(s):u(r)}var d=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 d{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
|
-
`)
|
|
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);x.includes("\0")||(R=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":i.includes("\0")||(R=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);})();
|
|
3
12
|
//# sourceMappingURL=index.global.js.map
|