@ragable/sdk 0.6.13 → 0.6.15

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 CHANGED
@@ -943,6 +943,90 @@ declare class RagableBrowserDatabaseClient<Database extends RagableDatabase = De
943
943
  private toUrl;
944
944
  query: <Row extends Record<string, unknown> = Record<string, unknown>>(params: BrowserSqlQueryParams) => Promise<PostgrestResult<BrowserSqlQueryResult<Row>>>;
945
945
  private baseHeaders;
946
+ /**
947
+ * Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
948
+ * Channels must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
949
+ */
950
+ /**
951
+ * Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
952
+ *
953
+ * Returns a `BrowserRealtimeSubscription` with:
954
+ * - `unsubscribe()` — permanently close the subscription (stops reconnects).
955
+ * - `status` — current connection state: `"connecting"` | `"connected"` | `"reconnecting"` | `"disconnected"`.
956
+ *
957
+ * The subscription automatically reconnects with exponential backoff when the
958
+ * stream drops. Server heartbeats (every 15 s) are monitored — if none arrive
959
+ * within `heartbeatTimeoutMs` (default 45 s), the connection is treated as dead
960
+ * and a reconnect is triggered. Auth errors (401/403/404) are non-retryable.
961
+ *
962
+ * Channel names must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
963
+ */
964
+ realtime: {
965
+ subscribe: (params: BrowserRealtimeSubscribeParams) => Promise<BrowserRealtimeSubscription>;
966
+ };
967
+ }
968
+ /**
969
+ * A single NOTIFY message received from a Postgres channel.
970
+ *
971
+ * - `channel` — the lowercase channel name that fired.
972
+ * - `payload` — the text payload (may be null if NOTIFY was sent without one).
973
+ * - `processId` — the PID of the Postgres backend that called NOTIFY.
974
+ */
975
+ interface BrowserRealtimeNotification {
976
+ channel: string;
977
+ payload: string | null;
978
+ processId: number;
979
+ }
980
+ /**
981
+ * Connection status of a realtime subscription.
982
+ *
983
+ * - `"connecting"` — establishing or re-establishing the SSE stream.
984
+ * - `"connected"` — stream is open, heartbeats are arriving, NOTIFY events are flowing.
985
+ * - `"reconnecting"` — the stream dropped and the SDK is waiting before the next retry.
986
+ * - `"disconnected"` — permanently stopped (via `unsubscribe()`, `signal` abort, or max retries exceeded).
987
+ */
988
+ type BrowserRealtimeStatus = "connecting" | "connected" | "reconnecting" | "disconnected";
989
+ interface BrowserRealtimeSubscribeParams {
990
+ databaseInstanceId?: string;
991
+ /** Channel names (normalized to lowercase on the server). */
992
+ channels: string[];
993
+ /** When aborted, the subscription stops permanently (equivalent to calling `unsubscribe()`). */
994
+ signal?: AbortSignal;
995
+ /** Called each time a Postgres NOTIFY message arrives. */
996
+ onNotify?: (msg: BrowserRealtimeNotification) => void;
997
+ /** Called once per connection attempt when the server confirms LISTEN is active. */
998
+ onReady?: (channels: string[]) => void;
999
+ /** Called when the stream encounters a non-retryable error or the server sends an error event. */
1000
+ onError?: (message: string) => void;
1001
+ /** Called whenever the connection status changes (connecting → connected → reconnecting → …). */
1002
+ onStatusChange?: (status: BrowserRealtimeStatus) => void;
1003
+ /** Called when the stream drops and the SDK will attempt to reconnect. `attempt` is 1-indexed. */
1004
+ onDisconnect?: (info: {
1005
+ attempt: number;
1006
+ retryInMs: number;
1007
+ }) => void;
1008
+ /** Called when a reconnect attempt succeeds (stream is open again). */
1009
+ onReconnect?: (info: {
1010
+ attempt: number;
1011
+ }) => void;
1012
+ /** Maximum number of reconnect attempts before giving up. Set `0` to disable reconnect. Default: **Infinity** (never stops). */
1013
+ maxReconnectAttempts?: number;
1014
+ /** Base delay for exponential backoff (ms). Default: **1000**. */
1015
+ reconnectBaseDelayMs?: number;
1016
+ /** Maximum delay between reconnect attempts (ms). Default: **30000**. */
1017
+ reconnectMaxDelayMs?: number;
1018
+ /** How long to wait without a heartbeat before considering the connection dead (ms). Default: **45000** (3× the server's 15 s heartbeat interval). */
1019
+ heartbeatTimeoutMs?: number;
1020
+ }
1021
+ /**
1022
+ * Handle returned by `database.realtime.subscribe()`.
1023
+ *
1024
+ * - Call `unsubscribe()` to permanently close the subscription (no more reconnects).
1025
+ * - Read `status` to check the current connection state at any time.
1026
+ */
1027
+ interface BrowserRealtimeSubscription {
1028
+ unsubscribe: () => void;
1029
+ readonly status: BrowserRealtimeStatus;
946
1030
  }
947
1031
  declare class RagableBrowserAgentsClient {
948
1032
  private readonly options;
@@ -1044,4 +1128,4 @@ declare function createClient(options: RagableClientOptions): Ragable;
1044
1128
  declare function createClient<Database extends RagableDatabase = DefaultRagableDatabase, AuthUser extends Record<string, unknown> = Record<string, unknown>>(options: RagableBrowserClientOptions): RagableBrowser<Database, AuthUser>;
1045
1129
  declare function createRagableServerClient(options: RagableClientOptions): Ragable;
1046
1130
 
1047
- export { type AgentChatMessage, type AgentChatParams, type AgentChatResult, type AgentPublicChatParams, type AgentStreamEvent, type AgentSummary, AgentsClient, AuthBroadcastChannel, type AuthBroadcastMessage, type AuthChangeEvent, type AuthOptions, type AuthSession, type BrowserAuthSession, type BrowserAuthTokens, type BrowserDataAuthMode, type BrowserSqlExecParams, type BrowserSqlExecResult, type BrowserSqlQueryParams, type BrowserSqlQueryResult, type ColumnName, type ColumnValue, CookieStorageAdapter, DEFAULT_RAGABLE_API_BASE, type DefaultRagableDatabase, type FormatContextOptions, type HttpMethod, type Json, LocalStorageAdapter, MemoryStorageAdapter, type PostgRESTFetch, type PostgRESTFetchParams, PostgrestDeleteReturningBuilder, PostgrestDeleteRootBuilder, PostgrestInsertReturningBuilder, PostgrestInsertRootBuilder, PostgrestInsertSdkErrorReturning, PostgrestInsertSdkErrorRoot, type PostgrestResult, PostgrestSelectBuilder, PostgrestTableApi, PostgrestUpdateReturningBuilder, PostgrestUpdateRootBuilder, type PostgrestUpsertOptions, PostgrestUpsertReturningBuilder, PostgrestUpsertRootBuilder, type RagClientForPipeline, type RagPipeline, type RagPipelineOptions, Ragable, RagableAbortError, RagableAuth, type RagableAuthConfig, RagableBrowser, RagableBrowserAgentsClient, RagableBrowserAuthClient, type RagableBrowserClientOptions, RagableBrowserDatabaseClient, type RagableClientOptions, type RagableDatabase, RagableError, RagableNetworkError, RagableRequestClient, RagableSdkError, type RagableTableDefinition, type RagableTableNames, RagableTimeoutError, type RequestOptions, type RetrieveParams, type RetryOptions, type RunQuery, type SessionStorage, SessionStorageAdapter, type ShiftAddDocumentParams, ShiftClient, type ShiftCreateIndexParams, type ShiftEntry, type ShiftIndex, type ShiftIngestResponse, type ShiftListEntriesParams, type ShiftListEntriesResponse, type ShiftSearchParams, type ShiftSearchResult, type ShiftUpdateIndexParams, type ShiftUploadFileParams, type ShiftUploadableFile, type SseJsonEvent, type SupabaseCompatSession, type TableInsertRow, type TableRow, type TableUpdatePatch, type Tables, type TablesInsert, type TablesUpdate, Transport, type TransportOptions, type TransportRequest, asPostgrestResponse, bindFetch, createBrowserClient, createClient, createRagPipeline, createRagableBrowserClient, createRagableServerClient, detectStorage, effectiveDataAuth, extractErrorMessage, formatPostgrestError, formatRetrievalContext, formatSdkError, generateIdempotencyKey, normalizeBrowserApiBase, parseSseDataLine, parseTransportResponse, readSseStream };
1131
+ export { type AgentChatMessage, type AgentChatParams, type AgentChatResult, type AgentPublicChatParams, type AgentStreamEvent, type AgentSummary, AgentsClient, AuthBroadcastChannel, type AuthBroadcastMessage, type AuthChangeEvent, type AuthOptions, type AuthSession, type BrowserAuthSession, type BrowserAuthTokens, type BrowserDataAuthMode, type BrowserRealtimeNotification, type BrowserRealtimeStatus, type BrowserRealtimeSubscribeParams, type BrowserRealtimeSubscription, type BrowserSqlExecParams, type BrowserSqlExecResult, type BrowserSqlQueryParams, type BrowserSqlQueryResult, type ColumnName, type ColumnValue, CookieStorageAdapter, DEFAULT_RAGABLE_API_BASE, type DefaultRagableDatabase, type FormatContextOptions, type HttpMethod, type Json, LocalStorageAdapter, MemoryStorageAdapter, type PostgRESTFetch, type PostgRESTFetchParams, PostgrestDeleteReturningBuilder, PostgrestDeleteRootBuilder, PostgrestInsertReturningBuilder, PostgrestInsertRootBuilder, PostgrestInsertSdkErrorReturning, PostgrestInsertSdkErrorRoot, type PostgrestResult, PostgrestSelectBuilder, PostgrestTableApi, PostgrestUpdateReturningBuilder, PostgrestUpdateRootBuilder, type PostgrestUpsertOptions, PostgrestUpsertReturningBuilder, PostgrestUpsertRootBuilder, type RagClientForPipeline, type RagPipeline, type RagPipelineOptions, Ragable, RagableAbortError, RagableAuth, type RagableAuthConfig, RagableBrowser, RagableBrowserAgentsClient, RagableBrowserAuthClient, type RagableBrowserClientOptions, RagableBrowserDatabaseClient, type RagableClientOptions, type RagableDatabase, RagableError, RagableNetworkError, RagableRequestClient, RagableSdkError, type RagableTableDefinition, type RagableTableNames, RagableTimeoutError, type RequestOptions, type RetrieveParams, type RetryOptions, type RunQuery, type SessionStorage, SessionStorageAdapter, type ShiftAddDocumentParams, ShiftClient, type ShiftCreateIndexParams, type ShiftEntry, type ShiftIndex, type ShiftIngestResponse, type ShiftListEntriesParams, type ShiftListEntriesResponse, type ShiftSearchParams, type ShiftSearchResult, type ShiftUpdateIndexParams, type ShiftUploadFileParams, type ShiftUploadableFile, type SseJsonEvent, type SupabaseCompatSession, type TableInsertRow, type TableRow, type TableUpdatePatch, type Tables, type TablesInsert, type TablesUpdate, Transport, type TransportOptions, type TransportRequest, asPostgrestResponse, bindFetch, createBrowserClient, createClient, createRagPipeline, createRagableBrowserClient, createRagableServerClient, detectStorage, effectiveDataAuth, extractErrorMessage, formatPostgrestError, formatRetrievalContext, formatSdkError, generateIdempotencyKey, normalizeBrowserApiBase, parseSseDataLine, parseTransportResponse, readSseStream };
package/dist/index.d.ts CHANGED
@@ -943,6 +943,90 @@ declare class RagableBrowserDatabaseClient<Database extends RagableDatabase = De
943
943
  private toUrl;
944
944
  query: <Row extends Record<string, unknown> = Record<string, unknown>>(params: BrowserSqlQueryParams) => Promise<PostgrestResult<BrowserSqlQueryResult<Row>>>;
945
945
  private baseHeaders;
946
+ /**
947
+ * Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
948
+ * Channels must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
949
+ */
950
+ /**
951
+ * Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
952
+ *
953
+ * Returns a `BrowserRealtimeSubscription` with:
954
+ * - `unsubscribe()` — permanently close the subscription (stops reconnects).
955
+ * - `status` — current connection state: `"connecting"` | `"connected"` | `"reconnecting"` | `"disconnected"`.
956
+ *
957
+ * The subscription automatically reconnects with exponential backoff when the
958
+ * stream drops. Server heartbeats (every 15 s) are monitored — if none arrive
959
+ * within `heartbeatTimeoutMs` (default 45 s), the connection is treated as dead
960
+ * and a reconnect is triggered. Auth errors (401/403/404) are non-retryable.
961
+ *
962
+ * Channel names must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
963
+ */
964
+ realtime: {
965
+ subscribe: (params: BrowserRealtimeSubscribeParams) => Promise<BrowserRealtimeSubscription>;
966
+ };
967
+ }
968
+ /**
969
+ * A single NOTIFY message received from a Postgres channel.
970
+ *
971
+ * - `channel` — the lowercase channel name that fired.
972
+ * - `payload` — the text payload (may be null if NOTIFY was sent without one).
973
+ * - `processId` — the PID of the Postgres backend that called NOTIFY.
974
+ */
975
+ interface BrowserRealtimeNotification {
976
+ channel: string;
977
+ payload: string | null;
978
+ processId: number;
979
+ }
980
+ /**
981
+ * Connection status of a realtime subscription.
982
+ *
983
+ * - `"connecting"` — establishing or re-establishing the SSE stream.
984
+ * - `"connected"` — stream is open, heartbeats are arriving, NOTIFY events are flowing.
985
+ * - `"reconnecting"` — the stream dropped and the SDK is waiting before the next retry.
986
+ * - `"disconnected"` — permanently stopped (via `unsubscribe()`, `signal` abort, or max retries exceeded).
987
+ */
988
+ type BrowserRealtimeStatus = "connecting" | "connected" | "reconnecting" | "disconnected";
989
+ interface BrowserRealtimeSubscribeParams {
990
+ databaseInstanceId?: string;
991
+ /** Channel names (normalized to lowercase on the server). */
992
+ channels: string[];
993
+ /** When aborted, the subscription stops permanently (equivalent to calling `unsubscribe()`). */
994
+ signal?: AbortSignal;
995
+ /** Called each time a Postgres NOTIFY message arrives. */
996
+ onNotify?: (msg: BrowserRealtimeNotification) => void;
997
+ /** Called once per connection attempt when the server confirms LISTEN is active. */
998
+ onReady?: (channels: string[]) => void;
999
+ /** Called when the stream encounters a non-retryable error or the server sends an error event. */
1000
+ onError?: (message: string) => void;
1001
+ /** Called whenever the connection status changes (connecting → connected → reconnecting → …). */
1002
+ onStatusChange?: (status: BrowserRealtimeStatus) => void;
1003
+ /** Called when the stream drops and the SDK will attempt to reconnect. `attempt` is 1-indexed. */
1004
+ onDisconnect?: (info: {
1005
+ attempt: number;
1006
+ retryInMs: number;
1007
+ }) => void;
1008
+ /** Called when a reconnect attempt succeeds (stream is open again). */
1009
+ onReconnect?: (info: {
1010
+ attempt: number;
1011
+ }) => void;
1012
+ /** Maximum number of reconnect attempts before giving up. Set `0` to disable reconnect. Default: **Infinity** (never stops). */
1013
+ maxReconnectAttempts?: number;
1014
+ /** Base delay for exponential backoff (ms). Default: **1000**. */
1015
+ reconnectBaseDelayMs?: number;
1016
+ /** Maximum delay between reconnect attempts (ms). Default: **30000**. */
1017
+ reconnectMaxDelayMs?: number;
1018
+ /** How long to wait without a heartbeat before considering the connection dead (ms). Default: **45000** (3× the server's 15 s heartbeat interval). */
1019
+ heartbeatTimeoutMs?: number;
1020
+ }
1021
+ /**
1022
+ * Handle returned by `database.realtime.subscribe()`.
1023
+ *
1024
+ * - Call `unsubscribe()` to permanently close the subscription (no more reconnects).
1025
+ * - Read `status` to check the current connection state at any time.
1026
+ */
1027
+ interface BrowserRealtimeSubscription {
1028
+ unsubscribe: () => void;
1029
+ readonly status: BrowserRealtimeStatus;
946
1030
  }
947
1031
  declare class RagableBrowserAgentsClient {
948
1032
  private readonly options;
@@ -1044,4 +1128,4 @@ declare function createClient(options: RagableClientOptions): Ragable;
1044
1128
  declare function createClient<Database extends RagableDatabase = DefaultRagableDatabase, AuthUser extends Record<string, unknown> = Record<string, unknown>>(options: RagableBrowserClientOptions): RagableBrowser<Database, AuthUser>;
1045
1129
  declare function createRagableServerClient(options: RagableClientOptions): Ragable;
1046
1130
 
1047
- export { type AgentChatMessage, type AgentChatParams, type AgentChatResult, type AgentPublicChatParams, type AgentStreamEvent, type AgentSummary, AgentsClient, AuthBroadcastChannel, type AuthBroadcastMessage, type AuthChangeEvent, type AuthOptions, type AuthSession, type BrowserAuthSession, type BrowserAuthTokens, type BrowserDataAuthMode, type BrowserSqlExecParams, type BrowserSqlExecResult, type BrowserSqlQueryParams, type BrowserSqlQueryResult, type ColumnName, type ColumnValue, CookieStorageAdapter, DEFAULT_RAGABLE_API_BASE, type DefaultRagableDatabase, type FormatContextOptions, type HttpMethod, type Json, LocalStorageAdapter, MemoryStorageAdapter, type PostgRESTFetch, type PostgRESTFetchParams, PostgrestDeleteReturningBuilder, PostgrestDeleteRootBuilder, PostgrestInsertReturningBuilder, PostgrestInsertRootBuilder, PostgrestInsertSdkErrorReturning, PostgrestInsertSdkErrorRoot, type PostgrestResult, PostgrestSelectBuilder, PostgrestTableApi, PostgrestUpdateReturningBuilder, PostgrestUpdateRootBuilder, type PostgrestUpsertOptions, PostgrestUpsertReturningBuilder, PostgrestUpsertRootBuilder, type RagClientForPipeline, type RagPipeline, type RagPipelineOptions, Ragable, RagableAbortError, RagableAuth, type RagableAuthConfig, RagableBrowser, RagableBrowserAgentsClient, RagableBrowserAuthClient, type RagableBrowserClientOptions, RagableBrowserDatabaseClient, type RagableClientOptions, type RagableDatabase, RagableError, RagableNetworkError, RagableRequestClient, RagableSdkError, type RagableTableDefinition, type RagableTableNames, RagableTimeoutError, type RequestOptions, type RetrieveParams, type RetryOptions, type RunQuery, type SessionStorage, SessionStorageAdapter, type ShiftAddDocumentParams, ShiftClient, type ShiftCreateIndexParams, type ShiftEntry, type ShiftIndex, type ShiftIngestResponse, type ShiftListEntriesParams, type ShiftListEntriesResponse, type ShiftSearchParams, type ShiftSearchResult, type ShiftUpdateIndexParams, type ShiftUploadFileParams, type ShiftUploadableFile, type SseJsonEvent, type SupabaseCompatSession, type TableInsertRow, type TableRow, type TableUpdatePatch, type Tables, type TablesInsert, type TablesUpdate, Transport, type TransportOptions, type TransportRequest, asPostgrestResponse, bindFetch, createBrowserClient, createClient, createRagPipeline, createRagableBrowserClient, createRagableServerClient, detectStorage, effectiveDataAuth, extractErrorMessage, formatPostgrestError, formatRetrievalContext, formatSdkError, generateIdempotencyKey, normalizeBrowserApiBase, parseSseDataLine, parseTransportResponse, readSseStream };
1131
+ export { type AgentChatMessage, type AgentChatParams, type AgentChatResult, type AgentPublicChatParams, type AgentStreamEvent, type AgentSummary, AgentsClient, AuthBroadcastChannel, type AuthBroadcastMessage, type AuthChangeEvent, type AuthOptions, type AuthSession, type BrowserAuthSession, type BrowserAuthTokens, type BrowserDataAuthMode, type BrowserRealtimeNotification, type BrowserRealtimeStatus, type BrowserRealtimeSubscribeParams, type BrowserRealtimeSubscription, type BrowserSqlExecParams, type BrowserSqlExecResult, type BrowserSqlQueryParams, type BrowserSqlQueryResult, type ColumnName, type ColumnValue, CookieStorageAdapter, DEFAULT_RAGABLE_API_BASE, type DefaultRagableDatabase, type FormatContextOptions, type HttpMethod, type Json, LocalStorageAdapter, MemoryStorageAdapter, type PostgRESTFetch, type PostgRESTFetchParams, PostgrestDeleteReturningBuilder, PostgrestDeleteRootBuilder, PostgrestInsertReturningBuilder, PostgrestInsertRootBuilder, PostgrestInsertSdkErrorReturning, PostgrestInsertSdkErrorRoot, type PostgrestResult, PostgrestSelectBuilder, PostgrestTableApi, PostgrestUpdateReturningBuilder, PostgrestUpdateRootBuilder, type PostgrestUpsertOptions, PostgrestUpsertReturningBuilder, PostgrestUpsertRootBuilder, type RagClientForPipeline, type RagPipeline, type RagPipelineOptions, Ragable, RagableAbortError, RagableAuth, type RagableAuthConfig, RagableBrowser, RagableBrowserAgentsClient, RagableBrowserAuthClient, type RagableBrowserClientOptions, RagableBrowserDatabaseClient, type RagableClientOptions, type RagableDatabase, RagableError, RagableNetworkError, RagableRequestClient, RagableSdkError, type RagableTableDefinition, type RagableTableNames, RagableTimeoutError, type RequestOptions, type RetrieveParams, type RetryOptions, type RunQuery, type SessionStorage, SessionStorageAdapter, type ShiftAddDocumentParams, ShiftClient, type ShiftCreateIndexParams, type ShiftEntry, type ShiftIndex, type ShiftIngestResponse, type ShiftListEntriesParams, type ShiftListEntriesResponse, type ShiftSearchParams, type ShiftSearchResult, type ShiftUpdateIndexParams, type ShiftUploadFileParams, type ShiftUploadableFile, type SseJsonEvent, type SupabaseCompatSession, type TableInsertRow, type TableRow, type TableUpdatePatch, type Tables, type TablesInsert, type TablesUpdate, Transport, type TransportOptions, type TransportRequest, asPostgrestResponse, bindFetch, createBrowserClient, createClient, createRagPipeline, createRagableBrowserClient, createRagableServerClient, detectStorage, effectiveDataAuth, extractErrorMessage, formatPostgrestError, formatRetrievalContext, formatSdkError, generateIdempotencyKey, normalizeBrowserApiBase, parseSseDataLine, parseTransportResponse, readSseStream };
package/dist/index.js CHANGED
@@ -2368,6 +2368,32 @@ var RagableBrowserDatabaseClient = class {
2368
2368
  return payload;
2369
2369
  });
2370
2370
  });
2371
+ /**
2372
+ * Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
2373
+ * Channels must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
2374
+ */
2375
+ /**
2376
+ * Postgres `LISTEN` / `NOTIFY` realtime via server-proxied SSE.
2377
+ *
2378
+ * Returns a `BrowserRealtimeSubscription` with:
2379
+ * - `unsubscribe()` — permanently close the subscription (stops reconnects).
2380
+ * - `status` — current connection state: `"connecting"` | `"connected"` | `"reconnecting"` | `"disconnected"`.
2381
+ *
2382
+ * The subscription automatically reconnects with exponential backoff when the
2383
+ * stream drops. Server heartbeats (every 15 s) are monitored — if none arrive
2384
+ * within `heartbeatTimeoutMs` (default 45 s), the connection is treated as dead
2385
+ * and a reconnect is triggered. Auth errors (401/403/404) are non-retryable.
2386
+ *
2387
+ * Channel names must be lowercase identifiers: `[a-z_][a-z0-9_]*` (max 63 chars).
2388
+ */
2389
+ __publicField(this, "realtime", {
2390
+ subscribe: (params) => subscribeBrowserRealtime(
2391
+ this.options,
2392
+ this.ragableAuth,
2393
+ this.fetchImpl,
2394
+ params
2395
+ )
2396
+ });
2371
2397
  this.fetchImpl = bindFetch(options.fetch);
2372
2398
  }
2373
2399
  /** @internal Called by RagableBrowser to share the Transport instance. */
@@ -2381,6 +2407,190 @@ var RagableBrowserDatabaseClient = class {
2381
2407
  return new Headers(this.options.headers);
2382
2408
  }
2383
2409
  };
2410
+ function followAbortSignal(parent, child) {
2411
+ if (!parent) return;
2412
+ if (parent.aborted) {
2413
+ child.abort();
2414
+ return;
2415
+ }
2416
+ parent.addEventListener("abort", () => child.abort(), { once: true });
2417
+ }
2418
+ function backoffDelay(attempt, baseMs, maxMs) {
2419
+ const exp = Math.min(baseMs * 2 ** (attempt - 1), maxMs);
2420
+ const jitter = exp * (0.5 + Math.random() * 0.5);
2421
+ return Math.round(jitter);
2422
+ }
2423
+ async function subscribeBrowserRealtime(options, ragableAuth, fetchImpl, params) {
2424
+ const gid = requireAuthGroupId(options);
2425
+ const databaseInstanceId = params.databaseInstanceId?.trim() || options.databaseInstanceId?.trim();
2426
+ if (!databaseInstanceId) {
2427
+ throw new RagableError(
2428
+ "realtime.subscribe requires databaseInstanceId in params or on createBrowserClient({ databaseInstanceId })",
2429
+ 400,
2430
+ { code: "SDK_MISSING_DATABASE_INSTANCE_ID" }
2431
+ );
2432
+ }
2433
+ if (!Array.isArray(params.channels) || params.channels.length === 0) {
2434
+ throw new RagableError(
2435
+ "realtime.subscribe requires a non-empty channels array",
2436
+ 400,
2437
+ { code: "SDK_REALTIME_CHANNELS_REQUIRED" }
2438
+ );
2439
+ }
2440
+ const maxAttempts = params.maxReconnectAttempts ?? Infinity;
2441
+ const baseDelay = params.reconnectBaseDelayMs ?? 1e3;
2442
+ const maxDelay = params.reconnectMaxDelayMs ?? 3e4;
2443
+ const heartbeatTimeout = params.heartbeatTimeoutMs ?? 45e3;
2444
+ const lifecycleAc = new AbortController();
2445
+ followAbortSignal(params.signal, lifecycleAc);
2446
+ let currentStatus = "connecting";
2447
+ const setStatus = (s) => {
2448
+ if (s === currentStatus) return;
2449
+ currentStatus = s;
2450
+ params.onStatusChange?.(s);
2451
+ };
2452
+ const subscription = {
2453
+ unsubscribe: () => lifecycleAc.abort(),
2454
+ get status() {
2455
+ return currentStatus;
2456
+ }
2457
+ };
2458
+ setStatus("connecting");
2459
+ async function connectOnce(signal) {
2460
+ const token = await resolveDatabaseAuthBearer(options, ragableAuth);
2461
+ const headers = new Headers(options.headers);
2462
+ headers.set("Authorization", `Bearer ${token}`);
2463
+ headers.set("Content-Type", "application/json");
2464
+ const response = await fetchImpl(
2465
+ `${normalizeBrowserApiBase()}/auth-groups/${gid}/data/realtime/stream`,
2466
+ {
2467
+ method: "POST",
2468
+ headers,
2469
+ body: JSON.stringify({
2470
+ databaseInstanceId,
2471
+ channels: params.channels
2472
+ }),
2473
+ signal
2474
+ }
2475
+ );
2476
+ if (!response.ok) {
2477
+ const payload = await parseMaybeJsonBody(response);
2478
+ const message = extractErrorMessage(payload, response.statusText);
2479
+ throw new RagableError(message, response.status, payload);
2480
+ }
2481
+ const streamBody = response.body;
2482
+ if (!streamBody) {
2483
+ throw new RagableError("Realtime stream has no body", 502, {
2484
+ code: "SDK_REALTIME_NO_BODY"
2485
+ });
2486
+ }
2487
+ let heartbeatTimer = null;
2488
+ const resetHeartbeatTimer = () => {
2489
+ if (heartbeatTimer) clearTimeout(heartbeatTimer);
2490
+ heartbeatTimer = setTimeout(() => {
2491
+ streamReader?.cancel().catch(() => void 0);
2492
+ }, heartbeatTimeout);
2493
+ };
2494
+ let streamReader = null;
2495
+ try {
2496
+ streamReader = streamBody.getReader();
2497
+ const decoder = new TextDecoder();
2498
+ let buffer = "";
2499
+ resetHeartbeatTimer();
2500
+ const processEvent = (evt) => {
2501
+ if (evt.type === "realtime:heartbeat") {
2502
+ resetHeartbeatTimer();
2503
+ return;
2504
+ }
2505
+ resetHeartbeatTimer();
2506
+ if (evt.type === "realtime:ready") {
2507
+ const ch = evt.channels;
2508
+ setStatus("connected");
2509
+ params.onReady?.(
2510
+ Array.isArray(ch) ? ch.map((c) => String(c)) : []
2511
+ );
2512
+ } else if (evt.type === "notify") {
2513
+ params.onNotify?.({
2514
+ channel: String(evt.channel ?? ""),
2515
+ payload: evt.payload === void 0 || evt.payload === null ? null : String(evt.payload),
2516
+ processId: Number(evt.processId ?? 0)
2517
+ });
2518
+ } else if (evt.type === "realtime:error") {
2519
+ params.onError?.(String(evt.message ?? "Realtime error"));
2520
+ }
2521
+ };
2522
+ while (true) {
2523
+ const { done, value } = await streamReader.read();
2524
+ if (done) break;
2525
+ buffer += decoder.decode(value, { stream: true });
2526
+ let boundary = buffer.indexOf("\n\n");
2527
+ while (boundary !== -1) {
2528
+ const block = buffer.slice(0, boundary);
2529
+ buffer = buffer.slice(boundary + 2);
2530
+ for (const line of block.split("\n")) {
2531
+ const dataPrefix = "data: ";
2532
+ if (!line.startsWith(dataPrefix)) continue;
2533
+ const json = line.slice(dataPrefix.length).trim();
2534
+ if (!json || json === "[DONE]") continue;
2535
+ try {
2536
+ processEvent(JSON.parse(json));
2537
+ } catch {
2538
+ }
2539
+ }
2540
+ boundary = buffer.indexOf("\n\n");
2541
+ }
2542
+ }
2543
+ return "stream_ended";
2544
+ } finally {
2545
+ if (heartbeatTimer) clearTimeout(heartbeatTimer);
2546
+ streamReader?.releaseLock();
2547
+ }
2548
+ }
2549
+ void (async () => {
2550
+ let attempt = 0;
2551
+ while (!lifecycleAc.signal.aborted) {
2552
+ const iterAc = new AbortController();
2553
+ followAbortSignal(lifecycleAc.signal, iterAc);
2554
+ try {
2555
+ const result = await connectOnce(iterAc.signal);
2556
+ if (lifecycleAc.signal.aborted) break;
2557
+ if (result === "stream_ended") {
2558
+ attempt++;
2559
+ }
2560
+ } catch (e) {
2561
+ if (lifecycleAc.signal.aborted) break;
2562
+ if (e.name === "AbortError") break;
2563
+ const status = e.status;
2564
+ if (status === 400 || status === 401 || status === 403 || status === 404) {
2565
+ params.onError?.(e.message);
2566
+ break;
2567
+ }
2568
+ attempt++;
2569
+ }
2570
+ if (lifecycleAc.signal.aborted) break;
2571
+ if (attempt > maxAttempts) {
2572
+ params.onError?.(`Realtime: gave up after ${maxAttempts} reconnect attempts`);
2573
+ break;
2574
+ }
2575
+ const delay = backoffDelay(attempt, baseDelay, maxDelay);
2576
+ setStatus("reconnecting");
2577
+ params.onDisconnect?.({ attempt, retryInMs: delay });
2578
+ await new Promise((r) => {
2579
+ const timer = setTimeout(r, delay);
2580
+ const onAbort = () => {
2581
+ clearTimeout(timer);
2582
+ r();
2583
+ };
2584
+ lifecycleAc.signal.addEventListener("abort", onAbort, { once: true });
2585
+ });
2586
+ if (lifecycleAc.signal.aborted) break;
2587
+ setStatus("connecting");
2588
+ params.onReconnect?.({ attempt });
2589
+ }
2590
+ setStatus("disconnected");
2591
+ })();
2592
+ return subscription;
2593
+ }
2384
2594
  var RagableBrowserAgentsClient = class {
2385
2595
  constructor(options) {
2386
2596
  this.options = options;