local-lite 0.0.14 → 0.0.16

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.
@@ -34,10 +34,6 @@ export interface SupabaseAdapterOptions {
34
34
  * Default: true
35
35
  */
36
36
  deletedValue?: any;
37
- /**
38
- * Legacy alias for deletedColumn.
39
- */
40
- deletedAtColumn?: string;
41
37
  /**
42
38
  * Optional custom Postgres RPC function name for batch pushing.
43
39
  * If provided, will call `supabase.rpc(pushRpcName, { operations })`.
@@ -89,7 +85,7 @@ export declare class SupabaseRemoteAdapter implements RemoteDBAdapter {
89
85
  */
90
86
  getClient(): AnySupabaseClient;
91
87
  /**
92
- * Property getter for backwards-compatibility.
88
+ * Active Supabase client instance.
93
89
  */
94
90
  get client(): AnySupabaseClient;
95
91
  /**
@@ -38,7 +38,7 @@ class SupabaseRemoteAdapter {
38
38
  this.scopedTables = options.scopedTables;
39
39
  this.updatedAtColumn = options.updatedAtColumn ?? 'updated_at';
40
40
  this.primaryKey = options.primaryKey ?? 'id';
41
- this.deletedColumn = options.deletedColumn ?? options.deletedAtColumn ?? 'deleted';
41
+ this.deletedColumn = options.deletedColumn ?? 'deleted';
42
42
  this.deletedValue = options.deletedValue !== undefined ? options.deletedValue : true;
43
43
  this.pushRpcName = options.pushRpcName;
44
44
  this.schema = options.schema ?? 'public';
@@ -61,7 +61,7 @@ class SupabaseRemoteAdapter {
61
61
  return this.clientResolver ?? null;
62
62
  }
63
63
  /**
64
- * Property getter for backwards-compatibility.
64
+ * Active Supabase client instance.
65
65
  */
66
66
  get client() {
67
67
  return this.getClient();
@@ -1,4 +1,4 @@
1
- import { GoogleDriveBackupStorage } from '../backups/cloud-storage.js';
1
+ import { GoogleDriveBackupStorage, GoogleDriveBackupClient, type GoogleDriveBackupClientOptions } from '../backups/cloud-storage.js';
2
2
  export declare const GOOGLE_AUTHORIZATION_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth";
3
3
  export declare const GOOGLE_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
4
4
  export declare const GOOGLE_USERINFO_ENDPOINT = "https://www.googleapis.com/oauth2/v3/userinfo";
@@ -72,4 +72,5 @@ export declare class GoogleAuthClient {
72
72
  getValidAccessToken(): Promise<string>;
73
73
  private fetchUserProfile;
74
74
  createDriveBackupStorage(): GoogleDriveBackupStorage;
75
+ createDriveBackupClient(options?: Partial<GoogleDriveBackupClientOptions>): GoogleDriveBackupClient;
75
76
  }
@@ -319,5 +319,12 @@ class GoogleAuthClient {
319
319
  createDriveBackupStorage() {
320
320
  return new cloud_storage_js_1.GoogleDriveBackupStorage(() => this.getValidAccessToken(), this.fetcher);
321
321
  }
322
+ createDriveBackupClient(options = {}) {
323
+ return new cloud_storage_js_1.GoogleDriveBackupClient({
324
+ authClient: this,
325
+ fetch: this.fetcher,
326
+ ...options,
327
+ });
328
+ }
322
329
  }
323
330
  exports.GoogleAuthClient = GoogleAuthClient;
@@ -1,3 +1,4 @@
1
+ import { OneDriveBackupStorage, OneDriveBackupClient, type OneDriveBackupClientOptions } from '../backups/onedrive.js';
1
2
  export declare const MICROSOFT_GRAPH_ENDPOINT = "https://graph.microsoft.com/v1.0";
2
3
  export declare const DEFAULT_MICROSOFT_AUTH_SCOPES: string[];
3
4
  export interface MicrosoftUser {
@@ -9,7 +10,6 @@ export interface MicrosoftUser {
9
10
  picture?: string;
10
11
  userPrincipalName?: string;
11
12
  }
12
- export type OneDriveUser = MicrosoftUser;
13
13
  export interface MicrosoftAuthTokens {
14
14
  accessToken: string;
15
15
  refreshToken?: string;
@@ -53,7 +53,6 @@ export interface MicrosoftAuthClientOptions {
53
53
  }
54
54
  export declare function createInMemoryMicrosoftTokenStore(): MicrosoftAuthTokenStore;
55
55
  export declare function createMicrosoftAuthTokenStore(storage: MicrosoftAuthKeyValueStorage, prefix?: string): MicrosoftAuthTokenStore;
56
- export declare const createOneDriveAuthTokenStore: typeof createMicrosoftAuthTokenStore;
57
56
  export declare class MicrosoftAuthClient {
58
57
  private readonly options;
59
58
  private readonly tokenStore;
@@ -72,5 +71,6 @@ export declare class MicrosoftAuthClient {
72
71
  getUser(): Promise<MicrosoftUser | null>;
73
72
  getValidAccessToken(): Promise<string>;
74
73
  private fetchUserProfile;
74
+ createOneDriveBackupStorage(): OneDriveBackupStorage;
75
+ createOneDriveBackupClient(options?: Partial<OneDriveBackupClientOptions>): OneDriveBackupClient;
75
76
  }
76
- export declare const OneDriveAuthClient: typeof MicrosoftAuthClient;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OneDriveAuthClient = exports.MicrosoftAuthClient = exports.createOneDriveAuthTokenStore = exports.DEFAULT_MICROSOFT_AUTH_SCOPES = exports.MICROSOFT_GRAPH_ENDPOINT = void 0;
3
+ exports.MicrosoftAuthClient = exports.DEFAULT_MICROSOFT_AUTH_SCOPES = exports.MICROSOFT_GRAPH_ENDPOINT = void 0;
4
4
  exports.createInMemoryMicrosoftTokenStore = createInMemoryMicrosoftTokenStore;
5
5
  exports.createMicrosoftAuthTokenStore = createMicrosoftAuthTokenStore;
6
6
  const sha2_js_1 = require("@noble/hashes/sha2.js");
7
7
  const utils_js_1 = require("@noble/hashes/utils.js");
8
+ const onedrive_js_1 = require("../backups/onedrive.js");
8
9
  exports.MICROSOFT_GRAPH_ENDPOINT = 'https://graph.microsoft.com/v1.0';
9
10
  exports.DEFAULT_MICROSOFT_AUTH_SCOPES = ['openid', 'profile', 'email', 'User.Read'];
10
11
  function secureRandomBytes(length) {
@@ -89,7 +90,6 @@ function createMicrosoftAuthTokenStore(storage, prefix = 'local-lite-microsoft-a
89
90
  },
90
91
  };
91
92
  }
92
- exports.createOneDriveAuthTokenStore = createMicrosoftAuthTokenStore;
93
93
  class MicrosoftAuthClient {
94
94
  options;
95
95
  tokenStore;
@@ -305,6 +305,15 @@ class MicrosoftAuthClient {
305
305
  userPrincipalName: raw.userPrincipalName,
306
306
  };
307
307
  }
308
+ createOneDriveBackupStorage() {
309
+ return new onedrive_js_1.OneDriveBackupStorage(() => this.getValidAccessToken(), this.fetcher);
310
+ }
311
+ createOneDriveBackupClient(options) {
312
+ return new onedrive_js_1.OneDriveBackupClient({
313
+ authClient: this,
314
+ fetch: this.fetcher,
315
+ ...options,
316
+ });
317
+ }
308
318
  }
309
319
  exports.MicrosoftAuthClient = MicrosoftAuthClient;
310
- exports.OneDriveAuthClient = MicrosoftAuthClient;
@@ -1,4 +1,6 @@
1
- import type { BackupStorage } from './index.js';
1
+ import type { BackupStorage, CloudBackupClient, CreateDatabaseBackupOptions, ResolvableBackupDatabase } from './operations.js';
2
+ import type { EncryptedBackupOptions, RestoreEncryptedBackupOptions } from './encryption.js';
3
+ import type { GoogleAuthClient } from '../auth/google.js';
2
4
  export interface CloudBackupFile {
3
5
  id: string;
4
6
  name: string;
@@ -6,6 +8,7 @@ export interface CloudBackupFile {
6
8
  size?: number;
7
9
  }
8
10
  export type BackupAccessTokenProvider = () => Promise<string>;
11
+ export declare const GOOGLE_DRIVE_SCOPE = "https://www.googleapis.com/auth/drive.file";
9
12
  export interface GoogleDriveTokens {
10
13
  accessToken: string;
11
14
  refreshToken?: string;
@@ -30,13 +33,16 @@ export interface GoogleDriveAuthorizationResponse {
30
33
  state: string;
31
34
  }
32
35
  export interface GoogleDriveBackupClientOptions {
33
- clientId: string;
34
- redirectUri: string;
35
- authorize: (request: GoogleDriveAuthorizationRequest) => Promise<GoogleDriveAuthorizationResponse | null>;
36
- tokenStore: GoogleDriveTokenStore;
36
+ authClient?: GoogleAuthClient;
37
+ clientId?: string;
38
+ redirectUri?: string;
39
+ authorize?: (request: GoogleDriveAuthorizationRequest) => Promise<GoogleDriveAuthorizationResponse | null>;
40
+ tokenStore?: GoogleDriveTokenStore;
41
+ storage?: GoogleDriveKeyValueStorage;
37
42
  randomBytes?: (length: number) => Uint8Array;
38
43
  fetch?: typeof fetch;
39
44
  }
45
+ export declare function createInMemoryGoogleDriveTokenStore(): GoogleDriveTokenStore;
40
46
  export declare function createGoogleDriveTokenStore(storage: GoogleDriveKeyValueStorage, key?: string): GoogleDriveTokenStore;
41
47
  export declare class GoogleDriveBackupStorage implements BackupStorage {
42
48
  private readonly getAccessToken;
@@ -44,18 +50,28 @@ export declare class GoogleDriveBackupStorage implements BackupStorage {
44
50
  constructor(getAccessToken: BackupAccessTokenProvider, fetcher?: typeof fetch);
45
51
  save(fileName: string, data: Uint8Array): Promise<void>;
46
52
  read(fileId: string): Promise<Uint8Array>;
53
+ delete(fileId: string): Promise<void>;
47
54
  list(): Promise<CloudBackupFile[]>;
48
55
  }
49
- export declare class GoogleDriveBackupClient implements BackupStorage {
56
+ export declare class GoogleDriveBackupClient implements CloudBackupClient {
50
57
  private readonly options;
51
58
  private readonly storage;
52
59
  private readonly fetcher;
60
+ private readonly authClient?;
61
+ private readonly tokenStore?;
62
+ private readonly listeners;
53
63
  constructor(options: GoogleDriveBackupClientOptions);
64
+ onStatusChange(listener: (connected: boolean) => void): () => void;
65
+ private notify;
54
66
  connect(): Promise<boolean>;
55
67
  disconnect(): Promise<void>;
56
68
  isConnected(): Promise<boolean>;
57
69
  getValidAccessToken(): Promise<string>;
58
70
  save(fileName: string, data: Uint8Array): Promise<void>;
59
71
  read(fileId: string): Promise<Uint8Array>;
72
+ delete(fileId: string): Promise<void>;
73
+ deleteBackup(fileId: string): Promise<void>;
60
74
  list(): Promise<CloudBackupFile[]>;
75
+ backup(database: ResolvableBackupDatabase, options?: CreateDatabaseBackupOptions & Partial<EncryptedBackupOptions>): Promise<string>;
76
+ restore(database: ResolvableBackupDatabase, fileNameOrId: string, options?: Partial<RestoreEncryptedBackupOptions>): Promise<void>;
61
77
  }
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GoogleDriveBackupClient = exports.GoogleDriveBackupStorage = void 0;
3
+ exports.GoogleDriveBackupClient = exports.GoogleDriveBackupStorage = exports.GOOGLE_DRIVE_SCOPE = void 0;
4
+ exports.createInMemoryGoogleDriveTokenStore = createInMemoryGoogleDriveTokenStore;
4
5
  exports.createGoogleDriveTokenStore = createGoogleDriveTokenStore;
5
6
  const sha2_js_1 = require("@noble/hashes/sha2.js");
6
7
  const utils_js_1 = require("@noble/hashes/utils.js");
8
+ const operations_js_1 = require("./operations.js");
7
9
  const GOOGLE_API = 'https://www.googleapis.com/drive/v3';
8
10
  const GOOGLE_UPLOAD_API = 'https://www.googleapis.com/upload/drive/v3';
9
11
  const GOOGLE_AUTHORIZATION_ENDPOINT = 'https://accounts.google.com/o/oauth2/v2/auth';
10
12
  const GOOGLE_TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token';
11
- const GOOGLE_DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive.file';
13
+ exports.GOOGLE_DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive.file';
12
14
  const BACKUP_FOLDER = 'backups';
13
15
  function secureRandomBytes(length) {
14
16
  const crypto = globalThis.crypto;
@@ -42,6 +44,18 @@ function validateGoogleTokens(value) {
42
44
  typeof tokens.expiresAt === 'number' &&
43
45
  (tokens.refreshToken === undefined || typeof tokens.refreshToken === 'string'));
44
46
  }
47
+ function createInMemoryGoogleDriveTokenStore() {
48
+ let stored = null;
49
+ return {
50
+ get: async () => stored,
51
+ set: async (tokens) => {
52
+ stored = tokens;
53
+ },
54
+ remove: async () => {
55
+ stored = null;
56
+ },
57
+ };
58
+ }
45
59
  function createGoogleDriveTokenStore(storage, key = 'local-lite-google-drive-backup-tokens') {
46
60
  return {
47
61
  get: async () => {
@@ -165,6 +179,16 @@ class GoogleDriveBackupStorage {
165
179
  throw await parseApiError(response);
166
180
  return new Uint8Array(await response.arrayBuffer());
167
181
  }
182
+ async delete(fileId) {
183
+ const token = await this.getAccessToken();
184
+ const response = await this.fetcher(`${GOOGLE_API}/files/${encodeURIComponent(fileId)}`, {
185
+ method: 'DELETE',
186
+ headers: { Authorization: `Bearer ${token}` },
187
+ });
188
+ if (!response.ok && response.status !== 404) {
189
+ throw await parseApiError(response);
190
+ }
191
+ }
168
192
  async list() {
169
193
  const token = await this.getAccessToken();
170
194
  const folderId = await getGoogleFolderId(token, this.fetcher);
@@ -188,16 +212,60 @@ class GoogleDriveBackupClient {
188
212
  options;
189
213
  storage;
190
214
  fetcher;
215
+ authClient;
216
+ tokenStore;
217
+ listeners = new Set();
191
218
  constructor(options) {
192
219
  this.options = options;
193
- if (!options.clientId.trim())
194
- throw new Error('Google OAuth client ID is required.');
195
- if (!options.redirectUri.trim())
196
- throw new Error('Google OAuth redirect URI is required.');
197
220
  this.fetcher = options.fetch ?? fetch;
198
- this.storage = new GoogleDriveBackupStorage(() => this.getValidAccessToken(), this.fetcher);
221
+ if (options.authClient) {
222
+ this.authClient = options.authClient;
223
+ this.storage = new GoogleDriveBackupStorage(() => this.authClient.getValidAccessToken(), this.fetcher);
224
+ this.authClient.onAuthStateChange(user => {
225
+ this.notify(Boolean(user));
226
+ });
227
+ }
228
+ else {
229
+ if (!options.clientId?.trim()) {
230
+ throw new Error('Google OAuth client ID is required when authClient is not provided.');
231
+ }
232
+ if (!options.redirectUri?.trim()) {
233
+ throw new Error('Google OAuth redirect URI is required when authClient is not provided.');
234
+ }
235
+ if (!options.authorize) {
236
+ throw new Error('Google OAuth authorize function is required when authClient is not provided.');
237
+ }
238
+ this.tokenStore =
239
+ options.tokenStore ??
240
+ (options.storage
241
+ ? createGoogleDriveTokenStore(options.storage)
242
+ : createInMemoryGoogleDriveTokenStore());
243
+ this.storage = new GoogleDriveBackupStorage(() => this.getValidAccessToken(), this.fetcher);
244
+ }
245
+ }
246
+ onStatusChange(listener) {
247
+ this.listeners.add(listener);
248
+ return () => {
249
+ this.listeners.delete(listener);
250
+ };
251
+ }
252
+ notify(connected) {
253
+ for (const listener of this.listeners) {
254
+ try {
255
+ listener(connected);
256
+ }
257
+ catch (err) {
258
+ console.error('Error in GoogleDriveBackupClient status listener:', err);
259
+ }
260
+ }
199
261
  }
200
262
  async connect() {
263
+ if (this.authClient) {
264
+ const user = await this.authClient.signIn();
265
+ const connected = user !== null;
266
+ this.notify(connected);
267
+ return connected;
268
+ }
201
269
  const randomBytes = this.options.randomBytes ?? secureRandomBytes;
202
270
  const verifierBytes = randomBytes(32);
203
271
  const stateBytes = randomBytes(32);
@@ -211,7 +279,7 @@ class GoogleDriveBackupClient {
211
279
  client_id: this.options.clientId,
212
280
  redirect_uri: this.options.redirectUri,
213
281
  response_type: 'code',
214
- scope: GOOGLE_DRIVE_SCOPE,
282
+ scope: exports.GOOGLE_DRIVE_SCOPE,
215
283
  access_type: 'offline',
216
284
  prompt: 'consent',
217
285
  code_challenge: codeChallenge,
@@ -222,8 +290,10 @@ class GoogleDriveBackupClient {
222
290
  authorizationUrl: `${GOOGLE_AUTHORIZATION_ENDPOINT}?${authorizationParams}`,
223
291
  redirectUri: this.options.redirectUri,
224
292
  });
225
- if (!authorization)
293
+ if (!authorization) {
294
+ this.notify(false);
226
295
  return false;
296
+ }
227
297
  if (authorization.state !== state) {
228
298
  throw new Error('Google OAuth state validation failed. Please try connecting again.');
229
299
  }
@@ -244,19 +314,32 @@ class GoogleDriveBackupClient {
244
314
  const payload = await parseTokenResponse(response);
245
315
  if (!response.ok)
246
316
  throwTokenError(payload, response.status);
247
- const prior = await this.options.tokenStore.get();
248
- await this.options.tokenStore.set(createStoredTokens(payload, prior));
317
+ const prior = await this.tokenStore.get();
318
+ await this.tokenStore.set(createStoredTokens(payload, prior));
319
+ this.notify(true);
249
320
  return true;
250
321
  }
251
322
  async disconnect() {
252
- await this.options.tokenStore.remove();
323
+ if (this.authClient) {
324
+ await this.authClient.signOut();
325
+ }
326
+ else if (this.tokenStore) {
327
+ await this.tokenStore.remove();
328
+ }
329
+ this.notify(false);
253
330
  }
254
331
  async isConnected() {
255
- const tokens = await this.options.tokenStore.get();
332
+ if (this.authClient) {
333
+ return this.authClient.isSignedIn();
334
+ }
335
+ const tokens = await this.tokenStore.get();
256
336
  return validateGoogleTokens(tokens);
257
337
  }
258
338
  async getValidAccessToken() {
259
- const tokens = await this.options.tokenStore.get();
339
+ if (this.authClient) {
340
+ return this.authClient.getValidAccessToken();
341
+ }
342
+ const tokens = await this.tokenStore.get();
260
343
  if (!validateGoogleTokens(tokens)) {
261
344
  throw new Error('Connect Google Drive before using cloud backups.');
262
345
  }
@@ -272,14 +355,14 @@ class GoogleDriveBackupClient {
272
355
  client_id: this.options.clientId,
273
356
  grant_type: 'refresh_token',
274
357
  refresh_token: tokens.refreshToken,
275
- scope: GOOGLE_DRIVE_SCOPE,
358
+ scope: exports.GOOGLE_DRIVE_SCOPE,
276
359
  }).toString(),
277
360
  });
278
361
  const payload = await parseTokenResponse(response);
279
362
  if (!response.ok)
280
363
  throwTokenError(payload, response.status);
281
364
  const updatedTokens = createStoredTokens(payload, tokens);
282
- await this.options.tokenStore.set(updatedTokens);
365
+ await this.tokenStore.set(updatedTokens);
283
366
  return updatedTokens.accessToken;
284
367
  }
285
368
  save(fileName, data) {
@@ -288,8 +371,20 @@ class GoogleDriveBackupClient {
288
371
  read(fileId) {
289
372
  return this.storage.read(fileId);
290
373
  }
374
+ delete(fileId) {
375
+ return this.storage.delete(fileId);
376
+ }
377
+ deleteBackup(fileId) {
378
+ return this.delete(fileId);
379
+ }
291
380
  list() {
292
381
  return this.storage.list();
293
382
  }
383
+ backup(database, options) {
384
+ return (0, operations_js_1.performBackup)(database, this, options);
385
+ }
386
+ restore(database, fileNameOrId, options) {
387
+ return (0, operations_js_1.performRestore)(database, this, fileNameOrId, options);
388
+ }
294
389
  }
295
390
  exports.GoogleDriveBackupClient = GoogleDriveBackupClient;
@@ -1,16 +1,4 @@
1
- export { type BackupAccessTokenProvider, type CloudBackupFile, type GoogleDriveAuthorizationRequest, type GoogleDriveAuthorizationResponse, type GoogleDriveBackupClientOptions, type GoogleDriveKeyValueStorage, type GoogleDriveTokenStore, type GoogleDriveTokens, GoogleDriveBackupClient, GoogleDriveBackupStorage, createGoogleDriveTokenStore, } from './cloud-storage.js';
2
- export { MICROSOFT_GRAPH_DRIVE, OneDriveBackupStorage, OneDriveBackupClient, } from './onedrive.js';
1
+ export { type BackupDatabase, type BackupStorage, type CloudBackupClient, type CreateDatabaseBackupOptions, type ResolvableBackupDatabase, createDatabaseBackup, restoreDatabaseBackup, performBackup, performRestore, resolveBackupDatabase, } from './operations.js';
2
+ export { type BackupAccessTokenProvider, type CloudBackupFile, type GoogleDriveAuthorizationRequest, type GoogleDriveAuthorizationResponse, type GoogleDriveBackupClientOptions, type GoogleDriveKeyValueStorage, type GoogleDriveTokenStore, type GoogleDriveTokens, GOOGLE_DRIVE_SCOPE, GoogleDriveBackupClient, GoogleDriveBackupStorage, createGoogleDriveTokenStore, createInMemoryGoogleDriveTokenStore, } from './cloud-storage.js';
3
+ export { type OneDriveBackupClientOptions, MICROSOFT_GRAPH_DRIVE, OneDriveBackupStorage, OneDriveBackupClient, } from './onedrive.js';
3
4
  export { type EncryptedBackupOptions, type RestoreEncryptedBackupOptions, isEncryptedBackup, encryptBackupData, decryptBackupData, createEncryptedDatabaseBackup, restoreEncryptedDatabaseBackup, } from './encryption.js';
4
- export interface BackupDatabase {
5
- exportDatabase(): Promise<Uint8Array>;
6
- importDatabase(data: Uint8Array): Promise<void>;
7
- }
8
- export interface BackupStorage {
9
- save(fileName: string, data: Uint8Array): Promise<void>;
10
- read(fileName: string): Promise<Uint8Array>;
11
- }
12
- export interface CreateDatabaseBackupOptions {
13
- fileName?: string;
14
- }
15
- export declare function createDatabaseBackup(database: BackupDatabase, storage: BackupStorage, options?: CreateDatabaseBackupOptions): Promise<string>;
16
- export declare function restoreDatabaseBackup(database: BackupDatabase, storage: BackupStorage, fileName: string): Promise<void>;
@@ -1,12 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.restoreEncryptedDatabaseBackup = exports.createEncryptedDatabaseBackup = exports.decryptBackupData = exports.encryptBackupData = exports.isEncryptedBackup = exports.OneDriveBackupClient = exports.OneDriveBackupStorage = exports.MICROSOFT_GRAPH_DRIVE = exports.createGoogleDriveTokenStore = exports.GoogleDriveBackupStorage = exports.GoogleDriveBackupClient = void 0;
4
- exports.createDatabaseBackup = createDatabaseBackup;
5
- exports.restoreDatabaseBackup = restoreDatabaseBackup;
3
+ exports.restoreEncryptedDatabaseBackup = exports.createEncryptedDatabaseBackup = exports.decryptBackupData = exports.encryptBackupData = exports.isEncryptedBackup = exports.OneDriveBackupClient = exports.OneDriveBackupStorage = exports.MICROSOFT_GRAPH_DRIVE = exports.createInMemoryGoogleDriveTokenStore = exports.createGoogleDriveTokenStore = exports.GoogleDriveBackupStorage = exports.GoogleDriveBackupClient = exports.GOOGLE_DRIVE_SCOPE = exports.resolveBackupDatabase = exports.performRestore = exports.performBackup = exports.restoreDatabaseBackup = exports.createDatabaseBackup = void 0;
4
+ var operations_js_1 = require("./operations.js");
5
+ Object.defineProperty(exports, "createDatabaseBackup", { enumerable: true, get: function () { return operations_js_1.createDatabaseBackup; } });
6
+ Object.defineProperty(exports, "restoreDatabaseBackup", { enumerable: true, get: function () { return operations_js_1.restoreDatabaseBackup; } });
7
+ Object.defineProperty(exports, "performBackup", { enumerable: true, get: function () { return operations_js_1.performBackup; } });
8
+ Object.defineProperty(exports, "performRestore", { enumerable: true, get: function () { return operations_js_1.performRestore; } });
9
+ Object.defineProperty(exports, "resolveBackupDatabase", { enumerable: true, get: function () { return operations_js_1.resolveBackupDatabase; } });
6
10
  var cloud_storage_js_1 = require("./cloud-storage.js");
11
+ Object.defineProperty(exports, "GOOGLE_DRIVE_SCOPE", { enumerable: true, get: function () { return cloud_storage_js_1.GOOGLE_DRIVE_SCOPE; } });
7
12
  Object.defineProperty(exports, "GoogleDriveBackupClient", { enumerable: true, get: function () { return cloud_storage_js_1.GoogleDriveBackupClient; } });
8
13
  Object.defineProperty(exports, "GoogleDriveBackupStorage", { enumerable: true, get: function () { return cloud_storage_js_1.GoogleDriveBackupStorage; } });
9
14
  Object.defineProperty(exports, "createGoogleDriveTokenStore", { enumerable: true, get: function () { return cloud_storage_js_1.createGoogleDriveTokenStore; } });
15
+ Object.defineProperty(exports, "createInMemoryGoogleDriveTokenStore", { enumerable: true, get: function () { return cloud_storage_js_1.createInMemoryGoogleDriveTokenStore; } });
10
16
  var onedrive_js_1 = require("./onedrive.js");
11
17
  Object.defineProperty(exports, "MICROSOFT_GRAPH_DRIVE", { enumerable: true, get: function () { return onedrive_js_1.MICROSOFT_GRAPH_DRIVE; } });
12
18
  Object.defineProperty(exports, "OneDriveBackupStorage", { enumerable: true, get: function () { return onedrive_js_1.OneDriveBackupStorage; } });
@@ -17,26 +23,3 @@ Object.defineProperty(exports, "encryptBackupData", { enumerable: true, get: fun
17
23
  Object.defineProperty(exports, "decryptBackupData", { enumerable: true, get: function () { return encryption_js_1.decryptBackupData; } });
18
24
  Object.defineProperty(exports, "createEncryptedDatabaseBackup", { enumerable: true, get: function () { return encryption_js_1.createEncryptedDatabaseBackup; } });
19
25
  Object.defineProperty(exports, "restoreEncryptedDatabaseBackup", { enumerable: true, get: function () { return encryption_js_1.restoreEncryptedDatabaseBackup; } });
20
- function validateFileName(fileName) {
21
- if (!fileName || /[\\/]/.test(fileName)) {
22
- throw new Error('Backup file name must be a single file name.');
23
- }
24
- }
25
- async function createDatabaseBackup(database, storage, options = {}) {
26
- const fileName = options.fileName ?? `local-lite-${new Date().toISOString().replace(/[:.]/g, '-')}.db`;
27
- validateFileName(fileName);
28
- const databaseBytes = await database.exportDatabase();
29
- if (databaseBytes.length === 0) {
30
- throw new Error('Cannot create a backup from an empty database.');
31
- }
32
- await storage.save(fileName, databaseBytes);
33
- return fileName;
34
- }
35
- async function restoreDatabaseBackup(database, storage, fileName) {
36
- validateFileName(fileName);
37
- const databaseBytes = await storage.read(fileName);
38
- if (databaseBytes.length === 0) {
39
- throw new Error('Cannot restore an empty database backup.');
40
- }
41
- await database.importDatabase(databaseBytes);
42
- }
@@ -1,5 +1,7 @@
1
- import type { BackupAccessTokenProvider, BackupStorage, CloudBackupFile } from './index.js';
2
- import { type MicrosoftAuthClientOptions } from '../auth/microsoft.js';
1
+ import type { BackupAccessTokenProvider, BackupStorage, CloudBackupClient, CreateDatabaseBackupOptions, ResolvableBackupDatabase } from './operations.js';
2
+ import type { CloudBackupFile } from './cloud-storage.js';
3
+ import type { EncryptedBackupOptions, RestoreEncryptedBackupOptions } from './encryption.js';
4
+ import { MicrosoftAuthClient, type MicrosoftAuthClientOptions } from '../auth/microsoft.js';
3
5
  export declare const MICROSOFT_GRAPH_DRIVE = "https://graph.microsoft.com/v1.0/me/drive";
4
6
  export declare class OneDriveBackupStorage implements BackupStorage {
5
7
  private readonly getAccessToken;
@@ -7,16 +9,28 @@ export declare class OneDriveBackupStorage implements BackupStorage {
7
9
  constructor(getAccessToken: BackupAccessTokenProvider, fetcher?: typeof fetch);
8
10
  save(fileName: string, data: Uint8Array): Promise<void>;
9
11
  read(fileIdOrName: string): Promise<Uint8Array>;
12
+ delete(fileIdOrName: string): Promise<void>;
10
13
  list(): Promise<CloudBackupFile[]>;
11
14
  }
12
- export declare class OneDriveBackupClient implements BackupStorage {
15
+ export type OneDriveBackupClientOptions = MicrosoftAuthClientOptions | {
16
+ authClient: MicrosoftAuthClient;
17
+ fetch?: typeof fetch;
18
+ };
19
+ export declare class OneDriveBackupClient implements CloudBackupClient {
13
20
  private readonly storage;
14
21
  private readonly authClient;
15
- constructor(options: MicrosoftAuthClientOptions);
22
+ private readonly listeners;
23
+ constructor(options: OneDriveBackupClientOptions);
24
+ onStatusChange(listener: (connected: boolean) => void): () => void;
25
+ private notify;
16
26
  connect(): Promise<boolean>;
17
27
  disconnect(): Promise<void>;
18
28
  isConnected(): Promise<boolean>;
19
29
  save(fileName: string, data: Uint8Array): Promise<void>;
20
30
  read(fileId: string): Promise<Uint8Array>;
31
+ delete(fileIdOrName: string): Promise<void>;
32
+ deleteBackup(fileIdOrName: string): Promise<void>;
21
33
  list(): Promise<CloudBackupFile[]>;
34
+ backup(database: ResolvableBackupDatabase, options?: CreateDatabaseBackupOptions & Partial<EncryptedBackupOptions>): Promise<string>;
35
+ restore(database: ResolvableBackupDatabase, fileNameOrId: string, options?: Partial<RestoreEncryptedBackupOptions>): Promise<void>;
22
36
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OneDriveBackupClient = exports.OneDriveBackupStorage = exports.MICROSOFT_GRAPH_DRIVE = void 0;
4
+ const operations_js_1 = require("./operations.js");
4
5
  const microsoft_js_1 = require("../auth/microsoft.js");
5
6
  exports.MICROSOFT_GRAPH_DRIVE = 'https://graph.microsoft.com/v1.0/me/drive';
6
7
  const BACKUP_FOLDER = 'backups';
@@ -50,6 +51,20 @@ class OneDriveBackupStorage {
50
51
  }
51
52
  return new Uint8Array(await response.arrayBuffer());
52
53
  }
54
+ async delete(fileIdOrName) {
55
+ const token = await this.getAccessToken();
56
+ let url = `${exports.MICROSOFT_GRAPH_DRIVE}/items/${encodeURIComponent(fileIdOrName)}`;
57
+ if (fileIdOrName.endsWith('.db') && !fileIdOrName.startsWith('item-')) {
58
+ url = `${exports.MICROSOFT_GRAPH_DRIVE}/special/approot:/${BACKUP_FOLDER}/${encodeURIComponent(fileIdOrName)}`;
59
+ }
60
+ const response = await this.fetcher(url, {
61
+ method: 'DELETE',
62
+ headers: { Authorization: `Bearer ${token}` },
63
+ });
64
+ if (!response.ok && response.status !== 404) {
65
+ throw new Error(`OneDrive delete failed (${response.status}): ${response.statusText}`);
66
+ }
67
+ }
53
68
  async list() {
54
69
  const token = await this.getAccessToken();
55
70
  const url = `${exports.MICROSOFT_GRAPH_DRIVE}/special/approot:/${BACKUP_FOLDER}:/children?$select=id,name,size,lastModifiedDateTime`;
@@ -77,26 +92,56 @@ exports.OneDriveBackupStorage = OneDriveBackupStorage;
77
92
  class OneDriveBackupClient {
78
93
  storage;
79
94
  authClient;
95
+ listeners = new Set();
80
96
  constructor(options) {
81
- const scopes = options.scopes ?? [
82
- 'openid',
83
- 'profile',
84
- 'email',
85
- 'User.Read',
86
- 'Files.ReadWrite.AppFolder',
87
- ];
88
- this.authClient = new microsoft_js_1.MicrosoftAuthClient({
89
- ...options,
90
- scopes,
97
+ if ('authClient' in options && options.authClient) {
98
+ this.authClient = options.authClient;
99
+ this.storage = new OneDriveBackupStorage(() => this.authClient.getValidAccessToken(), options.fetch ?? fetch);
100
+ }
101
+ else {
102
+ const msOptions = options;
103
+ const scopes = msOptions.scopes ?? [
104
+ 'openid',
105
+ 'profile',
106
+ 'email',
107
+ 'User.Read',
108
+ 'Files.ReadWrite.AppFolder',
109
+ ];
110
+ this.authClient = new microsoft_js_1.MicrosoftAuthClient({
111
+ ...msOptions,
112
+ scopes,
113
+ });
114
+ this.storage = new OneDriveBackupStorage(() => this.authClient.getValidAccessToken(), msOptions.fetch ?? fetch);
115
+ }
116
+ this.authClient.onAuthStateChange(user => {
117
+ this.notify(Boolean(user));
91
118
  });
92
- this.storage = new OneDriveBackupStorage(() => this.authClient.getValidAccessToken(), options.fetch ?? fetch);
119
+ }
120
+ onStatusChange(listener) {
121
+ this.listeners.add(listener);
122
+ return () => {
123
+ this.listeners.delete(listener);
124
+ };
125
+ }
126
+ notify(connected) {
127
+ for (const listener of this.listeners) {
128
+ try {
129
+ listener(connected);
130
+ }
131
+ catch (err) {
132
+ console.error('Error in OneDriveBackupClient status listener:', err);
133
+ }
134
+ }
93
135
  }
94
136
  async connect() {
95
137
  const user = await this.authClient.signIn();
96
- return user !== null;
138
+ const connected = user !== null;
139
+ this.notify(connected);
140
+ return connected;
97
141
  }
98
142
  async disconnect() {
99
143
  await this.authClient.signOut();
144
+ this.notify(false);
100
145
  }
101
146
  async isConnected() {
102
147
  return this.authClient.isSignedIn();
@@ -107,8 +152,20 @@ class OneDriveBackupClient {
107
152
  read(fileId) {
108
153
  return this.storage.read(fileId);
109
154
  }
155
+ delete(fileIdOrName) {
156
+ return this.storage.delete(fileIdOrName);
157
+ }
158
+ deleteBackup(fileIdOrName) {
159
+ return this.delete(fileIdOrName);
160
+ }
110
161
  list() {
111
162
  return this.storage.list();
112
163
  }
164
+ backup(database, options) {
165
+ return (0, operations_js_1.performBackup)(database, this, options);
166
+ }
167
+ restore(database, fileNameOrId, options) {
168
+ return (0, operations_js_1.performRestore)(database, this, fileNameOrId, options);
169
+ }
113
170
  }
114
171
  exports.OneDriveBackupClient = OneDriveBackupClient;