@prmichaelsen/firebase-admin-sdk-v8 2.0.19 β†’ 2.0.21

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.
@@ -0,0 +1,50 @@
1
+ name: E2E Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ mainline ]
6
+ pull_request:
7
+ branches: [ mainline ]
8
+ workflow_dispatch: # Allow manual trigger
9
+
10
+ jobs:
11
+ e2e-tests:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '20'
22
+ cache: 'npm'
23
+
24
+ - name: Install dependencies
25
+ run: npm ci
26
+
27
+ - name: Run unit tests
28
+ run: npm test
29
+
30
+ - name: Create service account file
31
+ run: |
32
+ echo '${{ secrets.FIREBASE_SERVICE_ACCOUNT }}' > service-account.json
33
+
34
+ - name: Run e2e tests with coverage
35
+ run: npm run test:e2e -- --coverage
36
+ env:
37
+ NODE_ENV: test
38
+
39
+ - name: Upload e2e coverage to Codecov
40
+ uses: codecov/codecov-action@v4
41
+ with:
42
+ token: ${{ secrets.CODECOV_TOKEN }}
43
+ files: ./coverage/lcov.info
44
+ flags: e2etests
45
+ name: codecov-e2e
46
+ fail_ci_if_error: false
47
+
48
+ - name: Clean up service account file
49
+ if: always()
50
+ run: rm -f service-account.json
@@ -0,0 +1,44 @@
1
+ name: Unit Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ mainline, develop ]
6
+ pull_request:
7
+ branches: [ mainline, develop ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [18, 20, 22]
16
+
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js ${{ matrix.node-version }}
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: ${{ matrix.node-version }}
25
+ cache: 'npm'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci
29
+
30
+ - name: Run unit tests
31
+ run: npm test
32
+
33
+ - name: Run build
34
+ run: npm run build
35
+
36
+ - name: Upload coverage to Codecov (Node 20 only)
37
+ if: matrix.node-version == 20
38
+ uses: codecov/codecov-action@v4
39
+ with:
40
+ token: ${{ secrets.CODECOV_TOKEN }}
41
+ files: ./coverage/lcov.info
42
+ flags: unittests
43
+ name: codecov-umbrella
44
+ fail_ci_if_error: false
package/README.md CHANGED
@@ -2,8 +2,11 @@
2
2
 
3
3
  > Firebase Admin SDK for Cloudflare Workers and edge runtimes using REST APIs
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/firebase-admin-sdk-v8.svg)](https://www.npmjs.com/package/firebase-admin-sdk-v8)
5
+ [![npm version](https://img.shields.io/npm/v/@prmichaelsen/firebase-admin-sdk-v8.svg)](https://www.npmjs.com/package/@prmichaelsen/firebase-admin-sdk-v8)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![Unit Tests](https://github.com/prmichaelsen/firebase-admin-sdk-v8/actions/workflows/test.yml/badge.svg)](https://github.com/prmichaelsen/firebase-admin-sdk-v8/actions/workflows/test.yml)
8
+ [![E2E Tests](https://github.com/prmichaelsen/firebase-admin-sdk-v8/actions/workflows/e2e-tests.yml/badge.svg)](https://github.com/prmichaelsen/firebase-admin-sdk-v8/actions/workflows/e2e-tests.yml)
9
+ [![codecov](https://codecov.io/gh/prmichaelsen/firebase-admin-sdk-v8/branch/mainline/graph/badge.svg)](https://codecov.io/gh/prmichaelsen/firebase-admin-sdk-v8)
7
10
 
8
11
  This library provides Firebase Admin SDK functionality for Cloudflare Workers and other edge runtimes. It uses REST APIs and JWT token generation instead of the Node.js Admin SDK, making it compatible with environments that don't support Node.js.
9
12
 
@@ -25,7 +28,7 @@ This library provides Firebase Admin SDK functionality for Cloudflare Workers an
25
28
  ## πŸ“¦ Installation
26
29
 
27
30
  ```bash
28
- npm install firebase-admin-sdk-v8
31
+ npm install @prmichaelsen/firebase-admin-sdk-v8
29
32
  ```
30
33
 
31
34
  ## πŸš€ Quick Start
@@ -78,7 +81,7 @@ FIREBASE_PROJECT_ID=your-project-id
78
81
  ### 2. Verify ID Tokens
79
82
 
80
83
  ```typescript
81
- import { verifyIdToken, getUserFromToken } from 'firebase-admin-sdk-v8';
84
+ import { verifyIdToken, getUserFromToken } from '@prmichaelsen/firebase-admin-sdk-v8';
82
85
 
83
86
  const authHeader = request.headers.get('authorization');
84
87
  const idToken = authHeader?.split('Bearer ')[1];
@@ -94,7 +97,7 @@ try {
94
97
  ### 3. Basic Firestore Operations
95
98
 
96
99
  ```typescript
97
- import { setDocument, getDocument, updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
100
+ import { setDocument, getDocument, updateDocument, FieldValue } from '@prmichaelsen/firebase-admin-sdk-v8';
98
101
 
99
102
  // Set a document (create or overwrite)
100
103
  await setDocument('users', 'user123', {
@@ -116,7 +119,7 @@ await updateDocument('users', 'user123', {
116
119
  ### 4. Advanced Queries
117
120
 
118
121
  ```typescript
119
- import { queryDocuments } from 'firebase-admin-sdk-v8';
122
+ import { queryDocuments } from '@prmichaelsen/firebase-admin-sdk-v8';
120
123
 
121
124
  const activeUsers = await queryDocuments('users', {
122
125
  where: [
@@ -397,7 +400,7 @@ export default {
397
400
  ### Leaderboard Example
398
401
 
399
402
  ```typescript
400
- import { queryDocuments, updateDocument, FieldValue } from 'firebase-admin-sdk-v8';
403
+ import { queryDocuments, updateDocument, FieldValue } from '@prmichaelsen/firebase-admin-sdk-v8';
401
404
 
402
405
  async function getTopPlayers(limit = 10) {
403
406
  return await queryDocuments('players', {
@@ -418,7 +421,7 @@ async function updatePlayerScore(playerId: string, points: number) {
418
421
  ### Bulk Operations Example
419
422
 
420
423
  ```typescript
421
- import { batchWrite, FieldValue } from 'firebase-admin-sdk-v8';
424
+ import { batchWrite, FieldValue } from '@prmichaelsen/firebase-admin-sdk-v8';
422
425
 
423
426
  async function bulkUpdateUsers(userIds: string[], updates: any) {
424
427
  const operations = userIds.map(userId => ({
@@ -518,11 +521,132 @@ For better query performance:
518
521
  | Firestore Queries | βœ… | where, orderBy, limit, cursors |
519
522
  | Firestore Batch | βœ… | Up to 500 operations |
520
523
  | Firestore Transactions | ❌ | Not yet implemented |
524
+ | **Realtime Listeners** | **❌** | **See explanation below** |
521
525
  | Field Values | βœ… | increment, arrayUnion, serverTimestamp, etc. |
522
526
  | Realtime Database | ❌ | Not planned |
523
527
  | Cloud Storage | ❌ | Not yet implemented |
524
528
  | Cloud Messaging | ❌ | Not yet implemented |
525
529
 
530
+ ## ⚠️ Realtime Listeners Not Supported
531
+
532
+ This library **does not support** Firestore realtime listeners (`onSnapshot()`). Here's why:
533
+
534
+ ### Technical Limitation
535
+
536
+ **This library uses the Firestore REST API**, which is:
537
+ - βœ… Stateless (request/response only)
538
+ - βœ… Compatible with edge runtimes (Cloudflare Workers, Vercel Edge)
539
+ - ❌ **No persistent connections**
540
+ - ❌ **No server-push capabilities**
541
+ - ❌ **No streaming support**
542
+
543
+ **Realtime listeners require**:
544
+ - Persistent connections (WebSocket or gRPC)
545
+ - Bidirectional streaming
546
+ - Server-push architecture
547
+
548
+ The Firestore REST API simply doesn't provide these capabilities.
549
+
550
+ ### Why Not Implement gRPC?
551
+
552
+ While Firestore does offer a gRPC API with streaming support, implementing it would require:
553
+
554
+ 1. **Complex Protocol Implementation**
555
+ - HTTP/2 framing
556
+ - gRPC message framing
557
+ - Protobuf encoding/decoding
558
+ - Authentication flow
559
+ - Reconnection logic
560
+ - ~100+ hours of development
561
+
562
+ 2. **Runtime Limitations**
563
+ - Cloudflare Workers doesn't support full gRPC (only gRPC-Web)
564
+ - gRPC-Web requires a proxy server
565
+ - Can't connect directly to Firestore's gRPC endpoint
566
+ - Would only work in Durable Objects, not regular Workers
567
+
568
+ 3. **Maintenance Burden**
569
+ - Must keep up with Firestore protocol changes
570
+ - Complex debugging and error handling
571
+ - High ongoing maintenance cost
572
+
573
+ ### Alternatives
574
+
575
+ If you need realtime updates, consider these approaches:
576
+
577
+ #### 1. **Polling (Simple)**
578
+ ```typescript
579
+ // Poll for changes every 5 seconds
580
+ setInterval(async () => {
581
+ const doc = await getDocument('users', 'user123');
582
+ // Handle updates
583
+ }, 5000);
584
+ ```
585
+
586
+ **Pros**: Simple, works everywhere
587
+ **Cons**: 5-second delay, polling costs
588
+
589
+ #### 2. **Durable Objects + Polling (Better)**
590
+ ```typescript
591
+ // Durable Object polls once, broadcasts to many clients
592
+ export class FirestoreSync {
593
+ async poll() {
594
+ const doc = await getDocument('users', 'user123');
595
+ // Broadcast to all connected WebSocket clients
596
+ for (const ws of this.sessions) {
597
+ ws.send(JSON.stringify(doc));
598
+ }
599
+ }
600
+ }
601
+ ```
602
+
603
+ **Pros**: One poll serves many clients, WebSocket push to clients
604
+ **Cons**: Still polling-based, Cloudflare-specific
605
+
606
+ #### 3. **Hybrid Architecture (Best)**
607
+ ```typescript
608
+ // Use firebase-admin-node for realtime in Node.js
609
+ import admin from 'firebase-admin';
610
+
611
+ admin.firestore().collection('users').doc('user123')
612
+ .onSnapshot((snapshot) => {
613
+ // True realtime updates
614
+ console.log('Update:', snapshot.data());
615
+ });
616
+
617
+ // Use this library for CRUD in edge functions
618
+ import { getDocument } from '@prmichaelsen/firebase-admin-sdk-v8';
619
+ const doc = await getDocument('users', 'user123');
620
+ ```
621
+
622
+ **Pros**: True realtime where needed, edge performance for CRUD
623
+ **Cons**: Requires separate Node.js service
624
+
625
+ #### 4. **Firebase Client SDK (Frontend)**
626
+ ```typescript
627
+ // Use Firebase Client SDK in browser/mobile
628
+ import { onSnapshot, doc } from 'firebase/firestore';
629
+
630
+ onSnapshot(doc(db, 'users', 'user123'), (snapshot) => {
631
+ console.log('Update:', snapshot.data());
632
+ });
633
+ ```
634
+
635
+ **Pros**: True realtime, built-in, well-supported
636
+ **Cons**: Client-side only, requires Firebase Auth
637
+
638
+ ### Recommendation
639
+
640
+ - **For edge runtimes**: Use polling or Durable Objects pattern
641
+ - **For true realtime**: Use `firebase-admin-node` in Node.js
642
+ - **For client apps**: Use Firebase Client SDK
643
+ - **For hybrid**: Use this library for CRUD + Node.js for realtime
644
+
645
+ ### Related
646
+
647
+ - [firebase-admin-node](https://github.com/firebase/firebase-admin-node) - Full Admin SDK with realtime support
648
+ - [Firebase Client SDK](https://firebase.google.com/docs/firestore/query-data/listen) - Client-side realtime listeners
649
+
526
650
  ## πŸ—ΊοΈ Roadmap
527
651
 
528
652
  - [ ] Custom token creation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/firebase-admin-sdk-v8",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
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",
package/firebase.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "projects": {
3
- "default": "prmichaelsen-firebase-e2e"
4
- },
5
- "firestore": {
6
- "rules": "firestore.rules",
7
- "indexes": "firestore.indexes.json"
8
- }
9
- }
@@ -1,33 +0,0 @@
1
- {
2
- "indexes": [
3
- {
4
- "collectionGroup": "e2e-tests",
5
- "queryScope": "COLLECTION",
6
- "fields": [
7
- {
8
- "fieldPath": "_test",
9
- "order": "ASCENDING"
10
- },
11
- {
12
- "fieldPath": "age",
13
- "order": "ASCENDING"
14
- }
15
- ]
16
- },
17
- {
18
- "collectionGroup": "messages",
19
- "queryScope": "COLLECTION",
20
- "fields": [
21
- {
22
- "fieldPath": "_test",
23
- "order": "ASCENDING"
24
- },
25
- {
26
- "fieldPath": "timestamp",
27
- "order": "ASCENDING"
28
- }
29
- ]
30
- }
31
- ],
32
- "fieldOverrides": []
33
- }
package/firestore.rules DELETED
@@ -1,11 +0,0 @@
1
- rules_version = '2';
2
-
3
- service cloud.firestore {
4
- match /databases/{database}/documents {
5
- // Allow all reads and writes for testing
6
- // WARNING: These rules are for testing only!
7
- match /{document=**} {
8
- allow read, write: if true;
9
- }
10
- }
11
- }
package/jest.config.js DELETED
@@ -1,12 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- roots: ['<rootDir>/src'],
5
- testMatch: ['**/*.spec.ts'],
6
- moduleFileExtensions: ['ts', 'js'],
7
- collectCoverageFrom: [
8
- 'src/**/*.ts',
9
- '!src/**/*.d.ts',
10
- '!src/**/*.spec.ts',
11
- ],
12
- };
@@ -1,14 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- testMatch: ['**/*.e2e.ts'],
5
- testTimeout: 30000, // 30 seconds for real API calls
6
- roots: ['<rootDir>/src'],
7
- collectCoverageFrom: [
8
- 'src/**/*.ts',
9
- '!src/**/*.spec.ts',
10
- '!src/**/*.e2e.ts',
11
- '!src/types.ts',
12
- '!src/index.ts',
13
- ],
14
- };
@@ -1,13 +0,0 @@
1
- {
2
- "type": "service_account",
3
- "project_id": "prmichaelsen-firebase-e2e",
4
- "private_key_id": "84caabb8515ec5fab4caa53a0f85405c270d5cd4",
5
- "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/0n8V7m7vCQ9/\n5FGYL5V20pQxliUMF/ycNBSV/xHrXAvTMxyMEjFK8Tg9sBLdYhuxC488lnwm3/o+\nn5JkckQ2AyzXX6mi+camwxdLXmT97kXqdFLisO4PY7Fv6HvvMgRQqysj7aJkyiz7\nrAs0DpQq1L70sBFdVLiScPH9FFnuV0EeyOTuVgYwGYk1L76/U7bb3WLNCmcmtG+Y\nt4BNzyMqFgtIdXCQFVBQf9HXy3x5xk8a1rrkf7pEuiwK0PXCDIVH7GYX4xCiQ1qs\nYF4IunNFhcwu1hk5XTIDSVrIn/qLPMZvEcBqHxIJd5JvePjx5hPP81b1mrGUVske\nsaRimjxxAgMBAAECggEAAWNKVG7KslkMRH5y5q56yYbMLVsAPp5SehDYZfNtU5jG\nucr2CxS7SDxcOKS0UOdmUDlyBQaztED3mbS5hZeGuHtSZjvaHtnpdDMXe+NIHhw3\nY520LHwKOjtG69/bPFz4x1qjBRoG4Zgi4NlFpXqbhinO4zdTkNYi6xBSd+R0oshP\nSo59lQvs8e3bMD4f4uTl7JxUifjVM64R3gCkH6AbGqU01wg8UzsllCf0fQM04w8i\nq1oVjhBVWYYVE7w2H+EU+LdiRSRET+Vrk5dtBL3vI6yckvGmxTBMnkK2gTFAAR6F\nnN4NKlUsiFol9WVRY3tdRNOnStjlORDyerSEFQaqhwKBgQDfAa5ddxBVbxUS3E2a\nnGJRA44fYlRyZf9KnJdz8uWsCvuG7UYbe2bp7TxlpEXdTG6Vqu/hhYWd/msmhupZ\nc+YFg1HWE1Ee+nQv7iwAD+okfncnKGIC65XjwaSEMRGrmtxBL6Qq4yxn/Yug/8YR\nniGRQKuMtJ2ZA0p41vI6Mkt7kwKBgQDcM7eQQ5482FcXuOfUlPoiWnd+pF5mNrU1\ngKoxdsXMYRKyTGMPLrOKqsf6kisQUlA48vWRCQOa9QBSjHktfOt2EZ3mNQz5k3AR\n/dIjCGf+ATr2P9Sc0uo7sA20XB62wmG+t2A/vxf9WzBAgdDk6nENB4nz6lL9xcak\ngvVt2vXSawKBgQCV6JRk4f/J3oVFC3DjaRKyMPid4kSwLh6B8mfhGrwHfc59cgz5\ntmeFAuPh057fV1zTIXhlmpMqlPdEi9cHUOCkfhVKGewjLetiuPE9DXWxGI5SdVQF\ncIZu9yH3duDRAaXj7/mklteoBAmTrbxg5XLdKKLpUBTM4ihyuNNWCa8yHwKBgCYK\noTnBFMM6NMGaZiKpohTxQBeW2eAar2+QzNZCyKUoWAyJecuTq9zW6Dl3qwzky4sr\nHhVyUzcgAHBCaGTdYehB3t94ZsdvGztgeD8pIp4VJFSKbnaxUVoCbjusdnnoVu6V\ny4D3yHMyn8FlK+uAPQudM835u2CwHEMrhK731uQFAoGBAKO0crVWuY1EP1RLSyLK\nIS3uUgbauBbQlE4ZPBTi84vXCZjN/53obFgkPHJ5tdjxj6C8x58jgHg/Hufyvbib\ngOQQxadM90UBumlzA8lV7A9jvL2ryfop9ketnVO5hPvB4O8iw9Z1R+25FeM9ZFJI\nqmEjiy9Nhmvpvur+FZ85qcRm\n-----END PRIVATE KEY-----\n",
6
- "client_email": "firebase-adminsdk-fbsvc@prmichaelsen-firebase-e2e.iam.gserviceaccount.com",
7
- "client_id": "103889460014910902622",
8
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
- "token_uri": "https://oauth2.googleapis.com/token",
10
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40prmichaelsen-firebase-e2e.iam.gserviceaccount.com",
12
- "universe_domain": "googleapis.com"
13
- }