@basictech/react 0.9.0-beta.0 → 0.9.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/changelog.md +34 -0
- package/dist/index.d.mts +269 -27
- package/dist/index.d.ts +269 -27
- package/dist/index.js +790 -129
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +786 -128
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/readme.md +66 -12
package/changelog.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# 1.3.4
|
|
2
2
|
|
|
3
|
+
## 0.9.0-beta.1
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
Local-first startup, anonymous mode, and multiple users.
|
|
8
|
+
|
|
9
|
+
- **Anonymous mode (default on):** the local database works without a
|
|
10
|
+
session — writes queue as ordinary ops in a local-only workspace (sync
|
|
11
|
+
status `local`) and merge into the account automatically on sign-in via
|
|
12
|
+
the normal bootstrap+flush path (deferred identity — no copy step). Set
|
|
13
|
+
`anonymous={false}` on the provider for classic sign-in-required behavior.
|
|
14
|
+
- **Offline cold start fixed:** the engine opens the local keyspace with no
|
|
15
|
+
token and no network (`openLocal()`), so reloading offline serves all data
|
|
16
|
+
from the replica; the connection acquires tokens with retry on its own.
|
|
17
|
+
`reauth_required` now *pauses* the connection instead of stopping the
|
|
18
|
+
engine — local reads/writes keep working while the user re-authenticates.
|
|
19
|
+
- **Multiple users:** several local users (anonymous or signed-in) side by
|
|
20
|
+
side with per-tab switching. New `useUsers()` hook
|
|
21
|
+
(`users`, `activeUser`, `switchUser`, `addUser`, `removeUser`), profile
|
|
22
|
+
registry in localStorage, per-user auth storage namespacing and isolated
|
|
23
|
+
sync keyspaces (`basic-sync:{project}:{userId}`). Existing single-user
|
|
24
|
+
sessions are adopted as the first profile automatically.
|
|
25
|
+
- **Owner guard:** keyspaces are stamped with the account DID at bootstrap;
|
|
26
|
+
local data from one account can never merge into another (a mismatched
|
|
27
|
+
keyspace is wiped before bootstrap). Also fixes a latent leak where
|
|
28
|
+
unpushed ops could survive an account change.
|
|
29
|
+
- **User-aware `useQuery`:** the active user id is appended to query deps
|
|
30
|
+
automatically so live queries re-attach on user switches; in-flight
|
|
31
|
+
queries hitting a closing store during the switch return undefined and
|
|
32
|
+
re-run.
|
|
33
|
+
- `signOut()` now wipes the active user's data and falls through to the next
|
|
34
|
+
local user (or a fresh anonymous workspace); `useAuth()` exposes
|
|
35
|
+
`isAnonymous`; sync status gains `local`.
|
|
36
|
+
|
|
3
37
|
## 0.9.0-beta.0
|
|
4
38
|
|
|
5
39
|
### Major Changes (breaking)
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import Dexie, { Table } from 'dexie';
|
|
3
|
-
import { useLiveQuery } from 'dexie-react-hooks';
|
|
4
3
|
|
|
5
4
|
interface BasicStorage {
|
|
6
5
|
get(key: string): Promise<string | null>;
|
|
@@ -76,6 +75,12 @@ type AuthManagerConfig = {
|
|
|
76
75
|
pdsUrl: string;
|
|
77
76
|
adminUrl: string;
|
|
78
77
|
debug: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Identifies which local user profile this manager belongs to (multi-user).
|
|
80
|
+
* Cross-tab events are scoped to it so a tab active on another profile
|
|
81
|
+
* ignores them. Defaults to '' (single-user / legacy profile).
|
|
82
|
+
*/
|
|
83
|
+
instanceKey?: string;
|
|
79
84
|
};
|
|
80
85
|
/**
|
|
81
86
|
* Framework-agnostic auth manager. Holds token state, handles OAuth flow,
|
|
@@ -110,11 +115,14 @@ declare class AuthManager {
|
|
|
110
115
|
private sessionCheckPromise;
|
|
111
116
|
private lastSessionCheckAt;
|
|
112
117
|
constructor(config: AuthManagerConfig, storage: BasicStorage, notify: () => void);
|
|
118
|
+
private get instanceKey();
|
|
113
119
|
private initCrossTabSync;
|
|
114
120
|
private broadcastTokenRefresh;
|
|
115
121
|
private broadcastSignIn;
|
|
116
122
|
private broadcastSignOut;
|
|
117
123
|
private broadcastSessionInvalidated;
|
|
124
|
+
/** Release resources (cross-tab channel). Used when switching users. */
|
|
125
|
+
destroy(): void;
|
|
118
126
|
/**
|
|
119
127
|
* Bootstrap auth: handle OAuth callback (?code=), restore session
|
|
120
128
|
* from refresh token, or load cached user for offline mode.
|
|
@@ -535,6 +543,17 @@ declare class SyncStore {
|
|
|
535
543
|
private get allStores();
|
|
536
544
|
getCursor(): Promise<number | null>;
|
|
537
545
|
getChannel(): Promise<string | null>;
|
|
546
|
+
/**
|
|
547
|
+
* The account DID this keyspace's confirmed data belongs to. Absent for
|
|
548
|
+
* anonymous-era data (which may be merged into whichever account signs in).
|
|
549
|
+
*/
|
|
550
|
+
getOwner(): Promise<string | null>;
|
|
551
|
+
setOwner(did: string): Promise<void>;
|
|
552
|
+
/**
|
|
553
|
+
* Clear everything (views, server state, pending, rejected, meta) without
|
|
554
|
+
* deleting the database — used when the keyspace changes owners.
|
|
555
|
+
*/
|
|
556
|
+
wipeAll(): Promise<void>;
|
|
538
557
|
/** All pending ops in creation order (used to warm the in-memory queue). */
|
|
539
558
|
loadPending(): Promise<PendingRow[]>;
|
|
540
559
|
listRejected(): Promise<RejectedRow[]>;
|
|
@@ -586,7 +605,7 @@ declare class SyncStore {
|
|
|
586
605
|
private recomputeViewRecord;
|
|
587
606
|
}
|
|
588
607
|
|
|
589
|
-
type SyncStatus = 'idle' | 'connecting' | 'online' | 'offline' | 'auth_required' | 'revoked' | 'stopped';
|
|
608
|
+
type SyncStatus = 'idle' | 'local' | 'connecting' | 'online' | 'offline' | 'auth_required' | 'revoked' | 'stopped';
|
|
590
609
|
declare const OWN_SUB = "own";
|
|
591
610
|
declare function shareSubKey(shareId: string): string;
|
|
592
611
|
interface PendingEntry {
|
|
@@ -668,6 +687,19 @@ interface SyncEngineOptions {
|
|
|
668
687
|
}) => Promise<Snapshot>;
|
|
669
688
|
/** Prefix for IndexedDB database names. Default `basic-sync`. */
|
|
670
689
|
dbNamePrefix?: string;
|
|
690
|
+
/**
|
|
691
|
+
* Keyspace segment appended to database names (multi-user: the local user
|
|
692
|
+
* id). `''`/unset = the legacy single-user keyspace.
|
|
693
|
+
*/
|
|
694
|
+
keyspaceId?: string;
|
|
695
|
+
/**
|
|
696
|
+
* The account DID the current session belongs to, consulted at bootstrap
|
|
697
|
+
* for the owner guard: a keyspace stamped with a different DID is wiped
|
|
698
|
+
* before bootstrapping (never merge one account's local data into
|
|
699
|
+
* another); an unstamped keyspace (anonymous-era data) keeps its pending
|
|
700
|
+
* ops — that is the anonymous → signed-in migration path.
|
|
701
|
+
*/
|
|
702
|
+
getOwnerDid?: () => string | null | Promise<string | null>;
|
|
671
703
|
/**
|
|
672
704
|
* App name included in `subscribe` messages. Production derives the channel
|
|
673
705
|
* from the token and ignores this; the sync-playground conformance server
|
|
@@ -688,7 +720,11 @@ declare class SyncEngine {
|
|
|
688
720
|
private readonly subs;
|
|
689
721
|
private limits;
|
|
690
722
|
private actor;
|
|
691
|
-
|
|
723
|
+
/** Own-sub store is open (local reads/writes work). */
|
|
724
|
+
private storesOpen;
|
|
725
|
+
/** A live connection is wanted (vs. local-only / paused). */
|
|
726
|
+
private connectIntended;
|
|
727
|
+
private openingLocal;
|
|
692
728
|
private revokedInfo;
|
|
693
729
|
private connectionStatus;
|
|
694
730
|
private _status;
|
|
@@ -705,8 +741,28 @@ declare class SyncEngine {
|
|
|
705
741
|
get pendingCount(): number;
|
|
706
742
|
listRejected(subKey?: string): Promise<RejectedRow[]>;
|
|
707
743
|
clearRejected(subKey?: string): Promise<void>;
|
|
708
|
-
/**
|
|
744
|
+
/**
|
|
745
|
+
* Open the own-channel keyspace for local reads/writes — no connection,
|
|
746
|
+
* no token needed. This is the anonymous / offline-cold-start entry point.
|
|
747
|
+
* Idempotent.
|
|
748
|
+
*/
|
|
749
|
+
openLocal(): Promise<void>;
|
|
750
|
+
/**
|
|
751
|
+
* Open the keyspace (if needed) and start syncing. Idempotent.
|
|
752
|
+
* Note: a `CONNECTION_REVOKED` latch is NOT cleared here — reconnecting a
|
|
753
|
+
* revoked app connection requires a fresh consent flow. Call
|
|
754
|
+
* {@link clearRevoked} (or rebind the engine) after re-authorization.
|
|
755
|
+
*/
|
|
756
|
+
connect(): Promise<void>;
|
|
757
|
+
/** Clear the revocation latch (after the user re-authorized the app). */
|
|
758
|
+
clearRevoked(): void;
|
|
759
|
+
/** @deprecated alias of {@link connect} */
|
|
709
760
|
start(): Promise<void>;
|
|
761
|
+
/**
|
|
762
|
+
* Disconnect but keep stores open: local reads/writes keep working and
|
|
763
|
+
* ops queue for the next connect. Used on reauth_required.
|
|
764
|
+
*/
|
|
765
|
+
pause(): void;
|
|
710
766
|
/** Close the socket and stores; local data is kept. */
|
|
711
767
|
stop(): void;
|
|
712
768
|
/**
|
|
@@ -760,6 +816,8 @@ declare class SyncEngine {
|
|
|
760
816
|
/** Push unsent pending ops, chunked to `limits.max_ops_per_push`. */
|
|
761
817
|
private flush;
|
|
762
818
|
private get dbPrefix();
|
|
819
|
+
/** Base database name for this keyspace (multi-user: includes the user id). */
|
|
820
|
+
private get baseDbName();
|
|
763
821
|
private enqueue;
|
|
764
822
|
private timer;
|
|
765
823
|
private recomputeStatus;
|
|
@@ -819,14 +877,104 @@ declare class RestDb implements BasicDb {
|
|
|
819
877
|
}
|
|
820
878
|
|
|
821
879
|
/**
|
|
822
|
-
*
|
|
823
|
-
*
|
|
824
|
-
*
|
|
880
|
+
* User registry — multiple local users per project (anonymous or signed-in),
|
|
881
|
+
* one active at a time, switchable.
|
|
882
|
+
*
|
|
883
|
+
* - Profiles live in localStorage under `basic_users:{projectId}` and are
|
|
884
|
+
* shared across tabs.
|
|
885
|
+
* - The *active* user id is per-tab (sessionStorage) so different tabs can be
|
|
886
|
+
* on different users; it survives the OAuth redirect, so a sign-in resumes
|
|
887
|
+
* on the profile that initiated it. Falls back to the most recently active
|
|
888
|
+
* profile.
|
|
889
|
+
* - Each profile owns an isolated sync keyspace and a namespaced slice of
|
|
890
|
+
* auth storage (refresh token, cached userinfo, PKCE state, ...) via
|
|
891
|
+
* `PrefixedStorage`.
|
|
892
|
+
* - A pre-multi-user session (0.9.0-beta.0: bare `basic_refresh_token` +
|
|
893
|
+
* `basic-sync:{projectId}` keyspace) is adopted as the first profile with
|
|
894
|
+
* empty prefix/keyspace — no key or IndexedDB renames.
|
|
895
|
+
*/
|
|
896
|
+
|
|
897
|
+
type BasicUserKind = 'anon' | 'account';
|
|
898
|
+
interface BasicUserProfile {
|
|
899
|
+
/** Local profile id (uuid). Stable across sign-in upgrades. */
|
|
900
|
+
id: string;
|
|
901
|
+
kind: BasicUserKind;
|
|
902
|
+
/** Account identity, set once signed in. */
|
|
903
|
+
did?: string | null;
|
|
904
|
+
handle?: string | null;
|
|
905
|
+
email?: string | null;
|
|
906
|
+
name?: string | null;
|
|
907
|
+
picture?: string | null;
|
|
908
|
+
/**
|
|
909
|
+
* Keyspace segment for sync data. `''` = the legacy pre-multi-user
|
|
910
|
+
* keyspace (`basic-sync:{projectId}`); otherwise db names append it.
|
|
911
|
+
*/
|
|
912
|
+
keyspace: string;
|
|
913
|
+
/**
|
|
914
|
+
* Prefix for this profile's auth storage keys. `''` = legacy unprefixed
|
|
915
|
+
* keys; otherwise `u:{id}:`.
|
|
916
|
+
*/
|
|
917
|
+
storagePrefix: string;
|
|
918
|
+
createdAt: number;
|
|
919
|
+
lastActiveAt: number;
|
|
920
|
+
}
|
|
921
|
+
/** Namespaces every key of an underlying BasicStorage adapter. */
|
|
922
|
+
declare class PrefixedStorage implements BasicStorage {
|
|
923
|
+
private readonly inner;
|
|
924
|
+
readonly prefix: string;
|
|
925
|
+
constructor(inner: BasicStorage, prefix: string);
|
|
926
|
+
get(key: string): Promise<string | null>;
|
|
927
|
+
set(key: string, value: string): Promise<void>;
|
|
928
|
+
remove(key: string): Promise<void>;
|
|
929
|
+
}
|
|
930
|
+
declare class UserRegistry {
|
|
931
|
+
private readonly storage;
|
|
932
|
+
private readonly projectId;
|
|
933
|
+
constructor(storage: BasicStorage, projectId: string);
|
|
934
|
+
list(): Promise<BasicUserProfile[]>;
|
|
935
|
+
private save;
|
|
936
|
+
get(id: string): Promise<BasicUserProfile | null>;
|
|
937
|
+
createAnon(): Promise<BasicUserProfile>;
|
|
938
|
+
update(id: string, patch: Partial<Omit<BasicUserProfile, 'id' | 'keyspace' | 'storagePrefix'>>): Promise<BasicUserProfile | null>;
|
|
939
|
+
remove(id: string): Promise<void>;
|
|
940
|
+
/** The profile (if any) already bound to an account DID. */
|
|
941
|
+
findByDid(did: string): Promise<BasicUserProfile | null>;
|
|
942
|
+
private getActiveIdRaw;
|
|
943
|
+
setActiveId(id: string): void;
|
|
944
|
+
private clearActiveId;
|
|
945
|
+
/**
|
|
946
|
+
* Resolve the active profile for this tab: sessionStorage choice if it
|
|
947
|
+
* still exists, else the most recently active profile, else null.
|
|
948
|
+
*/
|
|
949
|
+
resolveActive(): Promise<BasicUserProfile | null>;
|
|
950
|
+
touch(id: string): Promise<void>;
|
|
951
|
+
/**
|
|
952
|
+
* Adopt a pre-multi-user session as the first profile. Idempotent: runs
|
|
953
|
+
* only when the registry is empty and a bare refresh token exists. The
|
|
954
|
+
* adopted profile keeps the unprefixed storage keys and the legacy
|
|
955
|
+
* keyspace name, so nothing needs to move.
|
|
956
|
+
*/
|
|
957
|
+
adoptLegacySession(): Promise<BasicUserProfile | null>;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* BasicClient — the framework-agnostic SDK core. Owns, per active user:
|
|
962
|
+
* - AuthManager (OAuth/PKCE, tokens, cross-tab session; storage namespaced
|
|
963
|
+
* per local user profile)
|
|
964
|
+
* - SyncEngine (Sync/2 client on the profile's own keyspace)
|
|
825
965
|
* - RestClient (REST v2: snapshot/changes bootstrap, shares, CRUD)
|
|
826
966
|
*
|
|
827
|
-
*
|
|
828
|
-
*
|
|
829
|
-
*
|
|
967
|
+
* plus the multi-user registry: several local users (anonymous or signed-in)
|
|
968
|
+
* exist side by side, one active at a time per tab, switchable.
|
|
969
|
+
*
|
|
970
|
+
* Local-first rules:
|
|
971
|
+
* - The local keyspace opens with no token and no network (anonymous mode is
|
|
972
|
+
* on by default; offline cold start works).
|
|
973
|
+
* - Anonymous writes are pending ops; sign-in upgrades the profile in place
|
|
974
|
+
* and the normal bootstrap+flush merges them into the account.
|
|
975
|
+
* - `reauth_required` pauses the connection but keeps local reads/writes.
|
|
976
|
+
* - Sign-out wipes the profile's local data and falls through to the next
|
|
977
|
+
* (or a fresh anonymous) user. No page reloads.
|
|
830
978
|
*/
|
|
831
979
|
|
|
832
980
|
type BasicMode = 'sync' | 'rest';
|
|
@@ -853,6 +1001,11 @@ interface BasicClientConfig {
|
|
|
853
1001
|
debug?: boolean;
|
|
854
1002
|
/** 'sync' (offline-first local replica, default) or 'rest' (direct API). */
|
|
855
1003
|
mode?: BasicMode;
|
|
1004
|
+
/**
|
|
1005
|
+
* Anonymous/local-first usage (sync mode only, default true): the local db
|
|
1006
|
+
* works without a session; data merges into the account on sign-in.
|
|
1007
|
+
*/
|
|
1008
|
+
anonymous?: boolean;
|
|
856
1009
|
/** Node/testing: pass the `ws` constructor. */
|
|
857
1010
|
WebSocketImpl?: typeof WebSocket;
|
|
858
1011
|
}
|
|
@@ -881,36 +1034,64 @@ interface BasicClientSnapshot {
|
|
|
881
1034
|
syncEnabled: boolean;
|
|
882
1035
|
devInfo: BasicSchemaDevInfo | null;
|
|
883
1036
|
mode: BasicMode;
|
|
1037
|
+
/** All local user profiles (anonymous and signed-in). */
|
|
1038
|
+
users: BasicUserProfile[];
|
|
1039
|
+
/** The profile active in this tab. */
|
|
1040
|
+
activeUser: BasicUserProfile | null;
|
|
1041
|
+
/** Active profile has no account yet (local-only workspace). */
|
|
1042
|
+
isAnonymous: boolean;
|
|
884
1043
|
}
|
|
885
1044
|
interface ShareMountHandle {
|
|
886
1045
|
shareId: string;
|
|
887
1046
|
db: BasicDb;
|
|
888
1047
|
}
|
|
889
1048
|
declare class BasicClient {
|
|
890
|
-
readonly auth: AuthManager;
|
|
891
1049
|
readonly rest: RestClient;
|
|
892
|
-
readonly engine: SyncEngine | null;
|
|
893
1050
|
readonly mode: BasicMode;
|
|
894
1051
|
readonly config: BasicClientConfig;
|
|
895
1052
|
readonly projectId: string | undefined;
|
|
896
|
-
|
|
1053
|
+
readonly users: UserRegistry | null;
|
|
1054
|
+
private readonly rawStorage;
|
|
897
1055
|
private readonly restDb;
|
|
898
1056
|
private readonly debug;
|
|
1057
|
+
private readonly anonymousEnabled;
|
|
1058
|
+
private readonly authConfig;
|
|
1059
|
+
private readonly syncUrl;
|
|
1060
|
+
private binding;
|
|
1061
|
+
private usersCache;
|
|
899
1062
|
private devInfo;
|
|
900
1063
|
private syncEnabled;
|
|
901
1064
|
private schemaChecked;
|
|
902
1065
|
private started;
|
|
903
|
-
private
|
|
1066
|
+
private signOutInProgress;
|
|
1067
|
+
/** Serializes profile transitions (switch, dispose, sign-out fallthrough). */
|
|
1068
|
+
private profileOps;
|
|
904
1069
|
private mounts;
|
|
905
1070
|
private listeners;
|
|
906
1071
|
private snapshot;
|
|
907
1072
|
constructor(config: BasicClientConfig);
|
|
908
|
-
|
|
1073
|
+
get auth(): AuthManager;
|
|
1074
|
+
get engine(): SyncEngine | null;
|
|
1075
|
+
/** The database handle for the active user. Identity changes on switch. */
|
|
909
1076
|
get db(): BasicDb;
|
|
910
|
-
|
|
1077
|
+
get activeUser(): BasicUserProfile | null;
|
|
1078
|
+
/** Bootstrap: version migrations, profile resolution, schema check, auth init. */
|
|
911
1079
|
start(): Promise<void>;
|
|
912
|
-
/**
|
|
1080
|
+
/**
|
|
1081
|
+
* Sign out the active user: server-side revoke, wipe the profile's local
|
|
1082
|
+
* data, drop the profile, and fall through to the next (or a fresh
|
|
1083
|
+
* anonymous) user.
|
|
1084
|
+
*/
|
|
913
1085
|
signOut(): Promise<void>;
|
|
1086
|
+
/** Switch this tab to another local user. */
|
|
1087
|
+
switchUser(id: string): Promise<void>;
|
|
1088
|
+
/** Create a fresh anonymous user and switch to it. */
|
|
1089
|
+
addUser(): Promise<BasicUserProfile>;
|
|
1090
|
+
/**
|
|
1091
|
+
* Remove a local user: best-effort server-side revoke, wipe its keyspace
|
|
1092
|
+
* and auth storage, drop the profile. Removing the active user signs out.
|
|
1093
|
+
*/
|
|
1094
|
+
removeUser(id: string): Promise<void>;
|
|
914
1095
|
/** Stop connections and listeners; local data is kept. */
|
|
915
1096
|
stop(): void;
|
|
916
1097
|
/** Re-run the remote schema status check (dev toolbar). */
|
|
@@ -930,10 +1111,38 @@ declare class BasicClient {
|
|
|
930
1111
|
getMountedShare(shareId: string): ShareMountHandle | undefined;
|
|
931
1112
|
subscribe: (listener: () => void) => (() => void);
|
|
932
1113
|
getSnapshot: () => BasicClientSnapshot;
|
|
1114
|
+
private createBinding;
|
|
1115
|
+
/**
|
|
1116
|
+
* Bind and boot a profile. Publishes the new binding first so React
|
|
1117
|
+
* subscriptions re-attach to the new db, then tears the old binding down
|
|
1118
|
+
* on the next tick (avoids in-flight live queries hitting a closed store).
|
|
1119
|
+
*/
|
|
1120
|
+
private activateProfile;
|
|
1121
|
+
private bindingMatches;
|
|
1122
|
+
/** After sign-out/disposal: resume on the next profile or a fresh anon one. */
|
|
1123
|
+
private activateNextProfileLocked;
|
|
1124
|
+
/** Wipe a (non-active) profile's local footprint: keyspace dbs + auth keys. */
|
|
1125
|
+
private disposeProfileData;
|
|
1126
|
+
private deleteKeyspaceDatabases;
|
|
1127
|
+
/** Previous auth status, for transition detection (revoked-latch clearing). */
|
|
1128
|
+
private lastAuthStatus;
|
|
933
1129
|
private handleAuthChange;
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1130
|
+
/**
|
|
1131
|
+
* Drive the engine from auth + schema state:
|
|
1132
|
+
* - local keyspace opens with no token (anonymous mode / offline cold start)
|
|
1133
|
+
* - connect when a session exists (recovering counts — the connection
|
|
1134
|
+
* retries token acquisition itself)
|
|
1135
|
+
* - reauth_required pauses the connection, keeps local data usable
|
|
1136
|
+
*/
|
|
1137
|
+
private syncLifecycle;
|
|
1138
|
+
/**
|
|
1139
|
+
* After sign-in: bind the account identity to the active profile
|
|
1140
|
+
* (anonymous → account upgrade) and dedupe against an existing profile
|
|
1141
|
+
* for the same DID.
|
|
1142
|
+
*/
|
|
1143
|
+
private maybeUpgradeProfile;
|
|
1144
|
+
private refreshUsers;
|
|
1145
|
+
private queueProfileOp;
|
|
937
1146
|
private checkSchema;
|
|
938
1147
|
private buildSnapshot;
|
|
939
1148
|
private publish;
|
|
@@ -954,6 +1163,12 @@ interface BasicProviderProps {
|
|
|
954
1163
|
* - 'rest': direct REST calls, no local persistence
|
|
955
1164
|
*/
|
|
956
1165
|
mode?: BasicMode;
|
|
1166
|
+
/**
|
|
1167
|
+
* Anonymous/local-first usage (sync mode only, default true): the db works
|
|
1168
|
+
* without a session and local data merges into the account on sign-in.
|
|
1169
|
+
* Set false to require sign-in before any local data exists.
|
|
1170
|
+
*/
|
|
1171
|
+
anonymous?: boolean;
|
|
957
1172
|
/** Show the floating dev toolbar (localhost / NODE_ENV=development / debug). */
|
|
958
1173
|
devToolbar?: boolean;
|
|
959
1174
|
/**
|
|
@@ -962,24 +1177,32 @@ interface BasicProviderProps {
|
|
|
962
1177
|
*/
|
|
963
1178
|
renderWhileLoading?: boolean;
|
|
964
1179
|
}
|
|
965
|
-
declare function BasicProvider({ children, schema, project_id, auth, storage, debug, mode, devToolbar, renderWhileLoading, }: BasicProviderProps): React.JSX.Element;
|
|
1180
|
+
declare function BasicProvider({ children, schema, project_id, auth, storage, debug, mode, anonymous, devToolbar, renderWhileLoading, }: BasicProviderProps): React.JSX.Element;
|
|
966
1181
|
|
|
967
1182
|
/**
|
|
968
|
-
* Reactive live queries against the local database (sync mode)
|
|
969
|
-
*
|
|
970
|
-
*
|
|
1183
|
+
* Reactive live queries against the local database (sync mode), built on
|
|
1184
|
+
* dexie-react-hooks' `useLiveQuery`. Any read through `db.table(...)` (or
|
|
1185
|
+
* its `ref` Dexie table) is observable.
|
|
971
1186
|
*
|
|
972
1187
|
* ```tsx
|
|
973
1188
|
* const todos = useQuery(() => db.table('todos').getAll())
|
|
974
1189
|
* ```
|
|
1190
|
+
*
|
|
1191
|
+
* User-aware: the active user's id is appended to `deps` automatically, so
|
|
1192
|
+
* queries re-subscribe against the new user's database on `switchUser` /
|
|
1193
|
+
* sign-in / sign-out — provided the query reads `db` from the current render
|
|
1194
|
+
* (e.g. from `useBasic()`/`useDb()`). For closures created outside render,
|
|
1195
|
+
* pass `[db]` in deps explicitly.
|
|
975
1196
|
*/
|
|
976
|
-
declare
|
|
1197
|
+
declare function useQuery<T>(querier: () => T | Promise<T | undefined> | undefined, deps?: unknown[]): T | undefined;
|
|
977
1198
|
/** The BasicClient instance from the nearest provider. */
|
|
978
1199
|
declare function useBasicClient(): BasicClient;
|
|
979
1200
|
interface UseAuthResult {
|
|
980
1201
|
/** Auth bootstrap finished (a session may or may not exist). */
|
|
981
1202
|
isReady: boolean;
|
|
982
1203
|
isSignedIn: boolean;
|
|
1204
|
+
/** Active user is a local-only (anonymous) workspace with no account. */
|
|
1205
|
+
isAnonymous: boolean;
|
|
983
1206
|
status: AuthStatus;
|
|
984
1207
|
errorCode: string | null;
|
|
985
1208
|
user: User | null;
|
|
@@ -1035,15 +1258,34 @@ interface UseShareResult {
|
|
|
1035
1258
|
* pending queue — never merged with your own data.
|
|
1036
1259
|
*/
|
|
1037
1260
|
declare function useShare(shareId: string | null | undefined): UseShareResult;
|
|
1261
|
+
interface UseUsersResult {
|
|
1262
|
+
/** All local user profiles (anonymous and signed-in), shared across tabs. */
|
|
1263
|
+
users: BasicUserProfile[];
|
|
1264
|
+
/** The profile active in this tab. */
|
|
1265
|
+
activeUser: BasicUserProfile | null;
|
|
1266
|
+
isAnonymous: boolean;
|
|
1267
|
+
/** Switch this tab to another local user. */
|
|
1268
|
+
switchUser: (id: string) => Promise<void>;
|
|
1269
|
+
/** Create a fresh anonymous user and switch to it. */
|
|
1270
|
+
addUser: () => Promise<BasicUserProfile>;
|
|
1271
|
+
/** Remove a local user (wipes its local data; active user = sign out). */
|
|
1272
|
+
removeUser: (id: string) => Promise<void>;
|
|
1273
|
+
}
|
|
1274
|
+
/** Multiple local users (anonymous or signed-in) with per-tab switching. */
|
|
1275
|
+
declare function useUsers(): UseUsersResult;
|
|
1038
1276
|
interface UseBasicResult extends UseAuthResult {
|
|
1039
1277
|
db: BasicDb;
|
|
1040
1278
|
sync: UseSyncStatusResult;
|
|
1279
|
+
/** All local user profiles. */
|
|
1280
|
+
users: BasicUserProfile[];
|
|
1281
|
+
/** The profile active in this tab. */
|
|
1282
|
+
activeUser: BasicUserProfile | null;
|
|
1041
1283
|
/** Local schema vs server status; null if no schema on the provider. */
|
|
1042
1284
|
devInfo: BasicClientSnapshot['devInfo'];
|
|
1043
1285
|
refreshSchemaStatus: () => Promise<void>;
|
|
1044
1286
|
client: BasicClient;
|
|
1045
1287
|
}
|
|
1046
|
-
/** Umbrella hook: auth + db + sync status. */
|
|
1288
|
+
/** Umbrella hook: auth + db + sync status + users. */
|
|
1047
1289
|
declare function useBasic(): UseBasicResult;
|
|
1048
1290
|
|
|
1049
1291
|
/**
|
|
@@ -1149,4 +1391,4 @@ type BasicDevToolbarProps = {
|
|
|
1149
1391
|
*/
|
|
1150
1392
|
declare function BasicDevToolbar({ enabled, debug }: BasicDevToolbarProps): React.JSX.Element | null;
|
|
1151
1393
|
|
|
1152
|
-
export { AuthManager, type AuthResult, type AuthStatus, type BasicAuthConfig, BasicClient, type BasicClientConfig, type BasicClientSnapshot, type BasicDb, BasicDevToolbar, type BasicDevToolbarProps, type BasicMode, BasicProvider, type BasicProviderProps, type BasicRecord, type BasicSchemaDevInfo, type BasicStorage, type BasicTable, type ChangesPage, type ConnectionStatus, DEFAULT_LIMITS, type GetTokenOptions$1 as GetTokenOptions, LocalStorageAdapter, type LoggedOp, NotAuthenticatedError, OWN_SUB, type OpEnvelope, type OpType, PROTOCOL_VERSION, type PdsEndpoints, type PendingRow, type PushResult, type RejectedRow, type ResolvedDid, RestClient, type RestClientOptions, RestDb, RestError, type RestRecord, STORAGE_KEYS, type Share, type ShareMountHandle, type SharePermission, type ShareSelector, type Snapshot, type SubscriptionState, SyncConnection, SyncDb, SyncEngine, type SyncEngineEvents, type SyncEngineOptions, type SyncErrorCode, type SyncLimits, type SyncStatus, SyncStore, type SyncStoreSchema, type Token, type UseAuthResult, type UseBasicResult, type UseShareResult, type UseSharesResult, type UseSyncStatusResult, type User, applyOpToData, createBasicClient, isAuthError, isRebootstrapError, isRevocationError, isTerminalOpError, mintOpId, resolveDid, resolveDidWebUrl, resolveHandle, shareSubKey, useAuth, useBasic, useBasicClient, useDb, useQuery, useShare, useShares, useSyncStatus };
|
|
1394
|
+
export { AuthManager, type AuthResult, type AuthStatus, type BasicAuthConfig, BasicClient, type BasicClientConfig, type BasicClientSnapshot, type BasicDb, BasicDevToolbar, type BasicDevToolbarProps, type BasicMode, BasicProvider, type BasicProviderProps, type BasicRecord, type BasicSchemaDevInfo, type BasicStorage, type BasicTable, type BasicUserKind, type BasicUserProfile, type ChangesPage, type ConnectionStatus, DEFAULT_LIMITS, type GetTokenOptions$1 as GetTokenOptions, LocalStorageAdapter, type LoggedOp, NotAuthenticatedError, OWN_SUB, type OpEnvelope, type OpType, PROTOCOL_VERSION, type PdsEndpoints, type PendingRow, PrefixedStorage, type PushResult, type RejectedRow, type ResolvedDid, RestClient, type RestClientOptions, RestDb, RestError, type RestRecord, STORAGE_KEYS, type Share, type ShareMountHandle, type SharePermission, type ShareSelector, type Snapshot, type SubscriptionState, SyncConnection, SyncDb, SyncEngine, type SyncEngineEvents, type SyncEngineOptions, type SyncErrorCode, type SyncLimits, type SyncStatus, SyncStore, type SyncStoreSchema, type Token, type UseAuthResult, type UseBasicResult, type UseShareResult, type UseSharesResult, type UseSyncStatusResult, type UseUsersResult, type User, UserRegistry, applyOpToData, createBasicClient, isAuthError, isRebootstrapError, isRevocationError, isTerminalOpError, mintOpId, resolveDid, resolveDidWebUrl, resolveHandle, shareSubKey, useAuth, useBasic, useBasicClient, useDb, useQuery, useShare, useShares, useSyncStatus, useUsers };
|