@usethrottle/checkout-react 1.0.0 → 1.0.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 +15 -13
- package/dist/index.cjs +60 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -5
- package/dist/index.d.ts +62 -5
- package/dist/index.js +56 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ throttle embed-config set --origins https://shop.example.com
|
|
|
28
28
|
Or via API:
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
|
-
fetch('https://
|
|
31
|
+
fetch('https://api.usethrottle.dev/api/v1/embed-config', {
|
|
32
32
|
method: 'PUT',
|
|
33
33
|
headers: { 'x-api-key': 'sk_...', 'content-type': 'application/json' },
|
|
34
34
|
body: JSON.stringify({ allowed_origins: ['https://shop.example.com'] }),
|
|
@@ -75,7 +75,9 @@ export function CheckoutPage({ sessionId }: { sessionId: string }) {
|
|
|
75
75
|
parentOrigin="https://shop.example.com"
|
|
76
76
|
primary="#ff6b00"
|
|
77
77
|
logo="https://shop.example.com/logo.png"
|
|
78
|
-
onSucceeded={({ orderId, paymentId }) => {
|
|
78
|
+
onSucceeded={({ orderId, paymentId }) => {
|
|
79
|
+
/* ... */
|
|
80
|
+
}}
|
|
79
81
|
onStepChanged={({ step }) => {
|
|
80
82
|
// step: 'cart' | 'address' | 'shipping' | 'payment'
|
|
81
83
|
}}
|
|
@@ -92,7 +94,7 @@ import { useRef } from 'react';
|
|
|
92
94
|
|
|
93
95
|
export function MyEmbed({ sessionId }: { sessionId: string }) {
|
|
94
96
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
95
|
-
const baseUrl = 'https://
|
|
97
|
+
const baseUrl = 'https://checkout.usethrottle.dev';
|
|
96
98
|
|
|
97
99
|
useThrottleEvents({
|
|
98
100
|
iframeRef,
|
|
@@ -114,15 +116,15 @@ parent page over `postMessage`. They're complementary to Throttle's
|
|
|
114
116
|
outbound webhooks (which fire from Throttle's servers to your backend
|
|
115
117
|
over signed HTTP).
|
|
116
118
|
|
|
117
|
-
| Event
|
|
118
|
-
|
|
119
|
-
| `throttle.ready`
|
|
120
|
-
| `throttle.processing`
|
|
121
|
-
| `throttle.completed`
|
|
122
|
-
| `throttle.error`
|
|
123
|
-
| `throttle.cancelled`
|
|
124
|
-
| `throttle.step.changed` | (CheckoutEmbed) step transition | `onStepChanged({step})`
|
|
125
|
-
| `throttle.resize`
|
|
119
|
+
| Event | When | Callback |
|
|
120
|
+
| ----------------------- | ------------------------------- | ----------------------------------- |
|
|
121
|
+
| `throttle.ready` | iframe mounted | `onReady()` |
|
|
122
|
+
| `throttle.processing` | user clicked Pay; awaiting auth | `onProcessing()` |
|
|
123
|
+
| `throttle.completed` | payment captured | `onSucceeded({orderId, paymentId})` |
|
|
124
|
+
| `throttle.error` | card declined / network failure | `onFailed({code, message})` |
|
|
125
|
+
| `throttle.cancelled` | user dismissed | `onCanceled()` |
|
|
126
|
+
| `throttle.step.changed` | (CheckoutEmbed) step transition | `onStepChanged({step})` |
|
|
127
|
+
| `throttle.resize` | iframe content resized | (auto: updates iframe height) |
|
|
126
128
|
|
|
127
129
|
Every message is wrapped in
|
|
128
130
|
`{ source: 'throttle', version: 1, ...event }` so your page can
|
|
@@ -139,4 +141,4 @@ is now `onFailed({code, message})`. Update call sites accordingly.
|
|
|
139
141
|
## See also
|
|
140
142
|
|
|
141
143
|
- [CLI: `throttle embed-config`](https://www.npmjs.com/package/@usethrottle/cli)
|
|
142
|
-
- [
|
|
144
|
+
- [Checkout SDK: `@usethrottle/checkout-sdk`](https://www.npmjs.com/package/@usethrottle/checkout-sdk)
|
package/dist/index.cjs
CHANGED
|
@@ -28,7 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
module.exports = __toCommonJS(index_exports);
|
|
29
29
|
|
|
30
30
|
// src/CheckoutEmbed.tsx
|
|
31
|
-
var
|
|
31
|
+
var import_react3 = require("react");
|
|
32
32
|
|
|
33
33
|
// src/useThrottleEvents.ts
|
|
34
34
|
var import_react = require("react");
|
|
@@ -48,6 +48,32 @@ function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }) {
|
|
|
48
48
|
}, [iframeRef, expectedOrigin, onMessage]);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// src/useParentCommands.ts
|
|
52
|
+
var import_react2 = require("react");
|
|
53
|
+
function useParentCommands({
|
|
54
|
+
iframeRef,
|
|
55
|
+
targetOrigin,
|
|
56
|
+
submitDisabled,
|
|
57
|
+
iframeReady
|
|
58
|
+
}) {
|
|
59
|
+
const [lastSent, setLastSent] = (0, import_react2.useState)(void 0);
|
|
60
|
+
(0, import_react2.useEffect)(() => {
|
|
61
|
+
if (submitDisabled === void 0) return;
|
|
62
|
+
const win = iframeRef.current?.contentWindow;
|
|
63
|
+
if (!win) return;
|
|
64
|
+
if (lastSent === submitDisabled && iframeReady) return;
|
|
65
|
+
if (!iframeReady) return;
|
|
66
|
+
const message = {
|
|
67
|
+
source: "throttle-parent",
|
|
68
|
+
version: 1,
|
|
69
|
+
type: "set-submit-disabled",
|
|
70
|
+
disabled: submitDisabled
|
|
71
|
+
};
|
|
72
|
+
win.postMessage(message, targetOrigin);
|
|
73
|
+
setLastSent(submitDisabled);
|
|
74
|
+
}, [iframeRef, targetOrigin, submitDisabled, iframeReady, lastSent]);
|
|
75
|
+
}
|
|
76
|
+
|
|
51
77
|
// src/CheckoutEmbed.tsx
|
|
52
78
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
53
79
|
var DEFAULT_BASE_URL = "https://checkout.usethrottle.dev";
|
|
@@ -60,6 +86,7 @@ function CheckoutEmbed({
|
|
|
60
86
|
initialHeight = 600,
|
|
61
87
|
className,
|
|
62
88
|
style,
|
|
89
|
+
submitDisabled,
|
|
63
90
|
onReady,
|
|
64
91
|
onProcessing,
|
|
65
92
|
onSucceeded,
|
|
@@ -67,19 +94,25 @@ function CheckoutEmbed({
|
|
|
67
94
|
onCanceled,
|
|
68
95
|
onStepChanged
|
|
69
96
|
}) {
|
|
70
|
-
const iframeRef = (0,
|
|
97
|
+
const iframeRef = (0, import_react3.useRef)(null);
|
|
71
98
|
const expectedOrigin = new URL(baseUrl).origin;
|
|
72
|
-
const
|
|
99
|
+
const [iframeReady, setIframeReady] = (0, import_react3.useState)(false);
|
|
100
|
+
const dispatch = (0, import_react3.useCallback)(
|
|
73
101
|
(msg) => {
|
|
74
102
|
switch (msg.type) {
|
|
75
103
|
case "throttle.ready":
|
|
104
|
+
setIframeReady(true);
|
|
76
105
|
onReady?.();
|
|
77
106
|
break;
|
|
78
107
|
case "throttle.processing":
|
|
79
108
|
onProcessing?.();
|
|
80
109
|
break;
|
|
81
110
|
case "throttle.completed":
|
|
82
|
-
onSucceeded?.({
|
|
111
|
+
onSucceeded?.({
|
|
112
|
+
orderId: msg.orderId,
|
|
113
|
+
paymentId: msg.paymentId,
|
|
114
|
+
...msg.subscriptionId !== void 0 ? { subscriptionId: msg.subscriptionId } : {}
|
|
115
|
+
});
|
|
83
116
|
break;
|
|
84
117
|
case "throttle.error":
|
|
85
118
|
onFailed?.({ code: msg.code, message: msg.message });
|
|
@@ -98,6 +131,12 @@ function CheckoutEmbed({
|
|
|
98
131
|
[onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged]
|
|
99
132
|
);
|
|
100
133
|
useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });
|
|
134
|
+
useParentCommands({
|
|
135
|
+
iframeRef,
|
|
136
|
+
targetOrigin: expectedOrigin,
|
|
137
|
+
submitDisabled,
|
|
138
|
+
iframeReady
|
|
139
|
+
});
|
|
101
140
|
const params = new URLSearchParams({ embed: "1", mode: "checkout-full", parentOrigin });
|
|
102
141
|
if (primary) params.set("primary", primary);
|
|
103
142
|
if (logo) params.set("logo", logo);
|
|
@@ -117,7 +156,7 @@ function CheckoutEmbed({
|
|
|
117
156
|
}
|
|
118
157
|
|
|
119
158
|
// src/PaymentEmbed.tsx
|
|
120
|
-
var
|
|
159
|
+
var import_react4 = require("react");
|
|
121
160
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
122
161
|
var DEFAULT_BASE_URL2 = "https://checkout.usethrottle.dev";
|
|
123
162
|
function PaymentEmbed({
|
|
@@ -129,25 +168,32 @@ function PaymentEmbed({
|
|
|
129
168
|
initialHeight = 480,
|
|
130
169
|
className,
|
|
131
170
|
style,
|
|
171
|
+
submitDisabled,
|
|
132
172
|
onReady,
|
|
133
173
|
onProcessing,
|
|
134
174
|
onSucceeded,
|
|
135
175
|
onFailed,
|
|
136
176
|
onCanceled
|
|
137
177
|
}) {
|
|
138
|
-
const iframeRef = (0,
|
|
178
|
+
const iframeRef = (0, import_react4.useRef)(null);
|
|
139
179
|
const expectedOrigin = new URL(baseUrl).origin;
|
|
140
|
-
const
|
|
180
|
+
const [iframeReady, setIframeReady] = (0, import_react4.useState)(false);
|
|
181
|
+
const dispatch = (0, import_react4.useCallback)(
|
|
141
182
|
(msg) => {
|
|
142
183
|
switch (msg.type) {
|
|
143
184
|
case "throttle.ready":
|
|
185
|
+
setIframeReady(true);
|
|
144
186
|
onReady?.();
|
|
145
187
|
break;
|
|
146
188
|
case "throttle.processing":
|
|
147
189
|
onProcessing?.();
|
|
148
190
|
break;
|
|
149
191
|
case "throttle.completed":
|
|
150
|
-
onSucceeded?.({
|
|
192
|
+
onSucceeded?.({
|
|
193
|
+
orderId: msg.orderId,
|
|
194
|
+
paymentId: msg.paymentId,
|
|
195
|
+
...msg.subscriptionId !== void 0 ? { subscriptionId: msg.subscriptionId } : {}
|
|
196
|
+
});
|
|
151
197
|
break;
|
|
152
198
|
case "throttle.error":
|
|
153
199
|
onFailed?.({ code: msg.code, message: msg.message });
|
|
@@ -163,6 +209,12 @@ function PaymentEmbed({
|
|
|
163
209
|
[onReady, onProcessing, onSucceeded, onFailed, onCanceled]
|
|
164
210
|
);
|
|
165
211
|
useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });
|
|
212
|
+
useParentCommands({
|
|
213
|
+
iframeRef,
|
|
214
|
+
targetOrigin: expectedOrigin,
|
|
215
|
+
submitDisabled,
|
|
216
|
+
iframeReady
|
|
217
|
+
});
|
|
166
218
|
const params = new URLSearchParams({ embed: "1", mode: "payment-only", parentOrigin });
|
|
167
219
|
if (primary) params.set("primary", primary);
|
|
168
220
|
if (logo) params.set("logo", logo);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx","../src/CheckoutEmbed.tsx","../src/useThrottleEvents.ts","../src/PaymentEmbed.tsx"],"sourcesContent":["export { CheckoutEmbed } from './CheckoutEmbed.js';\nexport { PaymentEmbed } from './PaymentEmbed.js';\nexport { useThrottleEvents } from './useThrottleEvents.js';\nexport type {\n ThrottleEvent,\n ThrottleMessage,\n ThrottleEnvelope,\n ThrottleEmbedProps,\n CheckoutEmbedExtraProps,\n} from './types.js';\n\n// v0.1.x compat alias. v0.1's <ThrottleCheckout> shape (positional\n// onCompleted/onError args, optional baseUrl, no parentOrigin) is\n// gone in v0.2 — the alias resolves to <CheckoutEmbed> which now\n// requires `parentOrigin`. Update call sites accordingly.\nexport { CheckoutEmbed as ThrottleCheckout } from './CheckoutEmbed.js';\n","import { useCallback, useRef } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport type {\n ThrottleEmbedProps,\n CheckoutEmbedExtraProps,\n ThrottleMessage,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Full-checkout iframe embed. Renders the entire Throttle hosted\n * checkout (address / shipping / payment) inside an iframe and\n * surfaces lifecycle + terminal events through callbacks. The\n * iframe auto-resizes on `throttle.resize` events.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list\n * (`throttle embed-config set --origins ...`). Mismatches render\n * an in-iframe \"Embed not authorized\" panel.\n */\nexport function CheckoutEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 600,\n className,\n style,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n onStepChanged,\n}: ThrottleEmbedProps & CheckoutEmbedExtraProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({ orderId: msg.orderId, paymentId: msg.paymentId });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.step.changed':\n onStepChanged?.({ step: msg.step });\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n\n const params = new URLSearchParams({ embed: '1', mode: 'checkout-full', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle checkout\"\n />\n );\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { ThrottleMessage } from './types.js';\n\nexport interface UseThrottleEventsOptions {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n /**\n * The Throttle origin (e.g. https://checkout.usethrottle.dev).\n * Strict-equals check against `MessageEvent.origin`. Anything else\n * is silently dropped.\n */\n expectedOrigin: string;\n onMessage: (msg: ThrottleMessage) => void;\n}\n\n/**\n * Subscribe to validated postMessage events from a Throttle iframe.\n *\n * Validation:\n * - event.origin === expectedOrigin (strict string match)\n * - event.source === iframeRef.current.contentWindow (defends against\n * other iframes on the same origin spoofing events)\n * - event.data.source === 'throttle' && event.data.version === 1\n * - event.data.type starts with 'throttle.'\n *\n * Anything failing validation is silently dropped — the parent page\n * may receive postMessages from analytics SDKs, browser extensions,\n * other iframes, etc. We must never throw on those.\n */\nexport function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }: UseThrottleEventsOptions) {\n useEffect(() => {\n function handle(ev: MessageEvent) {\n if (ev.origin !== expectedOrigin) return;\n if (iframeRef.current && ev.source !== iframeRef.current.contentWindow) return;\n const data = ev.data as Partial<ThrottleMessage> | null | undefined;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'throttle' || data.version !== 1) return;\n if (typeof data.type !== 'string' || !data.type.startsWith('throttle.')) return;\n onMessage(data as ThrottleMessage);\n }\n window.addEventListener('message', handle);\n return () => window.removeEventListener('message', handle);\n }, [iframeRef, expectedOrigin, onMessage]);\n}\n","import { useCallback, useRef } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport type { ThrottleEmbedProps, ThrottleMessage } from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Payment-only iframe embed. Renders just the Gr4vy provider iframe\n * (no address / shipping / cart UI). Email is collected by the Gr4vy\n * iframe in proxy-mode sessions. Used when the merchant has built\n * their own checkout UI and only needs Throttle to handle payment\n * authorization + capture.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list.\n * The iframe auto-resizes on `throttle.resize` events.\n */\nexport function PaymentEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 480,\n className,\n style,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n}: ThrottleEmbedProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({ orderId: msg.orderId, paymentId: msg.paymentId });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n\n const params = new URLSearchParams({ embed: '1', mode: 'payment-only', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle payment\"\n />\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","DEFAULT_BASE_URL"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/CheckoutEmbed.tsx","../src/useThrottleEvents.ts","../src/useParentCommands.ts","../src/PaymentEmbed.tsx"],"sourcesContent":["export { CheckoutEmbed } from './CheckoutEmbed.js';\nexport { PaymentEmbed } from './PaymentEmbed.js';\nexport { useThrottleEvents } from './useThrottleEvents.js';\nexport type {\n ThrottleEvent,\n ThrottleMessage,\n ThrottleEnvelope,\n ThrottleEmbedProps,\n CheckoutEmbedExtraProps,\n RecurringIntent,\n ThrottleParentCommand,\n ThrottleParentEnvelope,\n ThrottleParentMessage,\n} from './types.js';\n\n// v0.1.x compat alias. v0.1's <ThrottleCheckout> shape (positional\n// onCompleted/onError args, optional baseUrl, no parentOrigin) is\n// gone in v0.2 — the alias resolves to <CheckoutEmbed> which now\n// requires `parentOrigin`. Update call sites accordingly.\nexport { CheckoutEmbed as ThrottleCheckout } from './CheckoutEmbed.js';\n","import { useCallback, useRef, useState } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport { useParentCommands } from './useParentCommands.js';\nimport type {\n ThrottleEmbedProps,\n CheckoutEmbedExtraProps,\n ThrottleMessage,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Full-checkout iframe embed. Renders the entire Throttle hosted\n * checkout (address / shipping / payment) inside an iframe and\n * surfaces lifecycle + terminal events through callbacks. The\n * iframe auto-resizes on `throttle.resize` events.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list\n * (`throttle embed-config set --origins ...`). Mismatches render\n * an in-iframe \"Embed not authorized\" panel.\n */\nexport function CheckoutEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 600,\n className,\n style,\n submitDisabled,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n onStepChanged,\n}: ThrottleEmbedProps & CheckoutEmbedExtraProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n const [iframeReady, setIframeReady] = useState(false);\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n setIframeReady(true);\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({\n orderId: msg.orderId,\n paymentId: msg.paymentId,\n ...(msg.subscriptionId !== undefined ? { subscriptionId: msg.subscriptionId } : {}),\n });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.step.changed':\n onStepChanged?.({ step: msg.step });\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n useParentCommands({\n iframeRef,\n targetOrigin: expectedOrigin,\n submitDisabled,\n iframeReady,\n });\n\n const params = new URLSearchParams({ embed: '1', mode: 'checkout-full', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle checkout\"\n />\n );\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { ThrottleMessage } from './types.js';\n\nexport interface UseThrottleEventsOptions {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n /**\n * The Throttle origin (e.g. https://checkout.usethrottle.dev).\n * Strict-equals check against `MessageEvent.origin`. Anything else\n * is silently dropped.\n */\n expectedOrigin: string;\n onMessage: (msg: ThrottleMessage) => void;\n}\n\n/**\n * Subscribe to validated postMessage events from a Throttle iframe.\n *\n * Validation:\n * - event.origin === expectedOrigin (strict string match)\n * - event.source === iframeRef.current.contentWindow (defends against\n * other iframes on the same origin spoofing events)\n * - event.data.source === 'throttle' && event.data.version === 1\n * - event.data.type starts with 'throttle.'\n *\n * Anything failing validation is silently dropped — the parent page\n * may receive postMessages from analytics SDKs, browser extensions,\n * other iframes, etc. We must never throw on those.\n */\nexport function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }: UseThrottleEventsOptions) {\n useEffect(() => {\n function handle(ev: MessageEvent) {\n if (ev.origin !== expectedOrigin) return;\n if (iframeRef.current && ev.source !== iframeRef.current.contentWindow) return;\n const data = ev.data as Partial<ThrottleMessage> | null | undefined;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'throttle' || data.version !== 1) return;\n if (typeof data.type !== 'string' || !data.type.startsWith('throttle.')) return;\n onMessage(data as ThrottleMessage);\n }\n window.addEventListener('message', handle);\n return () => window.removeEventListener('message', handle);\n }, [iframeRef, expectedOrigin, onMessage]);\n}\n","import { useEffect, useState, type RefObject } from 'react';\nimport type { ThrottleParentMessage } from './types.js';\n\ninterface UseParentCommandsOptions {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n /** The Throttle origin to address messages to. */\n targetOrigin: string;\n /**\n * The current value of `submitDisabled` from the embed props. Posts a\n * `set-submit-disabled` parent command whenever it changes — and once\n * after the iframe reports `throttle.ready` so the iframe sees the\n * intent even if it boots after the prop is already set.\n *\n * `undefined` means the parent never explicitly enabled/disabled — we\n * never post in that case. Backward-compat with embeds that don't\n * pass the prop.\n */\n submitDisabled?: boolean;\n /**\n * Set to `true` once the iframe posts `throttle.ready`. Until then,\n * commands are buffered (we still try to post but the iframe may not\n * have its listener attached yet — and we re-post on ready as a\n * belt-and-braces guard).\n */\n iframeReady: boolean;\n}\n\n/**\n * Post parent → iframe commands when controlled props change. v1.2 adds\n * `set-submit-disabled`; future commands extend the same channel.\n *\n * postMessage is fire-and-forget — we don't wait for an ack from the\n * iframe. The iframe's listener is idempotent (setting the same value\n * twice is a no-op).\n */\nexport function useParentCommands({\n iframeRef,\n targetOrigin,\n submitDisabled,\n iframeReady,\n}: UseParentCommandsOptions) {\n const [lastSent, setLastSent] = useState<boolean | undefined>(undefined);\n\n // Post when the prop value changes OR when the iframe transitions to\n // ready (so the first state lands).\n useEffect(() => {\n if (submitDisabled === undefined) return;\n const win = iframeRef.current?.contentWindow;\n if (!win) return;\n // Skip if we already sent this value AND the iframe was already ready\n // — avoids spam on unrelated re-renders.\n if (lastSent === submitDisabled && iframeReady) return;\n if (!iframeReady) return; // Defer until ready\n\n const message: ThrottleParentMessage = {\n source: 'throttle-parent',\n version: 1,\n type: 'set-submit-disabled',\n disabled: submitDisabled,\n };\n win.postMessage(message, targetOrigin);\n setLastSent(submitDisabled);\n }, [iframeRef, targetOrigin, submitDisabled, iframeReady, lastSent]);\n}\n","import { useCallback, useRef, useState } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport { useParentCommands } from './useParentCommands.js';\nimport type { ThrottleEmbedProps, ThrottleMessage } from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Payment-only iframe embed. Renders just the Gr4vy provider iframe\n * (no address / shipping / cart UI). Email is collected by the Gr4vy\n * iframe in proxy-mode sessions. Used when the merchant has built\n * their own checkout UI and only needs Throttle to handle payment\n * authorization + capture.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list.\n * The iframe auto-resizes on `throttle.resize` events.\n */\nexport function PaymentEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 480,\n className,\n style,\n submitDisabled,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n}: ThrottleEmbedProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n const [iframeReady, setIframeReady] = useState(false);\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n setIframeReady(true);\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({\n orderId: msg.orderId,\n paymentId: msg.paymentId,\n ...(msg.subscriptionId !== undefined ? { subscriptionId: msg.subscriptionId } : {}),\n });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n useParentCommands({\n iframeRef,\n targetOrigin: expectedOrigin,\n submitDisabled,\n iframeReady,\n });\n\n const params = new URLSearchParams({ embed: '1', mode: 'payment-only', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle payment\"\n />\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_jsx_runtime","DEFAULT_BASE_URL"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -21,6 +21,8 @@ type ThrottleEvent = {
|
|
|
21
21
|
type: 'throttle.completed';
|
|
22
22
|
orderId: string;
|
|
23
23
|
paymentId: string;
|
|
24
|
+
paymentStatus?: string;
|
|
25
|
+
subscriptionId?: string;
|
|
24
26
|
} | {
|
|
25
27
|
type: 'throttle.cancelled';
|
|
26
28
|
} | {
|
|
@@ -29,9 +31,46 @@ type ThrottleEvent = {
|
|
|
29
31
|
message: string;
|
|
30
32
|
} | {
|
|
31
33
|
type: 'throttle.step.changed';
|
|
32
|
-
step: 'cart' | 'address' | 'shipping' | 'payment';
|
|
34
|
+
step: 'cart' | 'address' | 'shipping' | 'billing' | 'payment';
|
|
33
35
|
};
|
|
34
36
|
type ThrottleMessage = ThrottleEvent & ThrottleEnvelope;
|
|
37
|
+
/**
|
|
38
|
+
* Parent → iframe commands. The SDK posts these when a controlled prop
|
|
39
|
+
* (like `submitDisabled`) changes on the React component. Apps building
|
|
40
|
+
* directly against postMessage (e.g., vanilla JS storefronts) can post
|
|
41
|
+
* the same shape themselves.
|
|
42
|
+
*/
|
|
43
|
+
type ThrottleParentCommand = {
|
|
44
|
+
type: 'set-submit-disabled';
|
|
45
|
+
disabled: boolean;
|
|
46
|
+
};
|
|
47
|
+
interface ThrottleParentEnvelope {
|
|
48
|
+
source: 'throttle-parent';
|
|
49
|
+
version: 1;
|
|
50
|
+
}
|
|
51
|
+
type ThrottleParentMessage = ThrottleParentCommand & ThrottleParentEnvelope;
|
|
52
|
+
/**
|
|
53
|
+
* Recurring subscription intent for an embed-driven subscribe flow.
|
|
54
|
+
*
|
|
55
|
+
* The authoritative recurring metadata lives on the checkout session
|
|
56
|
+
* (set when calling POST /api/v1/checkout/sessions). This prop is a
|
|
57
|
+
* type-level hint that signals subscription intent in your TSX without
|
|
58
|
+
* requiring a runtime read of the session.
|
|
59
|
+
*
|
|
60
|
+
* - `create: 'auto'` (default) — server creates the subscription on
|
|
61
|
+
* vault success. `onSucceeded` payload includes `subscriptionId`.
|
|
62
|
+
* - `create: 'manual'` — server only vaults; merchant calls
|
|
63
|
+
* `subscriptions.create` from their backend after `payment.vaulted`
|
|
64
|
+
* webhook or `onSucceeded` callback.
|
|
65
|
+
*/
|
|
66
|
+
interface RecurringIntent {
|
|
67
|
+
plan: string;
|
|
68
|
+
interval: 'weekly' | 'monthly' | 'quarterly' | 'yearly';
|
|
69
|
+
amount?: number;
|
|
70
|
+
trialDays?: number;
|
|
71
|
+
planName?: string;
|
|
72
|
+
create?: 'auto' | 'manual';
|
|
73
|
+
}
|
|
35
74
|
interface ThrottleEmbedProps {
|
|
36
75
|
/** Throttle checkout session id (cs_*). Required. */
|
|
37
76
|
sessionId: string;
|
|
@@ -52,11 +91,29 @@ interface ThrottleEmbedProps {
|
|
|
52
91
|
initialHeight?: number;
|
|
53
92
|
className?: string;
|
|
54
93
|
style?: CSSProperties;
|
|
94
|
+
/**
|
|
95
|
+
* Subscription intent. Type-level hint — when set, this signals to readers
|
|
96
|
+
* of your code that the embed seeds a subscription on success. The
|
|
97
|
+
* authoritative data lives on the session itself; this prop is purely
|
|
98
|
+
* declarative. See {@link RecurringIntent} for field semantics.
|
|
99
|
+
*/
|
|
100
|
+
recurring?: RecurringIntent;
|
|
101
|
+
/**
|
|
102
|
+
* Disable the submit affordance inside the iframe. Use this to gate
|
|
103
|
+
* payment behind parent-side form validity (e.g., a shipping address
|
|
104
|
+
* form rendered above the embed must be filled in first).
|
|
105
|
+
*
|
|
106
|
+
* The buyer can still see and interact with the card form fields. Only
|
|
107
|
+
* the path from "buyer submits" → "throttle captures" is blocked.
|
|
108
|
+
* Default `false` for backward compatibility.
|
|
109
|
+
*/
|
|
110
|
+
submitDisabled?: boolean;
|
|
55
111
|
onReady?: () => void;
|
|
56
112
|
onProcessing?: () => void;
|
|
57
113
|
onSucceeded?: (evt: {
|
|
58
114
|
orderId: string;
|
|
59
115
|
paymentId: string;
|
|
116
|
+
subscriptionId?: string;
|
|
60
117
|
}) => void;
|
|
61
118
|
onFailed?: (evt: {
|
|
62
119
|
code: string;
|
|
@@ -66,7 +123,7 @@ interface ThrottleEmbedProps {
|
|
|
66
123
|
}
|
|
67
124
|
interface CheckoutEmbedExtraProps {
|
|
68
125
|
onStepChanged?: (evt: {
|
|
69
|
-
step: 'cart' | 'address' | 'shipping' | 'payment';
|
|
126
|
+
step: 'cart' | 'address' | 'shipping' | 'billing' | 'payment';
|
|
70
127
|
}) => void;
|
|
71
128
|
}
|
|
72
129
|
|
|
@@ -80,7 +137,7 @@ interface CheckoutEmbedExtraProps {
|
|
|
80
137
|
* (`throttle embed-config set --origins ...`). Mismatches render
|
|
81
138
|
* an in-iframe "Embed not authorized" panel.
|
|
82
139
|
*/
|
|
83
|
-
declare function CheckoutEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged, }: ThrottleEmbedProps & CheckoutEmbedExtraProps): react_jsx_runtime.JSX.Element;
|
|
140
|
+
declare function CheckoutEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, submitDisabled, onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged, }: ThrottleEmbedProps & CheckoutEmbedExtraProps): react_jsx_runtime.JSX.Element;
|
|
84
141
|
|
|
85
142
|
/**
|
|
86
143
|
* Payment-only iframe embed. Renders just the Gr4vy provider iframe
|
|
@@ -92,7 +149,7 @@ declare function CheckoutEmbed({ sessionId, parentOrigin, baseUrl, primary, logo
|
|
|
92
149
|
* `parentOrigin` must match an entry in the merchant's allow-list.
|
|
93
150
|
* The iframe auto-resizes on `throttle.resize` events.
|
|
94
151
|
*/
|
|
95
|
-
declare function PaymentEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, onReady, onProcessing, onSucceeded, onFailed, onCanceled, }: ThrottleEmbedProps): react_jsx_runtime.JSX.Element;
|
|
152
|
+
declare function PaymentEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, submitDisabled, onReady, onProcessing, onSucceeded, onFailed, onCanceled, }: ThrottleEmbedProps): react_jsx_runtime.JSX.Element;
|
|
96
153
|
|
|
97
154
|
interface UseThrottleEventsOptions {
|
|
98
155
|
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
@@ -120,4 +177,4 @@ interface UseThrottleEventsOptions {
|
|
|
120
177
|
*/
|
|
121
178
|
declare function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }: UseThrottleEventsOptions): void;
|
|
122
179
|
|
|
123
|
-
export { CheckoutEmbed, type CheckoutEmbedExtraProps, PaymentEmbed, CheckoutEmbed as ThrottleCheckout, type ThrottleEmbedProps, type ThrottleEnvelope, type ThrottleEvent, type ThrottleMessage, useThrottleEvents };
|
|
180
|
+
export { CheckoutEmbed, type CheckoutEmbedExtraProps, PaymentEmbed, type RecurringIntent, CheckoutEmbed as ThrottleCheckout, type ThrottleEmbedProps, type ThrottleEnvelope, type ThrottleEvent, type ThrottleMessage, type ThrottleParentCommand, type ThrottleParentEnvelope, type ThrottleParentMessage, useThrottleEvents };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ type ThrottleEvent = {
|
|
|
21
21
|
type: 'throttle.completed';
|
|
22
22
|
orderId: string;
|
|
23
23
|
paymentId: string;
|
|
24
|
+
paymentStatus?: string;
|
|
25
|
+
subscriptionId?: string;
|
|
24
26
|
} | {
|
|
25
27
|
type: 'throttle.cancelled';
|
|
26
28
|
} | {
|
|
@@ -29,9 +31,46 @@ type ThrottleEvent = {
|
|
|
29
31
|
message: string;
|
|
30
32
|
} | {
|
|
31
33
|
type: 'throttle.step.changed';
|
|
32
|
-
step: 'cart' | 'address' | 'shipping' | 'payment';
|
|
34
|
+
step: 'cart' | 'address' | 'shipping' | 'billing' | 'payment';
|
|
33
35
|
};
|
|
34
36
|
type ThrottleMessage = ThrottleEvent & ThrottleEnvelope;
|
|
37
|
+
/**
|
|
38
|
+
* Parent → iframe commands. The SDK posts these when a controlled prop
|
|
39
|
+
* (like `submitDisabled`) changes on the React component. Apps building
|
|
40
|
+
* directly against postMessage (e.g., vanilla JS storefronts) can post
|
|
41
|
+
* the same shape themselves.
|
|
42
|
+
*/
|
|
43
|
+
type ThrottleParentCommand = {
|
|
44
|
+
type: 'set-submit-disabled';
|
|
45
|
+
disabled: boolean;
|
|
46
|
+
};
|
|
47
|
+
interface ThrottleParentEnvelope {
|
|
48
|
+
source: 'throttle-parent';
|
|
49
|
+
version: 1;
|
|
50
|
+
}
|
|
51
|
+
type ThrottleParentMessage = ThrottleParentCommand & ThrottleParentEnvelope;
|
|
52
|
+
/**
|
|
53
|
+
* Recurring subscription intent for an embed-driven subscribe flow.
|
|
54
|
+
*
|
|
55
|
+
* The authoritative recurring metadata lives on the checkout session
|
|
56
|
+
* (set when calling POST /api/v1/checkout/sessions). This prop is a
|
|
57
|
+
* type-level hint that signals subscription intent in your TSX without
|
|
58
|
+
* requiring a runtime read of the session.
|
|
59
|
+
*
|
|
60
|
+
* - `create: 'auto'` (default) — server creates the subscription on
|
|
61
|
+
* vault success. `onSucceeded` payload includes `subscriptionId`.
|
|
62
|
+
* - `create: 'manual'` — server only vaults; merchant calls
|
|
63
|
+
* `subscriptions.create` from their backend after `payment.vaulted`
|
|
64
|
+
* webhook or `onSucceeded` callback.
|
|
65
|
+
*/
|
|
66
|
+
interface RecurringIntent {
|
|
67
|
+
plan: string;
|
|
68
|
+
interval: 'weekly' | 'monthly' | 'quarterly' | 'yearly';
|
|
69
|
+
amount?: number;
|
|
70
|
+
trialDays?: number;
|
|
71
|
+
planName?: string;
|
|
72
|
+
create?: 'auto' | 'manual';
|
|
73
|
+
}
|
|
35
74
|
interface ThrottleEmbedProps {
|
|
36
75
|
/** Throttle checkout session id (cs_*). Required. */
|
|
37
76
|
sessionId: string;
|
|
@@ -52,11 +91,29 @@ interface ThrottleEmbedProps {
|
|
|
52
91
|
initialHeight?: number;
|
|
53
92
|
className?: string;
|
|
54
93
|
style?: CSSProperties;
|
|
94
|
+
/**
|
|
95
|
+
* Subscription intent. Type-level hint — when set, this signals to readers
|
|
96
|
+
* of your code that the embed seeds a subscription on success. The
|
|
97
|
+
* authoritative data lives on the session itself; this prop is purely
|
|
98
|
+
* declarative. See {@link RecurringIntent} for field semantics.
|
|
99
|
+
*/
|
|
100
|
+
recurring?: RecurringIntent;
|
|
101
|
+
/**
|
|
102
|
+
* Disable the submit affordance inside the iframe. Use this to gate
|
|
103
|
+
* payment behind parent-side form validity (e.g., a shipping address
|
|
104
|
+
* form rendered above the embed must be filled in first).
|
|
105
|
+
*
|
|
106
|
+
* The buyer can still see and interact with the card form fields. Only
|
|
107
|
+
* the path from "buyer submits" → "throttle captures" is blocked.
|
|
108
|
+
* Default `false` for backward compatibility.
|
|
109
|
+
*/
|
|
110
|
+
submitDisabled?: boolean;
|
|
55
111
|
onReady?: () => void;
|
|
56
112
|
onProcessing?: () => void;
|
|
57
113
|
onSucceeded?: (evt: {
|
|
58
114
|
orderId: string;
|
|
59
115
|
paymentId: string;
|
|
116
|
+
subscriptionId?: string;
|
|
60
117
|
}) => void;
|
|
61
118
|
onFailed?: (evt: {
|
|
62
119
|
code: string;
|
|
@@ -66,7 +123,7 @@ interface ThrottleEmbedProps {
|
|
|
66
123
|
}
|
|
67
124
|
interface CheckoutEmbedExtraProps {
|
|
68
125
|
onStepChanged?: (evt: {
|
|
69
|
-
step: 'cart' | 'address' | 'shipping' | 'payment';
|
|
126
|
+
step: 'cart' | 'address' | 'shipping' | 'billing' | 'payment';
|
|
70
127
|
}) => void;
|
|
71
128
|
}
|
|
72
129
|
|
|
@@ -80,7 +137,7 @@ interface CheckoutEmbedExtraProps {
|
|
|
80
137
|
* (`throttle embed-config set --origins ...`). Mismatches render
|
|
81
138
|
* an in-iframe "Embed not authorized" panel.
|
|
82
139
|
*/
|
|
83
|
-
declare function CheckoutEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged, }: ThrottleEmbedProps & CheckoutEmbedExtraProps): react_jsx_runtime.JSX.Element;
|
|
140
|
+
declare function CheckoutEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, submitDisabled, onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged, }: ThrottleEmbedProps & CheckoutEmbedExtraProps): react_jsx_runtime.JSX.Element;
|
|
84
141
|
|
|
85
142
|
/**
|
|
86
143
|
* Payment-only iframe embed. Renders just the Gr4vy provider iframe
|
|
@@ -92,7 +149,7 @@ declare function CheckoutEmbed({ sessionId, parentOrigin, baseUrl, primary, logo
|
|
|
92
149
|
* `parentOrigin` must match an entry in the merchant's allow-list.
|
|
93
150
|
* The iframe auto-resizes on `throttle.resize` events.
|
|
94
151
|
*/
|
|
95
|
-
declare function PaymentEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, onReady, onProcessing, onSucceeded, onFailed, onCanceled, }: ThrottleEmbedProps): react_jsx_runtime.JSX.Element;
|
|
152
|
+
declare function PaymentEmbed({ sessionId, parentOrigin, baseUrl, primary, logo, initialHeight, className, style, submitDisabled, onReady, onProcessing, onSucceeded, onFailed, onCanceled, }: ThrottleEmbedProps): react_jsx_runtime.JSX.Element;
|
|
96
153
|
|
|
97
154
|
interface UseThrottleEventsOptions {
|
|
98
155
|
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
@@ -120,4 +177,4 @@ interface UseThrottleEventsOptions {
|
|
|
120
177
|
*/
|
|
121
178
|
declare function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }: UseThrottleEventsOptions): void;
|
|
122
179
|
|
|
123
|
-
export { CheckoutEmbed, type CheckoutEmbedExtraProps, PaymentEmbed, CheckoutEmbed as ThrottleCheckout, type ThrottleEmbedProps, type ThrottleEnvelope, type ThrottleEvent, type ThrottleMessage, useThrottleEvents };
|
|
180
|
+
export { CheckoutEmbed, type CheckoutEmbedExtraProps, PaymentEmbed, type RecurringIntent, CheckoutEmbed as ThrottleCheckout, type ThrottleEmbedProps, type ThrottleEnvelope, type ThrottleEvent, type ThrottleMessage, type ThrottleParentCommand, type ThrottleParentEnvelope, type ThrottleParentMessage, useThrottleEvents };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/CheckoutEmbed.tsx
|
|
2
|
-
import { useCallback, useRef } from "react";
|
|
2
|
+
import { useCallback, useRef, useState as useState2 } from "react";
|
|
3
3
|
|
|
4
4
|
// src/useThrottleEvents.ts
|
|
5
5
|
import { useEffect } from "react";
|
|
@@ -19,6 +19,32 @@ function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }) {
|
|
|
19
19
|
}, [iframeRef, expectedOrigin, onMessage]);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// src/useParentCommands.ts
|
|
23
|
+
import { useEffect as useEffect2, useState } from "react";
|
|
24
|
+
function useParentCommands({
|
|
25
|
+
iframeRef,
|
|
26
|
+
targetOrigin,
|
|
27
|
+
submitDisabled,
|
|
28
|
+
iframeReady
|
|
29
|
+
}) {
|
|
30
|
+
const [lastSent, setLastSent] = useState(void 0);
|
|
31
|
+
useEffect2(() => {
|
|
32
|
+
if (submitDisabled === void 0) return;
|
|
33
|
+
const win = iframeRef.current?.contentWindow;
|
|
34
|
+
if (!win) return;
|
|
35
|
+
if (lastSent === submitDisabled && iframeReady) return;
|
|
36
|
+
if (!iframeReady) return;
|
|
37
|
+
const message = {
|
|
38
|
+
source: "throttle-parent",
|
|
39
|
+
version: 1,
|
|
40
|
+
type: "set-submit-disabled",
|
|
41
|
+
disabled: submitDisabled
|
|
42
|
+
};
|
|
43
|
+
win.postMessage(message, targetOrigin);
|
|
44
|
+
setLastSent(submitDisabled);
|
|
45
|
+
}, [iframeRef, targetOrigin, submitDisabled, iframeReady, lastSent]);
|
|
46
|
+
}
|
|
47
|
+
|
|
22
48
|
// src/CheckoutEmbed.tsx
|
|
23
49
|
import { jsx } from "react/jsx-runtime";
|
|
24
50
|
var DEFAULT_BASE_URL = "https://checkout.usethrottle.dev";
|
|
@@ -31,6 +57,7 @@ function CheckoutEmbed({
|
|
|
31
57
|
initialHeight = 600,
|
|
32
58
|
className,
|
|
33
59
|
style,
|
|
60
|
+
submitDisabled,
|
|
34
61
|
onReady,
|
|
35
62
|
onProcessing,
|
|
36
63
|
onSucceeded,
|
|
@@ -40,17 +67,23 @@ function CheckoutEmbed({
|
|
|
40
67
|
}) {
|
|
41
68
|
const iframeRef = useRef(null);
|
|
42
69
|
const expectedOrigin = new URL(baseUrl).origin;
|
|
70
|
+
const [iframeReady, setIframeReady] = useState2(false);
|
|
43
71
|
const dispatch = useCallback(
|
|
44
72
|
(msg) => {
|
|
45
73
|
switch (msg.type) {
|
|
46
74
|
case "throttle.ready":
|
|
75
|
+
setIframeReady(true);
|
|
47
76
|
onReady?.();
|
|
48
77
|
break;
|
|
49
78
|
case "throttle.processing":
|
|
50
79
|
onProcessing?.();
|
|
51
80
|
break;
|
|
52
81
|
case "throttle.completed":
|
|
53
|
-
onSucceeded?.({
|
|
82
|
+
onSucceeded?.({
|
|
83
|
+
orderId: msg.orderId,
|
|
84
|
+
paymentId: msg.paymentId,
|
|
85
|
+
...msg.subscriptionId !== void 0 ? { subscriptionId: msg.subscriptionId } : {}
|
|
86
|
+
});
|
|
54
87
|
break;
|
|
55
88
|
case "throttle.error":
|
|
56
89
|
onFailed?.({ code: msg.code, message: msg.message });
|
|
@@ -69,6 +102,12 @@ function CheckoutEmbed({
|
|
|
69
102
|
[onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged]
|
|
70
103
|
);
|
|
71
104
|
useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });
|
|
105
|
+
useParentCommands({
|
|
106
|
+
iframeRef,
|
|
107
|
+
targetOrigin: expectedOrigin,
|
|
108
|
+
submitDisabled,
|
|
109
|
+
iframeReady
|
|
110
|
+
});
|
|
72
111
|
const params = new URLSearchParams({ embed: "1", mode: "checkout-full", parentOrigin });
|
|
73
112
|
if (primary) params.set("primary", primary);
|
|
74
113
|
if (logo) params.set("logo", logo);
|
|
@@ -88,7 +127,7 @@ function CheckoutEmbed({
|
|
|
88
127
|
}
|
|
89
128
|
|
|
90
129
|
// src/PaymentEmbed.tsx
|
|
91
|
-
import { useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
130
|
+
import { useCallback as useCallback2, useRef as useRef2, useState as useState3 } from "react";
|
|
92
131
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
93
132
|
var DEFAULT_BASE_URL2 = "https://checkout.usethrottle.dev";
|
|
94
133
|
function PaymentEmbed({
|
|
@@ -100,6 +139,7 @@ function PaymentEmbed({
|
|
|
100
139
|
initialHeight = 480,
|
|
101
140
|
className,
|
|
102
141
|
style,
|
|
142
|
+
submitDisabled,
|
|
103
143
|
onReady,
|
|
104
144
|
onProcessing,
|
|
105
145
|
onSucceeded,
|
|
@@ -108,17 +148,23 @@ function PaymentEmbed({
|
|
|
108
148
|
}) {
|
|
109
149
|
const iframeRef = useRef2(null);
|
|
110
150
|
const expectedOrigin = new URL(baseUrl).origin;
|
|
151
|
+
const [iframeReady, setIframeReady] = useState3(false);
|
|
111
152
|
const dispatch = useCallback2(
|
|
112
153
|
(msg) => {
|
|
113
154
|
switch (msg.type) {
|
|
114
155
|
case "throttle.ready":
|
|
156
|
+
setIframeReady(true);
|
|
115
157
|
onReady?.();
|
|
116
158
|
break;
|
|
117
159
|
case "throttle.processing":
|
|
118
160
|
onProcessing?.();
|
|
119
161
|
break;
|
|
120
162
|
case "throttle.completed":
|
|
121
|
-
onSucceeded?.({
|
|
163
|
+
onSucceeded?.({
|
|
164
|
+
orderId: msg.orderId,
|
|
165
|
+
paymentId: msg.paymentId,
|
|
166
|
+
...msg.subscriptionId !== void 0 ? { subscriptionId: msg.subscriptionId } : {}
|
|
167
|
+
});
|
|
122
168
|
break;
|
|
123
169
|
case "throttle.error":
|
|
124
170
|
onFailed?.({ code: msg.code, message: msg.message });
|
|
@@ -134,6 +180,12 @@ function PaymentEmbed({
|
|
|
134
180
|
[onReady, onProcessing, onSucceeded, onFailed, onCanceled]
|
|
135
181
|
);
|
|
136
182
|
useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });
|
|
183
|
+
useParentCommands({
|
|
184
|
+
iframeRef,
|
|
185
|
+
targetOrigin: expectedOrigin,
|
|
186
|
+
submitDisabled,
|
|
187
|
+
iframeReady
|
|
188
|
+
});
|
|
137
189
|
const params = new URLSearchParams({ embed: "1", mode: "payment-only", parentOrigin });
|
|
138
190
|
if (primary) params.set("primary", primary);
|
|
139
191
|
if (logo) params.set("logo", logo);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/CheckoutEmbed.tsx","../src/useThrottleEvents.ts","../src/PaymentEmbed.tsx"],"sourcesContent":["import { useCallback, useRef } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport type {\n ThrottleEmbedProps,\n CheckoutEmbedExtraProps,\n ThrottleMessage,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Full-checkout iframe embed. Renders the entire Throttle hosted\n * checkout (address / shipping / payment) inside an iframe and\n * surfaces lifecycle + terminal events through callbacks. The\n * iframe auto-resizes on `throttle.resize` events.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list\n * (`throttle embed-config set --origins ...`). Mismatches render\n * an in-iframe \"Embed not authorized\" panel.\n */\nexport function CheckoutEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 600,\n className,\n style,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n onStepChanged,\n}: ThrottleEmbedProps & CheckoutEmbedExtraProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({ orderId: msg.orderId, paymentId: msg.paymentId });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.step.changed':\n onStepChanged?.({ step: msg.step });\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n\n const params = new URLSearchParams({ embed: '1', mode: 'checkout-full', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle checkout\"\n />\n );\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { ThrottleMessage } from './types.js';\n\nexport interface UseThrottleEventsOptions {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n /**\n * The Throttle origin (e.g. https://checkout.usethrottle.dev).\n * Strict-equals check against `MessageEvent.origin`. Anything else\n * is silently dropped.\n */\n expectedOrigin: string;\n onMessage: (msg: ThrottleMessage) => void;\n}\n\n/**\n * Subscribe to validated postMessage events from a Throttle iframe.\n *\n * Validation:\n * - event.origin === expectedOrigin (strict string match)\n * - event.source === iframeRef.current.contentWindow (defends against\n * other iframes on the same origin spoofing events)\n * - event.data.source === 'throttle' && event.data.version === 1\n * - event.data.type starts with 'throttle.'\n *\n * Anything failing validation is silently dropped — the parent page\n * may receive postMessages from analytics SDKs, browser extensions,\n * other iframes, etc. We must never throw on those.\n */\nexport function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }: UseThrottleEventsOptions) {\n useEffect(() => {\n function handle(ev: MessageEvent) {\n if (ev.origin !== expectedOrigin) return;\n if (iframeRef.current && ev.source !== iframeRef.current.contentWindow) return;\n const data = ev.data as Partial<ThrottleMessage> | null | undefined;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'throttle' || data.version !== 1) return;\n if (typeof data.type !== 'string' || !data.type.startsWith('throttle.')) return;\n onMessage(data as ThrottleMessage);\n }\n window.addEventListener('message', handle);\n return () => window.removeEventListener('message', handle);\n }, [iframeRef, expectedOrigin, onMessage]);\n}\n","import { useCallback, useRef } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport type { ThrottleEmbedProps, ThrottleMessage } from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Payment-only iframe embed. Renders just the Gr4vy provider iframe\n * (no address / shipping / cart UI). Email is collected by the Gr4vy\n * iframe in proxy-mode sessions. Used when the merchant has built\n * their own checkout UI and only needs Throttle to handle payment\n * authorization + capture.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list.\n * The iframe auto-resizes on `throttle.resize` events.\n */\nexport function PaymentEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 480,\n className,\n style,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n}: ThrottleEmbedProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({ orderId: msg.orderId, paymentId: msg.paymentId });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n\n const params = new URLSearchParams({ embed: '1', mode: 'payment-only', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle payment\"\n />\n );\n}\n"],"mappings":"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","names":["useCallback","useRef","jsx","DEFAULT_BASE_URL","useRef","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/CheckoutEmbed.tsx","../src/useThrottleEvents.ts","../src/useParentCommands.ts","../src/PaymentEmbed.tsx"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport { useParentCommands } from './useParentCommands.js';\nimport type {\n ThrottleEmbedProps,\n CheckoutEmbedExtraProps,\n ThrottleMessage,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Full-checkout iframe embed. Renders the entire Throttle hosted\n * checkout (address / shipping / payment) inside an iframe and\n * surfaces lifecycle + terminal events through callbacks. The\n * iframe auto-resizes on `throttle.resize` events.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list\n * (`throttle embed-config set --origins ...`). Mismatches render\n * an in-iframe \"Embed not authorized\" panel.\n */\nexport function CheckoutEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 600,\n className,\n style,\n submitDisabled,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n onStepChanged,\n}: ThrottleEmbedProps & CheckoutEmbedExtraProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n const [iframeReady, setIframeReady] = useState(false);\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n setIframeReady(true);\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({\n orderId: msg.orderId,\n paymentId: msg.paymentId,\n ...(msg.subscriptionId !== undefined ? { subscriptionId: msg.subscriptionId } : {}),\n });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.step.changed':\n onStepChanged?.({ step: msg.step });\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled, onStepChanged],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n useParentCommands({\n iframeRef,\n targetOrigin: expectedOrigin,\n submitDisabled,\n iframeReady,\n });\n\n const params = new URLSearchParams({ embed: '1', mode: 'checkout-full', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle checkout\"\n />\n );\n}\n","import { useEffect, type RefObject } from 'react';\nimport type { ThrottleMessage } from './types.js';\n\nexport interface UseThrottleEventsOptions {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n /**\n * The Throttle origin (e.g. https://checkout.usethrottle.dev).\n * Strict-equals check against `MessageEvent.origin`. Anything else\n * is silently dropped.\n */\n expectedOrigin: string;\n onMessage: (msg: ThrottleMessage) => void;\n}\n\n/**\n * Subscribe to validated postMessage events from a Throttle iframe.\n *\n * Validation:\n * - event.origin === expectedOrigin (strict string match)\n * - event.source === iframeRef.current.contentWindow (defends against\n * other iframes on the same origin spoofing events)\n * - event.data.source === 'throttle' && event.data.version === 1\n * - event.data.type starts with 'throttle.'\n *\n * Anything failing validation is silently dropped — the parent page\n * may receive postMessages from analytics SDKs, browser extensions,\n * other iframes, etc. We must never throw on those.\n */\nexport function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }: UseThrottleEventsOptions) {\n useEffect(() => {\n function handle(ev: MessageEvent) {\n if (ev.origin !== expectedOrigin) return;\n if (iframeRef.current && ev.source !== iframeRef.current.contentWindow) return;\n const data = ev.data as Partial<ThrottleMessage> | null | undefined;\n if (!data || typeof data !== 'object') return;\n if (data.source !== 'throttle' || data.version !== 1) return;\n if (typeof data.type !== 'string' || !data.type.startsWith('throttle.')) return;\n onMessage(data as ThrottleMessage);\n }\n window.addEventListener('message', handle);\n return () => window.removeEventListener('message', handle);\n }, [iframeRef, expectedOrigin, onMessage]);\n}\n","import { useEffect, useState, type RefObject } from 'react';\nimport type { ThrottleParentMessage } from './types.js';\n\ninterface UseParentCommandsOptions {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n /** The Throttle origin to address messages to. */\n targetOrigin: string;\n /**\n * The current value of `submitDisabled` from the embed props. Posts a\n * `set-submit-disabled` parent command whenever it changes — and once\n * after the iframe reports `throttle.ready` so the iframe sees the\n * intent even if it boots after the prop is already set.\n *\n * `undefined` means the parent never explicitly enabled/disabled — we\n * never post in that case. Backward-compat with embeds that don't\n * pass the prop.\n */\n submitDisabled?: boolean;\n /**\n * Set to `true` once the iframe posts `throttle.ready`. Until then,\n * commands are buffered (we still try to post but the iframe may not\n * have its listener attached yet — and we re-post on ready as a\n * belt-and-braces guard).\n */\n iframeReady: boolean;\n}\n\n/**\n * Post parent → iframe commands when controlled props change. v1.2 adds\n * `set-submit-disabled`; future commands extend the same channel.\n *\n * postMessage is fire-and-forget — we don't wait for an ack from the\n * iframe. The iframe's listener is idempotent (setting the same value\n * twice is a no-op).\n */\nexport function useParentCommands({\n iframeRef,\n targetOrigin,\n submitDisabled,\n iframeReady,\n}: UseParentCommandsOptions) {\n const [lastSent, setLastSent] = useState<boolean | undefined>(undefined);\n\n // Post when the prop value changes OR when the iframe transitions to\n // ready (so the first state lands).\n useEffect(() => {\n if (submitDisabled === undefined) return;\n const win = iframeRef.current?.contentWindow;\n if (!win) return;\n // Skip if we already sent this value AND the iframe was already ready\n // — avoids spam on unrelated re-renders.\n if (lastSent === submitDisabled && iframeReady) return;\n if (!iframeReady) return; // Defer until ready\n\n const message: ThrottleParentMessage = {\n source: 'throttle-parent',\n version: 1,\n type: 'set-submit-disabled',\n disabled: submitDisabled,\n };\n win.postMessage(message, targetOrigin);\n setLastSent(submitDisabled);\n }, [iframeRef, targetOrigin, submitDisabled, iframeReady, lastSent]);\n}\n","import { useCallback, useRef, useState } from 'react';\nimport { useThrottleEvents } from './useThrottleEvents.js';\nimport { useParentCommands } from './useParentCommands.js';\nimport type { ThrottleEmbedProps, ThrottleMessage } from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://checkout.usethrottle.dev';\n\n/**\n * Payment-only iframe embed. Renders just the Gr4vy provider iframe\n * (no address / shipping / cart UI). Email is collected by the Gr4vy\n * iframe in proxy-mode sessions. Used when the merchant has built\n * their own checkout UI and only needs Throttle to handle payment\n * authorization + capture.\n *\n * `parentOrigin` must match an entry in the merchant's allow-list.\n * The iframe auto-resizes on `throttle.resize` events.\n */\nexport function PaymentEmbed({\n sessionId,\n parentOrigin,\n baseUrl = DEFAULT_BASE_URL,\n primary,\n logo,\n initialHeight = 480,\n className,\n style,\n submitDisabled,\n onReady,\n onProcessing,\n onSucceeded,\n onFailed,\n onCanceled,\n}: ThrottleEmbedProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const expectedOrigin = new URL(baseUrl).origin;\n const [iframeReady, setIframeReady] = useState(false);\n\n const dispatch = useCallback(\n (msg: ThrottleMessage) => {\n switch (msg.type) {\n case 'throttle.ready':\n setIframeReady(true);\n onReady?.();\n break;\n case 'throttle.processing':\n onProcessing?.();\n break;\n case 'throttle.completed':\n onSucceeded?.({\n orderId: msg.orderId,\n paymentId: msg.paymentId,\n ...(msg.subscriptionId !== undefined ? { subscriptionId: msg.subscriptionId } : {}),\n });\n break;\n case 'throttle.error':\n onFailed?.({ code: msg.code, message: msg.message });\n break;\n case 'throttle.cancelled':\n onCanceled?.();\n break;\n case 'throttle.resize':\n if (iframeRef.current) iframeRef.current.style.height = `${msg.height}px`;\n break;\n }\n },\n [onReady, onProcessing, onSucceeded, onFailed, onCanceled],\n );\n\n useThrottleEvents({ iframeRef, expectedOrigin, onMessage: dispatch });\n useParentCommands({\n iframeRef,\n targetOrigin: expectedOrigin,\n submitDisabled,\n iframeReady,\n });\n\n const params = new URLSearchParams({ embed: '1', mode: 'payment-only', parentOrigin });\n if (primary) params.set('primary', primary);\n if (logo) params.set('logo', logo);\n const cleanBase = baseUrl.replace(/\\/$/, '');\n const src = `${cleanBase}/c/${encodeURIComponent(sessionId)}?${params.toString()}`;\n\n return (\n <iframe\n ref={iframeRef}\n src={src}\n className={className}\n style={{ border: 0, width: '100%', minHeight: initialHeight, ...style }}\n allow=\"payment *\"\n title=\"Throttle payment\"\n />\n );\n}\n"],"mappings":"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","names":["useState","useEffect","useState","useCallback","useRef","useState","jsx","DEFAULT_BASE_URL","useRef","useState","useCallback"]}
|