@rebasepro/client 0.2.5 → 0.4.0

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/auth.d.ts CHANGED
@@ -168,3 +168,11 @@ export declare function createAuth(transport: Transport, options?: CreateAuthOpt
168
168
  getSession: () => RebaseSession | null;
169
169
  onAuthStateChange: (callback: (event: AuthChangeEvent, session: RebaseSession | null) => void) => () => boolean;
170
170
  };
171
+ export interface CookieStorageOptions {
172
+ path?: string;
173
+ domain?: string;
174
+ secure?: boolean;
175
+ sameSite?: "Lax" | "Strict" | "None";
176
+ maxAge?: number;
177
+ }
178
+ export declare function createCookieStorage(options?: CookieStorageOptions): AuthStorage;
@@ -1,6 +1,6 @@
1
- import { Transport, FindParams } from "./transport";
1
+ import { FindParams, Transport } from "./transport";
2
2
  import { RebaseWebSocketClient } from "./websocket";
3
- import { CollectionAccessor, FilterOperator } from "@rebasepro/types";
3
+ import { CollectionAccessor, FilterOperator, LogicalCondition, WhereValue } from "@rebasepro/types";
4
4
  import { QueryBuilder } from "./query_builder";
5
5
  /**
6
6
  * CollectionClient extends `CollectionAccessor` from `@rebasepro/types` so that
@@ -9,7 +9,8 @@ import { QueryBuilder } from "./query_builder";
9
9
  * Additionally it exposes fluent query builder methods like `.where()`, `.orderBy()`.
10
10
  */
11
11
  export interface CollectionClient<M extends Record<string, unknown> = Record<string, unknown>> extends CollectionAccessor<M> {
12
- where(column: keyof M & string, operator: FilterOperator, value: unknown): QueryBuilder<M>;
12
+ where<K extends keyof M & string>(column: K, operator: FilterOperator, value: WhereValue<M[K]>): QueryBuilder<M>;
13
+ where(logicalCondition: LogicalCondition): QueryBuilder<M>;
13
14
  orderBy(column: keyof M & string, ascending?: "asc" | "desc"): QueryBuilder<M>;
14
15
  limit(count: number): QueryBuilder<M>;
15
16
  offset(count: number): QueryBuilder<M>;
package/dist/index.es.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Vector, GeoPoint, EntityRelation, EntityReference } from "@rebasepro/types";
2
2
  import { QueryBuilder } from "@rebasepro/common";
3
- import { QueryBuilder as QueryBuilder2 } from "@rebasepro/common";
3
+ import { QueryBuilder as QueryBuilder2, and, cond, or } from "@rebasepro/common";
4
4
  import { toSnakeCase } from "@rebasepro/utils";
5
5
  function rebaseReviver(_key, value) {
6
6
  if (value && typeof value === "object" && "__type" in value) {
@@ -66,15 +66,33 @@ function normalizeWhereValue(value) {
66
66
  if (value === null) return "eq.null";
67
67
  if (typeof value === "boolean") return `eq.${value}`;
68
68
  if (typeof value === "number") return String(value);
69
- if (Array.isArray(value) && value.length === 2) {
70
- const [rawOp, val] = value;
71
- const op = OP_MAP[rawOp] ?? rawOp;
72
- if (val === null) return `${op}.null`;
73
- if (Array.isArray(val)) return `${op}.(${val.join(",")})`;
74
- return `${op}.${val}`;
69
+ if (Array.isArray(value)) {
70
+ const conditions = Array.isArray(value[0]) ? value : [value];
71
+ const [rawOp, val] = conditions[0] || [];
72
+ if (rawOp) {
73
+ const op = OP_MAP[rawOp] ?? rawOp;
74
+ if (val === null) return `${op}.null`;
75
+ if (Array.isArray(val)) return `${op}.(${val.join(",")})`;
76
+ return `${op}.${val}`;
77
+ }
75
78
  }
76
79
  return String(value);
77
80
  }
81
+ function serializeLogicalCondition(cond2) {
82
+ if ("type" in cond2) {
83
+ const sub = cond2.conditions.map(serializeLogicalCondition).join(",");
84
+ return `${cond2.type}(${sub})`;
85
+ } else {
86
+ const op = OP_MAP[cond2.operator] ?? cond2.operator;
87
+ let formattedValue = cond2.value;
88
+ if (Array.isArray(cond2.value)) {
89
+ formattedValue = `(${cond2.value.join(",")})`;
90
+ } else if (cond2.value === null) {
91
+ formattedValue = "null";
92
+ }
93
+ return `${cond2.column}.${op}.${formattedValue}`;
94
+ }
95
+ }
78
96
  function buildQueryString(params) {
79
97
  if (!params) return "";
80
98
  const parts = [];
@@ -90,10 +108,22 @@ function buildQueryString(params) {
90
108
  if (params.include && params.include.length > 0) {
91
109
  parts.push(`include=${encodeURIComponent(params.include.join(","))}`);
92
110
  }
111
+ if (params.logical) {
112
+ const root = params.logical;
113
+ const serialized = root.conditions.map(serializeLogicalCondition).join(",");
114
+ parts.push(`${root.type}=${encodeURIComponent(`(${serialized})`)}`);
115
+ }
93
116
  if (params.where) {
94
117
  for (const [field, value] of Object.entries(params.where)) {
95
- const normalized = normalizeWhereValue(value);
96
- parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(normalized)}`);
118
+ if (Array.isArray(value) && value.length > 0 && Array.isArray(value[0])) {
119
+ for (const subVal of value) {
120
+ const normalized = normalizeWhereValue(subVal);
121
+ parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(normalized)}`);
122
+ }
123
+ } else {
124
+ const normalized = normalizeWhereValue(value);
125
+ parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(normalized)}`);
126
+ }
97
127
  }
98
128
  }
99
129
  return parts.length > 0 ? "?" + parts.join("&") : "";
@@ -703,6 +733,58 @@ function createAuth(transport, options) {
703
733
  onAuthStateChange
704
734
  };
705
735
  }
736
+ function createCookieStorage(options = {}) {
737
+ const defaultOptions = {
738
+ path: "/",
739
+ sameSite: "Lax",
740
+ ...options
741
+ };
742
+ return {
743
+ getItem(key) {
744
+ if (typeof document === "undefined") return null;
745
+ const nameEQ = encodeURIComponent(key) + "=";
746
+ const ca = document.cookie.split(";");
747
+ for (let i = 0; i < ca.length; i++) {
748
+ let c = ca[i];
749
+ while (c.charAt(0) === " ") c = c.substring(1, c.length);
750
+ if (c.indexOf(nameEQ) === 0) {
751
+ return decodeURIComponent(c.substring(nameEQ.length, c.length));
752
+ }
753
+ }
754
+ return null;
755
+ },
756
+ setItem(key, value) {
757
+ if (typeof document === "undefined") return;
758
+ let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
759
+ if (defaultOptions.path) {
760
+ cookieStr += `; path=${defaultOptions.path}`;
761
+ }
762
+ if (defaultOptions.domain) {
763
+ cookieStr += `; domain=${defaultOptions.domain}`;
764
+ }
765
+ if (defaultOptions.maxAge !== void 0) {
766
+ cookieStr += `; max-age=${defaultOptions.maxAge}`;
767
+ } else {
768
+ cookieStr += `; max-age=${365 * 24 * 60 * 60}`;
769
+ }
770
+ if (defaultOptions.secure) {
771
+ cookieStr += "; secure";
772
+ }
773
+ if (defaultOptions.sameSite) {
774
+ cookieStr += `; samesite=${defaultOptions.sameSite}`;
775
+ }
776
+ document.cookie = cookieStr;
777
+ },
778
+ removeItem(key) {
779
+ if (typeof document === "undefined") return;
780
+ let cookieStr = `${encodeURIComponent(key)}=; path=${defaultOptions.path || "/"}; max-age=-1`;
781
+ if (defaultOptions.domain) {
782
+ cookieStr += `; domain=${defaultOptions.domain}`;
783
+ }
784
+ document.cookie = cookieStr;
785
+ }
786
+ };
787
+ }
706
788
  function createAdmin(transport, options) {
707
789
  const opts = options || {};
708
790
  const adminPath = opts.adminPath || "/admin";
@@ -803,44 +885,34 @@ function createCron(transport, options) {
803
885
  function parseWhereFilter(where) {
804
886
  if (!where) return void 0;
805
887
  const filters = {};
806
- for (const [key, rawValue] of Object.entries(where)) {
807
- if (rawValue === null) {
808
- filters[key] = ["==", null];
809
- continue;
810
- }
811
- if (typeof rawValue === "boolean") {
812
- filters[key] = ["==", rawValue];
813
- continue;
814
- }
815
- if (typeof rawValue === "number") {
816
- filters[key] = ["==", rawValue];
817
- continue;
818
- }
819
- if (Array.isArray(rawValue) && rawValue.length === 2) {
888
+ const OP_TO_FILTER = {
889
+ "eq": "==",
890
+ "neq": "!=",
891
+ "gt": ">",
892
+ "gte": ">=",
893
+ "lt": "<",
894
+ "lte": "<=",
895
+ "==": "==",
896
+ "!=": "!=",
897
+ ">": ">",
898
+ ">=": ">=",
899
+ "<": "<",
900
+ "<=": "<=",
901
+ "in": "in",
902
+ "nin": "not-in",
903
+ "not-in": "not-in",
904
+ "cs": "array-contains",
905
+ "csa": "array-contains-any",
906
+ "array-contains": "array-contains",
907
+ "array-contains-any": "array-contains-any"
908
+ };
909
+ const parseSingle = (rawValue, fieldKey) => {
910
+ if (rawValue === null) return ["==", null];
911
+ if (typeof rawValue === "boolean") return ["==", rawValue];
912
+ if (typeof rawValue === "number") return ["==", rawValue];
913
+ if (Array.isArray(rawValue) && rawValue.length === 2 && typeof rawValue[0] === "string") {
820
914
  const [rawOp, val] = rawValue;
821
- const OP_TO_FILTER = {
822
- "eq": "==",
823
- "neq": "!=",
824
- "gt": ">",
825
- "gte": ">=",
826
- "lt": "<",
827
- "lte": "<=",
828
- "==": "==",
829
- "!=": "!=",
830
- ">": ">",
831
- ">=": ">=",
832
- "<": "<",
833
- "<=": "<=",
834
- "in": "in",
835
- "nin": "not-in",
836
- "not-in": "not-in",
837
- "cs": "array-contains",
838
- "csa": "array-contains-any",
839
- "array-contains": "array-contains",
840
- "array-contains-any": "array-contains-any"
841
- };
842
- filters[key] = [OP_TO_FILTER[rawOp] ?? "==", val];
843
- continue;
915
+ return [OP_TO_FILTER[rawOp] ?? "==", val];
844
916
  }
845
917
  const value = String(rawValue);
846
918
  const dotIndex = value.indexOf(".");
@@ -890,10 +962,17 @@ function parseWhereFilter(where) {
890
962
  if (val === "true") val = true;
891
963
  else if (val === "false") val = false;
892
964
  else if (val === "null") val = null;
893
- else if (typeof val === "string" && /^[0-9]+(\.[0-9]+)?$/.test(val) && key !== "id" && !key.endsWith("_id")) val = Number(val);
894
- filters[key] = [op, val];
965
+ else if (typeof val === "string" && /^[0-9]+(\.[0-9]+)?$/.test(val) && fieldKey !== "id" && !fieldKey.endsWith("_id")) val = Number(val);
966
+ return [op, val];
967
+ } else {
968
+ return ["==", value];
969
+ }
970
+ };
971
+ for (const [key, rawValue] of Object.entries(where)) {
972
+ if (Array.isArray(rawValue) && rawValue.length > 0 && Array.isArray(rawValue[0])) {
973
+ filters[key] = rawValue.map((r) => parseSingle(r, key));
895
974
  } else {
896
- filters[key] = ["==", value];
975
+ filters[key] = parseSingle(rawValue, key);
897
976
  }
898
977
  }
899
978
  return filters;
@@ -917,9 +996,16 @@ function createCollectionClient(transport, slug, ws) {
917
996
  };
918
997
  },
919
998
  async findById(id) {
920
- const raw = await transport.request(`${basePath}/${encodeURIComponent(String(id))}`, { method: "GET" });
921
- if (!raw) return void 0;
922
- return rowToEntity(raw, slug);
999
+ try {
1000
+ const raw = await transport.request(`${basePath}/${encodeURIComponent(String(id))}`, { method: "GET" });
1001
+ if (!raw) return void 0;
1002
+ return rowToEntity(raw, slug);
1003
+ } catch (err) {
1004
+ if (err instanceof RebaseApiError && err.status === 404) {
1005
+ return void 0;
1006
+ }
1007
+ throw err;
1008
+ }
923
1009
  },
924
1010
  async create(data, id) {
925
1011
  const body = { ...data };
@@ -945,14 +1031,22 @@ function createCollectionClient(transport, slug, ws) {
945
1031
  });
946
1032
  },
947
1033
  async count(params) {
948
- const countParams = { ...params, limit: void 0, offset: void 0 };
1034
+ const countParams = {
1035
+ ...params,
1036
+ limit: void 0,
1037
+ offset: void 0
1038
+ };
949
1039
  const qs = buildQueryString(countParams);
950
1040
  const raw = await transport.request(basePath + "/count" + qs, { method: "GET" });
951
1041
  return raw.count ?? 0;
952
1042
  },
953
1043
  // Fluent builder instantiation
954
- where(column, operator, value) {
955
- return new QueryBuilder(client).where(column, operator, value);
1044
+ where(columnOrCondition, operator, value) {
1045
+ const builder = new QueryBuilder(client);
1046
+ if (typeof columnOrCondition === "object") {
1047
+ return builder.where(columnOrCondition);
1048
+ }
1049
+ return builder.where(columnOrCondition, operator, value);
956
1050
  },
957
1051
  orderBy(column, ascending) {
958
1052
  return new QueryBuilder(client).orderBy(column, ascending);
@@ -1089,9 +1183,12 @@ class RebaseWebSocketClient {
1089
1183
  isAuthenticated = false;
1090
1184
  authPromise = null;
1091
1185
  WebSocketConstructor;
1186
+ onUnauthorized;
1187
+ refreshInProgress = null;
1092
1188
  constructor(config) {
1093
1189
  this.websocketUrl = config.websocketUrl;
1094
1190
  this.getAuthToken = config.getAuthToken;
1191
+ this.onUnauthorized = config.onUnauthorized;
1095
1192
  this.WebSocketConstructor = config.WebSocket || (typeof WebSocket !== "undefined" ? WebSocket : void 0);
1096
1193
  if (!this.WebSocketConstructor) {
1097
1194
  console.warn("WebSocket is not defined in this environment. Realtime subscriptions will not work unless you provide a WebSocket implementation in the config.");
@@ -1256,6 +1353,42 @@ class RebaseWebSocketClient {
1256
1353
  this.initWebSocket();
1257
1354
  }, delay);
1258
1355
  }
1356
+ isAuthError(message) {
1357
+ if (message.type === "AUTH_ERROR") return true;
1358
+ const { errorMessage, errorCode } = extractMessageError(message);
1359
+ if (errorCode === "UNAUTHORIZED" || errorCode === "JWT_EXPIRED" || errorCode === "AUTH_ERROR") return true;
1360
+ const lowerMessage = errorMessage.toLowerCase();
1361
+ return lowerMessage.includes("unauthorized") || lowerMessage.includes("token expired") || lowerMessage.includes("token is expired") || lowerMessage.includes("invalid token") || lowerMessage.includes("session expired") || lowerMessage.includes("auth error");
1362
+ }
1363
+ async handleAuthFailure() {
1364
+ if (this.refreshInProgress) {
1365
+ return this.refreshInProgress;
1366
+ }
1367
+ this.refreshInProgress = (async () => {
1368
+ this.isAuthenticated = false;
1369
+ this.authPromise = null;
1370
+ if (this.onUnauthorized) {
1371
+ try {
1372
+ const refreshed = await this.onUnauthorized();
1373
+ if (refreshed && this.getAuthToken) {
1374
+ const token = await this.getAuthToken();
1375
+ if (token) {
1376
+ await this.authenticate(token);
1377
+ return true;
1378
+ }
1379
+ }
1380
+ } catch (error) {
1381
+ console.error("WebSocket auth refresh failed:", error);
1382
+ }
1383
+ }
1384
+ return false;
1385
+ })();
1386
+ try {
1387
+ return await this.refreshInProgress;
1388
+ } finally {
1389
+ this.refreshInProgress = null;
1390
+ }
1391
+ }
1259
1392
  handleWebSocketMessage(message) {
1260
1393
  const {
1261
1394
  type,
@@ -1263,16 +1396,28 @@ class RebaseWebSocketClient {
1263
1396
  subscriptionId
1264
1397
  } = message;
1265
1398
  if (requestId && this.pendingRequests.has(requestId)) {
1266
- const {
1267
- resolve,
1268
- reject
1269
- } = this.pendingRequests.get(requestId);
1270
- this.pendingRequests.delete(requestId);
1399
+ const pendingReq = this.pendingRequests.get(requestId);
1271
1400
  if (type === "ERROR" || type === "AUTH_ERROR" || message.error) {
1272
- const { errorMessage, errorCode } = extractMessageError(message);
1273
- reject(new ApiError(errorMessage, errorMessage, errorCode));
1401
+ if (this.isAuthError(message)) {
1402
+ this.pendingRequests.delete(requestId);
1403
+ this.handleAuthFailure().then((refreshed) => {
1404
+ if (refreshed && pendingReq.message) {
1405
+ this.doSendMessage(pendingReq.message, pendingReq.resolve, pendingReq.reject).catch(pendingReq.reject);
1406
+ } else {
1407
+ const { errorMessage, errorCode } = extractMessageError(message);
1408
+ pendingReq.reject(new ApiError(errorMessage, errorMessage, errorCode));
1409
+ }
1410
+ }).catch((err) => {
1411
+ pendingReq.reject(err);
1412
+ });
1413
+ } else {
1414
+ this.pendingRequests.delete(requestId);
1415
+ const { errorMessage, errorCode } = extractMessageError(message);
1416
+ pendingReq.reject(new ApiError(errorMessage, errorMessage, errorCode));
1417
+ }
1274
1418
  } else {
1275
- resolve(message.payload || message);
1419
+ this.pendingRequests.delete(requestId);
1420
+ pendingReq.resolve(message.payload || message);
1276
1421
  }
1277
1422
  return;
1278
1423
  }
@@ -1363,6 +1508,40 @@ class RebaseWebSocketClient {
1363
1508
  if (collectionKey) {
1364
1509
  const collectionSub = this.collectionSubscriptions.get(collectionKey);
1365
1510
  if (collectionSub) {
1511
+ if (this.isAuthError(message)) {
1512
+ this.handleAuthFailure().then((refreshed) => {
1513
+ if (refreshed) {
1514
+ const oldBackendId = collectionSub.backendSubscriptionId;
1515
+ const newBackendId = `collection_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1516
+ collectionSub.backendSubscriptionId = newBackendId;
1517
+ this.backendToCollectionKey.delete(oldBackendId);
1518
+ this.backendToCollectionKey.set(newBackendId, collectionKey);
1519
+ this.sendMessage({
1520
+ type: "subscribe_collection",
1521
+ payload: {
1522
+ ...collectionSub.props,
1523
+ subscriptionId: newBackendId
1524
+ }
1525
+ }).catch((error2) => {
1526
+ console.error("[WS] Failed to re-subscribe collection after auth refresh:", collectionKey, error2);
1527
+ collectionSub.callbacks.forEach((callback) => {
1528
+ if (callback.onError) callback.onError(error2);
1529
+ });
1530
+ });
1531
+ } else {
1532
+ const { errorMessage: errorMessage2, errorCode: errorCode2 } = extractMessageError(message);
1533
+ const error2 = new ApiError(errorMessage2, errorMessage2, errorCode2);
1534
+ collectionSub.callbacks.forEach((callback) => {
1535
+ if (callback.onError) callback.onError(error2);
1536
+ });
1537
+ }
1538
+ }).catch((err) => {
1539
+ collectionSub.callbacks.forEach((callback) => {
1540
+ if (callback.onError) callback.onError(err);
1541
+ });
1542
+ });
1543
+ return;
1544
+ }
1366
1545
  const { errorMessage, errorCode } = extractMessageError(message);
1367
1546
  const error = new ApiError(errorMessage, errorMessage, errorCode);
1368
1547
  collectionSub.callbacks.forEach((callback) => {
@@ -1377,6 +1556,40 @@ class RebaseWebSocketClient {
1377
1556
  if (entityKey) {
1378
1557
  const entitySub = this.entitySubscriptions.get(entityKey);
1379
1558
  if (entitySub) {
1559
+ if (this.isAuthError(message)) {
1560
+ this.handleAuthFailure().then((refreshed) => {
1561
+ if (refreshed) {
1562
+ const oldBackendId = entitySub.backendSubscriptionId;
1563
+ const newBackendId = `entity_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
1564
+ entitySub.backendSubscriptionId = newBackendId;
1565
+ this.backendToEntityKey.delete(oldBackendId);
1566
+ this.backendToEntityKey.set(newBackendId, entityKey);
1567
+ this.sendMessage({
1568
+ type: "subscribe_entity",
1569
+ payload: {
1570
+ ...entitySub.props,
1571
+ subscriptionId: newBackendId
1572
+ }
1573
+ }).catch((error2) => {
1574
+ console.error("[WS] Failed to re-subscribe entity after auth refresh:", entityKey, error2);
1575
+ entitySub.callbacks.forEach((callback) => {
1576
+ if (callback.onError) callback.onError(error2);
1577
+ });
1578
+ });
1579
+ } else {
1580
+ const { errorMessage: errorMessage2, errorCode: errorCode2 } = extractMessageError(message);
1581
+ const error2 = new ApiError(errorMessage2, errorMessage2, errorCode2);
1582
+ entitySub.callbacks.forEach((callback) => {
1583
+ if (callback.onError) callback.onError(error2);
1584
+ });
1585
+ }
1586
+ }).catch((err) => {
1587
+ entitySub.callbacks.forEach((callback) => {
1588
+ if (callback.onError) callback.onError(err);
1589
+ });
1590
+ });
1591
+ return;
1592
+ }
1380
1593
  const { errorMessage, errorCode } = extractMessageError(message);
1381
1594
  const error = new ApiError(errorMessage, errorMessage, errorCode);
1382
1595
  entitySub.callbacks.forEach((callback) => {
@@ -2057,14 +2270,27 @@ function createStorage(transport) {
2057
2270
  };
2058
2271
  }
2059
2272
  function deriveWebSocketUrl(baseUrl) {
2060
- if (!baseUrl) {
2061
- if (typeof window !== "undefined") {
2062
- const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
2063
- return `${protocol}//${window.location.host}`;
2273
+ if (typeof window !== "undefined") {
2274
+ let absoluteUrl = "";
2275
+ if (!baseUrl) {
2276
+ absoluteUrl = window.location.origin;
2277
+ } else if (/^https?:\/\//i.test(baseUrl) || /^wss?:\/\//i.test(baseUrl)) {
2278
+ absoluteUrl = baseUrl;
2279
+ } else {
2280
+ try {
2281
+ absoluteUrl = new URL(baseUrl, window.location.href).origin;
2282
+ } catch {
2283
+ absoluteUrl = window.location.origin;
2284
+ }
2064
2285
  }
2286
+ const protocol = absoluteUrl.startsWith("https:") || absoluteUrl.startsWith("wss:") ? "wss:" : "ws:";
2287
+ return absoluteUrl.replace(/^https?:\/\//i, `${protocol}//`).replace(/^wss?:\/\//i, `${protocol}//`).replace(/\/$/, "");
2288
+ }
2289
+ if (!baseUrl) return "";
2290
+ if (!/^https?:\/\//i.test(baseUrl) && !/^wss?:\/\//i.test(baseUrl)) {
2065
2291
  return "";
2066
2292
  }
2067
- return baseUrl.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://").replace(/\/$/, "");
2293
+ return baseUrl.replace(/^https?:\/\//i, (match) => match.toLowerCase() === "https://" ? "wss://" : "ws://").replace(/\/$/, "");
2068
2294
  }
2069
2295
  function createRebaseClient(options) {
2070
2296
  const transport = createTransport(options);
@@ -2076,12 +2302,27 @@ function createRebaseClient(options) {
2076
2302
  const resolvedWsUrl = options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl);
2077
2303
  let ws;
2078
2304
  if (resolvedWsUrl) {
2305
+ const wsOnUnauthorized = options.onUnauthorized || (async () => {
2306
+ try {
2307
+ await auth.refreshSession();
2308
+ return true;
2309
+ } catch (e) {
2310
+ return false;
2311
+ }
2312
+ });
2079
2313
  ws = new RebaseWebSocketClient({
2080
2314
  websocketUrl: resolvedWsUrl,
2081
2315
  getAuthToken: async () => {
2082
- const session = await auth.getSession();
2316
+ let session = auth.getSession();
2317
+ if (session && session.expiresAt <= Date.now() + 1e4) {
2318
+ try {
2319
+ session = await auth.refreshSession();
2320
+ } catch (e) {
2321
+ }
2322
+ }
2083
2323
  return session?.accessToken || options.token || "";
2084
- }
2324
+ },
2325
+ onUnauthorized: wsOnUnauthorized
2085
2326
  });
2086
2327
  auth.onAuthStateChange((event, session) => {
2087
2328
  if (!ws) return;
@@ -2156,16 +2397,20 @@ export {
2156
2397
  QueryBuilder2 as QueryBuilder,
2157
2398
  RebaseApiError,
2158
2399
  RebaseWebSocketClient,
2400
+ and,
2159
2401
  buildQueryString,
2402
+ cond,
2160
2403
  createAdmin,
2161
2404
  createAuth,
2162
2405
  createCollectionClient,
2406
+ createCookieStorage,
2163
2407
  createCron,
2164
2408
  createFunctionsClient,
2165
2409
  createMemoryStorage,
2166
2410
  createRebaseClient,
2167
2411
  createStorage,
2168
2412
  createTransport,
2413
+ or,
2169
2414
  rebaseReviver
2170
2415
  };
2171
2416
  //# sourceMappingURL=index.es.js.map