@usethrottle/checkout-react 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +12 -9
package/dist/index.cjs
CHANGED
|
@@ -50,7 +50,7 @@ function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }) {
|
|
|
50
50
|
|
|
51
51
|
// src/CheckoutEmbed.tsx
|
|
52
52
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
53
|
-
var DEFAULT_BASE_URL = "https://
|
|
53
|
+
var DEFAULT_BASE_URL = "https://checkout.usethrottle.dev";
|
|
54
54
|
function CheckoutEmbed({
|
|
55
55
|
sessionId,
|
|
56
56
|
parentOrigin,
|
|
@@ -119,7 +119,7 @@ function CheckoutEmbed({
|
|
|
119
119
|
// src/PaymentEmbed.tsx
|
|
120
120
|
var import_react3 = require("react");
|
|
121
121
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
122
|
-
var DEFAULT_BASE_URL2 = "https://
|
|
122
|
+
var DEFAULT_BASE_URL2 = "https://checkout.usethrottle.dev";
|
|
123
123
|
function PaymentEmbed({
|
|
124
124
|
sessionId,
|
|
125
125
|
parentOrigin,
|
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://throttle-checkout.vercel.app';\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://throttle-checkout.vercel.app).\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://throttle-checkout.vercel.app';\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/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"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -42,7 +42,7 @@ interface ThrottleEmbedProps {
|
|
|
42
42
|
* Required.
|
|
43
43
|
*/
|
|
44
44
|
parentOrigin: string;
|
|
45
|
-
/** Base URL of the deployed checkout-web app. Defaults to https://
|
|
45
|
+
/** Base URL of the deployed checkout-web app. Defaults to https://checkout.usethrottle.dev. */
|
|
46
46
|
baseUrl?: string;
|
|
47
47
|
/** Optional brand color override (#rrggbb). */
|
|
48
48
|
primary?: string;
|
|
@@ -97,7 +97,7 @@ declare function PaymentEmbed({ sessionId, parentOrigin, baseUrl, primary, logo,
|
|
|
97
97
|
interface UseThrottleEventsOptions {
|
|
98
98
|
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
99
99
|
/**
|
|
100
|
-
* The Throttle origin (e.g. https://
|
|
100
|
+
* The Throttle origin (e.g. https://checkout.usethrottle.dev).
|
|
101
101
|
* Strict-equals check against `MessageEvent.origin`. Anything else
|
|
102
102
|
* is silently dropped.
|
|
103
103
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface ThrottleEmbedProps {
|
|
|
42
42
|
* Required.
|
|
43
43
|
*/
|
|
44
44
|
parentOrigin: string;
|
|
45
|
-
/** Base URL of the deployed checkout-web app. Defaults to https://
|
|
45
|
+
/** Base URL of the deployed checkout-web app. Defaults to https://checkout.usethrottle.dev. */
|
|
46
46
|
baseUrl?: string;
|
|
47
47
|
/** Optional brand color override (#rrggbb). */
|
|
48
48
|
primary?: string;
|
|
@@ -97,7 +97,7 @@ declare function PaymentEmbed({ sessionId, parentOrigin, baseUrl, primary, logo,
|
|
|
97
97
|
interface UseThrottleEventsOptions {
|
|
98
98
|
iframeRef: RefObject<HTMLIFrameElement | null>;
|
|
99
99
|
/**
|
|
100
|
-
* The Throttle origin (e.g. https://
|
|
100
|
+
* The Throttle origin (e.g. https://checkout.usethrottle.dev).
|
|
101
101
|
* Strict-equals check against `MessageEvent.origin`. Anything else
|
|
102
102
|
* is silently dropped.
|
|
103
103
|
*/
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ function useThrottleEvents({ iframeRef, expectedOrigin, onMessage }) {
|
|
|
21
21
|
|
|
22
22
|
// src/CheckoutEmbed.tsx
|
|
23
23
|
import { jsx } from "react/jsx-runtime";
|
|
24
|
-
var DEFAULT_BASE_URL = "https://
|
|
24
|
+
var DEFAULT_BASE_URL = "https://checkout.usethrottle.dev";
|
|
25
25
|
function CheckoutEmbed({
|
|
26
26
|
sessionId,
|
|
27
27
|
parentOrigin,
|
|
@@ -90,7 +90,7 @@ function CheckoutEmbed({
|
|
|
90
90
|
// src/PaymentEmbed.tsx
|
|
91
91
|
import { useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
92
92
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
93
|
-
var DEFAULT_BASE_URL2 = "https://
|
|
93
|
+
var DEFAULT_BASE_URL2 = "https://checkout.usethrottle.dev";
|
|
94
94
|
function PaymentEmbed({
|
|
95
95
|
sessionId,
|
|
96
96
|
parentOrigin,
|
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://throttle-checkout.vercel.app';\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://throttle-checkout.vercel.app).\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://throttle-checkout.vercel.app';\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":";AAAA,SAAS,aAAa,cAAc;;;ACApC,SAAS,iBAAiC;AA4BnC,SAAS,kBAAkB,EAAE,WAAW,gBAAgB,UAAU,GAA6B;AACpG,YAAU,MAAM;AACd,aAAS,OAAO,IAAkB;AAChC,UAAI,GAAG,WAAW,eAAgB;AAClC,UAAI,UAAU,WAAW,GAAG,WAAW,UAAU,QAAQ,cAAe;AACxE,YAAM,OAAO,GAAG;AAChB,UAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,UAAI,KAAK,WAAW,cAAc,KAAK,YAAY,EAAG;AACtD,UAAI,OAAO,KAAK,SAAS,YAAY,CAAC,KAAK,KAAK,WAAW,WAAW,EAAG;AACzE,gBAAU,IAAuB;AAAA,IACnC;AACA,WAAO,iBAAiB,WAAW,MAAM;AACzC,WAAO,MAAM,OAAO,oBAAoB,WAAW,MAAM;AAAA,EAC3D,GAAG,CAAC,WAAW,gBAAgB,SAAS,CAAC;AAC3C;;;ADmCI;AArEJ,IAAM,mBAAmB;AAYlB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiD;AAC/C,QAAM,YAAY,OAA0B,IAAI;AAChD,QAAM,iBAAiB,IAAI,IAAI,OAAO,EAAE;AAExC,QAAM,WAAW;AAAA,IACf,CAAC,QAAyB;AACxB,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,yBAAe;AACf;AAAA,QACF,KAAK;AACH,wBAAc,EAAE,SAAS,IAAI,SAAS,WAAW,IAAI,UAAU,CAAC;AAChE;AAAA,QACF,KAAK;AACH,qBAAW,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQ,CAAC;AACnD;AAAA,QACF,KAAK;AACH,uBAAa;AACb;AAAA,QACF,KAAK;AACH,0BAAgB,EAAE,MAAM,IAAI,KAAK,CAAC;AAClC;AAAA,QACF,KAAK;AACH,cAAI,UAAU,QAAS,WAAU,QAAQ,MAAM,SAAS,GAAG,IAAI,MAAM;AACrE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,CAAC,SAAS,cAAc,aAAa,UAAU,YAAY,aAAa;AAAA,EAC1E;AAEA,oBAAkB,EAAE,WAAW,gBAAgB,WAAW,SAAS,CAAC;AAEpE,QAAM,SAAS,IAAI,gBAAgB,EAAE,OAAO,KAAK,MAAM,iBAAiB,aAAa,CAAC;AACtF,MAAI,QAAS,QAAO,IAAI,WAAW,OAAO;AAC1C,MAAI,KAAM,QAAO,IAAI,QAAQ,IAAI;AACjC,QAAM,YAAY,QAAQ,QAAQ,OAAO,EAAE;AAC3C,QAAM,MAAM,GAAG,SAAS,MAAM,mBAAmB,SAAS,CAAC,IAAI,OAAO,SAAS,CAAC;AAEhF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,WAAW,eAAe,GAAG,MAAM;AAAA,MACtE,OAAM;AAAA,MACN,OAAM;AAAA;AAAA,EACR;AAEJ;;;AEtFA,SAAS,eAAAA,cAAa,UAAAC,eAAc;AAqEhC,gBAAAC,YAAA;AAjEJ,IAAMC,oBAAmB;AAYlB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,UAAUA;AAAA,EACV;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,YAAYC,QAA0B,IAAI;AAChD,QAAM,iBAAiB,IAAI,IAAI,OAAO,EAAE;AAExC,QAAM,WAAWC;AAAA,IACf,CAAC,QAAyB;AACxB,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,oBAAU;AACV;AAAA,QACF,KAAK;AACH,yBAAe;AACf;AAAA,QACF,KAAK;AACH,wBAAc,EAAE,SAAS,IAAI,SAAS,WAAW,IAAI,UAAU,CAAC;AAChE;AAAA,QACF,KAAK;AACH,qBAAW,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQ,CAAC;AACnD;AAAA,QACF,KAAK;AACH,uBAAa;AACb;AAAA,QACF,KAAK;AACH,cAAI,UAAU,QAAS,WAAU,QAAQ,MAAM,SAAS,GAAG,IAAI,MAAM;AACrE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,CAAC,SAAS,cAAc,aAAa,UAAU,UAAU;AAAA,EAC3D;AAEA,oBAAkB,EAAE,WAAW,gBAAgB,WAAW,SAAS,CAAC;AAEpE,QAAM,SAAS,IAAI,gBAAgB,EAAE,OAAO,KAAK,MAAM,gBAAgB,aAAa,CAAC;AACrF,MAAI,QAAS,QAAO,IAAI,WAAW,OAAO;AAC1C,MAAI,KAAM,QAAO,IAAI,QAAQ,IAAI;AACjC,QAAM,YAAY,QAAQ,QAAQ,OAAO,EAAE;AAC3C,QAAM,MAAM,GAAG,SAAS,MAAM,mBAAmB,SAAS,CAAC,IAAI,OAAO,SAAS,CAAC;AAEhF,SACE,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,WAAW,eAAe,GAAG,MAAM;AAAA,MACtE,OAAM;AAAA,MACN,OAAM;AAAA;AAAA,EACR;AAEJ;","names":["useCallback","useRef","jsx","DEFAULT_BASE_URL","useRef","useCallback"]}
|
|
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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usethrottle/checkout-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "React component for embedded Throttle checkout",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,13 +13,10 @@
|
|
|
13
13
|
"require": "./dist/index.cjs"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
-
"files": [
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
"test": "vitest run",
|
|
21
|
-
"test:watch": "vitest"
|
|
22
|
-
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
23
20
|
"peerDependencies": {
|
|
24
21
|
"react": ">=18"
|
|
25
22
|
},
|
|
@@ -36,5 +33,11 @@
|
|
|
36
33
|
},
|
|
37
34
|
"publishConfig": {
|
|
38
35
|
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"dev": "tsup --watch",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"test:watch": "vitest"
|
|
39
42
|
}
|
|
40
|
-
}
|
|
43
|
+
}
|