@meith/plugin-dues 0.7.0 → 0.9.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/package.json +3 -2
- package/src/config.ts +2 -4
- package/src/definition.tsx +59 -32
- package/src/demo.ts +7 -7
- package/src/entitlement.ts +23 -25
- package/src/handlers-admin.ts +3 -3
- package/src/handlers.ts +7 -12
- package/src/index.ts +5 -6
- package/src/messages/en.json +263 -0
- package/src/messages/index.ts +5 -0
- package/src/money.ts +18 -5
- package/src/period.ts +1 -4
- package/src/plans.ts +12 -10
- package/src/store.ts +23 -31
- package/src/stripe/client.ts +11 -7
- package/src/stripe/events.ts +2 -5
- package/src/tasks.ts +2 -2
- package/src/ui/admin.tsx +336 -295
- package/src/ui/pages.tsx +134 -174
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meith/plugin-dues",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Membership dues for a Meith board: Stripe-backed subscriptions as a contained plugin.",
|
|
5
5
|
"license": "LGPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@meith/
|
|
23
|
+
"@meith/theme-kit": "^0.9.0",
|
|
24
|
+
"@meith/plugin-kit": "^0.9.0"
|
|
24
25
|
},
|
|
25
26
|
"peerDependencies": {
|
|
26
27
|
"react": "^19.2.0"
|
package/src/config.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isCurrencyCode, isValidMinorAmount } from './money'
|
|
2
|
-
import { parsePeriod, periodCeilingDays
|
|
2
|
+
import { type Period, parsePeriod, periodCeilingDays } from './period'
|
|
3
3
|
|
|
4
4
|
export interface DuesPlanInput {
|
|
5
5
|
readonly key: string
|
|
@@ -114,9 +114,7 @@ export function parseDuesConfig(input: DuesConfigInput): DuesConfig {
|
|
|
114
114
|
|
|
115
115
|
const parsed = parsePeriod(plan.billing.period)
|
|
116
116
|
if (parsed === null) {
|
|
117
|
-
refuse(
|
|
118
|
-
`${where}: "${plan.billing.period}" is not an ISO-8601 period like P90D, P1M or P1Y.`,
|
|
119
|
-
)
|
|
117
|
+
refuse(`${where}: "${plan.billing.period}" is not an ISO-8601 period like P90D, P1M or P1Y.`)
|
|
120
118
|
}
|
|
121
119
|
if (periodCeilingDays(parsed) + graceDays > MAX_GRANTABLE_DAYS) {
|
|
122
120
|
refuse(
|
package/src/definition.tsx
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
definePlugin,
|
|
3
|
+
type PluginDefinition,
|
|
4
|
+
type PluginRequest,
|
|
5
|
+
type PluginResponse,
|
|
6
|
+
type PluginRuntimeContext,
|
|
7
|
+
} from '@meith/plugin-kit'
|
|
2
8
|
|
|
3
|
-
import {
|
|
9
|
+
import { type DuesConfigInput, parseDuesConfig } from './config'
|
|
4
10
|
import {
|
|
5
11
|
buildServices,
|
|
12
|
+
type DuesServices,
|
|
6
13
|
entitlementDeps,
|
|
7
14
|
handleCancel,
|
|
8
15
|
handleCheckout,
|
|
9
16
|
handlePortal,
|
|
10
17
|
handleWebhook,
|
|
11
|
-
type DuesServices,
|
|
12
18
|
} from './handlers'
|
|
13
19
|
import {
|
|
14
20
|
handleAdminCancel,
|
|
@@ -21,6 +27,7 @@ import {
|
|
|
21
27
|
handleAdminPlanUpdate,
|
|
22
28
|
handleAdminRevoke,
|
|
23
29
|
} from './handlers-admin'
|
|
30
|
+
import en from './messages/en.json'
|
|
24
31
|
import { DUES_MIGRATIONS } from './schema'
|
|
25
32
|
import { runReconcile, runSweep } from './tasks'
|
|
26
33
|
import { CodesPage, LedgerPage, MembersPage, PlansAdminPage, StatusPage } from './ui/admin'
|
|
@@ -39,49 +46,53 @@ export function dues(input: DuesConfigInput): PluginDefinition {
|
|
|
39
46
|
return definePlugin({
|
|
40
47
|
key: 'dues',
|
|
41
48
|
name: 'Dues',
|
|
42
|
-
version: '0.
|
|
43
|
-
description:
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
version: '0.9.0',
|
|
50
|
+
description: en['dues.definition.description'].replace('{label}', config.label.toLowerCase()),
|
|
51
|
+
descriptionKey: 'dues.definition.description',
|
|
52
|
+
descriptionArgs: { label: config.label.toLowerCase() },
|
|
46
53
|
apiVersion: '0',
|
|
47
54
|
|
|
48
55
|
settings: [
|
|
49
56
|
{
|
|
50
57
|
key: 'stripe_secret_key',
|
|
51
|
-
label: '
|
|
58
|
+
label: en['dues.definition.setting.secret.label'],
|
|
59
|
+
labelKey: 'dues.definition.setting.secret.label',
|
|
52
60
|
type: 'secret',
|
|
53
61
|
env: 'DUES_STRIPE_SECRET_KEY',
|
|
54
62
|
required: true,
|
|
55
63
|
default: '',
|
|
56
|
-
description: '
|
|
64
|
+
description: en['dues.definition.setting.secret.description'],
|
|
65
|
+
descriptionKey: 'dues.definition.setting.secret.description',
|
|
57
66
|
},
|
|
58
67
|
{
|
|
59
68
|
key: 'stripe_webhook_secret',
|
|
60
|
-
label: '
|
|
69
|
+
label: en['dues.definition.setting.webhook.label'],
|
|
70
|
+
labelKey: 'dues.definition.setting.webhook.label',
|
|
61
71
|
type: 'secret',
|
|
62
72
|
env: 'DUES_STRIPE_WEBHOOK_SECRET',
|
|
63
73
|
required: true,
|
|
64
74
|
default: '',
|
|
65
|
-
description:
|
|
66
|
-
|
|
67
|
-
'but can never confirm.',
|
|
75
|
+
description: en['dues.definition.setting.webhook.description'],
|
|
76
|
+
descriptionKey: 'dues.definition.setting.webhook.description',
|
|
68
77
|
},
|
|
69
78
|
{
|
|
70
79
|
key: 'stripe_api_version',
|
|
71
|
-
label: '
|
|
80
|
+
label: en['dues.definition.setting.apiVersion.label'],
|
|
81
|
+
labelKey: 'dues.definition.setting.apiVersion.label',
|
|
72
82
|
default: '2024-12-18.acacia',
|
|
73
83
|
advanced: true,
|
|
74
|
-
description:
|
|
75
|
-
|
|
76
|
-
'Change it only alongside a plugin upgrade that expects the new shapes.',
|
|
84
|
+
description: en['dues.definition.setting.apiVersion.description'],
|
|
85
|
+
descriptionKey: 'dues.definition.setting.apiVersion.description',
|
|
77
86
|
},
|
|
78
87
|
{
|
|
79
88
|
key: 'stripe_api_base',
|
|
80
|
-
label: '
|
|
89
|
+
label: en['dues.definition.setting.apiBase.label'],
|
|
90
|
+
labelKey: 'dues.definition.setting.apiBase.label',
|
|
81
91
|
env: 'DUES_STRIPE_API_BASE',
|
|
82
92
|
default: 'https://api.stripe.com',
|
|
83
93
|
advanced: true,
|
|
84
|
-
description: '
|
|
94
|
+
description: en['dues.definition.setting.apiBase.description'],
|
|
95
|
+
descriptionKey: 'dues.definition.setting.apiBase.description',
|
|
85
96
|
},
|
|
86
97
|
],
|
|
87
98
|
|
|
@@ -95,7 +106,10 @@ export function dues(input: DuesConfigInput): PluginDefinition {
|
|
|
95
106
|
const services = buildServices(config, context)
|
|
96
107
|
const result = await runReconcile(entitlementDeps(services), services.stripe)
|
|
97
108
|
if (
|
|
98
|
-
result.ordersSettled +
|
|
109
|
+
result.ordersSettled +
|
|
110
|
+
result.ordersClosed +
|
|
111
|
+
result.eventsReplayed +
|
|
112
|
+
result.subscriptionsCorrected >
|
|
99
113
|
0
|
|
100
114
|
) {
|
|
101
115
|
context.logger.info('dues: reconciled', { ...result })
|
|
@@ -116,13 +130,17 @@ export function dues(input: DuesConfigInput): PluginDefinition {
|
|
|
116
130
|
notifications: [
|
|
117
131
|
{
|
|
118
132
|
key: 'gift_received',
|
|
119
|
-
title: '
|
|
120
|
-
|
|
133
|
+
title: en['dues.definition.notification.gift.title'],
|
|
134
|
+
titleKey: 'dues.definition.notification.gift.title',
|
|
135
|
+
description: en['dues.definition.notification.gift.description'],
|
|
136
|
+
descriptionKey: 'dues.definition.notification.gift.description',
|
|
121
137
|
},
|
|
122
138
|
{
|
|
123
139
|
key: 'renewal_trouble',
|
|
124
|
-
title: '
|
|
125
|
-
|
|
140
|
+
title: en['dues.definition.notification.renewal.title'],
|
|
141
|
+
titleKey: 'dues.definition.notification.renewal.title',
|
|
142
|
+
description: en['dues.definition.notification.renewal.description'],
|
|
143
|
+
descriptionKey: 'dues.definition.notification.renewal.description',
|
|
126
144
|
},
|
|
127
145
|
],
|
|
128
146
|
|
|
@@ -221,19 +239,23 @@ export function dues(input: DuesConfigInput): PluginDefinition {
|
|
|
221
239
|
},
|
|
222
240
|
{
|
|
223
241
|
path: 'return',
|
|
224
|
-
title: '
|
|
242
|
+
title: en['dues.definition.page.return'],
|
|
243
|
+
titleKey: 'dues.definition.page.return',
|
|
225
244
|
access: 'member',
|
|
226
245
|
render: (context) => ReturnPage({ config, context }),
|
|
227
246
|
},
|
|
228
247
|
{
|
|
229
248
|
path: 'manage',
|
|
230
|
-
title:
|
|
249
|
+
title: en['dues.definition.manage'].replace('{label}', config.label.toLowerCase()),
|
|
250
|
+
titleKey: 'dues.definition.manage',
|
|
251
|
+
titleArgs: { label: config.label.toLowerCase() },
|
|
231
252
|
access: 'member',
|
|
232
253
|
render: (context) => ManagePage({ config, context }),
|
|
233
254
|
},
|
|
234
255
|
{
|
|
235
256
|
path: 'go',
|
|
236
|
-
title: '
|
|
257
|
+
title: en['dues.definition.go'],
|
|
258
|
+
titleKey: 'dues.definition.go',
|
|
237
259
|
access: 'member',
|
|
238
260
|
render: (context) =>
|
|
239
261
|
GoPage({
|
|
@@ -251,27 +273,32 @@ export function dues(input: DuesConfigInput): PluginDefinition {
|
|
|
251
273
|
adminPages: [
|
|
252
274
|
{
|
|
253
275
|
path: 'status',
|
|
254
|
-
title: '
|
|
276
|
+
title: en['dues.definition.page.status'],
|
|
277
|
+
titleKey: 'dues.definition.page.status',
|
|
255
278
|
render: (context) => StatusPage({ config, context }),
|
|
256
279
|
},
|
|
257
280
|
{
|
|
258
281
|
path: 'plans',
|
|
259
|
-
title: '
|
|
282
|
+
title: en['dues.definition.page.plans'],
|
|
283
|
+
titleKey: 'dues.definition.page.plans',
|
|
260
284
|
render: (context) => PlansAdminPage({ config, context }),
|
|
261
285
|
},
|
|
262
286
|
{
|
|
263
287
|
path: 'members',
|
|
264
|
-
title: '
|
|
288
|
+
title: en['dues.definition.page.members'],
|
|
289
|
+
titleKey: 'dues.definition.page.members',
|
|
265
290
|
render: (context) => MembersPage({ context }),
|
|
266
291
|
},
|
|
267
292
|
{
|
|
268
293
|
path: 'codes',
|
|
269
|
-
title: '
|
|
294
|
+
title: en['dues.definition.page.codes'],
|
|
295
|
+
titleKey: 'dues.definition.page.codes',
|
|
270
296
|
render: (context) => CodesPage({ config, context }),
|
|
271
297
|
},
|
|
272
298
|
{
|
|
273
299
|
path: 'ledger',
|
|
274
|
-
title: '
|
|
300
|
+
title: en['dues.definition.page.ledger'],
|
|
301
|
+
titleKey: 'dues.definition.page.ledger',
|
|
275
302
|
render: (context) => LedgerPage({ config, context }),
|
|
276
303
|
},
|
|
277
304
|
],
|
package/src/demo.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import type { PluginData, PluginGrants, PluginNotify } from '@meith/plugin-kit'
|
|
2
2
|
|
|
3
3
|
import { discountedPrice } from './codes'
|
|
4
|
-
import {
|
|
5
|
-
import { applyInternalEvent,
|
|
4
|
+
import { type DuesConfig, parseDuesConfig } from './config'
|
|
5
|
+
import { applyInternalEvent, type EntitlementDeps, settlePaidOrder } from './entitlement'
|
|
6
6
|
import { addDays } from './period'
|
|
7
7
|
import {
|
|
8
8
|
attachCheckoutSession,
|
|
9
|
+
type CodeRow,
|
|
9
10
|
insertCode,
|
|
10
11
|
insertOrder,
|
|
11
12
|
insertPlan,
|
|
12
13
|
markEventProcessed,
|
|
14
|
+
type NewPlan,
|
|
15
|
+
type OrderRow,
|
|
16
|
+
type PlanRow,
|
|
13
17
|
planRowByKey,
|
|
14
18
|
recordEvent,
|
|
15
19
|
setCodeDisabled,
|
|
16
20
|
setPlanArchived,
|
|
17
21
|
settleOrder,
|
|
18
|
-
type CodeRow,
|
|
19
|
-
type NewPlan,
|
|
20
|
-
type OrderRow,
|
|
21
|
-
type PlanRow,
|
|
22
22
|
} from './store'
|
|
23
|
-
import {
|
|
23
|
+
import { type StripeEventEnvelope, toInternalEvent } from './stripe/events'
|
|
24
24
|
|
|
25
25
|
export const DUES_DEMO_GROUP = 'supporters'
|
|
26
26
|
|
package/src/entitlement.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginData, PluginGrants, PluginNotify } from '@meith/plugin-kit'
|
|
2
2
|
|
|
3
3
|
import type { DuesConfig } from './config'
|
|
4
4
|
import { moneyMatches } from './money'
|
|
@@ -11,15 +11,15 @@ import {
|
|
|
11
11
|
insertLedger,
|
|
12
12
|
insertMembership,
|
|
13
13
|
liveMembership,
|
|
14
|
+
type MembershipRow,
|
|
14
15
|
membershipBySubscription,
|
|
16
|
+
type OrderRow,
|
|
15
17
|
orderByPaymentIntent,
|
|
16
18
|
orderBySessionId,
|
|
19
|
+
type PlanRow,
|
|
17
20
|
planRowByKey,
|
|
18
21
|
setMembershipStatus,
|
|
19
22
|
settleOrder,
|
|
20
|
-
type MembershipRow,
|
|
21
|
-
type OrderRow,
|
|
22
|
-
type PlanRow,
|
|
23
23
|
} from './store'
|
|
24
24
|
import type { InternalEvent } from './stripe/events'
|
|
25
25
|
|
|
@@ -48,9 +48,7 @@ async function tryNotify(
|
|
|
48
48
|
|
|
49
49
|
function grantReason(order: OrderRow): string {
|
|
50
50
|
const gift =
|
|
51
|
-
order.buyerUserId === order.recipientUserId
|
|
52
|
-
? ''
|
|
53
|
-
: `, a gift from user ${order.buyerUserId}`
|
|
51
|
+
order.buyerUserId === order.recipientUserId ? '' : `, a gift from user ${order.buyerUserId}`
|
|
54
52
|
return `dues order ${order.id}: ${order.planName}${gift}`
|
|
55
53
|
}
|
|
56
54
|
|
|
@@ -69,10 +67,15 @@ export async function settlePaidOrder(
|
|
|
69
67
|
if (order.status === 'paid') return 'already-settled'
|
|
70
68
|
if (order.status === 'failed' || order.status === 'cancelled') return `order-${order.status}`
|
|
71
69
|
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
if (
|
|
71
|
+
!moneyMatches(
|
|
72
|
+
{ amountMinor: order.amountMinor, currency: order.currency },
|
|
73
|
+
{
|
|
74
|
+
amountMinor: info.amountTotal,
|
|
75
|
+
currency: info.currency,
|
|
76
|
+
},
|
|
77
|
+
)
|
|
78
|
+
) {
|
|
76
79
|
await settleOrder(deps.data, order.id, {
|
|
77
80
|
status: 'pending',
|
|
78
81
|
needsAttention:
|
|
@@ -160,8 +163,9 @@ export async function settlePaidOrder(
|
|
|
160
163
|
await tryNotify(deps, {
|
|
161
164
|
userId: order.recipientUserId,
|
|
162
165
|
kind: 'gift_received',
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
subjectKey: 'dues.notification.gift.subject',
|
|
167
|
+
subjectArgs: { plan: order.planName },
|
|
168
|
+
bodyKey: 'dues.notification.gift.body',
|
|
165
169
|
href: '/plugins/dues/manage',
|
|
166
170
|
dedupeKey: `gift:${order.id}`,
|
|
167
171
|
})
|
|
@@ -179,7 +183,8 @@ function settledPeriodEnd(
|
|
|
179
183
|
if (order.billingMode === 'lifetime') return LIFETIME_END
|
|
180
184
|
|
|
181
185
|
if (order.billingMode === 'fixed') {
|
|
182
|
-
const base =
|
|
186
|
+
const base =
|
|
187
|
+
existing !== null && existing.currentPeriodEnd > now ? existing.currentPeriodEnd : now
|
|
183
188
|
if (isLifetime(base)) return LIFETIME_END
|
|
184
189
|
const parsed =
|
|
185
190
|
(plan?.periodSpec !== null && plan?.periodSpec !== undefined
|
|
@@ -240,8 +245,7 @@ export async function applyInternalEvent(
|
|
|
240
245
|
}
|
|
241
246
|
if (event.billingReason === 'subscription_create') return 'covered-by-checkout'
|
|
242
247
|
|
|
243
|
-
const periodEnd =
|
|
244
|
-
event.periodEnd ?? addBillingInterval(membership.currentPeriodEnd, 'month')
|
|
248
|
+
const periodEnd = event.periodEnd ?? addBillingInterval(membership.currentPeriodEnd, 'month')
|
|
245
249
|
const graceUntil = addDays(periodEnd, deps.config.graceDays)
|
|
246
250
|
|
|
247
251
|
await extendMembership(deps.data, membership.id, {
|
|
@@ -287,10 +291,8 @@ export async function applyInternalEvent(
|
|
|
287
291
|
await tryNotify(deps, {
|
|
288
292
|
userId: membership.userId,
|
|
289
293
|
kind: 'renewal_trouble',
|
|
290
|
-
|
|
291
|
-
body
|
|
292
|
-
'Stripe retries on its own. Your access holds during the grace window, ' +
|
|
293
|
-
'and updating your card from the manage page usually settles it.',
|
|
294
|
+
subjectKey: 'dues.notification.renewal.subject',
|
|
295
|
+
bodyKey: 'dues.notification.renewal.body',
|
|
294
296
|
href: '/plugins/dues/manage',
|
|
295
297
|
dedupeKey: `grace:${membership.id}`,
|
|
296
298
|
})
|
|
@@ -333,11 +335,7 @@ export async function applyInternalEvent(
|
|
|
333
335
|
const order = await orderByPaymentIntent(deps.data, event.paymentIntentId)
|
|
334
336
|
if (order === null) return 'unmatched-reversal'
|
|
335
337
|
|
|
336
|
-
const membership = await liveMembership(
|
|
337
|
-
deps.data,
|
|
338
|
-
order.recipientUserId,
|
|
339
|
-
order.groupKey,
|
|
340
|
-
)
|
|
338
|
+
const membership = await liveMembership(deps.data, order.recipientUserId, order.groupKey)
|
|
341
339
|
if (membership !== null) {
|
|
342
340
|
await setMembershipStatus(deps.data, membership.id, 'revoked')
|
|
343
341
|
try {
|
package/src/handlers-admin.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { PluginRequest, PluginResponse } from '@meith/plugin-kit'
|
|
2
2
|
|
|
3
3
|
import { generateCode, normalizeCode, validCodeShape } from './codes'
|
|
4
|
-
import { anyPlanByKey, clampGrantUntil, isLifetime, parsePlanForm } from './plans'
|
|
5
|
-
import { addDays } from './period'
|
|
6
4
|
import type { DuesServices } from './handlers'
|
|
5
|
+
import { addDays } from './period'
|
|
6
|
+
import { anyPlanByKey, clampGrantUntil, isLifetime, parsePlanForm } from './plans'
|
|
7
7
|
import {
|
|
8
8
|
clearMembershipAttention,
|
|
9
9
|
clearOrderAttention,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
flagMembership,
|
|
13
13
|
insertCode,
|
|
14
14
|
insertPlan,
|
|
15
|
+
type MembershipRow,
|
|
15
16
|
membershipById,
|
|
16
17
|
orderById,
|
|
17
18
|
planRowById,
|
|
@@ -20,7 +21,6 @@ import {
|
|
|
20
21
|
setPlanArchived,
|
|
21
22
|
setPlanStripePrice,
|
|
22
23
|
updatePlan,
|
|
23
|
-
type MembershipRow,
|
|
24
24
|
} from './store'
|
|
25
25
|
|
|
26
26
|
function toAdmin(
|
package/src/handlers.ts
CHANGED
|
@@ -1,29 +1,25 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PluginRequest,
|
|
3
|
-
PluginResponse,
|
|
4
|
-
PluginRuntimeContext,
|
|
5
|
-
} from '@meith/plugin-kit'
|
|
1
|
+
import type { PluginRequest, PluginResponse, PluginRuntimeContext } from '@meith/plugin-kit'
|
|
6
2
|
|
|
7
3
|
import { codeProblem, discountedPrice, normalizeCode } from './codes'
|
|
8
4
|
import type { DuesConfig } from './config'
|
|
5
|
+
import { applyInternalEvent, type EntitlementDeps, settlePaidOrder } from './entitlement'
|
|
9
6
|
import { isLifetime, sellablePlanByKey } from './plans'
|
|
10
|
-
import { applyInternalEvent, settlePaidOrder, type EntitlementDeps } from './entitlement'
|
|
11
7
|
import {
|
|
12
8
|
attachCheckoutSession,
|
|
9
|
+
type CodeRow,
|
|
13
10
|
codeByCode,
|
|
14
11
|
findStripeCustomer,
|
|
15
12
|
insertOrder,
|
|
16
13
|
liveMembership,
|
|
17
|
-
membershipById,
|
|
18
|
-
recordEvent,
|
|
19
14
|
markEventFailed,
|
|
20
15
|
markEventProcessed,
|
|
16
|
+
membershipById,
|
|
17
|
+
recordEvent,
|
|
21
18
|
saveCodeCoupon,
|
|
22
19
|
saveStripeCustomer,
|
|
23
20
|
setMembershipStatus,
|
|
24
|
-
type CodeRow,
|
|
25
21
|
} from './store'
|
|
26
|
-
import { createStripeClient,
|
|
22
|
+
import { createStripeClient, type StripeClient, StripeError } from './stripe/client'
|
|
27
23
|
import { parseEventEnvelope, toInternalEvent } from './stripe/events'
|
|
28
24
|
import { verifyStripeSignature } from './stripe/webhook'
|
|
29
25
|
|
|
@@ -151,8 +147,7 @@ export async function handleCheckout(
|
|
|
151
147
|
if (problem !== null) return back({ error: `code-${problem}`, ...bounce })
|
|
152
148
|
}
|
|
153
149
|
|
|
154
|
-
const charge =
|
|
155
|
-
code === null ? plan.priceMinor : discountedPrice(plan.priceMinor, code.percentOff)
|
|
150
|
+
const charge = code === null ? plan.priceMinor : discountedPrice(plan.priceMinor, code.percentOff)
|
|
156
151
|
|
|
157
152
|
if (services.stripe === null && (plan.mode === 'auto' || charge > 0)) {
|
|
158
153
|
return back({ error: 'unconfigured' })
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
export { dues } from './definition'
|
|
2
1
|
export type { DuesConfigInput, DuesPlanInput } from './config'
|
|
3
|
-
|
|
4
|
-
export { SUBSCRIBED_EVENT_TYPES } from './stripe/events'
|
|
5
|
-
export { signStripePayload } from './stripe/webhook'
|
|
6
|
-
|
|
2
|
+
export { dues } from './definition'
|
|
7
3
|
export {
|
|
8
4
|
DUES_DEMO_CODES,
|
|
9
5
|
DUES_DEMO_CURRENCY,
|
|
@@ -11,8 +7,11 @@ export {
|
|
|
11
7
|
DUES_DEMO_GROUP,
|
|
12
8
|
DUES_DEMO_PLANS,
|
|
13
9
|
DUES_DEMO_PRICES,
|
|
14
|
-
seedDuesDemo,
|
|
15
10
|
type DuesDemoCast,
|
|
16
11
|
type DuesDemoDeps,
|
|
17
12
|
type DuesDemoSummary,
|
|
13
|
+
seedDuesDemo,
|
|
18
14
|
} from './demo'
|
|
15
|
+
export { duesMessages } from './messages'
|
|
16
|
+
export { SUBSCRIBED_EVENT_TYPES } from './stripe/events'
|
|
17
|
+
export { signStripePayload } from './stripe/webhook'
|