@rebasepro/client 0.10.0 → 0.10.1-canary.31c773c
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/README.md +9 -1
- package/dist/collection.d.ts +55 -3
- package/dist/index.d.ts +23 -0
- package/dist/index.es.js +1963 -4
- package/dist/index.es.js.map +1 -1
- package/dist/offline-codec.d.ts +4 -0
- package/dist/offline-connectivity.d.ts +78 -0
- package/dist/offline-query.d.ts +51 -0
- package/dist/offline-store.d.ts +150 -0
- package/dist/offline.d.ts +306 -0
- package/package.json +5 -4
- package/src/collection.ts +118 -2
- package/src/index.ts +58 -1
- package/src/offline-codec.ts +79 -0
- package/src/offline-connectivity.test.ts +157 -0
- package/src/offline-connectivity.ts +207 -0
- package/src/offline-idb-store.test.ts +286 -0
- package/src/offline-integration.test.ts +175 -0
- package/src/offline-query.test.ts +249 -0
- package/src/offline-query.ts +356 -0
- package/src/offline-store.ts +353 -0
- package/src/offline-sync-engine.test.ts +676 -0
- package/src/offline.test.ts +719 -0
- package/src/offline.ts +1647 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @rebasepro/client
|
|
2
2
|
|
|
3
|
-
HTTP SDK client for the Rebase backend — typed CRUD, auth, storage, realtime WebSockets, admin, cron, and custom functions.
|
|
3
|
+
HTTP SDK client for the Rebase backend — typed CRUD, auth, storage, realtime WebSockets, offline / local-first sync, admin, cron, and custom functions.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -17,6 +17,7 @@ pnpm add @rebasepro/client
|
|
|
17
17
|
- **Admin** — user CRUD for admins
|
|
18
18
|
- **Storage** — file upload, download, delete, list
|
|
19
19
|
- **Realtime** — WebSocket subscriptions for collection and snapshot changes
|
|
20
|
+
- **Offline / local-first sync** (opt-in) — a local row database, writes that apply instantly offline and replay when the connection returns, and live queries
|
|
20
21
|
- **Cron** — list, trigger, and manage cron jobs
|
|
21
22
|
- **Custom functions** — invoke server-side Hono route functions
|
|
22
23
|
- **Type-safe data proxy** — `client.data.products` auto-maps to the `products` collection
|
|
@@ -41,6 +42,9 @@ pnpm add @rebasepro/client
|
|
|
41
42
|
| `fetch` | `typeof fetch` | `globalThis.fetch` | Custom fetch implementation |
|
|
42
43
|
| `onUnauthorized` | `() => Promise<boolean>` | auto-refresh | Handler for 401 responses |
|
|
43
44
|
| `websocketUrl` | `string` | derived from `baseUrl` | WebSocket URL for realtime |
|
|
45
|
+
| `realtime` | `boolean` | `true` | Open the WebSocket — `false` lets a one-shot script exit |
|
|
46
|
+
| `collections` | `Record<string, string>` | — | Maps accessor names to collection slugs |
|
|
47
|
+
| `offline` | `boolean \| OfflineConfig` | `false` | Local-first sync — see [the docs](https://rebase.pro/docs/sdk/offline) |
|
|
44
48
|
|
|
45
49
|
### Collection Client
|
|
46
50
|
|
|
@@ -61,6 +65,8 @@ pnpm add @rebasepro/client
|
|
|
61
65
|
| `include(...rels)` | Include related snapshots — returns `QueryBuilder` |
|
|
62
66
|
| `listen(params, onUpdate, onError?)` | Realtime subscription (requires WebSocket) |
|
|
63
67
|
| `listenById(id, onUpdate, onError?)` | Realtime single-snapshot subscription |
|
|
68
|
+
| `observe(params, onResult, onError?, options?)` | Live query — local-first when `offline` is on, otherwise fetch + `listen` |
|
|
69
|
+
| `observeById(id, onResult, onError?, options?)` | Live query for a single row |
|
|
64
70
|
|
|
65
71
|
### Auth Module (`client.auth`)
|
|
66
72
|
|
|
@@ -116,6 +122,8 @@ pnpm add @rebasepro/client
|
|
|
116
122
|
|---|---|
|
|
117
123
|
| `RebaseApiError` | Error class with `status`, `message`, `code`, `details` |
|
|
118
124
|
| `RebaseWebSocketClient` | WebSocket client for realtime subscriptions |
|
|
125
|
+
| `isOfflineError(error)` | True when a read failed with no network *and* nothing cached |
|
|
126
|
+
| `MemoryOfflineStore` | Reference `OfflineStore`; the IndexedDB one is wired automatically |
|
|
119
127
|
| `createCookieStorage(options?)` | Cookie-based auth storage adapter |
|
|
120
128
|
| `createMemoryStorage()` | In-memory auth storage adapter |
|
|
121
129
|
| `QueryBuilder` | Fluent query builder (also re-exported from `@rebasepro/common`) |
|
package/dist/collection.d.ts
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
import { FindParams, Transport } from "./transport";
|
|
2
2
|
import { RebaseWebSocketClient } from "./websocket";
|
|
3
|
-
import { SDKCollectionClient } from "@rebasepro/types";
|
|
3
|
+
import { FindResult, SDKCollectionClient } from "@rebasepro/types";
|
|
4
|
+
/**
|
|
5
|
+
* A live query result: a normal {@link FindResult} plus what an interface
|
|
6
|
+
* needs to decide whether to show a "saving…" or "offline" affordance over it.
|
|
7
|
+
*
|
|
8
|
+
* The three flags are always `false` on a client without offline support —
|
|
9
|
+
* every result there came straight from the server.
|
|
10
|
+
*/
|
|
11
|
+
export interface LiveResult<M extends Record<string, unknown>> extends FindResult<M> {
|
|
12
|
+
/** The data came from the local database, not from a completed request. */
|
|
13
|
+
fromCache: boolean;
|
|
14
|
+
/** At least one row here carries a write the server has not accepted yet. */
|
|
15
|
+
hasPendingWrites: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The local database may not hold every row the server would have
|
|
18
|
+
* returned, so treat this as a best effort rather than a complete answer.
|
|
19
|
+
*/
|
|
20
|
+
partial: boolean;
|
|
21
|
+
/** The most recent revalidation failure, when the last one failed. */
|
|
22
|
+
error?: Error;
|
|
23
|
+
}
|
|
24
|
+
/** Snapshot metadata for a single observed row. */
|
|
25
|
+
export interface RowSnapshotMeta {
|
|
26
|
+
fromCache: boolean;
|
|
27
|
+
hasPendingWrites: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ObserveOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Keep the subscription live off the realtime socket, so changes made by
|
|
32
|
+
* other clients arrive without a refetch. On by default whenever realtime
|
|
33
|
+
* is enabled on the client; pass `false` for a one-shot read that still
|
|
34
|
+
* reports offline/pending metadata.
|
|
35
|
+
*/
|
|
36
|
+
realtime?: boolean;
|
|
37
|
+
}
|
|
4
38
|
/**
|
|
5
39
|
* The concrete, HTTP-backed implementation of the public
|
|
6
40
|
* {@link SDKCollectionClient} contract — flat rows (no Entity wrapper), plus
|
|
@@ -8,10 +42,28 @@ import { SDKCollectionClient } from "@rebasepro/types";
|
|
|
8
42
|
*
|
|
9
43
|
* This is what `createRebaseClient().data.<collection>` returns. It is not a
|
|
10
44
|
* separate API from {@link SDKCollectionClient}; it only widens it with
|
|
11
|
-
* `count()
|
|
12
|
-
* transport-agnostic type.
|
|
45
|
+
* `count()` and the reactive `observe()` pair. Program against
|
|
46
|
+
* {@link SDKCollectionClient} when you want a transport-agnostic type.
|
|
13
47
|
*/
|
|
14
48
|
export interface CollectionClient<M extends Record<string, unknown> = Record<string, unknown>, I = Partial<M>, U = Partial<M>> extends SDKCollectionClient<M, I, U> {
|
|
15
49
|
count(params?: FindParams): Promise<number>;
|
|
50
|
+
/**
|
|
51
|
+
* Subscribe to a query's results.
|
|
52
|
+
*
|
|
53
|
+
* This is the reactive read primitive, and the one to reach for in a UI:
|
|
54
|
+
* unlike `find()` it keeps emitting. On a client with `offline` enabled it
|
|
55
|
+
* is local-first — the first emission comes from the local database, with
|
|
56
|
+
* no request in the way — and re-emits on every local write, every queued
|
|
57
|
+
* write reaching the server, and every rollback. With realtime enabled it
|
|
58
|
+
* also re-emits on changes made by other clients.
|
|
59
|
+
*
|
|
60
|
+
* Emissions are de-duplicated: a refresh that changes nothing does not
|
|
61
|
+
* call back.
|
|
62
|
+
*
|
|
63
|
+
* @returns An unsubscribe function.
|
|
64
|
+
*/
|
|
65
|
+
observe(params: FindParams | undefined, onResult: (result: LiveResult<M>) => void, onError?: (error: Error) => void, options?: ObserveOptions): () => void;
|
|
66
|
+
/** {@link CollectionClient.observe} for a single row. */
|
|
67
|
+
observeById(id: string | number, onResult: (row: M | undefined, meta: RowSnapshotMeta) => void, onError?: (error: Error) => void, options?: ObserveOptions): () => void;
|
|
16
68
|
}
|
|
17
69
|
export declare function createCollectionClient<M extends Record<string, unknown> = Record<string, unknown>>(transport: Transport, slug: string, ws?: RebaseWebSocketClient): CollectionClient<M>;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { CollectionClient } from "./collection";
|
|
|
8
8
|
import { createFunctionsClient } from "./functions";
|
|
9
9
|
import { RebaseWebSocketClient } from "./websocket";
|
|
10
10
|
import { RebaseRealtimeChannel, type ChannelOptions } from "./realtime-channel";
|
|
11
|
+
import { type OfflineApi, type OfflineConfig } from "./offline";
|
|
11
12
|
import { InsertOf, RebaseClient, RebaseSdkData, RowOf, StorageSource, StorageSourceDefinition, StorageSourceRegistry, UpdateOf } from "@rebasepro/types";
|
|
12
13
|
export { RebaseApiError } from "./transport";
|
|
13
14
|
export { RebaseClientError } from "./errors";
|
|
@@ -30,6 +31,11 @@ export type { FunctionInvokeOptions, FunctionsClient } from "./functions";
|
|
|
30
31
|
export { RebaseWebSocketClient } from "./websocket";
|
|
31
32
|
export { RebaseRealtimeChannel } from "./realtime-channel";
|
|
32
33
|
export type { PresenceState, PresenceDiff, BroadcastEvent, ChannelTransport, ChannelOptions, ChannelHistoryEntry, ChannelHistoryResult } from "./realtime-channel";
|
|
34
|
+
export type { OfflineApi, OfflineConfig, OfflineStatus } from "./offline";
|
|
35
|
+
export { isOfflineError } from "./offline";
|
|
36
|
+
export type { LiveResult, ObserveOptions, RowSnapshotMeta } from "./collection";
|
|
37
|
+
export type { OfflineStore, OfflineCacheEntry, OfflineCacheRecord, PendingMutation, MutationRollback } from "./offline-store";
|
|
38
|
+
export { MemoryOfflineStore } from "./offline-store";
|
|
33
39
|
export interface CreateRebaseClientOptions extends RebaseClientConfig {
|
|
34
40
|
auth?: CreateAuthOptions;
|
|
35
41
|
admin?: CreateAdminOptions;
|
|
@@ -50,6 +56,21 @@ export interface CreateRebaseClientOptions extends RebaseClientConfig {
|
|
|
50
56
|
* correct slugs via this map before falling back to automatic snake_casing.
|
|
51
57
|
*/
|
|
52
58
|
collections?: Record<string, string>;
|
|
59
|
+
/**
|
|
60
|
+
* Local-first sync for the data layer.
|
|
61
|
+
*
|
|
62
|
+
* `true` enables it with defaults: reads populate a local row database and
|
|
63
|
+
* fall back to it (evaluating filters and sorts locally) when the network
|
|
64
|
+
* is gone, writes made offline apply immediately and replay in order when
|
|
65
|
+
* it returns, and `observe()` becomes a live query that emits from the
|
|
66
|
+
* local database first. A rejected write is rolled back. Pass an
|
|
67
|
+
* {@link OfflineConfig} to control the store, cache sizes, retry backoff,
|
|
68
|
+
* or rejection handling.
|
|
69
|
+
*
|
|
70
|
+
* Local rows and queued writes are partitioned per signed-in user, and
|
|
71
|
+
* shared across tabs. Off by default.
|
|
72
|
+
*/
|
|
73
|
+
offline?: boolean | OfflineConfig;
|
|
53
74
|
}
|
|
54
75
|
type KebabToCamelCase<S extends string> = S extends `${infer T}-${infer U}` ? `${T}${Capitalize<KebabToCamelCase<U>>}` : S;
|
|
55
76
|
type DBEntry<DB, S extends string> = KebabToCamelCase<S> extends keyof DB ? DB[KebabToCamelCase<S>] : unknown;
|
|
@@ -110,5 +131,7 @@ export type CreateRebaseClientResult<DB = Record<string, unknown>> = Omit<Rebase
|
|
|
110
131
|
call: <T = unknown>(endpoint: string, payload?: unknown) => Promise<T>;
|
|
111
132
|
collection: <M extends Record<string, unknown> = Record<string, unknown>>(slug: string) => CollectionClient<M>;
|
|
112
133
|
data: TypedDataLayer<DB>;
|
|
134
|
+
/** Present only when the client was created with `offline` enabled. */
|
|
135
|
+
offline?: OfflineApi;
|
|
113
136
|
};
|
|
114
137
|
export declare function createRebaseClient<DB = Record<string, unknown>>(options: CreateRebaseClientOptions): CreateRebaseClientResult<DB>;
|