@rebasepro/client 0.11.1-canary.gfd39654 → 0.12.1-canary.g06f263c
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/api-keys.d.ts +10 -38
- package/dist/auth.d.ts +2 -0
- package/dist/functions.d.ts +2 -8
- package/dist/index.d.ts +13 -4
- package/dist/index.es.js +126 -13
- package/dist/index.es.js.map +1 -1
- package/dist/realtime-channel.d.ts +8 -8
- package/dist/transport.d.ts +35 -1
- package/dist/websocket.d.ts +18 -0
- package/package.json +8 -8
- package/src/anonymous-client-guard.test.ts +190 -0
- package/src/api-keys.ts +21 -44
- package/src/auth.ts +30 -0
- package/src/client-close.test.ts +80 -0
- package/src/collection.test.ts +1 -1
- package/src/collection.ts +14 -0
- package/src/functions.ts +11 -9
- package/src/index.ts +31 -9
- package/src/offline-idb-store.test.ts +58 -4
- package/src/offline-integration.test.ts +5 -0
- package/src/offline.ts +9 -1
- package/src/realtime-channel.ts +8 -8
- package/src/transport.ts +80 -1
- package/src/websocket.ts +51 -1
package/dist/api-keys.d.ts
CHANGED
|
@@ -1,42 +1,14 @@
|
|
|
1
1
|
import type { Transport } from "./transport";
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
permissions: ApiKeyPermission[];
|
|
13
|
-
admin: boolean;
|
|
14
|
-
rate_limit: number | null;
|
|
15
|
-
created_by: string;
|
|
16
|
-
created_at: string;
|
|
17
|
-
updated_at: string;
|
|
18
|
-
last_used_at: string | null;
|
|
19
|
-
expires_at: string | null;
|
|
20
|
-
revoked_at: string | null;
|
|
21
|
-
}
|
|
22
|
-
/** An API key including the full secret (returned only on creation). */
|
|
23
|
-
export interface ApiKeyWithSecret extends ApiKeyMasked {
|
|
24
|
-
key: string;
|
|
25
|
-
}
|
|
26
|
-
/** Payload for creating a new API key. */
|
|
27
|
-
export interface CreateApiKeyRequest {
|
|
28
|
-
name: string;
|
|
29
|
-
permissions: ApiKeyPermission[];
|
|
30
|
-
rate_limit?: number | null;
|
|
31
|
-
expires_at?: string | null;
|
|
32
|
-
}
|
|
33
|
-
/** Payload for updating an existing API key. */
|
|
34
|
-
export interface UpdateApiKeyRequest {
|
|
35
|
-
name?: string;
|
|
36
|
-
permissions?: ApiKeyPermission[];
|
|
37
|
-
rate_limit?: number | null;
|
|
38
|
-
expires_at?: string | null;
|
|
39
|
-
}
|
|
2
|
+
/**
|
|
3
|
+
* These were re-declared here, under a comment saying they lived in the server
|
|
4
|
+
* package rather than in `@rebasepro/types`. That stopped being true, and the
|
|
5
|
+
* copy drifted: it never gained `admin`, the flag that grants a key the `admin`
|
|
6
|
+
* role — admin routes plus the RLS `default_admin` policies — so the SDK could
|
|
7
|
+
* describe every kind of key except a privileged one, and
|
|
8
|
+
* `createKey({ …, admin: true })` was an excess-property error.
|
|
9
|
+
*/
|
|
10
|
+
export type { ApiKeyPermission, ApiKeyMasked, ApiKeyWithSecret, CreateApiKeyRequest, UpdateApiKeyRequest } from "@rebasepro/types";
|
|
11
|
+
import type { ApiKeyMasked, ApiKeyWithSecret, CreateApiKeyRequest, UpdateApiKeyRequest } from "@rebasepro/types";
|
|
40
12
|
/** Options for the `createApiKeys` factory. */
|
|
41
13
|
export interface CreateApiKeysOptions {
|
|
42
14
|
apiKeysPath?: string;
|
package/dist/auth.d.ts
CHANGED
|
@@ -128,6 +128,7 @@ export declare function createAuth(transport: Transport, options?: CreateAuthOpt
|
|
|
128
128
|
refreshToken: string;
|
|
129
129
|
}>;
|
|
130
130
|
signOut: () => Promise<void>;
|
|
131
|
+
stopAutoRefresh: () => void;
|
|
131
132
|
refreshSession: () => Promise<RebaseSession>;
|
|
132
133
|
handleUnauthorized: () => Promise<boolean>;
|
|
133
134
|
getUser: () => Promise<User>;
|
|
@@ -180,6 +181,7 @@ export declare function createAuth(transport: Transport, options?: CreateAuthOpt
|
|
|
180
181
|
getAuthConfig: () => Promise<AuthConfig>;
|
|
181
182
|
getSession: () => RebaseSession | null;
|
|
182
183
|
onAuthStateChange: (callback: (event: AuthChangeEvent, session: RebaseSession | null) => void) => () => boolean;
|
|
184
|
+
canRestoreSession: () => boolean;
|
|
183
185
|
isInitialized: () => Promise<void>;
|
|
184
186
|
};
|
|
185
187
|
export interface CookieStorageOptions {
|
package/dist/functions.d.ts
CHANGED
|
@@ -27,14 +27,8 @@ export interface FunctionsClient {
|
|
|
27
27
|
*/
|
|
28
28
|
invoke<T = unknown>(name: string, payload?: unknown, options?: FunctionInvokeOptions): Promise<T>;
|
|
29
29
|
}
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
33
|
-
/** Sub-path appended after the function name, e.g. `"status/123"`. */
|
|
34
|
-
path?: string;
|
|
35
|
-
/** Extra headers merged into the request (auth is still injected automatically). */
|
|
36
|
-
headers?: Record<string, string>;
|
|
37
|
-
}
|
|
30
|
+
export type { FunctionInvokeOptions } from "@rebasepro/types";
|
|
31
|
+
import type { FunctionInvokeOptions } from "@rebasepro/types";
|
|
38
32
|
/**
|
|
39
33
|
* Create a `FunctionsClient` backed by the given transport.
|
|
40
34
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,9 @@ export { RebaseClientError } from "./errors";
|
|
|
15
15
|
export type { RebaseClientConfig, FindParams, FindResponse } from "./transport";
|
|
16
16
|
export type { CollectionClient } from "./collection";
|
|
17
17
|
export type { FindResult, SDKCollectionClient, SDKQueryBuilderInterface, PaginationMeta } from "@rebasepro/types";
|
|
18
|
+
export type { IterateParams, FindAllParams, PageWalkOptions, CursorSpec } from "@rebasepro/types";
|
|
19
|
+
export { RebasePaginationError } from "@rebasepro/common";
|
|
20
|
+
export type { PaginationErrorCode } from "@rebasepro/common";
|
|
18
21
|
export { QueryBuilder, or, and, cond } from "@rebasepro/common";
|
|
19
22
|
export { createCookieStorage, createMemoryStorage } from "./auth";
|
|
20
23
|
export type { AuthConfig, AuthStorage, CookieStorageOptions, CreateAuthOptions } from "./auth";
|
|
@@ -117,11 +120,17 @@ export type CreateRebaseClientResult<DB = Record<string, unknown>> = Omit<Rebase
|
|
|
117
120
|
channel: (name: string, options?: ChannelOptions) => RebaseRealtimeChannel;
|
|
118
121
|
};
|
|
119
122
|
/**
|
|
120
|
-
* Release
|
|
123
|
+
* Release everything this client holds that can keep a process alive: the
|
|
124
|
+
* realtime socket and its reconnect timer, channel presence heartbeats, the
|
|
125
|
+
* offline manager, and the scheduled token refresh.
|
|
121
126
|
*
|
|
122
|
-
*
|
|
123
|
-
* call this will not exit
|
|
124
|
-
*
|
|
127
|
+
* Each of those keeps the Node event loop alive on its own, so a script
|
|
128
|
+
* that does not call this will not exit — and, until the refresh timer was
|
|
129
|
+
* included, one that *did* call it still would not if it had signed in.
|
|
130
|
+
*
|
|
131
|
+
* Safe when realtime was never started (`realtime: false`), safe when
|
|
132
|
+
* signed out, and safe to call twice. It does not sign the user out: a
|
|
133
|
+
* persisted session survives for the next client to restore.
|
|
125
134
|
*/
|
|
126
135
|
close: () => void;
|
|
127
136
|
storage: StorageSource;
|
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, PUBLIC_STORAGE_PREFIX, RebaseApiError, RebaseApiError as RebaseApiError$1, RebaseClientError, Vector, isPublicStoragePath, toCanonicalOp } from "@rebasepro/types";
|
|
2
|
-
import { COMPOSITE_ID_SEPARATOR, QueryBuilder, and, buildCompositeId, cond, or, serializeFilter, serializeLogicalCondition, serializeOrderBy } from "@rebasepro/common";
|
|
2
|
+
import { COMPOSITE_ID_SEPARATOR, QueryBuilder, RebasePaginationError, and, buildCompositeId, collectAllPages, cond, or, paginateFind, serializeFilter, serializeLogicalCondition, serializeOrderBy } from "@rebasepro/common";
|
|
3
3
|
import { toSnakeCase } from "@rebasepro/utils";
|
|
4
4
|
//#region src/reviver.ts
|
|
5
5
|
function rebaseReviver(_key, value) {
|
|
@@ -30,6 +30,25 @@ function rebaseReviver(_key, value) {
|
|
|
30
30
|
}
|
|
31
31
|
//#endregion
|
|
32
32
|
//#region src/transport.ts
|
|
33
|
+
/**
|
|
34
|
+
* True when there is no browser to have signed a user in — a Node script, a
|
|
35
|
+
* cron job, an edge worker.
|
|
36
|
+
*
|
|
37
|
+
* Anonymous is an ordinary, correct state in a browser: before sign-in, on a
|
|
38
|
+
* marketing page, for public reads. Warning there would be noise that teaches
|
|
39
|
+
* people to ignore warnings, so the guard is off entirely. This uses the same
|
|
40
|
+
* `typeof window` test as {@link resolveBaseUrl}, and additionally treats a
|
|
41
|
+
* defined `document` as a browser so an SSR shim or test harness that installs
|
|
42
|
+
* only one of the two is still excluded.
|
|
43
|
+
*/
|
|
44
|
+
function isServerLikeEnvironment() {
|
|
45
|
+
return typeof window === "undefined" && typeof document === "undefined";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Emitted once per client. Kept as a constant so the wording is testable and
|
|
49
|
+
* greppable — this is the string a user will paste into a search.
|
|
50
|
+
*/
|
|
51
|
+
var ANONYMOUS_SERVER_CLIENT_WARNING = "[rebase] This client was created outside a browser with no credential — no `token`, no auth token getter, and no cookie auth flow — so every request runs as an anonymous caller. Row-level security will return only publicly readable rows, which is usually nothing and occasionally the wrong thing. Inside a cron or function handler, use the `client` you were handed instead of building a new one: its data plane is already admin-scoped. In a standalone script or job, pass the service key as `token`. If you really do want anonymous access, pass `anonymous: true` to silence this.";
|
|
33
52
|
function buildQueryString(params) {
|
|
34
53
|
if (!params) return "";
|
|
35
54
|
const parts = [];
|
|
@@ -76,12 +95,31 @@ function resolveBaseUrl(configured) {
|
|
|
76
95
|
if (typeof window !== "undefined" && window.location?.origin) return window.location.origin;
|
|
77
96
|
return "";
|
|
78
97
|
}
|
|
79
|
-
function createTransport(config) {
|
|
98
|
+
function createTransport(config, environment) {
|
|
80
99
|
const fetchFn = config.fetch || globalThis.fetch;
|
|
81
100
|
const apiPath = config.apiPath || "/api";
|
|
82
101
|
let token = config.token;
|
|
83
102
|
let tokenGetter;
|
|
84
103
|
let onUnauthorizedHandler = config.onUnauthorized;
|
|
104
|
+
/** Once per client, never per request — log spam is its own bug. */
|
|
105
|
+
let anonymousWarningIssued = false;
|
|
106
|
+
/**
|
|
107
|
+
* Warn a server-side caller that it built a client that can only ever be
|
|
108
|
+
* anonymous. Deliberately checked at the *first request* rather than at
|
|
109
|
+
* construction: `setToken()` / `setAuthTokenGetter()` and a server-side
|
|
110
|
+
* `auth.signIn…()` (which calls `transport.setToken`) all land after the
|
|
111
|
+
* constructor, and warning at construction would fire on every one of them.
|
|
112
|
+
*/
|
|
113
|
+
function warnIfAnonymousServerClient(activeToken) {
|
|
114
|
+
if (anonymousWarningIssued) return;
|
|
115
|
+
if (activeToken) return;
|
|
116
|
+
if (tokenGetter) return;
|
|
117
|
+
if (config.anonymous) return;
|
|
118
|
+
if (environment?.credentialOutOfBand) return;
|
|
119
|
+
if (!isServerLikeEnvironment()) return;
|
|
120
|
+
anonymousWarningIssued = true;
|
|
121
|
+
console.warn(ANONYMOUS_SERVER_CLIENT_WARNING);
|
|
122
|
+
}
|
|
85
123
|
function getHeaders(activeToken, init) {
|
|
86
124
|
return {
|
|
87
125
|
"Content-Type": "application/json",
|
|
@@ -96,6 +134,7 @@ function createTransport(config) {
|
|
|
96
134
|
const fetched = await tokenGetter();
|
|
97
135
|
if (fetched !== null && fetched !== void 0) activeToken = fetched;
|
|
98
136
|
} catch (e) {}
|
|
137
|
+
warnIfAnonymousServerClient(activeToken);
|
|
99
138
|
const headers = getHeaders(activeToken, init);
|
|
100
139
|
if (init?.body instanceof FormData) delete headers["Content-Type"];
|
|
101
140
|
const res = await fetchFn(url, {
|
|
@@ -379,6 +418,29 @@ function createAuth(transport, options) {
|
|
|
379
418
|
attemptScheduledRefresh(0);
|
|
380
419
|
}, delay);
|
|
381
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Stop the scheduled token refresh, leaving the session itself alone.
|
|
423
|
+
*
|
|
424
|
+
* This is teardown, not sign-out. `scheduleRefresh` arms an ordinary
|
|
425
|
+
* `setTimeout` up to a token lifetime away, and it is not `unref`'d — so on
|
|
426
|
+
* Node it holds the event loop open by itself. `client.close()` promised
|
|
427
|
+
* that "a script that does not call this will not exit on its own", which
|
|
428
|
+
* was true, while the converse it plainly implies was not: a signed-in
|
|
429
|
+
* client that closed its socket still hung, because this timer outlived it.
|
|
430
|
+
* Any script, cron handler or job that signs in hit that.
|
|
431
|
+
*
|
|
432
|
+
* Deliberately does NOT clear the session, touch storage, or emit
|
|
433
|
+
* SIGNED_OUT. Closing a client is not the user signing out — `signOut()`
|
|
434
|
+
* POSTs /logout and revokes the whole sign-in, which is the wrong hammer
|
|
435
|
+
* (see `abandonSessionLocally`) — and a persisted session must still be
|
|
436
|
+
* there for the next client to restore.
|
|
437
|
+
*/
|
|
438
|
+
function stopAutoRefresh() {
|
|
439
|
+
if (refreshTimeout) {
|
|
440
|
+
clearTimeout(refreshTimeout);
|
|
441
|
+
refreshTimeout = null;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
382
444
|
function handleAuthResponse(data, event) {
|
|
383
445
|
const user = mapRawUser(data.user);
|
|
384
446
|
const session = {
|
|
@@ -849,6 +911,7 @@ function createAuth(transport, options) {
|
|
|
849
911
|
signInWithSlack,
|
|
850
912
|
signInWithSpotify,
|
|
851
913
|
signOut,
|
|
914
|
+
stopAutoRefresh,
|
|
852
915
|
refreshSession,
|
|
853
916
|
handleUnauthorized,
|
|
854
917
|
getUser,
|
|
@@ -868,6 +931,7 @@ function createAuth(transport, options) {
|
|
|
868
931
|
getAuthConfig,
|
|
869
932
|
getSession,
|
|
870
933
|
onAuthStateChange,
|
|
934
|
+
canRestoreSession: () => persistSession || authFlowMode === "cookie",
|
|
871
935
|
isInitialized: () => isInitialized
|
|
872
936
|
};
|
|
873
937
|
}
|
|
@@ -1184,6 +1248,12 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
1184
1248
|
meta: raw.meta
|
|
1185
1249
|
};
|
|
1186
1250
|
},
|
|
1251
|
+
iterate(params) {
|
|
1252
|
+
return paginateFind((p) => client.find(p), params, slug);
|
|
1253
|
+
},
|
|
1254
|
+
findAll(params) {
|
|
1255
|
+
return collectAllPages((p) => client.find(p), params, slug);
|
|
1256
|
+
},
|
|
1187
1257
|
async findById(id) {
|
|
1188
1258
|
try {
|
|
1189
1259
|
const raw = await transport.request(`${basePath}/${encodeURIComponent(String(id))}`, { method: "GET" });
|
|
@@ -1373,7 +1443,8 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
1373
1443
|
function createFunctionsClient(transport) {
|
|
1374
1444
|
return { async invoke(name, payload, options) {
|
|
1375
1445
|
const method = options?.method ?? "POST";
|
|
1376
|
-
const
|
|
1446
|
+
const rawPath = options?.path;
|
|
1447
|
+
const subPath = rawPath ? /^[?#]/.test(rawPath) ? rawPath : `/${rawPath.replace(/^\//, "")}` : "";
|
|
1377
1448
|
const routePath = `/functions/${encodeURIComponent(name)}${subPath}`;
|
|
1378
1449
|
const init = { method };
|
|
1379
1450
|
if (payload !== void 0 && method !== "GET") init.body = JSON.stringify(payload);
|
|
@@ -1587,7 +1658,7 @@ function extractMessageError(message) {
|
|
|
1587
1658
|
* Fire-and-forget (the server sends no response envelope), and exempt from the
|
|
1588
1659
|
* client-side auth gate — a public channel is usable without an account.
|
|
1589
1660
|
*/
|
|
1590
|
-
var CHANNEL_MESSAGE_TYPES = new Set([
|
|
1661
|
+
var CHANNEL_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
1591
1662
|
"join_channel",
|
|
1592
1663
|
"leave_channel",
|
|
1593
1664
|
"broadcast",
|
|
@@ -1616,6 +1687,17 @@ var RebaseWebSocketClient = class {
|
|
|
1616
1687
|
/** Set by `close()`. Blocks any later operation from silently redialling. */
|
|
1617
1688
|
closedByCaller = false;
|
|
1618
1689
|
/**
|
|
1690
|
+
* Set when the backoff budget ran out, cleared by anything that earns a
|
|
1691
|
+
* fresh one.
|
|
1692
|
+
*
|
|
1693
|
+
* Unlike {@link closedByCaller} this is not final — nobody *asked* for the
|
|
1694
|
+
* socket to stay down. Five attempts with exponential backoff is about a
|
|
1695
|
+
* minute, which a laptop lid, a wifi handover or a backend rollout all
|
|
1696
|
+
* exceed routinely; treating that as permanent meant realtime silently
|
|
1697
|
+
* stopped for the rest of the page's life, with a reload the only cure.
|
|
1698
|
+
*/
|
|
1699
|
+
gaveUp = false;
|
|
1700
|
+
/**
|
|
1619
1701
|
* Whether a socket exists at all (open or still opening).
|
|
1620
1702
|
*
|
|
1621
1703
|
* Lets callers distinguish "authenticate the live socket" from "there is
|
|
@@ -1688,10 +1770,30 @@ var RebaseWebSocketClient = class {
|
|
|
1688
1770
|
}
|
|
1689
1771
|
return;
|
|
1690
1772
|
}
|
|
1773
|
+
this.installOnlineListener();
|
|
1691
1774
|
if (this.ws || this.reconnectTimeout) return;
|
|
1775
|
+
if (this.gaveUp) {
|
|
1776
|
+
this.gaveUp = false;
|
|
1777
|
+
this.reconnectAttempts = 0;
|
|
1778
|
+
}
|
|
1692
1779
|
this.initWebSocket();
|
|
1693
1780
|
}
|
|
1694
1781
|
/**
|
|
1782
|
+
* The browser says the network is back — the usual reason the budget ran
|
|
1783
|
+
* out in the first place. Registered lazily so a Node client, or a page
|
|
1784
|
+
* that never subscribes, adds no listener.
|
|
1785
|
+
*/
|
|
1786
|
+
installOnlineListener() {
|
|
1787
|
+
if (this.onlineListener || typeof window === "undefined" || typeof window.addEventListener !== "function") return;
|
|
1788
|
+
this.onlineListener = () => {
|
|
1789
|
+
if (this.closedByCaller || !this.gaveUp) return;
|
|
1790
|
+
console.debug("Network is back — retrying the realtime connection");
|
|
1791
|
+
this.ensureConnected();
|
|
1792
|
+
};
|
|
1793
|
+
window.addEventListener("online", this.onlineListener);
|
|
1794
|
+
}
|
|
1795
|
+
onlineListener = null;
|
|
1796
|
+
/**
|
|
1695
1797
|
* Authenticate the WebSocket connection
|
|
1696
1798
|
*/
|
|
1697
1799
|
async authenticate(token) {
|
|
@@ -1749,6 +1851,10 @@ var RebaseWebSocketClient = class {
|
|
|
1749
1851
|
*/
|
|
1750
1852
|
disconnect(permanent = false) {
|
|
1751
1853
|
if (permanent) this.closedByCaller = true;
|
|
1854
|
+
if (permanent && this.onlineListener && typeof window !== "undefined") {
|
|
1855
|
+
window.removeEventListener("online", this.onlineListener);
|
|
1856
|
+
this.onlineListener = null;
|
|
1857
|
+
}
|
|
1752
1858
|
this.isAuthenticated = false;
|
|
1753
1859
|
this.authPromise = null;
|
|
1754
1860
|
if (this.reconnectTimeout) {
|
|
@@ -1773,7 +1879,8 @@ var RebaseWebSocketClient = class {
|
|
|
1773
1879
|
this.ws = null;
|
|
1774
1880
|
}
|
|
1775
1881
|
try {
|
|
1776
|
-
|
|
1882
|
+
const socket = new this.WebSocketConstructor(this.websocketUrl);
|
|
1883
|
+
this.ws = socket;
|
|
1777
1884
|
this.ws.onopen = async () => {
|
|
1778
1885
|
console.debug("Connected to PostgreSQL backend");
|
|
1779
1886
|
const wasReconnect = this.reconnectAttempts > 0;
|
|
@@ -1803,6 +1910,7 @@ var RebaseWebSocketClient = class {
|
|
|
1803
1910
|
};
|
|
1804
1911
|
this.ws.onclose = () => {
|
|
1805
1912
|
console.debug("Disconnected from PostgreSQL backend");
|
|
1913
|
+
if (this.ws === socket) this.ws = null;
|
|
1806
1914
|
this.isConnected = false;
|
|
1807
1915
|
this.isAuthenticated = false;
|
|
1808
1916
|
this.authPromise = null;
|
|
@@ -1838,6 +1946,7 @@ var RebaseWebSocketClient = class {
|
|
|
1838
1946
|
attemptReconnect() {
|
|
1839
1947
|
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
1840
1948
|
console.error("Max reconnection attempts reached");
|
|
1949
|
+
this.gaveUp = true;
|
|
1841
1950
|
this.failAllPendingSubscriptions(new RebaseApiError$1("Connection lost", { code: "CONNECTION_LOST" }));
|
|
1842
1951
|
return;
|
|
1843
1952
|
}
|
|
@@ -2380,7 +2489,7 @@ var RebaseWebSocketClient = class {
|
|
|
2380
2489
|
if (this.deepEqual(normCached, normIncoming)) return cachedRow;
|
|
2381
2490
|
else {
|
|
2382
2491
|
const mismatches = {};
|
|
2383
|
-
const allKeys = new Set([...Object.keys(normCached), ...Object.keys(normIncoming)]);
|
|
2492
|
+
const allKeys = /* @__PURE__ */ new Set([...Object.keys(normCached), ...Object.keys(normIncoming)]);
|
|
2384
2493
|
for (const key of allKeys) if (!this.deepEqual(normCached[key], normIncoming[key])) mismatches[key] = {
|
|
2385
2494
|
cached: normCached[key],
|
|
2386
2495
|
incoming: normIncoming[key]
|
|
@@ -3183,7 +3292,7 @@ function isNetworkError(error) {
|
|
|
3183
3292
|
* bug the same payload will hit again than a blip, and retrying it forever
|
|
3184
3293
|
* jams every write behind it.
|
|
3185
3294
|
*/
|
|
3186
|
-
var RETRYABLE_STATUSES = new Set([
|
|
3295
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([
|
|
3187
3296
|
408,
|
|
3188
3297
|
425,
|
|
3189
3298
|
429,
|
|
@@ -4008,6 +4117,8 @@ var OfflineManager = class {
|
|
|
4008
4117
|
meta: answer.meta
|
|
4009
4118
|
};
|
|
4010
4119
|
},
|
|
4120
|
+
iterate: (params) => paginateFind((p) => wrapped.find(p), params, slug),
|
|
4121
|
+
findAll: (params) => collectAllPages((p) => wrapped.find(p), params, slug),
|
|
4011
4122
|
findById: async (id) => {
|
|
4012
4123
|
await this.ensureCollection(slug);
|
|
4013
4124
|
if (this.connectivity.shouldAttempt()) try {
|
|
@@ -5077,7 +5188,7 @@ function deriveWebSocketUrl(baseUrl) {
|
|
|
5077
5188
|
return baseUrl.replace(/^https?:\/\//i, (match) => match.toLowerCase() === "https://" ? "wss://" : "ws://").replace(/\/$/, "");
|
|
5078
5189
|
}
|
|
5079
5190
|
function createRebaseClient(options) {
|
|
5080
|
-
const transport = createTransport(options);
|
|
5191
|
+
const transport = createTransport(options, { credentialOutOfBand: options.auth?.authFlowMode === "cookie" });
|
|
5081
5192
|
const auth = createAuth(transport, options.auth);
|
|
5082
5193
|
const admin = createAdmin(transport, options.admin);
|
|
5083
5194
|
const cron = createCron(transport, options.cron);
|
|
@@ -5231,23 +5342,25 @@ channel: (name, options) => {
|
|
|
5231
5342
|
return existing;
|
|
5232
5343
|
} },
|
|
5233
5344
|
/**
|
|
5234
|
-
* Release
|
|
5345
|
+
* Release every handle that can keep a process alive — see the
|
|
5346
|
+
* `close` docblock on the client interface.
|
|
5235
5347
|
*
|
|
5236
|
-
*
|
|
5237
|
-
* and
|
|
5238
|
-
* was never started, and safe to call twice.
|
|
5348
|
+
* Safe to call when realtime was never started, safe when signed out,
|
|
5349
|
+
* and safe to call twice.
|
|
5239
5350
|
*/
|
|
5240
5351
|
close: () => {
|
|
5241
5352
|
for (const channel of realtimeChannels.values()) channel.leave();
|
|
5242
5353
|
realtimeChannels.clear();
|
|
5243
5354
|
ws?.disconnect(true);
|
|
5244
5355
|
offlineManager?.dispose();
|
|
5356
|
+
auth.stopAutoRefresh();
|
|
5245
5357
|
},
|
|
5246
5358
|
setToken: transport.setToken,
|
|
5247
5359
|
setAuthTokenGetter: transport.setAuthTokenGetter,
|
|
5248
5360
|
setOnUnauthorized: transport.setOnUnauthorized,
|
|
5249
5361
|
resolveToken: transport.resolveToken,
|
|
5250
5362
|
baseUrl: transport.baseUrl,
|
|
5363
|
+
apiPath: transport.apiPath,
|
|
5251
5364
|
collection,
|
|
5252
5365
|
call: async (endpoint, payload) => {
|
|
5253
5366
|
const prefix = endpoint.startsWith("/") ? "" : "/";
|
|
@@ -5262,6 +5375,6 @@ channel: (name, options) => {
|
|
|
5262
5375
|
};
|
|
5263
5376
|
}
|
|
5264
5377
|
//#endregion
|
|
5265
|
-
export { MemoryOfflineStore, QueryBuilder, RebaseApiError, RebaseClientError, RebaseRealtimeChannel, RebaseWebSocketClient, and, cond, createBackups, createCookieStorage, createMemoryStorage, createRebaseClient, isOfflineError, or };
|
|
5378
|
+
export { MemoryOfflineStore, QueryBuilder, RebaseApiError, RebaseClientError, RebasePaginationError, RebaseRealtimeChannel, RebaseWebSocketClient, and, cond, createBackups, createCookieStorage, createMemoryStorage, createRebaseClient, isOfflineError, or };
|
|
5266
5379
|
|
|
5267
5380
|
//# sourceMappingURL=index.es.js.map
|