@neocleus/razorpay-firebase-functions 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.
Files changed (62) hide show
  1. package/README.md +165 -0
  2. package/lib/admin.d.ts +8 -0
  3. package/lib/admin.js +155 -0
  4. package/lib/admin.js.map +1 -0
  5. package/lib/api.d.ts +4 -0
  6. package/lib/api.js +203 -0
  7. package/lib/api.js.map +1 -0
  8. package/lib/callables/subscriptions.d.ts +9 -0
  9. package/lib/callables/subscriptions.js +138 -0
  10. package/lib/callables/subscriptions.js.map +1 -0
  11. package/lib/handlers/payments.d.ts +4 -0
  12. package/lib/handlers/payments.js +135 -0
  13. package/lib/handlers/payments.js.map +1 -0
  14. package/lib/handlers/subscriptions.d.ts +4 -0
  15. package/lib/handlers/subscriptions.js +87 -0
  16. package/lib/handlers/subscriptions.js.map +1 -0
  17. package/lib/index.d.ts +29 -0
  18. package/lib/index.js +88 -0
  19. package/lib/index.js.map +1 -0
  20. package/lib/logs.d.ts +10 -0
  21. package/lib/logs.js +36 -0
  22. package/lib/logs.js.map +1 -0
  23. package/lib/security.d.ts +1 -0
  24. package/lib/security.js +14 -0
  25. package/lib/security.js.map +1 -0
  26. package/lib/triggers/createCustomer.d.ts +4 -0
  27. package/lib/triggers/createCustomer.js +79 -0
  28. package/lib/triggers/createCustomer.js.map +1 -0
  29. package/lib/triggers/createOrder.d.ts +6 -0
  30. package/lib/triggers/createOrder.js +173 -0
  31. package/lib/triggers/createOrder.js.map +1 -0
  32. package/lib/triggers/createSubscription.d.ts +6 -0
  33. package/lib/triggers/createSubscription.js +211 -0
  34. package/lib/triggers/createSubscription.js.map +1 -0
  35. package/lib/triggers/onUserDeleted.d.ts +5 -0
  36. package/lib/triggers/onUserDeleted.js +118 -0
  37. package/lib/triggers/onUserDeleted.js.map +1 -0
  38. package/lib/triggers/syncClaims.d.ts +5 -0
  39. package/lib/triggers/syncClaims.js +92 -0
  40. package/lib/triggers/syncClaims.js.map +1 -0
  41. package/lib/types.d.ts +43 -0
  42. package/lib/types.js +3 -0
  43. package/lib/types.js.map +1 -0
  44. package/lib/utils/customerMapping.d.ts +9 -0
  45. package/lib/utils/customerMapping.js +68 -0
  46. package/lib/utils/customerMapping.js.map +1 -0
  47. package/lib/utils/ensureCustomer.d.ts +10 -0
  48. package/lib/utils/ensureCustomer.js +78 -0
  49. package/lib/utils/ensureCustomer.js.map +1 -0
  50. package/lib/utils/index.d.ts +15 -0
  51. package/lib/utils/index.js +75 -0
  52. package/lib/utils/index.js.map +1 -0
  53. package/lib/utils/processingLock.d.ts +12 -0
  54. package/lib/utils/processingLock.js +78 -0
  55. package/lib/utils/processingLock.js.map +1 -0
  56. package/lib/utils/retry.d.ts +9 -0
  57. package/lib/utils/retry.js +53 -0
  58. package/lib/utils/retry.js.map +1 -0
  59. package/lib/utils/typedFirestore.d.ts +25 -0
  60. package/lib/utils/typedFirestore.js +77 -0
  61. package/lib/utils/typedFirestore.js.map +1 -0
  62. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @neocleus/razorpay-firebase-functions
2
+
3
+ Consumable Firebase Cloud Functions for **Razorpay** payments and subscriptions integration using the Factory pattern.
4
+
5
+ This package provides the core server-side integration triggers and callable handlers for the **Run Payments with Razorpay** Firebase Extension. It can be initialized directly inside your own custom Cloud Functions codebase.
6
+
7
+ ---
8
+
9
+ ## 📥 Installation
10
+
11
+ Install the package in your Firebase Cloud Functions directory:
12
+
13
+ ```bash
14
+ npm install @neocleus/razorpay-firebase-functions
15
+ ```
16
+
17
+ ---
18
+
19
+ ## ⚙️ Quick Start & Initialization
20
+
21
+ Import `initializeRazorpay` and call it with your API credentials to export all triggers, callable functions, and webhook handlers.
22
+
23
+ ### `src/index.ts`
24
+ ```typescript
25
+ import * as admin from 'firebase-admin';
26
+ import { initializeRazorpay } from '@neocleus/razorpay-firebase-functions';
27
+
28
+ // 1. Initialize the Firebase Admin SDK
29
+ admin.initializeApp();
30
+
31
+ // 2. Configure and initialize Razorpay functions
32
+ const rzpFuncs = initializeRazorpay({
33
+ keyId: process.env.RAZORPAY_KEY_ID || '',
34
+ keySecret: process.env.RAZORPAY_KEY_SECRET || '',
35
+ webhookSecret: process.env.RAZORPAY_WEBHOOK_SECRET || '',
36
+ customersCollection: 'customers', // Optional, defaults to 'customers'
37
+ productsCollection: 'products', // Optional, defaults to 'products'
38
+ syncCustomers: true, // Optional, defaults to true
39
+ });
40
+
41
+ // 3. Export functions as flat deployable Cloud Functions
42
+ export const createOrder = rzpFuncs.createOrder;
43
+ export const createSubscription = rzpFuncs.createSubscription;
44
+ export const createCustomer = rzpFuncs.createCustomer;
45
+ export const onUserDeleted = rzpFuncs.onUserDeleted;
46
+ export const onCustomerDataDeleted = rzpFuncs.onCustomerDataDeleted;
47
+ export const webhookHandler = rzpFuncs.webhookHandler;
48
+ export const cancelSubscription = rzpFuncs.cancelSubscription;
49
+ export const updateSubscriptionPlan = rzpFuncs.updateSubscriptionPlan;
50
+ export const createPlan = rzpFuncs.createPlan;
51
+ export const syncPlans = rzpFuncs.syncPlans;
52
+ ```
53
+
54
+ ---
55
+
56
+ ## 🛡️ Robust Initialization Guard
57
+
58
+ To prevent silent deployment configuration errors, `initializeRazorpay` validates your keys during initialization.
59
+
60
+ If any required credential is missing (`keyId`, `keySecret`, or `webhookSecret`) or if the `keyId` does not start with the mandatory `rzp_` prefix, **the function immediately throws a runtime Error**. This prevents your Cloud Functions from deploying in a misconfigured state.
61
+
62
+ ---
63
+
64
+ ## 🛠️ Exported Functions Reference
65
+
66
+ 1. **Firestore Lifecycle Triggers**:
67
+ * `createOrder`: Watches `customers/{uid}/checkout_sessions/{id}` to securely generate orders on Razorpay's API with transaction locks and duplicate safeguards.
68
+ * `createSubscription`: Watches `customers/{uid}/subscriptions/{id}` to register subscription sessions on Razorpay's API.
69
+ 2. **Auth Triggers**:
70
+ * `createCustomer`: Listens to `auth.user().onCreate` to lazily sync users into Razorpay.
71
+ * `onUserDeleted` / `onCustomerDataDeleted`: Cleans up documents and references.
72
+ 3. **HTTPS Webhook Handler**:
73
+ * `webhookHandler`: Deploys as an HTTPS endpoint to listen to Razorpay webhook events. Hardened with HMAC signature checks, deterministic event-ID deduplication, and stuck-event processing recovery.
74
+ 4. **Client Callables**:
75
+ * `cancelSubscription`: Handles secure cancellation requests.
76
+ * `updateSubscriptionPlan`: Handles secure plan upgrades/downgrades, validating target `planId` against the products catalog collection.
77
+ 5. **Admin Callables**:
78
+ * `createPlan` / `syncPlans`: Enabled for users with custom claims (`admin: true`) to batch-sync catalogs from Razorpay using high-performance Firestore write batching.
79
+
80
+ ---
81
+
82
+ ## 🔒 Security Guidelines
83
+
84
+ * **Production Credentials**: Never commit plaintext API keys to Git. Configure these variables inside Google Cloud Secret Manager and load them dynamically in production.
85
+ * **Git Ignore Rules**: Add `.env` and `*.secret.local` to your ignore list:
86
+ ```
87
+ **/functions/.env
88
+ **/*.secret.local
89
+ ```
90
+
91
+ ### 📄 Required Firestore Security Rules
92
+
93
+ To enforce catalog-driven pricing, protect payment states, and prevent metadata spoofing, you must apply the following security rules in your `firestore.rules` file:
94
+
95
+ ```javascript
96
+ rules_version = '2';
97
+ service cloud.firestore {
98
+ match /databases/{database}/documents {
99
+
100
+ // ── Products / Plans Catalog ──
101
+ match /products/{productId} {
102
+ allow read: if true;
103
+ allow write: if false;
104
+ }
105
+
106
+ // ── Customer Documents ──
107
+ match /customers/{uid} {
108
+ allow read: if request.auth.uid == uid;
109
+ allow write: if false;
110
+
111
+ // ── Checkout Sessions (One-time Orders) ──
112
+ match /checkout_sessions/{id} {
113
+ allow read: if request.auth.uid == uid;
114
+ allow create: if request.auth.uid == uid
115
+ && request.resource.data.keys().hasOnly(['productId', 'metadata'])
116
+ && request.resource.data.productId is string
117
+ && request.resource.data.productId.size() <= 256
118
+ && (!('metadata' in request.resource.data) || request.resource.data.metadata is map)
119
+ && request.resource.data.keys().size() <= 5;
120
+
121
+ allow update, delete: if false;
122
+
123
+ match /razorpay_responses/{docId} {
124
+ allow read: if request.auth.uid == uid;
125
+ allow write: if false;
126
+ }
127
+ }
128
+
129
+ // ── Subscriptions ──
130
+ match /subscriptions/{id} {
131
+ allow read: if request.auth.uid == uid;
132
+ allow create: if request.auth.uid == uid
133
+ && request.resource.data.keys().hasOnly(['productId', 'interval', 'metadata', 'draftId'])
134
+ && request.resource.data.productId is string
135
+ && request.resource.data.productId.size() <= 256
136
+ && request.resource.data.interval is string
137
+ && request.resource.data.interval.size() <= 64
138
+ && (!('metadata' in request.resource.data) || request.resource.data.metadata is map)
139
+ && (!('draftId' in request.resource.data) || request.resource.data.draftId is string)
140
+ && request.resource.data.keys().size() <= 5;
141
+
142
+ allow update, delete: if false;
143
+
144
+ match /payments/{paymentId} {
145
+ allow read: if request.auth.uid == uid;
146
+ allow write: if false;
147
+ }
148
+
149
+ match /razorpay_responses/{docId} {
150
+ allow read: if request.auth.uid == uid;
151
+ allow write: if false;
152
+ }
153
+ }
154
+ }
155
+
156
+ // ── Webhook Events (Backend/Extension Only) ──
157
+ match /webhook_events/{eventId} {
158
+ allow read, write: if false;
159
+ }
160
+
161
+ // ── Deny everything else by default ──
162
+ // No wildcard match — unlisted paths are denied
163
+ }
164
+ }
165
+ ```
package/lib/admin.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import Razorpay from 'razorpay';
2
+ import { RazorpaySyncConfig, ProductDoc } from './types';
3
+ export declare const buildCreatePlan: (config: RazorpaySyncConfig, rzp: Razorpay) => import("firebase-functions/v2/https").CallableFunction<any, Promise<ProductDoc>>;
4
+ export declare const buildSyncPlans: (config: RazorpaySyncConfig, rzp: Razorpay) => import("firebase-functions/v2/https").CallableFunction<any, Promise<{
5
+ status: string;
6
+ count: number;
7
+ productsCount: number;
8
+ }>>;
package/lib/admin.js ADDED
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildSyncPlans = exports.buildCreatePlan = void 0;
37
+ const https_1 = require("firebase-functions/v2/https");
38
+ const admin = __importStar(require("firebase-admin"));
39
+ const firestore_1 = require("firebase-admin/firestore");
40
+ const logs_1 = require("./logs");
41
+ const utils_1 = require("./utils");
42
+ const typedFirestore_1 = require("./utils/typedFirestore");
43
+ const buildCreatePlan = (config, rzp) => {
44
+ return (0, https_1.onCall)(async (request) => {
45
+ if (!request.auth || request.auth.token.admin !== true) {
46
+ throw new https_1.HttpsError('permission-denied', 'Must be an administrative user to initiate plan creation.');
47
+ }
48
+ const { period, interval, item, notes } = request.data;
49
+ if (!period || !interval || !item || !item.name || !item.amount) {
50
+ throw new https_1.HttpsError('invalid-argument', 'Missing required fields: period, interval, item details.');
51
+ }
52
+ try {
53
+ const plan = await rzp.plans.create({
54
+ period,
55
+ interval,
56
+ item,
57
+ notes
58
+ });
59
+ const db = admin.firestore();
60
+ const productData = await (0, utils_1.syncPlanToProduct)(plan, db, config);
61
+ logs_1.logs.info(`Admin created plan: ${plan.id} and synced to product: ${productData.id}`);
62
+ return productData;
63
+ }
64
+ catch (err) {
65
+ logs_1.logs.error(err);
66
+ throw new https_1.HttpsError('internal', 'Failed to create plan.', err.message);
67
+ }
68
+ });
69
+ };
70
+ exports.buildCreatePlan = buildCreatePlan;
71
+ const buildSyncPlans = (config, rzp) => {
72
+ return (0, https_1.onCall)(async (request) => {
73
+ if (!request.auth || request.auth.token.admin !== true) {
74
+ throw new https_1.HttpsError('permission-denied', 'Must be an administrative user to initiate plan sync.');
75
+ }
76
+ try {
77
+ const db = admin.firestore();
78
+ const typedFs = new typedFirestore_1.TypedFirestore(db, config);
79
+ logs_1.logs.info('Starting administrative plan synchronization from Razorpay...');
80
+ let skip = 0;
81
+ const count = 100;
82
+ let hasMore = true;
83
+ const allPlans = [];
84
+ const MAX_PLANS = 10000;
85
+ while (hasMore && allPlans.length < MAX_PLANS) {
86
+ logs_1.logs.info(`Fetching plans from Razorpay (skip: ${skip}, limit: ${count})...`);
87
+ const plans = await rzp.plans.all({ skip, count });
88
+ if (!plans.items || plans.items.length === 0) {
89
+ break;
90
+ }
91
+ allPlans.push(...plans.items);
92
+ skip += count;
93
+ if (plans.items.length < count) {
94
+ hasMore = false;
95
+ }
96
+ }
97
+ logs_1.logs.info(`Fetched ${allPlans.length} plans. Grouping by product ID in memory...`);
98
+ // Group plans by productId in memory
99
+ const productPlansMap = new Map();
100
+ for (const plan of allPlans) {
101
+ const productId = (0, utils_1.generateProductId)(plan);
102
+ if (!productPlansMap.has(productId)) {
103
+ productPlansMap.set(productId, []);
104
+ }
105
+ productPlansMap.get(productId).push(plan);
106
+ }
107
+ logs_1.logs.info(`Identified ${productPlansMap.size} distinct products. Reading existing products collection...`);
108
+ // Read all existing products to avoid per-document lookups
109
+ const productsCollection = typedFs.getProductsCollection();
110
+ const existingProductsSnap = await productsCollection.get();
111
+ const existingProducts = new Map();
112
+ for (const doc of existingProductsSnap.docs) {
113
+ existingProducts.set(doc.id, doc.data());
114
+ }
115
+ logs_1.logs.info('Writing synchronized product catalogs to Firestore via BulkWriter...');
116
+ const bulkWriter = db.bulkWriter();
117
+ bulkWriter.onWriteError((error) => {
118
+ logs_1.logs.error(new Error(`BulkWriter error: ${error.message}`));
119
+ return false; // Do not retry
120
+ });
121
+ for (const [productId, plans] of productPlansMap.entries()) {
122
+ const productDocRef = typedFs.getProductDoc(productId);
123
+ const existingProduct = existingProducts.get(productId);
124
+ const productData = existingProduct || {
125
+ id: productId,
126
+ name: plans[0].item?.name || 'Razorpay Product',
127
+ description: plans[0].item?.description || '',
128
+ active: true,
129
+ allowedPlans: {},
130
+ created_at: firestore_1.FieldValue.serverTimestamp(),
131
+ };
132
+ productData.allowedPlans = productData.allowedPlans || {};
133
+ productData.plans = productData.plans || {};
134
+ for (const plan of plans) {
135
+ const planKey = (0, utils_1.generatePlanKey)(plan);
136
+ productData.allowedPlans[planKey] = plan.id;
137
+ productData.plans[planKey] = (0, utils_1.sanitizePlan)(plan);
138
+ }
139
+ productData.type = 'subscription';
140
+ productData.updated_at = firestore_1.FieldValue.serverTimestamp();
141
+ productData._synced_via = 'admin_api';
142
+ bulkWriter.set(productDocRef, productData, { merge: true });
143
+ }
144
+ await bulkWriter.close();
145
+ logs_1.logs.info(`Admin synced ${allPlans.length} plans successfully across ${productPlansMap.size} products.`);
146
+ return { status: 'SUCCESS', count: allPlans.length, productsCount: productPlansMap.size };
147
+ }
148
+ catch (err) {
149
+ logs_1.logs.error(err);
150
+ throw new https_1.HttpsError('internal', 'Sync failed.', err.message);
151
+ }
152
+ });
153
+ };
154
+ exports.buildSyncPlans = buildSyncPlans;
155
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"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"}
package/lib/api.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import Razorpay from 'razorpay';
2
+ import { Channel } from 'firebase-admin/eventarc';
3
+ import { RazorpaySyncConfig } from './types';
4
+ export declare const buildWebhookHandler: (config: RazorpaySyncConfig, rzp: Razorpay, eventChannel: Channel | null) => import("firebase-functions/v2/https").HttpsFunction;
package/lib/api.js ADDED
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildWebhookHandler = void 0;
37
+ const https_1 = require("firebase-functions/v2/https");
38
+ const crypto = __importStar(require("crypto"));
39
+ const admin = __importStar(require("firebase-admin"));
40
+ const firestore_1 = require("firebase-admin/firestore");
41
+ const security_1 = require("./security");
42
+ const logs_1 = require("./logs");
43
+ const subscriptions_1 = require("./handlers/subscriptions");
44
+ const payments_1 = require("./handlers/payments");
45
+ const retry_1 = require("./utils/retry");
46
+ const typedFirestore_1 = require("./utils/typedFirestore");
47
+ const ALLOWED_EVENTS = new Set([
48
+ "payment.authorized",
49
+ "payment.failed",
50
+ "payment.captured",
51
+ "payment.dispute.created",
52
+ "order.paid",
53
+ "order.notification.delivered",
54
+ "order.notification.failed",
55
+ "subscription.authenticated",
56
+ "subscription.paused",
57
+ "subscription.resumed",
58
+ "subscription.activated",
59
+ "subscription.pending",
60
+ "subscription.halted",
61
+ "subscription.charged",
62
+ "subscription.cancelled",
63
+ "subscription.completed",
64
+ "subscription.updated",
65
+ "payment.dispute.won",
66
+ "payment.dispute.lost",
67
+ "payment.dispute.closed",
68
+ "payment.dispute.under_review",
69
+ "payment.dispute.action_required",
70
+ "payment.downtime.started",
71
+ "payment.downtime.updated",
72
+ "payment.downtime.resolved"
73
+ ]);
74
+ const buildWebhookHandler = (config, rzp, eventChannel) => {
75
+ const webhookHandlerFunc = async (req, res) => {
76
+ if (req.method !== 'POST') {
77
+ res.status(405).send('Method Not Allowed');
78
+ return;
79
+ }
80
+ const signature = req.headers['x-razorpay-signature'];
81
+ let rawBody = '';
82
+ if (typeof req.rawBody === 'string') {
83
+ rawBody = req.rawBody;
84
+ }
85
+ else if (Buffer.isBuffer(req.rawBody)) {
86
+ rawBody = req.rawBody.toString('utf8');
87
+ }
88
+ else {
89
+ logs_1.logs.error(new Error('req.rawBody is missing or not a Buffer/String. Ensure you are not parsing the body before this handler.'));
90
+ res.status(400).send('Invalid Body');
91
+ return;
92
+ }
93
+ if (!(0, security_1.verifyWebhookSignature)(rawBody, signature, config.webhookSecret)) {
94
+ logs_1.logs.invalidSignature();
95
+ res.status(401).json({
96
+ error: 'Unauthorized',
97
+ });
98
+ return;
99
+ }
100
+ const event = req.body;
101
+ logs_1.logs.startWebhook(event.event);
102
+ if (!ALLOWED_EVENTS.has(event.event)) {
103
+ res.status(200).send('Event not handled');
104
+ return;
105
+ }
106
+ const eventId = event.id ||
107
+ req.headers['x-razorpay-event-id'] ||
108
+ `evt_${crypto.createHash('sha256').update(rawBody).digest('hex')}`;
109
+ const db = admin.firestore();
110
+ const typedFs = new typedFirestore_1.TypedFirestore(db, config);
111
+ const webhookEventRef = typedFs.getWebhookEventDoc(eventId);
112
+ try {
113
+ const expireAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days from now
114
+ await webhookEventRef.create({
115
+ event: event.event,
116
+ status: 'processing',
117
+ created_at: firestore_1.FieldValue.serverTimestamp(),
118
+ updated_at: firestore_1.FieldValue.serverTimestamp(),
119
+ expireAt,
120
+ });
121
+ }
122
+ catch (e) {
123
+ if (e.code === 6 || e.code === 'already-exists') {
124
+ const canRetry = await db.runTransaction(async (tx) => {
125
+ const doc = await tx.get(webhookEventRef);
126
+ if (!doc.exists)
127
+ return true;
128
+ const data = doc.data();
129
+ const updatedAt = data?.updated_at;
130
+ const isTimestamp = updatedAt instanceof admin.firestore.Timestamp;
131
+ const isStuck = data?.status === 'processing' &&
132
+ updatedAt &&
133
+ isTimestamp &&
134
+ (Date.now() - updatedAt.toMillis() > 2 * 60 * 1000); // 2 mins
135
+ if (data?.status === 'failed' || isStuck) {
136
+ tx.update(webhookEventRef, {
137
+ status: 'processing',
138
+ updated_at: firestore_1.FieldValue.serverTimestamp(),
139
+ });
140
+ return true;
141
+ }
142
+ return false;
143
+ });
144
+ if (!canRetry) {
145
+ logs_1.logs.info(`Webhook event ${eventId} already processed or in-flight. Skipping.`);
146
+ res.status(200).send('Already Processed');
147
+ return;
148
+ }
149
+ }
150
+ else {
151
+ logs_1.logs.error(e);
152
+ res.status(500).send('Webhook processing failed internally');
153
+ return;
154
+ }
155
+ }
156
+ try {
157
+ if (event.event.startsWith('subscription.')) {
158
+ await (0, subscriptions_1.handleSubscriptionEvent)(event, db, rzp, config);
159
+ }
160
+ else if (event.event.startsWith('payment.') || event.event.startsWith('order.')) {
161
+ await (0, payments_1.handlePaymentEvent)(event, db, rzp, config);
162
+ }
163
+ if (eventChannel) {
164
+ await eventChannel.publish({
165
+ type: `com.razorpay.v1.${event.event}`,
166
+ data: event.payload,
167
+ });
168
+ }
169
+ await webhookEventRef.update({
170
+ status: 'completed',
171
+ completed_at: firestore_1.FieldValue.serverTimestamp(),
172
+ }).catch((err) => {
173
+ logs_1.logs.error(`Failed to update webhook event status to completed (ID: ${eventId})`, err);
174
+ });
175
+ res.status(200).send('Webhook Processed');
176
+ }
177
+ catch (err) {
178
+ logs_1.logs.error(`Webhook processing failed for event: ${event.event} (ID: ${eventId})`, err);
179
+ const isRetryable = (0, retry_1.isTransientError)(err);
180
+ if (isRetryable) {
181
+ await webhookEventRef.update({ status: 'failed', updated_at: firestore_1.FieldValue.serverTimestamp() }).catch((err) => {
182
+ logs_1.logs.error(`Failed to update webhook event status to failed (ID: ${eventId})`, err);
183
+ });
184
+ res.status(500).send('Webhook processing failed internally - retryable');
185
+ }
186
+ else {
187
+ logs_1.logs.error(`PERMANENT WEBHOOK FAILURE — event ${event.event} (ID: ${eventId}) will NOT be retried. Manual investigation required.`);
188
+ await webhookEventRef.update({ status: 'permanently_failed', completed_at: firestore_1.FieldValue.serverTimestamp() }).catch((err) => {
189
+ logs_1.logs.error(`Failed to update webhook event status to permanently_failed (ID: ${eventId})`, err);
190
+ });
191
+ res.status(200).send('Webhook processing failed permanently');
192
+ }
193
+ }
194
+ };
195
+ return (0, https_1.onRequest)({
196
+ timeoutSeconds: 120,
197
+ memory: '512MiB',
198
+ maxInstances: 100,
199
+ minInstances: 0,
200
+ }, webhookHandlerFunc);
201
+ };
202
+ exports.buildWebhookHandler = buildWebhookHandler;
203
+ //# sourceMappingURL=api.js.map
package/lib/api.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import Razorpay from 'razorpay';
2
+ import { RazorpaySyncConfig } from '../types';
3
+ export declare const buildCancelSubscription: (config: RazorpaySyncConfig, rzp: Razorpay) => import("firebase-functions/v2/https").CallableFunction<any, Promise<{
4
+ status: "cancelled" | "active" | "pending" | "created" | "expired" | "authenticated" | "halted" | "completed";
5
+ }>>;
6
+ export declare const buildUpdateSubscriptionPlan: (config: RazorpaySyncConfig, rzp: Razorpay) => import("firebase-functions/v2/https").CallableFunction<any, Promise<{
7
+ plan_id: string;
8
+ status: "cancelled" | "active" | "pending" | "created" | "expired" | "authenticated" | "halted" | "completed";
9
+ }>>;