{"_id":"@cougargrades/firebase-rest-firestore","_rev":"2-9aca66b013cd0da7c4bd78fd6767bf8d","name":"@cougargrades/firebase-rest-firestore","dist-tags":{"latest":"1.6.1"},"versions":{"1.6.0":{"name":"@cougargrades/firebase-rest-firestore","version":"1.6.0","keywords":["firebase","firestore","rest","api","edge","cloudflare","workers","vercel"],"author":"","license":"MIT","_id":"@cougargrades/firebase-rest-firestore@1.6.0","maintainers":[{"name":"austinjckson","email":"adjackson6@uh.edu"},{"name":"au5ton","email":"austinjckson@gmail.com"}],"homepage":"https://github.com/cougargrades/firebase-rest-firestore#readme","bugs":{"url":"https://github.com/cougargrades/firebase-rest-firestore/issues"},"dist":{"shasum":"8a1d89bc3207e67da0ff84d0bcf029881b3e195a","tarball":"https://registry.npmjs.org/@cougargrades/firebase-rest-firestore/-/firebase-rest-firestore-1.6.0.tgz","fileCount":38,"integrity":"sha512-d9WAUnXCttX0ziaFss+Xx8Qhz+WSY84IjGuo7GZhtov2d1wWNIpIFh6LxofNmDo8W6bfkIVFNXkNQ/5oxh9XaQ==","signatures":[{"sig":"MEUCIQCBUDAoKezOZ9kedLRJaKWle4UUWYtVcBzxfrzfASFTyAIgYVWlg4THS5db+bxBFFtexkdn0GCzPaBbiZHKTSUcROg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":189602},"main":"dist/cjs/index.js","types":"dist/types/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=20.8.1"},"gitHead":"62a7b1295045efb7a2b184e8a77e781511c2e69f","scripts":{"test":"vitest","build":"npm run build:esm && npm run build:cjs && npm run build:types","watch":"concurrently \"npm run watch:esm\" \"npm run watch:cjs\" \"npm run watch:types\"","build:cjs":"tsc -p tsconfig.cjs.json","build:esm":"tsc -p tsconfig.esm.json","watch:cjs":"tsc -p tsconfig.cjs.json --watch","watch:esm":"tsc -p tsconfig.esm.json --watch","build:types":"tsc -p tsconfig.json --emitDeclarationOnly --declarationDir dist/types","watch:types":"tsc -p tsconfig.json --emitDeclarationOnly --declarationDir dist/types --watch","emulator:stop":"npx kill-port -y 4089 8089 9089","test:emulator":"bash test/scripts/test-with-emulator.sh","emulator:start":"cd test/emulator && firebase emulators:start -P demo-test-project","setup:local:env":"cp .env.local.example .env && echo 'Created .env file from local example.'"},"_npmUser":{"name":"au5ton","email":"austinjckson@gmail.com"},"repository":{"url":"git+https://github.com/cougargrades/firebase-rest-firestore.git","type":"git"},"_npmVersion":"11.4.2","description":"Firebase Firestore REST API client for Edge runtime environments","directories":{},"_nodeVersion":"24.4.1","dependencies":{"jose":"^4.14.4","urlpattern-polyfill":"^10.1.0"},"_hasShrinkwrap":false,"devDependencies":{"dotenv":"^16.4.7","vitest":"^3.0.9","typescript":"^5.0.4","@types/node":"^18.16.0","concurrently":"^8.2.2","semantic-release":"^24.2.3","@semantic-release/git":"^10.0.1","@semantic-release/changelog":"^6.0.3"},"_npmOperationalInternal":{"tmp":"tmp/firebase-rest-firestore_1.6.0_1771556643849_0.34286262503506415","host":"s3://npm-registry-packages-npm-production"}},"1.6.1":{"name":"@cougargrades/firebase-rest-firestore","version":"1.6.1","description":"Firebase Firestore REST API client for Edge runtime environments","main":"dist/cjs/index.js","module":"dist/esm/index.js","types":"dist/types/index.d.ts","scripts":{"build":"npm run build:esm; npm run build:cjs; npm run build:types","build:esm":"tsc -p tsconfig.esm.json","build:cjs":"tsc -p tsconfig.cjs.json","build:types":"tsc -p tsconfig.json --emitDeclarationOnly --declarationDir dist/types","watch":"concurrently \"npm run watch:esm\" \"npm run watch:cjs\" \"npm run watch:types\"","watch:esm":"tsc -p tsconfig.esm.json --watch","watch:cjs":"tsc -p tsconfig.cjs.json --watch","watch:types":"tsc -p tsconfig.json --emitDeclarationOnly --declarationDir dist/types --watch","prepublishOnly":"npm run build","setup:local:env":"cp .env.local.example .env && echo 'Created .env file from local example.'","emulator:start":"cd test/emulator && firebase emulators:start -P demo-test-project","emulator:stop":"npx kill-port -y 4089 8089 9089","test":"vitest","test:emulator":"bash test/scripts/test-with-emulator.sh"},"keywords":["firebase","firestore","rest","api","edge","cloudflare","workers","vercel"],"author":"","license":"MIT","dependencies":{"jose":"^4.14.4","urlpattern-polyfill":"^10.1.0"},"devDependencies":{"@semantic-release/changelog":"^6.0.3","@semantic-release/git":"^10.0.1","@types/node":"^18.16.0","concurrently":"^8.2.2","dotenv":"^16.4.7","semantic-release":"^24.2.3","typescript":"^5.0.4","vitest":"^3.0.9"},"engines":{"node":">=20.8.1"},"repository":{"type":"git","url":"git+https://github.com/cougargrades/firebase-rest-firestore.git"},"bugs":{"url":"https://github.com/cougargrades/firebase-rest-firestore/issues"},"homepage":"https://github.com/cougargrades/firebase-rest-firestore#readme","_id":"@cougargrades/firebase-rest-firestore@1.6.1","gitHead":"c1212a01366a5455e4892e4592219da11084b64a","_nodeVersion":"24.4.1","_npmVersion":"11.4.2","dist":{"integrity":"sha512-qv22dLW/5CJ4t14CtpMxYLb4Sj/KvArcUhTzlaOoG/xqhBVXv8W15VD3hT/Ec1AMmvWKWRapZcqGBjwLZc8xoQ==","shasum":"877794ea8b39149be6ab48d0ea79b62a2357cfcf","tarball":"https://registry.npmjs.org/@cougargrades/firebase-rest-firestore/-/firebase-rest-firestore-1.6.1.tgz","fileCount":38,"unpackedSize":189652,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBP7FcBZGnhkQmI6B9iqtHg+kuoUf9CPTVmu+6ptatlyAiAyb0oEbP7H+N0PvhRlSk9wsGBearetqm5f9oHZ6i0s8g=="}]},"_npmUser":{"name":"au5ton","email":"austinjckson@gmail.com"},"directories":{},"maintainers":[{"name":"austinjckson","email":"adjackson6@uh.edu"},{"name":"au5ton","email":"austinjckson@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/firebase-rest-firestore_1.6.1_1771559063350_0.7926327455375692"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-20T03:04:03.732Z","modified":"2026-02-20T03:44:23.650Z","1.6.0":"2026-02-20T03:04:04.002Z","1.6.1":"2026-02-20T03:44:23.496Z"},"bugs":{"url":"https://github.com/cougargrades/firebase-rest-firestore/issues"},"license":"MIT","homepage":"https://github.com/cougargrades/firebase-rest-firestore#readme","keywords":["firebase","firestore","rest","api","edge","cloudflare","workers","vercel"],"repository":{"type":"git","url":"git+https://github.com/cougargrades/firebase-rest-firestore.git"},"description":"Firebase Firestore REST API client for Edge runtime environments","maintainers":[{"name":"austinjckson","email":"adjackson6@uh.edu"},{"name":"au5ton","email":"austinjckson@gmail.com"}],"readme":"\r\n![NPM Version](https://img.shields.io/npm/v/%40cougargrades%2Ffirebase-rest-firestore)\r\n\r\n# Firebase REST Firestore\r\n\r\n[日本語版はこちら(Japanese Version)](./README.ja.md)\r\n\r\nFirebase Firestore REST API client for Edge runtime environments like Cloudflare Workers and Vercel Edge Functions.\r\n\r\n## Features\r\n\r\n- Works in Edge runtime environments where Firebase Admin SDK is not available\r\n- Full CRUD operations support\r\n- TypeScript support\r\n- Token caching for better performance\r\n- Simple and intuitive API\r\n- Explicit configuration without hidden environment variable dependencies\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install firebase-rest-firestore\r\n```\r\n\r\n## Quick Start\r\n\r\n```typescript\r\nimport { createFirestoreClient } from \"firebase-rest-firestore\";\r\n\r\n// Create a client with your configuration\r\nconst firestore = createFirestoreClient({\r\n  projectId: \"your-project-id\",\r\n  privateKey: \"your-private-key\",\r\n  clientEmail: \"your-client-email\",\r\n});\r\n\r\n// Add a document\r\nconst newDoc = await firestore.add(\"collection\", {\r\n  name: \"Test Document\",\r\n  value: 100,\r\n});\r\n\r\n// Get a document\r\nconst doc = await firestore.get(\"collection\", newDoc.id);\r\n\r\n// Update a document\r\nawait firestore.update(\"collection\", newDoc.id, { value: 200 });\r\n\r\n// Query documents\r\nconst querySnapshot = await firestore\r\n  .collection(\"games\")\r\n  .where(\"score\", \">\", 50)\r\n  .where(\"active\", \"==\", true)\r\n  .orderBy(\"score\", \"desc\")\r\n  .limit(10)\r\n  .get();\r\n\r\n// Process query results\r\nconst games = [];\r\nquerySnapshot.forEach(doc => {\r\n  games.push({\r\n    id: doc.id,\r\n    ...doc.data(),\r\n  });\r\n});\r\nconsole.log(\"Games with score > 50:\", games);\r\n\r\n// Delete a document\r\nawait firestore.delete(\"collection\", newDoc.id);\r\n```\r\n\r\n## Configuration\r\n\r\nThe `FirestoreConfig` object requires the following properties:\r\n\r\n| Property    | Description                  |\r\n| ----------- | ---------------------------- |\r\n| projectId   | Firebase project ID          |\r\n| privateKey  | Service account private key  |\r\n| clientEmail | Service account client email |\r\n\r\n## API Reference\r\n\r\n### FirestoreClient\r\n\r\nThe main class for interacting with Firestore.\r\n\r\n#### collection(collectionPath).add(data)\r\n\r\nCreates a new document with an auto-generated ID in the specified collection.\r\n\r\nParameters:\r\n\r\n- `data`: Document data to be added\r\n\r\nReturns: A reference to the created document.\r\n\r\n#### collection(collectionPath).doc(id?).set(data)\r\n\r\nCreates or overwrites a document with the specified ID. If no ID is provided, one will be auto-generated.\r\n\r\nParameters:\r\n\r\n- `id` (optional): Document ID\r\n- `data`: Document data\r\n\r\nReturns: A promise that resolves when the set operation is complete.\r\n\r\n#### get(collectionName, documentId)\r\n\r\nRetrieves a document by ID.\r\n\r\n#### update(collectionName, documentId, data)\r\n\r\nUpdates an existing document.\r\n\r\n#### delete(collectionName, documentId)\r\n\r\nDeletes a document.\r\n\r\n#### query(collectionName, options)\r\n\r\nQueries documents in a collection with filtering, ordering, and pagination.\r\n\r\n### createFirestoreClient(config)\r\n\r\nCreates a new FirestoreClient instance with the provided configuration.\r\n\r\n#### add(collectionName, data)\r\n\r\nAdds a new document to the specified collection.\r\n\r\nParameters:\r\n\r\n- `collectionName`: Name of the collection\r\n- `data`: Document data to be added\r\n\r\nReturns: The added document with auto-generated ID.\r\n\r\n## Error Handling\r\n\r\nFirebase REST Firestore throws exceptions with appropriate error messages when API requests fail. Here's an example of error handling:\r\n\r\n```typescript\r\ntry {\r\n  // Try to get a document\r\n  const game = await firestore.get(\"games\", \"non-existent-id\");\r\n\r\n  // If document doesn't exist, null is returned\r\n  if (game === null) {\r\n    console.log(\"Document not found\");\r\n    return;\r\n  }\r\n\r\n  // Process document if it exists\r\n  console.log(\"Fetched game:\", game);\r\n} catch (error) {\r\n  // Handle API errors (authentication, network, etc.)\r\n  console.error(\"Firestore error:\", error.message);\r\n}\r\n```\r\n\r\nCommon error cases:\r\n\r\n- Authentication errors (invalid credentials)\r\n- Network errors\r\n- Invalid query parameters\r\n- Firestore rate limits\r\n\r\n## Query Options Details\r\n\r\nThe `query` method supports the following options for filtering, sorting, and paginating Firestore documents:\r\n\r\n### where\r\n\r\nSpecify multiple filter conditions. Each condition is an object with the following properties:\r\n\r\n- `field`: The field name to filter on\r\n- `op`: The comparison operator. Available values:\r\n  - `EQUAL`: Equal to\r\n  - `NOT_EQUAL`: Not equal to\r\n  - `LESS_THAN`: Less than\r\n  - `LESS_THAN_OR_EQUAL`: Less than or equal to\r\n  - `GREATER_THAN`: Greater than\r\n  - `GREATER_THAN_OR_EQUAL`: Greater than or equal to\r\n  - `ARRAY_CONTAINS`: Array contains\r\n  - `IN`: Equal to any of the specified values\r\n  - `ARRAY_CONTAINS_ANY`: Array contains any of the specified values\r\n  - `NOT_IN`: Not equal to any of the specified values\r\n- `value`: The value to compare against\r\n\r\n```typescript\r\n// Query games with score > 50 and active = true\r\nconst games = await firestore.query(\"games\", {\r\n  where: [\r\n    { field: \"score\", op: \"GREATER_THAN\", value: 50 },\r\n    { field: \"active\", op: \"EQUAL\", value: true },\r\n  ],\r\n});\r\n```\r\n\r\n### orderBy\r\n\r\nSpecifies the field name to sort results by. Results are sorted in ascending order by default.\r\n\r\n```typescript\r\n// Sort by creation time\r\nconst games = await firestore.query(\"games\", {\r\n  orderBy: \"createdAt\",\r\n});\r\n```\r\n\r\n### limit\r\n\r\nLimits the maximum number of results returned.\r\n\r\n```typescript\r\n// Get at most 10 documents\r\nconst games = await firestore.query(\"games\", {\r\n  limit: 10,\r\n});\r\n```\r\n\r\n### offset\r\n\r\nSpecifies the number of results to skip. Useful for pagination.\r\n\r\n```typescript\r\n// Skip the first 20 results and get the next 10\r\nconst games = await firestore.query(\"games\", {\r\n  offset: 20,\r\n  limit: 10,\r\n});\r\n```\r\n\r\nExample of a compound query:\r\n\r\n```typescript\r\n// Get top 10 active games by score\r\nconst topGames = await firestore.query(\"games\", {\r\n  where: [{ field: \"active\", op: \"EQUAL\", value: true }],\r\n  orderBy: \"score\", // Sort by score\r\n  limit: 10,\r\n});\r\n```\r\n\r\n## Edge Runtime Examples\r\n\r\n### Cloudflare Workers\r\n\r\n```typescript\r\n// Set these environment variables in wrangler.toml\r\n// FIREBASE_PROJECT_ID\r\n// FIREBASE_PRIVATE_KEY\r\n// FIREBASE_CLIENT_EMAIL\r\n\r\nimport { createFirestoreClient } from \"firebase-rest-firestore\";\r\n\r\nexport default {\r\n  async fetch(request, env, ctx) {\r\n    // Load configuration from environment variables\r\n    const firestore = createFirestoreClient({\r\n      projectId: env.FIREBASE_PROJECT_ID,\r\n      privateKey: env.FIREBASE_PRIVATE_KEY.replace(/\\\\n/g, \"\\n\"),\r\n      clientEmail: env.FIREBASE_CLIENT_EMAIL,\r\n    });\r\n\r\n    const url = new URL(request.url);\r\n    const path = url.pathname;\r\n\r\n    // Example API endpoint\r\n    if (path === \"/api/games\" && request.method === \"GET\") {\r\n      try {\r\n        // Get active games\r\n        const games = await firestore.query(\"games\", {\r\n          where: [{ field: \"active\", op: \"EQUAL\", value: true }],\r\n          limit: 10,\r\n        });\r\n\r\n        return new Response(JSON.stringify(games), {\r\n          headers: { \"Content-Type\": \"application/json\" },\r\n        });\r\n      } catch (error) {\r\n        return new Response(JSON.stringify({ error: error.message }), {\r\n          status: 500,\r\n          headers: { \"Content-Type\": \"application/json\" },\r\n        });\r\n      }\r\n    }\r\n\r\n    return new Response(\"Not found\", { status: 404 });\r\n  },\r\n};\r\n```\r\n\r\n### Vercel Edge Functions\r\n\r\n```typescript\r\n// Set these environment variables in .env.local\r\n// FIREBASE_PROJECT_ID\r\n// FIREBASE_PRIVATE_KEY\r\n// FIREBASE_CLIENT_EMAIL\r\n\r\nimport { createFirestoreClient } from \"firebase-rest-firestore\";\r\n\r\nexport const config = {\r\n  runtime: \"edge\",\r\n};\r\n\r\nexport default async function handler(request) {\r\n  // Load configuration from environment variables\r\n  const firestore = createFirestoreClient({\r\n    projectId: process.env.FIREBASE_PROJECT_ID,\r\n    privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\\\n/g, \"\\n\"),\r\n    clientEmail: process.env.FIREBASE_CLIENT_EMAIL,\r\n  });\r\n\r\n  try {\r\n    // Get the latest 10 documents\r\n    const documents = await firestore.query(\"posts\", {\r\n      orderBy: \"createdAt\",\r\n      limit: 10,\r\n    });\r\n\r\n    return new Response(JSON.stringify(documents), {\r\n      headers: { \"Content-Type\": \"application/json\" },\r\n    });\r\n  } catch (error) {\r\n    return new Response(JSON.stringify({ error: error.message }), {\r\n      status: 500,\r\n      headers: { \"Content-Type\": \"application/json\" },\r\n    });\r\n  }\r\n}\r\n```\r\n\r\n## Performance Considerations\r\n\r\n### Token Caching\r\n\r\nFirebase REST Firestore caches JWT tokens to improve performance. By default, tokens are cached for 50 minutes (actual token expiry is 1 hour). This eliminates the need to generate a new token for each request, improving API request speed.\r\n\r\n```typescript\r\n// Tokens are cached internally, so multiple requests\r\n// have minimal authentication overhead\r\nconst doc1 = await firestore.get(\"collection\", \"doc1\");\r\nconst doc2 = await firestore.get(\"collection\", \"doc2\");\r\nconst doc3 = await firestore.get(\"collection\", \"doc3\");\r\n```\r\n\r\n### Query Optimization\r\n\r\nWhen dealing with large amounts of data, consider the following:\r\n\r\n1. **Set appropriate limits**: Always use the `limit` parameter to restrict the number of documents returned.\r\n\r\n2. **Query only needed fields**: Future versions will add support for retrieving only specific fields.\r\n\r\n3. **Create indexes**: For complex queries, create appropriate indexes in the Firebase console.\r\n\r\n4. **Use pagination**: When retrieving large datasets, implement pagination using `offset` and `limit`.\r\n\r\n### Edge Environment Considerations\r\n\r\nIn edge environments, be aware of:\r\n\r\n1. **Cold starts**: Initial execution has token generation overhead.\r\n\r\n2. **Memory usage**: Be mindful of memory limits when processing large amounts of data.\r\n\r\n3. **Timeouts**: Long-running queries may hit edge environment timeout limits.\r\n\r\n## Limitations and Roadmap\r\n\r\n### Current Limitations\r\n\r\n- **Batch operations**: The current version does not support batch processing for operating on multiple documents at once.\r\n- **Transactions**: Atomic transaction operations are not supported.\r\n- **Real-time listeners**: Due to the nature of REST APIs, real-time data synchronization is not supported.\r\n- **Subcollections**: The current version has limited direct support for nested subcollections.\r\n\r\n### Future Roadmap\r\n\r\nThe following features are planned for future versions:\r\n\r\n- Batch operations support\r\n- Basic transaction support\r\n- Improved subcollection support\r\n- More detailed query options (compound indexes, etc.)\r\n- Performance optimizations\r\n\r\nPlease report feature requests and bugs via GitHub Issues.\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md"}