local-lite 0.0.20 → 0.0.21

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.
@@ -2,3 +2,4 @@ export * from './google.js';
2
2
  export * from './microsoft.js';
3
3
  export * from './github.js';
4
4
  export * from './apple.js';
5
+ export * from './session.js';
@@ -18,3 +18,4 @@ __exportStar(require("./google.js"), exports);
18
18
  __exportStar(require("./microsoft.js"), exports);
19
19
  __exportStar(require("./github.js"), exports);
20
20
  __exportStar(require("./apple.js"), exports);
21
+ __exportStar(require("./session.js"), exports);
@@ -0,0 +1,107 @@
1
+ import { DBExecutable } from '../core/schema-manager.js';
2
+ import { EventEmitter } from '../reactive/event-emitter.js';
3
+ export declare const DEFAULT_SESSIONS_TABLE = "_local_sessions";
4
+ export declare const DEFAULT_OFFLINE_DURATION_MS: number;
5
+ export interface SessionRecord<TUser = any> {
6
+ id: string;
7
+ userId: string;
8
+ user: TUser;
9
+ token?: string | null;
10
+ refreshToken?: string | null;
11
+ provider?: string | null;
12
+ createdAt: number;
13
+ lastActiveAt: number;
14
+ expiresAt?: number | null;
15
+ offlineAccessUntil?: number | null;
16
+ metadata?: Record<string, any> | null;
17
+ isActive: boolean;
18
+ }
19
+ export interface CreateSessionOptions<TUser = any> {
20
+ id?: string;
21
+ userId: string;
22
+ user: TUser;
23
+ token?: string | null;
24
+ refreshToken?: string | null;
25
+ provider?: string | null;
26
+ expiresAt?: number | null;
27
+ /**
28
+ * Duration in ms the session remains valid while offline without re-authenticating.
29
+ * Default: 30 days. Set to 0 or Infinity for unlimited offline access.
30
+ */
31
+ offlineDurationMs?: number;
32
+ metadata?: Record<string, any>;
33
+ /**
34
+ * Whether to activate this session as the active user immediately.
35
+ * Default: true
36
+ */
37
+ setActive?: boolean;
38
+ }
39
+ export interface SessionManagerOptions {
40
+ tableName?: string;
41
+ defaultOfflineDurationMs?: number;
42
+ network?: {
43
+ isOnline(): boolean | Promise<boolean>;
44
+ };
45
+ }
46
+ export declare function mapSessionRow<TUser = any>(r: any): SessionRecord<TUser>;
47
+ export declare class SessionManager {
48
+ private db;
49
+ private events?;
50
+ private tableName;
51
+ private defaultOfflineDurationMs;
52
+ private network?;
53
+ constructor(db: DBExecutable, events?: EventEmitter | undefined, options?: SessionManagerOptions);
54
+ /**
55
+ * Ensures the _local_sessions schema exists.
56
+ */
57
+ initialize(): Promise<void>;
58
+ /**
59
+ * Creates or updates a user session, persisting it to local SQLite so it remains available offline.
60
+ */
61
+ createSession<TUser = any>(options: CreateSessionOptions<TUser>): Promise<SessionRecord<TUser>>;
62
+ /**
63
+ * Retrieves the currently active session.
64
+ * If offline, the session remains active even if server tokens expired, as long as offlineAccessUntil is valid.
65
+ */
66
+ getActiveSession<TUser = any>(): Promise<SessionRecord<TUser> | null>;
67
+ /**
68
+ * Returns true if there is an active valid session (works offline and online).
69
+ */
70
+ isAuthenticated(): Promise<boolean>;
71
+ /**
72
+ * Retrieves the authenticated user profile object, or null if signed out.
73
+ */
74
+ getUser<TUser = any>(): Promise<TUser | null>;
75
+ /**
76
+ * Updates last active timestamp.
77
+ */
78
+ touch(sessionId?: string): Promise<void>;
79
+ /**
80
+ * Partially updates the active user's profile data in SQLite.
81
+ */
82
+ updateUser<TUser = any>(partialUser: Partial<TUser>): Promise<SessionRecord<TUser> | null>;
83
+ /**
84
+ * Updates access tokens without re-authenticating or resetting the offline grace period.
85
+ */
86
+ updateTokens(tokens: {
87
+ token?: string | null;
88
+ refreshToken?: string | null;
89
+ expiresAt?: number | null;
90
+ }): Promise<void>;
91
+ /**
92
+ * Signs out the active user session.
93
+ */
94
+ clearSession(): Promise<void>;
95
+ /**
96
+ * Completely purges all stored sessions (e.g. factory reset or privacy wipe).
97
+ */
98
+ purgeAllSessions(): Promise<void>;
99
+ /**
100
+ * Lists all sessions currently cached in SQLite.
101
+ */
102
+ listSessions<TUser = any>(): Promise<SessionRecord<TUser>[]>;
103
+ /**
104
+ * Switches the active session to a different account (e.g., multi-account or organization switching offline).
105
+ */
106
+ switchSession<TUser = any>(sessionIdOrUserId: string): Promise<SessionRecord<TUser> | null>;
107
+ }
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionManager = exports.DEFAULT_OFFLINE_DURATION_MS = exports.DEFAULT_SESSIONS_TABLE = void 0;
4
+ exports.mapSessionRow = mapSessionRow;
5
+ const uuid_js_1 = require("../utils/uuid.js");
6
+ exports.DEFAULT_SESSIONS_TABLE = '_local_sessions';
7
+ exports.DEFAULT_OFFLINE_DURATION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
8
+ function mapSessionRow(r) {
9
+ let userData;
10
+ try {
11
+ userData = typeof r.user_data === 'string' ? JSON.parse(r.user_data) : r.user_data;
12
+ }
13
+ catch {
14
+ userData = r.user_data;
15
+ }
16
+ let metadata = null;
17
+ if (r.metadata) {
18
+ try {
19
+ metadata = typeof r.metadata === 'string' ? JSON.parse(r.metadata) : r.metadata;
20
+ }
21
+ catch {
22
+ metadata = null;
23
+ }
24
+ }
25
+ return {
26
+ id: String(r.id),
27
+ userId: String(r.user_id),
28
+ user: userData,
29
+ token: r.token || null,
30
+ refreshToken: r.refresh_token || null,
31
+ provider: r.provider || null,
32
+ createdAt: Number(r.created_at || 0),
33
+ lastActiveAt: Number(r.last_active_at || 0),
34
+ expiresAt: r.expires_at != null ? Number(r.expires_at) : null,
35
+ offlineAccessUntil: r.offline_access_until != null ? Number(r.offline_access_until) : null,
36
+ metadata,
37
+ isActive: r.is_active === 1 || r.is_active === '1' || r.is_active === true,
38
+ };
39
+ }
40
+ class SessionManager {
41
+ db;
42
+ events;
43
+ tableName;
44
+ defaultOfflineDurationMs;
45
+ network;
46
+ constructor(db, events, options = {}) {
47
+ this.db = db;
48
+ this.events = events;
49
+ this.tableName = options.tableName ?? exports.DEFAULT_SESSIONS_TABLE;
50
+ this.defaultOfflineDurationMs = options.defaultOfflineDurationMs ?? exports.DEFAULT_OFFLINE_DURATION_MS;
51
+ this.network = options.network;
52
+ }
53
+ /**
54
+ * Ensures the _local_sessions schema exists.
55
+ */
56
+ async initialize() {
57
+ await this.db.execute(`CREATE TABLE IF NOT EXISTS ${this.tableName} (
58
+ id TEXT PRIMARY KEY,
59
+ user_id TEXT NOT NULL,
60
+ user_data TEXT NOT NULL,
61
+ token TEXT,
62
+ refresh_token TEXT,
63
+ provider TEXT,
64
+ created_at INTEGER NOT NULL,
65
+ last_active_at INTEGER NOT NULL,
66
+ expires_at INTEGER,
67
+ offline_access_until INTEGER,
68
+ metadata TEXT,
69
+ is_active INTEGER NOT NULL DEFAULT 1
70
+ );`);
71
+ await this.db.execute(`CREATE INDEX IF NOT EXISTS idx_${this.tableName}_user ON ${this.tableName} (user_id);`);
72
+ await this.db.execute(`CREATE INDEX IF NOT EXISTS idx_${this.tableName}_active ON ${this.tableName} (is_active);`);
73
+ }
74
+ /**
75
+ * Creates or updates a user session, persisting it to local SQLite so it remains available offline.
76
+ */
77
+ async createSession(options) {
78
+ const id = options.id || `sess_${(0, uuid_js_1.generateUUID)()}`;
79
+ const now = Date.now();
80
+ const offlineDuration = options.offlineDurationMs !== undefined
81
+ ? options.offlineDurationMs
82
+ : this.defaultOfflineDurationMs;
83
+ const offlineAccessUntil = offlineDuration === 0 || offlineDuration === Infinity
84
+ ? null
85
+ : now + offlineDuration;
86
+ const setActive = options.setActive !== false;
87
+ const userDataStr = JSON.stringify(options.user ?? {});
88
+ const metadataStr = options.metadata ? JSON.stringify(options.metadata) : null;
89
+ if (setActive) {
90
+ // Deactivate other sessions
91
+ await this.db.execute(`UPDATE ${this.tableName} SET is_active = ?;`, [0]);
92
+ }
93
+ const sql = `
94
+ INSERT INTO ${this.tableName} (id, user_id, user_data, token, refresh_token, provider, created_at, last_active_at, expires_at, offline_access_until, metadata, is_active)
95
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
96
+ ON CONFLICT(id) DO UPDATE SET
97
+ user_id = excluded.user_id,
98
+ user_data = excluded.user_data,
99
+ token = excluded.token,
100
+ refresh_token = excluded.refresh_token,
101
+ provider = excluded.provider,
102
+ last_active_at = excluded.last_active_at,
103
+ expires_at = excluded.expires_at,
104
+ offline_access_until = excluded.offline_access_until,
105
+ metadata = excluded.metadata,
106
+ is_active = excluded.is_active;
107
+ `;
108
+ await this.db.execute(sql, [
109
+ id,
110
+ options.userId,
111
+ userDataStr,
112
+ options.token ?? null,
113
+ options.refreshToken ?? null,
114
+ options.provider ?? null,
115
+ now,
116
+ now,
117
+ options.expiresAt ?? null,
118
+ offlineAccessUntil,
119
+ metadataStr,
120
+ setActive ? 1 : 0,
121
+ ]);
122
+ const session = {
123
+ id,
124
+ userId: options.userId,
125
+ user: options.user,
126
+ token: options.token || null,
127
+ refreshToken: options.refreshToken || null,
128
+ provider: options.provider || null,
129
+ createdAt: now,
130
+ lastActiveAt: now,
131
+ expiresAt: options.expiresAt || null,
132
+ offlineAccessUntil,
133
+ metadata: options.metadata || null,
134
+ isActive: setActive,
135
+ };
136
+ this.events?.emit(this.tableName, { operation: 'SET_SESSION', session });
137
+ return session;
138
+ }
139
+ /**
140
+ * Retrieves the currently active session.
141
+ * If offline, the session remains active even if server tokens expired, as long as offlineAccessUntil is valid.
142
+ */
143
+ async getActiveSession() {
144
+ const rows = await this.db.execute(`SELECT * FROM ${this.tableName} WHERE is_active = ? LIMIT 1;`, [1]);
145
+ if (!rows || rows.length === 0) {
146
+ return null;
147
+ }
148
+ const session = mapSessionRow(rows[0]);
149
+ const now = Date.now();
150
+ // Check if offline access grace period has expired
151
+ if (session.offlineAccessUntil != null && now > session.offlineAccessUntil) {
152
+ await this.clearSession();
153
+ return null;
154
+ }
155
+ // Touch last active
156
+ await this.touch(session.id);
157
+ return session;
158
+ }
159
+ /**
160
+ * Returns true if there is an active valid session (works offline and online).
161
+ */
162
+ async isAuthenticated() {
163
+ const session = await this.getActiveSession();
164
+ return session !== null;
165
+ }
166
+ /**
167
+ * Retrieves the authenticated user profile object, or null if signed out.
168
+ */
169
+ async getUser() {
170
+ const session = await this.getActiveSession();
171
+ return session ? session.user : null;
172
+ }
173
+ /**
174
+ * Updates last active timestamp.
175
+ */
176
+ async touch(sessionId) {
177
+ const now = Date.now();
178
+ if (sessionId) {
179
+ await this.db.execute(`UPDATE ${this.tableName} SET last_active_at = ? WHERE id = ?;`, [now, sessionId]);
180
+ }
181
+ else {
182
+ await this.db.execute(`UPDATE ${this.tableName} SET last_active_at = ? WHERE is_active = ?;`, [now, 1]);
183
+ }
184
+ }
185
+ /**
186
+ * Partially updates the active user's profile data in SQLite.
187
+ */
188
+ async updateUser(partialUser) {
189
+ const session = await this.getActiveSession();
190
+ if (!session)
191
+ return null;
192
+ const updatedUser = {
193
+ ...session.user,
194
+ ...partialUser,
195
+ };
196
+ const userDataStr = JSON.stringify(updatedUser);
197
+ const now = Date.now();
198
+ await this.db.execute(`UPDATE ${this.tableName} SET user_data = ?, last_active_at = ? WHERE id = ?;`, [userDataStr, now, session.id]);
199
+ session.user = updatedUser;
200
+ session.lastActiveAt = now;
201
+ this.events?.emit(this.tableName, { operation: 'UPDATE_USER', session });
202
+ return session;
203
+ }
204
+ /**
205
+ * Updates access tokens without re-authenticating or resetting the offline grace period.
206
+ */
207
+ async updateTokens(tokens) {
208
+ const session = await this.getActiveSession();
209
+ if (!session)
210
+ return;
211
+ const token = tokens.token !== undefined ? tokens.token : session.token;
212
+ const refreshToken = tokens.refreshToken !== undefined ? tokens.refreshToken : session.refreshToken;
213
+ const expiresAt = tokens.expiresAt !== undefined ? tokens.expiresAt : session.expiresAt;
214
+ const now = Date.now();
215
+ await this.db.execute(`UPDATE ${this.tableName} SET token = ?, refresh_token = ?, expires_at = ?, last_active_at = ? WHERE id = ?;`, [token, refreshToken, expiresAt, now, session.id]);
216
+ session.token = token;
217
+ session.refreshToken = refreshToken;
218
+ session.expiresAt = expiresAt;
219
+ this.events?.emit(this.tableName, { operation: 'UPDATE_TOKENS', session });
220
+ }
221
+ /**
222
+ * Signs out the active user session.
223
+ */
224
+ async clearSession() {
225
+ await this.db.execute(`UPDATE ${this.tableName} SET is_active = ? WHERE is_active = ?;`, [0, 1]);
226
+ this.events?.emit(this.tableName, { operation: 'CLEAR_SESSION' });
227
+ }
228
+ /**
229
+ * Completely purges all stored sessions (e.g. factory reset or privacy wipe).
230
+ */
231
+ async purgeAllSessions() {
232
+ await this.db.execute(`DELETE FROM ${this.tableName};`);
233
+ this.events?.emit(this.tableName, { operation: 'PURGE_SESSIONS' });
234
+ }
235
+ /**
236
+ * Lists all sessions currently cached in SQLite.
237
+ */
238
+ async listSessions() {
239
+ const rows = await this.db.execute(`SELECT * FROM ${this.tableName} ORDER BY last_active_at DESC;`);
240
+ return (rows || []).map((r) => mapSessionRow(r));
241
+ }
242
+ /**
243
+ * Switches the active session to a different account (e.g., multi-account or organization switching offline).
244
+ */
245
+ async switchSession(sessionIdOrUserId) {
246
+ const rows = await this.db.execute(`SELECT * FROM ${this.tableName} WHERE id = ? OR user_id = ? LIMIT 1;`, [sessionIdOrUserId, sessionIdOrUserId]);
247
+ if (!rows || rows.length === 0) {
248
+ return null;
249
+ }
250
+ const targetSession = mapSessionRow(rows[0]);
251
+ await this.db.execute(`UPDATE ${this.tableName} SET is_active = ?;`, [0]);
252
+ await this.db.execute(`UPDATE ${this.tableName} SET is_active = ?, last_active_at = ? WHERE id = ?;`, [1, Date.now(), targetSession.id]);
253
+ targetSession.isActive = true;
254
+ targetSession.lastActiveAt = Date.now();
255
+ this.events?.emit(this.tableName, { operation: 'SWITCH_SESSION', session: targetSession });
256
+ return targetSession;
257
+ }
258
+ }
259
+ exports.SessionManager = SessionManager;
@@ -15,6 +15,7 @@ import { KVManager, type KVStoreOptions } from '../kv/index.js';
15
15
  import { SearchManager } from '../search/index.js';
16
16
  import { BlobStorageManager, type BlobStorageManagerOptions } from '../storage/index.js';
17
17
  import { JobScheduler, type JobSchedulerOptions } from '../scheduler/index.js';
18
+ import { SessionManager, type SessionManagerOptions } from '../auth/session.js';
18
19
  export interface LocalFirstClientConfig {
19
20
  local: LocalDBAdapter;
20
21
  remote: RemoteDBAdapter;
@@ -50,6 +51,7 @@ export interface LocalFirstClientConfig {
50
51
  kv?: KVStoreOptions;
51
52
  storage?: BlobStorageManagerOptions;
52
53
  scheduler?: JobSchedulerOptions;
54
+ session?: SessionManagerOptions;
53
55
  }
54
56
  export declare class TransactionalClient {
55
57
  private parent;
@@ -103,6 +105,7 @@ export declare class LocalFirstClient {
103
105
  readonly search: SearchManager;
104
106
  readonly storage: BlobStorageManager;
105
107
  readonly scheduler: JobScheduler;
108
+ readonly session: SessionManager;
106
109
  private primaryKey;
107
110
  private migrations;
108
111
  private autoStart;
@@ -20,6 +20,7 @@ const index_js_4 = require("../kv/index.js");
20
20
  const index_js_5 = require("../search/index.js");
21
21
  const index_js_6 = require("../storage/index.js");
22
22
  const index_js_7 = require("../scheduler/index.js");
23
+ const session_js_1 = require("../auth/session.js");
23
24
  function hasFunctionFilter(value) {
24
25
  if (typeof value === 'function')
25
26
  return true;
@@ -178,6 +179,7 @@ class LocalFirstClient {
178
179
  search;
179
180
  storage;
180
181
  scheduler;
182
+ session;
181
183
  primaryKey;
182
184
  migrations;
183
185
  autoStart;
@@ -210,6 +212,8 @@ class LocalFirstClient {
210
212
  '_local_job_runs',
211
213
  '_local_api_keys',
212
214
  '_local_actions',
215
+ '_local_sessions',
216
+ '_local_sessions',
213
217
  ]);
214
218
  const actionNetwork = config.actions?.network ?? config.network;
215
219
  this.keys = new index_js_3.ApiKeyManager(this.db, config.keys);
@@ -220,6 +224,10 @@ class LocalFirstClient {
220
224
  ...config.storage,
221
225
  });
222
226
  this.scheduler = new index_js_7.JobScheduler(this.db, config.scheduler);
227
+ this.session = new session_js_1.SessionManager(this.db, this.events, {
228
+ network: config.network,
229
+ ...config.session,
230
+ });
223
231
  this.actions = new index_js_2.ActionManager(this.db, this.events, () => Promise.resolve(actionNetwork ? actionNetwork.isOnline() : true), {
224
232
  network: actionNetwork,
225
233
  ...config.actions,
@@ -387,6 +395,7 @@ class LocalFirstClient {
387
395
  await this.kv.initialize();
388
396
  await this.storage.initialize();
389
397
  await this.scheduler.initialize();
398
+ await this.session.initialize();
390
399
  if (this.migrations.length > 0) {
391
400
  await this.db.transaction(async (tx) => {
392
401
  for (const query of this.migrations) {
@@ -133,3 +133,4 @@ export * from './auth.js';
133
133
  export * from './backups.js';
134
134
  export * from './kv.js';
135
135
  export * from './search.js';
136
+ export * from './session.js';
@@ -648,3 +648,4 @@ __exportStar(require("./auth.js"), exports);
648
648
  __exportStar(require("./backups.js"), exports);
649
649
  __exportStar(require("./kv.js"), exports);
650
650
  __exportStar(require("./search.js"), exports);
651
+ __exportStar(require("./session.js"), exports);
@@ -0,0 +1,26 @@
1
+ import { LocalFirstClient } from '../core/client.js';
2
+ import { SessionRecord, CreateSessionOptions } from '../auth/session.js';
3
+ export interface UseSessionResult<TUser = any> {
4
+ session: SessionRecord<TUser> | null;
5
+ user: TUser | null;
6
+ isAuthenticated: boolean;
7
+ isOffline: boolean;
8
+ loading: boolean;
9
+ createSession: (options: CreateSessionOptions<TUser>) => Promise<SessionRecord<TUser>>;
10
+ updateUser: (partialUser: Partial<TUser>) => Promise<SessionRecord<TUser> | null>;
11
+ updateTokens: (tokens: {
12
+ token?: string | null;
13
+ refreshToken?: string | null;
14
+ expiresAt?: number | null;
15
+ }) => Promise<void>;
16
+ signOut: () => Promise<void>;
17
+ refetchSession: () => Promise<SessionRecord<TUser> | null>;
18
+ }
19
+ /**
20
+ * Reactive React hook for persistent, offline-first user session management.
21
+ * The session remains authenticated even when offline, ensuring uninterrupted UX.
22
+ *
23
+ * Example:
24
+ * const { user, isAuthenticated, isOffline, signOut } = useSession(client);
25
+ */
26
+ export declare function useSession<TUser = any>(client: LocalFirstClient | null | undefined): UseSessionResult<TUser>;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSession = useSession;
4
+ const react_1 = require("react");
5
+ /**
6
+ * Reactive React hook for persistent, offline-first user session management.
7
+ * The session remains authenticated even when offline, ensuring uninterrupted UX.
8
+ *
9
+ * Example:
10
+ * const { user, isAuthenticated, isOffline, signOut } = useSession(client);
11
+ */
12
+ function useSession(client) {
13
+ const [session, setSession] = (0, react_1.useState)(null);
14
+ const [loading, setLoading] = (0, react_1.useState)(true);
15
+ const [isOffline, setIsOffline] = (0, react_1.useState)(false);
16
+ const loadSession = (0, react_1.useCallback)(async () => {
17
+ if (!client) {
18
+ setSession(null);
19
+ setLoading(false);
20
+ return null;
21
+ }
22
+ try {
23
+ const active = await client.session.getActiveSession();
24
+ setSession(active);
25
+ return active;
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ finally {
31
+ setLoading(false);
32
+ }
33
+ }, [client]);
34
+ (0, react_1.useEffect)(() => {
35
+ if (!client) {
36
+ setSession(null);
37
+ setLoading(false);
38
+ return;
39
+ }
40
+ let isMounted = true;
41
+ // Check network
42
+ const checkNetwork = () => {
43
+ const net = client.syncWorker?.networkStatusProvider;
44
+ if (net && typeof net.isOnline === 'function') {
45
+ const res = net.isOnline();
46
+ if (typeof res === 'boolean') {
47
+ if (isMounted)
48
+ setIsOffline(!res);
49
+ }
50
+ else if (res && typeof res.then === 'function') {
51
+ res.then((online) => {
52
+ if (isMounted)
53
+ setIsOffline(!online);
54
+ });
55
+ }
56
+ }
57
+ };
58
+ checkNetwork();
59
+ loadSession();
60
+ // Listen to session changes
61
+ const unsubscribeSession = client.events.on('_local_sessions', () => {
62
+ if (isMounted) {
63
+ loadSession();
64
+ }
65
+ });
66
+ // Listen to network changes if available
67
+ const unsubscribeNetwork = client.events.on('network', (status) => {
68
+ if (isMounted && status && typeof status.online === 'boolean') {
69
+ setIsOffline(!status.online);
70
+ }
71
+ });
72
+ return () => {
73
+ isMounted = false;
74
+ unsubscribeSession();
75
+ if (typeof unsubscribeNetwork === 'function') {
76
+ unsubscribeNetwork();
77
+ }
78
+ };
79
+ }, [client, loadSession]);
80
+ const createSession = (0, react_1.useCallback)(async (options) => {
81
+ if (!client)
82
+ throw new Error('Client not provided to useSession.');
83
+ const res = await client.session.createSession(options);
84
+ setSession(res);
85
+ return res;
86
+ }, [client]);
87
+ const updateUser = (0, react_1.useCallback)(async (partialUser) => {
88
+ if (!client)
89
+ return null;
90
+ const res = await client.session.updateUser(partialUser);
91
+ setSession(res);
92
+ return res;
93
+ }, [client]);
94
+ const updateTokens = (0, react_1.useCallback)(async (tokens) => {
95
+ if (!client)
96
+ return;
97
+ await client.session.updateTokens(tokens);
98
+ await loadSession();
99
+ }, [client, loadSession]);
100
+ const signOut = (0, react_1.useCallback)(async () => {
101
+ if (!client)
102
+ return;
103
+ await client.session.clearSession();
104
+ setSession(null);
105
+ }, [client]);
106
+ return {
107
+ session,
108
+ user: session ? session.user : null,
109
+ isAuthenticated: session !== null,
110
+ isOffline,
111
+ loading,
112
+ createSession,
113
+ updateUser,
114
+ updateTokens,
115
+ signOut,
116
+ refetchSession: loadSession,
117
+ };
118
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-lite",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "description": "Never let a lost connection break a promise. Local-first sync that faithfully keeps data safe until you're back online.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",