@beignet/core 0.0.12 → 0.0.14
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/CHANGELOG.md +21 -0
- package/README.md +159 -9
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +29 -1
- package/dist/client/client.js.map +1 -1
- package/dist/entitlements/index.d.ts +234 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +172 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/error-reporting/index.d.ts +131 -0
- package/dist/error-reporting/index.d.ts.map +1 -0
- package/dist/error-reporting/index.js +112 -0
- package/dist/error-reporting/index.js.map +1 -0
- package/dist/flags/index.d.ts +293 -0
- package/dist/flags/index.d.ts.map +1 -0
- package/dist/flags/index.js +204 -0
- package/dist/flags/index.js.map +1 -0
- package/dist/locks/index.d.ts +155 -0
- package/dist/locks/index.d.ts.map +1 -0
- package/dist/locks/index.js +248 -0
- package/dist/locks/index.js.map +1 -0
- package/dist/payments/index.d.ts +430 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +230 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/ports/index.d.ts +61 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +33 -0
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/policy.d.ts +104 -0
- package/dist/ports/policy.d.ts.map +1 -1
- package/dist/ports/policy.js +102 -7
- package/dist/ports/policy.js.map +1 -1
- package/dist/search/index.d.ts +175 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +344 -0
- package/dist/search/index.js.map +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +9 -1
- package/dist/server/server.js.map +1 -1
- package/dist/testing/index.d.ts +46 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +33 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +25 -1
- package/src/client/client.ts +33 -1
- package/src/entitlements/index.ts +479 -0
- package/src/error-reporting/index.ts +273 -0
- package/src/flags/index.ts +608 -0
- package/src/locks/index.ts +440 -0
- package/src/payments/index.ts +699 -0
- package/src/ports/index.ts +194 -0
- package/src/ports/policy.ts +272 -7
- package/src/search/index.ts +632 -0
- package/src/server/server.ts +15 -0
- package/src/testing/index.ts +83 -1
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beignet/core/payments
|
|
3
|
+
*
|
|
4
|
+
* Provider-neutral payments primitives for Beignet applications.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createProvider,
|
|
9
|
+
createProviderInstrumentation,
|
|
10
|
+
} from "../providers/index.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Value or promise of that value.
|
|
14
|
+
*/
|
|
15
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* String metadata attached to provider-owned payment objects.
|
|
19
|
+
*/
|
|
20
|
+
export type PaymentMetadata = Record<string, string>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Checkout modes understood by Beignet's provider-neutral payment port.
|
|
24
|
+
*/
|
|
25
|
+
export type PaymentCheckoutMode = "payment" | "subscription";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Hosted checkout line item.
|
|
29
|
+
*/
|
|
30
|
+
export interface PaymentCheckoutLineItem {
|
|
31
|
+
/**
|
|
32
|
+
* Provider price identifier.
|
|
33
|
+
*/
|
|
34
|
+
priceId: string;
|
|
35
|
+
/**
|
|
36
|
+
* Quantity for this price. Defaults to the provider's default behavior.
|
|
37
|
+
*/
|
|
38
|
+
quantity?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Input for creating a hosted checkout session.
|
|
43
|
+
*/
|
|
44
|
+
export interface CreateCheckoutSessionInput {
|
|
45
|
+
/**
|
|
46
|
+
* One-time payment or subscription checkout.
|
|
47
|
+
*/
|
|
48
|
+
mode: PaymentCheckoutMode;
|
|
49
|
+
/**
|
|
50
|
+
* Line items to include in checkout.
|
|
51
|
+
*/
|
|
52
|
+
lineItems: readonly PaymentCheckoutLineItem[];
|
|
53
|
+
/**
|
|
54
|
+
* URL the provider redirects to after successful checkout.
|
|
55
|
+
*/
|
|
56
|
+
successUrl: string;
|
|
57
|
+
/**
|
|
58
|
+
* URL the provider redirects to when checkout is canceled.
|
|
59
|
+
*/
|
|
60
|
+
cancelUrl: string;
|
|
61
|
+
/**
|
|
62
|
+
* Existing provider customer ID, when known.
|
|
63
|
+
*/
|
|
64
|
+
customerId?: string;
|
|
65
|
+
/**
|
|
66
|
+
* App-owned reference copied into the provider session.
|
|
67
|
+
*/
|
|
68
|
+
clientReferenceId?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Provider metadata.
|
|
71
|
+
*/
|
|
72
|
+
metadata?: PaymentMetadata;
|
|
73
|
+
/**
|
|
74
|
+
* Provider idempotency key for this external call.
|
|
75
|
+
*/
|
|
76
|
+
idempotencyKey?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Hosted checkout session returned by a payment provider.
|
|
81
|
+
*/
|
|
82
|
+
export interface CheckoutSession {
|
|
83
|
+
/**
|
|
84
|
+
* Provider session ID.
|
|
85
|
+
*/
|
|
86
|
+
id: string;
|
|
87
|
+
/**
|
|
88
|
+
* Provider name.
|
|
89
|
+
*/
|
|
90
|
+
provider: string;
|
|
91
|
+
/**
|
|
92
|
+
* Checkout mode.
|
|
93
|
+
*/
|
|
94
|
+
mode: PaymentCheckoutMode;
|
|
95
|
+
/**
|
|
96
|
+
* Hosted checkout URL, when the provider returns one.
|
|
97
|
+
*/
|
|
98
|
+
url?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Client secret, when the provider supports embedded checkout.
|
|
101
|
+
*/
|
|
102
|
+
clientSecret?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Provider customer ID, when known.
|
|
105
|
+
*/
|
|
106
|
+
customerId?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Provider status, when known.
|
|
109
|
+
*/
|
|
110
|
+
status?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Provider metadata.
|
|
113
|
+
*/
|
|
114
|
+
metadata?: PaymentMetadata;
|
|
115
|
+
/**
|
|
116
|
+
* Raw provider response for app-owned escape hatches.
|
|
117
|
+
*/
|
|
118
|
+
raw?: unknown;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Input for creating a billing portal session.
|
|
123
|
+
*/
|
|
124
|
+
export interface CreateBillingPortalSessionInput {
|
|
125
|
+
/**
|
|
126
|
+
* Provider customer ID.
|
|
127
|
+
*/
|
|
128
|
+
customerId: string;
|
|
129
|
+
/**
|
|
130
|
+
* URL the provider redirects to after leaving the portal.
|
|
131
|
+
*/
|
|
132
|
+
returnUrl: string;
|
|
133
|
+
/**
|
|
134
|
+
* Provider idempotency key for this external call.
|
|
135
|
+
*/
|
|
136
|
+
idempotencyKey?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Billing portal session returned by a payment provider.
|
|
141
|
+
*/
|
|
142
|
+
export interface BillingPortalSession {
|
|
143
|
+
/**
|
|
144
|
+
* Provider session ID.
|
|
145
|
+
*/
|
|
146
|
+
id: string;
|
|
147
|
+
/**
|
|
148
|
+
* Provider name.
|
|
149
|
+
*/
|
|
150
|
+
provider: string;
|
|
151
|
+
/**
|
|
152
|
+
* Hosted portal URL.
|
|
153
|
+
*/
|
|
154
|
+
url: string;
|
|
155
|
+
/**
|
|
156
|
+
* Provider customer ID.
|
|
157
|
+
*/
|
|
158
|
+
customerId: string;
|
|
159
|
+
/**
|
|
160
|
+
* Raw provider response for app-owned escape hatches.
|
|
161
|
+
*/
|
|
162
|
+
raw?: unknown;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Refund reasons common to hosted payment providers.
|
|
167
|
+
*/
|
|
168
|
+
export type PaymentRefundReason =
|
|
169
|
+
| "duplicate"
|
|
170
|
+
| "fraudulent"
|
|
171
|
+
| "requested_by_customer";
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Input for creating a refund.
|
|
175
|
+
*/
|
|
176
|
+
export interface CreateRefundInput {
|
|
177
|
+
/**
|
|
178
|
+
* Provider payment ID, such as a payment intent ID.
|
|
179
|
+
*/
|
|
180
|
+
paymentId: string;
|
|
181
|
+
/**
|
|
182
|
+
* Amount in the provider's smallest currency unit. Omit for a full refund.
|
|
183
|
+
*/
|
|
184
|
+
amount?: number;
|
|
185
|
+
/**
|
|
186
|
+
* Reason for the refund.
|
|
187
|
+
*/
|
|
188
|
+
reason?: PaymentRefundReason;
|
|
189
|
+
/**
|
|
190
|
+
* Provider metadata.
|
|
191
|
+
*/
|
|
192
|
+
metadata?: PaymentMetadata;
|
|
193
|
+
/**
|
|
194
|
+
* Provider idempotency key for this external call.
|
|
195
|
+
*/
|
|
196
|
+
idempotencyKey?: string;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Refund returned by a payment provider.
|
|
201
|
+
*/
|
|
202
|
+
export interface Refund {
|
|
203
|
+
/**
|
|
204
|
+
* Provider refund ID.
|
|
205
|
+
*/
|
|
206
|
+
id: string;
|
|
207
|
+
/**
|
|
208
|
+
* Provider name.
|
|
209
|
+
*/
|
|
210
|
+
provider: string;
|
|
211
|
+
/**
|
|
212
|
+
* Provider payment ID that was refunded.
|
|
213
|
+
*/
|
|
214
|
+
paymentId: string;
|
|
215
|
+
/**
|
|
216
|
+
* Refunded amount in the provider's smallest currency unit, when known.
|
|
217
|
+
*/
|
|
218
|
+
amount?: number;
|
|
219
|
+
/**
|
|
220
|
+
* Currency code, when known.
|
|
221
|
+
*/
|
|
222
|
+
currency?: string;
|
|
223
|
+
/**
|
|
224
|
+
* Provider refund status, when known.
|
|
225
|
+
*/
|
|
226
|
+
status?: string;
|
|
227
|
+
/**
|
|
228
|
+
* Provider metadata.
|
|
229
|
+
*/
|
|
230
|
+
metadata?: PaymentMetadata;
|
|
231
|
+
/**
|
|
232
|
+
* Raw provider response for app-owned escape hatches.
|
|
233
|
+
*/
|
|
234
|
+
raw?: unknown;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Raw webhook payload accepted by payment providers.
|
|
239
|
+
*/
|
|
240
|
+
export type PaymentWebhookRawBody = string | Uint8Array | ArrayBuffer;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Input for verifying and parsing a provider webhook.
|
|
244
|
+
*/
|
|
245
|
+
export interface VerifyPaymentWebhookInput {
|
|
246
|
+
/**
|
|
247
|
+
* Raw request body. Do not pass a parsed JSON body.
|
|
248
|
+
*/
|
|
249
|
+
rawBody: PaymentWebhookRawBody;
|
|
250
|
+
/**
|
|
251
|
+
* Provider signature header value.
|
|
252
|
+
*/
|
|
253
|
+
signature: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Normalized provider webhook event.
|
|
258
|
+
*/
|
|
259
|
+
export interface PaymentWebhookEvent {
|
|
260
|
+
/**
|
|
261
|
+
* Provider event ID.
|
|
262
|
+
*/
|
|
263
|
+
id: string;
|
|
264
|
+
/**
|
|
265
|
+
* Provider event type, such as "checkout.session.completed".
|
|
266
|
+
*/
|
|
267
|
+
type: string;
|
|
268
|
+
/**
|
|
269
|
+
* Provider name.
|
|
270
|
+
*/
|
|
271
|
+
provider: string;
|
|
272
|
+
/**
|
|
273
|
+
* Event creation time, when known.
|
|
274
|
+
*/
|
|
275
|
+
createdAt?: Date;
|
|
276
|
+
/**
|
|
277
|
+
* Whether the event came from live mode, when the provider exposes it.
|
|
278
|
+
*/
|
|
279
|
+
livemode?: boolean;
|
|
280
|
+
/**
|
|
281
|
+
* Provider event data object.
|
|
282
|
+
*/
|
|
283
|
+
data: unknown;
|
|
284
|
+
/**
|
|
285
|
+
* Raw provider event for app-owned escape hatches.
|
|
286
|
+
*/
|
|
287
|
+
raw?: unknown;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* App-facing payments port.
|
|
292
|
+
*
|
|
293
|
+
* Implement this with hosted payment providers such as Stripe. Application
|
|
294
|
+
* billing logic should depend on this interface instead of provider SDKs.
|
|
295
|
+
*/
|
|
296
|
+
export interface PaymentsPort {
|
|
297
|
+
/**
|
|
298
|
+
* Create a hosted checkout session.
|
|
299
|
+
*/
|
|
300
|
+
createCheckoutSession(
|
|
301
|
+
input: CreateCheckoutSessionInput,
|
|
302
|
+
): Promise<CheckoutSession>;
|
|
303
|
+
/**
|
|
304
|
+
* Create a hosted billing portal session.
|
|
305
|
+
*/
|
|
306
|
+
createBillingPortalSession(
|
|
307
|
+
input: CreateBillingPortalSessionInput,
|
|
308
|
+
): Promise<BillingPortalSession>;
|
|
309
|
+
/**
|
|
310
|
+
* Create a refund.
|
|
311
|
+
*/
|
|
312
|
+
createRefund(input: CreateRefundInput): Promise<Refund>;
|
|
313
|
+
/**
|
|
314
|
+
* Verify and parse a provider webhook.
|
|
315
|
+
*/
|
|
316
|
+
verifyWebhook(input: VerifyPaymentWebhookInput): Promise<PaymentWebhookEvent>;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Error thrown by payment helpers and provider adapters.
|
|
321
|
+
*/
|
|
322
|
+
export class PaymentProviderError extends Error {
|
|
323
|
+
/**
|
|
324
|
+
* Provider name when known.
|
|
325
|
+
*/
|
|
326
|
+
readonly provider?: string;
|
|
327
|
+
/**
|
|
328
|
+
* Operation that failed.
|
|
329
|
+
*/
|
|
330
|
+
readonly operation: string;
|
|
331
|
+
/**
|
|
332
|
+
* Provider error code when known.
|
|
333
|
+
*/
|
|
334
|
+
readonly code?: string;
|
|
335
|
+
/**
|
|
336
|
+
* Original provider error when available.
|
|
337
|
+
*/
|
|
338
|
+
readonly cause?: unknown;
|
|
339
|
+
|
|
340
|
+
constructor(args: {
|
|
341
|
+
provider?: string;
|
|
342
|
+
operation: string;
|
|
343
|
+
message: string;
|
|
344
|
+
code?: string;
|
|
345
|
+
cause?: unknown;
|
|
346
|
+
}) {
|
|
347
|
+
super(args.message);
|
|
348
|
+
this.name = "PaymentProviderError";
|
|
349
|
+
this.provider = args.provider;
|
|
350
|
+
this.operation = args.operation;
|
|
351
|
+
this.code = args.code;
|
|
352
|
+
this.cause = args.cause;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Captured checkout session created by the memory payments adapter.
|
|
358
|
+
*/
|
|
359
|
+
export type MemoryCheckoutSession = CheckoutSession & {
|
|
360
|
+
input: CreateCheckoutSessionInput;
|
|
361
|
+
createdAt: Date;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Captured billing portal session created by the memory payments adapter.
|
|
366
|
+
*/
|
|
367
|
+
export type MemoryBillingPortalSession = BillingPortalSession & {
|
|
368
|
+
input: CreateBillingPortalSessionInput;
|
|
369
|
+
createdAt: Date;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Captured refund created by the memory payments adapter.
|
|
374
|
+
*/
|
|
375
|
+
export type MemoryRefund = Refund & {
|
|
376
|
+
input: CreateRefundInput;
|
|
377
|
+
createdAt: Date;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* In-memory payments port for tests and local examples.
|
|
382
|
+
*/
|
|
383
|
+
export interface MemoryPaymentsPort extends PaymentsPort {
|
|
384
|
+
/**
|
|
385
|
+
* Captured checkout sessions.
|
|
386
|
+
*/
|
|
387
|
+
readonly checkoutSessions: readonly MemoryCheckoutSession[];
|
|
388
|
+
/**
|
|
389
|
+
* Captured billing portal sessions.
|
|
390
|
+
*/
|
|
391
|
+
readonly billingPortalSessions: readonly MemoryBillingPortalSession[];
|
|
392
|
+
/**
|
|
393
|
+
* Captured refunds.
|
|
394
|
+
*/
|
|
395
|
+
readonly refunds: readonly MemoryRefund[];
|
|
396
|
+
/**
|
|
397
|
+
* Webhook events that were verified by the memory adapter.
|
|
398
|
+
*/
|
|
399
|
+
readonly webhookEvents: readonly PaymentWebhookEvent[];
|
|
400
|
+
/**
|
|
401
|
+
* Queue a webhook event to be returned by the next `verifyWebhook(...)` call.
|
|
402
|
+
*/
|
|
403
|
+
queueWebhookEvent(event: PaymentWebhookEvent): void;
|
|
404
|
+
/**
|
|
405
|
+
* Clear captured state.
|
|
406
|
+
*/
|
|
407
|
+
clear(): void;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Options for `createMemoryPayments(...)`.
|
|
412
|
+
*/
|
|
413
|
+
export interface CreateMemoryPaymentsOptions {
|
|
414
|
+
/**
|
|
415
|
+
* Clock used for captured payment objects.
|
|
416
|
+
*/
|
|
417
|
+
now?: () => Date;
|
|
418
|
+
/**
|
|
419
|
+
* ID factory used for captured payment objects.
|
|
420
|
+
*/
|
|
421
|
+
id?: (prefix: string) => string;
|
|
422
|
+
/**
|
|
423
|
+
* Observer called after a checkout session is created.
|
|
424
|
+
*/
|
|
425
|
+
onCheckoutSessionCreated?: (
|
|
426
|
+
session: MemoryCheckoutSession,
|
|
427
|
+
) => MaybePromise<void>;
|
|
428
|
+
/**
|
|
429
|
+
* Observer called after a billing portal session is created.
|
|
430
|
+
*/
|
|
431
|
+
onBillingPortalSessionCreated?: (
|
|
432
|
+
session: MemoryBillingPortalSession,
|
|
433
|
+
) => MaybePromise<void>;
|
|
434
|
+
/**
|
|
435
|
+
* Observer called after a refund is created.
|
|
436
|
+
*/
|
|
437
|
+
onRefundCreated?: (refund: MemoryRefund) => MaybePromise<void>;
|
|
438
|
+
/**
|
|
439
|
+
* Observer called after a webhook event is verified.
|
|
440
|
+
*/
|
|
441
|
+
onWebhookVerified?: (event: PaymentWebhookEvent) => MaybePromise<void>;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function defaultMemoryId(prefix: string): string {
|
|
445
|
+
return `${prefix}_${crypto.randomUUID()}`;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function cloneMetadata(
|
|
449
|
+
metadata: PaymentMetadata | undefined,
|
|
450
|
+
): PaymentMetadata | undefined {
|
|
451
|
+
return metadata ? { ...metadata } : undefined;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function cloneCheckoutInput(
|
|
455
|
+
input: CreateCheckoutSessionInput,
|
|
456
|
+
): CreateCheckoutSessionInput {
|
|
457
|
+
return {
|
|
458
|
+
...input,
|
|
459
|
+
lineItems: input.lineItems.map((item) => ({ ...item })),
|
|
460
|
+
metadata: cloneMetadata(input.metadata),
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function cloneRefundInput(input: CreateRefundInput): CreateRefundInput {
|
|
465
|
+
return {
|
|
466
|
+
...input,
|
|
467
|
+
metadata: cloneMetadata(input.metadata),
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Create an in-memory payments port for tests, local development, and
|
|
473
|
+
* examples.
|
|
474
|
+
*
|
|
475
|
+
* The memory adapter does not contact a payment provider or validate webhook
|
|
476
|
+
* signatures. Queue webhook events explicitly with `queueWebhookEvent(...)`.
|
|
477
|
+
*/
|
|
478
|
+
export function createMemoryPayments(
|
|
479
|
+
options: CreateMemoryPaymentsOptions = {},
|
|
480
|
+
): MemoryPaymentsPort {
|
|
481
|
+
const checkoutSessions: MemoryCheckoutSession[] = [];
|
|
482
|
+
const billingPortalSessions: MemoryBillingPortalSession[] = [];
|
|
483
|
+
const refunds: MemoryRefund[] = [];
|
|
484
|
+
const webhookEvents: PaymentWebhookEvent[] = [];
|
|
485
|
+
const queuedWebhookEvents: PaymentWebhookEvent[] = [];
|
|
486
|
+
const now = options.now ?? (() => new Date());
|
|
487
|
+
const id = options.id ?? defaultMemoryId;
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
get checkoutSessions() {
|
|
491
|
+
return checkoutSessions;
|
|
492
|
+
},
|
|
493
|
+
|
|
494
|
+
get billingPortalSessions() {
|
|
495
|
+
return billingPortalSessions;
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
get refunds() {
|
|
499
|
+
return refunds;
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
get webhookEvents() {
|
|
503
|
+
return webhookEvents;
|
|
504
|
+
},
|
|
505
|
+
|
|
506
|
+
async createCheckoutSession(input) {
|
|
507
|
+
const session: MemoryCheckoutSession = {
|
|
508
|
+
id: id("checkout"),
|
|
509
|
+
provider: "memory",
|
|
510
|
+
mode: input.mode,
|
|
511
|
+
url: `https://payments.example.test/checkout/${id("url")}`,
|
|
512
|
+
customerId: input.customerId,
|
|
513
|
+
metadata: cloneMetadata(input.metadata),
|
|
514
|
+
input: cloneCheckoutInput(input),
|
|
515
|
+
createdAt: now(),
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
checkoutSessions.push(session);
|
|
519
|
+
await options.onCheckoutSessionCreated?.(session);
|
|
520
|
+
|
|
521
|
+
return session;
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
async createBillingPortalSession(input) {
|
|
525
|
+
const session: MemoryBillingPortalSession = {
|
|
526
|
+
id: id("portal"),
|
|
527
|
+
provider: "memory",
|
|
528
|
+
url: `https://payments.example.test/portal/${id("url")}`,
|
|
529
|
+
customerId: input.customerId,
|
|
530
|
+
input: { ...input },
|
|
531
|
+
createdAt: now(),
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
billingPortalSessions.push(session);
|
|
535
|
+
await options.onBillingPortalSessionCreated?.(session);
|
|
536
|
+
|
|
537
|
+
return session;
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
async createRefund(input) {
|
|
541
|
+
const refund: MemoryRefund = {
|
|
542
|
+
id: id("refund"),
|
|
543
|
+
provider: "memory",
|
|
544
|
+
paymentId: input.paymentId,
|
|
545
|
+
amount: input.amount,
|
|
546
|
+
status: "succeeded",
|
|
547
|
+
metadata: cloneMetadata(input.metadata),
|
|
548
|
+
input: cloneRefundInput(input),
|
|
549
|
+
createdAt: now(),
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
refunds.push(refund);
|
|
553
|
+
await options.onRefundCreated?.(refund);
|
|
554
|
+
|
|
555
|
+
return refund;
|
|
556
|
+
},
|
|
557
|
+
|
|
558
|
+
async verifyWebhook() {
|
|
559
|
+
const event = queuedWebhookEvents.shift();
|
|
560
|
+
if (!event) {
|
|
561
|
+
throw new PaymentProviderError({
|
|
562
|
+
provider: "memory",
|
|
563
|
+
operation: "payments.verifyWebhook",
|
|
564
|
+
message:
|
|
565
|
+
"No memory payment webhook event is queued. Call queueWebhookEvent(...) before verifyWebhook(...).",
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
webhookEvents.push(event);
|
|
570
|
+
await options.onWebhookVerified?.(event);
|
|
571
|
+
|
|
572
|
+
return event;
|
|
573
|
+
},
|
|
574
|
+
|
|
575
|
+
queueWebhookEvent(event) {
|
|
576
|
+
queuedWebhookEvents.push(event);
|
|
577
|
+
},
|
|
578
|
+
|
|
579
|
+
clear() {
|
|
580
|
+
checkoutSessions.length = 0;
|
|
581
|
+
billingPortalSessions.length = 0;
|
|
582
|
+
refunds.length = 0;
|
|
583
|
+
webhookEvents.length = 0;
|
|
584
|
+
queuedWebhookEvents.length = 0;
|
|
585
|
+
},
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Options for the memory payments provider.
|
|
591
|
+
*/
|
|
592
|
+
export interface MemoryPaymentsProviderOptions
|
|
593
|
+
extends CreateMemoryPaymentsOptions {
|
|
594
|
+
/**
|
|
595
|
+
* Provider name. Defaults to "memory-payments".
|
|
596
|
+
*/
|
|
597
|
+
name?: string;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Ports contributed by the memory payments provider.
|
|
602
|
+
*/
|
|
603
|
+
export interface MemoryPaymentsProviderPorts {
|
|
604
|
+
/**
|
|
605
|
+
* Beignet payments port.
|
|
606
|
+
*/
|
|
607
|
+
payments: PaymentsPort;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Create a provider that contributes an in-memory payments port.
|
|
612
|
+
*/
|
|
613
|
+
export function createMemoryPaymentsProvider(
|
|
614
|
+
options: MemoryPaymentsProviderOptions = {},
|
|
615
|
+
) {
|
|
616
|
+
const {
|
|
617
|
+
name = "memory-payments",
|
|
618
|
+
onCheckoutSessionCreated,
|
|
619
|
+
onBillingPortalSessionCreated,
|
|
620
|
+
onRefundCreated,
|
|
621
|
+
onWebhookVerified,
|
|
622
|
+
...paymentsOptions
|
|
623
|
+
} = options;
|
|
624
|
+
|
|
625
|
+
return createProvider({
|
|
626
|
+
name,
|
|
627
|
+
metadata: {
|
|
628
|
+
ports: ["payments"],
|
|
629
|
+
watchers: ["payments"],
|
|
630
|
+
},
|
|
631
|
+
setup({ ports }) {
|
|
632
|
+
const instrumentation = createProviderInstrumentation(ports, {
|
|
633
|
+
providerName: name,
|
|
634
|
+
watcher: "payments",
|
|
635
|
+
});
|
|
636
|
+
const payments: PaymentsPort = createMemoryPayments({
|
|
637
|
+
...paymentsOptions,
|
|
638
|
+
async onCheckoutSessionCreated(session) {
|
|
639
|
+
instrumentation.custom({
|
|
640
|
+
name: "payments.checkout.created",
|
|
641
|
+
label: "Checkout session created",
|
|
642
|
+
summary: session.id,
|
|
643
|
+
details: {
|
|
644
|
+
id: session.id,
|
|
645
|
+
mode: session.mode,
|
|
646
|
+
customerId: session.customerId,
|
|
647
|
+
},
|
|
648
|
+
});
|
|
649
|
+
await onCheckoutSessionCreated?.(session);
|
|
650
|
+
},
|
|
651
|
+
async onBillingPortalSessionCreated(session) {
|
|
652
|
+
instrumentation.custom({
|
|
653
|
+
name: "payments.portal.created",
|
|
654
|
+
label: "Billing portal session created",
|
|
655
|
+
summary: session.id,
|
|
656
|
+
details: {
|
|
657
|
+
id: session.id,
|
|
658
|
+
customerId: session.customerId,
|
|
659
|
+
},
|
|
660
|
+
});
|
|
661
|
+
await onBillingPortalSessionCreated?.(session);
|
|
662
|
+
},
|
|
663
|
+
async onRefundCreated(refund) {
|
|
664
|
+
instrumentation.custom({
|
|
665
|
+
name: "payments.refund.created",
|
|
666
|
+
label: "Refund created",
|
|
667
|
+
summary: refund.id,
|
|
668
|
+
details: {
|
|
669
|
+
id: refund.id,
|
|
670
|
+
paymentId: refund.paymentId,
|
|
671
|
+
amount: refund.amount,
|
|
672
|
+
status: refund.status,
|
|
673
|
+
},
|
|
674
|
+
});
|
|
675
|
+
await onRefundCreated?.(refund);
|
|
676
|
+
},
|
|
677
|
+
async onWebhookVerified(event) {
|
|
678
|
+
instrumentation.custom({
|
|
679
|
+
name: "payments.webhook.verified",
|
|
680
|
+
label: "Payment webhook verified",
|
|
681
|
+
summary: event.type,
|
|
682
|
+
details: {
|
|
683
|
+
id: event.id,
|
|
684
|
+
eventType: event.type,
|
|
685
|
+
livemode: event.livemode,
|
|
686
|
+
},
|
|
687
|
+
});
|
|
688
|
+
await onWebhookVerified?.(event);
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
return {
|
|
693
|
+
ports: {
|
|
694
|
+
payments,
|
|
695
|
+
} satisfies MemoryPaymentsProviderPorts,
|
|
696
|
+
};
|
|
697
|
+
},
|
|
698
|
+
});
|
|
699
|
+
}
|