@affectively/dash 5.1.0 → 5.2.0

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.
Files changed (36) hide show
  1. package/README.md +21 -0
  2. package/dist/src/api/firebase/auth/index.d.ts +137 -0
  3. package/dist/src/api/firebase/auth/index.js +352 -0
  4. package/dist/src/api/firebase/auth/providers.d.ts +254 -0
  5. package/dist/src/api/firebase/auth/providers.js +518 -0
  6. package/dist/src/api/firebase/database/index.d.ts +108 -0
  7. package/dist/src/api/firebase/database/index.js +368 -0
  8. package/dist/src/api/firebase/errors.d.ts +15 -0
  9. package/dist/src/api/firebase/errors.js +215 -0
  10. package/dist/src/api/firebase/firestore/data-types.d.ts +116 -0
  11. package/dist/src/api/firebase/firestore/data-types.js +280 -0
  12. package/dist/src/api/firebase/firestore/index.d.ts +7 -0
  13. package/dist/src/api/firebase/firestore/index.js +13 -0
  14. package/dist/src/api/firebase/firestore/listeners.d.ts +20 -0
  15. package/dist/src/api/firebase/firestore/listeners.js +50 -0
  16. package/dist/src/api/firebase/firestore/operations.d.ts +123 -0
  17. package/dist/src/api/firebase/firestore/operations.js +490 -0
  18. package/dist/src/api/firebase/firestore/query.d.ts +118 -0
  19. package/dist/src/api/firebase/firestore/query.js +418 -0
  20. package/dist/src/api/firebase/index.d.ts +11 -0
  21. package/dist/src/api/firebase/index.js +17 -0
  22. package/dist/src/api/firebase/storage/index.d.ts +100 -0
  23. package/dist/src/api/firebase/storage/index.js +286 -0
  24. package/dist/src/api/firebase/types.d.ts +341 -0
  25. package/dist/src/api/firebase/types.js +4 -0
  26. package/dist/src/auth/manager.d.ts +5 -1
  27. package/dist/src/auth/manager.js +19 -6
  28. package/dist/src/engine/sqlite.d.ts +129 -0
  29. package/dist/src/engine/sqlite.js +525 -0
  30. package/dist/src/index.d.ts +8 -0
  31. package/dist/src/index.js +17 -0
  32. package/dist/src/sync/aeon/offline-adapter.js +12 -8
  33. package/dist/src/sync/d1-provider.d.ts +97 -0
  34. package/dist/src/sync/d1-provider.js +345 -0
  35. package/dist/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +1 -1
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Firebase Cloud Storage API
3
+ */
4
+ import { createFirebaseError } from '../errors.js';
5
+ /**
6
+ * Storage reference implementation
7
+ */
8
+ export class StorageReferenceImpl {
9
+ storage;
10
+ _location;
11
+ bucket;
12
+ fullPath;
13
+ name;
14
+ parent;
15
+ root;
16
+ constructor(storage, bucket, path) {
17
+ this.storage = storage;
18
+ this.bucket = bucket;
19
+ this.fullPath = path;
20
+ this._location = { bucket, path };
21
+ // Extract file name
22
+ const segments = path.split('/');
23
+ this.name = segments[segments.length - 1] || '';
24
+ // Set parent
25
+ if (segments.length > 1) {
26
+ const parentPath = segments.slice(0, -1).join('/');
27
+ this.parent = new StorageReferenceImpl(storage, bucket, parentPath);
28
+ }
29
+ else {
30
+ this.parent = null;
31
+ }
32
+ // Set root
33
+ this.root = this;
34
+ let current = this.parent;
35
+ while (current) {
36
+ this.root = current;
37
+ current = current.parent;
38
+ }
39
+ }
40
+ toString() {
41
+ return `StorageReference(${this.bucket}/${this.fullPath})`;
42
+ }
43
+ }
44
+ /**
45
+ * Upload task implementation
46
+ */
47
+ export class UploadTaskImpl {
48
+ _ref;
49
+ _data;
50
+ _metadata;
51
+ _paused = false;
52
+ _cancelled = false;
53
+ _progress = 0;
54
+ _listeners = new Set();
55
+ _errorListeners = new Set();
56
+ _completeListeners = new Set();
57
+ constructor(ref, data, metadata) {
58
+ this._ref = ref;
59
+ this._data = data;
60
+ this._metadata = metadata || {};
61
+ }
62
+ on(event, nextOrObserver, error, complete) {
63
+ if (event === 'state_changed') {
64
+ if (typeof nextOrObserver === 'function') {
65
+ this._listeners.add(nextOrObserver);
66
+ }
67
+ else if (nextOrObserver && typeof nextOrObserver.next === 'function') {
68
+ this._listeners.add(nextOrObserver.next);
69
+ }
70
+ if (error) {
71
+ this._errorListeners.add(error);
72
+ }
73
+ if (complete) {
74
+ this._completeListeners.add(complete);
75
+ }
76
+ return () => {
77
+ this._listeners.clear();
78
+ this._errorListeners.clear();
79
+ this._completeListeners.clear();
80
+ };
81
+ }
82
+ return () => { };
83
+ }
84
+ async then(onFulfilled, onRejected) {
85
+ try {
86
+ const snapshot = await this._performUpload();
87
+ return onFulfilled?.(snapshot);
88
+ }
89
+ catch (error) {
90
+ return onRejected?.(error);
91
+ }
92
+ }
93
+ catch(onRejected) {
94
+ return this.then(undefined, onRejected);
95
+ }
96
+ pause() {
97
+ if (!this._cancelled) {
98
+ this._paused = true;
99
+ return true;
100
+ }
101
+ return false;
102
+ }
103
+ resume() {
104
+ if (!this._cancelled) {
105
+ this._paused = false;
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ cancel() {
111
+ if (!this._cancelled) {
112
+ this._cancelled = true;
113
+ return true;
114
+ }
115
+ return false;
116
+ }
117
+ async _performUpload() {
118
+ // Simulate upload progress
119
+ for (let i = 0; i <= 100; i += 10) {
120
+ if (this._cancelled) {
121
+ throw createFirebaseError('storage/cancelled', 'Upload was cancelled');
122
+ }
123
+ if (!this._paused) {
124
+ this._progress = i;
125
+ this._notifyProgress();
126
+ await new Promise(resolve => setTimeout(resolve, 100));
127
+ }
128
+ }
129
+ // Complete upload
130
+ this._progress = 100;
131
+ return this._createSnapshot();
132
+ }
133
+ _createSnapshot() {
134
+ const size = this._data instanceof Blob ? this._data.size : this._data.length;
135
+ return {
136
+ ref: this._ref,
137
+ metadata: {
138
+ bucket: this._ref.bucket,
139
+ fullPath: this._ref.fullPath,
140
+ name: this._ref.name,
141
+ downloadURLs: [`https://${this._ref.bucket}/${this._ref.fullPath}`],
142
+ generation: '1',
143
+ metageneration: '1',
144
+ size,
145
+ timeCreated: new Date().toISOString(),
146
+ updated: new Date().toISOString(),
147
+ ...this._metadata,
148
+ },
149
+ bytesTransferred: Math.floor((size * this._progress) / 100),
150
+ totalBytes: size,
151
+ state: this._cancelled ? 'cancelled' : 'success',
152
+ task: this,
153
+ };
154
+ }
155
+ _notifyProgress() {
156
+ const snapshot = this._createSnapshot();
157
+ this._listeners.forEach(listener => listener(snapshot));
158
+ }
159
+ }
160
+ /**
161
+ * Get storage reference
162
+ */
163
+ export function ref(storage, path) {
164
+ const bucket = storage.bucket || 'default-bucket';
165
+ const refPath = path || '/';
166
+ return new StorageReferenceImpl(storage, bucket, refPath);
167
+ }
168
+ /**
169
+ * Get reference from URL
170
+ */
171
+ export function refFromURL(storage, url) {
172
+ try {
173
+ const urlObj = new URL(url);
174
+ const pathParts = urlObj.pathname.split('/').filter(p => p.length > 0);
175
+ // Extract bucket and path from URL
176
+ const bucket = pathParts[0] || storage.bucket || 'default-bucket';
177
+ const path = pathParts.slice(1).join('/');
178
+ return new StorageReferenceImpl(storage, bucket, path);
179
+ }
180
+ catch (error) {
181
+ throw createFirebaseError('storage/invalid-argument', `Invalid URL: ${url}`);
182
+ }
183
+ }
184
+ /**
185
+ * Get child reference
186
+ */
187
+ export function child(parent, path) {
188
+ const childPath = `${parent.fullPath}/${path}`.replace(/\/{2,}/g, '/');
189
+ return new StorageReferenceImpl(parent.storage, parent.bucket, childPath);
190
+ }
191
+ /**
192
+ * Upload bytes
193
+ */
194
+ export async function uploadBytes(reference, data, metadata) {
195
+ const task = new UploadTaskImpl(reference, data, metadata);
196
+ return task.then();
197
+ }
198
+ /**
199
+ * Upload resumable (with progress tracking)
200
+ */
201
+ export function uploadBytesResumable(reference, data, metadata) {
202
+ return new UploadTaskImpl(reference, data, metadata);
203
+ }
204
+ /**
205
+ * Upload string
206
+ */
207
+ export async function uploadString(reference, value, format, metadata) {
208
+ let data = value;
209
+ if (format === 'base64') {
210
+ // Decode base64
211
+ data = atob(value);
212
+ }
213
+ else if (format === 'base64url') {
214
+ // Decode base64url
215
+ data = atob(value.replace(/-/g, '+').replace(/_/g, '/'));
216
+ }
217
+ else if (format === 'data_url') {
218
+ // Extract data from data URL
219
+ const matches = value.match(/,(.*)$/);
220
+ if (matches) {
221
+ data = atob(matches[1]);
222
+ }
223
+ }
224
+ return uploadBytes(reference, new Blob([data]), metadata);
225
+ }
226
+ /**
227
+ * Download bytes
228
+ */
229
+ export async function getBytes(reference, maxDownloadSizeBytes) {
230
+ // Mock: return empty buffer
231
+ return new ArrayBuffer(0);
232
+ }
233
+ /**
234
+ * Get download URL
235
+ */
236
+ export async function getDownloadURL(reference) {
237
+ return `https://${reference.bucket}.storage.googleapis.com/${reference.fullPath}`;
238
+ }
239
+ /**
240
+ * Get metadata
241
+ */
242
+ export async function getMetadata(reference) {
243
+ return {
244
+ bucket: reference.bucket,
245
+ fullPath: reference.fullPath,
246
+ name: reference.name,
247
+ downloadURLs: [await getDownloadURL(reference)],
248
+ generation: '1',
249
+ metageneration: '1',
250
+ size: 0,
251
+ timeCreated: new Date().toISOString(),
252
+ updated: new Date().toISOString(),
253
+ };
254
+ }
255
+ /**
256
+ * Update metadata
257
+ */
258
+ export async function updateMetadata(reference, metadata) {
259
+ const current = await getMetadata(reference);
260
+ return { ...current, ...metadata };
261
+ }
262
+ /**
263
+ * Delete object
264
+ */
265
+ export async function deleteObject(reference) {
266
+ // Mock delete
267
+ }
268
+ /**
269
+ * List files (with pagination)
270
+ */
271
+ export async function list(reference, options) {
272
+ return {
273
+ prefixes: [],
274
+ items: [],
275
+ nextPageToken: undefined,
276
+ };
277
+ }
278
+ /**
279
+ * List all files
280
+ */
281
+ export async function listAll(reference) {
282
+ return {
283
+ prefixes: [],
284
+ items: [],
285
+ };
286
+ }
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Firebase-compatible type definitions
3
+ */
4
+ export interface FirebaseApp {
5
+ name: string;
6
+ config: FirebaseConfig;
7
+ }
8
+ export interface FirebaseConfig {
9
+ apiKey?: string;
10
+ authDomain?: string;
11
+ projectId?: string;
12
+ storageBucket?: string;
13
+ messagingSenderId?: string;
14
+ appId?: string;
15
+ }
16
+ export interface Firestore {
17
+ app: FirebaseApp;
18
+ type: 'firestore';
19
+ _app?: FirebaseApp;
20
+ }
21
+ export interface RealtimeDatabase {
22
+ app: FirebaseApp;
23
+ type: 'database';
24
+ url?: string;
25
+ }
26
+ export interface FirebaseAuth {
27
+ app: FirebaseApp;
28
+ type: 'auth';
29
+ currentUser: User | null;
30
+ _currentUser: User | null;
31
+ onAuthStateChanged?(callback: (user: User | null) => void): () => void;
32
+ }
33
+ export interface FirebaseStorage {
34
+ app: FirebaseApp;
35
+ type: 'storage';
36
+ bucket?: string;
37
+ }
38
+ export interface DocumentReference<T = DocumentData> {
39
+ firestore: Firestore;
40
+ _key: string;
41
+ parent: CollectionReference<T>;
42
+ id: string;
43
+ path: string;
44
+ type: 'document';
45
+ }
46
+ export interface CollectionReference<T = DocumentData> {
47
+ firestore: Firestore;
48
+ _key: string;
49
+ path: string;
50
+ id: string;
51
+ parent: DocumentReference<DocumentData> | null;
52
+ type: 'collection';
53
+ _query?: QueryConstraint[];
54
+ }
55
+ export interface Query<T = DocumentData> {
56
+ firestore: Firestore;
57
+ _query: QueryConstraint[];
58
+ type: 'query';
59
+ }
60
+ export interface DocumentSnapshot<T = DocumentData> {
61
+ _firestore: Firestore;
62
+ _userDataWriter: any;
63
+ _doc: any;
64
+ ref: DocumentReference<T>;
65
+ id: string;
66
+ metadata: SnapshotMetadata;
67
+ exists(): boolean;
68
+ data(options?: SnapshotOptions): T | undefined;
69
+ get(fieldPath: string | FieldPath, options?: SnapshotOptions): any;
70
+ }
71
+ export interface QuerySnapshot<T = DocumentData> {
72
+ _firestore: Firestore;
73
+ _snapshot: any;
74
+ query: Query<T> | CollectionReference<T>;
75
+ docs: DocumentSnapshot<T>[];
76
+ size: number;
77
+ empty: boolean;
78
+ metadata: SnapshotMetadata;
79
+ docChanges(options?: SnapshotListenOptions): DocumentChange<T>[];
80
+ forEach(callback: (doc: DocumentSnapshot<T>) => void): void;
81
+ }
82
+ export interface DocumentChange<T = DocumentData> {
83
+ type: 'added' | 'removed' | 'modified';
84
+ doc: DocumentSnapshot<T>;
85
+ oldIndex: number;
86
+ newIndex: number;
87
+ }
88
+ export interface SnapshotMetadata {
89
+ hasPendingWrites: boolean;
90
+ fromCache: boolean;
91
+ }
92
+ export interface SnapshotOptions {
93
+ serverTimestamps?: 'estimate' | 'previous' | 'none';
94
+ }
95
+ export interface SnapshotListenOptions {
96
+ includeMetadataChanges?: boolean;
97
+ }
98
+ export interface QueryConstraint {
99
+ type: 'where' | 'orderBy' | 'limit' | 'limitToLast' | 'startAt' | 'startAfter' | 'endAt' | 'endBefore' | 'offset';
100
+ field?: string | FieldPath;
101
+ operator?: WhereFilterOp;
102
+ value?: any;
103
+ direction?: 'asc' | 'desc';
104
+ count?: number;
105
+ values?: any[];
106
+ }
107
+ export type WhereFilterOp = '<' | '<=' | '==' | '!=' | '>=' | '>' | 'array-contains' | 'in' | 'not-in' | 'array-contains-any';
108
+ export interface FieldPath {
109
+ _segments: string[];
110
+ }
111
+ export interface FieldValue {
112
+ _type: string;
113
+ _serialize(): any;
114
+ }
115
+ export interface Timestamp {
116
+ seconds: number;
117
+ nanoseconds: number;
118
+ _methodName: string;
119
+ toDate(): Date;
120
+ toMillis(): number;
121
+ isEqual(other: Timestamp): boolean;
122
+ }
123
+ export interface GeoPoint {
124
+ latitude: number;
125
+ longitude: number;
126
+ }
127
+ export type DocumentData = {
128
+ [key: string]: any;
129
+ };
130
+ export interface DatabaseReference {
131
+ database: RealtimeDatabase;
132
+ _key: string;
133
+ _path: string[];
134
+ key: string | null;
135
+ parent: DatabaseReference | null;
136
+ root: DatabaseReference;
137
+ path: string;
138
+ }
139
+ export interface DataSnapshot {
140
+ ref: DatabaseReference;
141
+ _database: RealtimeDatabase;
142
+ _node: any;
143
+ key: string | null;
144
+ size: number;
145
+ child(path: string): DataSnapshot;
146
+ exists(): boolean;
147
+ exportVal(): any;
148
+ getPriority(): string | number | null;
149
+ toJSON(): any;
150
+ val(): any;
151
+ }
152
+ export interface OnDisconnect {
153
+ ref: DatabaseReference;
154
+ cancel(onComplete?: (error: Error | null) => void): Promise<void>;
155
+ remove(onComplete?: (error: Error | null) => void): Promise<void>;
156
+ set(value: any, onComplete?: (error: Error | null) => void): Promise<void>;
157
+ setWithPriority(value: any, priority: string | number | null, onComplete?: (error: Error | null) => void): Promise<void>;
158
+ update(updates: {
159
+ [key: string]: any;
160
+ }, onComplete?: (error: Error | null) => void): Promise<void>;
161
+ }
162
+ export interface User {
163
+ uid: string;
164
+ email?: string | null;
165
+ emailVerified: boolean;
166
+ displayName?: string | null;
167
+ photoURL?: string | null;
168
+ phoneNumber?: string | null;
169
+ isAnonymous: boolean;
170
+ metadata: UserMetadata;
171
+ providerData: ProviderData[];
172
+ password?: string;
173
+ toJSON(): object;
174
+ getIdToken(forceRefresh?: boolean): Promise<string>;
175
+ getIdTokenResult(forceRefresh?: boolean): Promise<IdTokenResult>;
176
+ refresh(): Promise<void>;
177
+ delete(): Promise<void>;
178
+ linkWithCredential(credential: AuthCredential): Promise<UserCredential>;
179
+ unlink(providerId: string): Promise<UserCredential>;
180
+ reauthenticateWithCredential(credential: AuthCredential): Promise<UserCredential>;
181
+ updateProfile(profile: {
182
+ displayName?: string;
183
+ photoURL?: string;
184
+ }): Promise<void>;
185
+ updateEmail(newEmail: string): Promise<void>;
186
+ updatePassword(newPassword: string): Promise<void>;
187
+ updatePhoneNumber(credential: AuthCredential): Promise<void>;
188
+ }
189
+ export interface UserMetadata {
190
+ creationTime?: number;
191
+ lastSignInTime?: number;
192
+ _createdAt?: number;
193
+ _updatedAt?: number;
194
+ }
195
+ export interface ProviderData {
196
+ uid: string;
197
+ displayName: string | null;
198
+ email: string | null;
199
+ phoneNumber: string | null;
200
+ photoURL: string | null;
201
+ providerId: string;
202
+ }
203
+ export interface UserCredential {
204
+ user: User;
205
+ operationType: 'signIn' | 'link' | 'reauthenticate';
206
+ providerId: string | null;
207
+ }
208
+ export interface IdTokenResult {
209
+ token: string;
210
+ expirationTime: string;
211
+ authTime: string;
212
+ issuedAtTime: string;
213
+ signInProvider: string | null;
214
+ signInSecondFactor?: string | null;
215
+ claims: {
216
+ [key: string]: any;
217
+ };
218
+ }
219
+ export interface AuthProvider {
220
+ providerId: string;
221
+ setCustomParameters(customOAuthParameters: {
222
+ [key: string]: string;
223
+ }): AuthProvider;
224
+ }
225
+ export interface AuthCredential {
226
+ providerId: string;
227
+ signInMethod: string;
228
+ _idToken?: string;
229
+ _accessToken?: string;
230
+ _secret?: string;
231
+ _refreshToken?: string;
232
+ toJSON(): object;
233
+ }
234
+ export interface OAuthCredential {
235
+ providerId: string;
236
+ provider?: string;
237
+ signInMethod?: string;
238
+ idToken?: string;
239
+ accessToken?: string;
240
+ secret?: string;
241
+ refreshToken?: string;
242
+ identityToken?: string;
243
+ rawNonce?: string;
244
+ toJSON?(): object;
245
+ }
246
+ export interface MultiFactorInfo {
247
+ factorId: string;
248
+ uid: string;
249
+ displayName?: string;
250
+ enrollmentTime: string;
251
+ phoneNumber?: string;
252
+ }
253
+ export interface MultiFactorSession {
254
+ credential?: string;
255
+ _serverResponse?: any;
256
+ }
257
+ export interface PhoneAuthCredential extends AuthCredential {
258
+ verificationId: string;
259
+ verificationCode: string;
260
+ }
261
+ export interface ActionCodeInfo {
262
+ data: {
263
+ email?: string;
264
+ newEmail?: string;
265
+ multiFactorInfo?: any;
266
+ previousEmail?: string;
267
+ };
268
+ operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL' | 'REVERT_SECOND_FACTOR_ADDITION';
269
+ }
270
+ export interface StorageReference {
271
+ storage: FirebaseStorage;
272
+ _location: StorageLocation;
273
+ bucket: string;
274
+ fullPath: string;
275
+ name: string;
276
+ parent: StorageReference | null;
277
+ root: StorageReference;
278
+ }
279
+ export interface StorageLocation {
280
+ bucket: string;
281
+ path: string;
282
+ }
283
+ export interface UploadMetadata {
284
+ cacheControl?: string;
285
+ contentDisposition?: string;
286
+ contentEncoding?: string;
287
+ contentLanguage?: string;
288
+ contentType?: string;
289
+ customMetadata?: {
290
+ [key: string]: string;
291
+ };
292
+ }
293
+ export interface FullMetadata extends UploadMetadata {
294
+ bucket: string;
295
+ downloadURLs: string[];
296
+ fullPath: string;
297
+ generation: string;
298
+ metageneration: string;
299
+ name: string;
300
+ size: number;
301
+ timeCreated: string;
302
+ updated: string;
303
+ md5Hash?: string;
304
+ }
305
+ export interface ListOptions {
306
+ maxResults?: number;
307
+ pageToken?: string;
308
+ }
309
+ export interface ListResult {
310
+ prefixes: StorageReference[];
311
+ items: StorageReference[];
312
+ nextPageToken?: string;
313
+ }
314
+ export interface UploadTaskSnapshot {
315
+ ref: StorageReference;
316
+ metadata: FullMetadata;
317
+ bytesTransferred: number;
318
+ totalBytes: number;
319
+ state: 'running' | 'paused' | 'success' | 'cancelled' | 'error';
320
+ task: UploadTask;
321
+ }
322
+ export interface UploadTask {
323
+ cancel(): boolean;
324
+ catch(onRejected: (error: Error) => any): Promise<any>;
325
+ on(event: string, nextOrObserver?: any, error?: (error: Error) => void, complete?: () => void): Function;
326
+ pause(): boolean;
327
+ resume(): boolean;
328
+ then(onFulfilled?: (snapshot: UploadTaskSnapshot) => any, onRejected?: (error: Error) => any): Promise<any>;
329
+ }
330
+ export type IDatabaseReference = DatabaseReference;
331
+ export type IDataSnapshot = DataSnapshot;
332
+ export type IOnDisconnect = OnDisconnect;
333
+ export type IDocumentReference<T = DocumentData> = DocumentReference<T>;
334
+ export type ICollectionReference<T = DocumentData> = CollectionReference<T>;
335
+ export type IDocumentSnapshot<T = DocumentData> = DocumentSnapshot<T>;
336
+ export type IQuerySnapshot<T = DocumentData> = QuerySnapshot<T>;
337
+ export type IQuery<T = DocumentData> = Query<T>;
338
+ export interface FirebaseError extends Error {
339
+ code: string;
340
+ customData?: any;
341
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Firebase-compatible type definitions
3
+ */
4
+ export {};
@@ -84,7 +84,11 @@ export declare class AuthManager {
84
84
  /**
85
85
  * Clear local identity (logout)
86
86
  */
87
- clearIdentity(): Promise<void>;
87
+ /**
88
+ * Clear local identity (logout)
89
+ * @param injectedDb (for testing only) - pass a mock IndexedDB instance
90
+ */
91
+ clearIdentity(injectedDb?: any): Promise<void>;
88
92
  /**
89
93
  * Parse a UCAN token and extract its structure without verification
90
94
  * This is for inspection/debugging purposes
@@ -391,23 +391,36 @@ export class AuthManager {
391
391
  /**
392
392
  * Clear local identity (logout)
393
393
  */
394
- async clearIdentity() {
394
+ /**
395
+ * Clear local identity (logout)
396
+ * @param injectedDb (for testing only) - pass a mock IndexedDB instance
397
+ */
398
+ async clearIdentity(injectedDb) {
395
399
  this.keypair = null;
396
400
  this.did = null;
397
401
  this.oauthIdentities = [];
398
402
  this.initialized = false;
399
403
  try {
400
- const db = await openAuthDB();
404
+ const db = injectedDb || await openAuthDB();
401
405
  if (!db) {
402
406
  return; // IndexedDB not available
403
407
  }
404
408
  await new Promise((resolve, reject) => {
405
- const tx = db.transaction(STORE_NAME, 'readwrite');
406
- const store = tx.objectStore(STORE_NAME);
407
- const request = store.delete(IDENTITY_KEY);
409
+ let tx, store, request;
410
+ try {
411
+ tx = db.transaction(STORE_NAME, 'readwrite');
412
+ store = tx.objectStore(STORE_NAME);
413
+ request = store.delete(IDENTITY_KEY);
414
+ }
415
+ catch (err) {
416
+ reject(err);
417
+ return;
418
+ }
408
419
  request.onerror = () => reject(request.error);
409
420
  request.onsuccess = () => resolve();
410
- tx.oncomplete = () => db.close();
421
+ if (tx && typeof tx.oncomplete === 'function') {
422
+ tx.oncomplete = () => db.close();
423
+ }
411
424
  });
412
425
  }
413
426
  catch (error) {