@prmichaelsen/firebase-admin-sdk-v8 1.0.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.
package/EXAMPLES.md ADDED
@@ -0,0 +1,532 @@
1
+ # Firebase Admin SDK v8 - Advanced Examples
2
+
3
+ This document provides comprehensive examples of all features in the Firebase Admin SDK v8.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Authentication](#authentication)
8
+ - [Basic Firestore Operations](#basic-firestore-operations)
9
+ - [Field Value Operations](#field-value-operations)
10
+ - [Advanced Queries](#advanced-queries)
11
+ - [Batch Operations](#batch-operations)
12
+ - [Merge Operations](#merge-operations)
13
+
14
+ ## Authentication
15
+
16
+ ### Verify ID Token
17
+
18
+ ```typescript
19
+ import { verifyIdToken, getUserFromToken } from 'firebase-admin-sdk-v8';
20
+
21
+ // Verify token and get decoded claims
22
+ const decodedToken = await verifyIdToken(idToken);
23
+ console.log('User ID:', decodedToken.uid);
24
+ console.log('Email:', decodedToken.email);
25
+
26
+ // Get user info in a convenient format
27
+ const user = await getUserFromToken(idToken);
28
+ console.log('User:', user.uid, user.email, user.displayName);
29
+ ```
30
+
31
+ ## Basic Firestore Operations
32
+
33
+ ### Set Document (Create or Overwrite)
34
+
35
+ ```typescript
36
+ import { setDocument } from 'firebase-admin-sdk-v8';
37
+
38
+ // Create or completely overwrite a document
39
+ await setDocument('users', 'user123', {
40
+ name: 'John Doe',
41
+ email: 'john@example.com',
42
+ age: 30,
43
+ active: true,
44
+ });
45
+ ```
46
+
47
+ ### Add Document (Auto-generate ID)
48
+
49
+ ```typescript
50
+ import { addDocument } from 'firebase-admin-sdk-v8';
51
+
52
+ // Auto-generate document ID
53
+ const docId = await addDocument('posts', {
54
+ title: 'Hello World',
55
+ content: 'This is my first post',
56
+ createdAt: new Date(),
57
+ });
58
+
59
+ // Or specify custom ID
60
+ const customId = await addDocument('posts', {
61
+ title: 'Custom ID Post',
62
+ }, 'my-custom-id');
63
+ ```
64
+
65
+ ### Get Document
66
+
67
+ ```typescript
68
+ import { getDocument } from 'firebase-admin-sdk-v8';
69
+
70
+ const user = await getDocument('users', 'user123');
71
+ if (user) {
72
+ console.log('User found:', user.name);
73
+ } else {
74
+ console.log('User not found');
75
+ }
76
+ ```
77
+
78
+ ### Update Document
79
+
80
+ ```typescript
81
+ import { updateDocument } from 'firebase-admin-sdk-v8';
82
+
83
+ // Update specific fields (document must exist)
84
+ await updateDocument('users', 'user123', {
85
+ lastLogin: new Date(),
86
+ loginCount: 5,
87
+ });
88
+ ```
89
+
90
+ ### Delete Document
91
+
92
+ ```typescript
93
+ import { deleteDocument } from 'firebase-admin-sdk-v8';
94
+
95
+ await deleteDocument('users', 'user123');
96
+ ```
97
+
98
+ ## Field Value Operations
99
+
100
+ ### Server Timestamp
101
+
102
+ ```typescript
103
+ import { setDocument, FieldValue } from 'firebase-admin-sdk-v8';
104
+
105
+ await setDocument('posts', 'post1', {
106
+ title: 'My Post',
107
+ createdAt: FieldValue.serverTimestamp(),
108
+ updatedAt: FieldValue.serverTimestamp(),
109
+ });
110
+ ```
111
+
112
+ ### Increment
113
+
114
+ ```typescript
115
+ import { updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
116
+
117
+ // Increment a counter
118
+ await updateDocument('users', 'user123', {
119
+ loginCount: FieldValue.increment(1),
120
+ points: FieldValue.increment(10),
121
+ });
122
+
123
+ // Decrement (use negative number)
124
+ await updateDocument('inventory', 'item1', {
125
+ stock: FieldValue.increment(-1),
126
+ });
127
+ ```
128
+
129
+ ### Array Union (Add to Array)
130
+
131
+ ```typescript
132
+ import { updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
133
+
134
+ // Add tags to array (no duplicates)
135
+ await updateDocument('posts', 'post1', {
136
+ tags: FieldValue.arrayUnion('javascript', 'typescript', 'firebase'),
137
+ });
138
+
139
+ // Add multiple items
140
+ await updateDocument('users', 'user123', {
141
+ favoriteColors: FieldValue.arrayUnion('blue', 'green'),
142
+ });
143
+ ```
144
+
145
+ ### Array Remove
146
+
147
+ ```typescript
148
+ import { updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
149
+
150
+ // Remove tags from array
151
+ await updateDocument('posts', 'post1', {
152
+ tags: FieldValue.arrayRemove('outdated-tag'),
153
+ });
154
+ ```
155
+
156
+ ### Delete Field
157
+
158
+ ```typescript
159
+ import { updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
160
+
161
+ // Remove a field from document
162
+ await updateDocument('users', 'user123', {
163
+ temporaryField: FieldValue.delete(),
164
+ oldField: FieldValue.delete(),
165
+ });
166
+ ```
167
+
168
+ ## Advanced Queries
169
+
170
+ ### Simple Query
171
+
172
+ ```typescript
173
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
174
+
175
+ // Get all documents in collection
176
+ const allUsers = await queryDocuments('users');
177
+ allUsers.forEach(user => {
178
+ console.log(user.id, user.data.name);
179
+ });
180
+ ```
181
+
182
+ ### Where Filters
183
+
184
+ ```typescript
185
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
186
+
187
+ // Single condition
188
+ const activeUsers = await queryDocuments('users', {
189
+ where: [
190
+ { field: 'active', op: '==', value: true }
191
+ ]
192
+ });
193
+
194
+ // Multiple conditions (AND)
195
+ const adultActiveUsers = await queryDocuments('users', {
196
+ where: [
197
+ { field: 'active', op: '==', value: true },
198
+ { field: 'age', op: '>=', value: 18 }
199
+ ]
200
+ });
201
+
202
+ // Comparison operators
203
+ const seniorUsers = await queryDocuments('users', {
204
+ where: [
205
+ { field: 'age', op: '>', value: 65 }
206
+ ]
207
+ });
208
+
209
+ // Array contains
210
+ const jsDevs = await queryDocuments('users', {
211
+ where: [
212
+ { field: 'skills', op: 'array-contains', value: 'javascript' }
213
+ ]
214
+ });
215
+
216
+ // In operator
217
+ const specificUsers = await queryDocuments('users', {
218
+ where: [
219
+ { field: 'role', op: 'in', value: ['admin', 'moderator'] }
220
+ ]
221
+ });
222
+ ```
223
+
224
+ ### Order By
225
+
226
+ ```typescript
227
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
228
+
229
+ // Order by single field
230
+ const usersByName = await queryDocuments('users', {
231
+ orderBy: [
232
+ { field: 'name', direction: 'ASCENDING' }
233
+ ]
234
+ });
235
+
236
+ // Order by multiple fields
237
+ const sortedPosts = await queryDocuments('posts', {
238
+ orderBy: [
239
+ { field: 'featured', direction: 'DESCENDING' },
240
+ { field: 'createdAt', direction: 'DESCENDING' }
241
+ ]
242
+ });
243
+ ```
244
+
245
+ ### Limit and Offset
246
+
247
+ ```typescript
248
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
249
+
250
+ // Get first 10 users
251
+ const firstPage = await queryDocuments('users', {
252
+ limit: 10
253
+ });
254
+
255
+ // Pagination with offset
256
+ const secondPage = await queryDocuments('users', {
257
+ limit: 10,
258
+ offset: 10
259
+ });
260
+ ```
261
+
262
+ ### Complex Query
263
+
264
+ ```typescript
265
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
266
+
267
+ // Combine filters, ordering, and limit
268
+ const topActiveUsers = await queryDocuments('users', {
269
+ where: [
270
+ { field: 'active', op: '==', value: true },
271
+ { field: 'points', op: '>=', value: 100 }
272
+ ],
273
+ orderBy: [
274
+ { field: 'points', direction: 'DESCENDING' }
275
+ ],
276
+ limit: 10
277
+ });
278
+ ```
279
+
280
+ ### Cursor-based Pagination
281
+
282
+ ```typescript
283
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
284
+
285
+ // Start at specific value
286
+ const results = await queryDocuments('users', {
287
+ orderBy: [{ field: 'createdAt', direction: 'ASCENDING' }],
288
+ startAt: [new Date('2024-01-01')],
289
+ limit: 10
290
+ });
291
+
292
+ // Start after specific value (exclusive)
293
+ const nextResults = await queryDocuments('users', {
294
+ orderBy: [{ field: 'createdAt', direction: 'ASCENDING' }],
295
+ startAfter: [new Date('2024-01-01')],
296
+ limit: 10
297
+ });
298
+
299
+ // End at specific value
300
+ const endResults = await queryDocuments('users', {
301
+ orderBy: [{ field: 'createdAt', direction: 'ASCENDING' }],
302
+ endAt: [new Date('2024-12-31')],
303
+ });
304
+
305
+ // End before specific value (exclusive)
306
+ const beforeResults = await queryDocuments('users', {
307
+ orderBy: [{ field: 'createdAt', direction: 'ASCENDING' }],
308
+ endBefore: [new Date('2024-12-31')],
309
+ });
310
+ ```
311
+
312
+ ## Batch Operations
313
+
314
+ ### Batch Write (Multiple Operations)
315
+
316
+ ```typescript
317
+ import { batchWrite } from 'firebase-admin-sdk-v8';
318
+
319
+ // Perform multiple operations atomically
320
+ await batchWrite([
321
+ // Set a document
322
+ {
323
+ type: 'set',
324
+ collectionPath: 'users',
325
+ documentId: 'user1',
326
+ data: { name: 'John', email: 'john@example.com' }
327
+ },
328
+
329
+ // Update a document
330
+ {
331
+ type: 'update',
332
+ collectionPath: 'users',
333
+ documentId: 'user2',
334
+ data: { lastLogin: new Date() }
335
+ },
336
+
337
+ // Delete a document
338
+ {
339
+ type: 'delete',
340
+ collectionPath: 'users',
341
+ documentId: 'user3'
342
+ }
343
+ ]);
344
+ ```
345
+
346
+ ### Batch with Field Values
347
+
348
+ ```typescript
349
+ import { batchWrite, FieldValue } from 'firebase-admin-sdk-v8';
350
+
351
+ await batchWrite([
352
+ {
353
+ type: 'update',
354
+ collectionPath: 'posts',
355
+ documentId: 'post1',
356
+ data: {
357
+ views: FieldValue.increment(1),
358
+ lastViewed: FieldValue.serverTimestamp()
359
+ }
360
+ },
361
+ {
362
+ type: 'update',
363
+ collectionPath: 'users',
364
+ documentId: 'user1',
365
+ data: {
366
+ postsViewed: FieldValue.arrayUnion('post1')
367
+ }
368
+ }
369
+ ]);
370
+ ```
371
+
372
+ ## Merge Operations
373
+
374
+ ### Merge All Fields
375
+
376
+ ```typescript
377
+ import { setDocument } from 'firebase-admin-sdk-v8';
378
+
379
+ // Existing document: { name: 'John', age: 30, city: 'NYC' }
380
+
381
+ // Merge new data with existing
382
+ await setDocument('users', 'user123', {
383
+ age: 31,
384
+ country: 'USA'
385
+ }, { merge: true });
386
+
387
+ // Result: { name: 'John', age: 31, city: 'NYC', country: 'USA' }
388
+ ```
389
+
390
+ ### Merge Specific Fields
391
+
392
+ ```typescript
393
+ import { setDocument } from 'firebase-admin-sdk-v8';
394
+
395
+ // Existing document: { name: 'John', age: 30, city: 'NYC' }
396
+
397
+ // Only merge the 'age' field
398
+ await setDocument('users', 'user123', {
399
+ age: 31,
400
+ city: 'LA',
401
+ country: 'USA'
402
+ }, { mergeFields: ['age'] });
403
+
404
+ // Result: { name: 'John', age: 31, city: 'NYC' }
405
+ // Note: city and country were NOT updated
406
+ ```
407
+
408
+ ### Merge with Field Values
409
+
410
+ ```typescript
411
+ import { setDocument, FieldValue } from 'firebase-admin-sdk-v8';
412
+
413
+ // Merge with special field values
414
+ await setDocument('users', 'user123', {
415
+ lastLogin: FieldValue.serverTimestamp(),
416
+ loginCount: FieldValue.increment(1),
417
+ devices: FieldValue.arrayUnion('mobile')
418
+ }, { merge: true });
419
+ ```
420
+
421
+ ## Real-World Examples
422
+
423
+ ### User Registration
424
+
425
+ ```typescript
426
+ import { addDocument, FieldValue } from 'firebase-admin-sdk-v8';
427
+
428
+ async function registerUser(email: string, name: string) {
429
+ const userId = await addDocument('users', {
430
+ email,
431
+ name,
432
+ createdAt: FieldValue.serverTimestamp(),
433
+ loginCount: 0,
434
+ active: true,
435
+ roles: ['user'],
436
+ });
437
+
438
+ return userId;
439
+ }
440
+ ```
441
+
442
+ ### Track User Activity
443
+
444
+ ```typescript
445
+ import { updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
446
+
447
+ async function trackUserLogin(userId: string) {
448
+ await updateDocument('users', userId, {
449
+ lastLogin: FieldValue.serverTimestamp(),
450
+ loginCount: FieldValue.increment(1),
451
+ });
452
+ }
453
+ ```
454
+
455
+ ### Blog Post with Tags
456
+
457
+ ```typescript
458
+ import { addDocument, updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
459
+
460
+ async function createPost(title: string, content: string, tags: string[]) {
461
+ const postId = await addDocument('posts', {
462
+ title,
463
+ content,
464
+ tags,
465
+ views: 0,
466
+ likes: 0,
467
+ createdAt: FieldValue.serverTimestamp(),
468
+ updatedAt: FieldValue.serverTimestamp(),
469
+ });
470
+
471
+ return postId;
472
+ }
473
+
474
+ async function addTagToPost(postId: string, tag: string) {
475
+ await updateDocument('posts', postId, {
476
+ tags: FieldValue.arrayUnion(tag),
477
+ updatedAt: FieldValue.serverTimestamp(),
478
+ });
479
+ }
480
+
481
+ async function incrementPostViews(postId: string) {
482
+ await updateDocument('posts', postId, {
483
+ views: FieldValue.increment(1),
484
+ });
485
+ }
486
+ ```
487
+
488
+ ### Leaderboard Query
489
+
490
+ ```typescript
491
+ import { queryDocuments } from 'firebase-admin-sdk-v8';
492
+
493
+ async function getTopPlayers(limit: number = 10) {
494
+ return await queryDocuments('players', {
495
+ where: [
496
+ { field: 'active', op: '==', value: true }
497
+ ],
498
+ orderBy: [
499
+ { field: 'score', direction: 'DESCENDING' }
500
+ ],
501
+ limit
502
+ });
503
+ }
504
+ ```
505
+
506
+ ### Bulk User Update
507
+
508
+ ```typescript
509
+ import { batchWrite, FieldValue } from 'firebase-admin-sdk-v8';
510
+
511
+ async function bulkUpdateUsers(userIds: string[], updates: any) {
512
+ const operations = userIds.map(userId => ({
513
+ type: 'update' as const,
514
+ collectionPath: 'users',
515
+ documentId: userId,
516
+ data: {
517
+ ...updates,
518
+ updatedAt: FieldValue.serverTimestamp(),
519
+ }
520
+ }));
521
+
522
+ // Firestore batch limit is 500 operations
523
+ const chunks = [];
524
+ for (let i = 0; i < operations.length; i += 500) {
525
+ chunks.push(operations.slice(i, i + 500));
526
+ }
527
+
528
+ for (const chunk of chunks) {
529
+ await batchWrite(chunk);
530
+ }
531
+ }
532
+ ```