@hello-pay/react 0.5.1 → 0.6.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 CHANGED
@@ -146,7 +146,8 @@ var EMPTY_CONTEXT = {
146
146
  elements: null
147
147
  };
148
148
  var ElementsContext = (0, import_react.createContext)(EMPTY_CONTEXT);
149
- function Elements({ hellopay: hellopayProp, children }) {
149
+ function Elements({ hellopay: hellopayProp, options, children }) {
150
+ const sessionClientSecret = options?.sessionClientSecret;
150
151
  const [ctx, setCtx] = (0, import_react.useState)(EMPTY_CONTEXT);
151
152
  (0, import_react.useEffect)(() => {
152
153
  let cancelled = false;
@@ -157,7 +158,10 @@ function Elements({ hellopay: hellopayProp, children }) {
157
158
  setCtx(EMPTY_CONTEXT);
158
159
  return;
159
160
  }
160
- setCtx({ hellopay: sdk, elements: sdk.elements() });
161
+ setCtx({
162
+ hellopay: sdk,
163
+ elements: sdk.elements(sessionClientSecret ? { sessionClientSecret } : void 0)
164
+ });
161
165
  }).catch(() => {
162
166
  if (cancelled) return;
163
167
  setCtx(EMPTY_CONTEXT);
@@ -165,7 +169,7 @@ function Elements({ hellopay: hellopayProp, children }) {
165
169
  return () => {
166
170
  cancelled = true;
167
171
  };
168
- }, [hellopayProp]);
172
+ }, [hellopayProp, sessionClientSecret]);
169
173
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ElementsContext.Provider, { value: ctx, children });
170
174
  }
171
175
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/loadHelloPay.ts","../src/Elements.tsx","../src/ElementComponents.tsx","../src/hooks.ts","../src/ApplePayButton.tsx"],"sourcesContent":["export { loadHelloPay } from './loadHelloPay';\nexport type { LoadHelloPayOptions } from './loadHelloPay';\n\nexport { Elements } from './Elements';\nexport type { ElementsProps } from './Elements';\n\nexport {\n CardNumberElement,\n CardExpiryElement,\n CardCvcElement,\n CardholderNameElement,\n CardPasswordElement,\n} from './ElementComponents';\nexport type { ElementProps } from './ElementComponents';\n\nexport { ApplePayButton } from './ApplePayButton';\nexport type { ApplePayButtonProps } from './ApplePayButton';\n\nexport { useHelloPay, useElements } from './hooks';\n\nexport type {\n HelloPay,\n Elements as ElementsSession,\n Element,\n ElementType,\n ElementOptions,\n ElementStyle,\n ElementChangeEvent,\n CardNumberChangeEvent,\n OtherElementChangeEvent,\n IssuerCountryResult,\n ElementFocusEvent,\n ElementReadyEvent,\n TokenCard,\n HelloPayError,\n CreateTokenResult,\n TokenProvider,\n ApplePayCard,\n ApplePayOptions,\n ApplePayResult,\n ApplePayError,\n ApplePayCancelError,\n Unsubscribe,\n} from './types';\n","/**\n * HelloPay SDK ローダー。\n *\n * HelloPay 管理下のドメイン(js.hello-pay.app 等)から SDK を動的ロードし、\n * `window.HelloPay` ファクトリを解決する。\n *\n * - 同一 sdkUrl への呼び出しは script tag を 1 回だけ挿入(dedup)\n * - 異なる sdkUrl は独立したロードを維持(E2E / ローカル切り替え対応)\n * - SSR 環境では Promise<null> を解決(加盟店側で null チェック)\n * - 一時的な失敗はキャッシュせず次回呼び出しで再試行可能\n */\n\nimport type { HelloPay, HelloPayFactory } from './types';\n\n// SDK 本体は test / live どちらの publishable key でも同一ドメイン\n// (js.hello-pay.app) から配信する。test / live mode の切り替えは SDK 内部で\n// publishable key の prefix から解決し、test mode では接続先を test 環境\n// (*.stg.hello-pay.app) に向ける(hellopay.js と同じ方式)。\nconst DEFAULT_SDK_URL = 'https://js.hello-pay.app/v1/hellopay-elements.js';\n\n// sdkUrl 単位で script ロード Promise をキャッシュ。\n// loadPromise を単一変数にするとすべての URL で共有されてしまい、\n// 異なる sdkUrl(E2E / ローカル開発)が誤って同一ロードを共有する。\nconst scriptPromiseCache = new Map<string, Promise<HelloPayFactory | null>>();\n\n// publicKey + locale + sdkUrl の組み合わせごとに `HelloPaySDK` インスタンスをキャッシュ。\n// 加盟店が誤って inline で loadHelloPay を呼び出した場合でも同一 SDK インスタンスが\n// 返るようにして、Elements セッションの BroadcastChannel session ID ミスマッチを防ぐ。\nconst sdkCache = new Map<string, Promise<HelloPay | null>>();\n\n/** テスト専用: module-scope のキャッシュをすべて初期状態に戻す。 */\nexport function __resetLoadPromiseForTest(): void {\n scriptPromiseCache.clear();\n sdkCache.clear();\n}\n\nfunction normalizeSdkUrl(url: string): string {\n if (typeof window === 'undefined') return url;\n\n try {\n return new URL(url, window.location.href).href;\n } catch {\n return url;\n }\n}\n\nfunction normalizeLocale(locale?: string): string {\n return locale || 'ja';\n}\n\nfunction loadScript(url: string): Promise<HelloPayFactory | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n\n // URL を正規化してプロトコル省略形などを統一する。\n // テスト / SSR 環境では window.location が http URL でない場合があるため try-catch で保護。\n const normalizedUrl = normalizeSdkUrl(url);\n\n return new Promise((resolve, reject) => {\n // script は URL 単位で管理する。異なる URL の script を削除せず共存させることで、\n // E2E / ローカル開発で異なる sdkUrl が並列で呼ばれても Promise が宙吊りにならない。\n // 状態は dataset.hellopayState に \"loading\" | \"loaded\" | \"error\" で刻む。\n const managedScripts = Array.from(\n document.querySelectorAll<HTMLScriptElement>('script[data-hellopay-sdk]'),\n );\n\n const existing = managedScripts.find((script) => {\n const rawUrl = script.dataset.hellopayUrl || script.src;\n if (!rawUrl) return false;\n try {\n return new URL(rawUrl, window.location.href).href === normalizedUrl;\n } catch {\n return rawUrl === normalizedUrl;\n }\n });\n\n if (existing) {\n const state = existing.dataset.hellopayState;\n if (state === 'loaded') {\n resolve(window.HelloPay ?? null);\n return;\n }\n if (state === 'loading') {\n existing.addEventListener('load', () => resolve(window.HelloPay ?? null), {\n once: true,\n });\n existing.addEventListener(\n 'error',\n () => reject(new Error('HelloPay SDK failed to load')),\n { once: true },\n );\n return;\n }\n // state === \"error\" or undefined: 失敗済み or 未知の状態なので作り直す\n existing.remove();\n }\n\n const script = document.createElement('script');\n script.src = normalizedUrl;\n script.async = true;\n script.dataset.hellopaySdk = 'true';\n script.dataset.hellopayUrl = normalizedUrl; // URL 比較用\n script.dataset.hellopayState = 'loading';\n script.addEventListener(\n 'load',\n () => {\n if (!window.HelloPay) {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK loaded but window.HelloPay is missing'));\n return;\n }\n script.dataset.hellopayState = 'loaded';\n resolve(window.HelloPay);\n },\n { once: true },\n );\n script.addEventListener(\n 'error',\n () => {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK failed to load'));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n}\n\nexport interface LoadHelloPayOptions {\n /** SDK 配信 URL(ローカル開発・E2E で差し替える用。省略時は js.hello-pay.app から配信し、test/live は SDK 内部で key prefix から解決) */\n sdkUrl?: string;\n locale?: string;\n}\n\n/**\n * HelloPay SDK をロードして初期化する。\n * モジュールスコープで 1 回だけ呼び、返り値の Promise を `<Elements>` に渡す。\n */\nexport function loadHelloPay(\n publicKey: string,\n options: LoadHelloPayOptions = {},\n): Promise<HelloPay | null> {\n const sdkUrl = normalizeSdkUrl(options.sdkUrl ?? DEFAULT_SDK_URL);\n const locale = normalizeLocale(options.locale);\n const cacheKey = `${publicKey}::${locale}::${sdkUrl}`;\n const cached = sdkCache.get(cacheKey);\n if (cached) return cached;\n\n let scriptPromise = scriptPromiseCache.get(sdkUrl);\n if (!scriptPromise) {\n scriptPromise = loadScript(sdkUrl).catch((err) => {\n // 一時的なロード失敗はキャッシュせず次回呼び出しで再試行可能にする\n scriptPromiseCache.delete(sdkUrl);\n throw err;\n });\n scriptPromiseCache.set(sdkUrl, scriptPromise);\n }\n\n const sdkPromise = scriptPromise\n .then((factory) => {\n if (!factory) return null; // SSR\n return factory(publicKey, { locale: options.locale });\n })\n .catch((err) => {\n // SDK インスタンス生成失敗は sdkCache から退避して次回呼び出しで再試行可能にする\n sdkCache.delete(cacheKey);\n throw err;\n });\n sdkCache.set(cacheKey, sdkPromise);\n return sdkPromise;\n}\n","/**\n * <Elements> Provider.\n *\n * loadHelloPay() の Promise を受け取り、SDK インスタンスと Elements セッションを\n * 子孫に Context 経由で供給する。\n */\n\nimport { createContext, useEffect, useState, type ReactNode } from 'react';\nimport type { HelloPay, Elements as ElementsSession } from './types';\n\nexport interface ElementsContextValue {\n hellopay: HelloPay | null;\n elements: ElementsSession | null;\n}\n\nconst EMPTY_CONTEXT: ElementsContextValue = {\n hellopay: null,\n elements: null,\n};\n\nexport const ElementsContext = createContext<ElementsContextValue>(EMPTY_CONTEXT);\n\nexport interface ElementsProps {\n /** loadHelloPay() の戻り値。モジュールスコープで 1 回だけ生成すること */\n hellopay: Promise<HelloPay | null> | HelloPay | null;\n children: ReactNode;\n}\n\nexport function Elements({ hellopay: hellopayProp, children }: ElementsProps) {\n const [ctx, setCtx] = useState<ElementsContextValue>(EMPTY_CONTEXT);\n\n useEffect(() => {\n let cancelled = false;\n setCtx(EMPTY_CONTEXT);\n\n Promise.resolve(hellopayProp)\n .then((sdk) => {\n if (cancelled) return;\n if (!sdk) {\n setCtx(EMPTY_CONTEXT);\n return;\n }\n setCtx({ hellopay: sdk, elements: sdk.elements() });\n })\n .catch(() => {\n // SDK ロード失敗時は null のまま(unhandled rejection を防ぐ)\n if (cancelled) return;\n setCtx(EMPTY_CONTEXT);\n });\n\n return () => {\n cancelled = true;\n };\n }, [hellopayProp]);\n\n return <ElementsContext.Provider value={ctx}>{children}</ElementsContext.Provider>;\n}\n","/**\n * Element コンポーネント。\n *\n * 各コンポーネントは 1 つの `<div>` コンテナを描画するだけで、\n * 実体(カード情報が入る iframe)はコア SDK が差し込む。\n *\n * React Strict Mode の二重 mount 対応:\n * - effect の cleanup で element.unmount() を必ず呼ぶ\n * - unmount 後は Elements._elements 配列から除外される(コア SDK 側で対応済)\n * - 結果として Strict Mode で effect が再実行されても古い iframe は残らない\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useElements } from './hooks';\nimport type {\n ElementType,\n ElementOptions,\n ElementChangeEvent,\n ElementFocusEvent,\n ElementReadyEvent,\n} from './types';\n\nexport interface ElementProps {\n options?: ElementOptions;\n className?: string;\n style?: CSSProperties;\n onReady?: (e: ElementReadyEvent) => void;\n onChange?: (e: ElementChangeEvent) => void;\n onFocus?: (e: ElementFocusEvent) => void;\n onBlur?: (e: ElementFocusEvent) => void;\n}\n\nconst PROBE_PX = 100000;\n\n/**\n * コンテナの幅・高さのうち、中身に追従する(加盟店が寸法を決めていない)軸を返す。\n */\nfunction contentSizedAxes(container: HTMLElement) {\n // display: none の祖先の中ではレイアウトが無いので、computed value で見る。\n if (container.getClientRects().length === 0) {\n const computed = getComputedStyle(container);\n const isAuto = (v: string) => v === '' || v === 'auto';\n return { width: isAuto(computed.width), height: isAuto(computed.height) };\n }\n // computed の height で判定すると、border-box の padding・border や min-height で\n // 0 にならず見誤るので、大きな子を一時的に入れて寸法が伸びるかで確かめる。\n // 祖先の transform(モーダルの scale のアニメーションなど)に左右されないよう、\n // getBoundingClientRect ではなくレイアウト上の寸法の offset* で比べる。\n const before = { width: container.offsetWidth, height: container.offsetHeight };\n const probe = container.ownerDocument.createElement('div');\n probe.style.cssText = `width: ${PROBE_PX}px; height: ${PROBE_PX}px;`;\n container.appendChild(probe);\n const grows = {\n width: container.offsetWidth > before.width,\n height: container.offsetHeight > before.height,\n };\n probe.remove();\n return grows;\n}\n\n/**\n * 指定 type の Element を管理する React コンポーネントを生成する。\n */\nfunction createElementComponent(type: ElementType) {\n function ElementComponent({\n options,\n className,\n style,\n onReady,\n onChange,\n onFocus,\n onBlur,\n }: ElementProps) {\n const elements = useElements();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [fill, setFill] = useState({ width: false, height: false });\n\n // 最新のハンドラを ref で保持(effect を毎回 re-run させないため)\n const handlersRef = useRef({ onReady, onChange, onFocus, onBlur });\n handlersRef.current = { onReady, onChange, onFocus, onBlur };\n\n useEffect(() => {\n const container = containerRef.current;\n if (!elements || !container) return;\n\n // 100% を当てた後に測り直すと親の寸法に追従して見えるので、立てた軸は戻さない。\n const unset = contentSizedAxes(container);\n setFill((prev) => ({\n width: prev.width || unset.width,\n height: prev.height || unset.height,\n }));\n\n const element = elements.create(type, options);\n element.mount(container);\n\n const unsubs = [\n element.on('ready', (e) => handlersRef.current.onReady?.(e)),\n element.on('change', (e) => handlersRef.current.onChange?.(e)),\n element.on('focus', (e) => handlersRef.current.onFocus?.(e)),\n element.on('blur', (e) => handlersRef.current.onBlur?.(e)),\n ];\n\n return () => {\n unsubs.forEach((u) => u());\n element.unmount();\n };\n // options はマウント時にしか反映しない方針(Stripe と同じ挙動)。\n // 動的に style を変えたい場合は後続 PR で element.update() を追加。\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [elements]);\n\n // インラインの既定値は className の寸法に勝つので、加盟店が決めていない軸だけに付ける。\n // 判定は mount 時の 1 回だけなので、後から寸法を変えるなら style で渡す。\n return (\n <div\n ref={containerRef}\n className={className}\n style={{\n ...(fill.width && { width: '100%' }),\n ...(fill.height && { height: '100%' }),\n ...style,\n }}\n />\n );\n }\n ElementComponent.displayName = `HelloPay(${type})`;\n // getElement(CardNumberElement) のようにコンポーネント自身を型指定子として使えるよう、\n // 静的プロパティに type を生やしておく\n ElementComponent.__elementType = type as ElementType;\n return ElementComponent;\n}\n\nexport const CardNumberElement = createElementComponent('cardNumber');\nexport const CardExpiryElement = createElementComponent('cardExpiry');\nexport const CardCvcElement = createElementComponent('cardCvc');\nexport const CardholderNameElement = createElementComponent('cardholderName');\n// 韓国発行カードの Toss 登録に必要な暗証番号の先頭 2 桁。表示・非表示は\n// 発行国の判定結果に応じて呼び出し側が mount / unmount で制御する。\nexport const CardPasswordElement = createElementComponent('cardPassword');\n\nexport type ElementComponent = typeof CardNumberElement;\n","/**\n * React hooks.\n *\n * useHelloPay / useElements は <Elements> Provider の Context から\n * SDK インスタンスと Elements セッションを取り出す。\n * SDK ロード完了までは null を返すので、ハンドラ内で null チェックする。\n */\n\nimport { useContext } from 'react';\nimport { ElementsContext } from './Elements';\nimport type { HelloPay, Elements } from './types';\n\nexport function useHelloPay(): HelloPay | null {\n return useContext(ElementsContext).hellopay;\n}\n\nexport function useElements(): Elements | null {\n return useContext(ElementsContext).elements;\n}\n","/**\n * Apple Pay ボタン。\n *\n * `useHelloPay()` から SDK を取り、対応端末(Safari + Apple Pay 利用可能)でのみ\n * Apple 公式スタイルのボタンを描画する。非対応端末では何も描画しない。\n *\n * click で `hellopay.applePay()` を同期呼び出しし(`new ApplePaySession` の\n * user gesture 要件のため)、結果を `onToken` / `onError` / `onCancel` に振り分ける。\n * SDK は Apple Pay トークンを返すだけで課金はしないので、加盟店は `onToken` で\n * 受けたトークンを自社バックエンドから決済 API に送って課金する。\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useHelloPay } from './hooks';\nimport type { ApplePayCard, ApplePayOptions, HelloPayError } from './types';\n\nexport interface ApplePayButtonProps {\n options: ApplePayOptions;\n /** トークン取得成功時。トークンを自社バックエンド経由で決済 API に送る。 */\n onToken: (token: string, card: ApplePayCard) => void;\n /** validation / network エラー時。 */\n onError?: (error: HelloPayError) => void;\n /** ユーザーが Apple Pay シートを閉じた時。 */\n onCancel?: () => void;\n /** Apple Pay ボタンの色。既定 `black`。 */\n buttonStyle?: 'black' | 'white' | 'white-outline';\n /** Apple Pay ボタンの種別(`plain` / `buy` / `pay` 等)。既定 `plain`。 */\n buttonType?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function ApplePayButton({\n options,\n onToken,\n onError,\n onCancel,\n buttonStyle = 'black',\n buttonType = 'plain',\n className,\n style,\n}: ApplePayButtonProps) {\n const hellopay = useHelloPay();\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const [supported, setSupported] = useState(false);\n\n // canMakeApplePayPayments は ApplePaySession 依存で client-only のため effect で判定。\n useEffect(() => {\n setSupported(!!hellopay && hellopay.canMakeApplePayPayments());\n }, [hellopay]);\n\n // Apple Pay ボタンの見た目はベンダー CSS プロパティで指定する。React の style 型に\n // 無いため ref 経由で setProperty する。\n useEffect(() => {\n const el = buttonRef.current;\n if (!el) return;\n el.style.setProperty('-webkit-appearance', '-apple-pay-button');\n el.style.setProperty('-apple-pay-button-type', buttonType);\n el.style.setProperty('-apple-pay-button-style', buttonStyle);\n }, [supported, buttonType, buttonStyle]);\n\n // 最新のハンドラ / options を ref に保持し、click ハンドラを毎回作り直さない。\n const latest = useRef({ options, onToken, onError, onCancel, hellopay });\n latest.current = { options, onToken, onError, onCancel, hellopay };\n\n if (!supported) return null;\n\n const handleClick = () => {\n const current = latest.current;\n if (!current.hellopay) return;\n // user gesture 要件のため click ハンドラから同期呼び出しする。\n current.hellopay\n .applePay(current.options)\n .then((result) => {\n if (result.error) {\n if (result.error.type === 'cancel') {\n current.onCancel?.();\n } else {\n current.onError?.(result.error);\n }\n return;\n }\n current.onToken(result.token, result.card);\n })\n .catch((err: unknown) => {\n current.onError?.({\n type: 'config_error',\n code: 'apple_pay_error',\n message: err instanceof Error ? err.message : 'Apple Pay error',\n });\n });\n };\n\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleClick}\n className={className}\n style={{ width: '100%', height: '44px', cursor: 'pointer', ...style }}\n />\n );\n}\n\nApplePayButton.displayName = 'HelloPay(ApplePayButton)';\n"],"mappings":"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","names":["script","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/loadHelloPay.ts","../src/Elements.tsx","../src/ElementComponents.tsx","../src/hooks.ts","../src/ApplePayButton.tsx"],"sourcesContent":["export { loadHelloPay } from './loadHelloPay';\nexport type { LoadHelloPayOptions } from './loadHelloPay';\n\nexport { Elements } from './Elements';\nexport type { ElementsProps } from './Elements';\n\nexport {\n CardNumberElement,\n CardExpiryElement,\n CardCvcElement,\n CardholderNameElement,\n CardPasswordElement,\n} from './ElementComponents';\nexport type { ElementProps } from './ElementComponents';\n\nexport { ApplePayButton } from './ApplePayButton';\nexport type { ApplePayButtonProps } from './ApplePayButton';\n\nexport { useHelloPay, useElements } from './hooks';\n\nexport type {\n HelloPay,\n Elements as ElementsSession,\n Element,\n ElementType,\n ElementOptions,\n ElementStyle,\n ElementChangeEvent,\n CardNumberChangeEvent,\n OtherElementChangeEvent,\n IssuerCountryResult,\n ElementFocusEvent,\n ElementReadyEvent,\n ElementsOptions,\n TokenCard,\n HelloPayError,\n CreateTokenResult,\n TokenProvider,\n ApplePayCard,\n ApplePayOptions,\n ApplePayResult,\n ApplePayError,\n ApplePayCancelError,\n Unsubscribe,\n} from './types';\n","/**\n * HelloPay SDK ローダー。\n *\n * HelloPay 管理下のドメイン(js.hello-pay.app 等)から SDK を動的ロードし、\n * `window.HelloPay` ファクトリを解決する。\n *\n * - 同一 sdkUrl への呼び出しは script tag を 1 回だけ挿入(dedup)\n * - 異なる sdkUrl は独立したロードを維持(E2E / ローカル切り替え対応)\n * - SSR 環境では Promise<null> を解決(加盟店側で null チェック)\n * - 一時的な失敗はキャッシュせず次回呼び出しで再試行可能\n */\n\nimport type { HelloPay, HelloPayFactory } from './types';\n\n// SDK 本体は test / live どちらの publishable key でも同一ドメイン\n// (js.hello-pay.app) から配信する。test / live mode の切り替えは SDK 内部で\n// publishable key の prefix から解決し、test mode では接続先を test 環境\n// (*.stg.hello-pay.app) に向ける(hellopay.js と同じ方式)。\nconst DEFAULT_SDK_URL = 'https://js.hello-pay.app/v1/hellopay-elements.js';\n\n// sdkUrl 単位で script ロード Promise をキャッシュ。\n// loadPromise を単一変数にするとすべての URL で共有されてしまい、\n// 異なる sdkUrl(E2E / ローカル開発)が誤って同一ロードを共有する。\nconst scriptPromiseCache = new Map<string, Promise<HelloPayFactory | null>>();\n\n// publicKey + locale + sdkUrl の組み合わせごとに `HelloPaySDK` インスタンスをキャッシュ。\n// 加盟店が誤って inline で loadHelloPay を呼び出した場合でも同一 SDK インスタンスが\n// 返るようにして、Elements セッションの BroadcastChannel session ID ミスマッチを防ぐ。\nconst sdkCache = new Map<string, Promise<HelloPay | null>>();\n\n/** テスト専用: module-scope のキャッシュをすべて初期状態に戻す。 */\nexport function __resetLoadPromiseForTest(): void {\n scriptPromiseCache.clear();\n sdkCache.clear();\n}\n\nfunction normalizeSdkUrl(url: string): string {\n if (typeof window === 'undefined') return url;\n\n try {\n return new URL(url, window.location.href).href;\n } catch {\n return url;\n }\n}\n\nfunction normalizeLocale(locale?: string): string {\n return locale || 'ja';\n}\n\nfunction loadScript(url: string): Promise<HelloPayFactory | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n\n // URL を正規化してプロトコル省略形などを統一する。\n // テスト / SSR 環境では window.location が http URL でない場合があるため try-catch で保護。\n const normalizedUrl = normalizeSdkUrl(url);\n\n return new Promise((resolve, reject) => {\n // script は URL 単位で管理する。異なる URL の script を削除せず共存させることで、\n // E2E / ローカル開発で異なる sdkUrl が並列で呼ばれても Promise が宙吊りにならない。\n // 状態は dataset.hellopayState に \"loading\" | \"loaded\" | \"error\" で刻む。\n const managedScripts = Array.from(\n document.querySelectorAll<HTMLScriptElement>('script[data-hellopay-sdk]'),\n );\n\n const existing = managedScripts.find((script) => {\n const rawUrl = script.dataset.hellopayUrl || script.src;\n if (!rawUrl) return false;\n try {\n return new URL(rawUrl, window.location.href).href === normalizedUrl;\n } catch {\n return rawUrl === normalizedUrl;\n }\n });\n\n if (existing) {\n const state = existing.dataset.hellopayState;\n if (state === 'loaded') {\n resolve(window.HelloPay ?? null);\n return;\n }\n if (state === 'loading') {\n existing.addEventListener('load', () => resolve(window.HelloPay ?? null), {\n once: true,\n });\n existing.addEventListener(\n 'error',\n () => reject(new Error('HelloPay SDK failed to load')),\n { once: true },\n );\n return;\n }\n // state === \"error\" or undefined: 失敗済み or 未知の状態なので作り直す\n existing.remove();\n }\n\n const script = document.createElement('script');\n script.src = normalizedUrl;\n script.async = true;\n script.dataset.hellopaySdk = 'true';\n script.dataset.hellopayUrl = normalizedUrl; // URL 比較用\n script.dataset.hellopayState = 'loading';\n script.addEventListener(\n 'load',\n () => {\n if (!window.HelloPay) {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK loaded but window.HelloPay is missing'));\n return;\n }\n script.dataset.hellopayState = 'loaded';\n resolve(window.HelloPay);\n },\n { once: true },\n );\n script.addEventListener(\n 'error',\n () => {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK failed to load'));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n}\n\nexport interface LoadHelloPayOptions {\n /** SDK 配信 URL(ローカル開発・E2E で差し替える用。省略時は js.hello-pay.app から配信し、test/live は SDK 内部で key prefix から解決) */\n sdkUrl?: string;\n locale?: string;\n}\n\n/**\n * HelloPay SDK をロードして初期化する。\n * モジュールスコープで 1 回だけ呼び、返り値の Promise を `<Elements>` に渡す。\n */\nexport function loadHelloPay(\n publicKey: string,\n options: LoadHelloPayOptions = {},\n): Promise<HelloPay | null> {\n const sdkUrl = normalizeSdkUrl(options.sdkUrl ?? DEFAULT_SDK_URL);\n const locale = normalizeLocale(options.locale);\n const cacheKey = `${publicKey}::${locale}::${sdkUrl}`;\n const cached = sdkCache.get(cacheKey);\n if (cached) return cached;\n\n let scriptPromise = scriptPromiseCache.get(sdkUrl);\n if (!scriptPromise) {\n scriptPromise = loadScript(sdkUrl).catch((err) => {\n // 一時的なロード失敗はキャッシュせず次回呼び出しで再試行可能にする\n scriptPromiseCache.delete(sdkUrl);\n throw err;\n });\n scriptPromiseCache.set(sdkUrl, scriptPromise);\n }\n\n const sdkPromise = scriptPromise\n .then((factory) => {\n if (!factory) return null; // SSR\n return factory(publicKey, { locale: options.locale });\n })\n .catch((err) => {\n // SDK インスタンス生成失敗は sdkCache から退避して次回呼び出しで再試行可能にする\n sdkCache.delete(cacheKey);\n throw err;\n });\n sdkCache.set(cacheKey, sdkPromise);\n return sdkPromise;\n}\n","/**\n * <Elements> Provider.\n *\n * loadHelloPay() の Promise を受け取り、SDK インスタンスと Elements セッションを\n * 子孫に Context 経由で供給する。\n */\n\nimport { createContext, useEffect, useState, type ReactNode } from 'react';\nimport type { HelloPay, Elements as ElementsSession, ElementsOptions } from './types';\n\nexport interface ElementsContextValue {\n hellopay: HelloPay | null;\n elements: ElementsSession | null;\n}\n\nconst EMPTY_CONTEXT: ElementsContextValue = {\n hellopay: null,\n elements: null,\n};\n\nexport const ElementsContext = createContext<ElementsContextValue>(EMPTY_CONTEXT);\n\nexport interface ElementsProps {\n /** loadHelloPay() の戻り値。モジュールスコープで 1 回だけ生成すること */\n hellopay: Promise<HelloPay | null> | HelloPay | null;\n /** `sessionClientSecret` を渡すと、預かりカードのセッションで要る欄だけを出す */\n options?: ElementsOptions;\n children: ReactNode;\n}\n\nexport function Elements({ hellopay: hellopayProp, options, children }: ElementsProps) {\n const sessionClientSecret = options?.sessionClientSecret;\n const [ctx, setCtx] = useState<ElementsContextValue>(EMPTY_CONTEXT);\n\n useEffect(() => {\n let cancelled = false;\n setCtx(EMPTY_CONTEXT);\n\n Promise.resolve(hellopayProp)\n .then((sdk) => {\n if (cancelled) return;\n if (!sdk) {\n setCtx(EMPTY_CONTEXT);\n return;\n }\n setCtx({\n hellopay: sdk,\n elements: sdk.elements(sessionClientSecret ? { sessionClientSecret } : undefined),\n });\n })\n .catch(() => {\n // SDK ロード失敗時は null のまま(unhandled rejection を防ぐ)\n if (cancelled) return;\n setCtx(EMPTY_CONTEXT);\n });\n\n return () => {\n cancelled = true;\n };\n }, [hellopayProp, sessionClientSecret]);\n\n return <ElementsContext.Provider value={ctx}>{children}</ElementsContext.Provider>;\n}\n","/**\n * Element コンポーネント。\n *\n * 各コンポーネントは 1 つの `<div>` コンテナを描画するだけで、\n * 実体(カード情報が入る iframe)はコア SDK が差し込む。\n *\n * React Strict Mode の二重 mount 対応:\n * - effect の cleanup で element.unmount() を必ず呼ぶ\n * - unmount 後は Elements._elements 配列から除外される(コア SDK 側で対応済)\n * - 結果として Strict Mode で effect が再実行されても古い iframe は残らない\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useElements } from './hooks';\nimport type {\n ElementType,\n ElementOptions,\n ElementChangeEvent,\n ElementFocusEvent,\n ElementReadyEvent,\n} from './types';\n\nexport interface ElementProps {\n options?: ElementOptions;\n className?: string;\n style?: CSSProperties;\n onReady?: (e: ElementReadyEvent) => void;\n onChange?: (e: ElementChangeEvent) => void;\n onFocus?: (e: ElementFocusEvent) => void;\n onBlur?: (e: ElementFocusEvent) => void;\n}\n\nconst PROBE_PX = 100000;\n\n/**\n * コンテナの幅・高さのうち、中身に追従する(加盟店が寸法を決めていない)軸を返す。\n */\nfunction contentSizedAxes(container: HTMLElement) {\n // display: none の祖先の中ではレイアウトが無いので、computed value で見る。\n if (container.getClientRects().length === 0) {\n const computed = getComputedStyle(container);\n const isAuto = (v: string) => v === '' || v === 'auto';\n return { width: isAuto(computed.width), height: isAuto(computed.height) };\n }\n // computed の height で判定すると、border-box の padding・border や min-height で\n // 0 にならず見誤るので、大きな子を一時的に入れて寸法が伸びるかで確かめる。\n // 祖先の transform(モーダルの scale のアニメーションなど)に左右されないよう、\n // getBoundingClientRect ではなくレイアウト上の寸法の offset* で比べる。\n const before = { width: container.offsetWidth, height: container.offsetHeight };\n const probe = container.ownerDocument.createElement('div');\n probe.style.cssText = `width: ${PROBE_PX}px; height: ${PROBE_PX}px;`;\n container.appendChild(probe);\n const grows = {\n width: container.offsetWidth > before.width,\n height: container.offsetHeight > before.height,\n };\n probe.remove();\n return grows;\n}\n\n/**\n * 指定 type の Element を管理する React コンポーネントを生成する。\n */\nfunction createElementComponent(type: ElementType) {\n function ElementComponent({\n options,\n className,\n style,\n onReady,\n onChange,\n onFocus,\n onBlur,\n }: ElementProps) {\n const elements = useElements();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [fill, setFill] = useState({ width: false, height: false });\n\n // 最新のハンドラを ref で保持(effect を毎回 re-run させないため)\n const handlersRef = useRef({ onReady, onChange, onFocus, onBlur });\n handlersRef.current = { onReady, onChange, onFocus, onBlur };\n\n useEffect(() => {\n const container = containerRef.current;\n if (!elements || !container) return;\n\n // 100% を当てた後に測り直すと親の寸法に追従して見えるので、立てた軸は戻さない。\n const unset = contentSizedAxes(container);\n setFill((prev) => ({\n width: prev.width || unset.width,\n height: prev.height || unset.height,\n }));\n\n const element = elements.create(type, options);\n element.mount(container);\n\n const unsubs = [\n element.on('ready', (e) => handlersRef.current.onReady?.(e)),\n element.on('change', (e) => handlersRef.current.onChange?.(e)),\n element.on('focus', (e) => handlersRef.current.onFocus?.(e)),\n element.on('blur', (e) => handlersRef.current.onBlur?.(e)),\n ];\n\n return () => {\n unsubs.forEach((u) => u());\n element.unmount();\n };\n // options はマウント時にしか反映しない方針(Stripe と同じ挙動)。\n // 動的に style を変えたい場合は後続 PR で element.update() を追加。\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [elements]);\n\n // インラインの既定値は className の寸法に勝つので、加盟店が決めていない軸だけに付ける。\n // 判定は mount 時の 1 回だけなので、後から寸法を変えるなら style で渡す。\n return (\n <div\n ref={containerRef}\n className={className}\n style={{\n ...(fill.width && { width: '100%' }),\n ...(fill.height && { height: '100%' }),\n ...style,\n }}\n />\n );\n }\n ElementComponent.displayName = `HelloPay(${type})`;\n // getElement(CardNumberElement) のようにコンポーネント自身を型指定子として使えるよう、\n // 静的プロパティに type を生やしておく\n ElementComponent.__elementType = type as ElementType;\n return ElementComponent;\n}\n\nexport const CardNumberElement = createElementComponent('cardNumber');\nexport const CardExpiryElement = createElementComponent('cardExpiry');\nexport const CardCvcElement = createElementComponent('cardCvc');\nexport const CardholderNameElement = createElementComponent('cardholderName');\n// 韓国発行カードの Toss 登録に必要な暗証番号の先頭 2 桁。表示・非表示は\n// 発行国の判定結果に応じて呼び出し側が mount / unmount で制御する。\nexport const CardPasswordElement = createElementComponent('cardPassword');\n\nexport type ElementComponent = typeof CardNumberElement;\n","/**\n * React hooks.\n *\n * useHelloPay / useElements は <Elements> Provider の Context から\n * SDK インスタンスと Elements セッションを取り出す。\n * SDK ロード完了までは null を返すので、ハンドラ内で null チェックする。\n */\n\nimport { useContext } from 'react';\nimport { ElementsContext } from './Elements';\nimport type { HelloPay, Elements } from './types';\n\nexport function useHelloPay(): HelloPay | null {\n return useContext(ElementsContext).hellopay;\n}\n\nexport function useElements(): Elements | null {\n return useContext(ElementsContext).elements;\n}\n","/**\n * Apple Pay ボタン。\n *\n * `useHelloPay()` から SDK を取り、対応端末(Safari + Apple Pay 利用可能)でのみ\n * Apple 公式スタイルのボタンを描画する。非対応端末では何も描画しない。\n *\n * click で `hellopay.applePay()` を同期呼び出しし(`new ApplePaySession` の\n * user gesture 要件のため)、結果を `onToken` / `onError` / `onCancel` に振り分ける。\n * SDK は Apple Pay トークンを返すだけで課金はしないので、加盟店は `onToken` で\n * 受けたトークンを自社バックエンドから決済 API に送って課金する。\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useHelloPay } from './hooks';\nimport type { ApplePayCard, ApplePayOptions, HelloPayError } from './types';\n\nexport interface ApplePayButtonProps {\n options: ApplePayOptions;\n /** トークン取得成功時。トークンを自社バックエンド経由で決済 API に送る。 */\n onToken: (token: string, card: ApplePayCard) => void;\n /** validation / network エラー時。 */\n onError?: (error: HelloPayError) => void;\n /** ユーザーが Apple Pay シートを閉じた時。 */\n onCancel?: () => void;\n /** Apple Pay ボタンの色。既定 `black`。 */\n buttonStyle?: 'black' | 'white' | 'white-outline';\n /** Apple Pay ボタンの種別(`plain` / `buy` / `pay` 等)。既定 `plain`。 */\n buttonType?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function ApplePayButton({\n options,\n onToken,\n onError,\n onCancel,\n buttonStyle = 'black',\n buttonType = 'plain',\n className,\n style,\n}: ApplePayButtonProps) {\n const hellopay = useHelloPay();\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const [supported, setSupported] = useState(false);\n\n // canMakeApplePayPayments は ApplePaySession 依存で client-only のため effect で判定。\n useEffect(() => {\n setSupported(!!hellopay && hellopay.canMakeApplePayPayments());\n }, [hellopay]);\n\n // Apple Pay ボタンの見た目はベンダー CSS プロパティで指定する。React の style 型に\n // 無いため ref 経由で setProperty する。\n useEffect(() => {\n const el = buttonRef.current;\n if (!el) return;\n el.style.setProperty('-webkit-appearance', '-apple-pay-button');\n el.style.setProperty('-apple-pay-button-type', buttonType);\n el.style.setProperty('-apple-pay-button-style', buttonStyle);\n }, [supported, buttonType, buttonStyle]);\n\n // 最新のハンドラ / options を ref に保持し、click ハンドラを毎回作り直さない。\n const latest = useRef({ options, onToken, onError, onCancel, hellopay });\n latest.current = { options, onToken, onError, onCancel, hellopay };\n\n if (!supported) return null;\n\n const handleClick = () => {\n const current = latest.current;\n if (!current.hellopay) return;\n // user gesture 要件のため click ハンドラから同期呼び出しする。\n current.hellopay\n .applePay(current.options)\n .then((result) => {\n if (result.error) {\n if (result.error.type === 'cancel') {\n current.onCancel?.();\n } else {\n current.onError?.(result.error);\n }\n return;\n }\n current.onToken(result.token, result.card);\n })\n .catch((err: unknown) => {\n current.onError?.({\n type: 'config_error',\n code: 'apple_pay_error',\n message: err instanceof Error ? err.message : 'Apple Pay error',\n });\n });\n };\n\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleClick}\n className={className}\n style={{ width: '100%', height: '44px', cursor: 'pointer', ...style }}\n />\n );\n}\n\nApplePayButton.displayName = 'HelloPay(ApplePayButton)';\n"],"mappings":"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","names":["script","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
package/dist/index.d.cts CHANGED
@@ -36,10 +36,9 @@ interface ElementOptions {
36
36
  * `pending` はフォームを組み替えずに現状の表示を維持し、`unknown` は
37
37
  * どの発行国グループにも該当しないもの(`default`)として組み替える。
38
38
  *
39
- * 現在 `determined` になるのは韓国の国内専用カード(先頭 4 桁 `9410`)のみ。
40
- * それ以外の発行国と、韓国発行の国際ブランドカードは `unknown` を返す。
41
- * 誤検知を避けるため確実に判定できる範囲だけに絞っており、対応範囲は
42
- * 今後 `country` を増やす形で広げる。
39
+ * カード番号の先頭 8 桁が揃うと HelloPay に問い合わせ、KSNET の国内カード
40
+ * BIN 一覧にあれば `determined`(`country: 'KR'`)、無ければ `unknown` になる。
41
+ * 8 桁未満の間と問い合わせ中は `pending`、問い合わせに失敗したら `unknown`。
43
42
  */
44
43
  type IssuerCountryResult = {
45
44
  status: 'pending';
@@ -53,6 +52,10 @@ interface CardNumberChangeEvent {
53
52
  elementType: 'cardNumber';
54
53
  empty: boolean;
55
54
  complete: boolean;
55
+ /**
56
+ * `'unionpay'` はこのイベントにだけ現れる。トークン化結果 (`TokenCard.brand`) は
57
+ * acquirer 側の見え方を返すので、同じカードで別の値になりうる。
58
+ */
56
59
  brand?: string | null;
57
60
  issuerCountry: IssuerCountryResult;
58
61
  }
@@ -73,6 +76,18 @@ interface ElementFocusEvent {
73
76
  }
74
77
  interface ElementReadyEvent {
75
78
  elementType: ElementType;
79
+ /**
80
+ * 預かりカードの登録セッションで、この欄を出さないとき true。SDK は iframe を隠すので、
81
+ * 加盟店は見出しなど周りの要素を隠す。
82
+ */
83
+ hidden: boolean;
84
+ }
85
+ interface ElementsOptions {
86
+ /**
87
+ * 登録セッションの `client_secret`。預かりカードのセッションなら、カード番号と有効期限の
88
+ * 欄を出さず、CVC か暗証番号の欄だけを出す。
89
+ */
90
+ sessionClientSecret?: string;
76
91
  }
77
92
  type ElementEventMap = {
78
93
  ready: ElementReadyEvent;
@@ -189,6 +204,12 @@ interface CardRegistrationError extends HelloPayError {
189
204
  * (該当なしは `'default'`)。呼び出し側はこれを使って入力フォームを組み替える。
190
205
  */
191
206
  issuerCountryGroup?: string;
207
+ /**
208
+ * `card_brand_mismatch` のときだけ入る、判定したカードブランド (`visa` / `unionpay` など)。
209
+ * ブランドを判別できないカード (`9410` 始まり) では入らない。呼び出し側はこのブランドで
210
+ * 登録セッションを作り直す。
211
+ */
212
+ cardBrand?: string;
192
213
  }
193
214
  /**
194
215
  * Apple Pay で決済したカードのメタデータ。Apple Pay は client 側で last4 /
@@ -244,7 +265,7 @@ type ApplePayResult = {
244
265
  error: ApplePayError;
245
266
  };
246
267
  interface HelloPay {
247
- elements(): Elements$1;
268
+ elements(options?: ElementsOptions): Elements$1;
248
269
  createToken(cardNumberElement: Element): Promise<CreateTokenResult>;
249
270
  /**
250
271
  * 登録セッション経路 (#2747)。`sessionClientSecret` を渡すと、加盟店バックエンドが
@@ -301,9 +322,11 @@ declare function loadHelloPay(publicKey: string, options?: LoadHelloPayOptions):
301
322
  interface ElementsProps {
302
323
  /** loadHelloPay() の戻り値。モジュールスコープで 1 回だけ生成すること */
303
324
  hellopay: Promise<HelloPay | null> | HelloPay | null;
325
+ /** `sessionClientSecret` を渡すと、預かりカードのセッションで要る欄だけを出す */
326
+ options?: ElementsOptions;
304
327
  children: ReactNode;
305
328
  }
306
- declare function Elements({ hellopay: hellopayProp, children }: ElementsProps): react_jsx_runtime.JSX.Element;
329
+ declare function Elements({ hellopay: hellopayProp, options, children }: ElementsProps): react_jsx_runtime.JSX.Element;
307
330
 
308
331
  interface ElementProps {
309
332
  options?: ElementOptions;
@@ -371,4 +394,4 @@ declare namespace ApplePayButton {
371
394
  declare function useHelloPay(): HelloPay | null;
372
395
  declare function useElements(): Elements$1 | null;
373
396
 
374
- export { ApplePayButton, type ApplePayButtonProps, type ApplePayCancelError, type ApplePayCard, type ApplePayError, type ApplePayOptions, type ApplePayResult, CardCvcElement, CardExpiryElement, type CardNumberChangeEvent, CardNumberElement, CardPasswordElement, CardholderNameElement, type CreateTokenResult, type Element, type ElementChangeEvent, type ElementFocusEvent, type ElementOptions, type ElementProps, type ElementReadyEvent, type ElementStyle, type ElementType, Elements, type ElementsProps, type Elements$1 as ElementsSession, type HelloPay, type HelloPayError, type IssuerCountryResult, type LoadHelloPayOptions, type OtherElementChangeEvent, type TokenCard, type TokenProvider, type Unsubscribe, loadHelloPay, useElements, useHelloPay };
397
+ export { ApplePayButton, type ApplePayButtonProps, type ApplePayCancelError, type ApplePayCard, type ApplePayError, type ApplePayOptions, type ApplePayResult, CardCvcElement, CardExpiryElement, type CardNumberChangeEvent, CardNumberElement, CardPasswordElement, CardholderNameElement, type CreateTokenResult, type Element, type ElementChangeEvent, type ElementFocusEvent, type ElementOptions, type ElementProps, type ElementReadyEvent, type ElementStyle, type ElementType, Elements, type ElementsOptions, type ElementsProps, type Elements$1 as ElementsSession, type HelloPay, type HelloPayError, type IssuerCountryResult, type LoadHelloPayOptions, type OtherElementChangeEvent, type TokenCard, type TokenProvider, type Unsubscribe, loadHelloPay, useElements, useHelloPay };
package/dist/index.d.ts CHANGED
@@ -36,10 +36,9 @@ interface ElementOptions {
36
36
  * `pending` はフォームを組み替えずに現状の表示を維持し、`unknown` は
37
37
  * どの発行国グループにも該当しないもの(`default`)として組み替える。
38
38
  *
39
- * 現在 `determined` になるのは韓国の国内専用カード(先頭 4 桁 `9410`)のみ。
40
- * それ以外の発行国と、韓国発行の国際ブランドカードは `unknown` を返す。
41
- * 誤検知を避けるため確実に判定できる範囲だけに絞っており、対応範囲は
42
- * 今後 `country` を増やす形で広げる。
39
+ * カード番号の先頭 8 桁が揃うと HelloPay に問い合わせ、KSNET の国内カード
40
+ * BIN 一覧にあれば `determined`(`country: 'KR'`)、無ければ `unknown` になる。
41
+ * 8 桁未満の間と問い合わせ中は `pending`、問い合わせに失敗したら `unknown`。
43
42
  */
44
43
  type IssuerCountryResult = {
45
44
  status: 'pending';
@@ -53,6 +52,10 @@ interface CardNumberChangeEvent {
53
52
  elementType: 'cardNumber';
54
53
  empty: boolean;
55
54
  complete: boolean;
55
+ /**
56
+ * `'unionpay'` はこのイベントにだけ現れる。トークン化結果 (`TokenCard.brand`) は
57
+ * acquirer 側の見え方を返すので、同じカードで別の値になりうる。
58
+ */
56
59
  brand?: string | null;
57
60
  issuerCountry: IssuerCountryResult;
58
61
  }
@@ -73,6 +76,18 @@ interface ElementFocusEvent {
73
76
  }
74
77
  interface ElementReadyEvent {
75
78
  elementType: ElementType;
79
+ /**
80
+ * 預かりカードの登録セッションで、この欄を出さないとき true。SDK は iframe を隠すので、
81
+ * 加盟店は見出しなど周りの要素を隠す。
82
+ */
83
+ hidden: boolean;
84
+ }
85
+ interface ElementsOptions {
86
+ /**
87
+ * 登録セッションの `client_secret`。預かりカードのセッションなら、カード番号と有効期限の
88
+ * 欄を出さず、CVC か暗証番号の欄だけを出す。
89
+ */
90
+ sessionClientSecret?: string;
76
91
  }
77
92
  type ElementEventMap = {
78
93
  ready: ElementReadyEvent;
@@ -189,6 +204,12 @@ interface CardRegistrationError extends HelloPayError {
189
204
  * (該当なしは `'default'`)。呼び出し側はこれを使って入力フォームを組み替える。
190
205
  */
191
206
  issuerCountryGroup?: string;
207
+ /**
208
+ * `card_brand_mismatch` のときだけ入る、判定したカードブランド (`visa` / `unionpay` など)。
209
+ * ブランドを判別できないカード (`9410` 始まり) では入らない。呼び出し側はこのブランドで
210
+ * 登録セッションを作り直す。
211
+ */
212
+ cardBrand?: string;
192
213
  }
193
214
  /**
194
215
  * Apple Pay で決済したカードのメタデータ。Apple Pay は client 側で last4 /
@@ -244,7 +265,7 @@ type ApplePayResult = {
244
265
  error: ApplePayError;
245
266
  };
246
267
  interface HelloPay {
247
- elements(): Elements$1;
268
+ elements(options?: ElementsOptions): Elements$1;
248
269
  createToken(cardNumberElement: Element): Promise<CreateTokenResult>;
249
270
  /**
250
271
  * 登録セッション経路 (#2747)。`sessionClientSecret` を渡すと、加盟店バックエンドが
@@ -301,9 +322,11 @@ declare function loadHelloPay(publicKey: string, options?: LoadHelloPayOptions):
301
322
  interface ElementsProps {
302
323
  /** loadHelloPay() の戻り値。モジュールスコープで 1 回だけ生成すること */
303
324
  hellopay: Promise<HelloPay | null> | HelloPay | null;
325
+ /** `sessionClientSecret` を渡すと、預かりカードのセッションで要る欄だけを出す */
326
+ options?: ElementsOptions;
304
327
  children: ReactNode;
305
328
  }
306
- declare function Elements({ hellopay: hellopayProp, children }: ElementsProps): react_jsx_runtime.JSX.Element;
329
+ declare function Elements({ hellopay: hellopayProp, options, children }: ElementsProps): react_jsx_runtime.JSX.Element;
307
330
 
308
331
  interface ElementProps {
309
332
  options?: ElementOptions;
@@ -371,4 +394,4 @@ declare namespace ApplePayButton {
371
394
  declare function useHelloPay(): HelloPay | null;
372
395
  declare function useElements(): Elements$1 | null;
373
396
 
374
- export { ApplePayButton, type ApplePayButtonProps, type ApplePayCancelError, type ApplePayCard, type ApplePayError, type ApplePayOptions, type ApplePayResult, CardCvcElement, CardExpiryElement, type CardNumberChangeEvent, CardNumberElement, CardPasswordElement, CardholderNameElement, type CreateTokenResult, type Element, type ElementChangeEvent, type ElementFocusEvent, type ElementOptions, type ElementProps, type ElementReadyEvent, type ElementStyle, type ElementType, Elements, type ElementsProps, type Elements$1 as ElementsSession, type HelloPay, type HelloPayError, type IssuerCountryResult, type LoadHelloPayOptions, type OtherElementChangeEvent, type TokenCard, type TokenProvider, type Unsubscribe, loadHelloPay, useElements, useHelloPay };
397
+ export { ApplePayButton, type ApplePayButtonProps, type ApplePayCancelError, type ApplePayCard, type ApplePayError, type ApplePayOptions, type ApplePayResult, CardCvcElement, CardExpiryElement, type CardNumberChangeEvent, CardNumberElement, CardPasswordElement, CardholderNameElement, type CreateTokenResult, type Element, type ElementChangeEvent, type ElementFocusEvent, type ElementOptions, type ElementProps, type ElementReadyEvent, type ElementStyle, type ElementType, Elements, type ElementsOptions, type ElementsProps, type Elements$1 as ElementsSession, type HelloPay, type HelloPayError, type IssuerCountryResult, type LoadHelloPayOptions, type OtherElementChangeEvent, type TokenCard, type TokenProvider, type Unsubscribe, loadHelloPay, useElements, useHelloPay };
package/dist/index.js CHANGED
@@ -111,7 +111,8 @@ var EMPTY_CONTEXT = {
111
111
  elements: null
112
112
  };
113
113
  var ElementsContext = createContext(EMPTY_CONTEXT);
114
- function Elements({ hellopay: hellopayProp, children }) {
114
+ function Elements({ hellopay: hellopayProp, options, children }) {
115
+ const sessionClientSecret = options?.sessionClientSecret;
115
116
  const [ctx, setCtx] = useState(EMPTY_CONTEXT);
116
117
  useEffect(() => {
117
118
  let cancelled = false;
@@ -122,7 +123,10 @@ function Elements({ hellopay: hellopayProp, children }) {
122
123
  setCtx(EMPTY_CONTEXT);
123
124
  return;
124
125
  }
125
- setCtx({ hellopay: sdk, elements: sdk.elements() });
126
+ setCtx({
127
+ hellopay: sdk,
128
+ elements: sdk.elements(sessionClientSecret ? { sessionClientSecret } : void 0)
129
+ });
126
130
  }).catch(() => {
127
131
  if (cancelled) return;
128
132
  setCtx(EMPTY_CONTEXT);
@@ -130,7 +134,7 @@ function Elements({ hellopay: hellopayProp, children }) {
130
134
  return () => {
131
135
  cancelled = true;
132
136
  };
133
- }, [hellopayProp]);
137
+ }, [hellopayProp, sessionClientSecret]);
134
138
  return /* @__PURE__ */ jsx(ElementsContext.Provider, { value: ctx, children });
135
139
  }
136
140
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/loadHelloPay.ts","../src/Elements.tsx","../src/ElementComponents.tsx","../src/hooks.ts","../src/ApplePayButton.tsx"],"sourcesContent":["/**\n * HelloPay SDK ローダー。\n *\n * HelloPay 管理下のドメイン(js.hello-pay.app 等)から SDK を動的ロードし、\n * `window.HelloPay` ファクトリを解決する。\n *\n * - 同一 sdkUrl への呼び出しは script tag を 1 回だけ挿入(dedup)\n * - 異なる sdkUrl は独立したロードを維持(E2E / ローカル切り替え対応)\n * - SSR 環境では Promise<null> を解決(加盟店側で null チェック)\n * - 一時的な失敗はキャッシュせず次回呼び出しで再試行可能\n */\n\nimport type { HelloPay, HelloPayFactory } from './types';\n\n// SDK 本体は test / live どちらの publishable key でも同一ドメイン\n// (js.hello-pay.app) から配信する。test / live mode の切り替えは SDK 内部で\n// publishable key の prefix から解決し、test mode では接続先を test 環境\n// (*.stg.hello-pay.app) に向ける(hellopay.js と同じ方式)。\nconst DEFAULT_SDK_URL = 'https://js.hello-pay.app/v1/hellopay-elements.js';\n\n// sdkUrl 単位で script ロード Promise をキャッシュ。\n// loadPromise を単一変数にするとすべての URL で共有されてしまい、\n// 異なる sdkUrl(E2E / ローカル開発)が誤って同一ロードを共有する。\nconst scriptPromiseCache = new Map<string, Promise<HelloPayFactory | null>>();\n\n// publicKey + locale + sdkUrl の組み合わせごとに `HelloPaySDK` インスタンスをキャッシュ。\n// 加盟店が誤って inline で loadHelloPay を呼び出した場合でも同一 SDK インスタンスが\n// 返るようにして、Elements セッションの BroadcastChannel session ID ミスマッチを防ぐ。\nconst sdkCache = new Map<string, Promise<HelloPay | null>>();\n\n/** テスト専用: module-scope のキャッシュをすべて初期状態に戻す。 */\nexport function __resetLoadPromiseForTest(): void {\n scriptPromiseCache.clear();\n sdkCache.clear();\n}\n\nfunction normalizeSdkUrl(url: string): string {\n if (typeof window === 'undefined') return url;\n\n try {\n return new URL(url, window.location.href).href;\n } catch {\n return url;\n }\n}\n\nfunction normalizeLocale(locale?: string): string {\n return locale || 'ja';\n}\n\nfunction loadScript(url: string): Promise<HelloPayFactory | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n\n // URL を正規化してプロトコル省略形などを統一する。\n // テスト / SSR 環境では window.location が http URL でない場合があるため try-catch で保護。\n const normalizedUrl = normalizeSdkUrl(url);\n\n return new Promise((resolve, reject) => {\n // script は URL 単位で管理する。異なる URL の script を削除せず共存させることで、\n // E2E / ローカル開発で異なる sdkUrl が並列で呼ばれても Promise が宙吊りにならない。\n // 状態は dataset.hellopayState に \"loading\" | \"loaded\" | \"error\" で刻む。\n const managedScripts = Array.from(\n document.querySelectorAll<HTMLScriptElement>('script[data-hellopay-sdk]'),\n );\n\n const existing = managedScripts.find((script) => {\n const rawUrl = script.dataset.hellopayUrl || script.src;\n if (!rawUrl) return false;\n try {\n return new URL(rawUrl, window.location.href).href === normalizedUrl;\n } catch {\n return rawUrl === normalizedUrl;\n }\n });\n\n if (existing) {\n const state = existing.dataset.hellopayState;\n if (state === 'loaded') {\n resolve(window.HelloPay ?? null);\n return;\n }\n if (state === 'loading') {\n existing.addEventListener('load', () => resolve(window.HelloPay ?? null), {\n once: true,\n });\n existing.addEventListener(\n 'error',\n () => reject(new Error('HelloPay SDK failed to load')),\n { once: true },\n );\n return;\n }\n // state === \"error\" or undefined: 失敗済み or 未知の状態なので作り直す\n existing.remove();\n }\n\n const script = document.createElement('script');\n script.src = normalizedUrl;\n script.async = true;\n script.dataset.hellopaySdk = 'true';\n script.dataset.hellopayUrl = normalizedUrl; // URL 比較用\n script.dataset.hellopayState = 'loading';\n script.addEventListener(\n 'load',\n () => {\n if (!window.HelloPay) {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK loaded but window.HelloPay is missing'));\n return;\n }\n script.dataset.hellopayState = 'loaded';\n resolve(window.HelloPay);\n },\n { once: true },\n );\n script.addEventListener(\n 'error',\n () => {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK failed to load'));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n}\n\nexport interface LoadHelloPayOptions {\n /** SDK 配信 URL(ローカル開発・E2E で差し替える用。省略時は js.hello-pay.app から配信し、test/live は SDK 内部で key prefix から解決) */\n sdkUrl?: string;\n locale?: string;\n}\n\n/**\n * HelloPay SDK をロードして初期化する。\n * モジュールスコープで 1 回だけ呼び、返り値の Promise を `<Elements>` に渡す。\n */\nexport function loadHelloPay(\n publicKey: string,\n options: LoadHelloPayOptions = {},\n): Promise<HelloPay | null> {\n const sdkUrl = normalizeSdkUrl(options.sdkUrl ?? DEFAULT_SDK_URL);\n const locale = normalizeLocale(options.locale);\n const cacheKey = `${publicKey}::${locale}::${sdkUrl}`;\n const cached = sdkCache.get(cacheKey);\n if (cached) return cached;\n\n let scriptPromise = scriptPromiseCache.get(sdkUrl);\n if (!scriptPromise) {\n scriptPromise = loadScript(sdkUrl).catch((err) => {\n // 一時的なロード失敗はキャッシュせず次回呼び出しで再試行可能にする\n scriptPromiseCache.delete(sdkUrl);\n throw err;\n });\n scriptPromiseCache.set(sdkUrl, scriptPromise);\n }\n\n const sdkPromise = scriptPromise\n .then((factory) => {\n if (!factory) return null; // SSR\n return factory(publicKey, { locale: options.locale });\n })\n .catch((err) => {\n // SDK インスタンス生成失敗は sdkCache から退避して次回呼び出しで再試行可能にする\n sdkCache.delete(cacheKey);\n throw err;\n });\n sdkCache.set(cacheKey, sdkPromise);\n return sdkPromise;\n}\n","/**\n * <Elements> Provider.\n *\n * loadHelloPay() の Promise を受け取り、SDK インスタンスと Elements セッションを\n * 子孫に Context 経由で供給する。\n */\n\nimport { createContext, useEffect, useState, type ReactNode } from 'react';\nimport type { HelloPay, Elements as ElementsSession } from './types';\n\nexport interface ElementsContextValue {\n hellopay: HelloPay | null;\n elements: ElementsSession | null;\n}\n\nconst EMPTY_CONTEXT: ElementsContextValue = {\n hellopay: null,\n elements: null,\n};\n\nexport const ElementsContext = createContext<ElementsContextValue>(EMPTY_CONTEXT);\n\nexport interface ElementsProps {\n /** loadHelloPay() の戻り値。モジュールスコープで 1 回だけ生成すること */\n hellopay: Promise<HelloPay | null> | HelloPay | null;\n children: ReactNode;\n}\n\nexport function Elements({ hellopay: hellopayProp, children }: ElementsProps) {\n const [ctx, setCtx] = useState<ElementsContextValue>(EMPTY_CONTEXT);\n\n useEffect(() => {\n let cancelled = false;\n setCtx(EMPTY_CONTEXT);\n\n Promise.resolve(hellopayProp)\n .then((sdk) => {\n if (cancelled) return;\n if (!sdk) {\n setCtx(EMPTY_CONTEXT);\n return;\n }\n setCtx({ hellopay: sdk, elements: sdk.elements() });\n })\n .catch(() => {\n // SDK ロード失敗時は null のまま(unhandled rejection を防ぐ)\n if (cancelled) return;\n setCtx(EMPTY_CONTEXT);\n });\n\n return () => {\n cancelled = true;\n };\n }, [hellopayProp]);\n\n return <ElementsContext.Provider value={ctx}>{children}</ElementsContext.Provider>;\n}\n","/**\n * Element コンポーネント。\n *\n * 各コンポーネントは 1 つの `<div>` コンテナを描画するだけで、\n * 実体(カード情報が入る iframe)はコア SDK が差し込む。\n *\n * React Strict Mode の二重 mount 対応:\n * - effect の cleanup で element.unmount() を必ず呼ぶ\n * - unmount 後は Elements._elements 配列から除外される(コア SDK 側で対応済)\n * - 結果として Strict Mode で effect が再実行されても古い iframe は残らない\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useElements } from './hooks';\nimport type {\n ElementType,\n ElementOptions,\n ElementChangeEvent,\n ElementFocusEvent,\n ElementReadyEvent,\n} from './types';\n\nexport interface ElementProps {\n options?: ElementOptions;\n className?: string;\n style?: CSSProperties;\n onReady?: (e: ElementReadyEvent) => void;\n onChange?: (e: ElementChangeEvent) => void;\n onFocus?: (e: ElementFocusEvent) => void;\n onBlur?: (e: ElementFocusEvent) => void;\n}\n\nconst PROBE_PX = 100000;\n\n/**\n * コンテナの幅・高さのうち、中身に追従する(加盟店が寸法を決めていない)軸を返す。\n */\nfunction contentSizedAxes(container: HTMLElement) {\n // display: none の祖先の中ではレイアウトが無いので、computed value で見る。\n if (container.getClientRects().length === 0) {\n const computed = getComputedStyle(container);\n const isAuto = (v: string) => v === '' || v === 'auto';\n return { width: isAuto(computed.width), height: isAuto(computed.height) };\n }\n // computed の height で判定すると、border-box の padding・border や min-height で\n // 0 にならず見誤るので、大きな子を一時的に入れて寸法が伸びるかで確かめる。\n // 祖先の transform(モーダルの scale のアニメーションなど)に左右されないよう、\n // getBoundingClientRect ではなくレイアウト上の寸法の offset* で比べる。\n const before = { width: container.offsetWidth, height: container.offsetHeight };\n const probe = container.ownerDocument.createElement('div');\n probe.style.cssText = `width: ${PROBE_PX}px; height: ${PROBE_PX}px;`;\n container.appendChild(probe);\n const grows = {\n width: container.offsetWidth > before.width,\n height: container.offsetHeight > before.height,\n };\n probe.remove();\n return grows;\n}\n\n/**\n * 指定 type の Element を管理する React コンポーネントを生成する。\n */\nfunction createElementComponent(type: ElementType) {\n function ElementComponent({\n options,\n className,\n style,\n onReady,\n onChange,\n onFocus,\n onBlur,\n }: ElementProps) {\n const elements = useElements();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [fill, setFill] = useState({ width: false, height: false });\n\n // 最新のハンドラを ref で保持(effect を毎回 re-run させないため)\n const handlersRef = useRef({ onReady, onChange, onFocus, onBlur });\n handlersRef.current = { onReady, onChange, onFocus, onBlur };\n\n useEffect(() => {\n const container = containerRef.current;\n if (!elements || !container) return;\n\n // 100% を当てた後に測り直すと親の寸法に追従して見えるので、立てた軸は戻さない。\n const unset = contentSizedAxes(container);\n setFill((prev) => ({\n width: prev.width || unset.width,\n height: prev.height || unset.height,\n }));\n\n const element = elements.create(type, options);\n element.mount(container);\n\n const unsubs = [\n element.on('ready', (e) => handlersRef.current.onReady?.(e)),\n element.on('change', (e) => handlersRef.current.onChange?.(e)),\n element.on('focus', (e) => handlersRef.current.onFocus?.(e)),\n element.on('blur', (e) => handlersRef.current.onBlur?.(e)),\n ];\n\n return () => {\n unsubs.forEach((u) => u());\n element.unmount();\n };\n // options はマウント時にしか反映しない方針(Stripe と同じ挙動)。\n // 動的に style を変えたい場合は後続 PR で element.update() を追加。\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [elements]);\n\n // インラインの既定値は className の寸法に勝つので、加盟店が決めていない軸だけに付ける。\n // 判定は mount 時の 1 回だけなので、後から寸法を変えるなら style で渡す。\n return (\n <div\n ref={containerRef}\n className={className}\n style={{\n ...(fill.width && { width: '100%' }),\n ...(fill.height && { height: '100%' }),\n ...style,\n }}\n />\n );\n }\n ElementComponent.displayName = `HelloPay(${type})`;\n // getElement(CardNumberElement) のようにコンポーネント自身を型指定子として使えるよう、\n // 静的プロパティに type を生やしておく\n ElementComponent.__elementType = type as ElementType;\n return ElementComponent;\n}\n\nexport const CardNumberElement = createElementComponent('cardNumber');\nexport const CardExpiryElement = createElementComponent('cardExpiry');\nexport const CardCvcElement = createElementComponent('cardCvc');\nexport const CardholderNameElement = createElementComponent('cardholderName');\n// 韓国発行カードの Toss 登録に必要な暗証番号の先頭 2 桁。表示・非表示は\n// 発行国の判定結果に応じて呼び出し側が mount / unmount で制御する。\nexport const CardPasswordElement = createElementComponent('cardPassword');\n\nexport type ElementComponent = typeof CardNumberElement;\n","/**\n * React hooks.\n *\n * useHelloPay / useElements は <Elements> Provider の Context から\n * SDK インスタンスと Elements セッションを取り出す。\n * SDK ロード完了までは null を返すので、ハンドラ内で null チェックする。\n */\n\nimport { useContext } from 'react';\nimport { ElementsContext } from './Elements';\nimport type { HelloPay, Elements } from './types';\n\nexport function useHelloPay(): HelloPay | null {\n return useContext(ElementsContext).hellopay;\n}\n\nexport function useElements(): Elements | null {\n return useContext(ElementsContext).elements;\n}\n","/**\n * Apple Pay ボタン。\n *\n * `useHelloPay()` から SDK を取り、対応端末(Safari + Apple Pay 利用可能)でのみ\n * Apple 公式スタイルのボタンを描画する。非対応端末では何も描画しない。\n *\n * click で `hellopay.applePay()` を同期呼び出しし(`new ApplePaySession` の\n * user gesture 要件のため)、結果を `onToken` / `onError` / `onCancel` に振り分ける。\n * SDK は Apple Pay トークンを返すだけで課金はしないので、加盟店は `onToken` で\n * 受けたトークンを自社バックエンドから決済 API に送って課金する。\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useHelloPay } from './hooks';\nimport type { ApplePayCard, ApplePayOptions, HelloPayError } from './types';\n\nexport interface ApplePayButtonProps {\n options: ApplePayOptions;\n /** トークン取得成功時。トークンを自社バックエンド経由で決済 API に送る。 */\n onToken: (token: string, card: ApplePayCard) => void;\n /** validation / network エラー時。 */\n onError?: (error: HelloPayError) => void;\n /** ユーザーが Apple Pay シートを閉じた時。 */\n onCancel?: () => void;\n /** Apple Pay ボタンの色。既定 `black`。 */\n buttonStyle?: 'black' | 'white' | 'white-outline';\n /** Apple Pay ボタンの種別(`plain` / `buy` / `pay` 等)。既定 `plain`。 */\n buttonType?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function ApplePayButton({\n options,\n onToken,\n onError,\n onCancel,\n buttonStyle = 'black',\n buttonType = 'plain',\n className,\n style,\n}: ApplePayButtonProps) {\n const hellopay = useHelloPay();\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const [supported, setSupported] = useState(false);\n\n // canMakeApplePayPayments は ApplePaySession 依存で client-only のため effect で判定。\n useEffect(() => {\n setSupported(!!hellopay && hellopay.canMakeApplePayPayments());\n }, [hellopay]);\n\n // Apple Pay ボタンの見た目はベンダー CSS プロパティで指定する。React の style 型に\n // 無いため ref 経由で setProperty する。\n useEffect(() => {\n const el = buttonRef.current;\n if (!el) return;\n el.style.setProperty('-webkit-appearance', '-apple-pay-button');\n el.style.setProperty('-apple-pay-button-type', buttonType);\n el.style.setProperty('-apple-pay-button-style', buttonStyle);\n }, [supported, buttonType, buttonStyle]);\n\n // 最新のハンドラ / options を ref に保持し、click ハンドラを毎回作り直さない。\n const latest = useRef({ options, onToken, onError, onCancel, hellopay });\n latest.current = { options, onToken, onError, onCancel, hellopay };\n\n if (!supported) return null;\n\n const handleClick = () => {\n const current = latest.current;\n if (!current.hellopay) return;\n // user gesture 要件のため click ハンドラから同期呼び出しする。\n current.hellopay\n .applePay(current.options)\n .then((result) => {\n if (result.error) {\n if (result.error.type === 'cancel') {\n current.onCancel?.();\n } else {\n current.onError?.(result.error);\n }\n return;\n }\n current.onToken(result.token, result.card);\n })\n .catch((err: unknown) => {\n current.onError?.({\n type: 'config_error',\n code: 'apple_pay_error',\n message: err instanceof Error ? err.message : 'Apple Pay error',\n });\n });\n };\n\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleClick}\n className={className}\n style={{ width: '100%', height: '44px', cursor: 'pointer', ...style }}\n />\n );\n}\n\nApplePayButton.displayName = 'HelloPay(ApplePayButton)';\n"],"mappings":"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","names":["script","useEffect","useState","jsx","useState","useEffect","useEffect","useRef","useState","jsx","useRef","useState","useEffect"]}
1
+ {"version":3,"sources":["../src/loadHelloPay.ts","../src/Elements.tsx","../src/ElementComponents.tsx","../src/hooks.ts","../src/ApplePayButton.tsx"],"sourcesContent":["/**\n * HelloPay SDK ローダー。\n *\n * HelloPay 管理下のドメイン(js.hello-pay.app 等)から SDK を動的ロードし、\n * `window.HelloPay` ファクトリを解決する。\n *\n * - 同一 sdkUrl への呼び出しは script tag を 1 回だけ挿入(dedup)\n * - 異なる sdkUrl は独立したロードを維持(E2E / ローカル切り替え対応)\n * - SSR 環境では Promise<null> を解決(加盟店側で null チェック)\n * - 一時的な失敗はキャッシュせず次回呼び出しで再試行可能\n */\n\nimport type { HelloPay, HelloPayFactory } from './types';\n\n// SDK 本体は test / live どちらの publishable key でも同一ドメイン\n// (js.hello-pay.app) から配信する。test / live mode の切り替えは SDK 内部で\n// publishable key の prefix から解決し、test mode では接続先を test 環境\n// (*.stg.hello-pay.app) に向ける(hellopay.js と同じ方式)。\nconst DEFAULT_SDK_URL = 'https://js.hello-pay.app/v1/hellopay-elements.js';\n\n// sdkUrl 単位で script ロード Promise をキャッシュ。\n// loadPromise を単一変数にするとすべての URL で共有されてしまい、\n// 異なる sdkUrl(E2E / ローカル開発)が誤って同一ロードを共有する。\nconst scriptPromiseCache = new Map<string, Promise<HelloPayFactory | null>>();\n\n// publicKey + locale + sdkUrl の組み合わせごとに `HelloPaySDK` インスタンスをキャッシュ。\n// 加盟店が誤って inline で loadHelloPay を呼び出した場合でも同一 SDK インスタンスが\n// 返るようにして、Elements セッションの BroadcastChannel session ID ミスマッチを防ぐ。\nconst sdkCache = new Map<string, Promise<HelloPay | null>>();\n\n/** テスト専用: module-scope のキャッシュをすべて初期状態に戻す。 */\nexport function __resetLoadPromiseForTest(): void {\n scriptPromiseCache.clear();\n sdkCache.clear();\n}\n\nfunction normalizeSdkUrl(url: string): string {\n if (typeof window === 'undefined') return url;\n\n try {\n return new URL(url, window.location.href).href;\n } catch {\n return url;\n }\n}\n\nfunction normalizeLocale(locale?: string): string {\n return locale || 'ja';\n}\n\nfunction loadScript(url: string): Promise<HelloPayFactory | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n\n // URL を正規化してプロトコル省略形などを統一する。\n // テスト / SSR 環境では window.location が http URL でない場合があるため try-catch で保護。\n const normalizedUrl = normalizeSdkUrl(url);\n\n return new Promise((resolve, reject) => {\n // script は URL 単位で管理する。異なる URL の script を削除せず共存させることで、\n // E2E / ローカル開発で異なる sdkUrl が並列で呼ばれても Promise が宙吊りにならない。\n // 状態は dataset.hellopayState に \"loading\" | \"loaded\" | \"error\" で刻む。\n const managedScripts = Array.from(\n document.querySelectorAll<HTMLScriptElement>('script[data-hellopay-sdk]'),\n );\n\n const existing = managedScripts.find((script) => {\n const rawUrl = script.dataset.hellopayUrl || script.src;\n if (!rawUrl) return false;\n try {\n return new URL(rawUrl, window.location.href).href === normalizedUrl;\n } catch {\n return rawUrl === normalizedUrl;\n }\n });\n\n if (existing) {\n const state = existing.dataset.hellopayState;\n if (state === 'loaded') {\n resolve(window.HelloPay ?? null);\n return;\n }\n if (state === 'loading') {\n existing.addEventListener('load', () => resolve(window.HelloPay ?? null), {\n once: true,\n });\n existing.addEventListener(\n 'error',\n () => reject(new Error('HelloPay SDK failed to load')),\n { once: true },\n );\n return;\n }\n // state === \"error\" or undefined: 失敗済み or 未知の状態なので作り直す\n existing.remove();\n }\n\n const script = document.createElement('script');\n script.src = normalizedUrl;\n script.async = true;\n script.dataset.hellopaySdk = 'true';\n script.dataset.hellopayUrl = normalizedUrl; // URL 比較用\n script.dataset.hellopayState = 'loading';\n script.addEventListener(\n 'load',\n () => {\n if (!window.HelloPay) {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK loaded but window.HelloPay is missing'));\n return;\n }\n script.dataset.hellopayState = 'loaded';\n resolve(window.HelloPay);\n },\n { once: true },\n );\n script.addEventListener(\n 'error',\n () => {\n script.dataset.hellopayState = 'error';\n reject(new Error('HelloPay SDK failed to load'));\n },\n { once: true },\n );\n document.head.appendChild(script);\n });\n}\n\nexport interface LoadHelloPayOptions {\n /** SDK 配信 URL(ローカル開発・E2E で差し替える用。省略時は js.hello-pay.app から配信し、test/live は SDK 内部で key prefix から解決) */\n sdkUrl?: string;\n locale?: string;\n}\n\n/**\n * HelloPay SDK をロードして初期化する。\n * モジュールスコープで 1 回だけ呼び、返り値の Promise を `<Elements>` に渡す。\n */\nexport function loadHelloPay(\n publicKey: string,\n options: LoadHelloPayOptions = {},\n): Promise<HelloPay | null> {\n const sdkUrl = normalizeSdkUrl(options.sdkUrl ?? DEFAULT_SDK_URL);\n const locale = normalizeLocale(options.locale);\n const cacheKey = `${publicKey}::${locale}::${sdkUrl}`;\n const cached = sdkCache.get(cacheKey);\n if (cached) return cached;\n\n let scriptPromise = scriptPromiseCache.get(sdkUrl);\n if (!scriptPromise) {\n scriptPromise = loadScript(sdkUrl).catch((err) => {\n // 一時的なロード失敗はキャッシュせず次回呼び出しで再試行可能にする\n scriptPromiseCache.delete(sdkUrl);\n throw err;\n });\n scriptPromiseCache.set(sdkUrl, scriptPromise);\n }\n\n const sdkPromise = scriptPromise\n .then((factory) => {\n if (!factory) return null; // SSR\n return factory(publicKey, { locale: options.locale });\n })\n .catch((err) => {\n // SDK インスタンス生成失敗は sdkCache から退避して次回呼び出しで再試行可能にする\n sdkCache.delete(cacheKey);\n throw err;\n });\n sdkCache.set(cacheKey, sdkPromise);\n return sdkPromise;\n}\n","/**\n * <Elements> Provider.\n *\n * loadHelloPay() の Promise を受け取り、SDK インスタンスと Elements セッションを\n * 子孫に Context 経由で供給する。\n */\n\nimport { createContext, useEffect, useState, type ReactNode } from 'react';\nimport type { HelloPay, Elements as ElementsSession, ElementsOptions } from './types';\n\nexport interface ElementsContextValue {\n hellopay: HelloPay | null;\n elements: ElementsSession | null;\n}\n\nconst EMPTY_CONTEXT: ElementsContextValue = {\n hellopay: null,\n elements: null,\n};\n\nexport const ElementsContext = createContext<ElementsContextValue>(EMPTY_CONTEXT);\n\nexport interface ElementsProps {\n /** loadHelloPay() の戻り値。モジュールスコープで 1 回だけ生成すること */\n hellopay: Promise<HelloPay | null> | HelloPay | null;\n /** `sessionClientSecret` を渡すと、預かりカードのセッションで要る欄だけを出す */\n options?: ElementsOptions;\n children: ReactNode;\n}\n\nexport function Elements({ hellopay: hellopayProp, options, children }: ElementsProps) {\n const sessionClientSecret = options?.sessionClientSecret;\n const [ctx, setCtx] = useState<ElementsContextValue>(EMPTY_CONTEXT);\n\n useEffect(() => {\n let cancelled = false;\n setCtx(EMPTY_CONTEXT);\n\n Promise.resolve(hellopayProp)\n .then((sdk) => {\n if (cancelled) return;\n if (!sdk) {\n setCtx(EMPTY_CONTEXT);\n return;\n }\n setCtx({\n hellopay: sdk,\n elements: sdk.elements(sessionClientSecret ? { sessionClientSecret } : undefined),\n });\n })\n .catch(() => {\n // SDK ロード失敗時は null のまま(unhandled rejection を防ぐ)\n if (cancelled) return;\n setCtx(EMPTY_CONTEXT);\n });\n\n return () => {\n cancelled = true;\n };\n }, [hellopayProp, sessionClientSecret]);\n\n return <ElementsContext.Provider value={ctx}>{children}</ElementsContext.Provider>;\n}\n","/**\n * Element コンポーネント。\n *\n * 各コンポーネントは 1 つの `<div>` コンテナを描画するだけで、\n * 実体(カード情報が入る iframe)はコア SDK が差し込む。\n *\n * React Strict Mode の二重 mount 対応:\n * - effect の cleanup で element.unmount() を必ず呼ぶ\n * - unmount 後は Elements._elements 配列から除外される(コア SDK 側で対応済)\n * - 結果として Strict Mode で effect が再実行されても古い iframe は残らない\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useElements } from './hooks';\nimport type {\n ElementType,\n ElementOptions,\n ElementChangeEvent,\n ElementFocusEvent,\n ElementReadyEvent,\n} from './types';\n\nexport interface ElementProps {\n options?: ElementOptions;\n className?: string;\n style?: CSSProperties;\n onReady?: (e: ElementReadyEvent) => void;\n onChange?: (e: ElementChangeEvent) => void;\n onFocus?: (e: ElementFocusEvent) => void;\n onBlur?: (e: ElementFocusEvent) => void;\n}\n\nconst PROBE_PX = 100000;\n\n/**\n * コンテナの幅・高さのうち、中身に追従する(加盟店が寸法を決めていない)軸を返す。\n */\nfunction contentSizedAxes(container: HTMLElement) {\n // display: none の祖先の中ではレイアウトが無いので、computed value で見る。\n if (container.getClientRects().length === 0) {\n const computed = getComputedStyle(container);\n const isAuto = (v: string) => v === '' || v === 'auto';\n return { width: isAuto(computed.width), height: isAuto(computed.height) };\n }\n // computed の height で判定すると、border-box の padding・border や min-height で\n // 0 にならず見誤るので、大きな子を一時的に入れて寸法が伸びるかで確かめる。\n // 祖先の transform(モーダルの scale のアニメーションなど)に左右されないよう、\n // getBoundingClientRect ではなくレイアウト上の寸法の offset* で比べる。\n const before = { width: container.offsetWidth, height: container.offsetHeight };\n const probe = container.ownerDocument.createElement('div');\n probe.style.cssText = `width: ${PROBE_PX}px; height: ${PROBE_PX}px;`;\n container.appendChild(probe);\n const grows = {\n width: container.offsetWidth > before.width,\n height: container.offsetHeight > before.height,\n };\n probe.remove();\n return grows;\n}\n\n/**\n * 指定 type の Element を管理する React コンポーネントを生成する。\n */\nfunction createElementComponent(type: ElementType) {\n function ElementComponent({\n options,\n className,\n style,\n onReady,\n onChange,\n onFocus,\n onBlur,\n }: ElementProps) {\n const elements = useElements();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [fill, setFill] = useState({ width: false, height: false });\n\n // 最新のハンドラを ref で保持(effect を毎回 re-run させないため)\n const handlersRef = useRef({ onReady, onChange, onFocus, onBlur });\n handlersRef.current = { onReady, onChange, onFocus, onBlur };\n\n useEffect(() => {\n const container = containerRef.current;\n if (!elements || !container) return;\n\n // 100% を当てた後に測り直すと親の寸法に追従して見えるので、立てた軸は戻さない。\n const unset = contentSizedAxes(container);\n setFill((prev) => ({\n width: prev.width || unset.width,\n height: prev.height || unset.height,\n }));\n\n const element = elements.create(type, options);\n element.mount(container);\n\n const unsubs = [\n element.on('ready', (e) => handlersRef.current.onReady?.(e)),\n element.on('change', (e) => handlersRef.current.onChange?.(e)),\n element.on('focus', (e) => handlersRef.current.onFocus?.(e)),\n element.on('blur', (e) => handlersRef.current.onBlur?.(e)),\n ];\n\n return () => {\n unsubs.forEach((u) => u());\n element.unmount();\n };\n // options はマウント時にしか反映しない方針(Stripe と同じ挙動)。\n // 動的に style を変えたい場合は後続 PR で element.update() を追加。\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [elements]);\n\n // インラインの既定値は className の寸法に勝つので、加盟店が決めていない軸だけに付ける。\n // 判定は mount 時の 1 回だけなので、後から寸法を変えるなら style で渡す。\n return (\n <div\n ref={containerRef}\n className={className}\n style={{\n ...(fill.width && { width: '100%' }),\n ...(fill.height && { height: '100%' }),\n ...style,\n }}\n />\n );\n }\n ElementComponent.displayName = `HelloPay(${type})`;\n // getElement(CardNumberElement) のようにコンポーネント自身を型指定子として使えるよう、\n // 静的プロパティに type を生やしておく\n ElementComponent.__elementType = type as ElementType;\n return ElementComponent;\n}\n\nexport const CardNumberElement = createElementComponent('cardNumber');\nexport const CardExpiryElement = createElementComponent('cardExpiry');\nexport const CardCvcElement = createElementComponent('cardCvc');\nexport const CardholderNameElement = createElementComponent('cardholderName');\n// 韓国発行カードの Toss 登録に必要な暗証番号の先頭 2 桁。表示・非表示は\n// 発行国の判定結果に応じて呼び出し側が mount / unmount で制御する。\nexport const CardPasswordElement = createElementComponent('cardPassword');\n\nexport type ElementComponent = typeof CardNumberElement;\n","/**\n * React hooks.\n *\n * useHelloPay / useElements は <Elements> Provider の Context から\n * SDK インスタンスと Elements セッションを取り出す。\n * SDK ロード完了までは null を返すので、ハンドラ内で null チェックする。\n */\n\nimport { useContext } from 'react';\nimport { ElementsContext } from './Elements';\nimport type { HelloPay, Elements } from './types';\n\nexport function useHelloPay(): HelloPay | null {\n return useContext(ElementsContext).hellopay;\n}\n\nexport function useElements(): Elements | null {\n return useContext(ElementsContext).elements;\n}\n","/**\n * Apple Pay ボタン。\n *\n * `useHelloPay()` から SDK を取り、対応端末(Safari + Apple Pay 利用可能)でのみ\n * Apple 公式スタイルのボタンを描画する。非対応端末では何も描画しない。\n *\n * click で `hellopay.applePay()` を同期呼び出しし(`new ApplePaySession` の\n * user gesture 要件のため)、結果を `onToken` / `onError` / `onCancel` に振り分ける。\n * SDK は Apple Pay トークンを返すだけで課金はしないので、加盟店は `onToken` で\n * 受けたトークンを自社バックエンドから決済 API に送って課金する。\n */\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\nimport { useHelloPay } from './hooks';\nimport type { ApplePayCard, ApplePayOptions, HelloPayError } from './types';\n\nexport interface ApplePayButtonProps {\n options: ApplePayOptions;\n /** トークン取得成功時。トークンを自社バックエンド経由で決済 API に送る。 */\n onToken: (token: string, card: ApplePayCard) => void;\n /** validation / network エラー時。 */\n onError?: (error: HelloPayError) => void;\n /** ユーザーが Apple Pay シートを閉じた時。 */\n onCancel?: () => void;\n /** Apple Pay ボタンの色。既定 `black`。 */\n buttonStyle?: 'black' | 'white' | 'white-outline';\n /** Apple Pay ボタンの種別(`plain` / `buy` / `pay` 等)。既定 `plain`。 */\n buttonType?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function ApplePayButton({\n options,\n onToken,\n onError,\n onCancel,\n buttonStyle = 'black',\n buttonType = 'plain',\n className,\n style,\n}: ApplePayButtonProps) {\n const hellopay = useHelloPay();\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const [supported, setSupported] = useState(false);\n\n // canMakeApplePayPayments は ApplePaySession 依存で client-only のため effect で判定。\n useEffect(() => {\n setSupported(!!hellopay && hellopay.canMakeApplePayPayments());\n }, [hellopay]);\n\n // Apple Pay ボタンの見た目はベンダー CSS プロパティで指定する。React の style 型に\n // 無いため ref 経由で setProperty する。\n useEffect(() => {\n const el = buttonRef.current;\n if (!el) return;\n el.style.setProperty('-webkit-appearance', '-apple-pay-button');\n el.style.setProperty('-apple-pay-button-type', buttonType);\n el.style.setProperty('-apple-pay-button-style', buttonStyle);\n }, [supported, buttonType, buttonStyle]);\n\n // 最新のハンドラ / options を ref に保持し、click ハンドラを毎回作り直さない。\n const latest = useRef({ options, onToken, onError, onCancel, hellopay });\n latest.current = { options, onToken, onError, onCancel, hellopay };\n\n if (!supported) return null;\n\n const handleClick = () => {\n const current = latest.current;\n if (!current.hellopay) return;\n // user gesture 要件のため click ハンドラから同期呼び出しする。\n current.hellopay\n .applePay(current.options)\n .then((result) => {\n if (result.error) {\n if (result.error.type === 'cancel') {\n current.onCancel?.();\n } else {\n current.onError?.(result.error);\n }\n return;\n }\n current.onToken(result.token, result.card);\n })\n .catch((err: unknown) => {\n current.onError?.({\n type: 'config_error',\n code: 'apple_pay_error',\n message: err instanceof Error ? err.message : 'Apple Pay error',\n });\n });\n };\n\n return (\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleClick}\n className={className}\n style={{ width: '100%', height: '44px', cursor: 'pointer', ...style }}\n />\n );\n}\n\nApplePayButton.displayName = 'HelloPay(ApplePayButton)';\n"],"mappings":"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","names":["script","useEffect","useState","jsx","useState","useEffect","useEffect","useRef","useState","jsx","useRef","useState","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hello-pay/react",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "React components for accepting payments with HelloPay",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {