@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/dist/index.d.ts 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
- private started;
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
- /** Open the own-channel keyspace and connect. Idempotent. */
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
- * BasicClientthe framework-agnostic SDK core. Owns:
823
- * - AuthManager (OAuth/PKCE, tokens, cross-tab session)
824
- * - SyncEngine (Sync/2 client: local store, pending queue, WS connection)
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
- * and orchestrates them: sync connects when a healthy session exists, stops
828
- * on reauth_required, and tears down local data on sign-out (no page reload).
829
- * The React layer (`BasicProvider` + hooks) is a thin subscriber.
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
- private readonly syncDb;
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 cleanupFns;
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
- /** The database handle: offline-first in sync mode, direct API in rest mode. */
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
- /** Bootstrap: version migrations, schema check, auth initialization. */
1077
+ get activeUser(): BasicUserProfile | null;
1078
+ /** Bootstrap: version migrations, profile resolution, schema check, auth init. */
911
1079
  start(): Promise<void>;
912
- /** Sign out: server-side revoke, local auth clear, sync teardown + purge. */
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
- private maybeStartSync;
935
- private teardownLocalData;
936
- private wireEngineEvents;
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
- * Re-export of dexie-react-hooks' `useLiveQuery` any read through
970
- * `db.table(...)` (or its `ref` Dexie table) is observable.
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 const useQuery: typeof useLiveQuery;
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 };