@digilogiclabs/saas-factory-payments 0.1.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.
@@ -0,0 +1,484 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/server/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ StripeServerAPI: () => StripeServerAPI,
34
+ StripeWebhookHandler: () => StripeWebhookHandler,
35
+ createNextJSWebhookHandler: () => createNextJSWebhookHandler,
36
+ createStripeWebhookHandler: () => createStripeWebhookHandler,
37
+ createStripeWebhookMiddleware: () => createStripeWebhookMiddleware
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+
41
+ // src/server/api/stripe-server.ts
42
+ var import_stripe = __toESM(require("stripe"));
43
+
44
+ // src/shared/constants.ts
45
+ var STRIPE_API_VERSION = "2023-10-16";
46
+ var WEBHOOK_EVENTS = {
47
+ CUSTOMER_SUBSCRIPTION_CREATED: "customer.subscription.created",
48
+ CUSTOMER_SUBSCRIPTION_UPDATED: "customer.subscription.updated",
49
+ CUSTOMER_SUBSCRIPTION_DELETED: "customer.subscription.deleted",
50
+ INVOICE_PAYMENT_SUCCEEDED: "invoice.payment_succeeded",
51
+ INVOICE_PAYMENT_FAILED: "invoice.payment_failed",
52
+ CHECKOUT_SESSION_COMPLETED: "checkout.session.completed",
53
+ PAYMENT_INTENT_SUCCEEDED: "payment_intent.succeeded",
54
+ PAYMENT_INTENT_PAYMENT_FAILED: "payment_intent.payment_failed"
55
+ };
56
+
57
+ // src/server/api/stripe-server.ts
58
+ var StripeServerAPI = class {
59
+ constructor(secretKey, options) {
60
+ this.stripe = new import_stripe.default(secretKey, {
61
+ apiVersion: options?.apiVersion || STRIPE_API_VERSION,
62
+ typescript: true
63
+ });
64
+ }
65
+ // Customer methods
66
+ async createCustomer(params) {
67
+ return this.stripe.customers.create({
68
+ email: params.email,
69
+ name: params.name,
70
+ phone: params.phone,
71
+ metadata: params.metadata
72
+ });
73
+ }
74
+ async getCustomer(customerId) {
75
+ return this.stripe.customers.retrieve(customerId);
76
+ }
77
+ async updateCustomer(customerId, params) {
78
+ return this.stripe.customers.update(customerId, params);
79
+ }
80
+ async deleteCustomer(customerId) {
81
+ return this.stripe.customers.del(customerId);
82
+ }
83
+ // Subscription methods
84
+ async createSubscription(params) {
85
+ return this.stripe.subscriptions.create({
86
+ customer: params.customerId,
87
+ items: [
88
+ {
89
+ price: params.priceId,
90
+ quantity: params.quantity || 1
91
+ }
92
+ ],
93
+ trial_period_days: params.trialPeriodDays,
94
+ metadata: params.metadata,
95
+ payment_behavior: params.paymentBehavior || "default_incomplete",
96
+ payment_settings: {
97
+ save_default_payment_method: "on_subscription"
98
+ },
99
+ expand: ["latest_invoice.payment_intent"]
100
+ });
101
+ }
102
+ async getSubscription(subscriptionId) {
103
+ return this.stripe.subscriptions.retrieve(subscriptionId, {
104
+ expand: ["default_payment_method"]
105
+ });
106
+ }
107
+ async updateSubscription(subscriptionId, params) {
108
+ const updateData = {};
109
+ if (params.priceId) {
110
+ const subscription = await this.getSubscription(subscriptionId);
111
+ const currentItem = subscription.items.data[0];
112
+ updateData.items = [
113
+ {
114
+ id: currentItem.id,
115
+ price: params.priceId,
116
+ quantity: params.quantity || currentItem.quantity
117
+ }
118
+ ];
119
+ }
120
+ if (params.metadata) {
121
+ updateData.metadata = params.metadata;
122
+ }
123
+ if (typeof params.cancelAtPeriodEnd === "boolean") {
124
+ updateData.cancel_at_period_end = params.cancelAtPeriodEnd;
125
+ }
126
+ return this.stripe.subscriptions.update(subscriptionId, updateData);
127
+ }
128
+ async cancelSubscription(subscriptionId, immediately = false) {
129
+ if (immediately) {
130
+ return this.stripe.subscriptions.cancel(subscriptionId);
131
+ } else {
132
+ return this.stripe.subscriptions.update(subscriptionId, {
133
+ cancel_at_period_end: true
134
+ });
135
+ }
136
+ }
137
+ async reactivateSubscription(subscriptionId) {
138
+ return this.stripe.subscriptions.update(subscriptionId, {
139
+ cancel_at_period_end: false
140
+ });
141
+ }
142
+ async getCustomerSubscriptions(customerId) {
143
+ return this.stripe.subscriptions.list({
144
+ customer: customerId,
145
+ expand: ["data.default_payment_method"]
146
+ });
147
+ }
148
+ // Checkout methods
149
+ async createCheckoutSession(params) {
150
+ const sessionParams = {
151
+ payment_method_types: ["card"],
152
+ line_items: [
153
+ {
154
+ price: params.priceId,
155
+ quantity: 1
156
+ }
157
+ ],
158
+ mode: params.mode || "subscription",
159
+ success_url: params.successUrl,
160
+ cancel_url: params.cancelUrl,
161
+ allow_promotion_codes: params.allowPromotionCodes,
162
+ billing_address_collection: params.billingAddressCollection,
163
+ metadata: params.metadata
164
+ };
165
+ if (params.customerId) {
166
+ sessionParams.customer = params.customerId;
167
+ } else if (params.customerEmail) {
168
+ sessionParams.customer_email = params.customerEmail;
169
+ }
170
+ if (params.mode === "subscription" && params.trialPeriodDays) {
171
+ sessionParams.subscription_data = {
172
+ trial_period_days: params.trialPeriodDays
173
+ };
174
+ }
175
+ return this.stripe.checkout.sessions.create(sessionParams);
176
+ }
177
+ // Payment Intent methods
178
+ async createPaymentIntent(params) {
179
+ return this.stripe.paymentIntents.create({
180
+ amount: params.amount,
181
+ currency: params.currency,
182
+ customer: params.customerId,
183
+ payment_method_types: params.paymentMethodTypes || ["card"],
184
+ metadata: params.metadata,
185
+ description: params.description
186
+ });
187
+ }
188
+ async confirmPaymentIntent(paymentIntentId, params) {
189
+ return this.stripe.paymentIntents.confirm(paymentIntentId, {
190
+ payment_method: params?.paymentMethod
191
+ });
192
+ }
193
+ // Setup Intent methods (for subscriptions without immediate payment)
194
+ async createSetupIntent(params) {
195
+ return this.stripe.setupIntents.create({
196
+ customer: params.customerId,
197
+ payment_method_types: params.paymentMethodTypes || ["card"],
198
+ metadata: params.metadata,
199
+ usage: "off_session"
200
+ });
201
+ }
202
+ // Customer Portal methods
203
+ async createPortalSession(params) {
204
+ return this.stripe.billingPortal.sessions.create({
205
+ customer: params.customerId,
206
+ return_url: params.returnUrl
207
+ });
208
+ }
209
+ // Payment Method methods
210
+ async getCustomerPaymentMethods(customerId, type = "card") {
211
+ return this.stripe.paymentMethods.list({
212
+ customer: customerId,
213
+ type
214
+ });
215
+ }
216
+ async attachPaymentMethod(paymentMethodId, customerId) {
217
+ return this.stripe.paymentMethods.attach(paymentMethodId, {
218
+ customer: customerId
219
+ });
220
+ }
221
+ async detachPaymentMethod(paymentMethodId) {
222
+ return this.stripe.paymentMethods.detach(paymentMethodId);
223
+ }
224
+ async setDefaultPaymentMethod(customerId, paymentMethodId) {
225
+ return this.stripe.customers.update(customerId, {
226
+ invoice_settings: {
227
+ default_payment_method: paymentMethodId
228
+ }
229
+ });
230
+ }
231
+ // Invoice methods
232
+ async getCustomerInvoices(customerId, limit = 10) {
233
+ return this.stripe.invoices.list({
234
+ customer: customerId,
235
+ limit
236
+ });
237
+ }
238
+ async getInvoice(invoiceId) {
239
+ return this.stripe.invoices.retrieve(invoiceId);
240
+ }
241
+ // Webhook methods
242
+ constructWebhookEvent(payload, signature, webhookSecret) {
243
+ return this.stripe.webhooks.constructEvent(
244
+ payload,
245
+ signature,
246
+ webhookSecret
247
+ );
248
+ }
249
+ // Price and Product methods
250
+ async getPrice(priceId) {
251
+ return this.stripe.prices.retrieve(priceId, {
252
+ expand: ["product"]
253
+ });
254
+ }
255
+ async getPrices(params) {
256
+ return this.stripe.prices.list({
257
+ active: params?.active,
258
+ limit: params?.limit || 10,
259
+ product: params?.product,
260
+ expand: ["data.product"]
261
+ });
262
+ }
263
+ async getProduct(productId) {
264
+ return this.stripe.products.retrieve(productId);
265
+ }
266
+ // Ephemeral Key methods (for mobile)
267
+ async createEphemeralKey(customerId, apiVersion) {
268
+ return this.stripe.ephemeralKeys.create(
269
+ { customer: customerId },
270
+ { apiVersion }
271
+ );
272
+ }
273
+ };
274
+
275
+ // src/server/webhooks/stripe.ts
276
+ var StripeWebhookHandler = class {
277
+ constructor(secretKey, handlers = {}) {
278
+ this.stripeAPI = new StripeServerAPI(secretKey);
279
+ this.handlers = handlers;
280
+ }
281
+ async handleWebhook(payload, signature, webhookSecret) {
282
+ try {
283
+ const event = this.stripeAPI.constructWebhookEvent(
284
+ payload,
285
+ signature,
286
+ webhookSecret
287
+ );
288
+ console.log(`Received webhook event: ${event.type}`);
289
+ await this.processEvent(event);
290
+ return { success: true };
291
+ } catch (error) {
292
+ const errorMessage = error instanceof Error ? error.message : "Unknown webhook error";
293
+ console.error("Webhook error:", errorMessage);
294
+ return { success: false, error: errorMessage };
295
+ }
296
+ }
297
+ async processEvent(event) {
298
+ switch (event.type) {
299
+ case WEBHOOK_EVENTS.CUSTOMER_SUBSCRIPTION_CREATED:
300
+ await this.handleSubscriptionCreated(
301
+ event.data.object
302
+ );
303
+ break;
304
+ case WEBHOOK_EVENTS.CUSTOMER_SUBSCRIPTION_UPDATED:
305
+ await this.handleSubscriptionUpdated(
306
+ event.data.object
307
+ );
308
+ break;
309
+ case WEBHOOK_EVENTS.CUSTOMER_SUBSCRIPTION_DELETED:
310
+ await this.handleSubscriptionDeleted(
311
+ event.data.object
312
+ );
313
+ break;
314
+ case WEBHOOK_EVENTS.INVOICE_PAYMENT_SUCCEEDED:
315
+ await this.handleInvoicePaymentSucceeded(
316
+ event.data.object
317
+ );
318
+ break;
319
+ case WEBHOOK_EVENTS.INVOICE_PAYMENT_FAILED:
320
+ await this.handleInvoicePaymentFailed(
321
+ event.data.object
322
+ );
323
+ break;
324
+ case WEBHOOK_EVENTS.CHECKOUT_SESSION_COMPLETED:
325
+ await this.handleCheckoutSessionCompleted(
326
+ event.data.object
327
+ );
328
+ break;
329
+ case WEBHOOK_EVENTS.PAYMENT_INTENT_SUCCEEDED:
330
+ await this.handlePaymentIntentSucceeded(
331
+ event.data.object
332
+ );
333
+ break;
334
+ case WEBHOOK_EVENTS.PAYMENT_INTENT_PAYMENT_FAILED:
335
+ await this.handlePaymentIntentFailed(
336
+ event.data.object
337
+ );
338
+ break;
339
+ default:
340
+ console.log(`Unhandled event type: ${event.type}`);
341
+ }
342
+ }
343
+ async handleSubscriptionCreated(subscription) {
344
+ console.log(`Subscription created: ${subscription.id}`);
345
+ if (this.handlers.onCustomerSubscriptionCreated) {
346
+ await this.handlers.onCustomerSubscriptionCreated(subscription);
347
+ }
348
+ console.log(
349
+ `Customer ${subscription.customer} subscribed to ${subscription.items.data[0]?.price.id}`
350
+ );
351
+ }
352
+ async handleSubscriptionUpdated(subscription) {
353
+ console.log(`Subscription updated: ${subscription.id}`);
354
+ if (this.handlers.onCustomerSubscriptionUpdated) {
355
+ await this.handlers.onCustomerSubscriptionUpdated(subscription);
356
+ }
357
+ console.log(
358
+ `Subscription ${subscription.id} status: ${subscription.status}`
359
+ );
360
+ }
361
+ async handleSubscriptionDeleted(subscription) {
362
+ console.log(`Subscription deleted: ${subscription.id}`);
363
+ if (this.handlers.onCustomerSubscriptionDeleted) {
364
+ await this.handlers.onCustomerSubscriptionDeleted(subscription);
365
+ }
366
+ console.log(
367
+ `Customer ${subscription.customer} cancelled subscription ${subscription.id}`
368
+ );
369
+ }
370
+ async handleInvoicePaymentSucceeded(invoice) {
371
+ console.log(`Invoice payment succeeded: ${invoice.id}`);
372
+ if (this.handlers.onInvoicePaymentSucceeded) {
373
+ await this.handlers.onInvoicePaymentSucceeded(invoice);
374
+ }
375
+ if (invoice.subscription) {
376
+ console.log(`Payment succeeded for subscription ${invoice.subscription}`);
377
+ }
378
+ }
379
+ async handleInvoicePaymentFailed(invoice) {
380
+ console.log(`Invoice payment failed: ${invoice.id}`);
381
+ if (this.handlers.onInvoicePaymentFailed) {
382
+ await this.handlers.onInvoicePaymentFailed(invoice);
383
+ }
384
+ if (invoice.subscription) {
385
+ console.log(`Payment failed for subscription ${invoice.subscription}`);
386
+ }
387
+ }
388
+ async handleCheckoutSessionCompleted(session) {
389
+ console.log(`Checkout session completed: ${session.id}`);
390
+ if (this.handlers.onCheckoutSessionCompleted) {
391
+ await this.handlers.onCheckoutSessionCompleted(session);
392
+ }
393
+ if (session.mode === "subscription") {
394
+ console.log(
395
+ `Subscription checkout completed for customer ${session.customer}`
396
+ );
397
+ } else {
398
+ console.log(
399
+ `Payment checkout completed for customer ${session.customer}`
400
+ );
401
+ }
402
+ }
403
+ async handlePaymentIntentSucceeded(paymentIntent) {
404
+ console.log(`Payment intent succeeded: ${paymentIntent.id}`);
405
+ if (this.handlers.onPaymentIntentSucceeded) {
406
+ await this.handlers.onPaymentIntentSucceeded(paymentIntent);
407
+ }
408
+ console.log(
409
+ `Payment of ${paymentIntent.amount} ${paymentIntent.currency} succeeded`
410
+ );
411
+ }
412
+ async handlePaymentIntentFailed(paymentIntent) {
413
+ console.log(`Payment intent failed: ${paymentIntent.id}`);
414
+ if (this.handlers.onPaymentIntentPaymentFailed) {
415
+ await this.handlers.onPaymentIntentPaymentFailed(paymentIntent);
416
+ }
417
+ console.log(
418
+ `Payment of ${paymentIntent.amount} ${paymentIntent.currency} failed`
419
+ );
420
+ }
421
+ };
422
+ var createStripeWebhookHandler = (secretKey, handlers = {}) => {
423
+ return new StripeWebhookHandler(secretKey, handlers);
424
+ };
425
+ var createStripeWebhookMiddleware = (secretKey, webhookSecret, handlers = {}) => {
426
+ const webhookHandler = new StripeWebhookHandler(secretKey, handlers);
427
+ return async (req, res, next) => {
428
+ try {
429
+ const signature = req.headers["stripe-signature"];
430
+ if (!signature) {
431
+ return res.status(400).json({ error: "Missing stripe-signature header" });
432
+ }
433
+ const result = await webhookHandler.handleWebhook(
434
+ req.body,
435
+ signature,
436
+ webhookSecret
437
+ );
438
+ if (result.success) {
439
+ res.status(200).json({ received: true });
440
+ } else {
441
+ res.status(400).json({ error: result.error });
442
+ }
443
+ } catch (error) {
444
+ console.error("Webhook middleware error:", error);
445
+ res.status(500).json({ error: "Internal server error" });
446
+ }
447
+ };
448
+ };
449
+ var createNextJSWebhookHandler = (secretKey, webhookSecret, handlers = {}) => {
450
+ const webhookHandler = new StripeWebhookHandler(secretKey, handlers);
451
+ return async (req, res) => {
452
+ if (req.method !== "POST") {
453
+ res.setHeader("Allow", "POST");
454
+ return res.status(405).json({ error: "Method not allowed" });
455
+ }
456
+ try {
457
+ const signature = req.headers["stripe-signature"];
458
+ if (!signature) {
459
+ return res.status(400).json({ error: "Missing stripe-signature header" });
460
+ }
461
+ const result = await webhookHandler.handleWebhook(
462
+ req.body,
463
+ signature,
464
+ webhookSecret
465
+ );
466
+ if (result.success) {
467
+ res.status(200).json({ received: true });
468
+ } else {
469
+ res.status(400).json({ error: result.error });
470
+ }
471
+ } catch (error) {
472
+ console.error("Webhook handler error:", error);
473
+ res.status(500).json({ error: "Internal server error" });
474
+ }
475
+ };
476
+ };
477
+ // Annotate the CommonJS export names for ESM import in node:
478
+ 0 && (module.exports = {
479
+ StripeServerAPI,
480
+ StripeWebhookHandler,
481
+ createNextJSWebhookHandler,
482
+ createStripeWebhookHandler,
483
+ createStripeWebhookMiddleware
484
+ });