@live-change/stripe-service 0.8.108 → 0.8.110

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/LICENSE.md ADDED
@@ -0,0 +1,11 @@
1
+ Copyright 2019-2024 Michał Łaszczewski
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/index.js CHANGED
@@ -4,6 +4,7 @@ const app = App.app()
4
4
  import definition from './definition.js'
5
5
 
6
6
  import "./payment.js"
7
+ import "./stripeEvents.js"
7
8
  import "./webhook.js"
8
9
 
9
10
  export default definition
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/stripe-service",
3
- "version": "0.8.108",
3
+ "version": "0.8.110",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,14 +21,14 @@
21
21
  "url": "https://www.viamage.com/"
22
22
  },
23
23
  "dependencies": {
24
- "@live-change/framework": "^0.8.108",
25
- "@live-change/relations-plugin": "^0.8.108",
24
+ "@live-change/framework": "^0.8.110",
25
+ "@live-change/relations-plugin": "^0.8.110",
26
26
  "lru-cache": "^7.12.0",
27
27
  "pluralize": "^8.0.0",
28
28
  "progress-stream": "^2.0.0",
29
29
  "prosemirror-model": "^1.18.1",
30
30
  "stripe": "^17.2.1"
31
31
  },
32
- "gitHead": "b272a01967e326d10874fea13353ab8fa5c30fe8",
32
+ "gitHead": "8af31d640f43b00b2874f2c70fa4d4486541adfe",
33
33
  "type": "module"
34
34
  }
package/payment.js CHANGED
@@ -4,7 +4,7 @@ const app = App.app()
4
4
  import definition from './definition.js'
5
5
  import config from './config.js'
6
6
 
7
- import stripe from 'stripe'
7
+ import stripe from "./stripeClient.js"
8
8
 
9
9
  const itemsArray = {
10
10
  type: Array,
@@ -54,10 +54,18 @@ const paymentParameters = {
54
54
  cancelUrl: {
55
55
  type: String,
56
56
  validation: ['nonEmpty']
57
+ },
58
+ payerType: {
59
+ type: String,
60
+ validation: ['nonEmpty']
61
+ },
62
+ payer: {
63
+ type: String,
64
+ validation: ['nonEmpty']
57
65
  }
58
66
  }
59
67
 
60
- definition.model({
68
+ const Payment = definition.model({
61
69
  name: "Payment",
62
70
  entity:{
63
71
  },
@@ -65,7 +73,7 @@ definition.model({
65
73
  ...paymentParameters,
66
74
  state: {
67
75
  type: String,
68
- options: ['created', 'succeeded', 'failed', 'refunded']
76
+ options: ['created', 'pending', 'succeeded', 'failed', 'refunded']
69
77
  },
70
78
  stripeSession: {
71
79
  type: String
@@ -75,21 +83,31 @@ definition.model({
75
83
  }
76
84
  })
77
85
 
86
+ export { Payment}
87
+
78
88
  definition.trigger({
79
89
  name: 'startPayment',
80
90
  properties: {
81
91
  ...paymentParameters
82
92
  },
83
- async execute({ items, causeType, cause, successUrl, cancelUrl }, { client, service }, emit) {
84
- console.log("STRIPE SECRET KEY", config.secretKey)
93
+ waitForEvents:true,
94
+ async execute({ items, causeType, cause, successUrl, cancelUrl, payerType, payer }, { service }, emit) {
85
95
  const payment = app.generateUid()
86
- const stripeClient = stripe(config.secretKey)
87
96
  console.log("URLS", {
88
97
  success_url: successUrl ?? (config.checkoutSuccessUrl + '/' + payment),
89
98
  cancel_url: cancelUrl ?? (config.checkoutCancelUrl + '/' + payment)
90
99
  })
91
- const session = await stripeClient.checkout.sessions.create({
100
+ const metadata = {
101
+ type: 'payment',
102
+ payment
103
+ }
104
+ const session = await stripe.checkout.sessions.create({
92
105
  payment_method_types: ['card'],
106
+ client_reference_id: 'payment:'+payment,
107
+ // customer: // store stripe customer id ?
108
+ // customer_creation: 'always'
109
+ /// TODO:
110
+ // customer_email: /// get from contacts
93
111
  line_items: items.map(item => ({
94
112
  price_data: {
95
113
  currency: item.currency,
@@ -102,6 +120,13 @@ definition.trigger({
102
120
  },
103
121
  quantity: item.quantity
104
122
  })),
123
+ invoice_creation: {
124
+ enabled: true
125
+ },
126
+ metadata,
127
+ payment_intent_data: {
128
+ metadata
129
+ },
105
130
  mode: 'payment',
106
131
  success_url: successUrl ?? (config.checkoutSuccessUrl + '/' + payment),
107
132
  cancel_url: cancelUrl ?? (config.checkoutCancelUrl + '/' + payment)
@@ -110,7 +135,7 @@ definition.trigger({
110
135
  type: 'PaymentCreated',
111
136
  payment,
112
137
  data: {
113
- items, causeType, cause,
138
+ items, causeType, cause, payerType, payer,
114
139
  stripeSession: session.id,
115
140
  state: 'created'
116
141
  }
@@ -122,4 +147,3 @@ definition.trigger({
122
147
  }
123
148
  }
124
149
  })
125
-
@@ -0,0 +1,8 @@
1
+ import stripe from 'stripe'
2
+
3
+ import config from './config.js'
4
+
5
+ console.log("STRIPE SECRET KEY", config.secretKey)
6
+ const stripeClient = stripe(config.secretKey)
7
+
8
+ export default stripeClient
@@ -0,0 +1,323 @@
1
+ import App from '@live-change/framework'
2
+ const app = App.app()
3
+
4
+ import definition from './definition.js'
5
+ import config from './config.js'
6
+
7
+ import stripe from "./stripeClient.js"
8
+
9
+ import { Payment } from './payment.js'
10
+
11
+
12
+ /// TODO: obsługa zdarzeń:
13
+ /// dla stanu płatności:
14
+ /// charge.succeeded
15
+ /// charge.refunded
16
+
17
+
18
+ definition.trigger({
19
+ name: 'stripeEvent.checkout.session.completed',
20
+ properties: {
21
+ data: {
22
+ type: Object,
23
+ properties: {
24
+ object: {
25
+ type: Object,
26
+ properties: {
27
+ client_reference_id: {
28
+ type: String,
29
+ validation: ['nonEmpty']
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ },
36
+ async execute({ data: { object } }, { triggerService, trigger }, emit) {
37
+ //console.log('stripeEvent.checkout.session.completed', object)
38
+ const id = object.client_reference_id
39
+ const referenceType = id.slice(0, id.indexOf(':'))
40
+ const referenceId = id.slice(id.indexOf(':') + 1)
41
+ if(referenceType === 'payment') {
42
+ const payment = await Payment.get(referenceId)
43
+ if(!payment) throw new Error('Payment '+referenceId+' not found')
44
+ if(object.payment_status === 'paid') {
45
+ await triggerService({
46
+ service: definition.name,
47
+ type: 'stripe_updatePayment'
48
+ }, {
49
+ payment: referenceId,
50
+ state: 'succeeded'
51
+ })
52
+ const triggerData = {
53
+ payment: referenceId,
54
+ causeType: payment.causeType,
55
+ cause: payment.cause,
56
+ payerType: payment.payerType,
57
+ payer: payment.payer,
58
+ items: payment.items
59
+ }
60
+ await trigger({
61
+ type: 'paymentSucceeded_'+payment.causeType,
62
+ }, triggerData)
63
+ await trigger({
64
+ type: 'paymentSucceeded',
65
+ }, triggerData)
66
+ } else if(object.payment_status === 'unpaid') {
67
+ await triggerService({
68
+ service: definition.name,
69
+ type: 'stripe_updatePayment'
70
+ }, {
71
+ payment: referenceId,
72
+ state: 'pending'
73
+ })
74
+ }
75
+ } else {
76
+ // Ignore
77
+ }
78
+
79
+ }
80
+ })
81
+
82
+
83
+ definition.trigger({
84
+ name: 'stripeEvent.checkout.session.expired',
85
+ properties: {
86
+ data: {
87
+ type: Object,
88
+ properties: {
89
+ object: {
90
+ type: Object,
91
+ properties: {
92
+ client_reference_id: {
93
+ type: String,
94
+ validation: ['nonEmpty']
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ },
101
+ async execute({ data: { object } }, { triggerService, trigger }, emit) {
102
+ ///console.log('stripeEvent.checkout.session.expired', object)
103
+ const id = object.client_reference_id
104
+ const referenceType = id.slice(0, id.indexOf(':'))
105
+ const referenceId = id.slice(id.indexOf(':') + 1)
106
+ if(referenceType === 'payment') {
107
+ const payment = await Payment.get(referenceId)
108
+ if(!payment) throw new Error('Payment '+referenceId+' not found')
109
+ await triggerService({
110
+ type: 'stripe_updatePayment'
111
+ }, {
112
+ payment: referenceId,
113
+ state: 'failed'
114
+ })
115
+ const triggerData = {
116
+ payment: referenceId,
117
+ causeType: payment.causeType,
118
+ cause: payment.cause,
119
+ payerType: payment.payerType,
120
+ payer: payment.payer,
121
+ items: payment.items
122
+ }
123
+ await trigger({
124
+ type: 'paymentFailed_'+payment.causeType,
125
+ }, triggerData)
126
+ await trigger({
127
+ type: 'paymentFailed',
128
+ }, triggerData)
129
+ } else {
130
+ // Ignore
131
+ }
132
+
133
+ }
134
+ })
135
+
136
+
137
+ definition.trigger({
138
+ name: 'stripeEvent.checkout.session.async_payment_succeeded',
139
+ properties: {
140
+ data: {
141
+ type: Object,
142
+ properties: {
143
+ object: {
144
+ type: Object,
145
+ properties: {
146
+ client_reference_id: {
147
+ type: String,
148
+ validation: ['nonEmpty']
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ },
155
+ async execute({ data: { object } }, { triggerService, trigger }, emit) {
156
+ //console.log('stripeEvent.checkout.session.async_payment_succeeded', object)
157
+ const id = object.client_reference_id
158
+ const referenceType = id.slice(0, id.indexOf(':'))
159
+ const referenceId = id.slice(id.indexOf(':') + 1)
160
+ if(referenceType === 'payment') {
161
+ const payment = await Payment.get(referenceId)
162
+ if(!payment) throw new Error('Payment '+referenceId+' not found')
163
+ if(object.payment_status === 'paid') {
164
+ await triggerService({
165
+ type: 'stripe_updatePayment'
166
+ }, {
167
+ payment: referenceId,
168
+ state: 'succeeded'
169
+ })
170
+ const triggerData = {
171
+ payment: referenceId,
172
+ causeType: payment.causeType,
173
+ cause: payment.cause,
174
+ payerType: payment.payerType,
175
+ payer: payment.payer,
176
+ items: payment.items
177
+ }
178
+ await trigger({
179
+ type: 'paymentSucceeded_'+payment.causeType,
180
+ }, triggerData)
181
+ await trigger({
182
+ type: 'paymentSucceeded',
183
+ }, triggerData)
184
+ } else if(object.payment_status === 'unpaid') {
185
+ await triggerService({
186
+ type: 'stripe_updatePayment'
187
+ }, {
188
+ payment: referenceId,
189
+ state: 'pending'
190
+ })
191
+ }
192
+ } else {
193
+ // Ignore
194
+ }
195
+
196
+ }
197
+ })
198
+
199
+
200
+ definition.trigger({
201
+ name: 'stripeEvent.checkout.session.async_payment_failed',
202
+ properties: {
203
+ data: {
204
+ type: Object,
205
+ properties: {
206
+ object: {
207
+ type: Object,
208
+ properties: {
209
+ client_reference_id: {
210
+ type: String,
211
+ validation: ['nonEmpty']
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ },
218
+ async execute({ data: { object } }, { triggerService, trigger }, emit) {
219
+ //console.log('stripeEvent.checkout.session.async_payment_failed', object)
220
+ const id = object.client_reference_id
221
+ const referenceType = id.slice(0, id.indexOf(':'))
222
+ const referenceId = id.slice(id.indexOf(':') + 1)
223
+ if(referenceType === 'payment') {
224
+ const payment = await Payment.get(referenceId)
225
+ if(!payment) throw new Error('Payment '+referenceId+' not found')
226
+ await triggerService({
227
+ type: 'stripe_updatePayment'
228
+ }, {
229
+ payment: referenceId,
230
+ state: 'failed'
231
+ })
232
+ const triggerData = {
233
+ payment: referenceId,
234
+ causeType: payment.causeType,
235
+ cause: payment.cause,
236
+ payerType: payment.payerType,
237
+ payer: payment.payer,
238
+ items: payment.items
239
+ }
240
+ await trigger({
241
+ type: 'paymentFailed_'+payment.causeType,
242
+ }, triggerData)
243
+ await trigger({
244
+ type: 'paymentFailed',
245
+ }, triggerData)
246
+ } else {
247
+ // Ignore
248
+ }
249
+
250
+ }
251
+ })
252
+
253
+ definition.trigger({
254
+ name: 'stripeEvent.charge.succeeded',
255
+ properties: {
256
+ data: {
257
+ type: Object,
258
+ properties: {
259
+ object: {
260
+ type: Object
261
+ }
262
+ }
263
+ }
264
+ },
265
+ async execute({ data: { object } }, { triggerService, trigger }, emit) {
266
+ console.log('charge.succeeded', JSON.stringify(object, null, 2))
267
+ if(object.metadata?.type === 'payment') {
268
+ const payment = await Payment.get(object.metadata.payment)
269
+ const triggerData = {
270
+ payment: payment.id,
271
+ causeType: payment.causeType,
272
+ cause: payment.cause,
273
+ payerType: payment.payerType,
274
+ payer: payment.payer,
275
+ items: payment.items
276
+ }
277
+ await trigger({
278
+ type: 'chargeCollected_'+payment.causeType
279
+ }, triggerData)
280
+ await trigger({
281
+ type: 'chargeCollected'
282
+ }, triggerData)
283
+ } else {
284
+ // Ignore
285
+ }
286
+ }
287
+ })
288
+
289
+ definition.trigger({
290
+ name: 'stripeEvent.charge.refunded',
291
+ properties: {
292
+ data: {
293
+ type: Object,
294
+ properties: {
295
+ object: {
296
+ type: Object
297
+ }
298
+ }
299
+ }
300
+ },
301
+ async execute({ data: { object } }, { triggerService, trigger }, emit) {
302
+ console.log('charge.refunded', JSON.stringify(object, null, 2))
303
+ if(object.metadata?.type === 'payment') {
304
+ const payment = await Payment.get(object.metadata.payment)
305
+ const triggerData = {
306
+ payment: payment.id,
307
+ causeType: payment.causeType,
308
+ cause: payment.cause,
309
+ payerType: payment.payerType,
310
+ payer: payment.payer,
311
+ items: payment.items
312
+ }
313
+ await trigger({
314
+ type: 'chargeRefunded_'+payment.causeType,
315
+ }, triggerData)
316
+ await trigger({
317
+ type: 'chargeRefunded',
318
+ }, triggerData)
319
+ } else {
320
+ // Ignore
321
+ }
322
+ }
323
+ })
package/webhook.js CHANGED
@@ -1,11 +1,15 @@
1
1
  import App from '@live-change/framework'
2
2
  const app = App.app()
3
3
  import definition from './definition.js'
4
+ import config from './config.js'
4
5
 
5
6
  import crypto from "crypto"
6
7
  import express from "express"
7
8
  import stripe from "stripe"
8
9
 
10
+
11
+
12
+
9
13
  definition.endpoint({
10
14
  name: 'webhook',
11
15
  create() {
@@ -18,11 +22,14 @@ definition.endpoint({
18
22
  })
19
23
  expressApp.post('/', express.raw({type: 'application/json'}), async (request, response) => {
20
24
  try {
21
- const event = stripe.webhooks.constructEvent(request.body, sig, config.webhookSecret)
22
- console.log("STRIPE WEBHOOK", event)
23
- await app.triggerService({
24
- service: 'stripe',
25
- type: `stripe.${event.type}`
25
+ const signature = request.headers['stripe-signature']
26
+ const event = stripe.webhooks.constructEvent(request.body, signature, config.webhookSecret)
27
+ console.log("STRIPE WEBHOOK", event.type )//,JSON.stringify(event))
28
+ await app.trigger({
29
+ // service: 'stripe',
30
+ type: `stripeEvent.${event.type}`
31
+ }, {
32
+ ...event
26
33
  })
27
34
  response.json({ received: true })
28
35
  } catch (err) {