strapi5-plugin-for-stripe 1.0.0 → 1.0.2

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,306 @@
1
+ "use strict";
2
+ const axios = require("axios");
3
+ const Stripe = require("stripe");
4
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
5
+ const axios__default = /* @__PURE__ */ _interopDefault(axios);
6
+ const Stripe__default = /* @__PURE__ */ _interopDefault(Stripe);
7
+ const bootstrap = ({ strapi }) => {
8
+ };
9
+ const destroy = ({ strapi }) => {
10
+ };
11
+ const register = ({ strapi }) => {
12
+ };
13
+ const config = {
14
+ default: {},
15
+ validator() {
16
+ }
17
+ };
18
+ const contentTypes = {};
19
+ const stripeController = ({ strapi }) => ({
20
+ async stripeService() {
21
+ return strapi.plugin("strapi5-plugin-for-stripe").service("stripeService");
22
+ },
23
+ /* ============================
24
+ * SETTINGS
25
+ * ============================ */
26
+ async getSettingsInternal() {
27
+ return await strapi.store({ type: "plugin", name: "strapi5-plugin-for-stripe" }).get({ key: "settings" });
28
+ },
29
+ async getSettings(ctx) {
30
+ const settings = await this.getSettingsInternal();
31
+ ctx.body = settings || {};
32
+ },
33
+ async updateSettings(ctx) {
34
+ const data = ctx.request.body;
35
+ if (data.checkout?.successUrl) {
36
+ const u = new URL(data.checkout.successUrl);
37
+ if (data.environment === "live" && u.protocol !== "https:") {
38
+ throw new Error("successUrl must be HTTPS in live mode");
39
+ }
40
+ }
41
+ if (data.checkout?.cancelUrl) {
42
+ const u = new URL(data.checkout.cancelUrl);
43
+ if (data.environment === "live" && u.protocol !== "https:") {
44
+ throw new Error("cancelUrl must be HTTPS in live mode");
45
+ }
46
+ }
47
+ await strapi.store({ type: "plugin", name: "strapi5-plugin-for-stripe" }).set({ key: "settings", value: data });
48
+ ctx.body = { ok: true };
49
+ },
50
+ /* ============================
51
+ * PRODUCTS
52
+ * ============================ */
53
+ async createProduct(ctx) {
54
+ const settings = await this.getSettingsInternal();
55
+ const service = await this.stripeService();
56
+ const stripe = service.stripeClient(settings.environment || "test");
57
+ ctx.body = await stripe.prices.create(ctx.request.body);
58
+ },
59
+ async listProducts(ctx) {
60
+ const settings = await this.getSettingsInternal();
61
+ const service = await this.stripeService();
62
+ const stripe = service.stripeClient(settings.environment || "test");
63
+ ctx.body = {
64
+ prices: (await stripe.prices.list({
65
+ limit: ctx.query.limit || 20,
66
+ active: ctx.query.active || true
67
+ })).data,
68
+ products: (await stripe.products.list({
69
+ limit: ctx.query.limit || 20,
70
+ active: ctx.query.active || true
71
+ })).data
72
+ };
73
+ },
74
+ async updateProduct(ctx) {
75
+ const settings = await this.getSettingsInternal();
76
+ const service = await this.stripeService();
77
+ const stripe = service.stripeClient(settings.environment || "test");
78
+ ctx.body = await stripe.products.update(ctx.params.id, ctx.request.body);
79
+ },
80
+ async deleteProduct(ctx) {
81
+ const settings = await this.getSettingsInternal();
82
+ const service = await this.stripeService();
83
+ const stripe = service.stripeClient(settings.environment || "test");
84
+ ctx.body = {
85
+ productRes: await stripe.products.update(ctx.params.productId, {
86
+ active: false
87
+ }),
88
+ priceRes: await stripe.prices.update(ctx.params.priceId, {
89
+ active: false
90
+ })
91
+ };
92
+ },
93
+ async deletePrice(ctx) {
94
+ const settings = await this.getSettingsInternal();
95
+ const service = await this.stripeService();
96
+ const stripe = service.stripeClient(settings.environment || "test");
97
+ ctx.body = {
98
+ productRes: await stripe.products.update(ctx.params.productId, {
99
+ default_price: ctx.params.newPriceId
100
+ }),
101
+ priceRes: await stripe.prices.update(ctx.params.priceId, {
102
+ active: false
103
+ })
104
+ };
105
+ },
106
+ /* ============================
107
+ * CHECKOUT
108
+ * ============================ */
109
+ async checkout(ctx) {
110
+ const settings = await this.getSettingsInternal();
111
+ const service = await this.stripeService();
112
+ const stripe = service.stripeClient(settings.environment || "test");
113
+ const {
114
+ priceId,
115
+ customer_email,
116
+ productId,
117
+ productName,
118
+ metadata = {}
119
+ } = ctx.request.body;
120
+ if (!priceId || !customer_email) {
121
+ ctx.throw(400, "Missing priceId or customer_email");
122
+ }
123
+ const session = await stripe.checkout.sessions.create({
124
+ mode: "payment",
125
+ line_items: [
126
+ {
127
+ price: priceId,
128
+ quantity: 1
129
+ }
130
+ ],
131
+ customer_email,
132
+ success_url: settings.checkout.successUrl + "?sessionId={CHECKOUT_SESSION_ID}",
133
+ cancel_url: settings.checkout.cancelUrl,
134
+ metadata: {
135
+ productId,
136
+ productName,
137
+ ...metadata
138
+ }
139
+ });
140
+ ctx.body = {
141
+ url: session.url
142
+ };
143
+ },
144
+ /* ============================
145
+ * WEBHOOK
146
+ * ============================ */
147
+ async webhook(ctx) {
148
+ const settings = await this.getSettingsInternal();
149
+ const service = await this.stripeService();
150
+ const stripe = service.stripeClient(settings.environment || "test");
151
+ const signature = ctx.request.headers["stripe-signature"];
152
+ const webhookSecret = process.env.STRAPI_ADMIN_STRIPE_WEBHOOK_SECRET_KEY;
153
+ const forwardUrl = settings.webhook?.forwardUrl;
154
+ if (!signature || !webhookSecret) {
155
+ ctx.throw(400, "Webhook configuration missing");
156
+ }
157
+ const rawBody = ctx.request.body?.[Symbol.for("unparsedBody")] ?? ctx.request.body;
158
+ let event;
159
+ try {
160
+ event = stripe.webhooks.constructEvent(rawBody, signature, webhookSecret);
161
+ } catch (err) {
162
+ ctx.throw(400, "Invalid Stripe webhook signature");
163
+ }
164
+ if (forwardUrl) {
165
+ await axios__default.default.post(forwardUrl, event, {
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ "Stripe-Event-Id": event.id,
169
+ "Stripe-Event-Type": event.type
170
+ },
171
+ timeout: 1e4
172
+ });
173
+ }
174
+ ctx.body = { received: true };
175
+ }
176
+ });
177
+ const controllers = {
178
+ stripeController
179
+ };
180
+ const middlewares = {};
181
+ const policies = {};
182
+ const contentAPIRoutes = () => ({
183
+ type: "content-api",
184
+ routes: [
185
+ {
186
+ method: "POST",
187
+ path: "/checkout",
188
+ handler: "stripeController.checkout"
189
+ },
190
+ {
191
+ method: "POST",
192
+ path: "/webhook",
193
+ handler: "stripeController.webhook",
194
+ config: {
195
+ auth: false
196
+ }
197
+ }
198
+ ]
199
+ });
200
+ const adminAPIRoutes = () => ({
201
+ type: "admin",
202
+ routes: [
203
+ {
204
+ method: "GET",
205
+ path: "/settings",
206
+ handler: "stripeController.getSettings",
207
+ config: {
208
+ auth: {
209
+ admin: true
210
+ }
211
+ }
212
+ },
213
+ {
214
+ method: "PUT",
215
+ path: "/settings",
216
+ handler: "stripeController.updateSettings",
217
+ config: {
218
+ auth: {
219
+ admin: true
220
+ }
221
+ }
222
+ },
223
+ {
224
+ method: "POST",
225
+ path: "/products",
226
+ handler: "stripeController.createProduct",
227
+ config: {
228
+ auth: {
229
+ admin: true
230
+ }
231
+ }
232
+ },
233
+ {
234
+ method: "GET",
235
+ path: "/products",
236
+ handler: "stripeController.listProducts",
237
+ config: {
238
+ auth: {
239
+ admin: true
240
+ }
241
+ }
242
+ },
243
+ {
244
+ method: "PUT",
245
+ path: "/products/:id",
246
+ handler: "stripeController.updateProduct",
247
+ config: {
248
+ auth: {
249
+ admin: true
250
+ }
251
+ }
252
+ },
253
+ {
254
+ method: "DELETE",
255
+ path: "/products/:productId&:priceId",
256
+ handler: "stripeController.deleteProduct",
257
+ config: {
258
+ auth: {
259
+ admin: true
260
+ }
261
+ }
262
+ },
263
+ {
264
+ method: "DELETE",
265
+ path: "/prices/:productId&:priceId&:newPriceId",
266
+ handler: "stripeController.deletePrice",
267
+ config: {
268
+ auth: {
269
+ admin: true
270
+ }
271
+ }
272
+ }
273
+ ]
274
+ });
275
+ const routes = {
276
+ "content-api": contentAPIRoutes,
277
+ admin: adminAPIRoutes
278
+ };
279
+ const stripeService = ({ strapi }) => ({
280
+ /* ============================
281
+ * STRIPE CLIENT
282
+ * ============================ */
283
+ stripeClient(env) {
284
+ const key = env === "live" ? process.env.STRAPI_ADMIN_LIVE_STRIPE_SECRET_KEY : process.env.STRAPI_ADMIN_TEST_STRIPE_SECRET_KEY;
285
+ if (!key) {
286
+ throw new Error(`Missing Stripe secret key (${env})`);
287
+ }
288
+ return new Stripe__default.default(key);
289
+ }
290
+ });
291
+ const services = {
292
+ stripeService
293
+ };
294
+ const index = {
295
+ bootstrap,
296
+ destroy,
297
+ register,
298
+ config,
299
+ controllers,
300
+ contentTypes,
301
+ middlewares,
302
+ policies,
303
+ routes,
304
+ services
305
+ };
306
+ module.exports = index;
@@ -0,0 +1,304 @@
1
+ import axios from "axios";
2
+ import Stripe from "stripe";
3
+ const bootstrap = ({ strapi }) => {
4
+ };
5
+ const destroy = ({ strapi }) => {
6
+ };
7
+ const register = ({ strapi }) => {
8
+ };
9
+ const config = {
10
+ default: {},
11
+ validator() {
12
+ }
13
+ };
14
+ const contentTypes = {};
15
+ const stripeController = ({ strapi }) => ({
16
+ async stripeService() {
17
+ return strapi.plugin("strapi5-plugin-for-stripe").service("stripeService");
18
+ },
19
+ /* ============================
20
+ * SETTINGS
21
+ * ============================ */
22
+ async getSettingsInternal() {
23
+ return await strapi.store({ type: "plugin", name: "strapi5-plugin-for-stripe" }).get({ key: "settings" });
24
+ },
25
+ async getSettings(ctx) {
26
+ const settings = await this.getSettingsInternal();
27
+ ctx.body = settings || {};
28
+ },
29
+ async updateSettings(ctx) {
30
+ const data = ctx.request.body;
31
+ if (data.checkout?.successUrl) {
32
+ const u = new URL(data.checkout.successUrl);
33
+ if (data.environment === "live" && u.protocol !== "https:") {
34
+ throw new Error("successUrl must be HTTPS in live mode");
35
+ }
36
+ }
37
+ if (data.checkout?.cancelUrl) {
38
+ const u = new URL(data.checkout.cancelUrl);
39
+ if (data.environment === "live" && u.protocol !== "https:") {
40
+ throw new Error("cancelUrl must be HTTPS in live mode");
41
+ }
42
+ }
43
+ await strapi.store({ type: "plugin", name: "strapi5-plugin-for-stripe" }).set({ key: "settings", value: data });
44
+ ctx.body = { ok: true };
45
+ },
46
+ /* ============================
47
+ * PRODUCTS
48
+ * ============================ */
49
+ async createProduct(ctx) {
50
+ const settings = await this.getSettingsInternal();
51
+ const service = await this.stripeService();
52
+ const stripe = service.stripeClient(settings.environment || "test");
53
+ ctx.body = await stripe.prices.create(ctx.request.body);
54
+ },
55
+ async listProducts(ctx) {
56
+ const settings = await this.getSettingsInternal();
57
+ const service = await this.stripeService();
58
+ const stripe = service.stripeClient(settings.environment || "test");
59
+ ctx.body = {
60
+ prices: (await stripe.prices.list({
61
+ limit: ctx.query.limit || 20,
62
+ active: ctx.query.active || true
63
+ })).data,
64
+ products: (await stripe.products.list({
65
+ limit: ctx.query.limit || 20,
66
+ active: ctx.query.active || true
67
+ })).data
68
+ };
69
+ },
70
+ async updateProduct(ctx) {
71
+ const settings = await this.getSettingsInternal();
72
+ const service = await this.stripeService();
73
+ const stripe = service.stripeClient(settings.environment || "test");
74
+ ctx.body = await stripe.products.update(ctx.params.id, ctx.request.body);
75
+ },
76
+ async deleteProduct(ctx) {
77
+ const settings = await this.getSettingsInternal();
78
+ const service = await this.stripeService();
79
+ const stripe = service.stripeClient(settings.environment || "test");
80
+ ctx.body = {
81
+ productRes: await stripe.products.update(ctx.params.productId, {
82
+ active: false
83
+ }),
84
+ priceRes: await stripe.prices.update(ctx.params.priceId, {
85
+ active: false
86
+ })
87
+ };
88
+ },
89
+ async deletePrice(ctx) {
90
+ const settings = await this.getSettingsInternal();
91
+ const service = await this.stripeService();
92
+ const stripe = service.stripeClient(settings.environment || "test");
93
+ ctx.body = {
94
+ productRes: await stripe.products.update(ctx.params.productId, {
95
+ default_price: ctx.params.newPriceId
96
+ }),
97
+ priceRes: await stripe.prices.update(ctx.params.priceId, {
98
+ active: false
99
+ })
100
+ };
101
+ },
102
+ /* ============================
103
+ * CHECKOUT
104
+ * ============================ */
105
+ async checkout(ctx) {
106
+ const settings = await this.getSettingsInternal();
107
+ const service = await this.stripeService();
108
+ const stripe = service.stripeClient(settings.environment || "test");
109
+ const {
110
+ priceId,
111
+ customer_email,
112
+ productId,
113
+ productName,
114
+ metadata = {}
115
+ } = ctx.request.body;
116
+ if (!priceId || !customer_email) {
117
+ ctx.throw(400, "Missing priceId or customer_email");
118
+ }
119
+ const session = await stripe.checkout.sessions.create({
120
+ mode: "payment",
121
+ line_items: [
122
+ {
123
+ price: priceId,
124
+ quantity: 1
125
+ }
126
+ ],
127
+ customer_email,
128
+ success_url: settings.checkout.successUrl + "?sessionId={CHECKOUT_SESSION_ID}",
129
+ cancel_url: settings.checkout.cancelUrl,
130
+ metadata: {
131
+ productId,
132
+ productName,
133
+ ...metadata
134
+ }
135
+ });
136
+ ctx.body = {
137
+ url: session.url
138
+ };
139
+ },
140
+ /* ============================
141
+ * WEBHOOK
142
+ * ============================ */
143
+ async webhook(ctx) {
144
+ const settings = await this.getSettingsInternal();
145
+ const service = await this.stripeService();
146
+ const stripe = service.stripeClient(settings.environment || "test");
147
+ const signature = ctx.request.headers["stripe-signature"];
148
+ const webhookSecret = process.env.STRAPI_ADMIN_STRIPE_WEBHOOK_SECRET_KEY;
149
+ const forwardUrl = settings.webhook?.forwardUrl;
150
+ if (!signature || !webhookSecret) {
151
+ ctx.throw(400, "Webhook configuration missing");
152
+ }
153
+ const rawBody = ctx.request.body?.[Symbol.for("unparsedBody")] ?? ctx.request.body;
154
+ let event;
155
+ try {
156
+ event = stripe.webhooks.constructEvent(rawBody, signature, webhookSecret);
157
+ } catch (err) {
158
+ ctx.throw(400, "Invalid Stripe webhook signature");
159
+ }
160
+ if (forwardUrl) {
161
+ await axios.post(forwardUrl, event, {
162
+ headers: {
163
+ "Content-Type": "application/json",
164
+ "Stripe-Event-Id": event.id,
165
+ "Stripe-Event-Type": event.type
166
+ },
167
+ timeout: 1e4
168
+ });
169
+ }
170
+ ctx.body = { received: true };
171
+ }
172
+ });
173
+ const controllers = {
174
+ stripeController
175
+ };
176
+ const middlewares = {};
177
+ const policies = {};
178
+ const contentAPIRoutes = () => ({
179
+ type: "content-api",
180
+ routes: [
181
+ {
182
+ method: "POST",
183
+ path: "/checkout",
184
+ handler: "stripeController.checkout"
185
+ },
186
+ {
187
+ method: "POST",
188
+ path: "/webhook",
189
+ handler: "stripeController.webhook",
190
+ config: {
191
+ auth: false
192
+ }
193
+ }
194
+ ]
195
+ });
196
+ const adminAPIRoutes = () => ({
197
+ type: "admin",
198
+ routes: [
199
+ {
200
+ method: "GET",
201
+ path: "/settings",
202
+ handler: "stripeController.getSettings",
203
+ config: {
204
+ auth: {
205
+ admin: true
206
+ }
207
+ }
208
+ },
209
+ {
210
+ method: "PUT",
211
+ path: "/settings",
212
+ handler: "stripeController.updateSettings",
213
+ config: {
214
+ auth: {
215
+ admin: true
216
+ }
217
+ }
218
+ },
219
+ {
220
+ method: "POST",
221
+ path: "/products",
222
+ handler: "stripeController.createProduct",
223
+ config: {
224
+ auth: {
225
+ admin: true
226
+ }
227
+ }
228
+ },
229
+ {
230
+ method: "GET",
231
+ path: "/products",
232
+ handler: "stripeController.listProducts",
233
+ config: {
234
+ auth: {
235
+ admin: true
236
+ }
237
+ }
238
+ },
239
+ {
240
+ method: "PUT",
241
+ path: "/products/:id",
242
+ handler: "stripeController.updateProduct",
243
+ config: {
244
+ auth: {
245
+ admin: true
246
+ }
247
+ }
248
+ },
249
+ {
250
+ method: "DELETE",
251
+ path: "/products/:productId&:priceId",
252
+ handler: "stripeController.deleteProduct",
253
+ config: {
254
+ auth: {
255
+ admin: true
256
+ }
257
+ }
258
+ },
259
+ {
260
+ method: "DELETE",
261
+ path: "/prices/:productId&:priceId&:newPriceId",
262
+ handler: "stripeController.deletePrice",
263
+ config: {
264
+ auth: {
265
+ admin: true
266
+ }
267
+ }
268
+ }
269
+ ]
270
+ });
271
+ const routes = {
272
+ "content-api": contentAPIRoutes,
273
+ admin: adminAPIRoutes
274
+ };
275
+ const stripeService = ({ strapi }) => ({
276
+ /* ============================
277
+ * STRIPE CLIENT
278
+ * ============================ */
279
+ stripeClient(env) {
280
+ const key = env === "live" ? process.env.STRAPI_ADMIN_LIVE_STRIPE_SECRET_KEY : process.env.STRAPI_ADMIN_TEST_STRIPE_SECRET_KEY;
281
+ if (!key) {
282
+ throw new Error(`Missing Stripe secret key (${env})`);
283
+ }
284
+ return new Stripe(key);
285
+ }
286
+ });
287
+ const services = {
288
+ stripeService
289
+ };
290
+ const index = {
291
+ bootstrap,
292
+ destroy,
293
+ register,
294
+ config,
295
+ controllers,
296
+ contentTypes,
297
+ middlewares,
298
+ policies,
299
+ routes,
300
+ services
301
+ };
302
+ export {
303
+ index as default
304
+ };
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
- "version": "1.0.0",
2
+ "version": "1.0.2",
3
3
  "keywords": [],
4
- "type": "commonjs",
5
4
  "exports": {
6
5
  "./package.json": "./package.json",
7
6
  "./strapi-admin": {
@@ -22,6 +21,7 @@
22
21
  ],
23
22
  "scripts": {
24
23
  "build": "strapi-plugin build",
24
+ "prepack": "yarn build",
25
25
  "watch": "strapi-plugin watch",
26
26
  "watch:link": "strapi-plugin watch:link",
27
27
  "verify": "strapi-plugin verify"