@baasix/plugin-stripe 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.
- package/README.md +473 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/checkout.d.ts +24 -0
- package/dist/routes/checkout.d.ts.map +1 -0
- package/dist/routes/checkout.js +58 -0
- package/dist/routes/checkout.js.map +1 -0
- package/dist/routes/index.d.ts +26 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +44 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/portal.d.ts +31 -0
- package/dist/routes/portal.d.ts.map +1 -0
- package/dist/routes/portal.js +78 -0
- package/dist/routes/portal.js.map +1 -0
- package/dist/routes/products.d.ts +26 -0
- package/dist/routes/products.d.ts.map +1 -0
- package/dist/routes/products.js +65 -0
- package/dist/routes/products.js.map +1 -0
- package/dist/routes/subscription.d.ts +32 -0
- package/dist/routes/subscription.d.ts.map +1 -0
- package/dist/routes/subscription.js +121 -0
- package/dist/routes/subscription.js.map +1 -0
- package/dist/routes/webhook.d.ts +15 -0
- package/dist/routes/webhook.d.ts.map +1 -0
- package/dist/routes/webhook.js +52 -0
- package/dist/routes/webhook.js.map +1 -0
- package/dist/schemas/index.d.ts +31 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +140 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/services/stripeService.d.ts +58 -0
- package/dist/services/stripeService.d.ts.map +1 -0
- package/dist/services/stripeService.js +431 -0
- package/dist/services/stripeService.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/loadStripe.d.ts +28 -0
- package/dist/utils/loadStripe.d.ts.map +1 -0
- package/dist/utils/loadStripe.js +59 -0
- package/dist/utils/loadStripe.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Plugin Database Schemas
|
|
3
|
+
*
|
|
4
|
+
* Defines the database tables created by the Stripe plugin:
|
|
5
|
+
* - baasix_StripeCustomer: Maps users to Stripe customers
|
|
6
|
+
* - baasix_StripePayment: Records one-time payments
|
|
7
|
+
* - baasix_StripeSubscription: Tracks subscriptions
|
|
8
|
+
* - baasix_StripeProduct: Caches products/prices from Stripe
|
|
9
|
+
*/
|
|
10
|
+
import type { PluginSchemaDefinition } from "../types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Stripe Customer schema - maps Baasix users to Stripe customers
|
|
13
|
+
*/
|
|
14
|
+
export declare const stripeCustomerSchema: PluginSchemaDefinition;
|
|
15
|
+
/**
|
|
16
|
+
* Stripe Payment schema - records one-time payments
|
|
17
|
+
*/
|
|
18
|
+
export declare const stripePaymentSchema: PluginSchemaDefinition;
|
|
19
|
+
/**
|
|
20
|
+
* Stripe Subscription schema - tracks active and past subscriptions
|
|
21
|
+
*/
|
|
22
|
+
export declare const stripeSubscriptionSchema: PluginSchemaDefinition;
|
|
23
|
+
/**
|
|
24
|
+
* Stripe Product schema - caches products and prices from Stripe
|
|
25
|
+
*/
|
|
26
|
+
export declare const stripeProductSchema: PluginSchemaDefinition;
|
|
27
|
+
/**
|
|
28
|
+
* All Stripe plugin schemas
|
|
29
|
+
*/
|
|
30
|
+
export declare const stripeSchemas: PluginSchemaDefinition[];
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,sBAuBlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,sBA2BjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,sBA4BtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,sBA2BjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,sBAAsB,EAKjD,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Plugin Database Schemas
|
|
3
|
+
*
|
|
4
|
+
* Defines the database tables created by the Stripe plugin:
|
|
5
|
+
* - baasix_StripeCustomer: Maps users to Stripe customers
|
|
6
|
+
* - baasix_StripePayment: Records one-time payments
|
|
7
|
+
* - baasix_StripeSubscription: Tracks subscriptions
|
|
8
|
+
* - baasix_StripeProduct: Caches products/prices from Stripe
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Stripe Customer schema - maps Baasix users to Stripe customers
|
|
12
|
+
*/
|
|
13
|
+
export const stripeCustomerSchema = {
|
|
14
|
+
collectionName: "baasix_StripeCustomer",
|
|
15
|
+
schema: {
|
|
16
|
+
name: "StripeCustomer",
|
|
17
|
+
timestamps: true,
|
|
18
|
+
fields: {
|
|
19
|
+
id: { type: "UUID", primaryKey: true, defaultValue: { type: "UUIDV4" } },
|
|
20
|
+
user_Id: { type: "UUID", allowNull: false },
|
|
21
|
+
stripeCustomerId: { type: "String", allowNull: false },
|
|
22
|
+
email: { type: "String", allowNull: true },
|
|
23
|
+
metadata: { type: "JSON", allowNull: true },
|
|
24
|
+
user: {
|
|
25
|
+
relType: "BelongsTo",
|
|
26
|
+
target: "baasix_User",
|
|
27
|
+
foreignKey: "user_Id",
|
|
28
|
+
as: "user",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
indexes: [
|
|
32
|
+
{ fields: ["stripeCustomerId"], unique: true },
|
|
33
|
+
{ fields: ["user_Id"], unique: true },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Stripe Payment schema - records one-time payments
|
|
39
|
+
*/
|
|
40
|
+
export const stripePaymentSchema = {
|
|
41
|
+
collectionName: "baasix_StripePayment",
|
|
42
|
+
schema: {
|
|
43
|
+
name: "StripePayment",
|
|
44
|
+
timestamps: true,
|
|
45
|
+
fields: {
|
|
46
|
+
id: { type: "UUID", primaryKey: true, defaultValue: { type: "UUIDV4" } },
|
|
47
|
+
customer_Id: { type: "UUID", allowNull: false },
|
|
48
|
+
stripePaymentIntentId: { type: "String", allowNull: false },
|
|
49
|
+
stripeCheckoutSessionId: { type: "String", allowNull: true },
|
|
50
|
+
amount: { type: "Integer", allowNull: false },
|
|
51
|
+
currency: { type: "String", defaultValue: "usd" },
|
|
52
|
+
status: {
|
|
53
|
+
type: "ENUM",
|
|
54
|
+
values: ["pending", "processing", "succeeded", "failed", "canceled", "refunded"],
|
|
55
|
+
defaultValue: "pending",
|
|
56
|
+
},
|
|
57
|
+
metadata: { type: "JSON", allowNull: true },
|
|
58
|
+
customer: {
|
|
59
|
+
relType: "BelongsTo",
|
|
60
|
+
target: "baasix_StripeCustomer",
|
|
61
|
+
foreignKey: "customer_Id",
|
|
62
|
+
as: "customer",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
indexes: [{ fields: ["stripePaymentIntentId"], unique: true }],
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Stripe Subscription schema - tracks active and past subscriptions
|
|
70
|
+
*/
|
|
71
|
+
export const stripeSubscriptionSchema = {
|
|
72
|
+
collectionName: "baasix_StripeSubscription",
|
|
73
|
+
schema: {
|
|
74
|
+
name: "StripeSubscription",
|
|
75
|
+
timestamps: true,
|
|
76
|
+
fields: {
|
|
77
|
+
id: { type: "UUID", primaryKey: true, defaultValue: { type: "UUIDV4" } },
|
|
78
|
+
customer_Id: { type: "UUID", allowNull: false },
|
|
79
|
+
stripeSubscriptionId: { type: "String", allowNull: false },
|
|
80
|
+
stripePriceId: { type: "String", allowNull: false },
|
|
81
|
+
status: {
|
|
82
|
+
type: "ENUM",
|
|
83
|
+
values: ["active", "canceled", "incomplete", "past_due", "trialing", "unpaid", "incomplete_expired", "paused"],
|
|
84
|
+
defaultValue: "incomplete",
|
|
85
|
+
},
|
|
86
|
+
currentPeriodStart: { type: "DateTime", allowNull: true },
|
|
87
|
+
currentPeriodEnd: { type: "DateTime", allowNull: true },
|
|
88
|
+
cancelAtPeriodEnd: { type: "Boolean", defaultValue: false },
|
|
89
|
+
metadata: { type: "JSON", allowNull: true },
|
|
90
|
+
customer: {
|
|
91
|
+
relType: "BelongsTo",
|
|
92
|
+
target: "baasix_StripeCustomer",
|
|
93
|
+
foreignKey: "customer_Id",
|
|
94
|
+
as: "customer",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
indexes: [{ fields: ["stripeSubscriptionId"], unique: true }],
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Stripe Product schema - caches products and prices from Stripe
|
|
102
|
+
*/
|
|
103
|
+
export const stripeProductSchema = {
|
|
104
|
+
collectionName: "baasix_StripeProduct",
|
|
105
|
+
schema: {
|
|
106
|
+
name: "StripeProduct",
|
|
107
|
+
timestamps: true,
|
|
108
|
+
fields: {
|
|
109
|
+
id: { type: "UUID", primaryKey: true, defaultValue: { type: "UUIDV4" } },
|
|
110
|
+
stripeProductId: { type: "String", allowNull: false },
|
|
111
|
+
stripePriceId: { type: "String", allowNull: false },
|
|
112
|
+
name: { type: "String", allowNull: false },
|
|
113
|
+
description: { type: "Text", allowNull: true },
|
|
114
|
+
amount: { type: "Integer", allowNull: true },
|
|
115
|
+
currency: { type: "String", defaultValue: "usd" },
|
|
116
|
+
interval: {
|
|
117
|
+
type: "ENUM",
|
|
118
|
+
values: ["one_time", "day", "week", "month", "year"],
|
|
119
|
+
defaultValue: "one_time",
|
|
120
|
+
},
|
|
121
|
+
intervalCount: { type: "Integer", defaultValue: 1 },
|
|
122
|
+
active: { type: "Boolean", defaultValue: true },
|
|
123
|
+
metadata: { type: "JSON", allowNull: true },
|
|
124
|
+
},
|
|
125
|
+
indexes: [
|
|
126
|
+
{ fields: ["stripeProductId"] },
|
|
127
|
+
{ fields: ["stripePriceId"], unique: true },
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* All Stripe plugin schemas
|
|
133
|
+
*/
|
|
134
|
+
export const stripeSchemas = [
|
|
135
|
+
stripeCustomerSchema,
|
|
136
|
+
stripePaymentSchema,
|
|
137
|
+
stripeSubscriptionSchema,
|
|
138
|
+
stripeProductSchema,
|
|
139
|
+
];
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,cAAc,EAAE,uBAAuB;IACvC,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE;YACN,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACxE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;YAC3C,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YACtD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;YAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;YAC3C,IAAI,EAAE;gBACJ,OAAO,EAAE,WAAW;gBACpB,MAAM,EAAE,aAAa;gBACrB,UAAU,EAAE,SAAS;gBACrB,EAAE,EAAE,MAAM;aACX;SACF;QACD,OAAO,EAAE;YACP,EAAE,MAAM,EAAE,CAAC,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;YAC9C,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;SACtC;KACF;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,cAAc,EAAE,sBAAsB;IACtC,MAAM,EAAE;QACN,IAAI,EAAE,eAAe;QACrB,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE;YACN,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACxE,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;YAC/C,qBAAqB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YAC3D,uBAAuB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;YAC5D,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE;YAC7C,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE;YACjD,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,CAAC,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC;gBAChF,YAAY,EAAE,SAAS;aACxB;YACD,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;YAC3C,QAAQ,EAAE;gBACR,OAAO,EAAE,WAAW;gBACpB,MAAM,EAAE,uBAAuB;gBAC/B,UAAU,EAAE,aAAa;gBACzB,EAAE,EAAE,UAAU;aACf;SACF;QACD,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,uBAAuB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAC/D;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA2B;IAC9D,cAAc,EAAE,2BAA2B;IAC3C,MAAM,EAAE;QACN,IAAI,EAAE,oBAAoB;QAC1B,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE;YACN,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACxE,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;YAC/C,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YAC1D,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YACnD,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,QAAQ,CAAC;gBAC9G,YAAY,EAAE,YAAY;aAC3B;YACD,kBAAkB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE;YACzD,gBAAgB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE;YACvD,iBAAiB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE;YAC3D,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;YAC3C,QAAQ,EAAE;gBACR,OAAO,EAAE,WAAW;gBACpB,MAAM,EAAE,uBAAuB;gBAC/B,UAAU,EAAE,aAAa;gBACzB,EAAE,EAAE,UAAU;aACf;SACF;QACD,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,sBAAsB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAC9D;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,cAAc,EAAE,sBAAsB;IACtC,MAAM,EAAE;QACN,IAAI,EAAE,eAAe;QACrB,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE;YACN,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACxE,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YACrD,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YACnD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;YAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;YAC9C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE;YAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE;YACjD,QAAQ,EAAE;gBACR,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;gBACpD,YAAY,EAAE,UAAU;aACzB;YACD,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,EAAE;YACnD,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE;YAC/C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;SAC5C;QACD,OAAO,EAAE;YACP,EAAE,MAAM,EAAE,CAAC,iBAAiB,CAAC,EAAE;YAC/B,EAAE,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;SAC5C;KACF;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAA6B;IACrD,oBAAoB;IACpB,mBAAmB;IACnB,wBAAwB;IACxB,mBAAmB;CACpB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Service Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides all Stripe-related business logic including:
|
|
5
|
+
* - Customer management
|
|
6
|
+
* - Payment processing
|
|
7
|
+
* - Subscription management
|
|
8
|
+
* - Webhook handling
|
|
9
|
+
* - Product synchronization
|
|
10
|
+
*
|
|
11
|
+
* This service is available as a singleton after plugin initialization.
|
|
12
|
+
* You can access it via:
|
|
13
|
+
* - `getStripeService()` - from anywhere in your code
|
|
14
|
+
* - `context.services.stripeService` - in plugin routes/hooks
|
|
15
|
+
*/
|
|
16
|
+
import type { PluginContext, StripePluginConfig, StripeServiceInterface } from "../types.js";
|
|
17
|
+
declare global {
|
|
18
|
+
var __baasix_stripeService: StripeServiceInterface | undefined;
|
|
19
|
+
var __baasix_stripeServiceInitialized: boolean | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get the Stripe service singleton instance
|
|
23
|
+
*
|
|
24
|
+
* @throws Error if the service hasn't been initialized yet
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { getStripeService } from '@baasix/plugin-stripe';
|
|
29
|
+
*
|
|
30
|
+
* // In an endpoint or hook
|
|
31
|
+
* const stripeService = getStripeService();
|
|
32
|
+
* const customer = await stripeService.getOrCreateCustomer(userId);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function getStripeService(): StripeServiceInterface;
|
|
36
|
+
/**
|
|
37
|
+
* Check if the Stripe service has been initialized
|
|
38
|
+
*/
|
|
39
|
+
export declare function isStripeServiceInitialized(): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Initialize the Stripe service singleton (called internally by the plugin)
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export declare function initializeStripeService(service: StripeServiceInterface): void;
|
|
45
|
+
/**
|
|
46
|
+
* Reset the Stripe service singleton (for testing)
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
export declare function resetStripeService(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Creates the Stripe service instance
|
|
52
|
+
*
|
|
53
|
+
* @param getStripe - Function to get the Stripe SDK instance
|
|
54
|
+
* @param config - Plugin configuration
|
|
55
|
+
* @param context - Plugin context with database access
|
|
56
|
+
*/
|
|
57
|
+
export declare function createStripeService(getStripe: () => Promise<any>, config: StripePluginConfig, context: PluginContext): StripeServiceInterface;
|
|
58
|
+
//# sourceMappingURL=stripeService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripeService.d.ts","sourceRoot":"","sources":["../../src/services/stripeService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,sBAAsB,EAKvB,MAAM,aAAa,CAAC;AAOrB,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,sBAAsB,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAE/D,IAAI,iCAAiC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,IAAI,sBAAsB,CAOzD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAG7E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC;AAMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EAC7B,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,aAAa,GACrB,sBAAsB,CA8bxB"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Service Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides all Stripe-related business logic including:
|
|
5
|
+
* - Customer management
|
|
6
|
+
* - Payment processing
|
|
7
|
+
* - Subscription management
|
|
8
|
+
* - Webhook handling
|
|
9
|
+
* - Product synchronization
|
|
10
|
+
*
|
|
11
|
+
* This service is available as a singleton after plugin initialization.
|
|
12
|
+
* You can access it via:
|
|
13
|
+
* - `getStripeService()` - from anywhere in your code
|
|
14
|
+
* - `context.services.stripeService` - in plugin routes/hooks
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Get the Stripe service singleton instance
|
|
18
|
+
*
|
|
19
|
+
* @throws Error if the service hasn't been initialized yet
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { getStripeService } from '@baasix/plugin-stripe';
|
|
24
|
+
*
|
|
25
|
+
* // In an endpoint or hook
|
|
26
|
+
* const stripeService = getStripeService();
|
|
27
|
+
* const customer = await stripeService.getOrCreateCustomer(userId);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function getStripeService() {
|
|
31
|
+
if (!globalThis.__baasix_stripeService) {
|
|
32
|
+
throw new Error("Stripe service not initialized. Make sure the Stripe plugin is loaded in startServer().");
|
|
33
|
+
}
|
|
34
|
+
return globalThis.__baasix_stripeService;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if the Stripe service has been initialized
|
|
38
|
+
*/
|
|
39
|
+
export function isStripeServiceInitialized() {
|
|
40
|
+
return globalThis.__baasix_stripeServiceInitialized === true;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Initialize the Stripe service singleton (called internally by the plugin)
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
export function initializeStripeService(service) {
|
|
47
|
+
globalThis.__baasix_stripeService = service;
|
|
48
|
+
globalThis.__baasix_stripeServiceInitialized = true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reset the Stripe service singleton (for testing)
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export function resetStripeService() {
|
|
55
|
+
globalThis.__baasix_stripeService = undefined;
|
|
56
|
+
globalThis.__baasix_stripeServiceInitialized = false;
|
|
57
|
+
}
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// Service Factory
|
|
60
|
+
// ============================================================================
|
|
61
|
+
/**
|
|
62
|
+
* Creates the Stripe service instance
|
|
63
|
+
*
|
|
64
|
+
* @param getStripe - Function to get the Stripe SDK instance
|
|
65
|
+
* @param config - Plugin configuration
|
|
66
|
+
* @param context - Plugin context with database access
|
|
67
|
+
*/
|
|
68
|
+
export function createStripeService(getStripe, config, context) {
|
|
69
|
+
// Cache the stripe instance after first call
|
|
70
|
+
let cachedStripe = null;
|
|
71
|
+
const stripe = async () => {
|
|
72
|
+
if (!cachedStripe) {
|
|
73
|
+
cachedStripe = await getStripe();
|
|
74
|
+
}
|
|
75
|
+
return cachedStripe;
|
|
76
|
+
};
|
|
77
|
+
const service = {
|
|
78
|
+
/**
|
|
79
|
+
* Get the Stripe SDK instance (synchronous, returns cached value)
|
|
80
|
+
*/
|
|
81
|
+
get stripe() {
|
|
82
|
+
return cachedStripe;
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* Get or create a Stripe customer for a user
|
|
86
|
+
*/
|
|
87
|
+
async getOrCreateCustomer(userId) {
|
|
88
|
+
const stripeClient = await stripe();
|
|
89
|
+
const ItemsService = context.ItemsService;
|
|
90
|
+
const customerService = new ItemsService("baasix_StripeCustomer");
|
|
91
|
+
// Check for existing customer
|
|
92
|
+
const existing = await customerService.readByQuery({
|
|
93
|
+
filter: { user_Id: { _eq: userId } },
|
|
94
|
+
});
|
|
95
|
+
if (existing.length > 0) {
|
|
96
|
+
return existing[0];
|
|
97
|
+
}
|
|
98
|
+
// Get user details
|
|
99
|
+
const userService = new ItemsService("baasix_User");
|
|
100
|
+
const user = await userService.readOne(userId);
|
|
101
|
+
if (!user) {
|
|
102
|
+
throw new Error("User not found");
|
|
103
|
+
}
|
|
104
|
+
// Create Stripe customer
|
|
105
|
+
const stripeCustomer = await stripeClient.customers.create({
|
|
106
|
+
email: user.email,
|
|
107
|
+
name: [user.firstName, user.lastName].filter(Boolean).join(" ") || undefined,
|
|
108
|
+
metadata: { userId },
|
|
109
|
+
});
|
|
110
|
+
// Save mapping to database
|
|
111
|
+
return customerService.createOne({
|
|
112
|
+
user_Id: userId,
|
|
113
|
+
stripeCustomerId: stripeCustomer.id,
|
|
114
|
+
email: user.email,
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Get a Stripe customer by user ID
|
|
119
|
+
*/
|
|
120
|
+
async getCustomer(userId) {
|
|
121
|
+
const ItemsService = context.ItemsService;
|
|
122
|
+
const customerService = new ItemsService("baasix_StripeCustomer");
|
|
123
|
+
const results = await customerService.readByQuery({
|
|
124
|
+
filter: { user_Id: { _eq: userId } },
|
|
125
|
+
});
|
|
126
|
+
return results[0] || null;
|
|
127
|
+
},
|
|
128
|
+
/**
|
|
129
|
+
* Handle incoming Stripe webhook events
|
|
130
|
+
*/
|
|
131
|
+
async handleWebhook(event) {
|
|
132
|
+
const stripeClient = await stripe();
|
|
133
|
+
const ItemsService = context.ItemsService;
|
|
134
|
+
switch (event.type) {
|
|
135
|
+
case "checkout.session.completed": {
|
|
136
|
+
const session = event.data.object;
|
|
137
|
+
if (session.mode === "payment" && session.payment_intent) {
|
|
138
|
+
// Record the completed payment
|
|
139
|
+
const paymentService = new ItemsService("baasix_StripePayment");
|
|
140
|
+
const customerService = new ItemsService("baasix_StripeCustomer");
|
|
141
|
+
const customers = await customerService.readByQuery({
|
|
142
|
+
filter: { stripeCustomerId: { _eq: session.customer } },
|
|
143
|
+
});
|
|
144
|
+
if (customers.length > 0) {
|
|
145
|
+
await paymentService.createOne({
|
|
146
|
+
customer_Id: customers[0].id,
|
|
147
|
+
stripePaymentIntentId: session.payment_intent,
|
|
148
|
+
stripeCheckoutSessionId: session.id,
|
|
149
|
+
amount: session.amount_total || 0,
|
|
150
|
+
currency: session.currency || config.currency || "usd",
|
|
151
|
+
status: "succeeded",
|
|
152
|
+
metadata: session.metadata,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "payment_intent.succeeded": {
|
|
159
|
+
const paymentIntent = event.data.object;
|
|
160
|
+
const paymentService = new ItemsService("baasix_StripePayment");
|
|
161
|
+
// Update existing payment record if it exists
|
|
162
|
+
const existing = await paymentService.readByQuery({
|
|
163
|
+
filter: { stripePaymentIntentId: { _eq: paymentIntent.id } },
|
|
164
|
+
});
|
|
165
|
+
if (existing.length > 0) {
|
|
166
|
+
await paymentService.updateOne(existing[0].id, { status: "succeeded" });
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "payment_intent.payment_failed": {
|
|
171
|
+
const paymentIntent = event.data.object;
|
|
172
|
+
const paymentService = new ItemsService("baasix_StripePayment");
|
|
173
|
+
const existing = await paymentService.readByQuery({
|
|
174
|
+
filter: { stripePaymentIntentId: { _eq: paymentIntent.id } },
|
|
175
|
+
});
|
|
176
|
+
if (existing.length > 0) {
|
|
177
|
+
await paymentService.updateOne(existing[0].id, { status: "failed" });
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
case "customer.subscription.created":
|
|
182
|
+
case "customer.subscription.updated": {
|
|
183
|
+
const subscription = event.data.object;
|
|
184
|
+
await this.syncSubscription(subscription);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case "customer.subscription.deleted": {
|
|
188
|
+
const subscription = event.data.object;
|
|
189
|
+
const subService = new ItemsService("baasix_StripeSubscription");
|
|
190
|
+
const existing = await subService.readByQuery({
|
|
191
|
+
filter: { stripeSubscriptionId: { _eq: subscription.id } },
|
|
192
|
+
});
|
|
193
|
+
if (existing.length > 0) {
|
|
194
|
+
await subService.updateOne(existing[0].id, { status: "canceled" });
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case "invoice.payment_succeeded": {
|
|
199
|
+
// Handle subscription renewal
|
|
200
|
+
const invoice = event.data.object;
|
|
201
|
+
if (invoice.subscription) {
|
|
202
|
+
const subscription = await stripeClient.subscriptions.retrieve(invoice.subscription);
|
|
203
|
+
await this.syncSubscription(subscription);
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case "invoice.payment_failed": {
|
|
208
|
+
// Handle failed subscription payment
|
|
209
|
+
const invoice = event.data.object;
|
|
210
|
+
if (invoice.subscription) {
|
|
211
|
+
const subService = new ItemsService("baasix_StripeSubscription");
|
|
212
|
+
const existing = await subService.readByQuery({
|
|
213
|
+
filter: { stripeSubscriptionId: { _eq: invoice.subscription } },
|
|
214
|
+
});
|
|
215
|
+
if (existing.length > 0) {
|
|
216
|
+
await subService.updateOne(existing[0].id, { status: "past_due" });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
default:
|
|
222
|
+
console.log(`[Stripe Plugin] Unhandled webhook event: ${event.type}`);
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
/**
|
|
226
|
+
* Sync a subscription from Stripe to the database
|
|
227
|
+
*/
|
|
228
|
+
async syncSubscription(subscription) {
|
|
229
|
+
const ItemsService = context.ItemsService;
|
|
230
|
+
const subService = new ItemsService("baasix_StripeSubscription");
|
|
231
|
+
const customerService = new ItemsService("baasix_StripeCustomer");
|
|
232
|
+
// Find the customer
|
|
233
|
+
const customers = await customerService.readByQuery({
|
|
234
|
+
filter: { stripeCustomerId: { _eq: subscription.customer } },
|
|
235
|
+
});
|
|
236
|
+
if (customers.length === 0) {
|
|
237
|
+
console.warn(`[Stripe Plugin] Customer not found for subscription: ${subscription.id}`);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const priceId = subscription.items.data[0]?.price?.id;
|
|
241
|
+
if (!priceId) {
|
|
242
|
+
console.warn(`[Stripe Plugin] No price ID found for subscription: ${subscription.id}`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const data = {
|
|
246
|
+
customer_Id: customers[0].id,
|
|
247
|
+
stripeSubscriptionId: subscription.id,
|
|
248
|
+
stripePriceId: priceId,
|
|
249
|
+
status: subscription.status,
|
|
250
|
+
currentPeriodStart: new Date(subscription.current_period_start * 1000),
|
|
251
|
+
currentPeriodEnd: new Date(subscription.current_period_end * 1000),
|
|
252
|
+
cancelAtPeriodEnd: subscription.cancel_at_period_end,
|
|
253
|
+
metadata: subscription.metadata,
|
|
254
|
+
};
|
|
255
|
+
// Upsert the subscription
|
|
256
|
+
const existing = await subService.readByQuery({
|
|
257
|
+
filter: { stripeSubscriptionId: { _eq: subscription.id } },
|
|
258
|
+
});
|
|
259
|
+
if (existing.length > 0) {
|
|
260
|
+
await subService.updateOne(existing[0].id, data);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
await subService.createOne(data);
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
/**
|
|
267
|
+
* Manage a subscription (cancel or resume)
|
|
268
|
+
*/
|
|
269
|
+
async manageSubscription(userId, subscriptionId, action) {
|
|
270
|
+
const stripeClient = await stripe();
|
|
271
|
+
const ItemsService = context.ItemsService;
|
|
272
|
+
const subService = new ItemsService("baasix_StripeSubscription");
|
|
273
|
+
// Get customer to verify ownership
|
|
274
|
+
const customer = await this.getCustomer(userId);
|
|
275
|
+
if (!customer) {
|
|
276
|
+
throw new Error("Customer not found");
|
|
277
|
+
}
|
|
278
|
+
// Verify subscription belongs to user
|
|
279
|
+
const subs = await subService.readByQuery({
|
|
280
|
+
filter: {
|
|
281
|
+
id: { _eq: subscriptionId },
|
|
282
|
+
customer_Id: { _eq: customer.id },
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
if (subs.length === 0) {
|
|
286
|
+
throw new Error("Subscription not found");
|
|
287
|
+
}
|
|
288
|
+
const stripeSubId = subs[0].stripeSubscriptionId;
|
|
289
|
+
if (action === "cancel") {
|
|
290
|
+
await stripeClient.subscriptions.update(stripeSubId, { cancel_at_period_end: true });
|
|
291
|
+
await subService.updateOne(subscriptionId, { cancelAtPeriodEnd: true });
|
|
292
|
+
}
|
|
293
|
+
else if (action === "resume") {
|
|
294
|
+
await stripeClient.subscriptions.update(stripeSubId, { cancel_at_period_end: false });
|
|
295
|
+
await subService.updateOne(subscriptionId, { cancelAtPeriodEnd: false });
|
|
296
|
+
}
|
|
297
|
+
return { success: true };
|
|
298
|
+
},
|
|
299
|
+
/**
|
|
300
|
+
* Get a user's payment history
|
|
301
|
+
*/
|
|
302
|
+
async getUserPayments(userId) {
|
|
303
|
+
const customer = await this.getCustomer(userId);
|
|
304
|
+
if (!customer)
|
|
305
|
+
return [];
|
|
306
|
+
const ItemsService = context.ItemsService;
|
|
307
|
+
const paymentService = new ItemsService("baasix_StripePayment");
|
|
308
|
+
return paymentService.readByQuery({
|
|
309
|
+
filter: { customer_Id: { _eq: customer.id } },
|
|
310
|
+
sort: ["-createdAt"],
|
|
311
|
+
});
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* Get a user's subscriptions
|
|
315
|
+
*/
|
|
316
|
+
async getUserSubscriptions(userId) {
|
|
317
|
+
const customer = await this.getCustomer(userId);
|
|
318
|
+
if (!customer)
|
|
319
|
+
return [];
|
|
320
|
+
const ItemsService = context.ItemsService;
|
|
321
|
+
const subService = new ItemsService("baasix_StripeSubscription");
|
|
322
|
+
return subService.readByQuery({
|
|
323
|
+
filter: { customer_Id: { _eq: customer.id } },
|
|
324
|
+
sort: ["-createdAt"],
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
/**
|
|
328
|
+
* Get all active products
|
|
329
|
+
*/
|
|
330
|
+
async getProducts() {
|
|
331
|
+
const ItemsService = context.ItemsService;
|
|
332
|
+
const productService = new ItemsService("baasix_StripeProduct");
|
|
333
|
+
return productService.readByQuery({
|
|
334
|
+
filter: { active: { _eq: true } },
|
|
335
|
+
sort: ["name"],
|
|
336
|
+
});
|
|
337
|
+
},
|
|
338
|
+
/**
|
|
339
|
+
* Sync products and prices from Stripe
|
|
340
|
+
*/
|
|
341
|
+
async syncProducts() {
|
|
342
|
+
const stripeClient = await stripe();
|
|
343
|
+
const products = await stripeClient.products.list({ active: true, limit: 100 });
|
|
344
|
+
const prices = await stripeClient.prices.list({ active: true, limit: 100 });
|
|
345
|
+
const ItemsService = context.ItemsService;
|
|
346
|
+
const productService = new ItemsService("baasix_StripeProduct");
|
|
347
|
+
for (const price of prices.data) {
|
|
348
|
+
const product = products.data.find((p) => p.id === price.product);
|
|
349
|
+
if (!product)
|
|
350
|
+
continue;
|
|
351
|
+
const data = {
|
|
352
|
+
stripeProductId: product.id,
|
|
353
|
+
stripePriceId: price.id,
|
|
354
|
+
name: product.name,
|
|
355
|
+
description: product.description || null,
|
|
356
|
+
amount: price.unit_amount,
|
|
357
|
+
currency: price.currency,
|
|
358
|
+
interval: price.recurring?.interval || "one_time",
|
|
359
|
+
intervalCount: price.recurring?.interval_count || 1,
|
|
360
|
+
active: price.active && product.active,
|
|
361
|
+
metadata: product.metadata,
|
|
362
|
+
};
|
|
363
|
+
// Upsert by price ID
|
|
364
|
+
const existing = await productService.readByQuery({
|
|
365
|
+
filter: { stripePriceId: { _eq: price.id } },
|
|
366
|
+
});
|
|
367
|
+
if (existing.length > 0) {
|
|
368
|
+
await productService.updateOne(existing[0].id, data);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
await productService.createOne(data);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
console.log(`[Stripe Plugin] Synced ${prices.data.length} products/prices`);
|
|
375
|
+
},
|
|
376
|
+
/**
|
|
377
|
+
* Create a checkout session for one-time payment
|
|
378
|
+
*/
|
|
379
|
+
async createCheckoutSession(options) {
|
|
380
|
+
const stripeClient = await stripe();
|
|
381
|
+
const customer = await this.getOrCreateCustomer(options.userId);
|
|
382
|
+
const session = await stripeClient.checkout.sessions.create({
|
|
383
|
+
customer: customer.stripeCustomerId,
|
|
384
|
+
mode: "payment",
|
|
385
|
+
line_items: [{ price: options.priceId, quantity: options.quantity || 1 }],
|
|
386
|
+
success_url: options.successUrl,
|
|
387
|
+
cancel_url: options.cancelUrl,
|
|
388
|
+
metadata: { userId: options.userId, ...options.metadata },
|
|
389
|
+
});
|
|
390
|
+
return { sessionId: session.id, url: session.url };
|
|
391
|
+
},
|
|
392
|
+
/**
|
|
393
|
+
* Create a checkout session for subscription
|
|
394
|
+
*/
|
|
395
|
+
async createSubscriptionCheckout(options) {
|
|
396
|
+
const stripeClient = await stripe();
|
|
397
|
+
const customer = await this.getOrCreateCustomer(options.userId);
|
|
398
|
+
const session = await stripeClient.checkout.sessions.create({
|
|
399
|
+
customer: customer.stripeCustomerId,
|
|
400
|
+
mode: "subscription",
|
|
401
|
+
line_items: [{ price: options.priceId, quantity: 1 }],
|
|
402
|
+
success_url: options.successUrl,
|
|
403
|
+
cancel_url: options.cancelUrl,
|
|
404
|
+
subscription_data: options.trialDays
|
|
405
|
+
? { trial_period_days: options.trialDays }
|
|
406
|
+
: undefined,
|
|
407
|
+
metadata: { userId: options.userId, ...options.metadata },
|
|
408
|
+
});
|
|
409
|
+
return { sessionId: session.id, url: session.url };
|
|
410
|
+
},
|
|
411
|
+
/**
|
|
412
|
+
* Create a billing portal session for customer self-service
|
|
413
|
+
*/
|
|
414
|
+
async createPortalSession(userId, returnUrl) {
|
|
415
|
+
const stripeClient = await stripe();
|
|
416
|
+
const customer = await this.getCustomer(userId);
|
|
417
|
+
if (!customer) {
|
|
418
|
+
throw new Error("Customer not found");
|
|
419
|
+
}
|
|
420
|
+
const session = await stripeClient.billingPortal.sessions.create({
|
|
421
|
+
customer: customer.stripeCustomerId,
|
|
422
|
+
return_url: returnUrl,
|
|
423
|
+
});
|
|
424
|
+
return { url: session.url };
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
// Initialize the singleton
|
|
428
|
+
initializeStripeService(service);
|
|
429
|
+
return service;
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=stripeService.js.map
|