{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport React, {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from \"react\";\nimport type {\n  PermissionMessage,\n  PermissionSignature,\n} from \"@orca-so/wavebreak\";\n\nexport type Permission = {\n  message: PermissionMessage;\n  signature: PermissionSignature;\n};\n\nexport type AuthorizationRequestPayload = {\n  subject: string;\n  discriminatorBytes: number[];\n  correlationId?: string;\n};\n\nexport const PROTOCOL_VERSION = 1;\n\nexport const DEFAULT_AUTHORIZATION_URL =\n  \"https://www.orca.so/wavebreak-integration\";\n\nexport const AuthorizationMessageType = {\n  RequestVerification: \"REQUEST_VERIFICATION\",\n  VerificationSuccess: \"VERIFICATION_SUCCESS\",\n  VerificationFailed: \"VERIFICATION_FAILED\",\n} as const;\nexport type AuthorizationMessageType =\n  (typeof AuthorizationMessageType)[keyof typeof AuthorizationMessageType];\n\ntype WavebreakAuthorizationProviderProps = React.PropsWithChildren<{\n  authorizationUrl?: string;\n}>;\n\nexport type UseWavebreakAuthorization = {\n  requestPermission: (\n    payload: AuthorizationRequestPayload,\n  ) => Promise<Permission>;\n};\n\ntype InternalAuthorizationContext = {\n  requestPermission: (\n    payload: AuthorizationRequestPayload,\n  ) => Promise<Permission>;\n  ensureInitialized: () => void;\n};\n\nconst WavebreakAuthorizationContext =\n  createContext<InternalAuthorizationContext | null>(null);\n\nexport function WavebreakAuthorizationProvider({\n  authorizationUrl,\n  children,\n}: WavebreakAuthorizationProviderProps) {\n  const iframeRef = useRef<HTMLIFrameElement | null>(null);\n  const iframeReadyRef = useRef<boolean>(false);\n  const requestResolvers = useRef(\n    new Map<\n      string,\n      { resolve: (p: Permission) => void; reject: (e: unknown) => void }\n    >(),\n  );\n  const [iframeSrc, setIframeSrc] = useState<string | undefined>(undefined);\n\n  const targetUrl = useMemo(() => {\n    if (typeof window === \"undefined\") return \"\";\n    const url = new URL(authorizationUrl ?? DEFAULT_AUTHORIZATION_URL);\n    url.searchParams.set(\"parentOrigin\", window.location.origin);\n    return url.toString();\n  }, [authorizationUrl]);\n\n  const expectedAuthorizationIframeOrigin = useMemo(() => {\n    try {\n      return targetUrl ? new URL(targetUrl).origin : undefined;\n    } catch {\n      return undefined;\n    }\n  }, [targetUrl]);\n\n  const handleMessage = useCallback(\n    (event: MessageEvent) => {\n      if (!iframeRef.current) return;\n      const message = event.data as any;\n      if (!message || typeof message !== \"object\") return;\n\n      const { type, correlationId, data: payload, error } = message as any;\n\n      const contentWindow = iframeRef.current.contentWindow;\n      if (event.source !== contentWindow) return;\n      if (\n        !expectedAuthorizationIframeOrigin ||\n        event.origin !== expectedAuthorizationIframeOrigin\n      )\n        return;\n\n      const takeResolver = (id: string | undefined) => {\n        if (!id) return undefined;\n        const resolver = requestResolvers.current.get(id);\n        if (resolver) requestResolvers.current.delete(id);\n        return resolver;\n      };\n\n      if (type === AuthorizationMessageType.VerificationSuccess && payload) {\n        const resolver = takeResolver(correlationId);\n        if (resolver) resolver.resolve(payload as Permission);\n      } else if (type === AuthorizationMessageType.VerificationFailed) {\n        const resolver = takeResolver(correlationId);\n        if (resolver)\n          resolver.reject(new Error(error || \"Authorization failed\"));\n      }\n    },\n    [expectedAuthorizationIframeOrigin, targetUrl],\n  );\n\n  useEffect(() => {\n    if (!targetUrl) return;\n    window.addEventListener(\"message\", handleMessage);\n    return () => window.removeEventListener(\"message\", handleMessage);\n  }, [targetUrl, handleMessage]);\n\n  const requestPermission = useCallback(\n    (payload: AuthorizationRequestPayload) => {\n      return new Promise<Permission>(async (resolve, reject) => {\n        const correlationId =\n          payload.correlationId ||\n          `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n        requestResolvers.current.set(correlationId, { resolve, reject });\n\n        try {\n          if (!targetUrl) throw new Error(\"Invalid authorization URL\");\n          if (!iframeReadyRef.current) {\n            requestResolvers.current.delete(correlationId);\n            return reject(new Error(\"Authorization page initializing\"));\n          }\n          const contentWindow = iframeRef.current?.contentWindow;\n          if (!contentWindow) {\n            requestResolvers.current.delete(correlationId);\n            return reject(new Error(\"Authorization page not ready\"));\n          }\n          contentWindow.postMessage(\n            {\n              type: AuthorizationMessageType.RequestVerification,\n              payload: { ...payload, correlationId },\n              protocolVersion: PROTOCOL_VERSION,\n            },\n            new URL(targetUrl).origin,\n          );\n        } catch (e) {\n          requestResolvers.current.delete(correlationId);\n          reject(e);\n        }\n      });\n    },\n    [iframeSrc, targetUrl],\n  );\n\n  const ensureInitialized = useCallback(() => {\n    if (!targetUrl) return;\n    if (iframeSrc) return;\n    setIframeSrc(targetUrl);\n  }, [iframeSrc, targetUrl]);\n\n  return (\n    <WavebreakAuthorizationContext.Provider\n      value={{ requestPermission, ensureInitialized }}\n    >\n      <iframe\n        ref={iframeRef}\n        src={iframeSrc}\n        title=\"Wavebreak Authorization\"\n        sandbox=\"allow-scripts allow-same-origin allow-top-navigation-by-user-activation\"\n        style={{\n          position: \"absolute\",\n          top: -1,\n          left: -1,\n          width: 1,\n          height: 1,\n          opacity: 0,\n          pointerEvents: \"none\",\n        }}\n        onLoad={() => {\n          if (iframeSrc) iframeReadyRef.current = true;\n        }}\n        aria-hidden\n      />\n      {children}\n    </WavebreakAuthorizationContext.Provider>\n  );\n}\n\nexport function useWavebreakAuthorization(): UseWavebreakAuthorization {\n  const ctx = useContext(WavebreakAuthorizationContext);\n  if (!ctx)\n    throw new Error(\n      \"useWavebreakAuthorization must be used within WavebreakAuthorizationProvider\",\n    );\n  const { requestPermission, ensureInitialized } = ctx;\n\n  // Initialize iframe once when the hook is first used\n  useEffect(() => {\n    ensureInitialized();\n  }, []);\n\n  return { requestPermission };\n}\n"],"mappings":"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","names":[]}