@prmichaelsen/firebase-admin-sdk-v8 2.2.1 → 2.2.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,63 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - Collection iteration functions: `listDocuments()`, `iterateCollection()`, and `countDocuments()`
12
+ - Automatic pagination support for large collections
13
+ - Support for iterating with filters and ordering
14
+
15
+ ### Changed
16
+ - **BREAKING**: `fromFirestoreValue()` now throws an error for unknown Firestore value types instead of returning `null`
17
+ - Removed debug console.log statements from production code in `auth.ts`
18
+
19
+ ### Fixed
20
+ - Silent failures in Firestore data conversion now throw descriptive errors
21
+
22
+ ## [2.2.1] - 2026-02-12
23
+
24
+ ### Added
25
+ - Modular Firestore architecture with separate modules for converters, operations, query-builder, transforms, and path-validation
26
+ - Comprehensive path validation for Firestore operations
27
+ - Support for subcollection queries
28
+
29
+ ### Changed
30
+ - Refactored Firestore implementation into modular structure
31
+ - Improved error messages for path validation
32
+
33
+ ### Fixed
34
+ - Subcollection query support using correct REST API endpoints
35
+ - Path validation for nested collections
36
+
37
+ ## [2.2.0] - Previous Release
38
+
39
+ ### Added
40
+ - Firebase Storage support with signed URLs
41
+ - Custom token creation and sign-in
42
+ - Support for Firebase v10 session tokens
43
+ - Field transforms (serverTimestamp, increment, arrayUnion, arrayRemove, delete)
44
+ - Batch write operations
45
+ - Advanced query support (where, orderBy, limit)
46
+
47
+ ### Changed
48
+ - Improved token verification to support both v9 and v10 token formats
49
+ - Enhanced error handling across all modules
50
+
51
+ ### Fixed
52
+ - Public key caching and rotation handling
53
+ - Token verification for multiple issuer formats
54
+
55
+ ## [2.1.0] - Initial Release
56
+
57
+ ### Added
58
+ - Core Firebase Admin SDK functionality for Cloudflare Workers
59
+ - Authentication with ID token verification
60
+ - Firestore CRUD operations via REST API
61
+ - Service account configuration
62
+ - X.509 certificate handling
63
+ - JWT token generation
package/dist/index.d.mts CHANGED
@@ -480,6 +480,114 @@ declare function queryDocuments(collectionPath: string, options?: QueryOptions):
480
480
  */
481
481
  declare function batchWrite(operations: BatchWrite[]): Promise<BatchWriteResult>;
482
482
 
483
+ /**
484
+ * Firebase Admin SDK v8 - Firestore Collection Iteration
485
+ * Convenience functions for iterating through collections
486
+ */
487
+
488
+ /**
489
+ * List all documents in a collection
490
+ * This is a convenience wrapper around queryDocuments with no filters
491
+ *
492
+ * @param collectionPath - Collection path
493
+ * @param options - Query options (limit, orderBy, etc.)
494
+ * @returns Array of documents with id and data
495
+ * @throws {Error} If the operation fails
496
+ *
497
+ * @example
498
+ * ```typescript
499
+ * // List all users
500
+ * const users = await listDocuments('users');
501
+ *
502
+ * // List with pagination
503
+ * const firstPage = await listDocuments('users', { limit: 10 });
504
+ * const secondPage = await listDocuments('users', {
505
+ * limit: 10,
506
+ * startAfter: [firstPage[firstPage.length - 1].data.name]
507
+ * });
508
+ * ```
509
+ */
510
+ declare function listDocuments(collectionPath: string, options?: QueryOptions): Promise<Array<{
511
+ id: string;
512
+ data: DataObject;
513
+ }>>;
514
+ /**
515
+ * Iterate through all documents in a collection
516
+ * Handles pagination automatically by fetching documents in batches
517
+ *
518
+ * @param collectionPath - Collection path
519
+ * @param callback - Function called for each document
520
+ * @param options - Iteration options
521
+ * @throws {Error} If the operation fails
522
+ *
523
+ * @example
524
+ * ```typescript
525
+ * // Process all messages
526
+ * await iterateCollection(
527
+ * 'users/user123/conversations/main/messages',
528
+ * async (msg) => {
529
+ * console.log('Processing message:', msg.id);
530
+ * // Perform operations on each message
531
+ * },
532
+ * { batchSize: 100 }
533
+ * );
534
+ *
535
+ * // Iterate with ordering
536
+ * await iterateCollection(
537
+ * 'users',
538
+ * async (user) => {
539
+ * console.log('User:', user.data.name);
540
+ * },
541
+ * {
542
+ * batchSize: 50,
543
+ * orderBy: [{ field: 'createdAt', direction: 'ASCENDING' }]
544
+ * }
545
+ * );
546
+ * ```
547
+ */
548
+ declare function iterateCollection(collectionPath: string, callback: (doc: {
549
+ id: string;
550
+ data: DataObject;
551
+ }) => Promise<void>, options?: {
552
+ batchSize?: number;
553
+ orderBy?: Array<{
554
+ field: string;
555
+ direction: 'ASCENDING' | 'DESCENDING';
556
+ }>;
557
+ where?: Array<{
558
+ field: string;
559
+ op: any;
560
+ value: any;
561
+ }>;
562
+ }): Promise<void>;
563
+ /**
564
+ * Count documents in a collection
565
+ * Note: This fetches all documents to count them, which may be expensive for large collections
566
+ *
567
+ * @param collectionPath - Collection path
568
+ * @param options - Query options (where filters)
569
+ * @returns Number of documents
570
+ * @throws {Error} If the operation fails
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // Count all users
575
+ * const totalUsers = await countDocuments('users');
576
+ *
577
+ * // Count active users
578
+ * const activeUsers = await countDocuments('users', {
579
+ * where: [{ field: 'active', op: '==', value: true }]
580
+ * });
581
+ * ```
582
+ */
583
+ declare function countDocuments(collectionPath: string, options?: {
584
+ where?: Array<{
585
+ field: string;
586
+ op: any;
587
+ value: any;
588
+ }>;
589
+ }): Promise<number>;
590
+
483
591
  /**
484
592
  * Firebase Storage client using Google Cloud Storage REST API
485
593
  * Compatible with edge runtimes (Cloudflare Workers, Vercel Edge, etc.)
@@ -760,4 +868,4 @@ declare function getAdminAccessToken(): Promise<string>;
760
868
  */
761
869
  declare function clearTokenCache(): void;
762
870
 
763
- export { type BatchWrite, type BatchWriteResult, type CustomClaims, type CustomTokenSignInResponse, type DataObject, type DecodedIdToken, type DocumentReference, type DownloadOptions, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FileMetadata, type FirestoreDocument, type FirestoreValue, type ListFilesResult, type ListOptions, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type SignedUrlOptions, type TokenResponse, type UpdateOptions, type UploadOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearConfig, clearTokenCache, createCustomToken, deleteDocument, deleteFile, downloadFile, fileExists, generateSignedUrl, getAdminAccessToken, getAuth, getConfig, getDocument, getFileMetadata, getProjectId, getServiceAccount, getUserFromToken, initializeApp, listFiles, queryDocuments, setDocument, signInWithCustomToken, updateDocument, uploadFile, verifyIdToken };
871
+ export { type BatchWrite, type BatchWriteResult, type CustomClaims, type CustomTokenSignInResponse, type DataObject, type DecodedIdToken, type DocumentReference, type DownloadOptions, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FileMetadata, type FirestoreDocument, type FirestoreValue, type ListFilesResult, type ListOptions, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type SignedUrlOptions, type TokenResponse, type UpdateOptions, type UploadOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearConfig, clearTokenCache, countDocuments, createCustomToken, deleteDocument, deleteFile, downloadFile, fileExists, generateSignedUrl, getAdminAccessToken, getAuth, getConfig, getDocument, getFileMetadata, getProjectId, getServiceAccount, getUserFromToken, initializeApp, iterateCollection, listDocuments, listFiles, queryDocuments, setDocument, signInWithCustomToken, updateDocument, uploadFile, verifyIdToken };
package/dist/index.d.ts CHANGED
@@ -480,6 +480,114 @@ declare function queryDocuments(collectionPath: string, options?: QueryOptions):
480
480
  */
481
481
  declare function batchWrite(operations: BatchWrite[]): Promise<BatchWriteResult>;
482
482
 
483
+ /**
484
+ * Firebase Admin SDK v8 - Firestore Collection Iteration
485
+ * Convenience functions for iterating through collections
486
+ */
487
+
488
+ /**
489
+ * List all documents in a collection
490
+ * This is a convenience wrapper around queryDocuments with no filters
491
+ *
492
+ * @param collectionPath - Collection path
493
+ * @param options - Query options (limit, orderBy, etc.)
494
+ * @returns Array of documents with id and data
495
+ * @throws {Error} If the operation fails
496
+ *
497
+ * @example
498
+ * ```typescript
499
+ * // List all users
500
+ * const users = await listDocuments('users');
501
+ *
502
+ * // List with pagination
503
+ * const firstPage = await listDocuments('users', { limit: 10 });
504
+ * const secondPage = await listDocuments('users', {
505
+ * limit: 10,
506
+ * startAfter: [firstPage[firstPage.length - 1].data.name]
507
+ * });
508
+ * ```
509
+ */
510
+ declare function listDocuments(collectionPath: string, options?: QueryOptions): Promise<Array<{
511
+ id: string;
512
+ data: DataObject;
513
+ }>>;
514
+ /**
515
+ * Iterate through all documents in a collection
516
+ * Handles pagination automatically by fetching documents in batches
517
+ *
518
+ * @param collectionPath - Collection path
519
+ * @param callback - Function called for each document
520
+ * @param options - Iteration options
521
+ * @throws {Error} If the operation fails
522
+ *
523
+ * @example
524
+ * ```typescript
525
+ * // Process all messages
526
+ * await iterateCollection(
527
+ * 'users/user123/conversations/main/messages',
528
+ * async (msg) => {
529
+ * console.log('Processing message:', msg.id);
530
+ * // Perform operations on each message
531
+ * },
532
+ * { batchSize: 100 }
533
+ * );
534
+ *
535
+ * // Iterate with ordering
536
+ * await iterateCollection(
537
+ * 'users',
538
+ * async (user) => {
539
+ * console.log('User:', user.data.name);
540
+ * },
541
+ * {
542
+ * batchSize: 50,
543
+ * orderBy: [{ field: 'createdAt', direction: 'ASCENDING' }]
544
+ * }
545
+ * );
546
+ * ```
547
+ */
548
+ declare function iterateCollection(collectionPath: string, callback: (doc: {
549
+ id: string;
550
+ data: DataObject;
551
+ }) => Promise<void>, options?: {
552
+ batchSize?: number;
553
+ orderBy?: Array<{
554
+ field: string;
555
+ direction: 'ASCENDING' | 'DESCENDING';
556
+ }>;
557
+ where?: Array<{
558
+ field: string;
559
+ op: any;
560
+ value: any;
561
+ }>;
562
+ }): Promise<void>;
563
+ /**
564
+ * Count documents in a collection
565
+ * Note: This fetches all documents to count them, which may be expensive for large collections
566
+ *
567
+ * @param collectionPath - Collection path
568
+ * @param options - Query options (where filters)
569
+ * @returns Number of documents
570
+ * @throws {Error} If the operation fails
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // Count all users
575
+ * const totalUsers = await countDocuments('users');
576
+ *
577
+ * // Count active users
578
+ * const activeUsers = await countDocuments('users', {
579
+ * where: [{ field: 'active', op: '==', value: true }]
580
+ * });
581
+ * ```
582
+ */
583
+ declare function countDocuments(collectionPath: string, options?: {
584
+ where?: Array<{
585
+ field: string;
586
+ op: any;
587
+ value: any;
588
+ }>;
589
+ }): Promise<number>;
590
+
483
591
  /**
484
592
  * Firebase Storage client using Google Cloud Storage REST API
485
593
  * Compatible with edge runtimes (Cloudflare Workers, Vercel Edge, etc.)
@@ -760,4 +868,4 @@ declare function getAdminAccessToken(): Promise<string>;
760
868
  */
761
869
  declare function clearTokenCache(): void;
762
870
 
763
- export { type BatchWrite, type BatchWriteResult, type CustomClaims, type CustomTokenSignInResponse, type DataObject, type DecodedIdToken, type DocumentReference, type DownloadOptions, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FileMetadata, type FirestoreDocument, type FirestoreValue, type ListFilesResult, type ListOptions, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type SignedUrlOptions, type TokenResponse, type UpdateOptions, type UploadOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearConfig, clearTokenCache, createCustomToken, deleteDocument, deleteFile, downloadFile, fileExists, generateSignedUrl, getAdminAccessToken, getAuth, getConfig, getDocument, getFileMetadata, getProjectId, getServiceAccount, getUserFromToken, initializeApp, listFiles, queryDocuments, setDocument, signInWithCustomToken, updateDocument, uploadFile, verifyIdToken };
871
+ export { type BatchWrite, type BatchWriteResult, type CustomClaims, type CustomTokenSignInResponse, type DataObject, type DecodedIdToken, type DocumentReference, type DownloadOptions, FieldValue, type FieldValue$1 as FieldValueSentinel, FieldValueType, type FileMetadata, type FirestoreDocument, type FirestoreValue, type ListFilesResult, type ListOptions, type QueryFilter, type QueryOptions, type QueryOrder, type ServiceAccount, type SetOptions, type SignedUrlOptions, type TokenResponse, type UpdateOptions, type UploadOptions, type UserInfo, type WhereFilterOp, addDocument, batchWrite, clearConfig, clearTokenCache, countDocuments, createCustomToken, deleteDocument, deleteFile, downloadFile, fileExists, generateSignedUrl, getAdminAccessToken, getAuth, getConfig, getDocument, getFileMetadata, getProjectId, getServiceAccount, getUserFromToken, initializeApp, iterateCollection, listDocuments, listFiles, queryDocuments, setDocument, signInWithCustomToken, updateDocument, uploadFile, verifyIdToken };
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  batchWrite: () => batchWrite,
26
26
  clearConfig: () => clearConfig,
27
27
  clearTokenCache: () => clearTokenCache,
28
+ countDocuments: () => countDocuments,
28
29
  createCustomToken: () => createCustomToken,
29
30
  deleteDocument: () => deleteDocument,
30
31
  deleteFile: () => deleteFile,
@@ -40,6 +41,8 @@ __export(index_exports, {
40
41
  getServiceAccount: () => getServiceAccount,
41
42
  getUserFromToken: () => getUserFromToken,
42
43
  initializeApp: () => initializeApp,
44
+ iterateCollection: () => iterateCollection,
45
+ listDocuments: () => listDocuments,
43
46
  listFiles: () => listFiles,
44
47
  queryDocuments: () => queryDocuments,
45
48
  setDocument: () => setDocument,
@@ -1127,6 +1130,46 @@ async function batchWrite(operations) {
1127
1130
  return await response.json();
1128
1131
  }
1129
1132
 
1133
+ // src/firestore/iteration.ts
1134
+ async function listDocuments(collectionPath, options) {
1135
+ return queryDocuments(collectionPath, options);
1136
+ }
1137
+ async function iterateCollection(collectionPath, callback, options) {
1138
+ const batchSize = options?.batchSize || 100;
1139
+ let lastDoc = null;
1140
+ let hasMore = true;
1141
+ while (hasMore) {
1142
+ const queryOptions = {
1143
+ limit: batchSize,
1144
+ orderBy: options?.orderBy,
1145
+ where: options?.where
1146
+ };
1147
+ if (lastDoc && options?.orderBy && options.orderBy.length > 0) {
1148
+ const cursorValues = options.orderBy.map((order) => lastDoc.data[order.field]);
1149
+ queryOptions.startAfter = cursorValues;
1150
+ }
1151
+ const docs = await queryDocuments(collectionPath, queryOptions);
1152
+ for (const doc of docs) {
1153
+ await callback(doc);
1154
+ }
1155
+ hasMore = docs.length === batchSize;
1156
+ if (hasMore && docs.length > 0) {
1157
+ lastDoc = docs[docs.length - 1];
1158
+ }
1159
+ }
1160
+ }
1161
+ async function countDocuments(collectionPath, options) {
1162
+ let count = 0;
1163
+ await iterateCollection(
1164
+ collectionPath,
1165
+ async () => {
1166
+ count++;
1167
+ },
1168
+ { batchSize: 1e3, where: options?.where }
1169
+ );
1170
+ return count;
1171
+ }
1172
+
1130
1173
  // src/storage/client.ts
1131
1174
  var STORAGE_API_BASE = "https://storage.googleapis.com/storage/v1";
1132
1175
  var UPLOAD_API_BASE = "https://storage.googleapis.com/upload/storage/v1";
@@ -1442,6 +1485,7 @@ async function generateSignedUrl(path, options) {
1442
1485
  batchWrite,
1443
1486
  clearConfig,
1444
1487
  clearTokenCache,
1488
+ countDocuments,
1445
1489
  createCustomToken,
1446
1490
  deleteDocument,
1447
1491
  deleteFile,
@@ -1457,6 +1501,8 @@ async function generateSignedUrl(path, options) {
1457
1501
  getServiceAccount,
1458
1502
  getUserFromToken,
1459
1503
  initializeApp,
1504
+ iterateCollection,
1505
+ listDocuments,
1460
1506
  listFiles,
1461
1507
  queryDocuments,
1462
1508
  setDocument,
package/dist/index.mjs CHANGED
@@ -1075,6 +1075,46 @@ async function batchWrite(operations) {
1075
1075
  return await response.json();
1076
1076
  }
1077
1077
 
1078
+ // src/firestore/iteration.ts
1079
+ async function listDocuments(collectionPath, options) {
1080
+ return queryDocuments(collectionPath, options);
1081
+ }
1082
+ async function iterateCollection(collectionPath, callback, options) {
1083
+ const batchSize = options?.batchSize || 100;
1084
+ let lastDoc = null;
1085
+ let hasMore = true;
1086
+ while (hasMore) {
1087
+ const queryOptions = {
1088
+ limit: batchSize,
1089
+ orderBy: options?.orderBy,
1090
+ where: options?.where
1091
+ };
1092
+ if (lastDoc && options?.orderBy && options.orderBy.length > 0) {
1093
+ const cursorValues = options.orderBy.map((order) => lastDoc.data[order.field]);
1094
+ queryOptions.startAfter = cursorValues;
1095
+ }
1096
+ const docs = await queryDocuments(collectionPath, queryOptions);
1097
+ for (const doc of docs) {
1098
+ await callback(doc);
1099
+ }
1100
+ hasMore = docs.length === batchSize;
1101
+ if (hasMore && docs.length > 0) {
1102
+ lastDoc = docs[docs.length - 1];
1103
+ }
1104
+ }
1105
+ }
1106
+ async function countDocuments(collectionPath, options) {
1107
+ let count = 0;
1108
+ await iterateCollection(
1109
+ collectionPath,
1110
+ async () => {
1111
+ count++;
1112
+ },
1113
+ { batchSize: 1e3, where: options?.where }
1114
+ );
1115
+ return count;
1116
+ }
1117
+
1078
1118
  // src/storage/client.ts
1079
1119
  var STORAGE_API_BASE = "https://storage.googleapis.com/storage/v1";
1080
1120
  var UPLOAD_API_BASE = "https://storage.googleapis.com/upload/storage/v1";
@@ -1389,6 +1429,7 @@ export {
1389
1429
  batchWrite,
1390
1430
  clearConfig,
1391
1431
  clearTokenCache,
1432
+ countDocuments,
1392
1433
  createCustomToken,
1393
1434
  deleteDocument,
1394
1435
  deleteFile,
@@ -1404,6 +1445,8 @@ export {
1404
1445
  getServiceAccount,
1405
1446
  getUserFromToken,
1406
1447
  initializeApp,
1448
+ iterateCollection,
1449
+ listDocuments,
1407
1450
  listFiles,
1408
1451
  queryDocuments,
1409
1452
  setDocument,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/firebase-admin-sdk-v8",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
4
4
  "description": "Firebase Admin SDK for Cloudflare Workers and edge runtimes using REST APIs",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",