@ragable/sdk 0.6.13 → 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 +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +95 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2294,6 +2294,18 @@ var RagableBrowserDatabaseClient = class {
|
|
|
2294
2294
|
return payload;
|
|
2295
2295
|
});
|
|
2296
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
|
+
});
|
|
2297
2309
|
this.fetchImpl = bindFetch(options.fetch);
|
|
2298
2310
|
}
|
|
2299
2311
|
/** @internal Called by RagableBrowser to share the Transport instance. */
|
|
@@ -2307,6 +2319,89 @@ var RagableBrowserDatabaseClient = class {
|
|
|
2307
2319
|
return new Headers(this.options.headers);
|
|
2308
2320
|
}
|
|
2309
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
|
+
}
|
|
2310
2405
|
var RagableBrowserAgentsClient = class {
|
|
2311
2406
|
constructor(options) {
|
|
2312
2407
|
this.options = options;
|