@basictech/react 0.9.0-beta.0 → 0.11.0-beta.1
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/LICENSE +21 -0
- package/README.md +1101 -0
- package/dist/index.d.mts +236 -1119
- package/dist/index.d.ts +236 -1119
- package/dist/index.js +1010 -4117
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +980 -4070
- package/dist/index.mjs.map +1 -1
- package/package.json +23 -20
- package/changelog.md +0 -408
- package/readme.md +0 -413
package/dist/index.d.mts
CHANGED
|
@@ -1,1152 +1,269 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, ReactElement } from 'react';
|
|
3
|
+
import { BasicSchema, BasicConfig, BasicClient, BasicProfile, AuthStatus, BasicError, AuthUser, BasicSyncStatus, BasicRejection, BasicConflict, SourceRef, SchemaStatus, BasicDb, Repo, FileRecord, MountFileInfo, StorageInfo, FileListQuery, MountInfo, MountHandle, OutgoingShareInfo, CreateOutgoingShareInput, MountsQuery, JsonObject, BasicRecord, Query, MountViewerFiles, OwnerFiles, TableNames, Collection, InferValue, KeyValueStorage, TokenStore, AuthMessageChannel, ReplicaStoreFactory, StoragePartition, ReplicaStore, UploadTransportAdapter } from '@basictech/core';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
remove(key: string): Promise<void>;
|
|
9
|
-
}
|
|
10
|
-
declare class LocalStorageAdapter implements BasicStorage {
|
|
11
|
-
get(key: string): Promise<string | null>;
|
|
12
|
-
set(key: string, value: string): Promise<void>;
|
|
13
|
-
remove(key: string): Promise<void>;
|
|
14
|
-
}
|
|
15
|
-
declare const STORAGE_KEYS: {
|
|
16
|
-
readonly REFRESH_TOKEN: "basic_refresh_token";
|
|
17
|
-
readonly USER_INFO: "basic_user_info";
|
|
18
|
-
readonly AUTH_STATE: "basic_auth_state";
|
|
19
|
-
readonly REDIRECT_URI: "basic_redirect_uri";
|
|
20
|
-
readonly SERVER_URL: "basic_server_url";
|
|
21
|
-
readonly PDS_ENDPOINTS: "basic_pds_endpoints";
|
|
22
|
-
readonly LAST_CONNECT_REPORT: "basic_last_connect_report";
|
|
23
|
-
readonly DEBUG: "basic_debug";
|
|
24
|
-
readonly CODE_VERIFIER: "basic_code_verifier";
|
|
25
|
-
};
|
|
5
|
+
type BrowserBasicConfig<S extends BasicSchema = BasicSchema> = BasicConfig<S>;
|
|
6
|
+
/** Create a core client with the complete browser adapter set installed. */
|
|
7
|
+
declare function createBasicClient<S extends BasicSchema>(config: BrowserBasicConfig<S>): BasicClient<S>;
|
|
26
8
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* High-level auth lifecycle state.
|
|
41
|
-
*
|
|
42
|
-
* - `bootstrapping` — SDK is initializing; not yet determined if a session exists.
|
|
43
|
-
* - `authenticated` — User has a valid access token and active session.
|
|
44
|
-
* - `recovering` — A session likely exists (refresh token / cached user) but
|
|
45
|
-
* the SDK hasn't confirmed it yet (e.g. offline, mid-refresh).
|
|
46
|
-
* - `reauth_required` — The session is definitively invalid (revoked, expired
|
|
47
|
-
* refresh token, etc.). The user must sign in again.
|
|
48
|
-
* NOTE: `isSignedIn` remains `true` in this state so the UI
|
|
49
|
-
* can display user info while prompting re-authentication.
|
|
50
|
-
* Use `authStatus === 'reauth_required'` to distinguish
|
|
51
|
-
* this from a healthy signed-in state.
|
|
52
|
-
* - `signed_out` — No session. User is not authenticated.
|
|
53
|
-
*
|
|
54
|
-
* TODO: revisit naming and ergonomics — consider adding a `needsReauth` or
|
|
55
|
-
* `shouldPromptSignIn` convenience getter so consumers don't need to inspect
|
|
56
|
-
* the raw status to decide between "sign in" vs "sign out" UI.
|
|
57
|
-
*/
|
|
58
|
-
type AuthStatus = 'bootstrapping' | 'authenticated' | 'recovering' | 'reauth_required' | 'signed_out';
|
|
59
|
-
type AuthResult = {
|
|
60
|
-
success: boolean;
|
|
61
|
-
error?: string;
|
|
62
|
-
code?: string;
|
|
63
|
-
};
|
|
64
|
-
type GetTokenOptions$1 = {
|
|
65
|
-
forceRefresh?: boolean;
|
|
66
|
-
};
|
|
67
|
-
type PdsEndpoints = {
|
|
68
|
-
pds_url: string;
|
|
69
|
-
authorization_endpoint: string;
|
|
70
|
-
token_endpoint: string;
|
|
71
|
-
userinfo_endpoint: string;
|
|
72
|
-
};
|
|
73
|
-
type AuthManagerConfig = {
|
|
74
|
-
projectId: string | undefined;
|
|
75
|
-
scopes: string;
|
|
76
|
-
pdsUrl: string;
|
|
77
|
-
adminUrl: string;
|
|
78
|
-
debug: boolean;
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Framework-agnostic auth manager. Holds token state, handles OAuth flow,
|
|
82
|
-
* token refresh (with mutex), and user info fetching.
|
|
83
|
-
*
|
|
84
|
-
* React integration: pass a state-setter as `notify` so the component
|
|
85
|
-
* re-renders whenever auth state changes.
|
|
86
|
-
*/
|
|
87
|
-
declare class AuthManager {
|
|
88
|
-
token: Token | null;
|
|
89
|
-
user: User | null;
|
|
9
|
+
interface UseAccountsResult {
|
|
10
|
+
accounts: BasicProfile[];
|
|
11
|
+
active: BasicProfile | null;
|
|
12
|
+
switchAccount(id: string): Promise<void>;
|
|
13
|
+
addAccount(): Promise<BasicProfile>;
|
|
14
|
+
removeAccount(id: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
declare function useAccounts(): UseAccountsResult;
|
|
17
|
+
|
|
18
|
+
interface UseAuthResult {
|
|
19
|
+
isReady: boolean;
|
|
90
20
|
isSignedIn: boolean;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
21
|
+
isAnonymous: boolean;
|
|
22
|
+
status: AuthStatus;
|
|
23
|
+
error: BasicError | null;
|
|
24
|
+
user: AuthUser | null;
|
|
94
25
|
did: string | null;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
/** Space-separated scopes originally requested in the auth config */
|
|
98
|
-
requestedScopes: string;
|
|
99
|
-
readonly config: AuthManagerConfig;
|
|
100
|
-
readonly storage: BasicStorage;
|
|
101
|
-
/** True only during a user-initiated OAuth code exchange (not session restore) */
|
|
102
|
-
private freshSignIn;
|
|
103
|
-
private notify;
|
|
104
|
-
private refreshPromise;
|
|
105
|
-
private codeExchangePromise;
|
|
106
|
-
private pendingRefresh;
|
|
107
|
-
private isOnline;
|
|
108
|
-
private channel;
|
|
109
|
-
private nextUserRecoveryAt;
|
|
110
|
-
private sessionCheckPromise;
|
|
111
|
-
private lastSessionCheckAt;
|
|
112
|
-
constructor(config: AuthManagerConfig, storage: BasicStorage, notify: () => void);
|
|
113
|
-
private initCrossTabSync;
|
|
114
|
-
private broadcastTokenRefresh;
|
|
115
|
-
private broadcastSignIn;
|
|
116
|
-
private broadcastSignOut;
|
|
117
|
-
private broadcastSessionInvalidated;
|
|
118
|
-
/**
|
|
119
|
-
* Bootstrap auth: handle OAuth callback (?code=), restore session
|
|
120
|
-
* from refresh token, or load cached user for offline mode.
|
|
121
|
-
*/
|
|
122
|
-
initialize(): Promise<void>;
|
|
123
|
-
/**
|
|
124
|
-
* Get a valid access token string. Refreshes proactively (5s buffer)
|
|
125
|
-
* or on demand (forceRefresh). Mutex prevents concurrent refreshes.
|
|
126
|
-
*/
|
|
127
|
-
getToken(options?: GetTokenOptions$1): Promise<string>;
|
|
128
|
-
getSignInUrl(redirectUri?: string, endpoints?: PdsEndpoints): Promise<string>;
|
|
129
|
-
signIn(redirectUri?: string): Promise<void>;
|
|
130
|
-
signInWithHandle(handle: string): Promise<void>;
|
|
131
|
-
signInWithCode(code: string, state?: string): Promise<AuthResult>;
|
|
132
|
-
/**
|
|
133
|
-
* Sign out: revoke the session server-side (`POST /auth/logout`, best
|
|
134
|
-
* effort), then clear auth state and storage. Does NOT handle sync/DB
|
|
135
|
-
* cleanup — the client layer wraps this to add sync teardown.
|
|
136
|
-
*/
|
|
26
|
+
handle: string | null;
|
|
27
|
+
signIn(input?: string): Promise<void>;
|
|
137
28
|
signOut(): Promise<void>;
|
|
138
|
-
|
|
139
|
-
* Best-effort server-side revocation of the current device/session and
|
|
140
|
-
* its refresh chain (Step 2 auth: logout is finally server-side).
|
|
141
|
-
* Never blocks or fails the local sign-out.
|
|
142
|
-
*/
|
|
143
|
-
private revokeSessionOnServer;
|
|
144
|
-
reconcileSession(reason?: string, options?: {
|
|
145
|
-
forceRefresh?: boolean;
|
|
146
|
-
throttleMs?: number;
|
|
147
|
-
}): Promise<void>;
|
|
148
|
-
hasScope(scope: string): boolean;
|
|
149
|
-
/**
|
|
150
|
-
* Returns scopes that were requested but not granted in the current token.
|
|
151
|
-
* Useful after login or when a 403 is returned.
|
|
152
|
-
*/
|
|
153
|
-
missingScopes(): string[];
|
|
154
|
-
/**
|
|
155
|
-
* Register online/offline and visibility handlers that retry pending
|
|
156
|
-
* refreshes and proactively refresh tokens when the app resumes from
|
|
157
|
-
* background (critical for PWAs and mobile browsers where timers are
|
|
158
|
-
* frozen while backgrounded).
|
|
159
|
-
* Returns a cleanup function for useEffect teardown.
|
|
160
|
-
*/
|
|
161
|
-
setupNetworkListeners(): () => void;
|
|
162
|
-
private get adminHostname();
|
|
163
|
-
private defaultPdsEndpoints;
|
|
164
|
-
private getActivePdsEndpoints;
|
|
165
|
-
private reportConnection;
|
|
166
|
-
/**
|
|
167
|
-
* After a new token is stored, decode JWT claims and fetch user info.
|
|
168
|
-
*/
|
|
169
|
-
private processNewToken;
|
|
170
|
-
private restoreCachedUser;
|
|
171
|
-
private fetchUser;
|
|
172
|
-
/**
|
|
173
|
-
* Exchange an auth code or refresh token for an access token.
|
|
174
|
-
* Handles mutex (one in-flight refresh), token validation, and
|
|
175
|
-
* triggers processNewToken on success.
|
|
176
|
-
*/
|
|
177
|
-
private exchangeToken;
|
|
178
|
-
private resetAuthState;
|
|
179
|
-
private clearStoredAuth;
|
|
180
|
-
private isNetworkError;
|
|
181
|
-
private getRefreshToken;
|
|
182
|
-
private syncRefreshTokenFromStorage;
|
|
183
|
-
private applyTokenClaims;
|
|
184
|
-
private broadcastSessionUpdate;
|
|
185
|
-
private handleUserFetchFailure;
|
|
186
|
-
private isCompatibleUser;
|
|
187
|
-
private recoverMissingUserProfile;
|
|
188
|
-
private isDefinitiveTokenErrorCode;
|
|
189
|
-
private isDefinitiveAuthFailure;
|
|
190
|
-
/**
|
|
191
|
-
* Centralised auth status setter. Derives `isSignedIn` and `isAuthReady`
|
|
192
|
-
* from the status so they stay consistent.
|
|
193
|
-
*
|
|
194
|
-
* `isSignedIn` is intentionally `true` during `reauth_required` so the
|
|
195
|
-
* UI layer can still display user info while prompting re-authentication.
|
|
196
|
-
* Consumers should check `authStatus` (or a future convenience getter)
|
|
197
|
-
* when they need to distinguish "healthy session" from "needs re-auth".
|
|
198
|
-
*/
|
|
199
|
-
private updateAuthStatus;
|
|
200
|
-
private clearStoredSessionTokens;
|
|
201
|
-
private restoreStoredSession;
|
|
202
|
-
private handleExternalTokenRefresh;
|
|
203
|
-
private fetchCurrentSession;
|
|
204
|
-
private markReauthRequired;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Sync/2 wire protocol types — the client side of basic-server's
|
|
209
|
-
* `docs/SYNC_V2.md` contract (protocol version 1).
|
|
210
|
-
*
|
|
211
|
-
* WebSocket endpoint: `wss://<pds>/sync/`
|
|
212
|
-
* HTTP bootstrap: `GET /account/:project_id/db/snapshot`
|
|
213
|
-
* HTTP pull: `GET /account/:project_id/db/changes`
|
|
214
|
-
*/
|
|
215
|
-
declare const PROTOCOL_VERSION = 1;
|
|
216
|
-
type OpType = 'put' | 'patch' | 'delete';
|
|
217
|
-
/** An op as pushed by the client. `op_id` is the client-minted idempotency key. */
|
|
218
|
-
interface OpEnvelope {
|
|
219
|
-
op_id: string;
|
|
220
|
-
type: OpType;
|
|
221
|
-
table: string;
|
|
222
|
-
record_id: string;
|
|
223
|
-
data?: Record<string, unknown> | null;
|
|
224
|
-
/** What the writer had seen when creating the op. Recorded, never enforced (v1). */
|
|
225
|
-
base_seq?: number | null;
|
|
226
|
-
}
|
|
227
|
-
/** An op as delivered by the server (`ops` message / `changes` endpoint). */
|
|
228
|
-
interface LoggedOp extends OpEnvelope {
|
|
229
|
-
seq: number;
|
|
230
|
-
/** Server-stamped writer identity — never sent by the client. */
|
|
231
|
-
actor: string;
|
|
232
|
-
server_ts: string | number;
|
|
233
|
-
}
|
|
234
|
-
type SyncErrorCode = 'SCHEMA_VALIDATION_FAILED' | 'UNKNOWN_TABLE' | 'RECORD_NOT_FOUND' | 'PERMISSION_DENIED' | 'PAYLOAD_TOO_LARGE' | 'CHANNEL_FULL' | 'TOO_MANY_OPS' | 'RATE_LIMITED' | 'TRY_AGAIN' | 'SNAPSHOT_REQUIRED' | 'RESET_REQUIRED' | 'UNAUTHORIZED' | 'TOKEN_EXPIRED' | 'SHARE_REVOKED' | 'CONNECTION_REVOKED' | 'UNSUPPORTED_VERSION' | 'BAD_MESSAGE';
|
|
235
|
-
/** Terminal = poison-op rule applies: park in rejected store, never re-push. */
|
|
236
|
-
declare function isTerminalOpError(code: string | undefined, terminalFlag?: boolean): boolean;
|
|
237
|
-
/** Errors that mean "discard channel state, re-bootstrap from snapshot, resubscribe". */
|
|
238
|
-
declare function isRebootstrapError(code: string): boolean;
|
|
239
|
-
/** Errors that mean the subscription is gone and must not be retried. */
|
|
240
|
-
declare function isRevocationError(code: string): boolean;
|
|
241
|
-
/** Errors that mean the token was rejected; reauth then reconnect. */
|
|
242
|
-
declare function isAuthError(code: string): boolean;
|
|
243
|
-
interface SyncLimits {
|
|
244
|
-
max_ops_per_push: number;
|
|
245
|
-
max_op_bytes: number;
|
|
246
|
-
replay_limit: number;
|
|
247
|
-
}
|
|
248
|
-
declare const DEFAULT_LIMITS: SyncLimits;
|
|
249
|
-
/**
|
|
250
|
-
* First message on the socket. Sending only `{version, token}` opens a
|
|
251
|
-
* multiplexed session (auth-only welcome); streams are then bound with
|
|
252
|
-
* explicit `subscribe` messages. (The legacy single-subscription handshake
|
|
253
|
-
* with `cursor`/`share` on the hello is not used by this client.)
|
|
254
|
-
*/
|
|
255
|
-
interface HelloMsg {
|
|
256
|
-
type: 'hello';
|
|
257
|
-
version: number;
|
|
258
|
-
token: string;
|
|
259
|
-
}
|
|
260
|
-
interface SubscribeFilter {
|
|
261
|
-
table: string;
|
|
262
|
-
record_ids?: string[];
|
|
263
|
-
}
|
|
264
|
-
interface SubscribeMsg {
|
|
265
|
-
type: 'subscribe';
|
|
266
|
-
sub: string;
|
|
267
|
-
/** Last seq seen. Required — a null/absent cursor gets SNAPSHOT_REQUIRED. */
|
|
268
|
-
cursor: number;
|
|
269
|
-
/** Mount a share instead of the token's own channel. */
|
|
270
|
-
share?: string;
|
|
271
|
-
/** Narrow an own-channel subscription (partial sync). */
|
|
272
|
-
filter?: SubscribeFilter;
|
|
273
|
-
}
|
|
274
|
-
interface UnsubscribeMsg {
|
|
275
|
-
type: 'unsubscribe';
|
|
276
|
-
sub: string;
|
|
29
|
+
getToken(): Promise<string>;
|
|
277
30
|
}
|
|
278
|
-
|
|
279
|
-
type: 'push';
|
|
280
|
-
sub: string;
|
|
281
|
-
ops: OpEnvelope[];
|
|
282
|
-
}
|
|
283
|
-
interface PingMsg {
|
|
284
|
-
type: 'ping';
|
|
285
|
-
cursor?: number;
|
|
286
|
-
}
|
|
287
|
-
/** Refresh auth on a live socket without reconnecting. */
|
|
288
|
-
interface TokenMsg {
|
|
289
|
-
type: 'token';
|
|
290
|
-
token: string;
|
|
291
|
-
}
|
|
292
|
-
type ClientMsg = HelloMsg | SubscribeMsg | UnsubscribeMsg | PushMsg | PingMsg | TokenMsg;
|
|
293
|
-
/** Multiplexed handshake: auth-only welcome (`channel`/`cursor` absent). */
|
|
294
|
-
interface WelcomeMsg {
|
|
295
|
-
type: 'welcome';
|
|
296
|
-
actor: string;
|
|
297
|
-
limits: SyncLimits;
|
|
298
|
-
channel?: string;
|
|
299
|
-
cursor?: number;
|
|
300
|
-
head?: number;
|
|
301
|
-
schema_version?: string | number | null;
|
|
302
|
-
}
|
|
303
|
-
interface SubscribedMsg {
|
|
304
|
-
type: 'subscribed';
|
|
305
|
-
sub: string;
|
|
306
|
-
channel: string;
|
|
307
|
-
cursor: number;
|
|
308
|
-
head: number;
|
|
309
|
-
schema_version: string | number | null;
|
|
310
|
-
}
|
|
311
|
-
interface UnsubscribedMsg {
|
|
312
|
-
type: 'unsubscribed';
|
|
313
|
-
sub: string;
|
|
314
|
-
}
|
|
315
|
-
interface OpsMsg {
|
|
316
|
-
type: 'ops';
|
|
317
|
-
sub: string;
|
|
318
|
-
/** May be empty — a filtered tail still advances `cursor`; always adopt it. */
|
|
319
|
-
ops: LoggedOp[];
|
|
320
|
-
cursor: number;
|
|
321
|
-
}
|
|
322
|
-
type PushResult = {
|
|
323
|
-
op_id: string;
|
|
324
|
-
seq: number;
|
|
325
|
-
} | {
|
|
326
|
-
op_id: string;
|
|
327
|
-
error: SyncErrorCode;
|
|
328
|
-
terminal?: boolean;
|
|
329
|
-
message?: string;
|
|
330
|
-
};
|
|
331
|
-
interface PushedMsg {
|
|
332
|
-
type: 'pushed';
|
|
333
|
-
sub: string;
|
|
334
|
-
results: PushResult[];
|
|
335
|
-
/** Channel head after commit. Absent when nothing was committed. */
|
|
336
|
-
cursor?: number;
|
|
337
|
-
}
|
|
338
|
-
interface PongMsg {
|
|
339
|
-
type: 'pong';
|
|
340
|
-
head: number;
|
|
341
|
-
heads?: Record<string, number>;
|
|
342
|
-
}
|
|
343
|
-
interface TokenOkMsg {
|
|
344
|
-
type: 'token_ok';
|
|
345
|
-
}
|
|
346
|
-
interface ErrorMsg {
|
|
347
|
-
type: 'error';
|
|
348
|
-
code: SyncErrorCode;
|
|
349
|
-
message?: string;
|
|
350
|
-
terminal?: boolean;
|
|
351
|
-
/** Present when the error concerns one subscription on a multiplexed socket. */
|
|
352
|
-
sub?: string;
|
|
353
|
-
}
|
|
354
|
-
type ServerMsg = WelcomeMsg | SubscribedMsg | UnsubscribedMsg | OpsMsg | PushedMsg | PongMsg | TokenOkMsg | ErrorMsg;
|
|
355
|
-
/** `GET /account/:project_id/db/snapshot` → `{ data: Snapshot }` */
|
|
356
|
-
interface Snapshot {
|
|
357
|
-
channel: string;
|
|
358
|
-
/** table → record_id → field values (tombstones excluded, no `id` field). */
|
|
359
|
-
records: Record<string, Record<string, Record<string, unknown>>>;
|
|
360
|
-
/** Head seq the snapshot is consistent with. */
|
|
361
|
-
cursor: number;
|
|
362
|
-
}
|
|
363
|
-
/** `GET /account/:project_id/db/changes` → `{ data: ChangesPage }` */
|
|
364
|
-
interface ChangesPage {
|
|
365
|
-
ops: LoggedOp[];
|
|
366
|
-
cursor: number;
|
|
367
|
-
more: boolean;
|
|
368
|
-
}
|
|
369
|
-
type SharePermission = 'read' | 'write';
|
|
370
|
-
interface ShareSelector {
|
|
371
|
-
table: string;
|
|
372
|
-
record_ids?: string[] | null;
|
|
373
|
-
}
|
|
374
|
-
/** A share row as returned by `GET /account/shares`. */
|
|
375
|
-
interface Share {
|
|
376
|
-
id: string;
|
|
377
|
-
account_id: string;
|
|
378
|
-
channel_id: string;
|
|
379
|
-
grantee: string;
|
|
380
|
-
selector: ShareSelector;
|
|
381
|
-
permission: SharePermission;
|
|
382
|
-
created_at: string;
|
|
383
|
-
expires_at: string | null;
|
|
384
|
-
revoked_at: string | null;
|
|
385
|
-
}
|
|
386
|
-
/** Client-minted op id (idempotency key). */
|
|
387
|
-
declare function mintOpId(): string;
|
|
388
|
-
/**
|
|
389
|
-
* Apply one op to a record's field data. Returns the new data, or `undefined`
|
|
390
|
-
* when the record does not exist (deleted / never created).
|
|
391
|
-
*
|
|
392
|
-
* - `put`: create or replace the whole record
|
|
393
|
-
* - `patch`: shallow-merge top-level fields; no effect on a missing record
|
|
394
|
-
* - `delete`: tombstone (idempotent)
|
|
395
|
-
*/
|
|
396
|
-
declare function applyOpToData(existing: Record<string, unknown> | undefined, op: OpEnvelope): Record<string, unknown> | undefined;
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* RestClient — the REST v2 surface under `/account/:project_id/db/...`.
|
|
400
|
-
*
|
|
401
|
-
* Used by the sync engine for bootstrap (`snapshot`) and pull sync
|
|
402
|
-
* (`changes`), by the shares API, and by the REST-mode table API (CRUD on
|
|
403
|
-
* materialized state). All writes go through the same server-side sync
|
|
404
|
-
* engine as WebSocket pushes — one write path.
|
|
405
|
-
*/
|
|
31
|
+
declare function useAuth(): UseAuthResult;
|
|
406
32
|
|
|
407
|
-
interface
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
constructor(message: string, status: number, code?: string, response?: unknown);
|
|
415
|
-
}
|
|
416
|
-
declare class NotAuthenticatedError extends Error {
|
|
417
|
-
constructor(message?: string);
|
|
418
|
-
}
|
|
419
|
-
interface RestClientOptions {
|
|
420
|
-
/** PDS base URL, e.g. `https://pds.basic.id` */
|
|
421
|
-
baseUrl: string;
|
|
422
|
-
/** Project id (UUID or DID) — used in `/account/:project_id/...` paths. */
|
|
423
|
-
projectId: string;
|
|
424
|
-
getToken: (options?: GetTokenOptions) => Promise<string>;
|
|
425
|
-
log?: (...args: unknown[]) => void;
|
|
426
|
-
}
|
|
427
|
-
/** A record as returned by REST reads: flattened `{ id, ...fields }`. */
|
|
428
|
-
type RestRecord = {
|
|
429
|
-
id: string;
|
|
430
|
-
} & Record<string, unknown>;
|
|
431
|
-
declare class RestClient {
|
|
432
|
-
private readonly opts;
|
|
433
|
-
constructor(opts: RestClientOptions);
|
|
434
|
-
get projectId(): string;
|
|
435
|
-
/** `GET /account/:project_id/db` — tables, enforced schema version, channel head. */
|
|
436
|
-
getDbInfo(): Promise<{
|
|
437
|
-
tables: string[];
|
|
438
|
-
schema_version: string | number | null;
|
|
439
|
-
channel: {
|
|
440
|
-
id: string;
|
|
441
|
-
head_seq: number;
|
|
442
|
-
compacted_to_seq: number;
|
|
443
|
-
};
|
|
444
|
-
}>;
|
|
445
|
-
/** Bootstrap snapshot (SPEC §5). `share` bootstraps a mount; `table` filters. */
|
|
446
|
-
getSnapshot(options?: {
|
|
447
|
-
share?: string;
|
|
448
|
-
table?: string;
|
|
449
|
-
}): Promise<Snapshot>;
|
|
450
|
-
/** Pull ordered ops after a cursor — the non-WebSocket sync path. */
|
|
451
|
-
getChanges(options: {
|
|
452
|
-
cursor: number;
|
|
453
|
-
limit?: number;
|
|
454
|
-
share?: string;
|
|
455
|
-
table?: string;
|
|
456
|
-
}): Promise<ChangesPage>;
|
|
457
|
-
/**
|
|
458
|
-
* Shares granted by and received by the caller. App tokens see only
|
|
459
|
-
* shares involving their own app (the ones they can mount).
|
|
460
|
-
*/
|
|
461
|
-
listShares(): Promise<{
|
|
462
|
-
granted: Share[];
|
|
463
|
-
received: Share[];
|
|
464
|
-
}>;
|
|
465
|
-
list(table: string, query?: Record<string, string>): Promise<RestRecord[]>;
|
|
466
|
-
getRecord(table: string, id: string): Promise<RestRecord | null>;
|
|
467
|
-
/** `POST` — server mints the record id. */
|
|
468
|
-
createRecord(table: string, value: Record<string, unknown>): Promise<RestRecord>;
|
|
469
|
-
/** `PUT` — full replace. REST semantics: 404 for missing records. */
|
|
470
|
-
putRecord(table: string, id: string, value: Record<string, unknown>): Promise<RestRecord | null>;
|
|
471
|
-
/** `PATCH` — partial merge. 404 → null. */
|
|
472
|
-
patchRecord(table: string, id: string, value: Record<string, unknown>): Promise<RestRecord | null>;
|
|
473
|
-
/** `DELETE`. Returns false when the record did not exist. */
|
|
474
|
-
deleteRecord(table: string, id: string): Promise<boolean>;
|
|
475
|
-
private get dbPath();
|
|
476
|
-
/** Authenticated request; retries once with a force-refreshed token on 401. */
|
|
477
|
-
private request;
|
|
33
|
+
interface UseSyncStatusResult {
|
|
34
|
+
status: BasicSyncStatus;
|
|
35
|
+
pendingCount: number;
|
|
36
|
+
rejected: BasicRejection[];
|
|
37
|
+
conflicts: BasicConflict[];
|
|
38
|
+
resolveConflict(opId: string, choice: 'keep-mine' | 'keep-theirs'): Promise<boolean>;
|
|
39
|
+
discardRejected(opId: string): Promise<boolean>;
|
|
478
40
|
}
|
|
41
|
+
declare function useSyncStatus(source?: SourceRef): UseSyncStatusResult;
|
|
42
|
+
declare function useSchemaStatus(source?: SourceRef): SchemaStatus;
|
|
479
43
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
* reads (server state + pending ops rebased). `useQuery`/liveQuery reads
|
|
487
|
-
* these stores directly.
|
|
488
|
-
* - `_server`: confirmed records only, keyed `[table+record_id]`.
|
|
489
|
-
* - `_pending`: queued local ops (survive restarts), insertion-ordered.
|
|
490
|
-
* - `_rejected`: terminally rejected ops (poison-op rule — never re-pushed).
|
|
491
|
-
* - `_meta`: cursor, channel id, limits, schema version.
|
|
492
|
-
*
|
|
493
|
-
* The app-visible view is always `serverState + pending applied in order`
|
|
494
|
-
* (client responsibility #6). Rebasing is done per affected record inside
|
|
495
|
-
* the same transaction as the change that triggered it.
|
|
496
|
-
*/
|
|
497
|
-
|
|
498
|
-
interface PendingRow {
|
|
499
|
-
/** Auto-increment — preserves creation order across restarts. */
|
|
500
|
-
idx?: number;
|
|
501
|
-
op_id: string;
|
|
502
|
-
op: OpEnvelope;
|
|
503
|
-
/** Set when the server acked the op (`pushed` seq) but the echo hasn't arrived yet. */
|
|
504
|
-
acked_seq?: number;
|
|
505
|
-
}
|
|
506
|
-
interface RejectedRow {
|
|
507
|
-
idx?: number;
|
|
508
|
-
op_id: string;
|
|
509
|
-
op: OpEnvelope;
|
|
510
|
-
error: SyncErrorCode | string;
|
|
511
|
-
message?: string;
|
|
512
|
-
rejected_at: number;
|
|
513
|
-
}
|
|
514
|
-
interface SyncStoreSchema {
|
|
515
|
-
version?: number;
|
|
516
|
-
tables: Record<string, {
|
|
517
|
-
fields: Record<string, {
|
|
518
|
-
indexed?: boolean;
|
|
519
|
-
}>;
|
|
520
|
-
}>;
|
|
521
|
-
}
|
|
522
|
-
declare class SyncStore {
|
|
523
|
-
readonly db: Dexie;
|
|
524
|
-
readonly name: string;
|
|
525
|
-
private readonly tableNames;
|
|
526
|
-
constructor(name: string, schema: SyncStoreSchema);
|
|
527
|
-
/** The Dexie view table for an app table (what liveQuery reads). */
|
|
528
|
-
view(table: string): Table<Record<string, unknown>, string>;
|
|
529
|
-
hasTable(table: string): boolean;
|
|
530
|
-
get tables(): string[];
|
|
531
|
-
private get server();
|
|
532
|
-
private get pending();
|
|
533
|
-
private get rejected();
|
|
534
|
-
private get meta();
|
|
535
|
-
private get allStores();
|
|
536
|
-
getCursor(): Promise<number | null>;
|
|
537
|
-
getChannel(): Promise<string | null>;
|
|
538
|
-
/** All pending ops in creation order (used to warm the in-memory queue). */
|
|
539
|
-
loadPending(): Promise<PendingRow[]>;
|
|
540
|
-
listRejected(): Promise<RejectedRow[]>;
|
|
541
|
-
clearRejected(): Promise<void>;
|
|
542
|
-
/** Record a server ack for a pending op (echo not yet seen). */
|
|
543
|
-
markAcked(opId: string, seq: number): Promise<void>;
|
|
544
|
-
/**
|
|
545
|
-
* Enqueue a local op and apply it optimistically to the view.
|
|
546
|
-
* Returns the resulting view record (null when the op deletes it).
|
|
547
|
-
*/
|
|
548
|
-
addPending(op: OpEnvelope): Promise<Record<string, unknown> | null>;
|
|
549
|
-
/**
|
|
550
|
-
* Commit a batch of incoming server ops (already filtered/deduped by the
|
|
551
|
-
* engine): update `_server`, drop confirmed pending ops, advance the
|
|
552
|
-
* cursor, and rebase every affected view record — in one transaction.
|
|
553
|
-
*/
|
|
554
|
-
commitIncoming(params: {
|
|
555
|
-
applyOps: LoggedOp[];
|
|
556
|
-
confirmedOpIds: string[];
|
|
557
|
-
cursor: number;
|
|
558
|
-
}): Promise<void>;
|
|
559
|
-
/** Persist a cursor advance with no ops (empty `ops` message / pushed cursor). */
|
|
560
|
-
setCursor(cursor: number): Promise<void>;
|
|
561
|
-
/**
|
|
562
|
-
* Terminal rejection: remove from pending, park in the rejected store,
|
|
563
|
-
* roll the view record back to server state + remaining pending ops.
|
|
564
|
-
*/
|
|
565
|
-
rejectPending(opId: string, error: SyncErrorCode | string, message?: string): Promise<RejectedRow | null>;
|
|
566
|
-
/**
|
|
567
|
-
* Replace all server state from a snapshot (cold start or
|
|
568
|
-
* SNAPSHOT_REQUIRED/RESET_REQUIRED recovery). Pending ops survive and are
|
|
569
|
-
* re-applied on top of the fresh state.
|
|
570
|
-
*/
|
|
571
|
-
replaceFromSnapshot(params: {
|
|
572
|
-
channel: string;
|
|
573
|
-
records: Record<string, Record<string, Record<string, unknown>>>;
|
|
574
|
-
cursor: number;
|
|
575
|
-
}): Promise<void>;
|
|
576
|
-
getViewRecord(table: string, id: string): Promise<Record<string, unknown> | null>;
|
|
577
|
-
getViewRecords(table: string): Promise<Record<string, unknown>[]>;
|
|
578
|
-
close(): void;
|
|
579
|
-
/** Delete the underlying IndexedDB database (sign-out / revoked mount). */
|
|
580
|
-
destroy(): Promise<void>;
|
|
581
|
-
private applyToServer;
|
|
582
|
-
/**
|
|
583
|
-
* Rebase one record: view = server data + pending ops for that record in
|
|
584
|
-
* creation order. Must run inside a transaction covering all stores.
|
|
585
|
-
*/
|
|
586
|
-
private recomputeViewRecord;
|
|
44
|
+
interface UseBasicResult<S extends BasicSchema = BasicSchema> extends UseAuthResult {
|
|
45
|
+
client: BasicClient<S>;
|
|
46
|
+
db: BasicDb<S>;
|
|
47
|
+
accounts: UseAccountsResult;
|
|
48
|
+
sync: UseSyncStatusResult;
|
|
49
|
+
repos: Repo[];
|
|
587
50
|
}
|
|
51
|
+
declare function useBasic<S extends BasicSchema = BasicSchema>(): UseBasicResult<S>;
|
|
588
52
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
has(value: string): boolean;
|
|
604
|
-
add(value: string): void;
|
|
605
|
-
clear(): void;
|
|
606
|
-
}
|
|
607
|
-
interface SubscriptionState {
|
|
608
|
-
key: string;
|
|
609
|
-
shareId: string | null;
|
|
610
|
-
store: SyncStore;
|
|
611
|
-
cursor: number;
|
|
612
|
-
pending: PendingEntry[];
|
|
613
|
-
/** Bound on the current socket (subscribed ack received). */
|
|
614
|
-
active: boolean;
|
|
615
|
-
bootstrapped: boolean;
|
|
616
|
-
status: SubStatus;
|
|
617
|
-
revokedCode?: string;
|
|
618
|
-
appliedOpIds: BoundedSet;
|
|
619
|
-
/** Serializes ops/pushed/bootstrap handling per subscription. */
|
|
620
|
-
chain: Promise<void>;
|
|
621
|
-
schemaVersion: string | number | null;
|
|
622
|
-
}
|
|
623
|
-
interface SyncEngineEvents {
|
|
624
|
-
status: SyncStatus;
|
|
625
|
-
/** Records changed in a subscription's view (local write or server ops). */
|
|
626
|
-
change: {
|
|
627
|
-
sub: string;
|
|
628
|
-
tables: string[];
|
|
629
|
-
};
|
|
630
|
-
rejected: {
|
|
631
|
-
sub: string;
|
|
632
|
-
rejection: RejectedRow;
|
|
633
|
-
};
|
|
634
|
-
/** Sub-level protocol errors (share revoked, re-bootstrapping, ...). */
|
|
635
|
-
suberror: {
|
|
636
|
-
sub: string;
|
|
637
|
-
code: string;
|
|
638
|
-
message?: string;
|
|
639
|
-
};
|
|
640
|
-
/** Connection-level revocation — the app connection is gone. */
|
|
641
|
-
revoked: {
|
|
642
|
-
code: string;
|
|
643
|
-
message?: string;
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
interface EngineSchema {
|
|
647
|
-
project_id?: string;
|
|
648
|
-
version?: number;
|
|
649
|
-
tables: Record<string, {
|
|
650
|
-
fields: Record<string, {
|
|
651
|
-
type: string;
|
|
652
|
-
required?: boolean;
|
|
653
|
-
indexed?: boolean;
|
|
654
|
-
}>;
|
|
655
|
-
}>;
|
|
656
|
-
}
|
|
657
|
-
interface SyncEngineOptions {
|
|
658
|
-
projectId: string;
|
|
659
|
-
schema: EngineSchema;
|
|
660
|
-
/** e.g. `wss://pds.basic.id/sync/` */
|
|
661
|
-
wsUrl: string;
|
|
662
|
-
getToken: (options?: {
|
|
663
|
-
forceRefresh?: boolean;
|
|
664
|
-
}) => Promise<string>;
|
|
665
|
-
/** Bootstrap fetch (REST snapshot). Injected so the engine stays transport-thin. */
|
|
666
|
-
fetchSnapshot: (options?: {
|
|
667
|
-
share?: string;
|
|
668
|
-
}) => Promise<Snapshot>;
|
|
669
|
-
/** Prefix for IndexedDB database names. Default `basic-sync`. */
|
|
670
|
-
dbNamePrefix?: string;
|
|
671
|
-
/**
|
|
672
|
-
* App name included in `subscribe` messages. Production derives the channel
|
|
673
|
-
* from the token and ignores this; the sync-playground conformance server
|
|
674
|
-
* requires it. Leave unset against production.
|
|
675
|
-
*/
|
|
676
|
-
appName?: string;
|
|
677
|
-
WebSocketImpl?: typeof WebSocket;
|
|
678
|
-
heartbeatMs?: number;
|
|
679
|
-
/** Validate writes locally before queueing (mirrors server). Default true. */
|
|
680
|
-
validateWrites?: boolean;
|
|
681
|
-
log?: (...args: unknown[]) => void;
|
|
682
|
-
}
|
|
683
|
-
declare class SyncEngine {
|
|
684
|
-
readonly projectId: string;
|
|
685
|
-
readonly schema: EngineSchema;
|
|
686
|
-
private readonly opts;
|
|
687
|
-
private readonly connection;
|
|
688
|
-
private readonly subs;
|
|
689
|
-
private limits;
|
|
690
|
-
private actor;
|
|
691
|
-
private started;
|
|
692
|
-
private revokedInfo;
|
|
693
|
-
private connectionStatus;
|
|
694
|
-
private _status;
|
|
695
|
-
private listeners;
|
|
696
|
-
private timers;
|
|
697
|
-
constructor(opts: SyncEngineOptions);
|
|
698
|
-
on<E extends keyof SyncEngineEvents>(event: E, fn: (data: SyncEngineEvents[E]) => void): () => void;
|
|
699
|
-
private emit;
|
|
700
|
-
get status(): SyncStatus;
|
|
701
|
-
get syncLimits(): SyncLimits;
|
|
702
|
-
get serverActor(): string | null;
|
|
703
|
-
getSubscription(key: string): SubscriptionState | undefined;
|
|
704
|
-
get own(): SubscriptionState | undefined;
|
|
705
|
-
get pendingCount(): number;
|
|
706
|
-
listRejected(subKey?: string): Promise<RejectedRow[]>;
|
|
707
|
-
clearRejected(subKey?: string): Promise<void>;
|
|
708
|
-
/** Open the own-channel keyspace and connect. Idempotent. */
|
|
709
|
-
start(): Promise<void>;
|
|
710
|
-
/** Close the socket and stores; local data is kept. */
|
|
711
|
-
stop(): void;
|
|
712
|
-
/**
|
|
713
|
-
* Stop and delete every local database for this project (sign-out).
|
|
714
|
-
* Best-effort discovery of mount keyspaces from previous sessions.
|
|
715
|
-
*/
|
|
716
|
-
destroyLocal(): Promise<void>;
|
|
717
|
-
/**
|
|
718
|
-
* Mount a share: separate keyspace `(project, share)` with its own cursor
|
|
719
|
-
* and pending queue. Bootstraps + subscribes when the socket is online.
|
|
720
|
-
*/
|
|
721
|
-
mountShare(shareId: string): Promise<SubscriptionState>;
|
|
722
|
-
/** Unsubscribe a mount. Local cache is kept unless `purge` is set. */
|
|
723
|
-
unmountShare(shareId: string, options?: {
|
|
724
|
-
purge?: boolean;
|
|
725
|
-
}): Promise<void>;
|
|
726
|
-
/**
|
|
727
|
-
* Queue a local op, apply it optimistically, and push when online.
|
|
728
|
-
* Returns the resulting view record (null when deleted).
|
|
729
|
-
* Throws on local validation failure (fail fast — the server would
|
|
730
|
-
* terminally reject it anyway).
|
|
731
|
-
*/
|
|
732
|
-
apply(subKey: string, partial: {
|
|
733
|
-
type: OpType;
|
|
734
|
-
table: string;
|
|
735
|
-
record_id: string;
|
|
736
|
-
data?: Record<string, unknown>;
|
|
737
|
-
}): Promise<Record<string, unknown> | null>;
|
|
738
|
-
private handleConnectionStatus;
|
|
739
|
-
private handleWelcome;
|
|
740
|
-
private handleMessage;
|
|
741
|
-
private handleSubscribed;
|
|
742
|
-
private handleError;
|
|
743
|
-
private openSub;
|
|
744
|
-
/** Bootstrap if needed, then bind the stream on the current socket. */
|
|
745
|
-
private activateSub;
|
|
746
|
-
/** Cold start = snapshot + tail; never log replay (§5). Pending survives. */
|
|
747
|
-
private bootstrapSub;
|
|
748
|
-
/**
|
|
749
|
-
* Responsibilities 3+4+5: ordered apply, cursor advance, dedupe/confirm.
|
|
750
|
-
* Runs inside the sub's serial chain.
|
|
751
|
-
*/
|
|
752
|
-
private processOps;
|
|
753
|
-
/**
|
|
754
|
-
* Push verdicts (§6.5, §8, §9). Success acks are recorded but the op stays
|
|
755
|
-
* pending until its echo arrives in seq order — this preserves strict
|
|
756
|
-
* ordered apply even when `pushed` races ahead of intermediate remote ops.
|
|
757
|
-
* Terminal errors apply the poison-op rule; retryables back off.
|
|
758
|
-
*/
|
|
759
|
-
private processPushed;
|
|
760
|
-
/** Push unsent pending ops, chunked to `limits.max_ops_per_push`. */
|
|
761
|
-
private flush;
|
|
762
|
-
private get dbPrefix();
|
|
763
|
-
private enqueue;
|
|
764
|
-
private timer;
|
|
765
|
-
private recomputeStatus;
|
|
766
|
-
private log;
|
|
53
|
+
interface UseFilesResult {
|
|
54
|
+
data: Array<FileRecord | MountFileInfo>;
|
|
55
|
+
isLoading: boolean;
|
|
56
|
+
error: BasicError | null;
|
|
57
|
+
refresh(): void;
|
|
58
|
+
}
|
|
59
|
+
declare function useFiles(query?: FileListQuery, options?: {
|
|
60
|
+
source?: SourceRef;
|
|
61
|
+
}): UseFilesResult;
|
|
62
|
+
interface UseStorageInfoResult {
|
|
63
|
+
data: StorageInfo | null;
|
|
64
|
+
isLoading: boolean;
|
|
65
|
+
error: BasicError | null;
|
|
66
|
+
refresh(): void;
|
|
767
67
|
}
|
|
68
|
+
declare function useStorageInfo(): UseStorageInfoResult;
|
|
768
69
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
70
|
+
interface UseMountsResult<S extends BasicSchema = BasicSchema> {
|
|
71
|
+
data: MountInfo[];
|
|
72
|
+
mounts: MountInfo[];
|
|
73
|
+
isLoading: boolean;
|
|
74
|
+
error: BasicError | null;
|
|
75
|
+
refresh(): void;
|
|
76
|
+
open(mountId: string): Promise<MountHandle<S>>;
|
|
77
|
+
manageUrl(): string;
|
|
78
|
+
}
|
|
79
|
+
declare function useMounts(query?: MountsQuery): UseMountsResult;
|
|
80
|
+
interface UseOutgoingSharesResult {
|
|
81
|
+
data: OutgoingShareInfo[];
|
|
82
|
+
outgoingShares: OutgoingShareInfo[];
|
|
83
|
+
isLoading: boolean;
|
|
84
|
+
error: BasicError | null;
|
|
85
|
+
refresh(): void;
|
|
86
|
+
create(input: CreateOutgoingShareInput): Promise<OutgoingShareInfo>;
|
|
87
|
+
get(id: string): Promise<OutgoingShareInfo>;
|
|
88
|
+
cancel(id: string): Promise<OutgoingShareInfo>;
|
|
89
|
+
revoke(id: string): Promise<OutgoingShareInfo>;
|
|
90
|
+
manageUrl(): string;
|
|
91
|
+
}
|
|
92
|
+
declare function useOutgoingShares(): UseOutgoingSharesResult;
|
|
779
93
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
/** Create a record. Sync mode mints the id locally; REST mode server-side. */
|
|
785
|
-
create(data: Omit<T, 'id'>): Promise<T>;
|
|
786
|
-
/** Create or replace the whole record (Sync/2 `put` op). */
|
|
787
|
-
put(id: string, data: Omit<T, 'id'>): Promise<T>;
|
|
788
|
-
/** Shallow-merge top-level fields (`patch` op). Returns null when missing. */
|
|
789
|
-
patch(id: string, data: Partial<Omit<T, 'id'>>): Promise<T | null>;
|
|
790
|
-
/** Delete (tombstone). Idempotent. */
|
|
791
|
-
delete(id: string): Promise<void>;
|
|
792
|
-
get(id: string): Promise<T | null>;
|
|
793
|
-
getAll(): Promise<T[]>;
|
|
794
|
-
find(predicate: (record: T) => boolean): Promise<T[]>;
|
|
795
|
-
/** Sync mode: the Dexie view table (for liveQuery / advanced queries). */
|
|
796
|
-
ref?: Table<T, string>;
|
|
797
|
-
}
|
|
798
|
-
interface BasicDb {
|
|
799
|
-
readonly kind: 'sync' | 'rest';
|
|
800
|
-
table<T extends BasicRecord = BasicRecord>(name: string): BasicTable<T>;
|
|
801
|
-
}
|
|
802
|
-
declare class SyncDb implements BasicDb {
|
|
803
|
-
private readonly engine;
|
|
804
|
-
private readonly subKey;
|
|
805
|
-
readonly kind: "sync";
|
|
806
|
-
private readonly tables;
|
|
807
|
-
constructor(engine: SyncEngine, subKey?: string);
|
|
808
|
-
table<T extends BasicRecord = BasicRecord>(name: string): BasicTable<T>;
|
|
809
|
-
}
|
|
810
|
-
declare class RestDb implements BasicDb {
|
|
811
|
-
private readonly rest;
|
|
812
|
-
private readonly schema?;
|
|
813
|
-
readonly kind: "rest";
|
|
814
|
-
private readonly tables;
|
|
815
|
-
constructor(rest: RestClient, schema?: {
|
|
816
|
-
tables?: Record<string, unknown>;
|
|
817
|
-
} | undefined);
|
|
818
|
-
table<T extends BasicRecord = BasicRecord>(name: string): BasicTable<T>;
|
|
94
|
+
interface UseQueryResult<V extends JsonObject> {
|
|
95
|
+
data: BasicRecord<V>[];
|
|
96
|
+
isLoading: boolean;
|
|
97
|
+
error: BasicError | null;
|
|
819
98
|
}
|
|
99
|
+
declare function useQuery<V extends JsonObject = JsonObject>(collection: string, query?: Query<V>, options?: {
|
|
100
|
+
source?: SourceRef;
|
|
101
|
+
}): UseQueryResult<V>;
|
|
820
102
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
103
|
+
interface UseReposResult {
|
|
104
|
+
repos: Repo[];
|
|
105
|
+
defaultRepoId: string | null;
|
|
106
|
+
refresh(): Promise<Repo[]>;
|
|
107
|
+
create(input: {
|
|
108
|
+
name: string;
|
|
109
|
+
schema_type?: Repo['schema_type'];
|
|
110
|
+
schema?: JsonObject;
|
|
111
|
+
}): Promise<Repo>;
|
|
112
|
+
archive(repoId: string): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
declare function useRepos(): UseReposResult;
|
|
831
115
|
|
|
832
|
-
type
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
admin_url?: string;
|
|
839
|
-
/** Sync WebSocket URL. Default: pds_url with ws(s) scheme + `/sync/`. */
|
|
840
|
-
sync_url?: string;
|
|
841
|
-
}
|
|
842
|
-
interface BasicClientConfig {
|
|
843
|
-
/** The Basic schema document (`{ project_id, version, tables }`). */
|
|
844
|
-
schema?: Record<string, unknown> & {
|
|
845
|
-
project_id?: string;
|
|
846
|
-
version?: number;
|
|
847
|
-
tables?: Record<string, unknown>;
|
|
848
|
-
};
|
|
849
|
-
/** Project id override; normally taken from `schema.project_id`. */
|
|
850
|
-
project_id?: string;
|
|
851
|
-
auth?: BasicAuthConfig;
|
|
852
|
-
storage?: BasicStorage;
|
|
853
|
-
debug?: boolean;
|
|
854
|
-
/** 'sync' (offline-first local replica, default) or 'rest' (direct API). */
|
|
855
|
-
mode?: BasicMode;
|
|
856
|
-
/** Node/testing: pass the `ws` constructor. */
|
|
857
|
-
WebSocketImpl?: typeof WebSocket;
|
|
858
|
-
}
|
|
859
|
-
/** Local schema vs server status (dev toolbar and debugging). */
|
|
860
|
-
interface BasicSchemaDevInfo {
|
|
861
|
-
projectId: string | null;
|
|
862
|
-
localVersion: number | undefined;
|
|
863
|
-
status: string;
|
|
864
|
-
valid: boolean;
|
|
865
|
-
lastCheckedAt: number;
|
|
866
|
-
error?: string;
|
|
867
|
-
}
|
|
868
|
-
interface BasicClientSnapshot {
|
|
869
|
-
/** Auth bootstrap finished and (in sync mode) the local db is decided. */
|
|
870
|
-
isReady: boolean;
|
|
871
|
-
isSignedIn: boolean;
|
|
872
|
-
authStatus: AuthStatus;
|
|
873
|
-
authErrorCode: string | null;
|
|
874
|
-
user: User | null;
|
|
875
|
-
did: string | null;
|
|
876
|
-
/** Space-separated scopes granted in the current access token. */
|
|
877
|
-
scope: string | null;
|
|
878
|
-
syncStatus: SyncStatus;
|
|
879
|
-
pendingCount: number;
|
|
880
|
-
/** True when the schema allows sync (valid + published + matching server). */
|
|
881
|
-
syncEnabled: boolean;
|
|
882
|
-
devInfo: BasicSchemaDevInfo | null;
|
|
883
|
-
mode: BasicMode;
|
|
884
|
-
}
|
|
885
|
-
interface ShareMountHandle {
|
|
886
|
-
shareId: string;
|
|
887
|
-
db: BasicDb;
|
|
888
|
-
}
|
|
889
|
-
declare class BasicClient {
|
|
890
|
-
readonly auth: AuthManager;
|
|
891
|
-
readonly rest: RestClient;
|
|
892
|
-
readonly engine: SyncEngine | null;
|
|
893
|
-
readonly mode: BasicMode;
|
|
894
|
-
readonly config: BasicClientConfig;
|
|
895
|
-
readonly projectId: string | undefined;
|
|
896
|
-
private readonly syncDb;
|
|
897
|
-
private readonly restDb;
|
|
898
|
-
private readonly debug;
|
|
899
|
-
private devInfo;
|
|
900
|
-
private syncEnabled;
|
|
901
|
-
private schemaChecked;
|
|
902
|
-
private started;
|
|
903
|
-
private cleanupFns;
|
|
904
|
-
private mounts;
|
|
905
|
-
private listeners;
|
|
906
|
-
private snapshot;
|
|
907
|
-
constructor(config: BasicClientConfig);
|
|
908
|
-
/** The database handle: offline-first in sync mode, direct API in rest mode. */
|
|
909
|
-
get db(): BasicDb;
|
|
910
|
-
/** Bootstrap: version migrations, schema check, auth initialization. */
|
|
911
|
-
start(): Promise<void>;
|
|
912
|
-
/** Sign out: server-side revoke, local auth clear, sync teardown + purge. */
|
|
913
|
-
signOut(): Promise<void>;
|
|
914
|
-
/** Stop connections and listeners; local data is kept. */
|
|
915
|
-
stop(): void;
|
|
916
|
-
/** Re-run the remote schema status check (dev toolbar). */
|
|
917
|
-
refreshSchemaStatus(): Promise<void>;
|
|
918
|
-
listRejected(): Promise<RejectedRow[]>;
|
|
919
|
-
clearRejected(): Promise<void>;
|
|
920
|
-
/** Shares granted by / received by this user for this app. */
|
|
921
|
-
listShares(): Promise<{
|
|
922
|
-
granted: Share[];
|
|
923
|
-
received: Share[];
|
|
924
|
-
}>;
|
|
925
|
-
/** Mount a share: separate local keyspace + subscription. */
|
|
926
|
-
mountShare(shareId: string): Promise<ShareMountHandle>;
|
|
927
|
-
unmountShare(shareId: string, options?: {
|
|
928
|
-
purge?: boolean;
|
|
929
|
-
}): Promise<void>;
|
|
930
|
-
getMountedShare(shareId: string): ShareMountHandle | undefined;
|
|
931
|
-
subscribe: (listener: () => void) => (() => void);
|
|
932
|
-
getSnapshot: () => BasicClientSnapshot;
|
|
933
|
-
private handleAuthChange;
|
|
934
|
-
private maybeStartSync;
|
|
935
|
-
private teardownLocalData;
|
|
936
|
-
private wireEngineEvents;
|
|
937
|
-
private checkSchema;
|
|
938
|
-
private buildSnapshot;
|
|
939
|
-
private publish;
|
|
116
|
+
type CreateBasicConfig<S extends BasicSchema> = BrowserBasicConfig<S> & {
|
|
117
|
+
schema: S;
|
|
118
|
+
};
|
|
119
|
+
interface BoundBasicProviderProps {
|
|
120
|
+
children: ReactNode;
|
|
121
|
+
renderWhileLoading?: boolean;
|
|
940
122
|
}
|
|
941
|
-
|
|
123
|
+
interface CreatedBasic<S extends BasicSchema> {
|
|
124
|
+
client: BasicClient<S>;
|
|
125
|
+
Provider(props: BoundBasicProviderProps): ReactElement;
|
|
126
|
+
useBasic(): UseBasicResult<S>;
|
|
127
|
+
useAuth(): UseAuthResult;
|
|
128
|
+
useAccounts(): UseAccountsResult;
|
|
129
|
+
useDb(source: {
|
|
130
|
+
mountId: string;
|
|
131
|
+
}): BasicDb<S, MountViewerFiles>;
|
|
132
|
+
useDb(source?: 'default' | {
|
|
133
|
+
repoId: string;
|
|
134
|
+
}): BasicDb<S, OwnerFiles>;
|
|
135
|
+
useDb(source: SourceRef): BasicDb<S, OwnerFiles | MountViewerFiles>;
|
|
136
|
+
useCollection<T extends TableNames<S>>(name: T, options?: {
|
|
137
|
+
source?: SourceRef;
|
|
138
|
+
}): Collection<InferValue<S, T> & JsonObject>;
|
|
139
|
+
useQuery<T extends TableNames<S>>(collection: T, query?: Query<InferValue<S, T> & JsonObject>, options?: {
|
|
140
|
+
source?: SourceRef;
|
|
141
|
+
}): UseQueryResult<InferValue<S, T> & JsonObject>;
|
|
142
|
+
useSyncStatus(source?: SourceRef): UseSyncStatusResult;
|
|
143
|
+
useSchemaStatus(source?: SourceRef): SchemaStatus;
|
|
144
|
+
useRepos(): UseReposResult;
|
|
145
|
+
useFiles(query?: FileListQuery, options?: {
|
|
146
|
+
source?: SourceRef;
|
|
147
|
+
}): UseFilesResult;
|
|
148
|
+
useStorageInfo(): UseStorageInfoResult;
|
|
149
|
+
useMounts(query?: MountsQuery): UseMountsResult<S>;
|
|
150
|
+
useOutgoingShares(): UseOutgoingSharesResult;
|
|
151
|
+
}
|
|
152
|
+
/** Create one browser client and a complete hook surface bound to its schema. */
|
|
153
|
+
declare function createBasic<const S extends BasicSchema>(config: CreateBasicConfig<S>): CreatedBasic<S>;
|
|
942
154
|
|
|
943
|
-
interface
|
|
944
|
-
children:
|
|
945
|
-
/** The Basic schema object containing project_id and table definitions. */
|
|
946
|
-
schema?: Record<string, unknown>;
|
|
947
|
-
/** Project id override; normally taken from `schema.project_id`. */
|
|
948
|
-
project_id?: string;
|
|
949
|
-
auth?: BasicAuthConfig;
|
|
950
|
-
storage?: BasicStorage;
|
|
951
|
-
debug?: boolean;
|
|
952
|
-
/**
|
|
953
|
-
* - 'sync' (default): offline-first local replica synced over Sync/2
|
|
954
|
-
* - 'rest': direct REST calls, no local persistence
|
|
955
|
-
*/
|
|
956
|
-
mode?: BasicMode;
|
|
957
|
-
/** Show the floating dev toolbar (localhost / NODE_ENV=development / debug). */
|
|
958
|
-
devToolbar?: boolean;
|
|
959
|
-
/**
|
|
960
|
-
* Render children before auth/db are ready (default false: children render
|
|
961
|
-
* once the client finished bootstrapping, like previous versions).
|
|
962
|
-
*/
|
|
155
|
+
interface ProviderChildrenProps {
|
|
156
|
+
children: ReactNode;
|
|
963
157
|
renderWhileLoading?: boolean;
|
|
964
158
|
}
|
|
965
|
-
|
|
159
|
+
type BasicProviderProps<S extends BasicSchema = BasicSchema> = ProviderChildrenProps & ({
|
|
160
|
+
client: BasicClient<S>;
|
|
161
|
+
} | (BrowserBasicConfig<S> & {
|
|
162
|
+
client?: never;
|
|
163
|
+
}));
|
|
164
|
+
/** Generic provider for schema-less or explicitly generic applications. */
|
|
165
|
+
declare function BasicProvider<S extends BasicSchema = BasicSchema>(props: BasicProviderProps<S>): react.JSX.Element;
|
|
966
166
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
signInWithHandle: (handle: string) => Promise<void>;
|
|
993
|
-
signInWithCode: (code: string, state?: string) => Promise<AuthResult>;
|
|
994
|
-
signOut: () => Promise<void>;
|
|
995
|
-
getToken: (options?: GetTokenOptions$1) => Promise<string>;
|
|
996
|
-
getSignInUrl: (redirectUri?: string) => Promise<string>;
|
|
997
|
-
}
|
|
998
|
-
/** Auth state + actions. */
|
|
999
|
-
declare function useAuth(): UseAuthResult;
|
|
1000
|
-
/** The database handle (own channel). Offline-first in sync mode. */
|
|
1001
|
-
declare function useDb(): BasicDb;
|
|
1002
|
-
interface UseSyncStatusResult {
|
|
1003
|
-
/** Engine status: idle | connecting | online | offline | auth_required | revoked | stopped */
|
|
1004
|
-
status: SyncStatus;
|
|
1005
|
-
/** True when the schema is valid + published and sync can run. */
|
|
1006
|
-
enabled: boolean;
|
|
1007
|
-
/** Locally queued ops not yet confirmed by the server. */
|
|
1008
|
-
pendingCount: number;
|
|
1009
|
-
/** Terminally rejected ops (poison-op rule — never re-pushed). */
|
|
1010
|
-
listRejected: () => Promise<RejectedRow[]>;
|
|
1011
|
-
clearRejected: () => Promise<void>;
|
|
1012
|
-
}
|
|
1013
|
-
/** Sync engine state: connection status, pending queue depth, rejected ops. */
|
|
1014
|
-
declare function useSyncStatus(): UseSyncStatusResult;
|
|
1015
|
-
interface UseSharesResult {
|
|
1016
|
-
/** Shares this user granted to others (for this app). */
|
|
1017
|
-
granted: Share[];
|
|
1018
|
-
/** Shares others granted to this user (mountable). */
|
|
1019
|
-
received: Share[];
|
|
1020
|
-
isLoading: boolean;
|
|
1021
|
-
error: Error | null;
|
|
1022
|
-
refresh: () => Promise<void>;
|
|
1023
|
-
}
|
|
1024
|
-
/** List shares granted by / received by the signed-in user for this app. */
|
|
1025
|
-
declare function useShares(): UseSharesResult;
|
|
1026
|
-
interface UseShareResult {
|
|
1027
|
-
/** Table API over the mounted share's keyspace; null until mounted. */
|
|
1028
|
-
db: BasicDb | null;
|
|
1029
|
-
status: 'mounting' | 'mounted' | 'error' | 'revoked';
|
|
1030
|
-
error: Error | null;
|
|
167
|
+
declare function useDb<S extends BasicSchema = BasicSchema>(source: {
|
|
168
|
+
mountId: string;
|
|
169
|
+
}): BasicDb<S, MountViewerFiles>;
|
|
170
|
+
declare function useDb<S extends BasicSchema = BasicSchema>(source?: 'default' | {
|
|
171
|
+
repoId: string;
|
|
172
|
+
}): BasicDb<S, OwnerFiles>;
|
|
173
|
+
declare function useDb<S extends BasicSchema = BasicSchema>(source: SourceRef): BasicDb<S, OwnerFiles | MountViewerFiles>;
|
|
174
|
+
declare function useCollection<V extends JsonObject = JsonObject>(name: string, options?: {
|
|
175
|
+
source?: SourceRef;
|
|
176
|
+
}): Collection<V>;
|
|
177
|
+
|
|
178
|
+
/** Synchronous browser Storage adapted to core's key-value contract. */
|
|
179
|
+
declare class BrowserKeyValueStorage implements KeyValueStorage {
|
|
180
|
+
private readonly storage;
|
|
181
|
+
constructor(storage: Storage);
|
|
182
|
+
get(key: string): string | null;
|
|
183
|
+
set(key: string, value: string): void;
|
|
184
|
+
remove(key: string): void;
|
|
185
|
+
}
|
|
186
|
+
declare function browserStorage(name: 'localStorage' | 'sessionStorage'): BrowserKeyValueStorage | null;
|
|
187
|
+
|
|
188
|
+
interface MemoryAccessToken {
|
|
189
|
+
value: string;
|
|
190
|
+
expiresAt: number;
|
|
191
|
+
refreshToken: string;
|
|
1031
192
|
}
|
|
1032
193
|
/**
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
* pending queue — never merged with your own data.
|
|
194
|
+
* Browser token policy: refresh tokens survive reloads in the supplied
|
|
195
|
+
* persistent store; access tokens exist only in this JavaScript realm.
|
|
1036
196
|
*/
|
|
1037
|
-
declare
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
197
|
+
declare class BrowserTokenStore implements TokenStore {
|
|
198
|
+
private readonly persistent;
|
|
199
|
+
private readonly accessTokens;
|
|
200
|
+
private readonly accessWaiters;
|
|
201
|
+
constructor(persistent: KeyValueStorage);
|
|
202
|
+
get(key: string): Promise<string | null>;
|
|
203
|
+
set(key: string, value: string): Promise<void>;
|
|
204
|
+
remove(key: string): Promise<void>;
|
|
205
|
+
accessToken(key: string): MemoryAccessToken | null;
|
|
206
|
+
adoptAccessToken(key: string, value: string, expiresAt: number, refreshToken: string): Promise<void>;
|
|
207
|
+
private resolveAccessWaiters;
|
|
208
|
+
private waitForAccessToken;
|
|
1045
209
|
}
|
|
1046
|
-
/** Umbrella hook: auth + db + sync status. */
|
|
1047
|
-
declare function useBasic(): UseBasicResult;
|
|
1048
210
|
|
|
211
|
+
interface BrowserMessageChannel {
|
|
212
|
+
postMessage(message: unknown): void;
|
|
213
|
+
close(): void;
|
|
214
|
+
onmessage: ((event: {
|
|
215
|
+
data: unknown;
|
|
216
|
+
}) => void) | null;
|
|
217
|
+
}
|
|
218
|
+
/** Core message-channel adapter backed by the browser BroadcastChannel API. */
|
|
219
|
+
declare function createBrowserMessageChannel(name: string): BrowserMessageChannel;
|
|
1049
220
|
/**
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
1053
|
-
* Owns the transport only: hello handshake, heartbeat ping, exponential
|
|
1054
|
-
* backoff reconnect, and token refresh on auth rejection. Everything above
|
|
1055
|
-
* the socket (subscriptions, cursors, pending queues) belongs to SyncEngine,
|
|
1056
|
-
* which receives every parsed server message via `onMessage`.
|
|
221
|
+
* Access tokens may cross tabs transiently but are never written to browser
|
|
222
|
+
* storage. The receiving adapter adopts the token before core handles the
|
|
223
|
+
* ordinary token-rotation notification.
|
|
1057
224
|
*/
|
|
225
|
+
declare function createBrowserAuthChannelFactory(clientId: string, tokenStore: BrowserTokenStore): (name: string) => AuthMessageChannel;
|
|
1058
226
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
wsUrl: string;
|
|
1063
|
-
getToken: (options?: {
|
|
1064
|
-
forceRefresh?: boolean;
|
|
1065
|
-
}) => Promise<string>;
|
|
1066
|
-
/** Pass the `ws` constructor in Node; defaults to global WebSocket. */
|
|
1067
|
-
WebSocketImpl?: typeof WebSocket;
|
|
1068
|
-
/** Heartbeat interval (default 30s per spec). */
|
|
1069
|
-
heartbeatMs?: number;
|
|
1070
|
-
onWelcome: (msg: WelcomeMsg) => void;
|
|
1071
|
-
onMessage: (msg: ServerMsg) => void;
|
|
1072
|
-
onStatus: (status: ConnectionStatus) => void;
|
|
1073
|
-
log?: (...args: unknown[]) => void;
|
|
1074
|
-
}
|
|
1075
|
-
declare class SyncConnection {
|
|
1076
|
-
private readonly opts;
|
|
1077
|
-
private readonly WS;
|
|
1078
|
-
private readonly heartbeatMs;
|
|
1079
|
-
private ws;
|
|
1080
|
-
private _status;
|
|
1081
|
-
private stopped;
|
|
1082
|
-
private reconnectDelay;
|
|
1083
|
-
private timers;
|
|
1084
|
-
private heartbeatTimer;
|
|
1085
|
-
/** One forced-refresh reconnect attempt per auth rejection. */
|
|
1086
|
-
private authRetryUsed;
|
|
1087
|
-
private removeOnlineListener;
|
|
1088
|
-
constructor(opts: SyncConnectionOptions);
|
|
1089
|
-
get status(): ConnectionStatus;
|
|
1090
|
-
get isOnline(): boolean;
|
|
1091
|
-
start(): void;
|
|
1092
|
-
stop(): void;
|
|
1093
|
-
/** Send a message; returns false when the socket is not open. */
|
|
1094
|
-
send(msg: ClientMsg): boolean;
|
|
1095
|
-
/** Refresh auth on the live socket (no reconnect). */
|
|
1096
|
-
sendToken(): Promise<void>;
|
|
1097
|
-
/**
|
|
1098
|
-
* The server rejected our token (`UNAUTHORIZED` / `TOKEN_EXPIRED` + close).
|
|
1099
|
-
* Retry once with a force-refreshed token; give up (status `auth_failed`)
|
|
1100
|
-
* when the refresh itself fails or a fresh token is rejected again.
|
|
1101
|
-
*/
|
|
1102
|
-
handleAuthRejection(): void;
|
|
1103
|
-
private open;
|
|
1104
|
-
private handleMessage;
|
|
1105
|
-
private startHeartbeat;
|
|
1106
|
-
private stopHeartbeat;
|
|
1107
|
-
private scheduleReconnect;
|
|
1108
|
-
private listenForNetwork;
|
|
1109
|
-
private clearTimers;
|
|
1110
|
-
private setStatus;
|
|
1111
|
-
private log;
|
|
1112
|
-
}
|
|
227
|
+
declare function browserNavigate(url: string): void;
|
|
228
|
+
declare function browserCurrentUrl(): string;
|
|
229
|
+
declare function browserReplaceUrl(url: string): void;
|
|
1113
230
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
/**
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
231
|
+
interface ReplicaMessageChannel {
|
|
232
|
+
postMessage(message: unknown): void;
|
|
233
|
+
close(): void;
|
|
234
|
+
onmessage: ((event: {
|
|
235
|
+
data: unknown;
|
|
236
|
+
}) => void) | null;
|
|
237
|
+
}
|
|
238
|
+
interface AvailableLock {
|
|
239
|
+
name: string;
|
|
240
|
+
}
|
|
241
|
+
interface BrowserLockManager {
|
|
242
|
+
request<T>(name: string, options: {
|
|
243
|
+
mode?: 'exclusive';
|
|
244
|
+
ifAvailable?: true;
|
|
245
|
+
}, callback: (lock: AvailableLock | null) => T | Promise<T>): Promise<T>;
|
|
246
|
+
}
|
|
247
|
+
interface PersistenceStoreOptions {
|
|
248
|
+
locks?: BrowserLockManager | null;
|
|
249
|
+
createChannel?: ((name: string) => ReplicaMessageChannel) | null;
|
|
250
|
+
}
|
|
251
|
+
/** Dexie adapter for core's six-field, version-guarded replica store. */
|
|
252
|
+
declare class PersistenceStore implements ReplicaStoreFactory {
|
|
253
|
+
private readonly db;
|
|
254
|
+
private readonly stores;
|
|
255
|
+
private readonly locks;
|
|
256
|
+
private readonly createChannel;
|
|
257
|
+
private opened;
|
|
258
|
+
constructor(appKey: string, options?: PersistenceStoreOptions);
|
|
259
|
+
private get partitions();
|
|
260
|
+
open(): Promise<void>;
|
|
261
|
+
forPartition(partition: StoragePartition): ReplicaStore;
|
|
262
|
+
deleteProfile(profileId: string): Promise<void>;
|
|
263
|
+
close(): void;
|
|
264
|
+
}
|
|
1140
265
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
enabled?: boolean;
|
|
1144
|
-
/** Same as BasicProvider `debug` — when true, toolbar shows even off localhost. */
|
|
1145
|
-
debug?: boolean;
|
|
1146
|
-
};
|
|
1147
|
-
/**
|
|
1148
|
-
* Floating dev-only toolbar: auth, DB/sync, and schema status. Requires `BasicProvider` with `debug` or localhost / NODE_ENV=development for visibility unless `enabled` is forced.
|
|
1149
|
-
*/
|
|
1150
|
-
declare function BasicDevToolbar({ enabled, debug }: BasicDevToolbarProps): React.JSX.Element | null;
|
|
266
|
+
/** Browser multipart transport with upload progress, adapted from the Drive UI. */
|
|
267
|
+
declare const browserUploadTransport: UploadTransportAdapter;
|
|
1151
268
|
|
|
1152
|
-
export {
|
|
269
|
+
export { BasicProvider, type BasicProviderProps, type BoundBasicProviderProps, type BrowserBasicConfig, BrowserKeyValueStorage, type BrowserLockManager, type BrowserMessageChannel, BrowserTokenStore, type CreateBasicConfig, type CreatedBasic, PersistenceStore, type PersistenceStoreOptions, type UseAccountsResult, type UseAuthResult, type UseBasicResult, type UseFilesResult, type UseMountsResult, type UseOutgoingSharesResult, type UseQueryResult, type UseReposResult, type UseStorageInfoResult, type UseSyncStatusResult, browserCurrentUrl, browserNavigate, browserReplaceUrl, browserStorage, browserUploadTransport, createBasic, createBasicClient, createBrowserAuthChannelFactory, createBrowserMessageChannel, useAccounts, useAuth, useBasic, useCollection, useDb, useFiles, useMounts, useOutgoingShares, useQuery, useRepos, useSchemaStatus, useStorageInfo, useSyncStatus };
|