@funnelfox/payments-sdk 0.1.2-beta.8 → 0.2.0-beta.1
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/dist/index.cjs +229 -46
- package/dist/index.d.cts +65 -3
- package/dist/index.d.ts +65 -3
- package/dist/index.js +229 -46
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -61,7 +61,9 @@ function buildStripeCheckoutSessionBody(params) {
|
|
|
61
61
|
} : {}
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
|
-
...params.upgrade && { upgrade: params.upgrade }
|
|
64
|
+
...params.upgrade && { upgrade: params.upgrade },
|
|
65
|
+
...params.walletFirst && { wallet_first: params.walletFirst },
|
|
66
|
+
...params.uiMode && { ui_mode: params.uiMode }
|
|
65
67
|
};
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -124,55 +126,195 @@ var StripeCheckoutService = class extends HttpService {
|
|
|
124
126
|
}
|
|
125
127
|
};
|
|
126
128
|
|
|
129
|
+
// src/providers/stripe/ui/embedded-page.ts
|
|
130
|
+
var StripeEmbeddedPageUi = class {
|
|
131
|
+
checkout = null;
|
|
132
|
+
async mount(stripe, container, host) {
|
|
133
|
+
try {
|
|
134
|
+
this.checkout = await stripe.createEmbeddedCheckoutPage({
|
|
135
|
+
fetchClientSecret: () => host.clientSecret(),
|
|
136
|
+
onComplete: () => host.succeeded()
|
|
137
|
+
});
|
|
138
|
+
} catch (err) {
|
|
139
|
+
host.renderFailed(err, { message: err instanceof Error ? err.message : void 0 });
|
|
140
|
+
if (err instanceof CheckoutError) throw err;
|
|
141
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
142
|
+
throw new CheckoutError(`Stripe checkout failed: ${detail}`);
|
|
143
|
+
}
|
|
144
|
+
this.checkout.mount(container);
|
|
145
|
+
}
|
|
146
|
+
destroy() {
|
|
147
|
+
this.checkout?.destroy();
|
|
148
|
+
this.checkout = null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// src/providers/stripe/ui/form.ts
|
|
153
|
+
var CHECKOUT_FORM_BETA = "custom_checkout_payment_form_1";
|
|
154
|
+
var StripeFormUi = class {
|
|
155
|
+
constructor(options = {}) {
|
|
156
|
+
this.options = options;
|
|
157
|
+
}
|
|
158
|
+
options;
|
|
159
|
+
loadOptions = { betas: [CHECKOUT_FORM_BETA] };
|
|
160
|
+
checkout = null;
|
|
161
|
+
form = null;
|
|
162
|
+
async mount(stripe, container, host) {
|
|
163
|
+
const { appearance, fonts, loader, layout, expressCheckout } = this.options;
|
|
164
|
+
const startedAt = Date.now();
|
|
165
|
+
try {
|
|
166
|
+
if (typeof stripe.initCheckoutFormSdk !== "function") {
|
|
167
|
+
throw new CheckoutError("Stripe has not granted this account access to Checkout Form");
|
|
168
|
+
}
|
|
169
|
+
this.checkout = stripe.initCheckoutFormSdk({
|
|
170
|
+
clientSecret: host.clientSecret(),
|
|
171
|
+
...appearance && { appearance },
|
|
172
|
+
...fonts?.length && { fonts },
|
|
173
|
+
...loader && { loader }
|
|
174
|
+
});
|
|
175
|
+
this.checkout.on("change", (session) => host.changed(fromSession(session)));
|
|
176
|
+
this.form = this.checkout.createForm({
|
|
177
|
+
...layout && { layout },
|
|
178
|
+
...expressCheckout && { expressCheckout }
|
|
179
|
+
});
|
|
180
|
+
this.form.on("ready", () => host.ready(Date.now() - startedAt));
|
|
181
|
+
this.form.on(
|
|
182
|
+
"loaderror",
|
|
183
|
+
(event) => host.renderFailed(event.error, { message: event.error.message })
|
|
184
|
+
);
|
|
185
|
+
this.form.on("change", (event) => host.changed(fromForm(event)));
|
|
186
|
+
this.form.on("cancel", () => host.cancelled());
|
|
187
|
+
this.form.mount(container);
|
|
188
|
+
const actions = await this.loadActions();
|
|
189
|
+
this.form.on("confirm", (event) => void this.confirm(actions, event, host));
|
|
190
|
+
} catch (err) {
|
|
191
|
+
host.renderFailed(err, { message: err instanceof Error ? err.message : void 0 });
|
|
192
|
+
if (err instanceof CheckoutError) throw err;
|
|
193
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
194
|
+
throw new CheckoutError(`Stripe checkout failed: ${detail}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
destroy() {
|
|
198
|
+
this.form?.destroy();
|
|
199
|
+
this.form = null;
|
|
200
|
+
this.checkout = null;
|
|
201
|
+
}
|
|
202
|
+
async loadActions() {
|
|
203
|
+
const result = await this.checkout.loadActions();
|
|
204
|
+
if (result.type !== "success") {
|
|
205
|
+
throw new CheckoutError(`Stripe checkout failed: ${result.error.message}`);
|
|
206
|
+
}
|
|
207
|
+
return result.actions;
|
|
208
|
+
}
|
|
209
|
+
async confirm(actions, event, host) {
|
|
210
|
+
const express = event.source === "checkout-form-ece";
|
|
211
|
+
const paymentMethodType = express ? void 0 : event.paymentMethodType ?? void 0;
|
|
212
|
+
host.confirmed({ paymentMethodType, express });
|
|
213
|
+
try {
|
|
214
|
+
const result = await actions.confirm({ formConfirmEvent: event, redirect: "if_required" });
|
|
215
|
+
if (result.type === "error") {
|
|
216
|
+
host.paymentFailed(result.error, {
|
|
217
|
+
declineCode: result.error.code === "paymentFailed" ? result.error.paymentFailed.declineCode : null,
|
|
218
|
+
message: result.error.message
|
|
219
|
+
});
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
host.succeeded(fromSession(result.session));
|
|
223
|
+
} catch (err) {
|
|
224
|
+
host.paymentFailed(err, { message: err instanceof Error ? err.message : void 0 });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
function fromSession(session) {
|
|
229
|
+
return {
|
|
230
|
+
email: session.email ?? void 0,
|
|
231
|
+
currency: session.currency,
|
|
232
|
+
amountTotal: session.total?.total?.minorUnitsAmount
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function fromForm(event) {
|
|
236
|
+
const { payment, customerDetails, adaptivePricing } = event.value;
|
|
237
|
+
return {
|
|
238
|
+
paymentMethodType: payment?.type,
|
|
239
|
+
email: customerDetails?.email || void 0,
|
|
240
|
+
currency: adaptivePricing?.currency,
|
|
241
|
+
complete: event.complete
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/providers/stripe/ui/index.ts
|
|
246
|
+
function createStripeCheckoutUi(config) {
|
|
247
|
+
switch (config.uiMode) {
|
|
248
|
+
case "form":
|
|
249
|
+
return new StripeFormUi(config.form);
|
|
250
|
+
default:
|
|
251
|
+
return new StripeEmbeddedPageUi();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
127
255
|
// src/providers/stripe/index.ts
|
|
128
256
|
var StripeProvider = class {
|
|
129
257
|
constructor(config, callbacks, baseUrl, headers) {
|
|
130
258
|
this.config = config;
|
|
131
259
|
this.callbacks = callbacks;
|
|
132
260
|
this.service = new StripeCheckoutService(baseUrl, headers);
|
|
261
|
+
this.ui = createStripeCheckoutUi(config);
|
|
133
262
|
}
|
|
134
263
|
config;
|
|
135
264
|
callbacks;
|
|
136
|
-
stripe = null;
|
|
137
|
-
embeddedCheckout = null;
|
|
138
265
|
service;
|
|
266
|
+
ui;
|
|
267
|
+
stripe = null;
|
|
268
|
+
mounted = false;
|
|
139
269
|
clientSecret = null;
|
|
270
|
+
snapshot = {};
|
|
140
271
|
async init() {
|
|
141
|
-
const stripe = await (0, import_stripe_js.loadStripe)(this.config.publishableKey);
|
|
272
|
+
const stripe = await (0, import_stripe_js.loadStripe)(this.config.publishableKey, this.ui.loadOptions);
|
|
142
273
|
if (!stripe) {
|
|
143
|
-
|
|
274
|
+
const error = new CheckoutError("Failed to load Stripe.js \u2014 verify your publishableKey");
|
|
275
|
+
this.emitError("init", error, { message: error.message });
|
|
276
|
+
throw error;
|
|
144
277
|
}
|
|
145
278
|
this.stripe = stripe;
|
|
146
279
|
}
|
|
147
|
-
async render(container,
|
|
280
|
+
async render(container, _options) {
|
|
148
281
|
if (!this.stripe) {
|
|
149
282
|
throw new CheckoutError("Provider not initialized \u2014 call init() before render()");
|
|
150
283
|
}
|
|
151
|
-
if (this.
|
|
284
|
+
if (this.mounted) {
|
|
152
285
|
throw new CheckoutError("Already rendered \u2014 call destroy() before rendering again");
|
|
153
286
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
fetchClientSecret: () => this.fetchClientSecret(),
|
|
157
|
-
onComplete: () => this.handleComplete(),
|
|
158
|
-
onAnalyticsEvent: (event) => console.log("[stripe analytics]", event.eventType, event)
|
|
159
|
-
});
|
|
160
|
-
} catch (err) {
|
|
161
|
-
this.callbacks.onError?.({ provider: "stripe", error: err });
|
|
162
|
-
if (err instanceof CheckoutError) throw err;
|
|
163
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
164
|
-
throw new CheckoutError(`Stripe checkout failed: ${detail}`);
|
|
165
|
-
}
|
|
166
|
-
this.embeddedCheckout.mount(container);
|
|
287
|
+
this.mounted = true;
|
|
288
|
+
await this.ui.mount(this.stripe, container, this.host());
|
|
167
289
|
}
|
|
168
290
|
async reset() {
|
|
169
291
|
this.destroy();
|
|
170
292
|
}
|
|
171
293
|
destroy() {
|
|
172
|
-
this.
|
|
173
|
-
this.
|
|
294
|
+
this.ui.destroy();
|
|
295
|
+
this.mounted = false;
|
|
296
|
+
this.snapshot = {};
|
|
174
297
|
}
|
|
175
|
-
|
|
298
|
+
host() {
|
|
299
|
+
return {
|
|
300
|
+
clientSecret: () => this.createSession(),
|
|
301
|
+
ready: (durationMs) => this.callbacks.onReady?.({ provider: "stripe", durationMs }),
|
|
302
|
+
changed: (patch) => this.merge(patch),
|
|
303
|
+
confirmed: ({ paymentMethodType, express }) => this.callbacks.onConfirm?.({
|
|
304
|
+
provider: "stripe",
|
|
305
|
+
paymentMethodType: paymentMethodType ?? this.snapshot.paymentMethodType,
|
|
306
|
+
express
|
|
307
|
+
}),
|
|
308
|
+
cancelled: () => this.callbacks.onCancel?.({
|
|
309
|
+
provider: "stripe",
|
|
310
|
+
paymentMethodType: this.snapshot.paymentMethodType
|
|
311
|
+
}),
|
|
312
|
+
renderFailed: (error, detail) => this.emitError("render", error, detail),
|
|
313
|
+
paymentFailed: (error, detail) => this.emitError("payment", error, detail),
|
|
314
|
+
succeeded: (outcome) => void this.emitComplete(outcome)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
async createSession() {
|
|
176
318
|
const secret = await this.service.createCheckoutSession({
|
|
177
319
|
...this.config,
|
|
178
320
|
returnUrl: this.config.returnUrl ?? window.location.href
|
|
@@ -181,33 +323,74 @@ var StripeProvider = class {
|
|
|
181
323
|
return secret;
|
|
182
324
|
}
|
|
183
325
|
// Format: cs_test_{sessionId}_secret_{random}
|
|
184
|
-
|
|
185
|
-
if (!clientSecret)
|
|
186
|
-
|
|
187
|
-
return idx !== -1 ? clientSecret.slice(0, idx) : null;
|
|
188
|
-
}
|
|
189
|
-
async handleComplete() {
|
|
190
|
-
const sessionId = this.parseSessionId(this.clientSecret);
|
|
191
|
-
if (!sessionId) {
|
|
192
|
-
this.callbacks.onComplete?.({ provider: "stripe" });
|
|
193
|
-
return;
|
|
326
|
+
sessionId() {
|
|
327
|
+
if (!this.clientSecret) {
|
|
328
|
+
return null;
|
|
194
329
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
330
|
+
const idx = this.clientSecret.indexOf("_secret_");
|
|
331
|
+
return idx !== -1 ? this.clientSecret.slice(0, idx) : null;
|
|
332
|
+
}
|
|
333
|
+
merge(patch) {
|
|
334
|
+
const next = { ...this.snapshot };
|
|
335
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
336
|
+
if (value !== void 0) {
|
|
337
|
+
Object.assign(next, { [key]: value });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
this.snapshot = next;
|
|
341
|
+
this.callbacks.onChange?.({ provider: "stripe", ...next });
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Reads the session back for the ids only the backend can resolve, falling
|
|
345
|
+
* back to what the client already knows so a paid customer is never
|
|
346
|
+
* reported as a failure.
|
|
347
|
+
*/
|
|
348
|
+
async emitComplete(outcome) {
|
|
349
|
+
const sessionId = this.sessionId();
|
|
350
|
+
const fallback = {
|
|
351
|
+
amount_total: outcome?.amountTotal ?? null,
|
|
352
|
+
currency: outcome?.currency ?? null,
|
|
353
|
+
email: outcome?.email ?? null
|
|
354
|
+
};
|
|
355
|
+
let session = {};
|
|
356
|
+
if (sessionId) {
|
|
357
|
+
try {
|
|
358
|
+
session = definedOnly(await this.service.getSession(sessionId, this.config.accountId));
|
|
359
|
+
} catch {
|
|
360
|
+
session = {};
|
|
361
|
+
}
|
|
208
362
|
}
|
|
363
|
+
this.callbacks.onComplete?.({
|
|
364
|
+
provider: "stripe",
|
|
365
|
+
paymentMethodType: this.snapshot.paymentMethodType,
|
|
366
|
+
...toCompleteFields({ ...fallback, ...session })
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
emitError(phase, error, detail) {
|
|
370
|
+
this.callbacks.onError?.({
|
|
371
|
+
provider: "stripe",
|
|
372
|
+
phase,
|
|
373
|
+
paymentMethodType: this.snapshot.paymentMethodType,
|
|
374
|
+
error,
|
|
375
|
+
...detail
|
|
376
|
+
});
|
|
209
377
|
}
|
|
210
378
|
};
|
|
379
|
+
function definedOnly(session) {
|
|
380
|
+
return Object.fromEntries(
|
|
381
|
+
Object.entries(session).filter(([, value]) => value !== null && value !== void 0)
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
function toCompleteFields(session) {
|
|
385
|
+
return {
|
|
386
|
+
customerId: session.customer_id ?? void 0,
|
|
387
|
+
subscriptionId: session.subscription_id ?? void 0,
|
|
388
|
+
invoiceId: session.invoice_id ?? void 0,
|
|
389
|
+
amountPaid: session.amount_total ?? void 0,
|
|
390
|
+
currency: session.currency ?? void 0,
|
|
391
|
+
email: session.email ?? void 0
|
|
392
|
+
};
|
|
393
|
+
}
|
|
211
394
|
|
|
212
395
|
// src/providers/fastspring/index.ts
|
|
213
396
|
var FastSpringProvider = class {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
import { Appearance, CssFontSource, CustomFontSource, StripeCheckoutFormOptions } from '@stripe/stripe-js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Known values are suggested; providers may report their own ids
|
|
5
|
+
* (Stripe form reports e.g. `sepa_debit`, `link`, `klarna`).
|
|
6
|
+
*/
|
|
7
|
+
type PaymentMethodType = 'card' | 'google_pay' | 'apple_pay' | (string & {});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* How Stripe renders checkout. Independent of `managed`, which decides
|
|
11
|
+
* merchant of record — Stripe treats them as two parameters of one session.
|
|
12
|
+
*/
|
|
13
|
+
type StripeUiMode = 'embedded_page' | 'form';
|
|
14
|
+
/** Client-side UI options for `uiMode: 'form'`. */
|
|
15
|
+
interface StripeFormOptions {
|
|
16
|
+
/** Form supports the whole Appearance API except `rules`. */
|
|
17
|
+
appearance?: Omit<Appearance, 'rules'>;
|
|
18
|
+
/** Font sources so `appearance.variables.fontFamily` resolves inside the iframe. */
|
|
19
|
+
fonts?: Array<CssFontSource | CustomFontSource>;
|
|
20
|
+
loader?: 'auto' | 'always' | 'never';
|
|
21
|
+
/** Omit to let Stripe pick the layout it expects to convert best. */
|
|
22
|
+
layout?: StripeCheckoutFormOptions['layout'];
|
|
23
|
+
expressCheckout?: StripeCheckoutFormOptions['expressCheckout'];
|
|
24
|
+
}
|
|
3
25
|
interface StripeCustomer {
|
|
4
26
|
email?: string;
|
|
5
27
|
phone?: string;
|
|
@@ -39,6 +61,12 @@ interface StripeConfig {
|
|
|
39
61
|
trial?: StripeCheckoutTrial;
|
|
40
62
|
/** When true, treats this as a subscription upgrade — requires customerId to be set */
|
|
41
63
|
upgrade?: boolean;
|
|
64
|
+
/** When true, surfaces Apple Pay / Google Pay as the primary payment option (Wallet-First mode) */
|
|
65
|
+
walletFirst?: boolean;
|
|
66
|
+
/** Which checkout UI Stripe renders. Defaults to `embedded_page`. */
|
|
67
|
+
uiMode?: StripeUiMode;
|
|
68
|
+
/** UI options applied only when `uiMode` is `form`. */
|
|
69
|
+
form?: StripeFormOptions;
|
|
42
70
|
}
|
|
43
71
|
|
|
44
72
|
interface FastSpringConfig {
|
|
@@ -77,20 +105,54 @@ interface CheckoutCompleteEvent {
|
|
|
77
105
|
currency?: string;
|
|
78
106
|
email?: string;
|
|
79
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Where a checkout failed. `init`/`render` mean the UI never became usable;
|
|
110
|
+
* `payment` means the buyer's charge was declined or errored.
|
|
111
|
+
*/
|
|
112
|
+
type CheckoutErrorPhase = 'init' | 'render' | 'payment';
|
|
80
113
|
interface CheckoutErrorEvent {
|
|
81
114
|
provider: ProviderName;
|
|
82
115
|
paymentMethodType?: PaymentMethodType;
|
|
116
|
+
phase: CheckoutErrorPhase;
|
|
117
|
+
/** Provider decline code when it exposes one, for mapping to a failure reason. */
|
|
118
|
+
declineCode?: string | null;
|
|
119
|
+
message?: string;
|
|
83
120
|
error: unknown;
|
|
84
121
|
}
|
|
85
122
|
interface CheckoutCancelEvent {
|
|
86
123
|
provider: ProviderName;
|
|
87
124
|
paymentMethodType?: PaymentMethodType;
|
|
88
125
|
}
|
|
126
|
+
interface CheckoutReadyEvent {
|
|
127
|
+
provider: ProviderName;
|
|
128
|
+
/** Milliseconds from render() to the checkout UI being usable. */
|
|
129
|
+
durationMs: number;
|
|
130
|
+
}
|
|
131
|
+
/** The buyer authorized the payment; the charge is not confirmed yet. */
|
|
132
|
+
interface CheckoutConfirmEvent {
|
|
133
|
+
provider: ProviderName;
|
|
134
|
+
paymentMethodType?: PaymentMethodType;
|
|
135
|
+
/** Authorized through a wallet button rather than the pay button. */
|
|
136
|
+
express: boolean;
|
|
137
|
+
}
|
|
138
|
+
/** Latest snapshot of what the buyer selected and what they will be charged. */
|
|
139
|
+
interface CheckoutChangeEvent {
|
|
140
|
+
provider: ProviderName;
|
|
141
|
+
paymentMethodType?: PaymentMethodType;
|
|
142
|
+
email?: string;
|
|
143
|
+
/** Currency actually charged — Adaptive Pricing may differ from the listed one. */
|
|
144
|
+
currency?: string;
|
|
145
|
+
amountTotal?: number;
|
|
146
|
+
complete?: boolean;
|
|
147
|
+
}
|
|
89
148
|
|
|
90
149
|
interface CheckoutCallbacks {
|
|
91
150
|
onComplete?: (event: CheckoutCompleteEvent) => void;
|
|
92
151
|
onError?: (event: CheckoutErrorEvent) => void;
|
|
93
152
|
onCancel?: (event: CheckoutCancelEvent) => void;
|
|
153
|
+
onReady?: (event: CheckoutReadyEvent) => void;
|
|
154
|
+
onConfirm?: (event: CheckoutConfirmEvent) => void;
|
|
155
|
+
onChange?: (event: CheckoutChangeEvent) => void;
|
|
94
156
|
}
|
|
95
157
|
|
|
96
158
|
interface RenderOptions {
|
|
@@ -121,9 +183,9 @@ declare class CheckoutError extends Error {
|
|
|
121
183
|
constructor(message: string);
|
|
122
184
|
}
|
|
123
185
|
|
|
124
|
-
type CreateCheckoutSessionParams =
|
|
186
|
+
type CreateCheckoutSessionParams = Omit<StripeConfig, 'publishableKey' | 'returnUrl' | 'form'> & {
|
|
125
187
|
returnUrl: string;
|
|
126
188
|
};
|
|
127
189
|
declare function buildStripeCheckoutSessionBody(params: CreateCheckoutSessionParams): Record<string, unknown>;
|
|
128
190
|
|
|
129
|
-
export { type CheckoutCallbacks, type CheckoutCancelEvent, type CheckoutCompleteEvent, CheckoutError, type CheckoutErrorEvent, type CheckoutInstance, type CreateCheckoutSessionParams, type FastSpringConfig, type PaymentMethodType, type PaymentProvider, type ProviderConfigMap, type ProviderName, type RenderOptions, type StripeCheckoutTrial, type StripeConfig, buildStripeCheckoutSessionBody, initCheckout };
|
|
191
|
+
export { type CheckoutCallbacks, type CheckoutCancelEvent, type CheckoutChangeEvent, type CheckoutCompleteEvent, type CheckoutConfirmEvent, CheckoutError, type CheckoutErrorEvent, type CheckoutErrorPhase, type CheckoutInstance, type CheckoutReadyEvent, type CreateCheckoutSessionParams, type FastSpringConfig, type PaymentMethodType, type PaymentProvider, type ProviderConfigMap, type ProviderName, type RenderOptions, type StripeCheckoutTrial, type StripeConfig, type StripeFormOptions, type StripeUiMode, buildStripeCheckoutSessionBody, initCheckout };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
import { Appearance, CssFontSource, CustomFontSource, StripeCheckoutFormOptions } from '@stripe/stripe-js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Known values are suggested; providers may report their own ids
|
|
5
|
+
* (Stripe form reports e.g. `sepa_debit`, `link`, `klarna`).
|
|
6
|
+
*/
|
|
7
|
+
type PaymentMethodType = 'card' | 'google_pay' | 'apple_pay' | (string & {});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* How Stripe renders checkout. Independent of `managed`, which decides
|
|
11
|
+
* merchant of record — Stripe treats them as two parameters of one session.
|
|
12
|
+
*/
|
|
13
|
+
type StripeUiMode = 'embedded_page' | 'form';
|
|
14
|
+
/** Client-side UI options for `uiMode: 'form'`. */
|
|
15
|
+
interface StripeFormOptions {
|
|
16
|
+
/** Form supports the whole Appearance API except `rules`. */
|
|
17
|
+
appearance?: Omit<Appearance, 'rules'>;
|
|
18
|
+
/** Font sources so `appearance.variables.fontFamily` resolves inside the iframe. */
|
|
19
|
+
fonts?: Array<CssFontSource | CustomFontSource>;
|
|
20
|
+
loader?: 'auto' | 'always' | 'never';
|
|
21
|
+
/** Omit to let Stripe pick the layout it expects to convert best. */
|
|
22
|
+
layout?: StripeCheckoutFormOptions['layout'];
|
|
23
|
+
expressCheckout?: StripeCheckoutFormOptions['expressCheckout'];
|
|
24
|
+
}
|
|
3
25
|
interface StripeCustomer {
|
|
4
26
|
email?: string;
|
|
5
27
|
phone?: string;
|
|
@@ -39,6 +61,12 @@ interface StripeConfig {
|
|
|
39
61
|
trial?: StripeCheckoutTrial;
|
|
40
62
|
/** When true, treats this as a subscription upgrade — requires customerId to be set */
|
|
41
63
|
upgrade?: boolean;
|
|
64
|
+
/** When true, surfaces Apple Pay / Google Pay as the primary payment option (Wallet-First mode) */
|
|
65
|
+
walletFirst?: boolean;
|
|
66
|
+
/** Which checkout UI Stripe renders. Defaults to `embedded_page`. */
|
|
67
|
+
uiMode?: StripeUiMode;
|
|
68
|
+
/** UI options applied only when `uiMode` is `form`. */
|
|
69
|
+
form?: StripeFormOptions;
|
|
42
70
|
}
|
|
43
71
|
|
|
44
72
|
interface FastSpringConfig {
|
|
@@ -77,20 +105,54 @@ interface CheckoutCompleteEvent {
|
|
|
77
105
|
currency?: string;
|
|
78
106
|
email?: string;
|
|
79
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Where a checkout failed. `init`/`render` mean the UI never became usable;
|
|
110
|
+
* `payment` means the buyer's charge was declined or errored.
|
|
111
|
+
*/
|
|
112
|
+
type CheckoutErrorPhase = 'init' | 'render' | 'payment';
|
|
80
113
|
interface CheckoutErrorEvent {
|
|
81
114
|
provider: ProviderName;
|
|
82
115
|
paymentMethodType?: PaymentMethodType;
|
|
116
|
+
phase: CheckoutErrorPhase;
|
|
117
|
+
/** Provider decline code when it exposes one, for mapping to a failure reason. */
|
|
118
|
+
declineCode?: string | null;
|
|
119
|
+
message?: string;
|
|
83
120
|
error: unknown;
|
|
84
121
|
}
|
|
85
122
|
interface CheckoutCancelEvent {
|
|
86
123
|
provider: ProviderName;
|
|
87
124
|
paymentMethodType?: PaymentMethodType;
|
|
88
125
|
}
|
|
126
|
+
interface CheckoutReadyEvent {
|
|
127
|
+
provider: ProviderName;
|
|
128
|
+
/** Milliseconds from render() to the checkout UI being usable. */
|
|
129
|
+
durationMs: number;
|
|
130
|
+
}
|
|
131
|
+
/** The buyer authorized the payment; the charge is not confirmed yet. */
|
|
132
|
+
interface CheckoutConfirmEvent {
|
|
133
|
+
provider: ProviderName;
|
|
134
|
+
paymentMethodType?: PaymentMethodType;
|
|
135
|
+
/** Authorized through a wallet button rather than the pay button. */
|
|
136
|
+
express: boolean;
|
|
137
|
+
}
|
|
138
|
+
/** Latest snapshot of what the buyer selected and what they will be charged. */
|
|
139
|
+
interface CheckoutChangeEvent {
|
|
140
|
+
provider: ProviderName;
|
|
141
|
+
paymentMethodType?: PaymentMethodType;
|
|
142
|
+
email?: string;
|
|
143
|
+
/** Currency actually charged — Adaptive Pricing may differ from the listed one. */
|
|
144
|
+
currency?: string;
|
|
145
|
+
amountTotal?: number;
|
|
146
|
+
complete?: boolean;
|
|
147
|
+
}
|
|
89
148
|
|
|
90
149
|
interface CheckoutCallbacks {
|
|
91
150
|
onComplete?: (event: CheckoutCompleteEvent) => void;
|
|
92
151
|
onError?: (event: CheckoutErrorEvent) => void;
|
|
93
152
|
onCancel?: (event: CheckoutCancelEvent) => void;
|
|
153
|
+
onReady?: (event: CheckoutReadyEvent) => void;
|
|
154
|
+
onConfirm?: (event: CheckoutConfirmEvent) => void;
|
|
155
|
+
onChange?: (event: CheckoutChangeEvent) => void;
|
|
94
156
|
}
|
|
95
157
|
|
|
96
158
|
interface RenderOptions {
|
|
@@ -121,9 +183,9 @@ declare class CheckoutError extends Error {
|
|
|
121
183
|
constructor(message: string);
|
|
122
184
|
}
|
|
123
185
|
|
|
124
|
-
type CreateCheckoutSessionParams =
|
|
186
|
+
type CreateCheckoutSessionParams = Omit<StripeConfig, 'publishableKey' | 'returnUrl' | 'form'> & {
|
|
125
187
|
returnUrl: string;
|
|
126
188
|
};
|
|
127
189
|
declare function buildStripeCheckoutSessionBody(params: CreateCheckoutSessionParams): Record<string, unknown>;
|
|
128
190
|
|
|
129
|
-
export { type CheckoutCallbacks, type CheckoutCancelEvent, type CheckoutCompleteEvent, CheckoutError, type CheckoutErrorEvent, type CheckoutInstance, type CreateCheckoutSessionParams, type FastSpringConfig, type PaymentMethodType, type PaymentProvider, type ProviderConfigMap, type ProviderName, type RenderOptions, type StripeCheckoutTrial, type StripeConfig, buildStripeCheckoutSessionBody, initCheckout };
|
|
191
|
+
export { type CheckoutCallbacks, type CheckoutCancelEvent, type CheckoutChangeEvent, type CheckoutCompleteEvent, type CheckoutConfirmEvent, CheckoutError, type CheckoutErrorEvent, type CheckoutErrorPhase, type CheckoutInstance, type CheckoutReadyEvent, type CreateCheckoutSessionParams, type FastSpringConfig, type PaymentMethodType, type PaymentProvider, type ProviderConfigMap, type ProviderName, type RenderOptions, type StripeCheckoutTrial, type StripeConfig, type StripeFormOptions, type StripeUiMode, buildStripeCheckoutSessionBody, initCheckout };
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,9 @@ function buildStripeCheckoutSessionBody(params) {
|
|
|
33
33
|
} : {}
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
-
...params.upgrade && { upgrade: params.upgrade }
|
|
36
|
+
...params.upgrade && { upgrade: params.upgrade },
|
|
37
|
+
...params.walletFirst && { wallet_first: params.walletFirst },
|
|
38
|
+
...params.uiMode && { ui_mode: params.uiMode }
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -96,55 +98,195 @@ var StripeCheckoutService = class extends HttpService {
|
|
|
96
98
|
}
|
|
97
99
|
};
|
|
98
100
|
|
|
101
|
+
// src/providers/stripe/ui/embedded-page.ts
|
|
102
|
+
var StripeEmbeddedPageUi = class {
|
|
103
|
+
checkout = null;
|
|
104
|
+
async mount(stripe, container, host) {
|
|
105
|
+
try {
|
|
106
|
+
this.checkout = await stripe.createEmbeddedCheckoutPage({
|
|
107
|
+
fetchClientSecret: () => host.clientSecret(),
|
|
108
|
+
onComplete: () => host.succeeded()
|
|
109
|
+
});
|
|
110
|
+
} catch (err) {
|
|
111
|
+
host.renderFailed(err, { message: err instanceof Error ? err.message : void 0 });
|
|
112
|
+
if (err instanceof CheckoutError) throw err;
|
|
113
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
114
|
+
throw new CheckoutError(`Stripe checkout failed: ${detail}`);
|
|
115
|
+
}
|
|
116
|
+
this.checkout.mount(container);
|
|
117
|
+
}
|
|
118
|
+
destroy() {
|
|
119
|
+
this.checkout?.destroy();
|
|
120
|
+
this.checkout = null;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// src/providers/stripe/ui/form.ts
|
|
125
|
+
var CHECKOUT_FORM_BETA = "custom_checkout_payment_form_1";
|
|
126
|
+
var StripeFormUi = class {
|
|
127
|
+
constructor(options = {}) {
|
|
128
|
+
this.options = options;
|
|
129
|
+
}
|
|
130
|
+
options;
|
|
131
|
+
loadOptions = { betas: [CHECKOUT_FORM_BETA] };
|
|
132
|
+
checkout = null;
|
|
133
|
+
form = null;
|
|
134
|
+
async mount(stripe, container, host) {
|
|
135
|
+
const { appearance, fonts, loader, layout, expressCheckout } = this.options;
|
|
136
|
+
const startedAt = Date.now();
|
|
137
|
+
try {
|
|
138
|
+
if (typeof stripe.initCheckoutFormSdk !== "function") {
|
|
139
|
+
throw new CheckoutError("Stripe has not granted this account access to Checkout Form");
|
|
140
|
+
}
|
|
141
|
+
this.checkout = stripe.initCheckoutFormSdk({
|
|
142
|
+
clientSecret: host.clientSecret(),
|
|
143
|
+
...appearance && { appearance },
|
|
144
|
+
...fonts?.length && { fonts },
|
|
145
|
+
...loader && { loader }
|
|
146
|
+
});
|
|
147
|
+
this.checkout.on("change", (session) => host.changed(fromSession(session)));
|
|
148
|
+
this.form = this.checkout.createForm({
|
|
149
|
+
...layout && { layout },
|
|
150
|
+
...expressCheckout && { expressCheckout }
|
|
151
|
+
});
|
|
152
|
+
this.form.on("ready", () => host.ready(Date.now() - startedAt));
|
|
153
|
+
this.form.on(
|
|
154
|
+
"loaderror",
|
|
155
|
+
(event) => host.renderFailed(event.error, { message: event.error.message })
|
|
156
|
+
);
|
|
157
|
+
this.form.on("change", (event) => host.changed(fromForm(event)));
|
|
158
|
+
this.form.on("cancel", () => host.cancelled());
|
|
159
|
+
this.form.mount(container);
|
|
160
|
+
const actions = await this.loadActions();
|
|
161
|
+
this.form.on("confirm", (event) => void this.confirm(actions, event, host));
|
|
162
|
+
} catch (err) {
|
|
163
|
+
host.renderFailed(err, { message: err instanceof Error ? err.message : void 0 });
|
|
164
|
+
if (err instanceof CheckoutError) throw err;
|
|
165
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
166
|
+
throw new CheckoutError(`Stripe checkout failed: ${detail}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
destroy() {
|
|
170
|
+
this.form?.destroy();
|
|
171
|
+
this.form = null;
|
|
172
|
+
this.checkout = null;
|
|
173
|
+
}
|
|
174
|
+
async loadActions() {
|
|
175
|
+
const result = await this.checkout.loadActions();
|
|
176
|
+
if (result.type !== "success") {
|
|
177
|
+
throw new CheckoutError(`Stripe checkout failed: ${result.error.message}`);
|
|
178
|
+
}
|
|
179
|
+
return result.actions;
|
|
180
|
+
}
|
|
181
|
+
async confirm(actions, event, host) {
|
|
182
|
+
const express = event.source === "checkout-form-ece";
|
|
183
|
+
const paymentMethodType = express ? void 0 : event.paymentMethodType ?? void 0;
|
|
184
|
+
host.confirmed({ paymentMethodType, express });
|
|
185
|
+
try {
|
|
186
|
+
const result = await actions.confirm({ formConfirmEvent: event, redirect: "if_required" });
|
|
187
|
+
if (result.type === "error") {
|
|
188
|
+
host.paymentFailed(result.error, {
|
|
189
|
+
declineCode: result.error.code === "paymentFailed" ? result.error.paymentFailed.declineCode : null,
|
|
190
|
+
message: result.error.message
|
|
191
|
+
});
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
host.succeeded(fromSession(result.session));
|
|
195
|
+
} catch (err) {
|
|
196
|
+
host.paymentFailed(err, { message: err instanceof Error ? err.message : void 0 });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
function fromSession(session) {
|
|
201
|
+
return {
|
|
202
|
+
email: session.email ?? void 0,
|
|
203
|
+
currency: session.currency,
|
|
204
|
+
amountTotal: session.total?.total?.minorUnitsAmount
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function fromForm(event) {
|
|
208
|
+
const { payment, customerDetails, adaptivePricing } = event.value;
|
|
209
|
+
return {
|
|
210
|
+
paymentMethodType: payment?.type,
|
|
211
|
+
email: customerDetails?.email || void 0,
|
|
212
|
+
currency: adaptivePricing?.currency,
|
|
213
|
+
complete: event.complete
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/providers/stripe/ui/index.ts
|
|
218
|
+
function createStripeCheckoutUi(config) {
|
|
219
|
+
switch (config.uiMode) {
|
|
220
|
+
case "form":
|
|
221
|
+
return new StripeFormUi(config.form);
|
|
222
|
+
default:
|
|
223
|
+
return new StripeEmbeddedPageUi();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
99
227
|
// src/providers/stripe/index.ts
|
|
100
228
|
var StripeProvider = class {
|
|
101
229
|
constructor(config, callbacks, baseUrl, headers) {
|
|
102
230
|
this.config = config;
|
|
103
231
|
this.callbacks = callbacks;
|
|
104
232
|
this.service = new StripeCheckoutService(baseUrl, headers);
|
|
233
|
+
this.ui = createStripeCheckoutUi(config);
|
|
105
234
|
}
|
|
106
235
|
config;
|
|
107
236
|
callbacks;
|
|
108
|
-
stripe = null;
|
|
109
|
-
embeddedCheckout = null;
|
|
110
237
|
service;
|
|
238
|
+
ui;
|
|
239
|
+
stripe = null;
|
|
240
|
+
mounted = false;
|
|
111
241
|
clientSecret = null;
|
|
242
|
+
snapshot = {};
|
|
112
243
|
async init() {
|
|
113
|
-
const stripe = await loadStripe(this.config.publishableKey);
|
|
244
|
+
const stripe = await loadStripe(this.config.publishableKey, this.ui.loadOptions);
|
|
114
245
|
if (!stripe) {
|
|
115
|
-
|
|
246
|
+
const error = new CheckoutError("Failed to load Stripe.js \u2014 verify your publishableKey");
|
|
247
|
+
this.emitError("init", error, { message: error.message });
|
|
248
|
+
throw error;
|
|
116
249
|
}
|
|
117
250
|
this.stripe = stripe;
|
|
118
251
|
}
|
|
119
|
-
async render(container,
|
|
252
|
+
async render(container, _options) {
|
|
120
253
|
if (!this.stripe) {
|
|
121
254
|
throw new CheckoutError("Provider not initialized \u2014 call init() before render()");
|
|
122
255
|
}
|
|
123
|
-
if (this.
|
|
256
|
+
if (this.mounted) {
|
|
124
257
|
throw new CheckoutError("Already rendered \u2014 call destroy() before rendering again");
|
|
125
258
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
fetchClientSecret: () => this.fetchClientSecret(),
|
|
129
|
-
onComplete: () => this.handleComplete(),
|
|
130
|
-
onAnalyticsEvent: (event) => console.log("[stripe analytics]", event.eventType, event)
|
|
131
|
-
});
|
|
132
|
-
} catch (err) {
|
|
133
|
-
this.callbacks.onError?.({ provider: "stripe", error: err });
|
|
134
|
-
if (err instanceof CheckoutError) throw err;
|
|
135
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
136
|
-
throw new CheckoutError(`Stripe checkout failed: ${detail}`);
|
|
137
|
-
}
|
|
138
|
-
this.embeddedCheckout.mount(container);
|
|
259
|
+
this.mounted = true;
|
|
260
|
+
await this.ui.mount(this.stripe, container, this.host());
|
|
139
261
|
}
|
|
140
262
|
async reset() {
|
|
141
263
|
this.destroy();
|
|
142
264
|
}
|
|
143
265
|
destroy() {
|
|
144
|
-
this.
|
|
145
|
-
this.
|
|
266
|
+
this.ui.destroy();
|
|
267
|
+
this.mounted = false;
|
|
268
|
+
this.snapshot = {};
|
|
146
269
|
}
|
|
147
|
-
|
|
270
|
+
host() {
|
|
271
|
+
return {
|
|
272
|
+
clientSecret: () => this.createSession(),
|
|
273
|
+
ready: (durationMs) => this.callbacks.onReady?.({ provider: "stripe", durationMs }),
|
|
274
|
+
changed: (patch) => this.merge(patch),
|
|
275
|
+
confirmed: ({ paymentMethodType, express }) => this.callbacks.onConfirm?.({
|
|
276
|
+
provider: "stripe",
|
|
277
|
+
paymentMethodType: paymentMethodType ?? this.snapshot.paymentMethodType,
|
|
278
|
+
express
|
|
279
|
+
}),
|
|
280
|
+
cancelled: () => this.callbacks.onCancel?.({
|
|
281
|
+
provider: "stripe",
|
|
282
|
+
paymentMethodType: this.snapshot.paymentMethodType
|
|
283
|
+
}),
|
|
284
|
+
renderFailed: (error, detail) => this.emitError("render", error, detail),
|
|
285
|
+
paymentFailed: (error, detail) => this.emitError("payment", error, detail),
|
|
286
|
+
succeeded: (outcome) => void this.emitComplete(outcome)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
async createSession() {
|
|
148
290
|
const secret = await this.service.createCheckoutSession({
|
|
149
291
|
...this.config,
|
|
150
292
|
returnUrl: this.config.returnUrl ?? window.location.href
|
|
@@ -153,33 +295,74 @@ var StripeProvider = class {
|
|
|
153
295
|
return secret;
|
|
154
296
|
}
|
|
155
297
|
// Format: cs_test_{sessionId}_secret_{random}
|
|
156
|
-
|
|
157
|
-
if (!clientSecret)
|
|
158
|
-
|
|
159
|
-
return idx !== -1 ? clientSecret.slice(0, idx) : null;
|
|
160
|
-
}
|
|
161
|
-
async handleComplete() {
|
|
162
|
-
const sessionId = this.parseSessionId(this.clientSecret);
|
|
163
|
-
if (!sessionId) {
|
|
164
|
-
this.callbacks.onComplete?.({ provider: "stripe" });
|
|
165
|
-
return;
|
|
298
|
+
sessionId() {
|
|
299
|
+
if (!this.clientSecret) {
|
|
300
|
+
return null;
|
|
166
301
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
302
|
+
const idx = this.clientSecret.indexOf("_secret_");
|
|
303
|
+
return idx !== -1 ? this.clientSecret.slice(0, idx) : null;
|
|
304
|
+
}
|
|
305
|
+
merge(patch) {
|
|
306
|
+
const next = { ...this.snapshot };
|
|
307
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
308
|
+
if (value !== void 0) {
|
|
309
|
+
Object.assign(next, { [key]: value });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
this.snapshot = next;
|
|
313
|
+
this.callbacks.onChange?.({ provider: "stripe", ...next });
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Reads the session back for the ids only the backend can resolve, falling
|
|
317
|
+
* back to what the client already knows so a paid customer is never
|
|
318
|
+
* reported as a failure.
|
|
319
|
+
*/
|
|
320
|
+
async emitComplete(outcome) {
|
|
321
|
+
const sessionId = this.sessionId();
|
|
322
|
+
const fallback = {
|
|
323
|
+
amount_total: outcome?.amountTotal ?? null,
|
|
324
|
+
currency: outcome?.currency ?? null,
|
|
325
|
+
email: outcome?.email ?? null
|
|
326
|
+
};
|
|
327
|
+
let session = {};
|
|
328
|
+
if (sessionId) {
|
|
329
|
+
try {
|
|
330
|
+
session = definedOnly(await this.service.getSession(sessionId, this.config.accountId));
|
|
331
|
+
} catch {
|
|
332
|
+
session = {};
|
|
333
|
+
}
|
|
180
334
|
}
|
|
335
|
+
this.callbacks.onComplete?.({
|
|
336
|
+
provider: "stripe",
|
|
337
|
+
paymentMethodType: this.snapshot.paymentMethodType,
|
|
338
|
+
...toCompleteFields({ ...fallback, ...session })
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
emitError(phase, error, detail) {
|
|
342
|
+
this.callbacks.onError?.({
|
|
343
|
+
provider: "stripe",
|
|
344
|
+
phase,
|
|
345
|
+
paymentMethodType: this.snapshot.paymentMethodType,
|
|
346
|
+
error,
|
|
347
|
+
...detail
|
|
348
|
+
});
|
|
181
349
|
}
|
|
182
350
|
};
|
|
351
|
+
function definedOnly(session) {
|
|
352
|
+
return Object.fromEntries(
|
|
353
|
+
Object.entries(session).filter(([, value]) => value !== null && value !== void 0)
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
function toCompleteFields(session) {
|
|
357
|
+
return {
|
|
358
|
+
customerId: session.customer_id ?? void 0,
|
|
359
|
+
subscriptionId: session.subscription_id ?? void 0,
|
|
360
|
+
invoiceId: session.invoice_id ?? void 0,
|
|
361
|
+
amountPaid: session.amount_total ?? void 0,
|
|
362
|
+
currency: session.currency ?? void 0,
|
|
363
|
+
email: session.email ?? void 0
|
|
364
|
+
};
|
|
365
|
+
}
|
|
183
366
|
|
|
184
367
|
// src/providers/fastspring/index.ts
|
|
185
368
|
var FastSpringProvider = class {
|