@n1xv/stripe-elements 0.0.0-stage → 0.1.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/README.md +105 -2
- package/dist/appearance.d.ts +31 -0
- package/dist/appearance.d.ts.map +1 -0
- package/dist/appearance.js +17 -0
- package/dist/appearance.js.map +1 -0
- package/dist/elements.d.ts +151 -0
- package/dist/elements.d.ts.map +1 -0
- package/dist/elements.js +380 -0
- package/dist/elements.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/outcome.d.ts +39 -0
- package/dist/outcome.d.ts.map +1 -0
- package/dist/outcome.js +50 -0
- package/dist/outcome.js.map +1 -0
- package/dist/stripe-js.d.ts +22 -0
- package/dist/stripe-js.d.ts.map +1 -0
- package/dist/stripe-js.js +24 -0
- package/dist/stripe-js.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -3
package/README.md
CHANGED
|
@@ -1,3 +1,106 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @n1xv/stripe-elements
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Stripe Elements on **your** checkout screen, instead of a redirect to someone
|
|
4
|
+
else's.
|
|
5
|
+
|
|
6
|
+
Hosted Checkout is one line and works. What it cannot do is sit inside your own
|
|
7
|
+
page: no wallet row above your paywall button, no consent sentence recorded
|
|
8
|
+
against the press, no saved card for a returning buyer, and no control over the
|
|
9
|
+
screen where the money is actually taken.
|
|
10
|
+
|
|
11
|
+
This package is the mechanics of doing it yourself. It is **not** a checkout —
|
|
12
|
+
there is no modal, no copy, no price and no consent text here. Those belong to
|
|
13
|
+
the product.
|
|
14
|
+
|
|
15
|
+
## What it does
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { mountElements } from '@n1xv/stripe-elements';
|
|
19
|
+
|
|
20
|
+
const checkout = await mountElements(
|
|
21
|
+
// The charge does not exist yet. It is created when Pay is pressed.
|
|
22
|
+
{ deferred: { amount: 1200, currency: 'USD', recurring: true } },
|
|
23
|
+
{
|
|
24
|
+
publishableKey: () => fetch('/api/billing/config').then((r) => r.json()).then((c) => c.publishableKey),
|
|
25
|
+
slots: { payment: '#card', express: '#wallets' },
|
|
26
|
+
onChange: (complete) => setCanPay(complete),
|
|
27
|
+
billing: { country }, // collected before this, so Stripe stops asking
|
|
28
|
+
wallet: {
|
|
29
|
+
ready: () => Boolean(total), // a wallet sheet fixes its amount when it opens
|
|
30
|
+
onNotReady: () => toast('One moment — still pricing.'),
|
|
31
|
+
create: () => createChargeOnServer(),
|
|
32
|
+
},
|
|
33
|
+
onWalletResult: (r) => r.outcome === 'completed' && done(),
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (!checkout) return; // payments are switched off; render the screen anyway
|
|
38
|
+
|
|
39
|
+
// On your Pay button:
|
|
40
|
+
const problem = await checkout.submit(); // validates before anything is created
|
|
41
|
+
if (problem) return show(problem);
|
|
42
|
+
const secret = await createChargeOnServer(); // now, not before
|
|
43
|
+
const result = await checkout.confirm(secret);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`null` from `mountElements` is an ordinary answer: a fresh clone has no keys and
|
|
47
|
+
must still render.
|
|
48
|
+
|
|
49
|
+
## Why deferred
|
|
50
|
+
|
|
51
|
+
The charge is created when Pay is pressed, not to make a form appear. Creating
|
|
52
|
+
it first means every buyer who merely *looked* at the card form has left an
|
|
53
|
+
incomplete subscription behind — and the consent has to be ticked before a form
|
|
54
|
+
that does not exist yet.
|
|
55
|
+
|
|
56
|
+
## What is decided here, and what is not
|
|
57
|
+
|
|
58
|
+
Nothing in this package grants anything or decides a price. Both are settled
|
|
59
|
+
server-side before a secret exists, and entitlements follow the webhook a moment
|
|
60
|
+
after the payment clears — so poll your own billing state rather than trusting
|
|
61
|
+
what the page saw.
|
|
62
|
+
|
|
63
|
+
## The three outcomes
|
|
64
|
+
|
|
65
|
+
`completed`, `closed`, `unavailable` — never a boolean. A caller that collapses
|
|
66
|
+
them tells somebody whose card was declined that payments are down.
|
|
67
|
+
|
|
68
|
+
`retry: true` means *this charge is spent*: Stripe refuses further confirmations
|
|
69
|
+
against an intent declined too many times, and every attempt after that fails
|
|
70
|
+
for a reason that has nothing to do with the card being typed. Build a new
|
|
71
|
+
charge.
|
|
72
|
+
|
|
73
|
+
Card errors are passed through in Stripe's own words — "insufficient funds" is
|
|
74
|
+
actionable, "that didn't go through" is not. Everything else is ours and is
|
|
75
|
+
listed in `DEFAULT_MESSAGES`; override it to translate.
|
|
76
|
+
|
|
77
|
+
## Theme
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
appearance: { scope: '.app', darkClass: 'dark', primaryVariable: '--primary' }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Stripe's iframe cannot inherit CSS, so the palette is handed over. Name the
|
|
84
|
+
element your theme actually lives on: reading `<html>` for a class that is set
|
|
85
|
+
somewhere else is true-always or false-always, and the symptom is a black card
|
|
86
|
+
form inside a white page.
|
|
87
|
+
|
|
88
|
+
## Keeping the server in step
|
|
89
|
+
|
|
90
|
+
A deferred form is told which methods to offer, because it has no intent to
|
|
91
|
+
read them from. Keep `paymentMethodTypes` equal to the server's
|
|
92
|
+
`payment_method_types`, or the form offers a method the intent will refuse — a
|
|
93
|
+
decline with no cause the buyer can act on.
|
|
94
|
+
|
|
95
|
+
> Stripe renamed the underlying option to `allowedPaymentMethodTypes`. The old
|
|
96
|
+
> `paymentMethodTypes` is **rejected outright** by current Stripe.js — "no
|
|
97
|
+
> longer supported in this version" — thrown at mount, so the form simply never
|
|
98
|
+
> appears. This package sends the current name; the option on `MountOptions`
|
|
99
|
+
> keeps the familiar one.
|
|
100
|
+
|
|
101
|
+
## Origin
|
|
102
|
+
|
|
103
|
+
Lifted from a production checkout in `nrr-tv`, with the product removed: the
|
|
104
|
+
plan ladder, the credit packs, the legal copy and the modal that composed them
|
|
105
|
+
stayed behind. The comments explaining *why* came with the code, because each
|
|
106
|
+
one is a bug somebody already paid for.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Appearance } from '@stripe/stripe-js';
|
|
2
|
+
/**
|
|
3
|
+
* Make Stripe's iframe look like the rest of the app.
|
|
4
|
+
*
|
|
5
|
+
* Read off the live theme rather than hard-coded: an app with a light and a
|
|
6
|
+
* dark mode cannot let the element inherit CSS across an iframe boundary, so a
|
|
7
|
+
* fixed palette here is a white form on a black card for half the users.
|
|
8
|
+
*
|
|
9
|
+
* Which element carries the theme is the caller's to say, and getting it wrong
|
|
10
|
+
* is invisible in every test that does not look at the answer. The version this
|
|
11
|
+
* came from asked `<html>` for an attribute nothing in that app ever set, so
|
|
12
|
+
* the condition was true always and every form rendered in Stripe's night
|
|
13
|
+
* theme — including on a light page. Hence `scope`: name the element the theme
|
|
14
|
+
* actually lives on.
|
|
15
|
+
*/
|
|
16
|
+
export type ThemeSource = {
|
|
17
|
+
/**
|
|
18
|
+
* The element the theme and the brand variables live on, as a selector.
|
|
19
|
+
* Defaults to `:root`, which is right when nothing scopes them.
|
|
20
|
+
*/
|
|
21
|
+
scope?: string;
|
|
22
|
+
/** The class that means dark. Defaults to `dark`. */
|
|
23
|
+
darkClass?: string;
|
|
24
|
+
/** The CSS custom property holding the accent colour. */
|
|
25
|
+
primaryVariable?: string;
|
|
26
|
+
/** Used when the variable is absent — local dev, or a page without the theme. */
|
|
27
|
+
primaryFallback?: string;
|
|
28
|
+
borderRadius?: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function appearanceFromTheme(source?: ThemeSource): Appearance;
|
|
31
|
+
//# sourceMappingURL=appearance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance.d.ts","sourceRoot":"","sources":["../src/appearance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,WAAgB,GAAG,UAAU,CAuBxE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function appearanceFromTheme(source = {}) {
|
|
2
|
+
const { scope = ':root', darkClass = 'dark', primaryVariable = '--primary', primaryFallback = '#7c3aed', borderRadius = '12px', } = source;
|
|
3
|
+
// `:root` always matches, but a named scope may not have rendered yet — and
|
|
4
|
+
// falling through to the document element is better than throwing inside a
|
|
5
|
+
// checkout.
|
|
6
|
+
const element = document.querySelector(scope) ?? document.documentElement;
|
|
7
|
+
const css = getComputedStyle(element);
|
|
8
|
+
const dark = element.classList.contains(darkClass);
|
|
9
|
+
return {
|
|
10
|
+
theme: dark ? 'night' : 'stripe',
|
|
11
|
+
variables: {
|
|
12
|
+
colorPrimary: css.getPropertyValue(primaryVariable).trim() || primaryFallback,
|
|
13
|
+
borderRadius,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=appearance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appearance.js","sourceRoot":"","sources":["../src/appearance.ts"],"names":[],"mappings":"AA+BA,MAAM,UAAU,mBAAmB,CAAC,SAAsB,EAAE;IAC1D,MAAM,EACJ,KAAK,GAAG,OAAO,EACf,SAAS,GAAG,MAAM,EAClB,eAAe,GAAG,WAAW,EAC7B,eAAe,GAAG,SAAS,EAC3B,YAAY,GAAG,MAAM,GACtB,GAAG,MAAM,CAAC;IAEX,4EAA4E;IAC5E,2EAA2E;IAC3E,YAAY;IACZ,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,eAAe,CAAC;IAC1E,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAEnD,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;QAChC,SAAS,EAAE;YACT,YAAY,EAAE,GAAG,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,IAAI,EAAE,IAAI,eAAe;YAC7E,YAAY;SACb;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Appearance } from '@stripe/stripe-js';
|
|
2
|
+
import { type ThemeSource } from './appearance.js';
|
|
3
|
+
import { type OutcomeMessages } from './outcome.js';
|
|
4
|
+
import { type PublishableKeySource } from './stripe-js.js';
|
|
5
|
+
import type { BillingAddress, ConfirmResult, MountIntent, MountedCheckout, WalletHooks } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Stripe Elements, mounted into your own checkout screen.
|
|
8
|
+
*
|
|
9
|
+
* Vanilla `@stripe/stripe-js` rather than the React bindings: the payments
|
|
10
|
+
* layer stays a plain async API the UI calls, which keeps this package usable
|
|
11
|
+
* from any framework and avoids a second React tree inside a modal.
|
|
12
|
+
*
|
|
13
|
+
* Three elements, and each earns its place:
|
|
14
|
+
*
|
|
15
|
+
* - **Express Checkout** is Apple Pay / Google Pay / Link. It only renders the
|
|
16
|
+
* wallets the visitor can actually use, so on a desktop without any it draws
|
|
17
|
+
* nothing — the caller has to treat an empty express row as normal rather
|
|
18
|
+
* than as a failure to load.
|
|
19
|
+
* - **Payment** is the card form.
|
|
20
|
+
* - **Address** is collected by the caller BEFORE this, not here: the total
|
|
21
|
+
* depends on it and a finalised invoice cannot be re-taxed.
|
|
22
|
+
*
|
|
23
|
+
* Nothing here grants anything, and nothing here decides a price. Both are
|
|
24
|
+
* settled server-side before a secret exists.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* The height of a wallet button, in px.
|
|
28
|
+
*
|
|
29
|
+
* Stripe draws its buttons inside an iframe, so CSS on the host side cannot
|
|
30
|
+
* touch them — the only lever is this option, and its range is 40–55 (default
|
|
31
|
+
* 44). 55 is the top of that range and the closest it can come to an ordinary
|
|
32
|
+
* button, which is why a host's own buttons should be pinned to the same
|
|
33
|
+
* number rather than left at whatever their padding produced.
|
|
34
|
+
*/
|
|
35
|
+
export declare const EXPRESS_BUTTON_HEIGHT = 55;
|
|
36
|
+
/**
|
|
37
|
+
* The payment methods a DEFERRED form offers.
|
|
38
|
+
*
|
|
39
|
+
* The same list the intent will be created with, named here because a deferred
|
|
40
|
+
* form has no intent to read it from. Left unset, the form offers whatever the
|
|
41
|
+
* dashboard enables and can then fail at confirmation against an intent that
|
|
42
|
+
* accepts something narrower — a decline with no cause the buyer can act on.
|
|
43
|
+
*
|
|
44
|
+
* Passed to Stripe as `allowedPaymentMethodTypes`. It used to be
|
|
45
|
+
* `paymentMethodTypes`, and that name is not merely deprecated: current
|
|
46
|
+
* Stripe.js REFUSES the call outright — "`paymentMethodTypes` is no longer
|
|
47
|
+
* supported in this version of Stripe.js" — so the form never appears at all.
|
|
48
|
+
* The failure arrives as a thrown error at mount, which a caller that catches
|
|
49
|
+
* broadly will report as a generic problem.
|
|
50
|
+
*/
|
|
51
|
+
export declare const DEFAULT_PAYMENT_METHOD_TYPES: readonly ["card", "link"];
|
|
52
|
+
export type MountOptions = {
|
|
53
|
+
/** Where each element goes, as selectors. */
|
|
54
|
+
slots: {
|
|
55
|
+
payment?: string;
|
|
56
|
+
express?: string;
|
|
57
|
+
};
|
|
58
|
+
/** Needed before anything can be drawn. */
|
|
59
|
+
publishableKey: PublishableKeySource;
|
|
60
|
+
/** Reports completeness so the caller can enable its own Pay button. */
|
|
61
|
+
onChange?: (complete: boolean) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Lets the form show cards this buyer has already saved.
|
|
64
|
+
*
|
|
65
|
+
* A client secret describes one PAYMENT, not one person, so without this the
|
|
66
|
+
* Payment Element has no way to know whose cards to offer and shows a blank
|
|
67
|
+
* form to everybody — including a subscriber whose card is charged monthly.
|
|
68
|
+
* Absent when Stripe could not mint one, which costs the convenience and
|
|
69
|
+
* nothing else.
|
|
70
|
+
*/
|
|
71
|
+
customerSessionSecret?: string;
|
|
72
|
+
/**
|
|
73
|
+
* How a WALLET payment ended.
|
|
74
|
+
*
|
|
75
|
+
* Apple Pay and Google Pay confirm from inside the element's own sheet, not
|
|
76
|
+
* from the caller's Pay button, so their outcome arrives here rather than as
|
|
77
|
+
* the return value of `confirm()`. Without it a successful wallet payment
|
|
78
|
+
* leaves the checkout sitting open on a charge that has already cleared.
|
|
79
|
+
*/
|
|
80
|
+
onWalletResult?: (result: ConfirmResult) => void;
|
|
81
|
+
wallet?: WalletHooks;
|
|
82
|
+
/**
|
|
83
|
+
* The buyer's email, so Link can recognise them.
|
|
84
|
+
*
|
|
85
|
+
* Link keeps a wallet against an EMAIL, including one created on somebody
|
|
86
|
+
* else's site. Told it up front, Link offers the saved cards behind it —
|
|
87
|
+
* verifying with a code — instead of an empty form.
|
|
88
|
+
*/
|
|
89
|
+
email?: string;
|
|
90
|
+
/**
|
|
91
|
+
* The billing address the caller already collected, when it did.
|
|
92
|
+
*
|
|
93
|
+
* Present it and Stripe stops asking: the Payment Element collects a billing
|
|
94
|
+
* address by default, which puts a SECOND country dropdown under the card on
|
|
95
|
+
* a screen that already asked. Two selectors is not only an extra step — they
|
|
96
|
+
* can disagree, and the tax on the invoice was computed from the caller's.
|
|
97
|
+
*/
|
|
98
|
+
billing?: BillingAddress;
|
|
99
|
+
/** Defaults to reading the live theme; pass an object to fix it. */
|
|
100
|
+
appearance?: Appearance | ThemeSource;
|
|
101
|
+
/** Defaults to `['card', 'link']`. Must match the server's intent. */
|
|
102
|
+
paymentMethodTypes?: readonly string[];
|
|
103
|
+
/** Override to translate. See `OutcomeMessages`. */
|
|
104
|
+
messages?: OutcomeMessages;
|
|
105
|
+
/**
|
|
106
|
+
* Where a redirecting method brings the buyer back. Defaults to the current
|
|
107
|
+
* origin and path.
|
|
108
|
+
*
|
|
109
|
+
* The query is dropped deliberately: a buyer coming back from a redirect
|
|
110
|
+
* carries Stripe's own result parameters in it, and reusing that as the next
|
|
111
|
+
* return address sends them back to a stale secret.
|
|
112
|
+
*/
|
|
113
|
+
returnUrl?: () => string;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Mount the payment form — for a server-created secret, or ahead of one.
|
|
117
|
+
*
|
|
118
|
+
* Returns null when Stripe.js could not load or payments are switched off,
|
|
119
|
+
* which is an ordinary answer rather than a throw: a fresh clone with no keys
|
|
120
|
+
* must still render its screen.
|
|
121
|
+
*/
|
|
122
|
+
export declare function mountElements(intent: MountIntent, options: MountOptions): Promise<MountedCheckout | null>;
|
|
123
|
+
/**
|
|
124
|
+
* Mount a form that stores a card without charging it.
|
|
125
|
+
*
|
|
126
|
+
* No wallet row: Apple Pay and Google Pay can be saved, but the reason to be on
|
|
127
|
+
* this screen is to put a card on file for renewals, and a wallet tile there
|
|
128
|
+
* reads as a way to pay for something.
|
|
129
|
+
*/
|
|
130
|
+
export declare function mountCardSetup(clientSecret: string, options: Omit<MountOptions, 'slots' | 'wallet' | 'onWalletResult'> & {
|
|
131
|
+
slot: string;
|
|
132
|
+
}): Promise<MountedCheckout | null>;
|
|
133
|
+
/**
|
|
134
|
+
* Answer a challenge on a payment that already exists.
|
|
135
|
+
*
|
|
136
|
+
* Nothing is collected and nothing is mounted: the card is the one on file, the
|
|
137
|
+
* charge was raised server-side, and the only thing missing is the cardholder
|
|
138
|
+
* tapping their bank's prompt.
|
|
139
|
+
*
|
|
140
|
+
* `retry` keeps its meaning — this payment is spent. What a fresh one LOOKS
|
|
141
|
+
* like differs: a checkout screen rebuilds its own charge, while here the
|
|
142
|
+
* charge belongs to an update the provider is holding, so the only way forward
|
|
143
|
+
* is a working card on file and a fresh amendment. Stripping the flag here
|
|
144
|
+
* leaves the caller with `unavailable` and no way to tell "the card on file was
|
|
145
|
+
* refused for good" from "Stripe.js did not load".
|
|
146
|
+
*/
|
|
147
|
+
export declare function authenticate(clientSecret: string, options: {
|
|
148
|
+
publishableKey: PublishableKeySource;
|
|
149
|
+
messages?: OutcomeMessages;
|
|
150
|
+
}): Promise<ConfirmResult>;
|
|
151
|
+
//# sourceMappingURL=elements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAKX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAA0C,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAgB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAEb,WAAW,EACX,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,2BAA4B,CAAC;AActE,MAAM,MAAM,YAAY,GAAG;IACzB,6CAA6C;IAC7C,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,2CAA2C;IAC3C,cAAc,EAAE,oBAAoB,CAAC;IACrC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;;;;;;;OAQG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,oEAAoE;IACpE,UAAU,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;IACtC,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,oDAAoD;IACpD,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;CAC1B,CAAC;AAOF;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA6OjC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,QAAQ,GAAG,gBAAgB,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GACpF,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;IAAE,cAAc,EAAE,oBAAoB,CAAC;IAAC,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAE,GAC5E,OAAO,CAAC,aAAa,CAAC,CAMxB"}
|
package/dist/elements.js
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { appearanceFromTheme } from './appearance.js';
|
|
2
|
+
import { classifyConfirmError, DEFAULT_MESSAGES } from './outcome.js';
|
|
3
|
+
import { loadStripeJs } from './stripe-js.js';
|
|
4
|
+
/**
|
|
5
|
+
* Stripe Elements, mounted into your own checkout screen.
|
|
6
|
+
*
|
|
7
|
+
* Vanilla `@stripe/stripe-js` rather than the React bindings: the payments
|
|
8
|
+
* layer stays a plain async API the UI calls, which keeps this package usable
|
|
9
|
+
* from any framework and avoids a second React tree inside a modal.
|
|
10
|
+
*
|
|
11
|
+
* Three elements, and each earns its place:
|
|
12
|
+
*
|
|
13
|
+
* - **Express Checkout** is Apple Pay / Google Pay / Link. It only renders the
|
|
14
|
+
* wallets the visitor can actually use, so on a desktop without any it draws
|
|
15
|
+
* nothing — the caller has to treat an empty express row as normal rather
|
|
16
|
+
* than as a failure to load.
|
|
17
|
+
* - **Payment** is the card form.
|
|
18
|
+
* - **Address** is collected by the caller BEFORE this, not here: the total
|
|
19
|
+
* depends on it and a finalised invoice cannot be re-taxed.
|
|
20
|
+
*
|
|
21
|
+
* Nothing here grants anything, and nothing here decides a price. Both are
|
|
22
|
+
* settled server-side before a secret exists.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* The height of a wallet button, in px.
|
|
26
|
+
*
|
|
27
|
+
* Stripe draws its buttons inside an iframe, so CSS on the host side cannot
|
|
28
|
+
* touch them — the only lever is this option, and its range is 40–55 (default
|
|
29
|
+
* 44). 55 is the top of that range and the closest it can come to an ordinary
|
|
30
|
+
* button, which is why a host's own buttons should be pinned to the same
|
|
31
|
+
* number rather than left at whatever their padding produced.
|
|
32
|
+
*/
|
|
33
|
+
export const EXPRESS_BUTTON_HEIGHT = 55;
|
|
34
|
+
/**
|
|
35
|
+
* The payment methods a DEFERRED form offers.
|
|
36
|
+
*
|
|
37
|
+
* The same list the intent will be created with, named here because a deferred
|
|
38
|
+
* form has no intent to read it from. Left unset, the form offers whatever the
|
|
39
|
+
* dashboard enables and can then fail at confirmation against an intent that
|
|
40
|
+
* accepts something narrower — a decline with no cause the buyer can act on.
|
|
41
|
+
*
|
|
42
|
+
* Passed to Stripe as `allowedPaymentMethodTypes`. It used to be
|
|
43
|
+
* `paymentMethodTypes`, and that name is not merely deprecated: current
|
|
44
|
+
* Stripe.js REFUSES the call outright — "`paymentMethodTypes` is no longer
|
|
45
|
+
* supported in this version of Stripe.js" — so the form never appears at all.
|
|
46
|
+
* The failure arrives as a thrown error at mount, which a caller that catches
|
|
47
|
+
* broadly will report as a generic problem.
|
|
48
|
+
*/
|
|
49
|
+
export const DEFAULT_PAYMENT_METHOD_TYPES = ['card', 'link'];
|
|
50
|
+
const isThemeSource = (a) => a !== undefined && !('theme' in a) && !('variables' in a) && !('rules' in a);
|
|
51
|
+
const defaultReturnUrl = () => `${window.location.origin}${window.location.pathname}`;
|
|
52
|
+
/**
|
|
53
|
+
* Mount the payment form — for a server-created secret, or ahead of one.
|
|
54
|
+
*
|
|
55
|
+
* Returns null when Stripe.js could not load or payments are switched off,
|
|
56
|
+
* which is an ordinary answer rather than a throw: a fresh clone with no keys
|
|
57
|
+
* must still render its screen.
|
|
58
|
+
*/
|
|
59
|
+
export async function mountElements(intent, options) {
|
|
60
|
+
const { slots, publishableKey, onChange, customerSessionSecret, onWalletResult, wallet, email, billing, paymentMethodTypes = DEFAULT_PAYMENT_METHOD_TYPES, messages = DEFAULT_MESSAGES, returnUrl = defaultReturnUrl, } = options;
|
|
61
|
+
const stripe = await loadStripeJs(publishableKey).catch(() => null);
|
|
62
|
+
if (!stripe)
|
|
63
|
+
return null;
|
|
64
|
+
const appearance = isThemeSource(options.appearance)
|
|
65
|
+
? appearanceFromTheme(options.appearance)
|
|
66
|
+
: (options.appearance ?? appearanceFromTheme());
|
|
67
|
+
const deferred = 'deferred' in intent ? intent.deferred : null;
|
|
68
|
+
const kind = 'deferred' in intent ? 'payment' : (intent.kind ?? 'payment');
|
|
69
|
+
let complete = false;
|
|
70
|
+
// Everything that does not depend on which kind of form this is. Stripe types
|
|
71
|
+
// the two shapes as separate overloads, so the CALL has to branch even though
|
|
72
|
+
// most of the options do not.
|
|
73
|
+
const shared = {
|
|
74
|
+
appearance,
|
|
75
|
+
...(customerSessionSecret ? { customerSessionClientSecret: customerSessionSecret } : {}),
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* The two modes are spelled out rather than computed, because Stripe types
|
|
79
|
+
* them as separate members of a union: a `mode` narrowed to
|
|
80
|
+
* `'subscription' | 'payment'` matches neither, and the call stops
|
|
81
|
+
* typechecking for a reason that has nothing to do with it being wrong.
|
|
82
|
+
*
|
|
83
|
+
* Something that renews unattended needs a card usable off-session; a
|
|
84
|
+
* one-off is over when it is paid, and keeping the card is the buyer's own
|
|
85
|
+
* tick in the element.
|
|
86
|
+
*/
|
|
87
|
+
const deferredOptions = deferred
|
|
88
|
+
? deferred.recurring
|
|
89
|
+
? {
|
|
90
|
+
mode: 'subscription',
|
|
91
|
+
amount: deferred.amount,
|
|
92
|
+
currency: deferred.currency.toLowerCase(),
|
|
93
|
+
setupFutureUsage: 'off_session',
|
|
94
|
+
allowedPaymentMethodTypes: [...paymentMethodTypes],
|
|
95
|
+
...shared,
|
|
96
|
+
}
|
|
97
|
+
: {
|
|
98
|
+
mode: 'payment',
|
|
99
|
+
amount: deferred.amount,
|
|
100
|
+
currency: deferred.currency.toLowerCase(),
|
|
101
|
+
allowedPaymentMethodTypes: [...paymentMethodTypes],
|
|
102
|
+
...shared,
|
|
103
|
+
}
|
|
104
|
+
: null;
|
|
105
|
+
const elements = deferredOptions
|
|
106
|
+
? stripe.elements(deferredOptions)
|
|
107
|
+
: stripe.elements({ clientSecret: intent.secret, ...shared });
|
|
108
|
+
// A country we do not have cannot be sent, and suppressing the field without
|
|
109
|
+
// sending one is a dead end: Stripe refuses the confirmation and the buyer
|
|
110
|
+
// has nowhere to type the answer. Falling back to Stripe's own field costs a
|
|
111
|
+
// duplicate dropdown in a case that should not happen — the cheaper failure.
|
|
112
|
+
const address = billing?.country ? billing : undefined;
|
|
113
|
+
const payment = slots.payment
|
|
114
|
+
? elements.create('payment', {
|
|
115
|
+
layout: 'tabs',
|
|
116
|
+
...(email ? { defaultValues: { billingDetails: { email } } } : {}),
|
|
117
|
+
// Suppress EXACTLY what was already asked for, field by field.
|
|
118
|
+
// `address: "never"` hides all of it and then Stripe demands a complete
|
|
119
|
+
// address back at confirmation; naming the fields keeps the contract to
|
|
120
|
+
// the ones the caller can satisfy.
|
|
121
|
+
...(address
|
|
122
|
+
? {
|
|
123
|
+
fields: {
|
|
124
|
+
billingDetails: {
|
|
125
|
+
address: {
|
|
126
|
+
country: 'never',
|
|
127
|
+
postalCode: address.postalCode ? 'never' : 'auto',
|
|
128
|
+
line1: 'auto',
|
|
129
|
+
line2: 'auto',
|
|
130
|
+
city: 'auto',
|
|
131
|
+
state: 'auto',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
: {}),
|
|
137
|
+
})
|
|
138
|
+
: null;
|
|
139
|
+
if (payment && slots.payment) {
|
|
140
|
+
payment.on('change', (e) => {
|
|
141
|
+
complete = e.complete;
|
|
142
|
+
onChange?.(complete);
|
|
143
|
+
});
|
|
144
|
+
payment.mount(slots.payment);
|
|
145
|
+
}
|
|
146
|
+
const submit = async () => {
|
|
147
|
+
const { error } = await elements.submit();
|
|
148
|
+
// Stripe's own words: "Your card number is incomplete" tells the buyer
|
|
149
|
+
// where to look, and a sentence of ours would not.
|
|
150
|
+
return error ? (error.message ?? messages.declined) : null;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* The wallet row, and the handler without which it is decoration.
|
|
154
|
+
*
|
|
155
|
+
* A wallet button does NOT pay by itself: pressing it opens the sheet and
|
|
156
|
+
* then waits for a `confirm` handler to take it from there. Mounted without
|
|
157
|
+
* one, Apple Pay and Google Pay open, collect a card, and go nowhere — the
|
|
158
|
+
* worst version of a payment method that does not work, because the buyer has
|
|
159
|
+
* every reason to believe they have just paid.
|
|
160
|
+
*/
|
|
161
|
+
let express = null;
|
|
162
|
+
if (slots.express && document.querySelector(slots.express)) {
|
|
163
|
+
try {
|
|
164
|
+
const el = elements.create('expressCheckout', {
|
|
165
|
+
/**
|
|
166
|
+
* Wallets first, Link last.
|
|
167
|
+
*
|
|
168
|
+
* Stripe's default is a dynamic order it optimises per visitor, which
|
|
169
|
+
* puts Link — a Stripe account, i.e. one more thing to sign into —
|
|
170
|
+
* ahead of the wallet already unlocked on the device.
|
|
171
|
+
*/
|
|
172
|
+
paymentMethodOrder: ['applePay', 'googlePay', 'link'],
|
|
173
|
+
buttonHeight: EXPRESS_BUTTON_HEIGHT,
|
|
174
|
+
layout: {
|
|
175
|
+
/**
|
|
176
|
+
* One per row. Left to Stripe, two wallets share a row and come out
|
|
177
|
+
* half the width of the card button beneath them — three buttons
|
|
178
|
+
* doing the same job in two different sizes, which on a phone reads
|
|
179
|
+
* as two of them being secondary.
|
|
180
|
+
*/
|
|
181
|
+
maxColumns: 1,
|
|
182
|
+
/**
|
|
183
|
+
* Never fold the rest behind a "more" button: the overflow menu hides
|
|
184
|
+
* the cheapest conversion there is — a wallet the visitor has already
|
|
185
|
+
* authenticated — behind a second tap.
|
|
186
|
+
*/
|
|
187
|
+
overflow: 'never',
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
el.on('ready', (event) => {
|
|
191
|
+
const available = event
|
|
192
|
+
.availablePaymentMethods;
|
|
193
|
+
wallet?.onReady?.(Object.keys(available ?? {}).filter((k) => available?.[k]));
|
|
194
|
+
});
|
|
195
|
+
if (wallet) {
|
|
196
|
+
// Refusing to resolve is how Stripe is told to keep the sheet shut —
|
|
197
|
+
// far better than a sheet that opens, takes a fingerprint and then
|
|
198
|
+
// fails on a total that moved under it.
|
|
199
|
+
el.on('click', (event) => {
|
|
200
|
+
if (!wallet.ready())
|
|
201
|
+
return wallet.onNotReady();
|
|
202
|
+
event.resolve();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
el.on('confirm', () => {
|
|
206
|
+
void (async () => {
|
|
207
|
+
const failed = await submit();
|
|
208
|
+
if (failed)
|
|
209
|
+
return onWalletResult?.({ outcome: 'closed', error: failed });
|
|
210
|
+
/**
|
|
211
|
+
* The charge, created only now — the wallet sheet is the one path
|
|
212
|
+
* that reaches a confirmation without passing the caller's Pay
|
|
213
|
+
* button, so it has to raise the charge itself. A null means the
|
|
214
|
+
* caller already knows why, so there is nothing to report twice.
|
|
215
|
+
*/
|
|
216
|
+
const secret = deferred ? await wallet?.create() : undefined;
|
|
217
|
+
if (deferred && !secret)
|
|
218
|
+
return;
|
|
219
|
+
// Deliberately WITHOUT the collected address: a wallet supplies its
|
|
220
|
+
// own billing details from the card in it, and `payment_method_data`
|
|
221
|
+
// on that confirmation fights the payment method the sheet produced.
|
|
222
|
+
const result = await confirmPayment(stripe, elements, {
|
|
223
|
+
clientSecret: secret ?? undefined,
|
|
224
|
+
messages,
|
|
225
|
+
returnUrl,
|
|
226
|
+
});
|
|
227
|
+
onWalletResult?.(result);
|
|
228
|
+
})();
|
|
229
|
+
});
|
|
230
|
+
el.mount(slots.express);
|
|
231
|
+
express = el;
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* no wallet available — the card form is still there */
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
complete: () => complete,
|
|
239
|
+
submit,
|
|
240
|
+
/**
|
|
241
|
+
* Re-price without rebuilding.
|
|
242
|
+
*
|
|
243
|
+
* The total moves while the form is open — a buyer who changes their
|
|
244
|
+
* country changes the tax — and a deferred form carries the amount itself,
|
|
245
|
+
* so an element left at the old one confirms an intent whose total no
|
|
246
|
+
* longer matches and Stripe refuses it. Remounting instead would throw away
|
|
247
|
+
* a half-typed card on a country change.
|
|
248
|
+
*/
|
|
249
|
+
update: async (charge) => {
|
|
250
|
+
if (!deferred)
|
|
251
|
+
return;
|
|
252
|
+
await elements.update({
|
|
253
|
+
amount: charge.amount,
|
|
254
|
+
currency: charge.currency.toLowerCase(),
|
|
255
|
+
});
|
|
256
|
+
},
|
|
257
|
+
/**
|
|
258
|
+
* BOTH elements, not just the form.
|
|
259
|
+
*
|
|
260
|
+
* Destroying only the payment element leaves the wallet row mounted against
|
|
261
|
+
* a client secret that no longer exists — a Google Pay button sitting under
|
|
262
|
+
* an error message, on a payment that was already abandoned.
|
|
263
|
+
*/
|
|
264
|
+
destroy: () => {
|
|
265
|
+
elements.getElement('payment')?.destroy();
|
|
266
|
+
express?.destroy();
|
|
267
|
+
},
|
|
268
|
+
confirm: (clientSecret) => kind === 'setup'
|
|
269
|
+
? confirmSetup(stripe, elements, { messages, returnUrl })
|
|
270
|
+
: confirmPayment(stripe, elements, { billing: address, clientSecret, messages, returnUrl }),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Mount a form that stores a card without charging it.
|
|
275
|
+
*
|
|
276
|
+
* No wallet row: Apple Pay and Google Pay can be saved, but the reason to be on
|
|
277
|
+
* this screen is to put a card on file for renewals, and a wallet tile there
|
|
278
|
+
* reads as a way to pay for something.
|
|
279
|
+
*/
|
|
280
|
+
export function mountCardSetup(clientSecret, options) {
|
|
281
|
+
const { slot, ...rest } = options;
|
|
282
|
+
return mountElements({ secret: clientSecret, kind: 'setup' }, { ...rest, slots: { payment: slot } });
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Answer a challenge on a payment that already exists.
|
|
286
|
+
*
|
|
287
|
+
* Nothing is collected and nothing is mounted: the card is the one on file, the
|
|
288
|
+
* charge was raised server-side, and the only thing missing is the cardholder
|
|
289
|
+
* tapping their bank's prompt.
|
|
290
|
+
*
|
|
291
|
+
* `retry` keeps its meaning — this payment is spent. What a fresh one LOOKS
|
|
292
|
+
* like differs: a checkout screen rebuilds its own charge, while here the
|
|
293
|
+
* charge belongs to an update the provider is holding, so the only way forward
|
|
294
|
+
* is a working card on file and a fresh amendment. Stripping the flag here
|
|
295
|
+
* leaves the caller with `unavailable` and no way to tell "the card on file was
|
|
296
|
+
* refused for good" from "Stripe.js did not load".
|
|
297
|
+
*/
|
|
298
|
+
export async function authenticate(clientSecret, options) {
|
|
299
|
+
const messages = options.messages ?? DEFAULT_MESSAGES;
|
|
300
|
+
const stripe = await loadStripeJs(options.publishableKey).catch(() => null);
|
|
301
|
+
if (!stripe)
|
|
302
|
+
return { outcome: 'unavailable', error: messages.unavailable };
|
|
303
|
+
const { error } = await stripe.handleNextAction({ clientSecret });
|
|
304
|
+
return classifyConfirmError(error ?? null, messages);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Store the card, and mark it usable everywhere.
|
|
308
|
+
*
|
|
309
|
+
* `allow_redisplay: 'always'` is not a detail — it is the difference between a
|
|
310
|
+
* card that appears in settings and the next checkout, and one that silently
|
|
311
|
+
* does not. A SetupIntent has no field for it and a card confirmed without one
|
|
312
|
+
* comes back `unspecified`, which every "saved cards" surface filters out. The
|
|
313
|
+
* consent behind it is the act itself: this call only happens because somebody
|
|
314
|
+
* opened "Add a card" and pressed save.
|
|
315
|
+
*/
|
|
316
|
+
async function confirmSetup(stripe, elements, opts) {
|
|
317
|
+
const { error, setupIntent } = await stripe.confirmSetup({
|
|
318
|
+
elements,
|
|
319
|
+
redirect: 'if_required',
|
|
320
|
+
confirmParams: {
|
|
321
|
+
payment_method_data: { allow_redisplay: 'always' },
|
|
322
|
+
// A setup that pins `card` cannot redirect today — but the obligation
|
|
323
|
+
// belongs to the call, not to the current list, and the day Link joins it
|
|
324
|
+
// this is what stops a hosted-page failure.
|
|
325
|
+
return_url: opts.returnUrl(),
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
const result = classifyConfirmError(error ?? null, opts.messages);
|
|
329
|
+
if (result.outcome !== 'completed')
|
|
330
|
+
return result;
|
|
331
|
+
// Which card was stored, so a caller that needs it billed can say so.
|
|
332
|
+
const cardId = typeof setupIntent?.payment_method === 'string'
|
|
333
|
+
? setupIntent.payment_method
|
|
334
|
+
: setupIntent?.payment_method?.id;
|
|
335
|
+
return cardId ? { ...result, cardId } : result;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Take the payment without leaving the page.
|
|
339
|
+
*
|
|
340
|
+
* `redirect: 'if_required'` keeps the buyer here for cards and only navigates
|
|
341
|
+
* for methods that genuinely cannot complete inline. A plain `redirect:
|
|
342
|
+
* 'always'` would send everyone away and bring them back on a return_url — the
|
|
343
|
+
* same hand-off an own-screen checkout exists to avoid.
|
|
344
|
+
*/
|
|
345
|
+
async function confirmPayment(stripe, elements, opts) {
|
|
346
|
+
const { error } = await stripe.confirmPayment({
|
|
347
|
+
elements,
|
|
348
|
+
...(opts.clientSecret ? { clientSecret: opts.clientSecret } : {}),
|
|
349
|
+
redirect: 'if_required',
|
|
350
|
+
confirmParams: {
|
|
351
|
+
/**
|
|
352
|
+
* REQUIRED, even though almost nobody is sent anywhere.
|
|
353
|
+
*
|
|
354
|
+
* `redirect: 'if_required'` decides whether the buyer travels; it does
|
|
355
|
+
* not excuse the caller from saying where they would land. Stripe refuses
|
|
356
|
+
* the whole confirmation for any method that MIGHT redirect when this is
|
|
357
|
+
* absent — which is how Link comes to open a hosted page reading
|
|
358
|
+
* "Something went wrong".
|
|
359
|
+
*/
|
|
360
|
+
return_url: opts.returnUrl(),
|
|
361
|
+
// The address the element was told not to ask for. Only sent when it was
|
|
362
|
+
// suppressed — passing it while the element still collects one would
|
|
363
|
+
// overwrite whatever the buyer typed there.
|
|
364
|
+
...(opts.billing
|
|
365
|
+
? {
|
|
366
|
+
payment_method_data: {
|
|
367
|
+
billing_details: {
|
|
368
|
+
address: {
|
|
369
|
+
country: opts.billing.country,
|
|
370
|
+
...(opts.billing.postalCode ? { postal_code: opts.billing.postalCode } : {}),
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
}
|
|
375
|
+
: {}),
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
return classifyConfirmError(error ?? null, opts.messages);
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,mBAAmB,EAAoB,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAwB,MAAM,cAAc,CAAC;AAC5F,OAAO,EAAE,YAAY,EAA6B,MAAM,gBAAgB,CAAC;AAUzE;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AA2EtE,MAAM,aAAa,GAAG,CAAC,CAAuC,EAAoB,EAAE,CAClF,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;AAE/E,MAAM,gBAAgB,GAAG,GAAW,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAE9F;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAmB,EACnB,OAAqB;IAErB,MAAM,EACJ,KAAK,EACL,cAAc,EACd,QAAQ,EACR,qBAAqB,EACrB,cAAc,EACd,MAAM,EACN,KAAK,EACL,OAAO,EACP,kBAAkB,GAAG,4BAA4B,EACjD,QAAQ,GAAG,gBAAgB,EAC3B,SAAS,GAAG,gBAAgB,GAC7B,GAAG,OAAO,CAAC;IAEZ,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC;QAClD,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC;QACzC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,mBAAmB,EAAE,CAAC,CAAC;IAElD,MAAM,QAAQ,GAAG,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,MAAM,IAAI,GAAG,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;IAE3E,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,8EAA8E;IAC9E,8EAA8E;IAC9E,8BAA8B;IAC9B,MAAM,MAAM,GAAG;QACb,UAAU;QACV,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzF,CAAC;IAEF;;;;;;;;;OASG;IACH,MAAM,eAAe,GAAmC,QAAQ;QAC9D,CAAC,CAAC,QAAQ,CAAC,SAAS;YAClB,CAAC,CAAC;gBACE,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE;gBACzC,gBAAgB,EAAE,aAAa;gBAC/B,yBAAyB,EAAE,CAAC,GAAG,kBAAkB,CAAC;gBAClD,GAAG,MAAM;aACV;YACH,CAAC,CAAC;gBACE,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE;gBACzC,yBAAyB,EAAE,CAAC,GAAG,kBAAkB,CAAC;gBAClD,GAAG,MAAM;aACV;QACL,CAAC,CAAC,IAAI,CAAC;IAET,MAAM,QAAQ,GAAmB,eAAe;QAC9C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;QAClC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAG,MAA6B,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAExF,6EAA6E;IAC7E,2EAA2E;IAC3E,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAEvD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO;QAC3B,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE;YACzB,MAAM,EAAE,MAAM;YACd,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,+DAA+D;YAC/D,wEAAwE;YACxE,wEAAwE;YACxE,mCAAmC;YACnC,GAAG,CAAC,OAAO;gBACT,CAAC,CAAC;oBACE,MAAM,EAAE;wBACN,cAAc,EAAE;4BACd,OAAO,EAAE;gCACP,OAAO,EAAE,OAAgB;gCACzB,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAE,OAAiB,CAAC,CAAC,CAAE,MAAgB;gCACvE,KAAK,EAAE,MAAe;gCACtB,KAAK,EAAE,MAAe;gCACtB,IAAI,EAAE,MAAe;gCACrB,KAAK,EAAE,MAAe;6BACvB;yBACF;qBACF;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC;IAET,IAAI,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;YACzB,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;YACtB,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,IAA4B,EAAE;QAChD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC1C,uEAAuE;QACvE,mDAAmD;QACnD,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC,CAAC;IAEF;;;;;;;;OAQG;IACH,IAAI,OAAO,GAAwC,IAAI,CAAC;IACxD,IAAI,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,iBAAiB,EAAE;gBAC5C;;;;;;mBAMG;gBACH,kBAAkB,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,CAAC;gBACrD,YAAY,EAAE,qBAAqB;gBACnC,MAAM,EAAE;oBACN;;;;;uBAKG;oBACH,UAAU,EAAE,CAAC;oBACb;;;;uBAIG;oBACH,QAAQ,EAAE,OAAO;iBAClB;aACF,CAAC,CAAC;YAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBACvB,MAAM,SAAS,GAAI,KAA+D;qBAC/E,uBAAuB,CAAC;gBAC3B,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAChF,CAAC,CAAC,CAAC;YAEH,IAAI,MAAM,EAAE,CAAC;gBACX,qEAAqE;gBACrE,mEAAmE;gBACnE,wCAAwC;gBACxC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;oBACvB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;wBAAE,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;oBAChD,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,CAAC,CAAC,CAAC;YACL,CAAC;YAED,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;gBACpB,KAAK,CAAC,KAAK,IAAI,EAAE;oBACf,MAAM,MAAM,GAAG,MAAM,MAAM,EAAE,CAAC;oBAC9B,IAAI,MAAM;wBAAE,OAAO,cAAc,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;oBAC1E;;;;;uBAKG;oBACH,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;oBAC7D,IAAI,QAAQ,IAAI,CAAC,MAAM;wBAAE,OAAO;oBAChC,oEAAoE;oBACpE,qEAAqE;oBACrE,qEAAqE;oBACrE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE;wBACpD,YAAY,EAAE,MAAM,IAAI,SAAS;wBACjC,QAAQ;wBACR,SAAS;qBACV,CAAC,CAAC;oBACH,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC;gBAC3B,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,OAAO,GAAG,EAAE,CAAC;QACf,CAAC;QAAC,MAAM,CAAC;YACP,wDAAwD;QAC1D,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ;QACxB,MAAM;QACN;;;;;;;;WAQG;QACH,MAAM,EAAE,KAAK,EAAE,MAAsB,EAAE,EAAE;YACvC,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,MAAM,QAAQ,CAAC,MAAM,CAAC;gBACpB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE;aACxC,CAAC,CAAC;QACL,CAAC;QACD;;;;;;WAMG;QACH,OAAO,EAAE,GAAG,EAAE;YACZ,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;YAC1C,OAAO,EAAE,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,OAAO,EAAE,CAAC,YAAqB,EAAE,EAAE,CACjC,IAAI,KAAK,OAAO;YACd,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;YACzD,CAAC,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;KAChG,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,YAAoB,EACpB,OAAqF;IAErF,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAClC,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;AACvG,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,YAAoB,EACpB,OAA6E;IAE7E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,gBAAgB,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC5E,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC5E,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;IAClE,OAAO,oBAAoB,CAAC,KAAK,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,YAAY,CACzB,MAAc,EACd,QAAwB,EACxB,IAA4D;IAE5D,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC;QACvD,QAAQ;QACR,QAAQ,EAAE,aAAa;QACvB,aAAa,EAAE;YACb,mBAAmB,EAAE,EAAE,eAAe,EAAE,QAAQ,EAAE;YAClD,sEAAsE;YACtE,0EAA0E;YAC1E,4CAA4C;YAC5C,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE;SAC7B;KACF,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,IAAI,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClE,IAAI,MAAM,CAAC,OAAO,KAAK,WAAW;QAAE,OAAO,MAAM,CAAC;IAClD,sEAAsE;IACtE,MAAM,MAAM,GACV,OAAO,WAAW,EAAE,cAAc,KAAK,QAAQ;QAC7C,CAAC,CAAC,WAAW,CAAC,cAAc;QAC5B,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,CAAC;IACtC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AACjD,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,cAAc,CAC3B,MAAc,EACd,QAAwB,EACxB,IAYC;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC;QAC5C,QAAQ;QACR,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,QAAQ,EAAE,aAAa;QACvB,aAAa,EAAE;YACb;;;;;;;;eAQG;YACH,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE;YAC5B,yEAAyE;YACzE,qEAAqE;YACrE,4CAA4C;YAC5C,GAAG,CAAC,IAAI,CAAC,OAAO;gBACd,CAAC,CAAC;oBACE,mBAAmB,EAAE;wBACnB,eAAe,EAAE;4BACf,OAAO,EAAE;gCACP,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;gCAC7B,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;6BAC7E;yBACF;qBACF;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR;KACF,CAAC,CAAC;IACH,OAAO,oBAAoB,CAAC,KAAK,IAAI,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC5D,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Elements on your own checkout screen.
|
|
3
|
+
*
|
|
4
|
+
* What this is NOT: a checkout. There is no modal, no copy, no consent
|
|
5
|
+
* sentence and no price here — those belong to the product, and the version
|
|
6
|
+
* this was taken from proved it by being 818 lines of them. What is shared
|
|
7
|
+
* between products is the mechanics underneath: mounting the three elements,
|
|
8
|
+
* confirming against a charge that may not exist yet, and agreeing on what a
|
|
9
|
+
* failure means.
|
|
10
|
+
*
|
|
11
|
+
* Nothing in this package grants anything. Entitlements follow the webhook, a
|
|
12
|
+
* moment after the payment clears — so a caller polls its own billing state
|
|
13
|
+
* rather than trusting what the page saw.
|
|
14
|
+
*/
|
|
15
|
+
export { mountElements, mountCardSetup, authenticate, EXPRESS_BUTTON_HEIGHT, DEFAULT_PAYMENT_METHOD_TYPES } from './elements.js';
|
|
16
|
+
export type { MountOptions } from './elements.js';
|
|
17
|
+
export { loadStripeJs, resetStripeJs } from './stripe-js.js';
|
|
18
|
+
export type { PublishableKeySource } from './stripe-js.js';
|
|
19
|
+
export { appearanceFromTheme } from './appearance.js';
|
|
20
|
+
export type { ThemeSource } from './appearance.js';
|
|
21
|
+
export { classifyConfirmError, DEFAULT_MESSAGES } from './outcome.js';
|
|
22
|
+
export type { OutcomeMessages } from './outcome.js';
|
|
23
|
+
export type { BillingAddress, CheckoutOutcome, ConfirmResult, DeferredCharge, MountIntent, MountedCheckout, WalletHooks, } from './types.js';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AACjI,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC7D,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACtE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,YAAY,EACV,cAAc,EACd,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,EACX,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stripe Elements on your own checkout screen.
|
|
3
|
+
*
|
|
4
|
+
* What this is NOT: a checkout. There is no modal, no copy, no consent
|
|
5
|
+
* sentence and no price here — those belong to the product, and the version
|
|
6
|
+
* this was taken from proved it by being 818 lines of them. What is shared
|
|
7
|
+
* between products is the mechanics underneath: mounting the three elements,
|
|
8
|
+
* confirming against a charge that may not exist yet, and agreeing on what a
|
|
9
|
+
* failure means.
|
|
10
|
+
*
|
|
11
|
+
* Nothing in this package grants anything. Entitlements follow the webhook, a
|
|
12
|
+
* moment after the payment clears — so a caller polls its own billing state
|
|
13
|
+
* rather than trusting what the page saw.
|
|
14
|
+
*/
|
|
15
|
+
export { mountElements, mountCardSetup, authenticate, EXPRESS_BUTTON_HEIGHT, DEFAULT_PAYMENT_METHOD_TYPES } from './elements.js';
|
|
16
|
+
export { loadStripeJs, resetStripeJs } from './stripe-js.js';
|
|
17
|
+
export { appearanceFromTheme } from './appearance.js';
|
|
18
|
+
export { classifyConfirmError, DEFAULT_MESSAGES } from './outcome.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAGjI,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { StripeError } from '@stripe/stripe-js';
|
|
2
|
+
import type { ConfirmResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a Stripe failure means for the buyer, in one place.
|
|
5
|
+
*
|
|
6
|
+
* Shared by the card confirmation, the wallet sheet and the 3D Secure challenge
|
|
7
|
+
* — three entrances to the same set of outcomes. Everything that is not a card
|
|
8
|
+
* error used to collapse into one sentence with no way out but reloading the
|
|
9
|
+
* page, which is how a checkout comes to reject cards that worked minutes
|
|
10
|
+
* earlier.
|
|
11
|
+
*
|
|
12
|
+
* Exported, and pure, on purpose: the version this was taken from lived inside
|
|
13
|
+
* the module that loads Stripe.js, so its own test restated the rules in prose
|
|
14
|
+
* instead of calling them. A rule stated twice is a rule that drifts.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The sentences shown when the failure is ours to explain.
|
|
18
|
+
*
|
|
19
|
+
* A card error is NOT in here: Stripe's own wording is better than anything
|
|
20
|
+
* written in advance — "insufficient funds" is actionable, "that didn't go
|
|
21
|
+
* through" is not — so it is passed through untouched.
|
|
22
|
+
*
|
|
23
|
+
* Override them to translate. The keys are the failure, not the copy.
|
|
24
|
+
*/
|
|
25
|
+
export type OutcomeMessages = {
|
|
26
|
+
/** A card error with no message of its own. */
|
|
27
|
+
declined: string;
|
|
28
|
+
/** Too many attempts in too short a time. */
|
|
29
|
+
rateLimited: string;
|
|
30
|
+
/** The request never arrived. */
|
|
31
|
+
offline: string;
|
|
32
|
+
/** This charge is spent; a fresh one is the only way forward. */
|
|
33
|
+
expired: string;
|
|
34
|
+
/** Ours to fix — a bad key, an outage. */
|
|
35
|
+
unavailable: string;
|
|
36
|
+
};
|
|
37
|
+
export declare const DEFAULT_MESSAGES: OutcomeMessages;
|
|
38
|
+
export declare function classifyConfirmError(error: StripeError | null, messages?: OutcomeMessages): ConfirmResult;
|
|
39
|
+
//# sourceMappingURL=outcome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;GAYG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,eAM9B,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,QAAQ,GAAE,eAAkC,GAC3C,aAAa,CA6Cf"}
|
package/dist/outcome.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export const DEFAULT_MESSAGES = {
|
|
2
|
+
declined: 'That payment was declined.',
|
|
3
|
+
rateLimited: 'Too many attempts just now. Wait a moment and try again.',
|
|
4
|
+
offline: 'Connection lost. Try again.',
|
|
5
|
+
expired: 'This payment expired. Press pay again to start a new one.',
|
|
6
|
+
unavailable: 'Payments are unavailable right now.',
|
|
7
|
+
};
|
|
8
|
+
export function classifyConfirmError(error, messages = DEFAULT_MESSAGES) {
|
|
9
|
+
if (!error)
|
|
10
|
+
return { outcome: 'completed' };
|
|
11
|
+
// The buyer's problem to fix, and Stripe's own words are better than ours.
|
|
12
|
+
if (error.type === 'card_error' || error.type === 'validation_error') {
|
|
13
|
+
return { outcome: 'closed', error: error.message ?? messages.declined };
|
|
14
|
+
}
|
|
15
|
+
// Retrying immediately makes it worse, and recreating the charge does not
|
|
16
|
+
// help — the limit is on the account, not on this payment.
|
|
17
|
+
if (error.type === 'rate_limit_error') {
|
|
18
|
+
return { outcome: 'closed', error: messages.rateLimited };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The request never arrived. The payment is untouched, so the ONLY right move
|
|
22
|
+
* is to send the same one again — rebuilding it would abandon a perfectly
|
|
23
|
+
* good charge and tell the buyer their payment expired because their wifi
|
|
24
|
+
* blinked.
|
|
25
|
+
*/
|
|
26
|
+
if (error.type === 'api_connection_error') {
|
|
27
|
+
return { outcome: 'closed', error: messages.offline };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The payment itself is no longer usable.
|
|
31
|
+
*
|
|
32
|
+
* Reached after a run of failures: Stripe stops accepting confirmations
|
|
33
|
+
* against an intent that has been declined repeatedly, and every further
|
|
34
|
+
* attempt is refused for a reason that has nothing to do with the card now
|
|
35
|
+
* being typed. Without separating this out it shows as one opaque sentence on
|
|
36
|
+
* every card — including cards that worked minutes earlier — and the only way
|
|
37
|
+
* out is reloading the page, which quietly starts a fresh charge. `retry`
|
|
38
|
+
* says so, and the caller starts that fresh charge itself.
|
|
39
|
+
*/
|
|
40
|
+
if (error.type === 'invalid_request_error') {
|
|
41
|
+
return { outcome: 'unavailable', retry: true, error: messages.expired };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Ours, not theirs. Deliberately NOT a rebuild: a new charge against a broken
|
|
45
|
+
* configuration is dead on arrival, and inviting the buyer to press again
|
|
46
|
+
* turns one failure into a row of them.
|
|
47
|
+
*/
|
|
48
|
+
return { outcome: 'unavailable', error: messages.unavailable };
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=outcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome.js","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAwCA,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,QAAQ,EAAE,4BAA4B;IACtC,WAAW,EAAE,0DAA0D;IACvE,OAAO,EAAE,6BAA6B;IACtC,OAAO,EAAE,2DAA2D;IACpE,WAAW,EAAE,qCAAqC;CACnD,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAClC,KAAyB,EACzB,WAA4B,gBAAgB;IAE5C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAE5C,2EAA2E;IAC3E,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QACrE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC1E,CAAC;IAED,0EAA0E;IAC1E,2DAA2D;IAC3D,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC5D,CAAC;IAED;;;;;OAKG;IACH,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC;IACxD,CAAC;IAED;;;;;;;;;;OAUG;IACH,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;QAC3C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC1E,CAAC;IAED;;;;OAIG;IACH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Stripe } from '@stripe/stripe-js';
|
|
2
|
+
/**
|
|
3
|
+
* Loading Stripe.js, once per page.
|
|
4
|
+
*
|
|
5
|
+
* The key is a function rather than a string because a template fetches it from
|
|
6
|
+
* its own server (`/api/billing/config`) and does not have it at import time.
|
|
7
|
+
* Returning an empty string is the "payments are switched off" answer, and it
|
|
8
|
+
* is an ordinary one: a fresh clone has no keys and must still render.
|
|
9
|
+
*
|
|
10
|
+
* Only a successful load is memoised. A flaky network on the first attempt must
|
|
11
|
+
* not leave the page permanently convinced that payments are off.
|
|
12
|
+
*/
|
|
13
|
+
export type PublishableKeySource = string | (() => Promise<string | null> | string | null);
|
|
14
|
+
export declare function loadStripeJs(key: PublishableKeySource): Promise<Stripe | null>;
|
|
15
|
+
/**
|
|
16
|
+
* Forget the memoised load.
|
|
17
|
+
*
|
|
18
|
+
* For tests, and for an app that can switch accounts without a reload. Nothing
|
|
19
|
+
* in a normal page lifetime needs it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resetStripeJs(): void;
|
|
22
|
+
//# sourceMappingURL=stripe-js.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-js.d.ts","sourceRoot":"","sources":["../src/stripe-js.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC;AAI3F,wBAAgB,YAAY,CAAC,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAU9E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { loadStripe } from '@stripe/stripe-js';
|
|
2
|
+
let cached = null;
|
|
3
|
+
export function loadStripeJs(key) {
|
|
4
|
+
cached ??= (async () => {
|
|
5
|
+
const value = typeof key === 'function' ? await key() : key;
|
|
6
|
+
if (!value)
|
|
7
|
+
return null;
|
|
8
|
+
return loadStripe(value);
|
|
9
|
+
})().catch((err) => {
|
|
10
|
+
cached = null;
|
|
11
|
+
throw err;
|
|
12
|
+
});
|
|
13
|
+
return cached;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Forget the memoised load.
|
|
17
|
+
*
|
|
18
|
+
* For tests, and for an app that can switch accounts without a reload. Nothing
|
|
19
|
+
* in a normal page lifetime needs it.
|
|
20
|
+
*/
|
|
21
|
+
export function resetStripeJs() {
|
|
22
|
+
cached = null;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=stripe-js.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stripe-js.js","sourceRoot":"","sources":["../src/stripe-js.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAe5D,IAAI,MAAM,GAAkC,IAAI,CAAC;AAEjD,MAAM,UAAU,YAAY,CAAC,GAAyB;IACpD,MAAM,KAAK,CAAC,KAAK,IAAI,EAAE;QACrB,MAAM,KAAK,GAAG,OAAO,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5D,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC1B,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,GAAG,CAAC;IACZ,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the checkout can come to, and what the caller is handed back.
|
|
3
|
+
*
|
|
4
|
+
* Three outcomes rather than a boolean, because "the buyer closed it" and "we
|
|
5
|
+
* are broken" need different screens. A caller that collapses them tells
|
|
6
|
+
* somebody whose card was declined that payments are down.
|
|
7
|
+
*/
|
|
8
|
+
export type CheckoutOutcome = 'completed' | 'closed' | 'unavailable';
|
|
9
|
+
/** What a confirmation attempt came to. `retry` means: build a new charge. */
|
|
10
|
+
export type ConfirmResult = {
|
|
11
|
+
outcome: CheckoutOutcome;
|
|
12
|
+
/** Ready to show. Stripe's own wording where it is the buyer's to fix. */
|
|
13
|
+
error?: string;
|
|
14
|
+
/** The intent is spent — the caller must create another before trying again. */
|
|
15
|
+
retry?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The card a SETUP just stored.
|
|
18
|
+
*
|
|
19
|
+
* Carried because attaching a card does not make it billable: Stripe charges
|
|
20
|
+
* the subscription's default payment method, then the customer's, and a card
|
|
21
|
+
* that is neither is simply on file. A caller that added a card BECAUSE the
|
|
22
|
+
* one on file was refused has to be able to say which one to use — otherwise
|
|
23
|
+
* the retry goes back to the card that just failed.
|
|
24
|
+
*/
|
|
25
|
+
cardId?: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A charge that does not exist yet, described well enough to draw its form.
|
|
29
|
+
*
|
|
30
|
+
* Stripe calls this deferred intent creation, and it is what lets the checkout
|
|
31
|
+
* be ONE screen: the card form, the wallets and the total are on screen from
|
|
32
|
+
* the start, and the charge is created at the moment Pay is pressed rather than
|
|
33
|
+
* to make a form appear. Creating it first means every buyer who got as far as
|
|
34
|
+
* looking at a card form has already left an incomplete subscription behind.
|
|
35
|
+
*
|
|
36
|
+
* `recurring` picks the mode: something that renews is a `subscription` whose
|
|
37
|
+
* card must be usable again unattended; a one-off is a `payment` where keeping
|
|
38
|
+
* the card is the buyer's own choice in the element's checkbox.
|
|
39
|
+
*/
|
|
40
|
+
export type DeferredCharge = {
|
|
41
|
+
/** Minor units and currency, exactly as the server quoted them. */
|
|
42
|
+
amount: number;
|
|
43
|
+
currency: string;
|
|
44
|
+
recurring: boolean;
|
|
45
|
+
};
|
|
46
|
+
/** What the form is for: a secret to confirm, or a charge not yet created. */
|
|
47
|
+
export type MountIntent = {
|
|
48
|
+
secret: string;
|
|
49
|
+
kind?: 'payment' | 'setup';
|
|
50
|
+
} | {
|
|
51
|
+
deferred: DeferredCharge;
|
|
52
|
+
};
|
|
53
|
+
export type MountedCheckout = {
|
|
54
|
+
/**
|
|
55
|
+
* Confirm the payment. Resolves once Stripe has taken it, or says why not.
|
|
56
|
+
*
|
|
57
|
+
* The secret is an argument rather than something the form was built with,
|
|
58
|
+
* because a deferred form is mounted BEFORE the charge exists. Omitted for a
|
|
59
|
+
* form that already has one.
|
|
60
|
+
*/
|
|
61
|
+
confirm: (clientSecret?: string) => Promise<ConfirmResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Validate and collect, before anything is created. `null` means good to go;
|
|
64
|
+
* a string is Stripe's own complaint about the form, ready to show.
|
|
65
|
+
*
|
|
66
|
+
* Required by Stripe on a deferred form and harmless on any other: it is what
|
|
67
|
+
* turns "the buyer typed something" into payment details Stripe will accept,
|
|
68
|
+
* and it is where an incomplete card is caught — a press that reaches the
|
|
69
|
+
* server would otherwise leave a charge behind for a card never filled in.
|
|
70
|
+
*/
|
|
71
|
+
submit: () => Promise<string | null>;
|
|
72
|
+
/** Re-price a deferred form when the total changes. */
|
|
73
|
+
update: (charge: DeferredCharge) => Promise<void>;
|
|
74
|
+
/** Whether the form is filled in far enough to pay. */
|
|
75
|
+
complete: () => boolean;
|
|
76
|
+
destroy: () => void;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* A wallet's own path to a charge, and the one thing that still holds it back.
|
|
80
|
+
*
|
|
81
|
+
* Apple Pay, Google Pay and Link confirm from inside their sheet, so they never
|
|
82
|
+
* touch the caller's Pay button — and on a deferred form they need the same
|
|
83
|
+
* steps it takes: submit, create the charge, confirm. `create` is that middle
|
|
84
|
+
* one.
|
|
85
|
+
*
|
|
86
|
+
* `ready` answers a narrow question: is there a settled price to charge? A
|
|
87
|
+
* buyer who changes country and taps Apple Pay while the re-quote is still in
|
|
88
|
+
* flight would have the charge raised at the new total against a form still
|
|
89
|
+
* carrying the old one, and Stripe refuses a confirmation whose amounts
|
|
90
|
+
* disagree.
|
|
91
|
+
*/
|
|
92
|
+
export type WalletHooks = {
|
|
93
|
+
ready: () => boolean;
|
|
94
|
+
onNotReady: () => void;
|
|
95
|
+
create: () => Promise<string | null>;
|
|
96
|
+
/**
|
|
97
|
+
* Which wallets this visitor has, once Stripe has decided — empty when none.
|
|
98
|
+
*
|
|
99
|
+
* An empty wallet row and a wallet row still loading look identical from
|
|
100
|
+
* outside the iframe, and guessing between them is how a paywall ends up
|
|
101
|
+
* either flashing a gap or holding a spinner for ever.
|
|
102
|
+
*/
|
|
103
|
+
onReady?: (available: string[]) => void;
|
|
104
|
+
};
|
|
105
|
+
/** The address the caller already collected, so Stripe stops asking for it. */
|
|
106
|
+
export type BillingAddress = {
|
|
107
|
+
country: string;
|
|
108
|
+
postalCode?: string;
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,aAAa,CAAC;AAErE,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,eAAe,CAAC;IACzB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,cAAc,CAAA;CAAE,CAAC;AAExG,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;;OAMG;IACH,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3D;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACrC,uDAAuD;IACvD,MAAM,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,uDAAuD;IACvD,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACrC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@n1xv/stripe-elements",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Stripe Elements on your own checkout screen: deferred charges, wallet row, saved cards, 3D Secure, and one vocabulary for what a failure means",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@stripe/stripe-js": ">=9"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/n1xv/saas-kit.git",
|
|
22
|
+
"directory": "packages/stripe-elements"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"stripe",
|
|
26
|
+
"stripe-elements",
|
|
27
|
+
"checkout",
|
|
28
|
+
"paywall",
|
|
29
|
+
"apple-pay",
|
|
30
|
+
"google-pay"
|
|
31
|
+
],
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@stripe/stripe-js": "^10.1.0",
|
|
34
|
+
"jsdom": "^30.1.3"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -p tsconfig.build.json",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"lint": "echo 'lint runs from the repo root'",
|
|
40
|
+
"test": "vitest run --passWithNoTests"
|
|
41
|
+
}
|
|
6
42
|
}
|