@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.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;