svelte-firekit 0.1.5 → 0.1.7

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.
@@ -3,7 +3,7 @@
3
3
  * @module FirekitAuth
4
4
  * @version 1.0.0
5
5
  */
6
- import { EmailAuthProvider, PhoneAuthProvider, RecaptchaVerifier, signInWithEmailAndPassword, signInWithPopup, signInWithPhoneNumber as firebaseSignInWithPhoneNumber, signInWithCredential, signInAnonymously as firebaseSignInAnonymously, createUserWithEmailAndPassword, signOut, sendPasswordResetEmail, confirmPasswordReset, sendEmailVerification, updateProfile, updateEmail, updatePassword, reauthenticateWithCredential, deleteUser, reload, getIdToken, onAuthStateChanged } from 'firebase/auth';
6
+ import { EmailAuthProvider, PhoneAuthProvider, RecaptchaVerifier, signInWithEmailAndPassword, signInWithPopup, signInWithPhoneNumber as firebaseSignInWithPhoneNumber, signInWithCredential, signInAnonymously as firebaseSignInAnonymously, createUserWithEmailAndPassword, signOut, sendPasswordResetEmail, confirmPasswordReset, sendEmailVerification, updateProfile, updateEmail, updatePassword, reauthenticateWithCredential, deleteUser, reload, getIdToken, onAuthStateChanged, getAdditionalUserInfo } from 'firebase/auth';
7
7
  import { doc, setDoc, serverTimestamp } from 'firebase/firestore';
8
8
  import { firebaseService } from '../firebase.js';
9
9
  import { AuthErrorCode, FirekitAuthError } from '../types/auth.js';
@@ -205,14 +205,15 @@ class FirekitAuth {
205
205
  * Signs in user with email and password
206
206
  * @param {string} email User's email address
207
207
  * @param {string} password User's password
208
- * @returns {Promise<UserProfile>} Promise resolving to user profile
208
+ * @returns {Promise<SignInResult>} Promise resolving to sign-in result
209
209
  * @throws {FirekitAuthError} If sign-in fails
210
210
  *
211
211
  * @example
212
212
  * ```typescript
213
213
  * try {
214
- * const user = await firekitAuth.signInWithEmail("user@example.com", "password123");
215
- * console.log("Signed in:", user.displayName);
214
+ * const result = await firekitAuth.signInWithEmail("user@example.com", "password123");
215
+ * console.log("Signed in:", result.user.displayName);
216
+ * console.log("Is new user:", result.isNewUser);
216
217
  * } catch (error) {
217
218
  * console.error("Sign-in failed:", error.message);
218
219
  * }
@@ -227,7 +228,17 @@ class FirekitAuth {
227
228
  this.notifyStateListeners();
228
229
  const userCredential = await signInWithEmailAndPassword(this.auth, email, password);
229
230
  await this.updateUserInFirestore(userCredential.user);
230
- return this.mapFirebaseUserToProfile(userCredential.user);
231
+ const userProfile = this.mapFirebaseUserToProfile(userCredential.user);
232
+ const additionalUserInfo = getAdditionalUserInfo(userCredential);
233
+ const isNewUser = additionalUserInfo?.isNewUser ?? false;
234
+ return {
235
+ success: true,
236
+ user: userProfile,
237
+ method: 'email',
238
+ timestamp: new Date(),
239
+ isNewUser,
240
+ requiresEmailVerification: !userProfile.emailVerified
241
+ };
231
242
  }
232
243
  catch (error) {
233
244
  this.handleAuthError(error);
@@ -239,14 +250,16 @@ class FirekitAuth {
239
250
  }
240
251
  /**
241
252
  * Signs in user with Google popup
242
- * @returns {Promise<UserProfile>} Promise resolving to user profile
253
+ * @returns {Promise<OAuthSignInResult>} Promise resolving to OAuth sign-in result
243
254
  * @throws {FirekitAuthError} If sign-in fails
244
255
  *
245
256
  * @example
246
257
  * ```typescript
247
258
  * try {
248
- * const user = await firekitAuth.signInWithGoogle();
249
- * console.log("Signed in with Google:", user.email);
259
+ * const result = await firekitAuth.signInWithGoogle();
260
+ * console.log("Signed in with Google:", result.user.email);
261
+ * console.log("Is new user:", result.isNewUser);
262
+ * console.log("Access token:", result.accessToken);
250
263
  * } catch (error) {
251
264
  * if (error.code === 'auth/popup-closed-by-user') {
252
265
  * console.log("User cancelled sign-in");
@@ -264,7 +277,17 @@ class FirekitAuth {
264
277
  const provider = createGoogleProvider();
265
278
  const result = await signInWithPopup(this.auth, provider);
266
279
  await this.updateUserInFirestore(result.user);
267
- return this.mapFirebaseUserToProfile(result.user);
280
+ const userProfile = this.mapFirebaseUserToProfile(result.user);
281
+ const additionalUserInfo = getAdditionalUserInfo(result);
282
+ const isNewUser = additionalUserInfo?.isNewUser ?? false;
283
+ return {
284
+ success: true,
285
+ user: userProfile,
286
+ method: 'google',
287
+ timestamp: new Date(),
288
+ isNewUser,
289
+ provider: 'google'
290
+ };
268
291
  }
269
292
  catch (error) {
270
293
  this.handleAuthError(error);
@@ -276,7 +299,7 @@ class FirekitAuth {
276
299
  }
277
300
  /**
278
301
  * Signs in user with Facebook popup
279
- * @returns {Promise<UserProfile>} Promise resolving to user profile
302
+ * @returns {Promise<OAuthSignInResult>} Promise resolving to OAuth sign-in result
280
303
  * @throws {FirekitAuthError} If sign-in fails
281
304
  */
282
305
  async signInWithFacebook() {
@@ -289,7 +312,17 @@ class FirekitAuth {
289
312
  const provider = createFacebookProvider();
290
313
  const result = await signInWithPopup(this.auth, provider);
291
314
  await this.updateUserInFirestore(result.user);
292
- return this.mapFirebaseUserToProfile(result.user);
315
+ const userProfile = this.mapFirebaseUserToProfile(result.user);
316
+ const additionalUserInfo = getAdditionalUserInfo(result);
317
+ const isNewUser = additionalUserInfo?.isNewUser ?? false;
318
+ return {
319
+ success: true,
320
+ user: userProfile,
321
+ method: 'facebook',
322
+ timestamp: new Date(),
323
+ isNewUser,
324
+ provider: 'facebook'
325
+ };
293
326
  }
294
327
  catch (error) {
295
328
  this.handleAuthError(error);
@@ -301,7 +334,7 @@ class FirekitAuth {
301
334
  }
302
335
  /**
303
336
  * Signs in user with Apple popup
304
- * @returns {Promise<UserProfile>} Promise resolving to user profile
337
+ * @returns {Promise<OAuthSignInResult>} Promise resolving to OAuth sign-in result
305
338
  * @throws {FirekitAuthError} If sign-in fails
306
339
  */
307
340
  async signInWithApple() {
@@ -314,7 +347,17 @@ class FirekitAuth {
314
347
  const provider = createAppleProvider();
315
348
  const result = await signInWithPopup(this.auth, provider);
316
349
  await this.updateUserInFirestore(result.user);
317
- return this.mapFirebaseUserToProfile(result.user);
350
+ const userProfile = this.mapFirebaseUserToProfile(result.user);
351
+ const additionalUserInfo = getAdditionalUserInfo(result);
352
+ const isNewUser = additionalUserInfo?.isNewUser ?? false;
353
+ return {
354
+ success: true,
355
+ user: userProfile,
356
+ method: 'apple',
357
+ timestamp: new Date(),
358
+ isNewUser,
359
+ provider: 'apple'
360
+ };
318
361
  }
319
362
  catch (error) {
320
363
  this.handleAuthError(error);
@@ -326,13 +369,14 @@ class FirekitAuth {
326
369
  }
327
370
  /**
328
371
  * Signs in user anonymously
329
- * @returns {Promise<UserProfile>} Promise resolving to user profile
372
+ * @returns {Promise<SignInResult>} Promise resolving to sign-in result
330
373
  * @throws {FirekitAuthError} If sign-in fails
331
374
  *
332
375
  * @example
333
376
  * ```typescript
334
- * const user = await firekitAuth.signInAnonymously();
335
- * console.log("Anonymous user:", user.uid);
377
+ * const result = await firekitAuth.signInAnonymously();
378
+ * console.log("Anonymous user:", result.user.uid);
379
+ * console.log("Is new user:", result.isNewUser);
336
380
  * ```
337
381
  */
338
382
  async signInAnonymously() {
@@ -344,7 +388,16 @@ class FirekitAuth {
344
388
  this.notifyStateListeners();
345
389
  const result = await firebaseSignInAnonymously(this.auth);
346
390
  await this.updateUserInFirestore(result.user);
347
- return this.mapFirebaseUserToProfile(result.user);
391
+ const userProfile = this.mapFirebaseUserToProfile(result.user);
392
+ const additionalUserInfo = getAdditionalUserInfo(result);
393
+ const isNewUser = additionalUserInfo?.isNewUser ?? false;
394
+ return {
395
+ success: true,
396
+ user: userProfile,
397
+ method: 'anonymous',
398
+ timestamp: new Date(),
399
+ isNewUser
400
+ };
348
401
  }
349
402
  catch (error) {
350
403
  this.handleAuthError(error);
@@ -397,7 +450,16 @@ class FirekitAuth {
397
450
  try {
398
451
  const userCredential = await confirmationResult.confirm(verificationCode);
399
452
  await this.updateUserInFirestore(userCredential.user);
400
- return this.mapFirebaseUserToProfile(userCredential.user);
453
+ const userProfile = this.mapFirebaseUserToProfile(userCredential.user);
454
+ const additionalUserInfo = getAdditionalUserInfo(userCredential);
455
+ const isNewUser = additionalUserInfo?.isNewUser ?? false;
456
+ return {
457
+ success: true,
458
+ user: userProfile,
459
+ method: 'phone',
460
+ timestamp: new Date(),
461
+ isNewUser
462
+ };
401
463
  }
402
464
  catch (error) {
403
465
  this.handleAuthError(error);
@@ -427,17 +489,18 @@ class FirekitAuth {
427
489
  * @param {string} password User's password
428
490
  * @param {string} [displayName] User's display name
429
491
  * @param {boolean} [sendVerification=true] Whether to send email verification
430
- * @returns {Promise<UserProfile>} Promise resolving to user profile
492
+ * @returns {Promise<RegistrationResult>} Promise resolving to registration result
431
493
  * @throws {FirekitAuthError} If registration fails
432
494
  *
433
495
  * @example
434
496
  * ```typescript
435
- * const user = await firekitAuth.registerWithEmail(
497
+ * const result = await firekitAuth.registerWithEmail(
436
498
  * "user@example.com",
437
499
  * "password123",
438
500
  * "John Doe"
439
501
  * );
440
- * console.log("Registered:", user.displayName);
502
+ * console.log("Registered:", result.user.displayName);
503
+ * console.log("Email verification sent:", result.emailVerificationSent);
441
504
  * ```
442
505
  */
443
506
  async registerWithEmail(email, password, displayName, sendVerification = true) {
@@ -458,7 +521,15 @@ class FirekitAuth {
458
521
  await sendEmailVerification(user);
459
522
  }
460
523
  await this.updateUserInFirestore(user);
461
- return this.mapFirebaseUserToProfile(user);
524
+ const userProfile = this.mapFirebaseUserToProfile(user);
525
+ return {
526
+ success: true,
527
+ user: userProfile,
528
+ method: 'email',
529
+ timestamp: new Date(),
530
+ emailVerificationSent: sendVerification,
531
+ requiresEmailVerification: !userProfile.emailVerified
532
+ };
462
533
  }
463
534
  catch (error) {
464
535
  this.handleAuthError(error);
@@ -4,7 +4,7 @@
4
4
  * @version 1.0.0
5
5
  */
6
6
  import { type Query, type CollectionReference, type DocumentData, type QueryConstraint } from 'firebase/firestore';
7
- import { type CollectionState, type CollectionOptions, type CollectionEventCallback, type CollectionStats, type QueryBuilder, CollectionError } from '../types/collection.js';
7
+ import { type CollectionState, type CollectionOptions, type CollectionStats, type QueryBuilder, CollectionError } from '../types/collection.js';
8
8
  /**
9
9
  * Comprehensive Firestore collection management with real-time updates and advanced features.
10
10
  * Uses Svelte 5 runes for optimal reactivity and performance.
@@ -57,7 +57,6 @@ declare class FirekitCollection<T extends DocumentData = DocumentData> {
57
57
  private collectionRef;
58
58
  protected queryRef: Query<T> | null;
59
59
  private unsubscribe;
60
- private eventListeners;
61
60
  protected options: CollectionOptions;
62
61
  private stats;
63
62
  private cache;
@@ -118,10 +117,6 @@ declare class FirekitCollection<T extends DocumentData = DocumentData> {
118
117
  * Calculate memory usage of documents
119
118
  */
120
119
  private calculateMemoryUsage;
121
- /**
122
- * Emit event to all listeners
123
- */
124
- private emitEvent;
125
120
  /**
126
121
  * Get current collection data
127
122
  */
@@ -242,14 +237,6 @@ declare class FirekitCollection<T extends DocumentData = DocumentData> {
242
237
  * Reset statistics
243
238
  */
244
239
  resetStats(): void;
245
- /**
246
- * Add event listener
247
- */
248
- addEventListener(callback: CollectionEventCallback<T>): () => void;
249
- /**
250
- * Remove all event listeners
251
- */
252
- clearEventListeners(): void;
253
240
  /**
254
241
  * Wait for collection to initialize
255
242
  */
@@ -98,7 +98,6 @@ class FirekitCollection {
98
98
  collectionRef = null;
99
99
  queryRef = null;
100
100
  unsubscribe = null;
101
- eventListeners = new Set();
102
101
  options;
103
102
  stats = this.initializeStats();
104
103
  cache = new Map();
@@ -158,12 +157,6 @@ class FirekitCollection {
158
157
  this._loading = false;
159
158
  this._initialized = true;
160
159
  this._lastUpdated = cached.timestamp;
161
- this.emitEvent({
162
- type: 'cache_hit',
163
- data: cached.data,
164
- timestamp: new Date(),
165
- path: this.collectionPath
166
- });
167
160
  this.stats.cacheHitRate = (this.stats.cacheHitRate + 1) / 2;
168
161
  }
169
162
  // Create collection reference
@@ -189,11 +182,6 @@ class FirekitCollection {
189
182
  setupRealtimeListener() {
190
183
  if (!this.queryRef)
191
184
  return;
192
- this.emitEvent({
193
- type: 'loading_started',
194
- timestamp: new Date(),
195
- path: this.collectionPath
196
- });
197
185
  const options = {
198
186
  includeMetadataChanges: this.options.includeMetadata || false
199
187
  };
@@ -211,11 +199,6 @@ class FirekitCollection {
211
199
  return;
212
200
  try {
213
201
  this._loading = true;
214
- this.emitEvent({
215
- type: 'loading_started',
216
- timestamp: new Date(),
217
- path: this.collectionPath
218
- });
219
202
  const startTime = Date.now();
220
203
  const snapshot = await getDocs(this.queryRef);
221
204
  const queryTime = Date.now() - startTime;
@@ -271,33 +254,6 @@ class FirekitCollection {
271
254
  });
272
255
  this.cleanupCache();
273
256
  }
274
- // Emit events
275
- this.emitEvent({
276
- type: 'data_changed',
277
- data: documents,
278
- changes,
279
- timestamp: new Date(),
280
- path: this.collectionPath
281
- });
282
- this.emitEvent({
283
- type: 'loading_finished',
284
- data: {
285
- documentCount: documents.length,
286
- processingTime: Date.now() - startTime
287
- },
288
- timestamp: new Date(),
289
- path: this.collectionPath
290
- });
291
- // Emit individual change events
292
- changes.forEach((change) => {
293
- this.emitEvent({
294
- type: `document_${change.type}`,
295
- data: change.doc,
296
- changes: [change],
297
- timestamp: new Date(),
298
- path: this.collectionPath
299
- });
300
- });
301
257
  }
302
258
  catch (error) {
303
259
  this.handleError(error);
@@ -365,12 +321,6 @@ class FirekitCollection {
365
321
  }
366
322
  this._error = collectionError;
367
323
  this._loading = false;
368
- this.emitEvent({
369
- type: 'error',
370
- error: collectionError,
371
- timestamp: new Date(),
372
- path: this.collectionPath
373
- });
374
324
  console.error('FirekitCollection error:', collectionError);
375
325
  }
376
326
  /**
@@ -469,19 +419,6 @@ class FirekitCollection {
469
419
  return 0;
470
420
  }
471
421
  }
472
- /**
473
- * Emit event to all listeners
474
- */
475
- emitEvent(event) {
476
- this.eventListeners.forEach((callback) => {
477
- try {
478
- callback(event);
479
- }
480
- catch (error) {
481
- console.error('Error in collection event listener:', error);
482
- }
483
- });
484
- }
485
422
  // ========================================
486
423
  // REACTIVE GETTERS (Public API)
487
424
  // ========================================
@@ -736,22 +673,6 @@ class FirekitCollection {
736
673
  resetStats() {
737
674
  this.stats = this.initializeStats();
738
675
  }
739
- // ========================================
740
- // EVENT MANAGEMENT
741
- // ========================================
742
- /**
743
- * Add event listener
744
- */
745
- addEventListener(callback) {
746
- this.eventListeners.add(callback);
747
- return () => this.eventListeners.delete(callback);
748
- }
749
- /**
750
- * Remove all event listeners
751
- */
752
- clearEventListeners() {
753
- this.eventListeners.clear();
754
- }
755
676
  /**
756
677
  * Wait for collection to initialize
757
678
  */
@@ -761,12 +682,18 @@ class FirekitCollection {
761
682
  resolve(this._data);
762
683
  return;
763
684
  }
764
- const unsubscribe = this.addEventListener((event) => {
765
- if (event.type === 'data_changed' || event.type === 'error') {
766
- unsubscribe();
685
+ // Poll for initialization since we removed events
686
+ const checkInterval = setInterval(() => {
687
+ if (this._initialized) {
688
+ clearInterval(checkInterval);
767
689
  resolve(this._data);
768
690
  }
769
- });
691
+ }, 100);
692
+ // Timeout after 10 seconds
693
+ setTimeout(() => {
694
+ clearInterval(checkInterval);
695
+ resolve(this._data);
696
+ }, 10000);
770
697
  });
771
698
  }
772
699
  // ========================================
@@ -783,8 +710,6 @@ class FirekitCollection {
783
710
  }
784
711
  // Clear cache
785
712
  this.cache.clear();
786
- // Clear event listeners
787
- this.eventListeners.clear();
788
713
  // Reset state
789
714
  this._data = [];
790
715
  this._loading = false;
@@ -0,0 +1,9 @@
1
+ export { firekitCollection, firekitCollectionOnce, firekitCollectionGroup } from './collection.svelte.js';
2
+ export { firekitDoc, firekitDocOnce, firekitDocWithMetadata } from './document.svelte.js';
3
+ export { firekitUser } from './user.svelte.js';
4
+ export { firekitAuth } from './auth.js';
5
+ export { firekitDownloadUrl, firekitStorageList, firekitUploadTask } from './storage.svelte.js';
6
+ export { firekitPresence } from './presence.svelte.js';
7
+ export { firekitRealtimeDB, firekitRealtimeList } from './realtime.svelte.js';
8
+ export { firekitDocMutations } from './mutations.js';
9
+ export { firekitAnalytics } from './analytics.js';
@@ -0,0 +1,10 @@
1
+ // Export all svelte-firekit services
2
+ export { firekitCollection, firekitCollectionOnce, firekitCollectionGroup } from './collection.svelte.js';
3
+ export { firekitDoc, firekitDocOnce, firekitDocWithMetadata } from './document.svelte.js';
4
+ export { firekitUser } from './user.svelte.js';
5
+ export { firekitAuth } from './auth.js';
6
+ export { firekitDownloadUrl, firekitStorageList, firekitUploadTask } from './storage.svelte.js';
7
+ export { firekitPresence } from './presence.svelte.js';
8
+ export { firekitRealtimeDB, firekitRealtimeList } from './realtime.svelte.js';
9
+ export { firekitDocMutations } from './mutations.js';
10
+ export { firekitAnalytics } from './analytics.js';
@@ -4,7 +4,7 @@
4
4
  * @version 1.0.0
5
5
  */
6
6
  import { type DocumentData, type WithFieldValue, type PartialWithFieldValue } from 'firebase/firestore';
7
- import { type MutationResponse, type MutationOptions, type BatchOperation, type BatchResult, type ExistenceCheckResult, type BulkMutationConfig, type MutationEventCallback, type MutationAnalytics } from '../types/mutations.js';
7
+ import { type MutationResponse, type MutationOptions, type BatchOperation, type BatchResult, type ExistenceCheckResult, type BulkMutationConfig, type MutationAnalytics } from '../types/mutations.js';
8
8
  /**
9
9
  * Comprehensive Firestore document mutation service with advanced features.
10
10
  * Handles CRUD operations, batch processing, validation, error handling, and analytics.
@@ -28,15 +28,9 @@ import { type MutationResponse, type MutationOptions, type BatchOperation, type
28
28
  * { type: 'create', path: 'users', data: userData },
29
29
  * { type: 'update', path: 'profiles/123', data: profileUpdate }
30
30
  * ]);
31
- *
32
- * // Listen to mutation events
33
- * const unsubscribe = firekitDocMutations.addEventListener((event) => {
34
- * console.log('Mutation event:', event.type, event.data);
35
- * });
36
31
  * ```
37
32
  */
38
33
  declare class FirekitDocumentMutations {
39
- private eventListeners;
40
34
  private analytics;
41
35
  private defaultOptions;
42
36
  /**
@@ -63,10 +57,6 @@ declare class FirekitDocumentMutations {
63
57
  * Update error analytics
64
58
  */
65
59
  private updateErrorAnalytics;
66
- /**
67
- * Emit event to all listeners
68
- */
69
- private emitEvent;
70
60
  /**
71
61
  * Execute operation with retry logic
72
62
  */
@@ -216,6 +206,10 @@ declare class FirekitDocumentMutations {
216
206
  * Add operation to batch writer
217
207
  */
218
208
  private addOperationToBatch;
209
+ /**
210
+ * Generate a unique document ID (Firestore-style)
211
+ */
212
+ private generateDocumentId;
219
213
  /**
220
214
  * Chunk array into smaller arrays
221
215
  */
@@ -255,27 +249,6 @@ declare class FirekitDocumentMutations {
255
249
  * Update operation analytics
256
250
  */
257
251
  private updateOperationAnalytics;
258
- /**
259
- * Add event listener for mutation events
260
- *
261
- * @param callback Event callback function
262
- * @returns Cleanup function to remove listener
263
- *
264
- * @example
265
- * ```typescript
266
- * const unsubscribe = firekitDocMutations.addEventListener((event) => {
267
- * console.log('Mutation event:', event.type, event.data);
268
- * });
269
- *
270
- * // Clean up when done
271
- * unsubscribe();
272
- * ```
273
- */
274
- addEventListener(callback: MutationEventCallback): () => void;
275
- /**
276
- * Remove all event listeners
277
- */
278
- clearEventListeners(): void;
279
252
  /**
280
253
  * Get current mutation analytics
281
254
  *
@@ -325,11 +298,6 @@ declare class FirekitDocumentMutations {
325
298
  * { type: 'create', path: 'users', data: userData },
326
299
  * { type: 'update', path: 'profiles/123', data: updateData }
327
300
  * ]);
328
- *
329
- * // Listen to events
330
- * const unsubscribe = firekitDocMutations.addEventListener((event) => {
331
- * console.log('Mutation:', event.type, event.data);
332
- * });
333
301
  * ```
334
302
  */
335
303
  export declare const firekitDocMutations: FirekitDocumentMutations;