@payloadcms/plugin-stripe 0.0.9 → 0.0.10
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
CHANGED
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
A plugin for [Payload CMS](https://github.com/payloadcms/payload) to connect [Stripe](https://stripe.com) and Payload.
|
|
6
6
|
|
|
7
7
|
Core features:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
8
|
+
|
|
9
|
+
- Hides your Stripe credentials when shipping SaaS applications
|
|
10
|
+
- Allows restricted keys through [Payload access control](https://payloadcms.com/docs/access-control/overview)
|
|
11
|
+
- Enables a two-way communication channel between Stripe and Payload
|
|
12
|
+
- Proxies the [Stripe REST API](https://stripe.com/docs/api)
|
|
13
|
+
- Proxies [Stripe webhooks](https://stripe.com/docs/webhooks)
|
|
14
|
+
- Automatically syncs data between the two platforms
|
|
14
15
|
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
@@ -25,15 +26,15 @@ Core features:
|
|
|
25
26
|
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
|
26
27
|
|
|
27
28
|
```js
|
|
28
|
-
import { buildConfig } from
|
|
29
|
-
import stripePlugin from
|
|
29
|
+
import { buildConfig } from "payload/config";
|
|
30
|
+
import stripePlugin from "@payloadcms/plugin-stripe";
|
|
30
31
|
|
|
31
32
|
const config = buildConfig({
|
|
32
33
|
plugins: [
|
|
33
34
|
stripePlugin({
|
|
34
35
|
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
|
|
35
|
-
})
|
|
36
|
-
]
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
export default config;
|
|
@@ -70,8 +71,8 @@ This option will setup a basic sync between Payload collections and Stripe resou
|
|
|
70
71
|
> NOTE: Due to limitations in the Stripe API, this currently only works with top-level fields. This is because every Stripe object is a separate entity, making it difficult to abstract into a simple reusable library. In the future, we may find a pattern around this. But for now, cases like that will need to be hard-coded. See the [demo](./demo) for an example of this.
|
|
71
72
|
|
|
72
73
|
```js
|
|
73
|
-
import { buildConfig } from
|
|
74
|
-
import stripePlugin from
|
|
74
|
+
import { buildConfig } from "payload/config";
|
|
75
|
+
import stripePlugin from "@payloadcms/plugin-stripe";
|
|
75
76
|
|
|
76
77
|
const config = buildConfig({
|
|
77
78
|
plugins: [
|
|
@@ -80,19 +81,19 @@ const config = buildConfig({
|
|
|
80
81
|
stripeWebhooksEndpointSecret: process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET,
|
|
81
82
|
sync: [
|
|
82
83
|
{
|
|
83
|
-
collection:
|
|
84
|
-
stripeResourceType:
|
|
85
|
-
stripeResourceTypeSingular:
|
|
84
|
+
collection: "customers",
|
|
85
|
+
stripeResourceType: "customers",
|
|
86
|
+
stripeResourceTypeSingular: "customer",
|
|
86
87
|
fields: [
|
|
87
88
|
{
|
|
88
|
-
fieldPath:
|
|
89
|
-
stripeProperty:
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
})
|
|
95
|
-
]
|
|
89
|
+
fieldPath: "name", // this is a field on your own Payload config
|
|
90
|
+
stripeProperty: "name", // use dot notation, if applicable
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
96
97
|
});
|
|
97
98
|
|
|
98
99
|
export default config;
|
|
@@ -116,27 +117,29 @@ Using `sync` will do the following:
|
|
|
116
117
|
|
|
117
118
|
The following custom endpoints are automatically opened for you:
|
|
118
119
|
|
|
119
|
-
>NOTE: the `/api` part of these routes may be different based on the settings defined in your Payload config.
|
|
120
|
+
> NOTE: the `/api` part of these routes may be different based on the settings defined in your Payload config.
|
|
120
121
|
|
|
121
122
|
- #### `POST /api/stripe/rest`
|
|
122
123
|
|
|
123
124
|
Proxies the [Stripe REST API](https://stripe.com/docs/api) behind [Payload access control](https://payloadcms.com/docs/access-control/overview) and returns the result. If you need to proxy the API server-side, use the [stripeProxy](#node) function.
|
|
124
125
|
|
|
125
126
|
```js
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
127
|
+
const res = await fetch(`/api/stripe/rest`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
credentials: "include",
|
|
130
|
+
headers: {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
// Authorization: `JWT ${token}` // NOTE: do this if not in a browser (i.e. curl or Postman)
|
|
133
|
+
},
|
|
134
|
+
body: JSON.stringify({
|
|
135
|
+
stripeMethod: "stripe.subscriptions.list",
|
|
136
|
+
stripeArgs: [
|
|
137
|
+
{
|
|
138
|
+
customer: "abc",
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
140
143
|
```
|
|
141
144
|
|
|
142
145
|
- #### `POST /stripe/webhooks`
|
|
@@ -148,11 +151,13 @@ The following custom endpoints are automatically opened for you:
|
|
|
148
151
|
[Stripe webhooks](https://stripe.com/docs/webhooks) are used to sync from Stripe to Payload. Webhooks listen for events on your Stripe account so you can trigger reactions to them. Follow the steps below to enable webhooks.
|
|
149
152
|
|
|
150
153
|
Development:
|
|
154
|
+
|
|
151
155
|
1. Login using Stripe cli `stripe login`
|
|
152
156
|
1. Forward events to localhost `stripe listen --forward-to localhost:3000/stripe/webhooks`
|
|
153
157
|
1. Paste the given secret into your `.env` file as `STRIPE_WEBHOOKS_ENDPOINT_SECRET`
|
|
154
158
|
|
|
155
159
|
Production:
|
|
160
|
+
|
|
156
161
|
1. Login and [create a new webhook](https://dashboard.stripe.com/test/webhooks/create) from the Stripe dashboard
|
|
157
162
|
1. Paste `YOUR_DOMAIN_NAME/api/stripe/webhooks` as the "Webhook Endpoint URL"
|
|
158
163
|
1. Select which events to broadcast
|
|
@@ -160,8 +165,8 @@ Production:
|
|
|
160
165
|
1. Then, handle these events using the `webhooks` portion of this plugin's config:
|
|
161
166
|
|
|
162
167
|
```js
|
|
163
|
-
import { buildConfig } from
|
|
164
|
-
import stripePlugin from
|
|
168
|
+
import { buildConfig } from "payload/config";
|
|
169
|
+
import stripePlugin from "@payloadcms/plugin-stripe";
|
|
165
170
|
|
|
166
171
|
const config = buildConfig({
|
|
167
172
|
plugins: [
|
|
@@ -169,10 +174,10 @@ const config = buildConfig({
|
|
|
169
174
|
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
|
|
170
175
|
stripeWebhooksEndpointSecret: process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET,
|
|
171
176
|
webhooks: {
|
|
172
|
-
|
|
177
|
+
"customer.subscription.updated": ({ event, stripe, stripeConfig }) => {
|
|
173
178
|
// DO SOMETHING
|
|
174
|
-
}
|
|
175
|
-
}
|
|
179
|
+
},
|
|
180
|
+
},
|
|
176
181
|
// NOTE: you can also catch all Stripe webhook events and handle the event types yourself
|
|
177
182
|
// webhooks: (event, stripe, stripeConfig) => {
|
|
178
183
|
// switch (event.type): {
|
|
@@ -185,8 +190,8 @@ const config = buildConfig({
|
|
|
185
190
|
// }
|
|
186
191
|
// }
|
|
187
192
|
// }
|
|
188
|
-
})
|
|
189
|
-
]
|
|
193
|
+
}),
|
|
194
|
+
],
|
|
190
195
|
});
|
|
191
196
|
|
|
192
197
|
export default config;
|
|
@@ -199,10 +204,10 @@ For a full list of available webhooks, see [here](https://stripe.com/docs/cli/tr
|
|
|
199
204
|
On the server you should interface with Stripe directly using the [stripe](https://www.npmjs.com/package/stripe) npm module. That might look something like this:
|
|
200
205
|
|
|
201
206
|
```js
|
|
202
|
-
import Stripe from
|
|
207
|
+
import Stripe from "stripe";
|
|
203
208
|
|
|
204
209
|
const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
|
|
205
|
-
const stripe = new Stripe(stripeSecretKey, { apiVersion:
|
|
210
|
+
const stripe = new Stripe(stripeSecretKey, { apiVersion: "2022-08-01" });
|
|
206
211
|
|
|
207
212
|
export const MyFunction = async () => {
|
|
208
213
|
try {
|
|
@@ -214,22 +219,24 @@ export const MyFunction = async () => {
|
|
|
214
219
|
} catch (error) {
|
|
215
220
|
console.error(error.message);
|
|
216
221
|
}
|
|
217
|
-
}
|
|
222
|
+
};
|
|
218
223
|
```
|
|
219
224
|
|
|
220
225
|
Alternatively, you can interface with the Stripe using the `stripeProxy`, which is exactly what the `/api/stripe/rest` endpoint does behind-the-scenes. Here's the same example as above, but piped through the proxy:
|
|
221
226
|
|
|
222
227
|
```js
|
|
223
|
-
import { stripeProxy } from
|
|
228
|
+
import { stripeProxy } from "@payloadcms/plugin-stripe";
|
|
224
229
|
|
|
225
230
|
export const MyFunction = async () => {
|
|
226
231
|
try {
|
|
227
232
|
const customer = await stripeProxy({
|
|
228
233
|
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
|
|
229
|
-
stripeMethod:
|
|
230
|
-
stripeArgs:
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
stripeMethod: "customers.create",
|
|
235
|
+
stripeArgs: [
|
|
236
|
+
{
|
|
237
|
+
email: data.email,
|
|
238
|
+
},
|
|
239
|
+
],
|
|
233
240
|
});
|
|
234
241
|
|
|
235
242
|
if (customer.status === 200) {
|
|
@@ -242,7 +249,7 @@ export const MyFunction = async () => {
|
|
|
242
249
|
} catch (error) {
|
|
243
250
|
console.error(error.message);
|
|
244
251
|
}
|
|
245
|
-
}
|
|
252
|
+
};
|
|
246
253
|
```
|
|
247
254
|
|
|
248
255
|
## TypeScript
|
package/dist/routes/rest.js
CHANGED
|
@@ -40,7 +40,7 @@ exports.stripeREST = void 0;
|
|
|
40
40
|
var errors_1 = require("payload/errors");
|
|
41
41
|
var stripeProxy_1 = require("../utilities/stripeProxy");
|
|
42
42
|
var stripeREST = function (args) { return __awaiter(void 0, void 0, void 0, function () {
|
|
43
|
-
var req, res, next, stripeConfig, payload, user, _a, stripeMethod, stripeArgs // example: 'cus_MGgt3Tuj3D66f2'
|
|
43
|
+
var req, res, next, stripeConfig, payload, user, _a, stripeMethod, stripeArgs // example: ['cus_MGgt3Tuj3D66f2'] or [{ limit: 100 }, { stripeAccount: 'acct_1J9Z4pKZ4Z4Z4Z4Z' }]
|
|
44
44
|
, stripeSecretKey, pluginRes, status_1, error_1, message;
|
|
45
45
|
return __generator(this, function (_b) {
|
|
46
46
|
switch (_b.label) {
|
|
@@ -57,7 +57,7 @@ var stripeREST = function (args) { return __awaiter(void 0, void 0, void 0, func
|
|
|
57
57
|
return [4 /*yield*/, (0, stripeProxy_1.stripeProxy)({
|
|
58
58
|
stripeSecretKey: stripeSecretKey,
|
|
59
59
|
stripeMethod: stripeMethod,
|
|
60
|
-
stripeArgs: stripeArgs
|
|
60
|
+
stripeArgs: stripeArgs
|
|
61
61
|
})];
|
|
62
62
|
case 2:
|
|
63
63
|
pluginRes = _b.sent();
|
package/dist/routes/rest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../src/routes/rest.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,yCAA2C;AAG3C,wDAAuD;AAEhD,IAAM,UAAU,GAAG,UAAO,IAKhC;;;;;;gBAEG,GAAG,GAID,IAAI,IAJH,EACH,GAAG,GAGD,IAAI,IAHH,EACH,IAAI,GAEF,IAAI,KAFF,EACJ,YAAY,GACV,IAAI,aADM,CACL;gBAGP,OAAO,GAML,GAAG,QANE,EACP,IAAI,GAKF,GAAG,KALD,EACJ,KAIE,GAAG,KADJ,EAFC,YAAY,kBAAA,EACZ,UAAU,gBAAA,CAEN;gBAEA,eAAe,GAAK,YAAY,gBAAjB,CAAkB;;;;gBAGvC,IAAI,CAAC,IAAI,EAAE,EAAE,+CAA+C;oBAC1D,MAAM,IAAI,kBAAS,EAAE,CAAC;iBACvB;gBAEiB,qBAAM,IAAA,yBAAW,EAAC;wBAClC,eAAe,iBAAA;wBACf,YAAY,cAAA;wBACZ,UAAU,YAAA
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../src/routes/rest.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,yCAA2C;AAG3C,wDAAuD;AAEhD,IAAM,UAAU,GAAG,UAAO,IAKhC;;;;;;gBAEG,GAAG,GAID,IAAI,IAJH,EACH,GAAG,GAGD,IAAI,IAHH,EACH,IAAI,GAEF,IAAI,KAFF,EACJ,YAAY,GACV,IAAI,aADM,CACL;gBAGP,OAAO,GAML,GAAG,QANE,EACP,IAAI,GAKF,GAAG,KALD,EACJ,KAIE,GAAG,KADJ,EAFC,YAAY,kBAAA,EACZ,UAAU,gBAAA,CAEN;gBAEA,eAAe,GAAK,YAAY,gBAAjB,CAAkB;;;;gBAGvC,IAAI,CAAC,IAAI,EAAE,EAAE,+CAA+C;oBAC1D,MAAM,IAAI,kBAAS,EAAE,CAAC;iBACvB;gBAEiB,qBAAM,IAAA,yBAAW,EAAC;wBAClC,eAAe,iBAAA;wBACf,YAAY,cAAA;wBACZ,UAAU,YAAA;qBACX,CAAC,EAAA;;gBAJI,SAAS,GAAG,SAIhB;gBAGA,WACE,SAAS,OADL,CACM;gBAEd,GAAG,CAAC,MAAM,CAAC,QAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;;;;gBAG7B,OAAO,GAAG,oEAA6D,OAAK,MAAG,CAAC;gBACtF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC9B,sBAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;wBAC1B,OAAO,SAAA;qBACR,CAAC,EAAC;;;;KAEN,CAAC;AAhDW,QAAA,UAAU,cAgDrB"}
|
|
@@ -56,15 +56,16 @@ var stripeProxy = function (_a) {
|
|
|
56
56
|
url: 'https://payloadcms.com',
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
|
-
if (!(typeof stripeMethod === 'string')) return [3 /*break*/,
|
|
59
|
+
if (!(typeof stripeMethod === 'string')) return [3 /*break*/, 9];
|
|
60
60
|
topLevelMethod = stripeMethod.split('.')[0];
|
|
61
61
|
contextToBind = stripe[topLevelMethod];
|
|
62
62
|
foundMethod = (0, lodash_get_1.default)(stripe, stripeMethod).bind(contextToBind);
|
|
63
|
-
if (!(typeof foundMethod === 'function')) return [3 /*break*/,
|
|
63
|
+
if (!(typeof foundMethod === 'function')) return [3 /*break*/, 7];
|
|
64
|
+
if (!Array.isArray(stripeArgs)) return [3 /*break*/, 5];
|
|
64
65
|
_b.label = 1;
|
|
65
66
|
case 1:
|
|
66
67
|
_b.trys.push([1, 3, , 4]);
|
|
67
|
-
return [4 /*yield*/, foundMethod(stripeArgs)];
|
|
68
|
+
return [4 /*yield*/, foundMethod.apply(void 0, stripeArgs)];
|
|
68
69
|
case 2:
|
|
69
70
|
stripeResponse = _b.sent();
|
|
70
71
|
return [2 /*return*/, {
|
|
@@ -78,10 +79,12 @@ var stripeProxy = function (_a) {
|
|
|
78
79
|
message: "A Stripe API error has occurred: ".concat(error_1)
|
|
79
80
|
}];
|
|
80
81
|
case 4: return [3 /*break*/, 6];
|
|
81
|
-
case 5: throw Error("
|
|
82
|
+
case 5: throw new Error("Argument 'stripeArgs' must be an array.");
|
|
82
83
|
case 6: return [3 /*break*/, 8];
|
|
83
|
-
case 7: throw Error('
|
|
84
|
-
case 8: return [
|
|
84
|
+
case 7: throw Error("The provided Stripe method of '".concat(stripeMethod, "' is not a part of the Stripe API."));
|
|
85
|
+
case 8: return [3 /*break*/, 10];
|
|
86
|
+
case 9: throw Error('You must provide a Stripe method to call.');
|
|
87
|
+
case 10: return [2 /*return*/];
|
|
85
88
|
}
|
|
86
89
|
});
|
|
87
90
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stripeProxy.js","sourceRoot":"","sources":["../../src/utilities/stripeProxy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0DAAmC;AACnC,kDAA4B;AAGrB,IAAM,WAAW,GAAgB,UAAO,EAI9C;QAHC,eAAe,qBAAA,EACf,YAAY,kBAAA,EACZ,UAAU,gBAAA;;;;;;oBAEJ,MAAM,GAAG,IAAI,gBAAM,CAAC,eAAe,EAAE;wBACzC,UAAU,EAAE,YAAY;wBACxB,OAAO,EAAE;4BACP,IAAI,EAAE,uBAAuB;4BAC7B,GAAG,EAAE,wBAAwB;yBAC9B;qBACF,CAAC,CAAC;yBAEC,CAAA,OAAO,YAAY,KAAK,QAAQ,CAAA,EAAhC,wBAAgC;oBAC5B,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAiB,CAAC;oBAC5D,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;oBAGvC,WAAW,GAAG,IAAA,oBAAS,EAAC,MAAM,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;yBAEpE,CAAA,OAAO,WAAW,KAAK,UAAU,CAAA,EAAjC,wBAAiC;;;;
|
|
1
|
+
{"version":3,"file":"stripeProxy.js","sourceRoot":"","sources":["../../src/utilities/stripeProxy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,0DAAmC;AACnC,kDAA4B;AAGrB,IAAM,WAAW,GAAgB,UAAO,EAI9C;QAHC,eAAe,qBAAA,EACf,YAAY,kBAAA,EACZ,UAAU,gBAAA;;;;;;oBAEJ,MAAM,GAAG,IAAI,gBAAM,CAAC,eAAe,EAAE;wBACzC,UAAU,EAAE,YAAY;wBACxB,OAAO,EAAE;4BACP,IAAI,EAAE,uBAAuB;4BAC7B,GAAG,EAAE,wBAAwB;yBAC9B;qBACF,CAAC,CAAC;yBAEC,CAAA,OAAO,YAAY,KAAK,QAAQ,CAAA,EAAhC,wBAAgC;oBAC5B,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAiB,CAAC;oBAC5D,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;oBAGvC,WAAW,GAAG,IAAA,oBAAS,EAAC,MAAM,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;yBAEpE,CAAA,OAAO,WAAW,KAAK,UAAU,CAAA,EAAjC,wBAAiC;yBAC/B,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAzB,wBAAyB;;;;oBAEF,qBAAM,WAAW,eAAI,UAAU,GAAC;;oBAAjD,cAAc,GAAG,SAAgC;oBACvD,sBAAO;4BACL,MAAM,EAAE,GAAG;4BACX,IAAI,EAAE,cAAc;yBACrB,EAAC;;;oBAEF,sBAAO;4BACL,MAAM,EAAE,GAAG;4BACX,OAAO,EAAE,2CAAoC,OAAK,CAAE;yBACrD,EAAC;;wBAGJ,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;;wBAG7D,MAAM,KAAK,CAAC,yCAAkC,YAAY,uCAAoC,CAAC,CAAA;;wBAGjG,MAAM,KAAK,CAAC,2CAA2C,CAAC,CAAA;;;;;CAE3D,CAAA;AA3CY,QAAA,WAAW,eA2CvB"}
|
package/package.json
CHANGED