@ragable/sdk 0.6.12 → 0.6.14
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.mts +55 -2
- package/dist/index.d.ts +55 -2
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +102 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1457,6 +1457,13 @@ var PostgrestTableApi = class {
|
|
|
1457
1457
|
this.databaseInstanceId = databaseInstanceId;
|
|
1458
1458
|
this.table = table;
|
|
1459
1459
|
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Start a SELECT. Pass a PostgREST `select` string; use embedded resources for joins — see
|
|
1462
|
+
* {@link PostgrestSelectBuilder}.
|
|
1463
|
+
*
|
|
1464
|
+
* @param columns Column list and optional embeds (default `"*"`). Omitted or `"*"` means all base columns.
|
|
1465
|
+
* @typeParam RowResult Row shape returned by the query; defaults to this table’s `Row`. Override when using joins.
|
|
1466
|
+
*/
|
|
1460
1467
|
select(columns = "*") {
|
|
1461
1468
|
return new PostgrestSelectBuilder(
|
|
1462
1469
|
this.pgFetch,
|
|
@@ -2287,6 +2294,18 @@ var RagableBrowserDatabaseClient = class {
|
|
|
2287
2294
|
return payload;
|
|
2288
2295
|
});
|
|
2289
2296
|
});
|
|
2297
|
+
/**
|
|
2298
|
+
* Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
|
|
2299
|
+
* Channels must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
|
|
2300
|
+
*/
|
|
2301
|
+
__publicField(this, "realtime", {
|
|
2302
|
+
subscribe: (params) => subscribeBrowserRealtime(
|
|
2303
|
+
this.options,
|
|
2304
|
+
this.ragableAuth,
|
|
2305
|
+
this.fetchImpl,
|
|
2306
|
+
params
|
|
2307
|
+
)
|
|
2308
|
+
});
|
|
2290
2309
|
this.fetchImpl = bindFetch(options.fetch);
|
|
2291
2310
|
}
|
|
2292
2311
|
/** @internal Called by RagableBrowser to share the Transport instance. */
|
|
@@ -2300,6 +2319,89 @@ var RagableBrowserDatabaseClient = class {
|
|
|
2300
2319
|
return new Headers(this.options.headers);
|
|
2301
2320
|
}
|
|
2302
2321
|
};
|
|
2322
|
+
function followAbortSignal(parent, child) {
|
|
2323
|
+
if (!parent) return;
|
|
2324
|
+
if (parent.aborted) {
|
|
2325
|
+
child.abort();
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
parent.addEventListener("abort", () => child.abort(), { once: true });
|
|
2329
|
+
}
|
|
2330
|
+
async function subscribeBrowserRealtime(options, ragableAuth, fetchImpl, params) {
|
|
2331
|
+
const gid = requireAuthGroupId(options);
|
|
2332
|
+
const token = await resolveDatabaseAuthBearer(options, ragableAuth);
|
|
2333
|
+
const databaseInstanceId = params.databaseInstanceId?.trim() || options.databaseInstanceId?.trim();
|
|
2334
|
+
if (!databaseInstanceId) {
|
|
2335
|
+
throw new RagableError(
|
|
2336
|
+
"realtime.subscribe requires databaseInstanceId in params or on createBrowserClient({ databaseInstanceId })",
|
|
2337
|
+
400,
|
|
2338
|
+
{ code: "SDK_MISSING_DATABASE_INSTANCE_ID" }
|
|
2339
|
+
);
|
|
2340
|
+
}
|
|
2341
|
+
if (!Array.isArray(params.channels) || params.channels.length === 0) {
|
|
2342
|
+
throw new RagableError(
|
|
2343
|
+
"realtime.subscribe requires a non-empty channels array",
|
|
2344
|
+
400,
|
|
2345
|
+
{ code: "SDK_REALTIME_CHANNELS_REQUIRED" }
|
|
2346
|
+
);
|
|
2347
|
+
}
|
|
2348
|
+
const ac = new AbortController();
|
|
2349
|
+
followAbortSignal(params.signal, ac);
|
|
2350
|
+
const headers = new Headers(options.headers);
|
|
2351
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
2352
|
+
headers.set("Content-Type", "application/json");
|
|
2353
|
+
const response = await fetchImpl(
|
|
2354
|
+
`${normalizeBrowserApiBase()}/auth-groups/${gid}/data/realtime/stream`,
|
|
2355
|
+
{
|
|
2356
|
+
method: "POST",
|
|
2357
|
+
headers,
|
|
2358
|
+
body: JSON.stringify({
|
|
2359
|
+
databaseInstanceId,
|
|
2360
|
+
channels: params.channels
|
|
2361
|
+
}),
|
|
2362
|
+
signal: ac.signal
|
|
2363
|
+
}
|
|
2364
|
+
);
|
|
2365
|
+
const payload = await parseMaybeJsonBody(response);
|
|
2366
|
+
if (!response.ok) {
|
|
2367
|
+
const message = extractErrorMessage(payload, response.statusText);
|
|
2368
|
+
throw new RagableError(message, response.status, payload);
|
|
2369
|
+
}
|
|
2370
|
+
const streamBody = response.body;
|
|
2371
|
+
if (!streamBody) {
|
|
2372
|
+
throw new RagableError(
|
|
2373
|
+
"Realtime stream has no body",
|
|
2374
|
+
502,
|
|
2375
|
+
{ code: "SDK_REALTIME_NO_BODY" }
|
|
2376
|
+
);
|
|
2377
|
+
}
|
|
2378
|
+
void (async () => {
|
|
2379
|
+
try {
|
|
2380
|
+
for await (const evt of readSseStream(streamBody)) {
|
|
2381
|
+
if (evt.type === "realtime:ready") {
|
|
2382
|
+
const ch = evt.channels;
|
|
2383
|
+
params.onReady?.(
|
|
2384
|
+
Array.isArray(ch) ? ch.map((c) => String(c)) : []
|
|
2385
|
+
);
|
|
2386
|
+
} else if (evt.type === "notify") {
|
|
2387
|
+
params.onNotify?.({
|
|
2388
|
+
channel: String(evt.channel ?? ""),
|
|
2389
|
+
payload: evt.payload === void 0 || evt.payload === null ? null : String(evt.payload),
|
|
2390
|
+
processId: Number(evt.processId ?? 0)
|
|
2391
|
+
});
|
|
2392
|
+
} else if (evt.type === "realtime:error") {
|
|
2393
|
+
params.onError?.(String(evt.message ?? "Realtime error"));
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
} catch (e) {
|
|
2397
|
+
if (e.name === "AbortError") return;
|
|
2398
|
+
params.onError?.(e.message);
|
|
2399
|
+
}
|
|
2400
|
+
})();
|
|
2401
|
+
return {
|
|
2402
|
+
unsubscribe: () => ac.abort()
|
|
2403
|
+
};
|
|
2404
|
+
}
|
|
2303
2405
|
var RagableBrowserAgentsClient = class {
|
|
2304
2406
|
constructor(options) {
|
|
2305
2407
|
this.options = options;
|