@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.
- package/README.md +165 -0
- package/lib/admin.d.ts +8 -0
- package/lib/admin.js +155 -0
- package/lib/admin.js.map +1 -0
- package/lib/api.d.ts +4 -0
- package/lib/api.js +203 -0
- package/lib/api.js.map +1 -0
- package/lib/callables/subscriptions.d.ts +9 -0
- package/lib/callables/subscriptions.js +138 -0
- package/lib/callables/subscriptions.js.map +1 -0
- package/lib/handlers/payments.d.ts +4 -0
- package/lib/handlers/payments.js +135 -0
- package/lib/handlers/payments.js.map +1 -0
- package/lib/handlers/subscriptions.d.ts +4 -0
- package/lib/handlers/subscriptions.js +87 -0
- package/lib/handlers/subscriptions.js.map +1 -0
- package/lib/index.d.ts +29 -0
- package/lib/index.js +88 -0
- package/lib/index.js.map +1 -0
- package/lib/logs.d.ts +10 -0
- package/lib/logs.js +36 -0
- package/lib/logs.js.map +1 -0
- package/lib/security.d.ts +1 -0
- package/lib/security.js +14 -0
- package/lib/security.js.map +1 -0
- package/lib/triggers/createCustomer.d.ts +4 -0
- package/lib/triggers/createCustomer.js +79 -0
- package/lib/triggers/createCustomer.js.map +1 -0
- package/lib/triggers/createOrder.d.ts +6 -0
- package/lib/triggers/createOrder.js +173 -0
- package/lib/triggers/createOrder.js.map +1 -0
- package/lib/triggers/createSubscription.d.ts +6 -0
- package/lib/triggers/createSubscription.js +211 -0
- package/lib/triggers/createSubscription.js.map +1 -0
- package/lib/triggers/onUserDeleted.d.ts +5 -0
- package/lib/triggers/onUserDeleted.js +118 -0
- package/lib/triggers/onUserDeleted.js.map +1 -0
- package/lib/triggers/syncClaims.d.ts +5 -0
- package/lib/triggers/syncClaims.js +92 -0
- package/lib/triggers/syncClaims.js.map +1 -0
- package/lib/types.d.ts +43 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/utils/customerMapping.d.ts +9 -0
- package/lib/utils/customerMapping.js +68 -0
- package/lib/utils/customerMapping.js.map +1 -0
- package/lib/utils/ensureCustomer.d.ts +10 -0
- package/lib/utils/ensureCustomer.js +78 -0
- package/lib/utils/ensureCustomer.js.map +1 -0
- package/lib/utils/index.d.ts +15 -0
- package/lib/utils/index.js +75 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/processingLock.d.ts +12 -0
- package/lib/utils/processingLock.js +78 -0
- package/lib/utils/processingLock.js.map +1 -0
- package/lib/utils/retry.d.ts +9 -0
- package/lib/utils/retry.js +53 -0
- package/lib/utils/retry.js.map +1 -0
- package/lib/utils/typedFirestore.d.ts +25 -0
- package/lib/utils/typedFirestore.js +77 -0
- package/lib/utils/typedFirestore.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,138 @@
|
|
|
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.buildUpdateSubscriptionPlan = exports.buildCancelSubscription = 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 typedFirestore_1 = require("../utils/typedFirestore");
|
|
42
|
+
const buildCancelSubscription = (config, rzp) => {
|
|
43
|
+
return (0, https_1.onCall)(async (request) => {
|
|
44
|
+
const uid = request.auth?.uid;
|
|
45
|
+
if (!uid) {
|
|
46
|
+
throw new https_1.HttpsError('unauthenticated', 'User must be authenticated to cancel a subscription');
|
|
47
|
+
}
|
|
48
|
+
const { subscriptionId } = request.data;
|
|
49
|
+
if (!subscriptionId) {
|
|
50
|
+
throw new https_1.HttpsError('invalid-argument', 'The "subscriptionId" must be provided');
|
|
51
|
+
}
|
|
52
|
+
const db = admin.firestore();
|
|
53
|
+
const typedFs = new typedFirestore_1.TypedFirestore(db, config);
|
|
54
|
+
const docRef = typedFs.getSubscriptionDoc(uid, subscriptionId);
|
|
55
|
+
const doc = await docRef.get();
|
|
56
|
+
if (!doc.exists) {
|
|
57
|
+
throw new https_1.HttpsError('not-found', 'Subscription not found');
|
|
58
|
+
}
|
|
59
|
+
const existingData = doc.data();
|
|
60
|
+
if (existingData?.status === 'cancelled' || existingData?.status === 'completed') {
|
|
61
|
+
throw new https_1.HttpsError('failed-precondition', 'Subscription is already cancelled or completed.');
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const cancelledSubscription = await rzp.subscriptions.cancel(subscriptionId);
|
|
65
|
+
// Update main document status & timestamps only
|
|
66
|
+
const updateData = {
|
|
67
|
+
status: cancelledSubscription.status,
|
|
68
|
+
updated_at: firestore_1.FieldValue.serverTimestamp()
|
|
69
|
+
};
|
|
70
|
+
await docRef.set(updateData, { merge: true });
|
|
71
|
+
// Save raw subscription response separately
|
|
72
|
+
const detailsDocRef = typedFs.getSubscriptionDetailsDoc(uid, subscriptionId);
|
|
73
|
+
await detailsDocRef.set(cancelledSubscription);
|
|
74
|
+
logs_1.logs.info(`Successfully cancelled subscription ${subscriptionId} for user ${uid}`);
|
|
75
|
+
return { status: cancelledSubscription.status };
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
logs_1.logs.error(new Error(`Failed to cancel subscription ${subscriptionId}: ${error.message}`));
|
|
79
|
+
throw new https_1.HttpsError('internal', `Failed to cancel subscription: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
exports.buildCancelSubscription = buildCancelSubscription;
|
|
84
|
+
const buildUpdateSubscriptionPlan = (config, rzp) => {
|
|
85
|
+
return (0, https_1.onCall)(async (request) => {
|
|
86
|
+
const uid = request.auth?.uid;
|
|
87
|
+
if (!uid) {
|
|
88
|
+
throw new https_1.HttpsError('unauthenticated', 'User must be authenticated to update a subscription');
|
|
89
|
+
}
|
|
90
|
+
const { subscriptionId, planId, scheduleChangeAt } = request.data;
|
|
91
|
+
if (!subscriptionId || !planId) {
|
|
92
|
+
throw new https_1.HttpsError('invalid-argument', 'Both "subscriptionId" and "planId" must be provided');
|
|
93
|
+
}
|
|
94
|
+
// Only allow known-safe values for schedule_change_at
|
|
95
|
+
const validSchedule = scheduleChangeAt === 'cycle_end' ? 'cycle_end' : 'now';
|
|
96
|
+
const db = admin.firestore();
|
|
97
|
+
const typedFs = new typedFirestore_1.TypedFirestore(db, config);
|
|
98
|
+
const docRef = typedFs.getSubscriptionDoc(uid, subscriptionId);
|
|
99
|
+
const doc = await docRef.get();
|
|
100
|
+
if (!doc.exists) {
|
|
101
|
+
throw new https_1.HttpsError('not-found', 'Subscription not found');
|
|
102
|
+
}
|
|
103
|
+
// SEC-07: Validate that the planId is valid and belongs to an active product
|
|
104
|
+
const productsSnap = await typedFs.getProductsCollection()
|
|
105
|
+
.where('active', '==', true)
|
|
106
|
+
.get();
|
|
107
|
+
const isAllowed = productsSnap.docs.some(productDoc => {
|
|
108
|
+
const data = productDoc.data();
|
|
109
|
+
return data.allowedPlans && Object.values(data.allowedPlans).includes(planId);
|
|
110
|
+
});
|
|
111
|
+
if (!isAllowed) {
|
|
112
|
+
throw new https_1.HttpsError('invalid-argument', 'The specified plan is not available.');
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const updatedSubscription = await rzp.subscriptions.update(subscriptionId, {
|
|
116
|
+
plan_id: planId,
|
|
117
|
+
schedule_change_at: validSchedule
|
|
118
|
+
});
|
|
119
|
+
// Update main document status & timestamps only
|
|
120
|
+
const updateData = {
|
|
121
|
+
status: updatedSubscription.status,
|
|
122
|
+
updated_at: firestore_1.FieldValue.serverTimestamp()
|
|
123
|
+
};
|
|
124
|
+
await docRef.set(updateData, { merge: true });
|
|
125
|
+
// Save raw subscription response separately
|
|
126
|
+
const detailsDocRef = typedFs.getSubscriptionDetailsDoc(uid, subscriptionId);
|
|
127
|
+
await detailsDocRef.set(updatedSubscription);
|
|
128
|
+
logs_1.logs.info(`Successfully updated subscription ${subscriptionId} for user ${uid} to plan ${planId}`);
|
|
129
|
+
return { plan_id: updatedSubscription.plan_id, status: updatedSubscription.status };
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
logs_1.logs.error(new Error(`Failed to update subscription ${subscriptionId}: ${error.message}`));
|
|
133
|
+
throw new https_1.HttpsError('internal', `Failed to update subscription: ${error.message}`);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
exports.buildUpdateSubscriptionPlan = buildUpdateSubscriptionPlan;
|
|
138
|
+
//# sourceMappingURL=subscriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../../src/callables/subscriptions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as admin from 'firebase-admin';
|
|
2
|
+
import Razorpay from 'razorpay';
|
|
3
|
+
import { WebhookEvent, RazorpaySyncConfig } from '../types';
|
|
4
|
+
export declare const handlePaymentEvent: (event: WebhookEvent, db: admin.firestore.Firestore, razorpayClient: InstanceType<typeof Razorpay>, config: RazorpaySyncConfig) => Promise<void>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handlePaymentEvent = void 0;
|
|
4
|
+
const firestore_1 = require("firebase-admin/firestore");
|
|
5
|
+
const logs_1 = require("../logs");
|
|
6
|
+
const retry_1 = require("../utils/retry");
|
|
7
|
+
const customerMapping_1 = require("../utils/customerMapping");
|
|
8
|
+
const typedFirestore_1 = require("../utils/typedFirestore");
|
|
9
|
+
const handlePaymentEvent = async (event, db, razorpayClient, config) => {
|
|
10
|
+
const webhookPaymentId = event.payload.payment?.entity?.id || event.payload.payment?.id;
|
|
11
|
+
const webhookOrderId = event.payload.order?.entity?.id || event.payload.order?.id;
|
|
12
|
+
if (!webhookPaymentId && !webhookOrderId) {
|
|
13
|
+
logs_1.logs.error(new Error(`Missing both payment and order IDs in webhook payload: ${event.id}`));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
let fetchedPayment = null;
|
|
17
|
+
let fetchedOrder = null;
|
|
18
|
+
let isPayment = false;
|
|
19
|
+
try {
|
|
20
|
+
if (event.event.startsWith('payment.') && webhookPaymentId) {
|
|
21
|
+
fetchedPayment = await (0, retry_1.fetchWithBackoff)(() => razorpayClient.payments.fetch(webhookPaymentId));
|
|
22
|
+
isPayment = true;
|
|
23
|
+
}
|
|
24
|
+
else if (event.event.startsWith('order.') && webhookOrderId) {
|
|
25
|
+
fetchedOrder = await (0, retry_1.fetchWithBackoff)(() => razorpayClient.orders.fetch(webhookOrderId));
|
|
26
|
+
}
|
|
27
|
+
else if (webhookOrderId) {
|
|
28
|
+
fetchedOrder = await (0, retry_1.fetchWithBackoff)(() => razorpayClient.orders.fetch(webhookOrderId));
|
|
29
|
+
}
|
|
30
|
+
else if (webhookPaymentId) {
|
|
31
|
+
fetchedPayment = await (0, retry_1.fetchWithBackoff)(() => razorpayClient.payments.fetch(webhookPaymentId));
|
|
32
|
+
isPayment = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
logs_1.logs.error(new Error(`Failed to fetch entity from Razorpay API. Event: ${event.event}. Error: ${err.message}`));
|
|
37
|
+
if ((0, retry_1.isTransientError)(err)) {
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const fetchedEntity = fetchedPayment || fetchedOrder;
|
|
43
|
+
if (!fetchedEntity) {
|
|
44
|
+
logs_1.logs.error(new Error(`Failed to resolve entity for event: ${event.event}`));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const notes = fetchedEntity.notes;
|
|
48
|
+
const sessionId = notes?.sessionId ? String(notes.sessionId) : undefined;
|
|
49
|
+
let uid;
|
|
50
|
+
const customerId = (isPayment && fetchedPayment)
|
|
51
|
+
? fetchedPayment.customer_id
|
|
52
|
+
: (fetchedOrder ? fetchedOrder.customer_id : undefined);
|
|
53
|
+
if (customerId) {
|
|
54
|
+
const mappedUid = await (0, customerMapping_1.getUidByCustomerId)(customerId, config.customersCollection);
|
|
55
|
+
if (mappedUid) {
|
|
56
|
+
uid = mappedUid;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
logs_1.logs.error(new Error(`Failed to map Razorpay Customer ID ${customerId} to a Firebase UID. Rejecting webhook.`));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!uid) {
|
|
64
|
+
logs_1.logs.error(new Error(`Cannot resolve UID for event ${event.event}. No customer_id mapping and notes.uid fallback removed for security.`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!sessionId) {
|
|
68
|
+
logs_1.logs.error(new Error(`Missing sessionId in notes for event ${event.event}.`));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
let newStatus = 'processing';
|
|
72
|
+
if (isPayment && fetchedPayment) {
|
|
73
|
+
if (fetchedPayment.status === 'captured')
|
|
74
|
+
newStatus = 'paid';
|
|
75
|
+
else if (fetchedPayment.status === 'failed')
|
|
76
|
+
newStatus = 'failed';
|
|
77
|
+
else
|
|
78
|
+
newStatus = 'processing';
|
|
79
|
+
}
|
|
80
|
+
else if (fetchedOrder) {
|
|
81
|
+
if (fetchedOrder.status === 'paid')
|
|
82
|
+
newStatus = 'paid';
|
|
83
|
+
else
|
|
84
|
+
newStatus = 'processing';
|
|
85
|
+
}
|
|
86
|
+
const typedFs = new typedFirestore_1.TypedFirestore(db, config);
|
|
87
|
+
const docRef = typedFs.getCheckoutSessionDoc(uid, sessionId);
|
|
88
|
+
const orderDocRef = typedFs.getCheckoutSessionOrderDoc(uid, sessionId);
|
|
89
|
+
try {
|
|
90
|
+
await db.runTransaction(async (tx) => {
|
|
91
|
+
const snap = await tx.get(docRef);
|
|
92
|
+
if (!snap.exists) {
|
|
93
|
+
logs_1.logs.error(new Error(`Checkout session ${sessionId} for user ${uid} does not exist. Possible notes injection attempt.`));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Secure validation: Fetch the server-written order document inside the transaction to verify order ID
|
|
97
|
+
const orderSnap = await tx.get(orderDocRef);
|
|
98
|
+
if (!orderSnap.exists) {
|
|
99
|
+
logs_1.logs.error(new Error(`Order details missing for session ${sessionId}. Possible notes injection.`));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const orderData = orderSnap.data();
|
|
103
|
+
const expectedOrderId = isPayment && fetchedPayment ? fetchedPayment.order_id : fetchedOrder.id;
|
|
104
|
+
if (!orderData || orderData.id !== expectedOrderId) {
|
|
105
|
+
logs_1.logs.error(new Error(`Order ID mismatch for session ${sessionId}. Expected: ${orderData?.id}, Got: ${expectedOrderId}. Possible notes injection.`));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const dataToWrite = {
|
|
109
|
+
status: newStatus,
|
|
110
|
+
updated_at: firestore_1.FieldValue.serverTimestamp(),
|
|
111
|
+
};
|
|
112
|
+
const existingData = snap.data();
|
|
113
|
+
if (existingData?.processing_at) {
|
|
114
|
+
dataToWrite.processing_at = firestore_1.FieldValue.delete();
|
|
115
|
+
}
|
|
116
|
+
// Update status and timestamp on the main document
|
|
117
|
+
tx.set(docRef, dataToWrite, { merge: true });
|
|
118
|
+
// Store raw Razorpay responses in separate subcollection documents
|
|
119
|
+
if (isPayment && fetchedPayment) {
|
|
120
|
+
const paymentDocRef = typedFs.getCheckoutSessionPaymentDoc(uid, sessionId);
|
|
121
|
+
tx.set(paymentDocRef, fetchedPayment);
|
|
122
|
+
}
|
|
123
|
+
else if (fetchedOrder) {
|
|
124
|
+
tx.set(orderDocRef, fetchedOrder);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
logs_1.logs.webhookProcessed(event.event, fetchedEntity.id);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
logs_1.logs.error(error);
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
exports.handlePaymentEvent = handlePaymentEvent;
|
|
135
|
+
//# sourceMappingURL=payments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payments.js","sourceRoot":"","sources":["../../src/handlers/payments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as admin from 'firebase-admin';
|
|
2
|
+
import Razorpay from 'razorpay';
|
|
3
|
+
import { WebhookEvent, RazorpaySyncConfig } from '../types';
|
|
4
|
+
export declare const handleSubscriptionEvent: (event: WebhookEvent, db: admin.firestore.Firestore, razorpayClient: InstanceType<typeof Razorpay>, config: RazorpaySyncConfig) => Promise<void>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleSubscriptionEvent = void 0;
|
|
4
|
+
const firestore_1 = require("firebase-admin/firestore");
|
|
5
|
+
const logs_1 = require("../logs");
|
|
6
|
+
const retry_1 = require("../utils/retry");
|
|
7
|
+
const customerMapping_1 = require("../utils/customerMapping");
|
|
8
|
+
const typedFirestore_1 = require("../utils/typedFirestore");
|
|
9
|
+
const handleSubscriptionEvent = async (event, db, razorpayClient, config) => {
|
|
10
|
+
const webhookSubscription = event.payload.subscription?.entity;
|
|
11
|
+
if (!webhookSubscription?.id) {
|
|
12
|
+
logs_1.logs.error(new Error(`Missing subscription entity or ID in webhook payload: ${event.id}`));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let subscriptionEntity;
|
|
16
|
+
try {
|
|
17
|
+
subscriptionEntity = await (0, retry_1.fetchWithBackoff)(() => razorpayClient.subscriptions.fetch(webhookSubscription.id));
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
logs_1.logs.error(new Error(`Failed to fetch subscription from Razorpay API: ${webhookSubscription.id}. Error: ${err.message}`));
|
|
21
|
+
if ((0, retry_1.isTransientError)(err)) {
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const customerId = subscriptionEntity.customer_id;
|
|
27
|
+
if (!customerId) {
|
|
28
|
+
logs_1.logs.error(new Error(`No customer_id found on subscription ${subscriptionEntity.id}. Cannot resolve UID.`));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const uid = await (0, customerMapping_1.getUidByCustomerId)(customerId, config.customersCollection);
|
|
32
|
+
if (!uid) {
|
|
33
|
+
logs_1.logs.error(new Error(`No Firebase UID found mapped to Razorpay Customer ID ${customerId} for subscription ${subscriptionEntity.id}`));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const newStatus = String(subscriptionEntity.status);
|
|
37
|
+
const subscriptionId = subscriptionEntity.id;
|
|
38
|
+
const typedFs = new typedFirestore_1.TypedFirestore(db, config);
|
|
39
|
+
const docRef = typedFs.getSubscriptionDoc(uid, subscriptionId);
|
|
40
|
+
let paymentEntity = null;
|
|
41
|
+
const webhookPayment = event.payload.payment?.entity || (event.payload.payment?.id ? event.payload.payment : null);
|
|
42
|
+
if (webhookPayment?.id) {
|
|
43
|
+
try {
|
|
44
|
+
paymentEntity = await (0, retry_1.fetchWithBackoff)(() => razorpayClient.payments.fetch(webhookPayment.id));
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
logs_1.logs.error(new Error(`Failed to fetch payment from Razorpay API: ${webhookPayment.id}. Error: ${err.message}`));
|
|
48
|
+
if ((0, retry_1.isTransientError)(err)) {
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await db.runTransaction(async (tx) => {
|
|
55
|
+
const existingDoc = await tx.get(docRef);
|
|
56
|
+
if (!existingDoc.exists) {
|
|
57
|
+
logs_1.logs.error(new Error(`Subscription document does not exist in Firestore for ID: ${subscriptionId}. Rejecting webhook event.`));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const existingData = existingDoc.data();
|
|
61
|
+
const dataToWrite = {
|
|
62
|
+
status: newStatus,
|
|
63
|
+
updated_at: firestore_1.FieldValue.serverTimestamp(),
|
|
64
|
+
};
|
|
65
|
+
if (existingData?.processing_at) {
|
|
66
|
+
dataToWrite.processing_at = firestore_1.FieldValue.delete();
|
|
67
|
+
}
|
|
68
|
+
// Update status and timestamp on the main document
|
|
69
|
+
tx.set(docRef, dataToWrite, { merge: true });
|
|
70
|
+
// Store the raw subscription object in the canonical subcollection
|
|
71
|
+
const detailsDocRef = typedFs.getSubscriptionDetailsDoc(uid, subscriptionId);
|
|
72
|
+
tx.set(detailsDocRef, subscriptionEntity);
|
|
73
|
+
// Store the raw payment entity directly in the payments subcollection
|
|
74
|
+
if (paymentEntity) {
|
|
75
|
+
const paymentRef = typedFs.getSubscriptionPaymentDoc(uid, subscriptionId, paymentEntity.id);
|
|
76
|
+
tx.set(paymentRef, paymentEntity);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
logs_1.logs.webhookProcessed(event.event, subscriptionEntity.id);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
logs_1.logs.error(error);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
exports.handleSubscriptionEvent = handleSubscriptionEvent;
|
|
87
|
+
//# sourceMappingURL=subscriptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../../src/handlers/subscriptions.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RazorpayUserConfig } from './types';
|
|
2
|
+
export { RazorpayUserConfig, RazorpaySyncConfig } from './types';
|
|
3
|
+
export declare function initializeRazorpay(userConfig: RazorpayUserConfig): {
|
|
4
|
+
createOrder: import("firebase-functions/v2/core").CloudFunction<import("firebase-functions/v2/firestore").FirestoreEvent<import("firebase-functions/v2/firestore").QueryDocumentSnapshot | undefined, {
|
|
5
|
+
uid: string;
|
|
6
|
+
id: string;
|
|
7
|
+
}>>;
|
|
8
|
+
createSubscription: import("firebase-functions/v2/core").CloudFunction<import("firebase-functions/v2/firestore").FirestoreEvent<import("firebase-functions/v2/firestore").QueryDocumentSnapshot | undefined, {
|
|
9
|
+
uid: string;
|
|
10
|
+
id: string;
|
|
11
|
+
}>>;
|
|
12
|
+
createCustomer: import("firebase-functions/v1").CloudFunction<import("firebase-admin/auth").UserRecord>;
|
|
13
|
+
onUserDeleted: import("firebase-functions/v1").CloudFunction<import("firebase-admin/auth").UserRecord>;
|
|
14
|
+
onCustomerDataDeleted: import("firebase-functions/v1").CloudFunction<import("firebase-functions/v1/firestore").QueryDocumentSnapshot>;
|
|
15
|
+
webhookHandler: import("firebase-functions/v2/https").HttpsFunction;
|
|
16
|
+
cancelSubscription: import("firebase-functions/v2/https").CallableFunction<any, Promise<{
|
|
17
|
+
status: "cancelled" | "active" | "pending" | "created" | "expired" | "authenticated" | "halted" | "completed";
|
|
18
|
+
}>>;
|
|
19
|
+
updateSubscriptionPlan: import("firebase-functions/v2/https").CallableFunction<any, Promise<{
|
|
20
|
+
plan_id: string;
|
|
21
|
+
status: "cancelled" | "active" | "pending" | "created" | "expired" | "authenticated" | "halted" | "completed";
|
|
22
|
+
}>>;
|
|
23
|
+
createPlan: import("firebase-functions/v2/https").CallableFunction<any, Promise<import("./types").ProductDoc>>;
|
|
24
|
+
syncPlans: import("firebase-functions/v2/https").CallableFunction<any, Promise<{
|
|
25
|
+
status: string;
|
|
26
|
+
count: number;
|
|
27
|
+
productsCount: number;
|
|
28
|
+
}>>;
|
|
29
|
+
};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initializeRazorpay = initializeRazorpay;
|
|
7
|
+
const razorpay_1 = __importDefault(require("razorpay"));
|
|
8
|
+
const eventarc_1 = require("firebase-admin/eventarc");
|
|
9
|
+
const logs_1 = require("./logs");
|
|
10
|
+
// Import builders
|
|
11
|
+
const createOrder_1 = require("./triggers/createOrder");
|
|
12
|
+
const createSubscription_1 = require("./triggers/createSubscription");
|
|
13
|
+
const createCustomer_1 = require("./triggers/createCustomer");
|
|
14
|
+
const onUserDeleted_1 = require("./triggers/onUserDeleted");
|
|
15
|
+
const subscriptions_1 = require("./callables/subscriptions");
|
|
16
|
+
const admin_1 = require("./admin");
|
|
17
|
+
const api_1 = require("./api");
|
|
18
|
+
function initializeRazorpay(userConfig) {
|
|
19
|
+
// 1. Log initialization
|
|
20
|
+
logs_1.logs.init();
|
|
21
|
+
// 2. Validate required configs
|
|
22
|
+
if (!userConfig.keyId || !userConfig.keySecret) {
|
|
23
|
+
throw new Error("keyId or keySecret is missing. Razorpay functions cannot be initialized.");
|
|
24
|
+
}
|
|
25
|
+
else if (!userConfig.keyId.startsWith('rzp_')) {
|
|
26
|
+
throw new Error(`keyId seems malformed (expected to start with 'rzp_'). Configuration is invalid.`);
|
|
27
|
+
}
|
|
28
|
+
if (!userConfig.webhookSecret) {
|
|
29
|
+
throw new Error('webhookSecret is missing. Razorpay functions cannot be initialized.');
|
|
30
|
+
}
|
|
31
|
+
// 3. Apply defaults
|
|
32
|
+
const config = {
|
|
33
|
+
keyId: userConfig.keyId,
|
|
34
|
+
keySecret: userConfig.keySecret,
|
|
35
|
+
webhookSecret: userConfig.webhookSecret,
|
|
36
|
+
customersCollection: userConfig.customersCollection || 'customers',
|
|
37
|
+
productsCollection: userConfig.productsCollection || 'products',
|
|
38
|
+
syncCustomers: userConfig.syncCustomers ?? true,
|
|
39
|
+
eventarcChannel: userConfig.eventarcChannel,
|
|
40
|
+
allowedEventTypes: userConfig.allowedEventTypes,
|
|
41
|
+
};
|
|
42
|
+
// 4. Initialize Razorpay Client once
|
|
43
|
+
const rzpClient = new razorpay_1.default({
|
|
44
|
+
key_id: config.keyId,
|
|
45
|
+
key_secret: config.keySecret,
|
|
46
|
+
});
|
|
47
|
+
// Allow overriding the API base URL (for emulator/integration testing ONLY)
|
|
48
|
+
if (process.env.RAZORPAY_API_URL) {
|
|
49
|
+
if (process.env.NODE_ENV === 'production') {
|
|
50
|
+
logs_1.logs.error(new Error('RAZORPAY_API_URL is set in production. This is a security risk (SSRF). Ignoring.'));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
logs_1.logs.info(`Initializing Razorpay client with custom base URL: ${process.env.RAZORPAY_API_URL}`);
|
|
54
|
+
rzpClient.api.rq.defaults.baseURL = process.env.RAZORPAY_API_URL;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 5. Initialize Eventarc channel if configured
|
|
58
|
+
let eventChannel = null;
|
|
59
|
+
if (config.eventarcChannel) {
|
|
60
|
+
try {
|
|
61
|
+
eventChannel = (0, eventarc_1.getEventarc)().channel(config.eventarcChannel, {
|
|
62
|
+
allowedEventTypes: config.allowedEventTypes,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
logs_1.logs.error(`Failed to initialize Eventarc channel: ${e.message || e}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// 6. Build and return grouped functions
|
|
70
|
+
return {
|
|
71
|
+
// Session and Subscription Firestore Triggers
|
|
72
|
+
createOrder: (0, createOrder_1.buildCreateOrder)(config, rzpClient),
|
|
73
|
+
createSubscription: (0, createSubscription_1.buildCreateSubscription)(config, rzpClient),
|
|
74
|
+
// Auth and lifecycle triggers
|
|
75
|
+
createCustomer: (0, createCustomer_1.buildCreateCustomer)(config, rzpClient),
|
|
76
|
+
onUserDeleted: (0, onUserDeleted_1.buildOnUserDeleted)(config),
|
|
77
|
+
onCustomerDataDeleted: (0, onUserDeleted_1.buildOnCustomerDataDeleted)(config, rzpClient),
|
|
78
|
+
// HTTPS Webhook Handler
|
|
79
|
+
webhookHandler: (0, api_1.buildWebhookHandler)(config, rzpClient, eventChannel),
|
|
80
|
+
// Client Callables
|
|
81
|
+
cancelSubscription: (0, subscriptions_1.buildCancelSubscription)(config, rzpClient),
|
|
82
|
+
updateSubscriptionPlan: (0, subscriptions_1.buildUpdateSubscriptionPlan)(config, rzpClient),
|
|
83
|
+
// Admin callables
|
|
84
|
+
createPlan: (0, admin_1.buildCreatePlan)(config, rzpClient),
|
|
85
|
+
syncPlans: (0, admin_1.buildSyncPlans)(config, rzpClient),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/logs.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const logs: {
|
|
2
|
+
init: () => void;
|
|
3
|
+
info: (message: string) => void;
|
|
4
|
+
startWebhook: (eventType: string) => void;
|
|
5
|
+
webhookProcessed: (eventType: string, id: string) => void;
|
|
6
|
+
invalidSignature: () => void;
|
|
7
|
+
orderCreated: (orderId: string, docPath: string) => void;
|
|
8
|
+
subscriptionCreated: (subId: string, docPath: string) => void;
|
|
9
|
+
error: (message: string | Error, err?: unknown) => void;
|
|
10
|
+
};
|
package/lib/logs.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logs = void 0;
|
|
4
|
+
const firebase_functions_1 = require("firebase-functions");
|
|
5
|
+
exports.logs = {
|
|
6
|
+
init: () => {
|
|
7
|
+
firebase_functions_1.logger.info('Initializing Razorpay Firebase package');
|
|
8
|
+
},
|
|
9
|
+
info: (message) => {
|
|
10
|
+
firebase_functions_1.logger.info(message);
|
|
11
|
+
},
|
|
12
|
+
startWebhook: (eventType) => {
|
|
13
|
+
firebase_functions_1.logger.info(`Started processing Razorpay webhook for event: ${eventType}`);
|
|
14
|
+
},
|
|
15
|
+
webhookProcessed: (eventType, id) => {
|
|
16
|
+
firebase_functions_1.logger.info(`Successfully processed webhook event ${eventType} for entity ${id}`);
|
|
17
|
+
},
|
|
18
|
+
invalidSignature: () => {
|
|
19
|
+
firebase_functions_1.logger.error('Webhook failed signature verification');
|
|
20
|
+
},
|
|
21
|
+
orderCreated: (orderId, docPath) => {
|
|
22
|
+
firebase_functions_1.logger.info(`Successfully created Razorpay order ${orderId} for ${docPath}`);
|
|
23
|
+
},
|
|
24
|
+
subscriptionCreated: (subId, docPath) => {
|
|
25
|
+
firebase_functions_1.logger.info(`Successfully created Razorpay subscription ${subId} for ${docPath}`);
|
|
26
|
+
},
|
|
27
|
+
error: (message, err) => {
|
|
28
|
+
if (err) {
|
|
29
|
+
firebase_functions_1.logger.error(message, err);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
firebase_functions_1.logger.error(message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=logs.js.map
|
package/lib/logs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":";;;AAAA,2DAA4C;AAE/B,QAAA,IAAI,GAAG;IAChB,IAAI,EAAE,GAAG,EAAE;QACP,2BAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE;QACtB,2BAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,YAAY,EAAE,CAAC,SAAiB,EAAE,EAAE;QAChC,2BAAM,CAAC,IAAI,CAAC,kDAAkD,SAAS,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,gBAAgB,EAAE,CAAC,SAAiB,EAAE,EAAU,EAAE,EAAE;QAChD,2BAAM,CAAC,IAAI,CAAC,wCAAwC,SAAS,eAAe,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,gBAAgB,EAAE,GAAG,EAAE;QACnB,2BAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC1D,CAAC;IAED,YAAY,EAAE,CAAC,OAAe,EAAE,OAAe,EAAE,EAAE;QAC/C,2BAAM,CAAC,IAAI,CAAC,uCAAuC,OAAO,QAAQ,OAAO,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,mBAAmB,EAAE,CAAC,KAAa,EAAE,OAAe,EAAE,EAAE;QACpD,2BAAM,CAAC,IAAI,CAAC,8CAA8C,KAAK,QAAQ,OAAO,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,KAAK,EAAE,CAAC,OAAuB,EAAE,GAAa,EAAE,EAAE;QAC9C,IAAI,GAAG,EAAE,CAAC;YACN,2BAAM,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACJ,2BAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;IACL,CAAC;CACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const verifyWebhookSignature: (payload: string, signature: string, webhookSecret: string) => boolean;
|
package/lib/security.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.verifyWebhookSignature = void 0;
|
|
7
|
+
const razorpay_1 = __importDefault(require("razorpay"));
|
|
8
|
+
const verifyWebhookSignature = (payload, signature, webhookSecret) => {
|
|
9
|
+
if (!signature || !payload || !webhookSecret)
|
|
10
|
+
return false;
|
|
11
|
+
return razorpay_1.default.validateWebhookSignature(payload, signature, webhookSecret);
|
|
12
|
+
};
|
|
13
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
14
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":";;;;;;AAAA,wDAAgC;AAEzB,MAAM,sBAAsB,GAAG,CAClC,OAAe,EACf,SAAiB,EACjB,aAAqB,EACd,EAAE;IACT,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IAE3D,OAAO,kBAAQ,CAAC,wBAAwB,CACpC,OAAO,EACP,SAAS,EACT,aAAa,CAChB,CAAC;AACN,CAAC,CAAC;AAZW,QAAA,sBAAsB,0BAYjC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as functions from 'firebase-functions';
|
|
2
|
+
import Razorpay from 'razorpay';
|
|
3
|
+
import { RazorpaySyncConfig } from '../types';
|
|
4
|
+
export declare const buildCreateCustomer: (config: RazorpaySyncConfig, rzp: Razorpay) => functions.CloudFunction<import("firebase-admin/auth").UserRecord>;
|