🚀. Socket Launch Week Day 3:Socket Firewall Now Blocks Malicious VS Code and Open VSX Extensions.Learn more
Sign In

@chaindoc_io/embed-sdk

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@chaindoc_io/embed-sdk - npm Package Compare versions

Comparing version
2.2.0-alpha.2
to
2.2.0
+11
-6
CHANGELOG.md

@@ -8,14 +8,19 @@ # Changelog

## [2.2.0-alpha.2] - 2026-05-07
## [2.2.0] - 2026-05-07
### Changed
- **Default modal size raised to `450x850`** (from `400x600`). The previous defaults were too small for the embedded UI to render the signature pad and document preview without overflow on long document names — partner integrations that did not pass explicit `modalWidth`/`modalHeight` rendered a broken signing flow out of the box. The new defaults match the size used by the internal QA test environment, which is the only configuration the embedded UI was actually validated on. Integrators who already pass dimensions are unaffected.
- **JSDoc `@default` annotations corrected** on `SignatureFlowOptions.modalWidth`/`modalHeight` — they previously claimed `800`/`600` while the runtime used `400`/`600`. Documentation in `docs/ADVANCED_USAGE.md` and `docs/API_REFERENCE.md` was updated to match.
- **Internal cleanups**: tightened typing on `EmbedInstance`'s internal event handler map and added unit tests covering both default and explicit-size modal container styles.
### Added
- **ESLint config (`.eslintrc.cjs`)**: project had ESLint dependencies and a `lint` script but no config file, so `yarn lint` was a no-op. Adding the standard `@typescript-eslint/recommended` config makes the script functional and lets us enforce the type tightening introduced alongside this release. Dev-only artifact — not shipped in the published tarball.
- **ESLint config (`.eslintrc.cjs`)**: the package had ESLint dependencies and a `lint` script but no config file, so `yarn lint` was a no-op. The standard `@typescript-eslint/recommended` config makes the script functional. Dev-only artifact — not shipped in the published tarball.
## [2.2.0-alpha.1] - 2026-05-07
### Released from
### Changed
- `2.2.0-alpha.1` (2026-05-07)
- `2.2.0-alpha.2` (2026-05-07)
- **Default modal size raised to `450x850`** (from `400x600`). The previous defaults were too small for the embedded UI to render the signature pad and document preview without overflow on long document names. The new defaults match the size used by the internal QA test environment, which is the only configuration the embedded UI was validated on. Integrators who do not pass `modalWidth`/`modalHeight` will now get a working signing flow out of the box. JSDoc `@default` annotations on `SignatureFlowOptions.modalWidth`/`modalHeight` were also corrected — they previously claimed `800`/`600` while the runtime used `400`/`600`.
## [2.1.1] - 2026-04-27

@@ -22,0 +27,0 @@

@@ -51,3 +51,3 @@ "use strict";var ChaindocEmbed=(()=>{var h=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var x=(i,e)=>{for(var t in e)h(i,t,{get:e[t],enumerable:!0})},M=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of C(e))!I.call(i,s)&&s!==t&&h(i,s,{get:()=>e[s],enumerable:!(n=S(e,s))||n.enumerable});return i};var O=i=>M(h({},"__esModule",{value:!0}),i);var k={};x(k,{ChaindocEmbed:()=>d,EmbedInstance:()=>o});function c(i){switch(i){case"production":return"https://embed.chaindoc.io";case"staging":return"https://embed-demo.chaindoc.io";case"development":return"https://embed-demo.chaindoc.io";default:return"https://embed.chaindoc.io"}}function p(i){let e=c(i);try{return new URL(e).origin}catch{return e}}function u(i,e,t,n,s,a,g){let r=new URL(`/embed/sign/${e}`,i),m=t?.trim().toLowerCase();return m&&r.searchParams.set("email",m),n&&r.searchParams.set("mode",n),s&&r.searchParams.set("theme",s),a&&r.searchParams.set("lang",a),g!==void 0&&r.searchParams.set("closeOnEscape",String(g)),r.toString()}function f(i){if(typeof i=="string"){let e=document.querySelector(i);if(!e)throw new Error(`Container element not found: ${i}`);return e}return i}var l=class{constructor(e){this.debug=e}log(...e){this.debug&&console.log("[Chaindoc SDK]",...e)}warn(...e){this.debug&&console.warn("[Chaindoc SDK]",...e)}error(...e){this.debug&&console.error("[Chaindoc SDK]",...e)}};function v(i){return typeof i=="object"&&i!==null&&"source"in i&&i.source==="chaindoc-embed"}function b(i){return`

z-index: 2147483647;
`.trim()),this.isFullscreen=!0)}exitFullscreen(){this.isFullscreen&&(this.logger.log("Exiting fullscreen"),this.previousIframeStyle!==null?this.iframe.setAttribute("style",this.previousIframeStyle):this.iframe.removeAttribute("style"),this.previousIframeStyle=null,this.isFullscreen=!1)}sendMessage(e){if(!this.iframe.contentWindow){this.logger.error("Cannot send message: iframe contentWindow not available");return}this.iframe.contentWindow.postMessage(e,this.allowedOrigin),this.logger.log("Sent message to iframe:",e.type)}close(){if(this.state.isClosed){this.logger.warn("Instance already closed");return}this.logger.log("Closing instance"),this.sendMessage({source:"chaindoc-embed",type:"CLOSE"}),setTimeout(()=>{this.state.isClosed||(this.logger.warn("Iframe did not respond to CLOSE, forcing cleanup"),this.cleanup())},3e3)}changeTheme(e){this.logger.log("Changing theme to:",e),this.state.theme=e,this.sendMessage({source:"chaindoc-embed",type:"THEME_CHANGE",data:{theme:e}})}isReady(){return this.state.isReady}getSessionId(){return this.state.sessionId}_internalOn(e,t){let n=this.internalEventHandlers.get(e);if(n){n.add(t);return}this.internalEventHandlers.set(e,new Set([t]))}emit(e){let t=this.internalEventHandlers.get(e);t&&t.forEach(n=>n())}cleanup(){this.state.isClosed||(this.logger.log("Cleaning up instance"),this.isFullscreen&&this.exitFullscreen(),this.state.isClosed=!0,window.removeEventListener("message",this.messageListener),this.overlay&&(this.overlay.remove(),document.body.style.overflow=this.previousOverflow),this.container&&this.container.querySelector("[data-chaindoc-inline]")?.remove(),this.options.onClose?.(),this.emit("close"),this.internalEventHandlers.clear())}};var d=class{constructor(e){this.instances=new Set;if(!e.publicKey)throw new Error("ChaindocEmbed: publicKey is required");if(!e.publicKey.startsWith("pk_"))throw new Error('ChaindocEmbed: publicKey must start with "pk_"');this.config={publicKey:e.publicKey,environment:e.environment||"production",debug:e.debug||!1},this.logger=new l(this.config.debug),this.logger.log("SDK initialized",this.config)}openSignatureFlow(e){if(!e.sessionId)throw new Error("openSignatureFlow: sessionId is required");if(!e.sessionId.startsWith("ses_"))throw new Error('openSignatureFlow: sessionId must start with "ses_"');if((e.mode||"modal")==="inline"&&!e.container)throw new Error("openSignatureFlow: container is required for inline mode");this.logger.log("Opening signature flow",e);let n=new o(this.config,e,this.logger);return this.instances.add(n),n._internalOn("close",()=>{this.instances.delete(n)}),n}destroy(){this.logger.log("Destroying SDK and all instances");for(let e of this.instances)e.close();this.instances.clear()}static get version(){return"2.2.0-alpha.2"}};return O(k);})();
`.trim()),this.isFullscreen=!0)}exitFullscreen(){this.isFullscreen&&(this.logger.log("Exiting fullscreen"),this.previousIframeStyle!==null?this.iframe.setAttribute("style",this.previousIframeStyle):this.iframe.removeAttribute("style"),this.previousIframeStyle=null,this.isFullscreen=!1)}sendMessage(e){if(!this.iframe.contentWindow){this.logger.error("Cannot send message: iframe contentWindow not available");return}this.iframe.contentWindow.postMessage(e,this.allowedOrigin),this.logger.log("Sent message to iframe:",e.type)}close(){if(this.state.isClosed){this.logger.warn("Instance already closed");return}this.logger.log("Closing instance"),this.sendMessage({source:"chaindoc-embed",type:"CLOSE"}),setTimeout(()=>{this.state.isClosed||(this.logger.warn("Iframe did not respond to CLOSE, forcing cleanup"),this.cleanup())},3e3)}changeTheme(e){this.logger.log("Changing theme to:",e),this.state.theme=e,this.sendMessage({source:"chaindoc-embed",type:"THEME_CHANGE",data:{theme:e}})}isReady(){return this.state.isReady}getSessionId(){return this.state.sessionId}_internalOn(e,t){let n=this.internalEventHandlers.get(e);if(n){n.add(t);return}this.internalEventHandlers.set(e,new Set([t]))}emit(e){let t=this.internalEventHandlers.get(e);t&&t.forEach(n=>n())}cleanup(){this.state.isClosed||(this.logger.log("Cleaning up instance"),this.isFullscreen&&this.exitFullscreen(),this.state.isClosed=!0,window.removeEventListener("message",this.messageListener),this.overlay&&(this.overlay.remove(),document.body.style.overflow=this.previousOverflow),this.container&&this.container.querySelector("[data-chaindoc-inline]")?.remove(),this.options.onClose?.(),this.emit("close"),this.internalEventHandlers.clear())}};var d=class{constructor(e){this.instances=new Set;if(!e.publicKey)throw new Error("ChaindocEmbed: publicKey is required");if(!e.publicKey.startsWith("pk_"))throw new Error('ChaindocEmbed: publicKey must start with "pk_"');this.config={publicKey:e.publicKey,environment:e.environment||"production",debug:e.debug||!1},this.logger=new l(this.config.debug),this.logger.log("SDK initialized",this.config)}openSignatureFlow(e){if(!e.sessionId)throw new Error("openSignatureFlow: sessionId is required");if(!e.sessionId.startsWith("ses_"))throw new Error('openSignatureFlow: sessionId must start with "ses_"');if((e.mode||"modal")==="inline"&&!e.container)throw new Error("openSignatureFlow: container is required for inline mode");this.logger.log("Opening signature flow",e);let n=new o(this.config,e,this.logger);return this.instances.add(n),n._internalOn("close",()=>{this.instances.delete(n)}),n}destroy(){this.logger.log("Destroying SDK and all instances");for(let e of this.instances)e.close();this.instances.clear()}static get version(){return"2.2.0"}};return O(k);})();
//# sourceMappingURL=embed-sdk.umd.js.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/styles.ts","../src/EmbedInstance.ts","../src/ChaindocEmbed.ts"],"sourcesContent":["/**\n * @chaindoc/embed-sdk\n *\n * JavaScript/TypeScript SDK for embedding Chaindoc document signing flow via iframe.\n *\n * @packageDocumentation\n */\n\nexport { ChaindocEmbed } from \"./ChaindocEmbed\";\nexport { EmbedInstance } from \"./EmbedInstance\";\nexport type {\n ChaindocEmbedConfig,\n SignatureFlowOptions,\n Environment,\n DisplayMode,\n Theme,\n Language,\n SignatureSuccessData,\n SignatureErrorData,\n ResendOtpData,\n IframeToSdkMessage,\n SdkToIframeMessage,\n} from \"./types\";\n","/**\n * Utility functions for Chaindoc Embed SDK\n */\n\nimport type { DisplayMode, Environment } from \"./types\";\n\n/**\n * Get the iframe base URL based on environment\n */\nexport function getIframeBaseUrl(environment: Environment): string {\n switch (environment) {\n case \"production\":\n return \"https://embed.chaindoc.io\";\n case \"staging\":\n return \"https://embed-demo.chaindoc.io\";\n case \"development\":\n return \"https://embed-demo.chaindoc.io\";\n default:\n return \"https://embed.chaindoc.io\";\n }\n}\n\n/**\n * Get allowed origin for postMessage validation\n */\nexport function getAllowedOrigin(environment: Environment): string {\n const baseUrl = getIframeBaseUrl(environment);\n try {\n const url = new URL(baseUrl);\n return url.origin;\n } catch {\n return baseUrl;\n }\n}\n\n/**\n * Build iframe URL with query parameters\n */\nexport function buildIframeUrl(\n baseUrl: string,\n sessionId: string,\n email?: string,\n mode?: DisplayMode,\n theme?: string,\n language?: string,\n closeOnEscape?: boolean\n): string {\n // Session ID goes into the path, not as a query parameter\n const url = new URL(`/embed/sign/${sessionId}`, baseUrl);\n\n const normalizedEmail = email?.trim().toLowerCase();\n if (normalizedEmail) {\n url.searchParams.set(\"email\", normalizedEmail);\n }\n\n if (mode) {\n url.searchParams.set(\"mode\", mode);\n }\n\n if (theme) {\n url.searchParams.set(\"theme\", theme);\n }\n\n if (language) {\n url.searchParams.set(\"lang\", language);\n }\n\n if (closeOnEscape !== undefined) {\n url.searchParams.set(\"closeOnEscape\", String(closeOnEscape));\n }\n\n return url.toString();\n}\n\n/**\n * Resolve container element from HTMLElement or selector string\n */\nexport function resolveContainer(container: HTMLElement | string): HTMLElement {\n if (typeof container === \"string\") {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n return element;\n }\n return container;\n}\n\n/**\n * Debug logger (only logs when debug mode is enabled)\n */\nexport class Logger {\n constructor(private debug: boolean) {}\n\n log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (this.debug) {\n console.error(\"[Chaindoc SDK]\", ...args);\n }\n }\n}\n\n/**\n * Type guard to check if a message is from Chaindoc iframe\n */\nexport function isChaindocMessage(\n message: unknown\n): message is { source: \"chaindoc-embed\" } {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"source\" in message &&\n message.source === \"chaindoc-embed\"\n );\n}\n","/**\n * CSS-in-JS styles for modal and inline modes\n */\n\n/**\n * Get styles for modal overlay\n */\nexport function getOverlayStyles(zIndex: number): string {\n return `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${zIndex};\n padding: 20px;\n `.trim();\n}\n\n/**\n * Get styles for modal container\n */\nexport function getModalContainerStyles(\n width?: number,\n height?: number\n): string {\n const modalWidth = width ?? 450;\n const modalHeight = height ?? 850;\n\n return `\n position: relative;\n width: 100%;\n max-width: ${modalWidth}px;\n height: ${modalHeight}px;\n max-height: 90vh;\n background: white;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n `.trim();\n}\n\n/**\n * Get styles for iframe (common for both modal and inline)\n */\nexport function getIframeStyles(mode: \"modal\" | \"inline\"): string {\n const baseStyles = `\n width: 100%;\n border: none;\n display: block;\n `.trim();\n\n if (mode === \"modal\") {\n return `\n ${baseStyles}\n height: 100%;\n min-height: 400px;\n `.trim();\n }\n\n // Inline mode\n return `\n ${baseStyles}\n height: 0;\n `.trim();\n}\n\n/**\n * Get styles for inline container wrapper\n */\nexport function getInlineContainerStyles(): string {\n return `\n position: relative;\n width: 100%;\n `.trim();\n}\n","/**\n * Instance class for managing individual signature flows\n */\n\nimport type {\n SignatureFlowOptions,\n Theme,\n IframeToSdkMessage,\n SdkToIframeMessage,\n InstanceState,\n Environment,\n} from './types';\nimport {\n getIframeBaseUrl,\n getAllowedOrigin,\n buildIframeUrl,\n resolveContainer,\n isChaindocMessage,\n Logger,\n} from './utils';\nimport {\n getOverlayStyles,\n getModalContainerStyles,\n getIframeStyles,\n getInlineContainerStyles,\n} from './styles';\n\n/**\n * Internal config interface for EmbedInstance\n */\ninterface InternalConfig {\n publicKey: string;\n environment: Environment;\n debug: boolean;\n}\n\ntype InternalEventHandler = () => void;\n\n/**\n * Represents a single signature flow instance\n *\n * @example\n * ```typescript\n * const instance = sdk.openSignatureFlow({ sessionId: 'ses_xxx' });\n * instance.changeTheme('dark');\n * instance.close();\n * ```\n */\nexport class EmbedInstance {\n private config: InternalConfig;\n private options: SignatureFlowOptions;\n private logger: Logger;\n\n private state: InstanceState;\n private iframe: HTMLIFrameElement;\n private overlay: HTMLDivElement | null = null;\n private modalContainer: HTMLDivElement | null = null;\n private container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private isFullscreen: boolean = false;\n private previousIframeStyle: string | null = null;\n\n private internalEventHandlers: Map<string, Set<InternalEventHandler>> = new Map();\n\n constructor(\n config: InternalConfig,\n options: SignatureFlowOptions,\n logger: Logger\n ) {\n this.config = config;\n this.logger = logger;\n\n // Store options\n this.options = options;\n\n // Initialize state\n this.state = {\n sessionId: this.options.sessionId,\n mode: this.options.mode || 'modal',\n theme: this.options.theme || 'light',\n isReady: false,\n isClosed: false,\n hasSucceeded: false,\n };\n\n // Calculate allowed origin\n const baseUrl = getIframeBaseUrl(this.config.environment);\n this.allowedOrigin = getAllowedOrigin(this.config.environment);\n\n // Build iframe URL\n const iframeUrl = buildIframeUrl(\n baseUrl,\n this.options.sessionId,\n this.options.email,\n this.state.mode,\n this.state.theme,\n this.options.language,\n this.options.closeOnEscape\n );\n\n // Create iframe\n this.iframe = this.createIframe(iframeUrl);\n\n // Setup message listener\n this.messageListener = this.handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n\n // Render based on mode\n if (this.state.mode === 'modal') {\n this.renderModal();\n } else {\n this.renderInline();\n }\n\n this.logger.log('Instance created', { sessionId: this.state.sessionId, mode: this.state.mode });\n }\n\n /**\n * Create iframe element\n */\n private createIframe(url: string): HTMLIFrameElement {\n const iframe = document.createElement('iframe');\n iframe.src = url;\n iframe.setAttribute('style', getIframeStyles(this.state.mode));\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads'\n );\n // Permissions for KYC verification (camera/microphone for liveness check, geolocation optional)\n iframe.setAttribute('allow', 'clipboard-write; camera; microphone; geolocation');\n return iframe;\n }\n\n /**\n * Render modal mode\n */\n private renderModal(): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.setAttribute('style', getOverlayStyles(this.options.zIndex ?? 999999));\n this.overlay.setAttribute('data-chaindoc-overlay', 'true');\n\n // Create modal container\n this.modalContainer = document.createElement('div');\n this.modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n this.modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(this.modalContainer);\n\n // Click outside to cancel and close (configurable, default: true)\n if (this.options.closeOnClickOutside !== false) {\n this.overlay.addEventListener('click', (e) => {\n if (e.target === this.overlay) {\n this.logger.log('Clicked outside modal - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n });\n }\n\n // ESC key to cancel and close (configurable, default: true)\n if (this.options.closeOnEscape !== false) {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.logger.log('ESC key pressed - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n };\n document.addEventListener('keydown', handleEscape);\n\n // Store cleanup\n this._internalOn('close', () => {\n document.removeEventListener('keydown', handleEscape);\n });\n }\n\n // Lock body scroll (preserve previous value for restoration)\n this.previousOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n // Append to body\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Render inline mode\n */\n private renderInline(): void {\n if (!this.options.container) {\n throw new Error('Container is required for inline mode');\n }\n\n // Resolve container\n this.container = resolveContainer(this.options.container);\n\n // Create wrapper\n const wrapper = document.createElement('div');\n wrapper.setAttribute('style', getInlineContainerStyles());\n wrapper.setAttribute('data-chaindoc-inline', 'true');\n wrapper.appendChild(this.iframe);\n\n // Inject into container\n this.container.appendChild(wrapper);\n }\n\n /**\n * Handle incoming postMessage events\n */\n private handleMessage(event: MessageEvent): void {\n // Validate origin and source (ensure message comes from our iframe, not another iframe with same origin)\n if (event.origin !== this.allowedOrigin || event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Validate message structure\n if (!isChaindocMessage(event.data)) {\n return;\n }\n\n const message = event.data as IframeToSdkMessage;\n this.logger.log('Received message:', message.type, message);\n\n // Handle message by type\n switch (message.type) {\n case 'READY':\n this.state.isReady = true;\n this.options.onReady?.();\n break;\n\n case 'RESIZE':\n if ('data' in message && !this.isFullscreen) {\n this.iframe.style.height = `${message.data.height}px`;\n }\n break;\n\n case 'SUCCESS':\n this.state.hasSucceeded = true;\n if ('data' in message) {\n this.options.onSuccess?.(message.data);\n }\n break;\n\n case 'ERROR':\n if ('data' in message) {\n this.options.onError?.(message.data);\n }\n break;\n\n case 'CANCEL':\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n break;\n\n case 'CLOSED':\n this.cleanup();\n break;\n\n case 'RESEND_OTP':\n if ('data' in message) {\n this.options.onResendOtp?.(message.data);\n }\n break;\n\n case 'REQUEST_FULLSCREEN':\n this.enterFullscreen();\n break;\n\n case 'EXIT_FULLSCREEN':\n this.exitFullscreen();\n break;\n\n default:\n this.logger.warn('Unknown message type:', message);\n }\n }\n\n /**\n * Expand iframe to cover the entire parent viewport.\n * Works uniformly in modal and inline modes, including iOS Safari\n * (does not rely on the native Fullscreen API).\n *\n * Parent body.overflow is intentionally NOT modified here: it is brittle\n * (easy to leak a `hidden` lock back to the host page if the restore path\n * is missed). Scroll-chaining from the fullscreen iframe is handled inside\n * the iframe itself via `overscroll-behavior: contain` on the scroll area.\n */\n private enterFullscreen(): void {\n if (this.isFullscreen || this.state.isClosed) {\n return;\n }\n\n this.logger.log('Entering fullscreen');\n\n this.previousIframeStyle = this.iframe.getAttribute('style');\n\n this.iframe.setAttribute(\n 'style',\n `\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n max-width: none;\n max-height: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n padding: 0;\n display: block;\n z-index: 2147483647;\n `.trim()\n );\n\n this.isFullscreen = true;\n }\n\n /**\n * Restore iframe to its previous size and position.\n */\n private exitFullscreen(): void {\n if (!this.isFullscreen) {\n return;\n }\n\n this.logger.log('Exiting fullscreen');\n\n if (this.previousIframeStyle !== null) {\n this.iframe.setAttribute('style', this.previousIframeStyle);\n } else {\n this.iframe.removeAttribute('style');\n }\n this.previousIframeStyle = null;\n\n this.isFullscreen = false;\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: SdkToIframeMessage): void {\n if (!this.iframe.contentWindow) {\n this.logger.error('Cannot send message: iframe contentWindow not available');\n return;\n }\n\n this.iframe.contentWindow.postMessage(message, this.allowedOrigin);\n this.logger.log('Sent message to iframe:', message.type);\n }\n\n /**\n * Close the signature flow\n */\n close(): void {\n if (this.state.isClosed) {\n this.logger.warn('Instance already closed');\n return;\n }\n\n this.logger.log('Closing instance');\n\n // Send CLOSE message to iframe\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'CLOSE',\n });\n\n // Force cleanup after timeout if iframe doesn't respond\n setTimeout(() => {\n if (!this.state.isClosed) {\n this.logger.warn('Iframe did not respond to CLOSE, forcing cleanup');\n this.cleanup();\n }\n }, 3000);\n }\n\n /**\n * Change theme\n */\n changeTheme(theme: Theme): void {\n this.logger.log('Changing theme to:', theme);\n\n this.state.theme = theme;\n\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'THEME_CHANGE',\n data: { theme },\n });\n }\n\n /**\n * Check if iframe is ready\n */\n isReady(): boolean {\n return this.state.isReady;\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.state.sessionId;\n }\n\n /**\n * Internal event system (for cleanup tracking)\n * @internal\n */\n _internalOn(event: string, handler: InternalEventHandler): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n return;\n }\n\n this.internalEventHandlers.set(event, new Set([handler]));\n }\n\n private emit(event: string): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => handler());\n }\n }\n\n /**\n * Cleanup all resources\n */\n private cleanup(): void {\n if (this.state.isClosed) {\n return;\n }\n\n this.logger.log('Cleaning up instance');\n\n // Restore body overflow if we are destroyed while fullscreen is active\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.state.isClosed = true;\n\n // Remove message listener\n window.removeEventListener('message', this.messageListener);\n\n // Remove DOM elements\n if (this.overlay) {\n this.overlay.remove();\n document.body.style.overflow = this.previousOverflow;\n }\n\n if (this.container) {\n const wrapper = this.container.querySelector('[data-chaindoc-inline]');\n wrapper?.remove();\n }\n\n // Call onClose callback\n this.options.onClose?.();\n\n // Emit internal close event\n this.emit('close');\n\n // Clear internal handlers\n this.internalEventHandlers.clear();\n }\n}\n","/**\n * Main SDK class for Chaindoc Embed\n */\n\nimport { EmbedInstance } from \"./EmbedInstance\";\nimport type { ChaindocEmbedConfig, SignatureFlowOptions } from \"./types\";\nimport { Logger } from \"./utils\";\n\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Main entry point for Chaindoc Embed SDK\n *\n * @example\n * ```typescript\n * const sdk = new ChaindocEmbed({\n * publicKey: 'pk_test_xxx',\n * environment: 'development',\n * debug: true\n * });\n *\n * const instance = sdk.openSignatureFlow({\n * sessionId: 'ses_xxx',\n * onSuccess: (data) => console.log('Signed!', data)\n * });\n * ```\n */\n/**\n * Internal config type with defaults applied\n */\ninterface InternalConfig {\n publicKey: string;\n environment: \"production\" | \"staging\" | \"development\";\n debug: boolean;\n}\n\nexport class ChaindocEmbed {\n private config: InternalConfig;\n private logger: Logger;\n private instances: Set<EmbedInstance> = new Set();\n\n /**\n * Create a new ChaindocEmbed instance\n *\n * @param config - SDK configuration\n * @throws {Error} If publicKey is missing or invalid\n */\n constructor(config: ChaindocEmbedConfig) {\n // Validate required config\n if (!config.publicKey) {\n throw new Error(\"ChaindocEmbed: publicKey is required\");\n }\n\n if (!config.publicKey.startsWith(\"pk_\")) {\n throw new Error('ChaindocEmbed: publicKey must start with \"pk_\"');\n }\n\n // Set defaults\n this.config = {\n publicKey: config.publicKey,\n environment: config.environment || \"production\",\n debug: config.debug || false,\n };\n\n this.logger = new Logger(this.config.debug);\n this.logger.log(\"SDK initialized\", this.config);\n }\n\n /**\n * Open a signature flow\n *\n * @param options - Signature flow options\n * @returns EmbedInstance for controlling the flow\n * @throws {Error} If sessionId is missing or invalid\n * @throws {Error} If inline mode is used without container\n */\n openSignatureFlow(options: SignatureFlowOptions): EmbedInstance {\n // Validate required options\n if (!options.sessionId) {\n throw new Error(\"openSignatureFlow: sessionId is required\");\n }\n\n if (!options.sessionId.startsWith(\"ses_\")) {\n throw new Error('openSignatureFlow: sessionId must start with \"ses_\"');\n }\n\n const mode = options.mode || \"modal\";\n\n if (mode === \"inline\" && !options.container) {\n throw new Error(\n \"openSignatureFlow: container is required for inline mode\"\n );\n }\n\n this.logger.log(\"Opening signature flow\", options);\n\n // Create instance\n const instance = new EmbedInstance(this.config, options, this.logger);\n\n // Track instance\n this.instances.add(instance);\n\n // Remove from tracking when closed\n instance._internalOn(\"close\", () => {\n this.instances.delete(instance);\n });\n\n return instance;\n }\n\n /**\n * Destroy all instances and cleanup\n */\n destroy(): void {\n this.logger.log(\"Destroying SDK and all instances\");\n\n for (const instance of this.instances) {\n instance.close();\n }\n\n this.instances.clear();\n }\n\n /**\n * Get SDK version\n */\n static get version(): string {\n return __SDK_VERSION__;\n }\n}\n"],"mappings":"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","names":["src_exports","__export","ChaindocEmbed","EmbedInstance","getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","normalizedEmail","resolveContainer","container","element","Logger","debug","args","isChaindocMessage","message","getOverlayStyles","zIndex","getModalContainerStyles","width","height","getIframeStyles","mode","baseStyles","getInlineContainerStyles","EmbedInstance","config","options","logger","baseUrl","getIframeBaseUrl","getAllowedOrigin","iframeUrl","buildIframeUrl","url","iframe","getIframeStyles","getOverlayStyles","getModalContainerStyles","handleEscape","e","resolveContainer","wrapper","getInlineContainerStyles","event","isChaindocMessage","message","theme","handler","handlers","ChaindocEmbed","config","Logger","options","instance","EmbedInstance"]}
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/styles.ts","../src/EmbedInstance.ts","../src/ChaindocEmbed.ts"],"sourcesContent":["/**\n * @chaindoc/embed-sdk\n *\n * JavaScript/TypeScript SDK for embedding Chaindoc document signing flow via iframe.\n *\n * @packageDocumentation\n */\n\nexport { ChaindocEmbed } from \"./ChaindocEmbed\";\nexport { EmbedInstance } from \"./EmbedInstance\";\nexport type {\n ChaindocEmbedConfig,\n SignatureFlowOptions,\n Environment,\n DisplayMode,\n Theme,\n Language,\n SignatureSuccessData,\n SignatureErrorData,\n ResendOtpData,\n IframeToSdkMessage,\n SdkToIframeMessage,\n} from \"./types\";\n","/**\n * Utility functions for Chaindoc Embed SDK\n */\n\nimport type { DisplayMode, Environment } from \"./types\";\n\n/**\n * Get the iframe base URL based on environment\n */\nexport function getIframeBaseUrl(environment: Environment): string {\n switch (environment) {\n case \"production\":\n return \"https://embed.chaindoc.io\";\n case \"staging\":\n return \"https://embed-demo.chaindoc.io\";\n case \"development\":\n return \"https://embed-demo.chaindoc.io\";\n default:\n return \"https://embed.chaindoc.io\";\n }\n}\n\n/**\n * Get allowed origin for postMessage validation\n */\nexport function getAllowedOrigin(environment: Environment): string {\n const baseUrl = getIframeBaseUrl(environment);\n try {\n const url = new URL(baseUrl);\n return url.origin;\n } catch {\n return baseUrl;\n }\n}\n\n/**\n * Build iframe URL with query parameters\n */\nexport function buildIframeUrl(\n baseUrl: string,\n sessionId: string,\n email?: string,\n mode?: DisplayMode,\n theme?: string,\n language?: string,\n closeOnEscape?: boolean\n): string {\n // Session ID goes into the path, not as a query parameter\n const url = new URL(`/embed/sign/${sessionId}`, baseUrl);\n\n const normalizedEmail = email?.trim().toLowerCase();\n if (normalizedEmail) {\n url.searchParams.set(\"email\", normalizedEmail);\n }\n\n if (mode) {\n url.searchParams.set(\"mode\", mode);\n }\n\n if (theme) {\n url.searchParams.set(\"theme\", theme);\n }\n\n if (language) {\n url.searchParams.set(\"lang\", language);\n }\n\n if (closeOnEscape !== undefined) {\n url.searchParams.set(\"closeOnEscape\", String(closeOnEscape));\n }\n\n return url.toString();\n}\n\n/**\n * Resolve container element from HTMLElement or selector string\n */\nexport function resolveContainer(container: HTMLElement | string): HTMLElement {\n if (typeof container === \"string\") {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n return element;\n }\n return container;\n}\n\n/**\n * Debug logger (only logs when debug mode is enabled)\n */\nexport class Logger {\n constructor(private debug: boolean) {}\n\n log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (this.debug) {\n console.error(\"[Chaindoc SDK]\", ...args);\n }\n }\n}\n\n/**\n * Type guard to check if a message is from Chaindoc iframe\n */\nexport function isChaindocMessage(\n message: unknown\n): message is { source: \"chaindoc-embed\" } {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"source\" in message &&\n message.source === \"chaindoc-embed\"\n );\n}\n","/**\n * CSS-in-JS styles for modal and inline modes\n */\n\n/**\n * Get styles for modal overlay\n */\nexport function getOverlayStyles(zIndex: number): string {\n return `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${zIndex};\n padding: 20px;\n `.trim();\n}\n\n/**\n * Get styles for modal container\n */\nexport function getModalContainerStyles(\n width?: number,\n height?: number\n): string {\n const modalWidth = width ?? 450;\n const modalHeight = height ?? 850;\n\n return `\n position: relative;\n width: 100%;\n max-width: ${modalWidth}px;\n height: ${modalHeight}px;\n max-height: 90vh;\n background: white;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n `.trim();\n}\n\n/**\n * Get styles for iframe (common for both modal and inline)\n */\nexport function getIframeStyles(mode: \"modal\" | \"inline\"): string {\n const baseStyles = `\n width: 100%;\n border: none;\n display: block;\n `.trim();\n\n if (mode === \"modal\") {\n return `\n ${baseStyles}\n height: 100%;\n min-height: 400px;\n `.trim();\n }\n\n // Inline mode\n return `\n ${baseStyles}\n height: 0;\n `.trim();\n}\n\n/**\n * Get styles for inline container wrapper\n */\nexport function getInlineContainerStyles(): string {\n return `\n position: relative;\n width: 100%;\n `.trim();\n}\n","/**\n * Instance class for managing individual signature flows\n */\n\nimport type {\n SignatureFlowOptions,\n Theme,\n IframeToSdkMessage,\n SdkToIframeMessage,\n InstanceState,\n Environment,\n} from './types';\nimport {\n getIframeBaseUrl,\n getAllowedOrigin,\n buildIframeUrl,\n resolveContainer,\n isChaindocMessage,\n Logger,\n} from './utils';\nimport {\n getOverlayStyles,\n getModalContainerStyles,\n getIframeStyles,\n getInlineContainerStyles,\n} from './styles';\n\n/**\n * Internal config interface for EmbedInstance\n */\ninterface InternalConfig {\n publicKey: string;\n environment: Environment;\n debug: boolean;\n}\n\ntype InternalEventHandler = () => void;\n\n/**\n * Represents a single signature flow instance\n *\n * @example\n * ```typescript\n * const instance = sdk.openSignatureFlow({ sessionId: 'ses_xxx' });\n * instance.changeTheme('dark');\n * instance.close();\n * ```\n */\nexport class EmbedInstance {\n private config: InternalConfig;\n private options: SignatureFlowOptions;\n private logger: Logger;\n\n private state: InstanceState;\n private iframe: HTMLIFrameElement;\n private overlay: HTMLDivElement | null = null;\n private modalContainer: HTMLDivElement | null = null;\n private container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private isFullscreen: boolean = false;\n private previousIframeStyle: string | null = null;\n\n private internalEventHandlers: Map<string, Set<InternalEventHandler>> = new Map();\n\n constructor(\n config: InternalConfig,\n options: SignatureFlowOptions,\n logger: Logger\n ) {\n this.config = config;\n this.logger = logger;\n\n // Store options\n this.options = options;\n\n // Initialize state\n this.state = {\n sessionId: this.options.sessionId,\n mode: this.options.mode || 'modal',\n theme: this.options.theme || 'light',\n isReady: false,\n isClosed: false,\n hasSucceeded: false,\n };\n\n // Calculate allowed origin\n const baseUrl = getIframeBaseUrl(this.config.environment);\n this.allowedOrigin = getAllowedOrigin(this.config.environment);\n\n // Build iframe URL\n const iframeUrl = buildIframeUrl(\n baseUrl,\n this.options.sessionId,\n this.options.email,\n this.state.mode,\n this.state.theme,\n this.options.language,\n this.options.closeOnEscape\n );\n\n // Create iframe\n this.iframe = this.createIframe(iframeUrl);\n\n // Setup message listener\n this.messageListener = this.handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n\n // Render based on mode\n if (this.state.mode === 'modal') {\n this.renderModal();\n } else {\n this.renderInline();\n }\n\n this.logger.log('Instance created', { sessionId: this.state.sessionId, mode: this.state.mode });\n }\n\n /**\n * Create iframe element\n */\n private createIframe(url: string): HTMLIFrameElement {\n const iframe = document.createElement('iframe');\n iframe.src = url;\n iframe.setAttribute('style', getIframeStyles(this.state.mode));\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads'\n );\n // Permissions for KYC verification (camera/microphone for liveness check, geolocation optional)\n iframe.setAttribute('allow', 'clipboard-write; camera; microphone; geolocation');\n return iframe;\n }\n\n /**\n * Render modal mode\n */\n private renderModal(): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.setAttribute('style', getOverlayStyles(this.options.zIndex ?? 999999));\n this.overlay.setAttribute('data-chaindoc-overlay', 'true');\n\n // Create modal container\n this.modalContainer = document.createElement('div');\n this.modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n this.modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(this.modalContainer);\n\n // Click outside to cancel and close (configurable, default: true)\n if (this.options.closeOnClickOutside !== false) {\n this.overlay.addEventListener('click', (e) => {\n if (e.target === this.overlay) {\n this.logger.log('Clicked outside modal - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n });\n }\n\n // ESC key to cancel and close (configurable, default: true)\n if (this.options.closeOnEscape !== false) {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.logger.log('ESC key pressed - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n };\n document.addEventListener('keydown', handleEscape);\n\n // Store cleanup\n this._internalOn('close', () => {\n document.removeEventListener('keydown', handleEscape);\n });\n }\n\n // Lock body scroll (preserve previous value for restoration)\n this.previousOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n // Append to body\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Render inline mode\n */\n private renderInline(): void {\n if (!this.options.container) {\n throw new Error('Container is required for inline mode');\n }\n\n // Resolve container\n this.container = resolveContainer(this.options.container);\n\n // Create wrapper\n const wrapper = document.createElement('div');\n wrapper.setAttribute('style', getInlineContainerStyles());\n wrapper.setAttribute('data-chaindoc-inline', 'true');\n wrapper.appendChild(this.iframe);\n\n // Inject into container\n this.container.appendChild(wrapper);\n }\n\n /**\n * Handle incoming postMessage events\n */\n private handleMessage(event: MessageEvent): void {\n // Validate origin and source (ensure message comes from our iframe, not another iframe with same origin)\n if (event.origin !== this.allowedOrigin || event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Validate message structure\n if (!isChaindocMessage(event.data)) {\n return;\n }\n\n const message = event.data as IframeToSdkMessage;\n this.logger.log('Received message:', message.type, message);\n\n // Handle message by type\n switch (message.type) {\n case 'READY':\n this.state.isReady = true;\n this.options.onReady?.();\n break;\n\n case 'RESIZE':\n if ('data' in message && !this.isFullscreen) {\n this.iframe.style.height = `${message.data.height}px`;\n }\n break;\n\n case 'SUCCESS':\n this.state.hasSucceeded = true;\n if ('data' in message) {\n this.options.onSuccess?.(message.data);\n }\n break;\n\n case 'ERROR':\n if ('data' in message) {\n this.options.onError?.(message.data);\n }\n break;\n\n case 'CANCEL':\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n break;\n\n case 'CLOSED':\n this.cleanup();\n break;\n\n case 'RESEND_OTP':\n if ('data' in message) {\n this.options.onResendOtp?.(message.data);\n }\n break;\n\n case 'REQUEST_FULLSCREEN':\n this.enterFullscreen();\n break;\n\n case 'EXIT_FULLSCREEN':\n this.exitFullscreen();\n break;\n\n default:\n this.logger.warn('Unknown message type:', message);\n }\n }\n\n /**\n * Expand iframe to cover the entire parent viewport.\n * Works uniformly in modal and inline modes, including iOS Safari\n * (does not rely on the native Fullscreen API).\n *\n * Parent body.overflow is intentionally NOT modified here: it is brittle\n * (easy to leak a `hidden` lock back to the host page if the restore path\n * is missed). Scroll-chaining from the fullscreen iframe is handled inside\n * the iframe itself via `overscroll-behavior: contain` on the scroll area.\n */\n private enterFullscreen(): void {\n if (this.isFullscreen || this.state.isClosed) {\n return;\n }\n\n this.logger.log('Entering fullscreen');\n\n this.previousIframeStyle = this.iframe.getAttribute('style');\n\n this.iframe.setAttribute(\n 'style',\n `\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n max-width: none;\n max-height: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n padding: 0;\n display: block;\n z-index: 2147483647;\n `.trim()\n );\n\n this.isFullscreen = true;\n }\n\n /**\n * Restore iframe to its previous size and position.\n */\n private exitFullscreen(): void {\n if (!this.isFullscreen) {\n return;\n }\n\n this.logger.log('Exiting fullscreen');\n\n if (this.previousIframeStyle !== null) {\n this.iframe.setAttribute('style', this.previousIframeStyle);\n } else {\n this.iframe.removeAttribute('style');\n }\n this.previousIframeStyle = null;\n\n this.isFullscreen = false;\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: SdkToIframeMessage): void {\n if (!this.iframe.contentWindow) {\n this.logger.error('Cannot send message: iframe contentWindow not available');\n return;\n }\n\n this.iframe.contentWindow.postMessage(message, this.allowedOrigin);\n this.logger.log('Sent message to iframe:', message.type);\n }\n\n /**\n * Close the signature flow\n */\n close(): void {\n if (this.state.isClosed) {\n this.logger.warn('Instance already closed');\n return;\n }\n\n this.logger.log('Closing instance');\n\n // Send CLOSE message to iframe\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'CLOSE',\n });\n\n // Force cleanup after timeout if iframe doesn't respond\n setTimeout(() => {\n if (!this.state.isClosed) {\n this.logger.warn('Iframe did not respond to CLOSE, forcing cleanup');\n this.cleanup();\n }\n }, 3000);\n }\n\n /**\n * Change theme\n */\n changeTheme(theme: Theme): void {\n this.logger.log('Changing theme to:', theme);\n\n this.state.theme = theme;\n\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'THEME_CHANGE',\n data: { theme },\n });\n }\n\n /**\n * Check if iframe is ready\n */\n isReady(): boolean {\n return this.state.isReady;\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.state.sessionId;\n }\n\n /**\n * Internal event system (for cleanup tracking)\n * @internal\n */\n _internalOn(event: string, handler: InternalEventHandler): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n return;\n }\n\n this.internalEventHandlers.set(event, new Set([handler]));\n }\n\n private emit(event: string): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => handler());\n }\n }\n\n /**\n * Cleanup all resources\n */\n private cleanup(): void {\n if (this.state.isClosed) {\n return;\n }\n\n this.logger.log('Cleaning up instance');\n\n // Restore body overflow if we are destroyed while fullscreen is active\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.state.isClosed = true;\n\n // Remove message listener\n window.removeEventListener('message', this.messageListener);\n\n // Remove DOM elements\n if (this.overlay) {\n this.overlay.remove();\n document.body.style.overflow = this.previousOverflow;\n }\n\n if (this.container) {\n const wrapper = this.container.querySelector('[data-chaindoc-inline]');\n wrapper?.remove();\n }\n\n // Call onClose callback\n this.options.onClose?.();\n\n // Emit internal close event\n this.emit('close');\n\n // Clear internal handlers\n this.internalEventHandlers.clear();\n }\n}\n","/**\n * Main SDK class for Chaindoc Embed\n */\n\nimport { EmbedInstance } from \"./EmbedInstance\";\nimport type { ChaindocEmbedConfig, SignatureFlowOptions } from \"./types\";\nimport { Logger } from \"./utils\";\n\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Main entry point for Chaindoc Embed SDK\n *\n * @example\n * ```typescript\n * const sdk = new ChaindocEmbed({\n * publicKey: 'pk_test_xxx',\n * environment: 'development',\n * debug: true\n * });\n *\n * const instance = sdk.openSignatureFlow({\n * sessionId: 'ses_xxx',\n * onSuccess: (data) => console.log('Signed!', data)\n * });\n * ```\n */\n/**\n * Internal config type with defaults applied\n */\ninterface InternalConfig {\n publicKey: string;\n environment: \"production\" | \"staging\" | \"development\";\n debug: boolean;\n}\n\nexport class ChaindocEmbed {\n private config: InternalConfig;\n private logger: Logger;\n private instances: Set<EmbedInstance> = new Set();\n\n /**\n * Create a new ChaindocEmbed instance\n *\n * @param config - SDK configuration\n * @throws {Error} If publicKey is missing or invalid\n */\n constructor(config: ChaindocEmbedConfig) {\n // Validate required config\n if (!config.publicKey) {\n throw new Error(\"ChaindocEmbed: publicKey is required\");\n }\n\n if (!config.publicKey.startsWith(\"pk_\")) {\n throw new Error('ChaindocEmbed: publicKey must start with \"pk_\"');\n }\n\n // Set defaults\n this.config = {\n publicKey: config.publicKey,\n environment: config.environment || \"production\",\n debug: config.debug || false,\n };\n\n this.logger = new Logger(this.config.debug);\n this.logger.log(\"SDK initialized\", this.config);\n }\n\n /**\n * Open a signature flow\n *\n * @param options - Signature flow options\n * @returns EmbedInstance for controlling the flow\n * @throws {Error} If sessionId is missing or invalid\n * @throws {Error} If inline mode is used without container\n */\n openSignatureFlow(options: SignatureFlowOptions): EmbedInstance {\n // Validate required options\n if (!options.sessionId) {\n throw new Error(\"openSignatureFlow: sessionId is required\");\n }\n\n if (!options.sessionId.startsWith(\"ses_\")) {\n throw new Error('openSignatureFlow: sessionId must start with \"ses_\"');\n }\n\n const mode = options.mode || \"modal\";\n\n if (mode === \"inline\" && !options.container) {\n throw new Error(\n \"openSignatureFlow: container is required for inline mode\"\n );\n }\n\n this.logger.log(\"Opening signature flow\", options);\n\n // Create instance\n const instance = new EmbedInstance(this.config, options, this.logger);\n\n // Track instance\n this.instances.add(instance);\n\n // Remove from tracking when closed\n instance._internalOn(\"close\", () => {\n this.instances.delete(instance);\n });\n\n return instance;\n }\n\n /**\n * Destroy all instances and cleanup\n */\n destroy(): void {\n this.logger.log(\"Destroying SDK and all instances\");\n\n for (const instance of this.instances) {\n instance.close();\n }\n\n this.instances.clear();\n }\n\n /**\n * Get SDK version\n */\n static get version(): string {\n return __SDK_VERSION__;\n }\n}\n"],"mappings":"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","names":["src_exports","__export","ChaindocEmbed","EmbedInstance","getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","normalizedEmail","resolveContainer","container","element","Logger","debug","args","isChaindocMessage","message","getOverlayStyles","zIndex","getModalContainerStyles","width","height","getIframeStyles","mode","baseStyles","getInlineContainerStyles","EmbedInstance","config","options","logger","baseUrl","getIframeBaseUrl","getAllowedOrigin","iframeUrl","buildIframeUrl","url","iframe","getIframeStyles","getOverlayStyles","getModalContainerStyles","handleEscape","e","resolveContainer","wrapper","getInlineContainerStyles","event","isChaindocMessage","message","theme","handler","handlers","ChaindocEmbed","config","Logger","options","instance","EmbedInstance"]}

@@ -51,3 +51,3 @@ "use strict";var h=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var x=(i,e)=>{for(var t in e)h(i,t,{get:e[t],enumerable:!0})},M=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of C(e))!I.call(i,s)&&s!==t&&h(i,s,{get:()=>e[s],enumerable:!(n=S(e,s))||n.enumerable});return i};var O=i=>M(h({},"__esModule",{value:!0}),i);var k={};x(k,{ChaindocEmbed:()=>d,EmbedInstance:()=>o});module.exports=O(k);function c(i){switch(i){case"production":return"https://embed.chaindoc.io";case"staging":return"https://embed-demo.chaindoc.io";case"development":return"https://embed-demo.chaindoc.io";default:return"https://embed.chaindoc.io"}}function p(i){let e=c(i);try{return new URL(e).origin}catch{return e}}function u(i,e,t,n,s,a,g){let r=new URL(`/embed/sign/${e}`,i),m=t?.trim().toLowerCase();return m&&r.searchParams.set("email",m),n&&r.searchParams.set("mode",n),s&&r.searchParams.set("theme",s),a&&r.searchParams.set("lang",a),g!==void 0&&r.searchParams.set("closeOnEscape",String(g)),r.toString()}function f(i){if(typeof i=="string"){let e=document.querySelector(i);if(!e)throw new Error(`Container element not found: ${i}`);return e}return i}var l=class{constructor(e){this.debug=e}log(...e){this.debug&&console.log("[Chaindoc SDK]",...e)}warn(...e){this.debug&&console.warn("[Chaindoc SDK]",...e)}error(...e){this.debug&&console.error("[Chaindoc SDK]",...e)}};function v(i){return typeof i=="object"&&i!==null&&"source"in i&&i.source==="chaindoc-embed"}function b(i){return`

z-index: 2147483647;
`.trim()),this.isFullscreen=!0)}exitFullscreen(){this.isFullscreen&&(this.logger.log("Exiting fullscreen"),this.previousIframeStyle!==null?this.iframe.setAttribute("style",this.previousIframeStyle):this.iframe.removeAttribute("style"),this.previousIframeStyle=null,this.isFullscreen=!1)}sendMessage(e){if(!this.iframe.contentWindow){this.logger.error("Cannot send message: iframe contentWindow not available");return}this.iframe.contentWindow.postMessage(e,this.allowedOrigin),this.logger.log("Sent message to iframe:",e.type)}close(){if(this.state.isClosed){this.logger.warn("Instance already closed");return}this.logger.log("Closing instance"),this.sendMessage({source:"chaindoc-embed",type:"CLOSE"}),setTimeout(()=>{this.state.isClosed||(this.logger.warn("Iframe did not respond to CLOSE, forcing cleanup"),this.cleanup())},3e3)}changeTheme(e){this.logger.log("Changing theme to:",e),this.state.theme=e,this.sendMessage({source:"chaindoc-embed",type:"THEME_CHANGE",data:{theme:e}})}isReady(){return this.state.isReady}getSessionId(){return this.state.sessionId}_internalOn(e,t){let n=this.internalEventHandlers.get(e);if(n){n.add(t);return}this.internalEventHandlers.set(e,new Set([t]))}emit(e){let t=this.internalEventHandlers.get(e);t&&t.forEach(n=>n())}cleanup(){this.state.isClosed||(this.logger.log("Cleaning up instance"),this.isFullscreen&&this.exitFullscreen(),this.state.isClosed=!0,window.removeEventListener("message",this.messageListener),this.overlay&&(this.overlay.remove(),document.body.style.overflow=this.previousOverflow),this.container&&this.container.querySelector("[data-chaindoc-inline]")?.remove(),this.options.onClose?.(),this.emit("close"),this.internalEventHandlers.clear())}};var d=class{constructor(e){this.instances=new Set;if(!e.publicKey)throw new Error("ChaindocEmbed: publicKey is required");if(!e.publicKey.startsWith("pk_"))throw new Error('ChaindocEmbed: publicKey must start with "pk_"');this.config={publicKey:e.publicKey,environment:e.environment||"production",debug:e.debug||!1},this.logger=new l(this.config.debug),this.logger.log("SDK initialized",this.config)}openSignatureFlow(e){if(!e.sessionId)throw new Error("openSignatureFlow: sessionId is required");if(!e.sessionId.startsWith("ses_"))throw new Error('openSignatureFlow: sessionId must start with "ses_"');if((e.mode||"modal")==="inline"&&!e.container)throw new Error("openSignatureFlow: container is required for inline mode");this.logger.log("Opening signature flow",e);let n=new o(this.config,e,this.logger);return this.instances.add(n),n._internalOn("close",()=>{this.instances.delete(n)}),n}destroy(){this.logger.log("Destroying SDK and all instances");for(let e of this.instances)e.close();this.instances.clear()}static get version(){return"2.2.0-alpha.2"}};0&&(module.exports={ChaindocEmbed,EmbedInstance});
`.trim()),this.isFullscreen=!0)}exitFullscreen(){this.isFullscreen&&(this.logger.log("Exiting fullscreen"),this.previousIframeStyle!==null?this.iframe.setAttribute("style",this.previousIframeStyle):this.iframe.removeAttribute("style"),this.previousIframeStyle=null,this.isFullscreen=!1)}sendMessage(e){if(!this.iframe.contentWindow){this.logger.error("Cannot send message: iframe contentWindow not available");return}this.iframe.contentWindow.postMessage(e,this.allowedOrigin),this.logger.log("Sent message to iframe:",e.type)}close(){if(this.state.isClosed){this.logger.warn("Instance already closed");return}this.logger.log("Closing instance"),this.sendMessage({source:"chaindoc-embed",type:"CLOSE"}),setTimeout(()=>{this.state.isClosed||(this.logger.warn("Iframe did not respond to CLOSE, forcing cleanup"),this.cleanup())},3e3)}changeTheme(e){this.logger.log("Changing theme to:",e),this.state.theme=e,this.sendMessage({source:"chaindoc-embed",type:"THEME_CHANGE",data:{theme:e}})}isReady(){return this.state.isReady}getSessionId(){return this.state.sessionId}_internalOn(e,t){let n=this.internalEventHandlers.get(e);if(n){n.add(t);return}this.internalEventHandlers.set(e,new Set([t]))}emit(e){let t=this.internalEventHandlers.get(e);t&&t.forEach(n=>n())}cleanup(){this.state.isClosed||(this.logger.log("Cleaning up instance"),this.isFullscreen&&this.exitFullscreen(),this.state.isClosed=!0,window.removeEventListener("message",this.messageListener),this.overlay&&(this.overlay.remove(),document.body.style.overflow=this.previousOverflow),this.container&&this.container.querySelector("[data-chaindoc-inline]")?.remove(),this.options.onClose?.(),this.emit("close"),this.internalEventHandlers.clear())}};var d=class{constructor(e){this.instances=new Set;if(!e.publicKey)throw new Error("ChaindocEmbed: publicKey is required");if(!e.publicKey.startsWith("pk_"))throw new Error('ChaindocEmbed: publicKey must start with "pk_"');this.config={publicKey:e.publicKey,environment:e.environment||"production",debug:e.debug||!1},this.logger=new l(this.config.debug),this.logger.log("SDK initialized",this.config)}openSignatureFlow(e){if(!e.sessionId)throw new Error("openSignatureFlow: sessionId is required");if(!e.sessionId.startsWith("ses_"))throw new Error('openSignatureFlow: sessionId must start with "ses_"');if((e.mode||"modal")==="inline"&&!e.container)throw new Error("openSignatureFlow: container is required for inline mode");this.logger.log("Opening signature flow",e);let n=new o(this.config,e,this.logger);return this.instances.add(n),n._internalOn("close",()=>{this.instances.delete(n)}),n}destroy(){this.logger.log("Destroying SDK and all instances");for(let e of this.instances)e.close();this.instances.clear()}static get version(){return"2.2.0"}};0&&(module.exports={ChaindocEmbed,EmbedInstance});
//# sourceMappingURL=index.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/styles.ts","../src/EmbedInstance.ts","../src/ChaindocEmbed.ts"],"sourcesContent":["/**\n * @chaindoc/embed-sdk\n *\n * JavaScript/TypeScript SDK for embedding Chaindoc document signing flow via iframe.\n *\n * @packageDocumentation\n */\n\nexport { ChaindocEmbed } from \"./ChaindocEmbed\";\nexport { EmbedInstance } from \"./EmbedInstance\";\nexport type {\n ChaindocEmbedConfig,\n SignatureFlowOptions,\n Environment,\n DisplayMode,\n Theme,\n Language,\n SignatureSuccessData,\n SignatureErrorData,\n ResendOtpData,\n IframeToSdkMessage,\n SdkToIframeMessage,\n} from \"./types\";\n","/**\n * Utility functions for Chaindoc Embed SDK\n */\n\nimport type { DisplayMode, Environment } from \"./types\";\n\n/**\n * Get the iframe base URL based on environment\n */\nexport function getIframeBaseUrl(environment: Environment): string {\n switch (environment) {\n case \"production\":\n return \"https://embed.chaindoc.io\";\n case \"staging\":\n return \"https://embed-demo.chaindoc.io\";\n case \"development\":\n return \"https://embed-demo.chaindoc.io\";\n default:\n return \"https://embed.chaindoc.io\";\n }\n}\n\n/**\n * Get allowed origin for postMessage validation\n */\nexport function getAllowedOrigin(environment: Environment): string {\n const baseUrl = getIframeBaseUrl(environment);\n try {\n const url = new URL(baseUrl);\n return url.origin;\n } catch {\n return baseUrl;\n }\n}\n\n/**\n * Build iframe URL with query parameters\n */\nexport function buildIframeUrl(\n baseUrl: string,\n sessionId: string,\n email?: string,\n mode?: DisplayMode,\n theme?: string,\n language?: string,\n closeOnEscape?: boolean\n): string {\n // Session ID goes into the path, not as a query parameter\n const url = new URL(`/embed/sign/${sessionId}`, baseUrl);\n\n const normalizedEmail = email?.trim().toLowerCase();\n if (normalizedEmail) {\n url.searchParams.set(\"email\", normalizedEmail);\n }\n\n if (mode) {\n url.searchParams.set(\"mode\", mode);\n }\n\n if (theme) {\n url.searchParams.set(\"theme\", theme);\n }\n\n if (language) {\n url.searchParams.set(\"lang\", language);\n }\n\n if (closeOnEscape !== undefined) {\n url.searchParams.set(\"closeOnEscape\", String(closeOnEscape));\n }\n\n return url.toString();\n}\n\n/**\n * Resolve container element from HTMLElement or selector string\n */\nexport function resolveContainer(container: HTMLElement | string): HTMLElement {\n if (typeof container === \"string\") {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n return element;\n }\n return container;\n}\n\n/**\n * Debug logger (only logs when debug mode is enabled)\n */\nexport class Logger {\n constructor(private debug: boolean) {}\n\n log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (this.debug) {\n console.error(\"[Chaindoc SDK]\", ...args);\n }\n }\n}\n\n/**\n * Type guard to check if a message is from Chaindoc iframe\n */\nexport function isChaindocMessage(\n message: unknown\n): message is { source: \"chaindoc-embed\" } {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"source\" in message &&\n message.source === \"chaindoc-embed\"\n );\n}\n","/**\n * CSS-in-JS styles for modal and inline modes\n */\n\n/**\n * Get styles for modal overlay\n */\nexport function getOverlayStyles(zIndex: number): string {\n return `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${zIndex};\n padding: 20px;\n `.trim();\n}\n\n/**\n * Get styles for modal container\n */\nexport function getModalContainerStyles(\n width?: number,\n height?: number\n): string {\n const modalWidth = width ?? 450;\n const modalHeight = height ?? 850;\n\n return `\n position: relative;\n width: 100%;\n max-width: ${modalWidth}px;\n height: ${modalHeight}px;\n max-height: 90vh;\n background: white;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n `.trim();\n}\n\n/**\n * Get styles for iframe (common for both modal and inline)\n */\nexport function getIframeStyles(mode: \"modal\" | \"inline\"): string {\n const baseStyles = `\n width: 100%;\n border: none;\n display: block;\n `.trim();\n\n if (mode === \"modal\") {\n return `\n ${baseStyles}\n height: 100%;\n min-height: 400px;\n `.trim();\n }\n\n // Inline mode\n return `\n ${baseStyles}\n height: 0;\n `.trim();\n}\n\n/**\n * Get styles for inline container wrapper\n */\nexport function getInlineContainerStyles(): string {\n return `\n position: relative;\n width: 100%;\n `.trim();\n}\n","/**\n * Instance class for managing individual signature flows\n */\n\nimport type {\n SignatureFlowOptions,\n Theme,\n IframeToSdkMessage,\n SdkToIframeMessage,\n InstanceState,\n Environment,\n} from './types';\nimport {\n getIframeBaseUrl,\n getAllowedOrigin,\n buildIframeUrl,\n resolveContainer,\n isChaindocMessage,\n Logger,\n} from './utils';\nimport {\n getOverlayStyles,\n getModalContainerStyles,\n getIframeStyles,\n getInlineContainerStyles,\n} from './styles';\n\n/**\n * Internal config interface for EmbedInstance\n */\ninterface InternalConfig {\n publicKey: string;\n environment: Environment;\n debug: boolean;\n}\n\ntype InternalEventHandler = () => void;\n\n/**\n * Represents a single signature flow instance\n *\n * @example\n * ```typescript\n * const instance = sdk.openSignatureFlow({ sessionId: 'ses_xxx' });\n * instance.changeTheme('dark');\n * instance.close();\n * ```\n */\nexport class EmbedInstance {\n private config: InternalConfig;\n private options: SignatureFlowOptions;\n private logger: Logger;\n\n private state: InstanceState;\n private iframe: HTMLIFrameElement;\n private overlay: HTMLDivElement | null = null;\n private modalContainer: HTMLDivElement | null = null;\n private container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private isFullscreen: boolean = false;\n private previousIframeStyle: string | null = null;\n\n private internalEventHandlers: Map<string, Set<InternalEventHandler>> = new Map();\n\n constructor(\n config: InternalConfig,\n options: SignatureFlowOptions,\n logger: Logger\n ) {\n this.config = config;\n this.logger = logger;\n\n // Store options\n this.options = options;\n\n // Initialize state\n this.state = {\n sessionId: this.options.sessionId,\n mode: this.options.mode || 'modal',\n theme: this.options.theme || 'light',\n isReady: false,\n isClosed: false,\n hasSucceeded: false,\n };\n\n // Calculate allowed origin\n const baseUrl = getIframeBaseUrl(this.config.environment);\n this.allowedOrigin = getAllowedOrigin(this.config.environment);\n\n // Build iframe URL\n const iframeUrl = buildIframeUrl(\n baseUrl,\n this.options.sessionId,\n this.options.email,\n this.state.mode,\n this.state.theme,\n this.options.language,\n this.options.closeOnEscape\n );\n\n // Create iframe\n this.iframe = this.createIframe(iframeUrl);\n\n // Setup message listener\n this.messageListener = this.handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n\n // Render based on mode\n if (this.state.mode === 'modal') {\n this.renderModal();\n } else {\n this.renderInline();\n }\n\n this.logger.log('Instance created', { sessionId: this.state.sessionId, mode: this.state.mode });\n }\n\n /**\n * Create iframe element\n */\n private createIframe(url: string): HTMLIFrameElement {\n const iframe = document.createElement('iframe');\n iframe.src = url;\n iframe.setAttribute('style', getIframeStyles(this.state.mode));\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads'\n );\n // Permissions for KYC verification (camera/microphone for liveness check, geolocation optional)\n iframe.setAttribute('allow', 'clipboard-write; camera; microphone; geolocation');\n return iframe;\n }\n\n /**\n * Render modal mode\n */\n private renderModal(): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.setAttribute('style', getOverlayStyles(this.options.zIndex ?? 999999));\n this.overlay.setAttribute('data-chaindoc-overlay', 'true');\n\n // Create modal container\n this.modalContainer = document.createElement('div');\n this.modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n this.modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(this.modalContainer);\n\n // Click outside to cancel and close (configurable, default: true)\n if (this.options.closeOnClickOutside !== false) {\n this.overlay.addEventListener('click', (e) => {\n if (e.target === this.overlay) {\n this.logger.log('Clicked outside modal - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n });\n }\n\n // ESC key to cancel and close (configurable, default: true)\n if (this.options.closeOnEscape !== false) {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.logger.log('ESC key pressed - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n };\n document.addEventListener('keydown', handleEscape);\n\n // Store cleanup\n this._internalOn('close', () => {\n document.removeEventListener('keydown', handleEscape);\n });\n }\n\n // Lock body scroll (preserve previous value for restoration)\n this.previousOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n // Append to body\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Render inline mode\n */\n private renderInline(): void {\n if (!this.options.container) {\n throw new Error('Container is required for inline mode');\n }\n\n // Resolve container\n this.container = resolveContainer(this.options.container);\n\n // Create wrapper\n const wrapper = document.createElement('div');\n wrapper.setAttribute('style', getInlineContainerStyles());\n wrapper.setAttribute('data-chaindoc-inline', 'true');\n wrapper.appendChild(this.iframe);\n\n // Inject into container\n this.container.appendChild(wrapper);\n }\n\n /**\n * Handle incoming postMessage events\n */\n private handleMessage(event: MessageEvent): void {\n // Validate origin and source (ensure message comes from our iframe, not another iframe with same origin)\n if (event.origin !== this.allowedOrigin || event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Validate message structure\n if (!isChaindocMessage(event.data)) {\n return;\n }\n\n const message = event.data as IframeToSdkMessage;\n this.logger.log('Received message:', message.type, message);\n\n // Handle message by type\n switch (message.type) {\n case 'READY':\n this.state.isReady = true;\n this.options.onReady?.();\n break;\n\n case 'RESIZE':\n if ('data' in message && !this.isFullscreen) {\n this.iframe.style.height = `${message.data.height}px`;\n }\n break;\n\n case 'SUCCESS':\n this.state.hasSucceeded = true;\n if ('data' in message) {\n this.options.onSuccess?.(message.data);\n }\n break;\n\n case 'ERROR':\n if ('data' in message) {\n this.options.onError?.(message.data);\n }\n break;\n\n case 'CANCEL':\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n break;\n\n case 'CLOSED':\n this.cleanup();\n break;\n\n case 'RESEND_OTP':\n if ('data' in message) {\n this.options.onResendOtp?.(message.data);\n }\n break;\n\n case 'REQUEST_FULLSCREEN':\n this.enterFullscreen();\n break;\n\n case 'EXIT_FULLSCREEN':\n this.exitFullscreen();\n break;\n\n default:\n this.logger.warn('Unknown message type:', message);\n }\n }\n\n /**\n * Expand iframe to cover the entire parent viewport.\n * Works uniformly in modal and inline modes, including iOS Safari\n * (does not rely on the native Fullscreen API).\n *\n * Parent body.overflow is intentionally NOT modified here: it is brittle\n * (easy to leak a `hidden` lock back to the host page if the restore path\n * is missed). Scroll-chaining from the fullscreen iframe is handled inside\n * the iframe itself via `overscroll-behavior: contain` on the scroll area.\n */\n private enterFullscreen(): void {\n if (this.isFullscreen || this.state.isClosed) {\n return;\n }\n\n this.logger.log('Entering fullscreen');\n\n this.previousIframeStyle = this.iframe.getAttribute('style');\n\n this.iframe.setAttribute(\n 'style',\n `\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n max-width: none;\n max-height: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n padding: 0;\n display: block;\n z-index: 2147483647;\n `.trim()\n );\n\n this.isFullscreen = true;\n }\n\n /**\n * Restore iframe to its previous size and position.\n */\n private exitFullscreen(): void {\n if (!this.isFullscreen) {\n return;\n }\n\n this.logger.log('Exiting fullscreen');\n\n if (this.previousIframeStyle !== null) {\n this.iframe.setAttribute('style', this.previousIframeStyle);\n } else {\n this.iframe.removeAttribute('style');\n }\n this.previousIframeStyle = null;\n\n this.isFullscreen = false;\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: SdkToIframeMessage): void {\n if (!this.iframe.contentWindow) {\n this.logger.error('Cannot send message: iframe contentWindow not available');\n return;\n }\n\n this.iframe.contentWindow.postMessage(message, this.allowedOrigin);\n this.logger.log('Sent message to iframe:', message.type);\n }\n\n /**\n * Close the signature flow\n */\n close(): void {\n if (this.state.isClosed) {\n this.logger.warn('Instance already closed');\n return;\n }\n\n this.logger.log('Closing instance');\n\n // Send CLOSE message to iframe\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'CLOSE',\n });\n\n // Force cleanup after timeout if iframe doesn't respond\n setTimeout(() => {\n if (!this.state.isClosed) {\n this.logger.warn('Iframe did not respond to CLOSE, forcing cleanup');\n this.cleanup();\n }\n }, 3000);\n }\n\n /**\n * Change theme\n */\n changeTheme(theme: Theme): void {\n this.logger.log('Changing theme to:', theme);\n\n this.state.theme = theme;\n\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'THEME_CHANGE',\n data: { theme },\n });\n }\n\n /**\n * Check if iframe is ready\n */\n isReady(): boolean {\n return this.state.isReady;\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.state.sessionId;\n }\n\n /**\n * Internal event system (for cleanup tracking)\n * @internal\n */\n _internalOn(event: string, handler: InternalEventHandler): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n return;\n }\n\n this.internalEventHandlers.set(event, new Set([handler]));\n }\n\n private emit(event: string): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => handler());\n }\n }\n\n /**\n * Cleanup all resources\n */\n private cleanup(): void {\n if (this.state.isClosed) {\n return;\n }\n\n this.logger.log('Cleaning up instance');\n\n // Restore body overflow if we are destroyed while fullscreen is active\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.state.isClosed = true;\n\n // Remove message listener\n window.removeEventListener('message', this.messageListener);\n\n // Remove DOM elements\n if (this.overlay) {\n this.overlay.remove();\n document.body.style.overflow = this.previousOverflow;\n }\n\n if (this.container) {\n const wrapper = this.container.querySelector('[data-chaindoc-inline]');\n wrapper?.remove();\n }\n\n // Call onClose callback\n this.options.onClose?.();\n\n // Emit internal close event\n this.emit('close');\n\n // Clear internal handlers\n this.internalEventHandlers.clear();\n }\n}\n","/**\n * Main SDK class for Chaindoc Embed\n */\n\nimport { EmbedInstance } from \"./EmbedInstance\";\nimport type { ChaindocEmbedConfig, SignatureFlowOptions } from \"./types\";\nimport { Logger } from \"./utils\";\n\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Main entry point for Chaindoc Embed SDK\n *\n * @example\n * ```typescript\n * const sdk = new ChaindocEmbed({\n * publicKey: 'pk_test_xxx',\n * environment: 'development',\n * debug: true\n * });\n *\n * const instance = sdk.openSignatureFlow({\n * sessionId: 'ses_xxx',\n * onSuccess: (data) => console.log('Signed!', data)\n * });\n * ```\n */\n/**\n * Internal config type with defaults applied\n */\ninterface InternalConfig {\n publicKey: string;\n environment: \"production\" | \"staging\" | \"development\";\n debug: boolean;\n}\n\nexport class ChaindocEmbed {\n private config: InternalConfig;\n private logger: Logger;\n private instances: Set<EmbedInstance> = new Set();\n\n /**\n * Create a new ChaindocEmbed instance\n *\n * @param config - SDK configuration\n * @throws {Error} If publicKey is missing or invalid\n */\n constructor(config: ChaindocEmbedConfig) {\n // Validate required config\n if (!config.publicKey) {\n throw new Error(\"ChaindocEmbed: publicKey is required\");\n }\n\n if (!config.publicKey.startsWith(\"pk_\")) {\n throw new Error('ChaindocEmbed: publicKey must start with \"pk_\"');\n }\n\n // Set defaults\n this.config = {\n publicKey: config.publicKey,\n environment: config.environment || \"production\",\n debug: config.debug || false,\n };\n\n this.logger = new Logger(this.config.debug);\n this.logger.log(\"SDK initialized\", this.config);\n }\n\n /**\n * Open a signature flow\n *\n * @param options - Signature flow options\n * @returns EmbedInstance for controlling the flow\n * @throws {Error} If sessionId is missing or invalid\n * @throws {Error} If inline mode is used without container\n */\n openSignatureFlow(options: SignatureFlowOptions): EmbedInstance {\n // Validate required options\n if (!options.sessionId) {\n throw new Error(\"openSignatureFlow: sessionId is required\");\n }\n\n if (!options.sessionId.startsWith(\"ses_\")) {\n throw new Error('openSignatureFlow: sessionId must start with \"ses_\"');\n }\n\n const mode = options.mode || \"modal\";\n\n if (mode === \"inline\" && !options.container) {\n throw new Error(\n \"openSignatureFlow: container is required for inline mode\"\n );\n }\n\n this.logger.log(\"Opening signature flow\", options);\n\n // Create instance\n const instance = new EmbedInstance(this.config, options, this.logger);\n\n // Track instance\n this.instances.add(instance);\n\n // Remove from tracking when closed\n instance._internalOn(\"close\", () => {\n this.instances.delete(instance);\n });\n\n return instance;\n }\n\n /**\n * Destroy all instances and cleanup\n */\n destroy(): void {\n this.logger.log(\"Destroying SDK and all instances\");\n\n for (const instance of this.instances) {\n instance.close();\n }\n\n this.instances.clear();\n }\n\n /**\n * Get SDK version\n */\n static get version(): string {\n return __SDK_VERSION__;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","ChaindocEmbed","EmbedInstance","__toCommonJS","getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","normalizedEmail","resolveContainer","container","element","Logger","debug","args","isChaindocMessage","message","getOverlayStyles","zIndex","getModalContainerStyles","width","height","getIframeStyles","mode","baseStyles","getInlineContainerStyles","EmbedInstance","config","options","logger","baseUrl","getIframeBaseUrl","getAllowedOrigin","iframeUrl","buildIframeUrl","url","iframe","getIframeStyles","getOverlayStyles","getModalContainerStyles","handleEscape","e","resolveContainer","wrapper","getInlineContainerStyles","event","isChaindocMessage","message","theme","handler","handlers","ChaindocEmbed","config","Logger","options","instance","EmbedInstance"]}
{"version":3,"sources":["../src/index.ts","../src/utils.ts","../src/styles.ts","../src/EmbedInstance.ts","../src/ChaindocEmbed.ts"],"sourcesContent":["/**\n * @chaindoc/embed-sdk\n *\n * JavaScript/TypeScript SDK for embedding Chaindoc document signing flow via iframe.\n *\n * @packageDocumentation\n */\n\nexport { ChaindocEmbed } from \"./ChaindocEmbed\";\nexport { EmbedInstance } from \"./EmbedInstance\";\nexport type {\n ChaindocEmbedConfig,\n SignatureFlowOptions,\n Environment,\n DisplayMode,\n Theme,\n Language,\n SignatureSuccessData,\n SignatureErrorData,\n ResendOtpData,\n IframeToSdkMessage,\n SdkToIframeMessage,\n} from \"./types\";\n","/**\n * Utility functions for Chaindoc Embed SDK\n */\n\nimport type { DisplayMode, Environment } from \"./types\";\n\n/**\n * Get the iframe base URL based on environment\n */\nexport function getIframeBaseUrl(environment: Environment): string {\n switch (environment) {\n case \"production\":\n return \"https://embed.chaindoc.io\";\n case \"staging\":\n return \"https://embed-demo.chaindoc.io\";\n case \"development\":\n return \"https://embed-demo.chaindoc.io\";\n default:\n return \"https://embed.chaindoc.io\";\n }\n}\n\n/**\n * Get allowed origin for postMessage validation\n */\nexport function getAllowedOrigin(environment: Environment): string {\n const baseUrl = getIframeBaseUrl(environment);\n try {\n const url = new URL(baseUrl);\n return url.origin;\n } catch {\n return baseUrl;\n }\n}\n\n/**\n * Build iframe URL with query parameters\n */\nexport function buildIframeUrl(\n baseUrl: string,\n sessionId: string,\n email?: string,\n mode?: DisplayMode,\n theme?: string,\n language?: string,\n closeOnEscape?: boolean\n): string {\n // Session ID goes into the path, not as a query parameter\n const url = new URL(`/embed/sign/${sessionId}`, baseUrl);\n\n const normalizedEmail = email?.trim().toLowerCase();\n if (normalizedEmail) {\n url.searchParams.set(\"email\", normalizedEmail);\n }\n\n if (mode) {\n url.searchParams.set(\"mode\", mode);\n }\n\n if (theme) {\n url.searchParams.set(\"theme\", theme);\n }\n\n if (language) {\n url.searchParams.set(\"lang\", language);\n }\n\n if (closeOnEscape !== undefined) {\n url.searchParams.set(\"closeOnEscape\", String(closeOnEscape));\n }\n\n return url.toString();\n}\n\n/**\n * Resolve container element from HTMLElement or selector string\n */\nexport function resolveContainer(container: HTMLElement | string): HTMLElement {\n if (typeof container === \"string\") {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n return element;\n }\n return container;\n}\n\n/**\n * Debug logger (only logs when debug mode is enabled)\n */\nexport class Logger {\n constructor(private debug: boolean) {}\n\n log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (this.debug) {\n console.error(\"[Chaindoc SDK]\", ...args);\n }\n }\n}\n\n/**\n * Type guard to check if a message is from Chaindoc iframe\n */\nexport function isChaindocMessage(\n message: unknown\n): message is { source: \"chaindoc-embed\" } {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"source\" in message &&\n message.source === \"chaindoc-embed\"\n );\n}\n","/**\n * CSS-in-JS styles for modal and inline modes\n */\n\n/**\n * Get styles for modal overlay\n */\nexport function getOverlayStyles(zIndex: number): string {\n return `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${zIndex};\n padding: 20px;\n `.trim();\n}\n\n/**\n * Get styles for modal container\n */\nexport function getModalContainerStyles(\n width?: number,\n height?: number\n): string {\n const modalWidth = width ?? 450;\n const modalHeight = height ?? 850;\n\n return `\n position: relative;\n width: 100%;\n max-width: ${modalWidth}px;\n height: ${modalHeight}px;\n max-height: 90vh;\n background: white;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n `.trim();\n}\n\n/**\n * Get styles for iframe (common for both modal and inline)\n */\nexport function getIframeStyles(mode: \"modal\" | \"inline\"): string {\n const baseStyles = `\n width: 100%;\n border: none;\n display: block;\n `.trim();\n\n if (mode === \"modal\") {\n return `\n ${baseStyles}\n height: 100%;\n min-height: 400px;\n `.trim();\n }\n\n // Inline mode\n return `\n ${baseStyles}\n height: 0;\n `.trim();\n}\n\n/**\n * Get styles for inline container wrapper\n */\nexport function getInlineContainerStyles(): string {\n return `\n position: relative;\n width: 100%;\n `.trim();\n}\n","/**\n * Instance class for managing individual signature flows\n */\n\nimport type {\n SignatureFlowOptions,\n Theme,\n IframeToSdkMessage,\n SdkToIframeMessage,\n InstanceState,\n Environment,\n} from './types';\nimport {\n getIframeBaseUrl,\n getAllowedOrigin,\n buildIframeUrl,\n resolveContainer,\n isChaindocMessage,\n Logger,\n} from './utils';\nimport {\n getOverlayStyles,\n getModalContainerStyles,\n getIframeStyles,\n getInlineContainerStyles,\n} from './styles';\n\n/**\n * Internal config interface for EmbedInstance\n */\ninterface InternalConfig {\n publicKey: string;\n environment: Environment;\n debug: boolean;\n}\n\ntype InternalEventHandler = () => void;\n\n/**\n * Represents a single signature flow instance\n *\n * @example\n * ```typescript\n * const instance = sdk.openSignatureFlow({ sessionId: 'ses_xxx' });\n * instance.changeTheme('dark');\n * instance.close();\n * ```\n */\nexport class EmbedInstance {\n private config: InternalConfig;\n private options: SignatureFlowOptions;\n private logger: Logger;\n\n private state: InstanceState;\n private iframe: HTMLIFrameElement;\n private overlay: HTMLDivElement | null = null;\n private modalContainer: HTMLDivElement | null = null;\n private container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private isFullscreen: boolean = false;\n private previousIframeStyle: string | null = null;\n\n private internalEventHandlers: Map<string, Set<InternalEventHandler>> = new Map();\n\n constructor(\n config: InternalConfig,\n options: SignatureFlowOptions,\n logger: Logger\n ) {\n this.config = config;\n this.logger = logger;\n\n // Store options\n this.options = options;\n\n // Initialize state\n this.state = {\n sessionId: this.options.sessionId,\n mode: this.options.mode || 'modal',\n theme: this.options.theme || 'light',\n isReady: false,\n isClosed: false,\n hasSucceeded: false,\n };\n\n // Calculate allowed origin\n const baseUrl = getIframeBaseUrl(this.config.environment);\n this.allowedOrigin = getAllowedOrigin(this.config.environment);\n\n // Build iframe URL\n const iframeUrl = buildIframeUrl(\n baseUrl,\n this.options.sessionId,\n this.options.email,\n this.state.mode,\n this.state.theme,\n this.options.language,\n this.options.closeOnEscape\n );\n\n // Create iframe\n this.iframe = this.createIframe(iframeUrl);\n\n // Setup message listener\n this.messageListener = this.handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n\n // Render based on mode\n if (this.state.mode === 'modal') {\n this.renderModal();\n } else {\n this.renderInline();\n }\n\n this.logger.log('Instance created', { sessionId: this.state.sessionId, mode: this.state.mode });\n }\n\n /**\n * Create iframe element\n */\n private createIframe(url: string): HTMLIFrameElement {\n const iframe = document.createElement('iframe');\n iframe.src = url;\n iframe.setAttribute('style', getIframeStyles(this.state.mode));\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads'\n );\n // Permissions for KYC verification (camera/microphone for liveness check, geolocation optional)\n iframe.setAttribute('allow', 'clipboard-write; camera; microphone; geolocation');\n return iframe;\n }\n\n /**\n * Render modal mode\n */\n private renderModal(): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.setAttribute('style', getOverlayStyles(this.options.zIndex ?? 999999));\n this.overlay.setAttribute('data-chaindoc-overlay', 'true');\n\n // Create modal container\n this.modalContainer = document.createElement('div');\n this.modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n this.modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(this.modalContainer);\n\n // Click outside to cancel and close (configurable, default: true)\n if (this.options.closeOnClickOutside !== false) {\n this.overlay.addEventListener('click', (e) => {\n if (e.target === this.overlay) {\n this.logger.log('Clicked outside modal - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n });\n }\n\n // ESC key to cancel and close (configurable, default: true)\n if (this.options.closeOnEscape !== false) {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.logger.log('ESC key pressed - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n };\n document.addEventListener('keydown', handleEscape);\n\n // Store cleanup\n this._internalOn('close', () => {\n document.removeEventListener('keydown', handleEscape);\n });\n }\n\n // Lock body scroll (preserve previous value for restoration)\n this.previousOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n // Append to body\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Render inline mode\n */\n private renderInline(): void {\n if (!this.options.container) {\n throw new Error('Container is required for inline mode');\n }\n\n // Resolve container\n this.container = resolveContainer(this.options.container);\n\n // Create wrapper\n const wrapper = document.createElement('div');\n wrapper.setAttribute('style', getInlineContainerStyles());\n wrapper.setAttribute('data-chaindoc-inline', 'true');\n wrapper.appendChild(this.iframe);\n\n // Inject into container\n this.container.appendChild(wrapper);\n }\n\n /**\n * Handle incoming postMessage events\n */\n private handleMessage(event: MessageEvent): void {\n // Validate origin and source (ensure message comes from our iframe, not another iframe with same origin)\n if (event.origin !== this.allowedOrigin || event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Validate message structure\n if (!isChaindocMessage(event.data)) {\n return;\n }\n\n const message = event.data as IframeToSdkMessage;\n this.logger.log('Received message:', message.type, message);\n\n // Handle message by type\n switch (message.type) {\n case 'READY':\n this.state.isReady = true;\n this.options.onReady?.();\n break;\n\n case 'RESIZE':\n if ('data' in message && !this.isFullscreen) {\n this.iframe.style.height = `${message.data.height}px`;\n }\n break;\n\n case 'SUCCESS':\n this.state.hasSucceeded = true;\n if ('data' in message) {\n this.options.onSuccess?.(message.data);\n }\n break;\n\n case 'ERROR':\n if ('data' in message) {\n this.options.onError?.(message.data);\n }\n break;\n\n case 'CANCEL':\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n break;\n\n case 'CLOSED':\n this.cleanup();\n break;\n\n case 'RESEND_OTP':\n if ('data' in message) {\n this.options.onResendOtp?.(message.data);\n }\n break;\n\n case 'REQUEST_FULLSCREEN':\n this.enterFullscreen();\n break;\n\n case 'EXIT_FULLSCREEN':\n this.exitFullscreen();\n break;\n\n default:\n this.logger.warn('Unknown message type:', message);\n }\n }\n\n /**\n * Expand iframe to cover the entire parent viewport.\n * Works uniformly in modal and inline modes, including iOS Safari\n * (does not rely on the native Fullscreen API).\n *\n * Parent body.overflow is intentionally NOT modified here: it is brittle\n * (easy to leak a `hidden` lock back to the host page if the restore path\n * is missed). Scroll-chaining from the fullscreen iframe is handled inside\n * the iframe itself via `overscroll-behavior: contain` on the scroll area.\n */\n private enterFullscreen(): void {\n if (this.isFullscreen || this.state.isClosed) {\n return;\n }\n\n this.logger.log('Entering fullscreen');\n\n this.previousIframeStyle = this.iframe.getAttribute('style');\n\n this.iframe.setAttribute(\n 'style',\n `\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n max-width: none;\n max-height: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n padding: 0;\n display: block;\n z-index: 2147483647;\n `.trim()\n );\n\n this.isFullscreen = true;\n }\n\n /**\n * Restore iframe to its previous size and position.\n */\n private exitFullscreen(): void {\n if (!this.isFullscreen) {\n return;\n }\n\n this.logger.log('Exiting fullscreen');\n\n if (this.previousIframeStyle !== null) {\n this.iframe.setAttribute('style', this.previousIframeStyle);\n } else {\n this.iframe.removeAttribute('style');\n }\n this.previousIframeStyle = null;\n\n this.isFullscreen = false;\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: SdkToIframeMessage): void {\n if (!this.iframe.contentWindow) {\n this.logger.error('Cannot send message: iframe contentWindow not available');\n return;\n }\n\n this.iframe.contentWindow.postMessage(message, this.allowedOrigin);\n this.logger.log('Sent message to iframe:', message.type);\n }\n\n /**\n * Close the signature flow\n */\n close(): void {\n if (this.state.isClosed) {\n this.logger.warn('Instance already closed');\n return;\n }\n\n this.logger.log('Closing instance');\n\n // Send CLOSE message to iframe\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'CLOSE',\n });\n\n // Force cleanup after timeout if iframe doesn't respond\n setTimeout(() => {\n if (!this.state.isClosed) {\n this.logger.warn('Iframe did not respond to CLOSE, forcing cleanup');\n this.cleanup();\n }\n }, 3000);\n }\n\n /**\n * Change theme\n */\n changeTheme(theme: Theme): void {\n this.logger.log('Changing theme to:', theme);\n\n this.state.theme = theme;\n\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'THEME_CHANGE',\n data: { theme },\n });\n }\n\n /**\n * Check if iframe is ready\n */\n isReady(): boolean {\n return this.state.isReady;\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.state.sessionId;\n }\n\n /**\n * Internal event system (for cleanup tracking)\n * @internal\n */\n _internalOn(event: string, handler: InternalEventHandler): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n return;\n }\n\n this.internalEventHandlers.set(event, new Set([handler]));\n }\n\n private emit(event: string): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => handler());\n }\n }\n\n /**\n * Cleanup all resources\n */\n private cleanup(): void {\n if (this.state.isClosed) {\n return;\n }\n\n this.logger.log('Cleaning up instance');\n\n // Restore body overflow if we are destroyed while fullscreen is active\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.state.isClosed = true;\n\n // Remove message listener\n window.removeEventListener('message', this.messageListener);\n\n // Remove DOM elements\n if (this.overlay) {\n this.overlay.remove();\n document.body.style.overflow = this.previousOverflow;\n }\n\n if (this.container) {\n const wrapper = this.container.querySelector('[data-chaindoc-inline]');\n wrapper?.remove();\n }\n\n // Call onClose callback\n this.options.onClose?.();\n\n // Emit internal close event\n this.emit('close');\n\n // Clear internal handlers\n this.internalEventHandlers.clear();\n }\n}\n","/**\n * Main SDK class for Chaindoc Embed\n */\n\nimport { EmbedInstance } from \"./EmbedInstance\";\nimport type { ChaindocEmbedConfig, SignatureFlowOptions } from \"./types\";\nimport { Logger } from \"./utils\";\n\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Main entry point for Chaindoc Embed SDK\n *\n * @example\n * ```typescript\n * const sdk = new ChaindocEmbed({\n * publicKey: 'pk_test_xxx',\n * environment: 'development',\n * debug: true\n * });\n *\n * const instance = sdk.openSignatureFlow({\n * sessionId: 'ses_xxx',\n * onSuccess: (data) => console.log('Signed!', data)\n * });\n * ```\n */\n/**\n * Internal config type with defaults applied\n */\ninterface InternalConfig {\n publicKey: string;\n environment: \"production\" | \"staging\" | \"development\";\n debug: boolean;\n}\n\nexport class ChaindocEmbed {\n private config: InternalConfig;\n private logger: Logger;\n private instances: Set<EmbedInstance> = new Set();\n\n /**\n * Create a new ChaindocEmbed instance\n *\n * @param config - SDK configuration\n * @throws {Error} If publicKey is missing or invalid\n */\n constructor(config: ChaindocEmbedConfig) {\n // Validate required config\n if (!config.publicKey) {\n throw new Error(\"ChaindocEmbed: publicKey is required\");\n }\n\n if (!config.publicKey.startsWith(\"pk_\")) {\n throw new Error('ChaindocEmbed: publicKey must start with \"pk_\"');\n }\n\n // Set defaults\n this.config = {\n publicKey: config.publicKey,\n environment: config.environment || \"production\",\n debug: config.debug || false,\n };\n\n this.logger = new Logger(this.config.debug);\n this.logger.log(\"SDK initialized\", this.config);\n }\n\n /**\n * Open a signature flow\n *\n * @param options - Signature flow options\n * @returns EmbedInstance for controlling the flow\n * @throws {Error} If sessionId is missing or invalid\n * @throws {Error} If inline mode is used without container\n */\n openSignatureFlow(options: SignatureFlowOptions): EmbedInstance {\n // Validate required options\n if (!options.sessionId) {\n throw new Error(\"openSignatureFlow: sessionId is required\");\n }\n\n if (!options.sessionId.startsWith(\"ses_\")) {\n throw new Error('openSignatureFlow: sessionId must start with \"ses_\"');\n }\n\n const mode = options.mode || \"modal\";\n\n if (mode === \"inline\" && !options.container) {\n throw new Error(\n \"openSignatureFlow: container is required for inline mode\"\n );\n }\n\n this.logger.log(\"Opening signature flow\", options);\n\n // Create instance\n const instance = new EmbedInstance(this.config, options, this.logger);\n\n // Track instance\n this.instances.add(instance);\n\n // Remove from tracking when closed\n instance._internalOn(\"close\", () => {\n this.instances.delete(instance);\n });\n\n return instance;\n }\n\n /**\n * Destroy all instances and cleanup\n */\n destroy(): void {\n this.logger.log(\"Destroying SDK and all instances\");\n\n for (const instance of this.instances) {\n instance.close();\n }\n\n this.instances.clear();\n }\n\n /**\n * Get SDK version\n */\n static get version(): string {\n return __SDK_VERSION__;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","ChaindocEmbed","EmbedInstance","__toCommonJS","getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","normalizedEmail","resolveContainer","container","element","Logger","debug","args","isChaindocMessage","message","getOverlayStyles","zIndex","getModalContainerStyles","width","height","getIframeStyles","mode","baseStyles","getInlineContainerStyles","EmbedInstance","config","options","logger","baseUrl","getIframeBaseUrl","getAllowedOrigin","iframeUrl","buildIframeUrl","url","iframe","getIframeStyles","getOverlayStyles","getModalContainerStyles","handleEscape","e","resolveContainer","wrapper","getInlineContainerStyles","event","isChaindocMessage","message","theme","handler","handlers","ChaindocEmbed","config","Logger","options","instance","EmbedInstance"]}

@@ -51,3 +51,3 @@ function d(i){switch(i){case"production":return"https://embed.chaindoc.io";case"staging":return"https://embed-demo.chaindoc.io";case"development":return"https://embed-demo.chaindoc.io";default:return"https://embed.chaindoc.io"}}function m(i){let e=d(i);try{return new URL(e).origin}catch{return e}}function p(i,e,t,n,o,a,c){let s=new URL(`/embed/sign/${e}`,i),g=t?.trim().toLowerCase();return g&&s.searchParams.set("email",g),n&&s.searchParams.set("mode",n),o&&s.searchParams.set("theme",o),a&&s.searchParams.set("lang",a),c!==void 0&&s.searchParams.set("closeOnEscape",String(c)),s.toString()}function u(i){if(typeof i=="string"){let e=document.querySelector(i);if(!e)throw new Error(`Container element not found: ${i}`);return e}return i}var l=class{constructor(e){this.debug=e}log(...e){this.debug&&console.log("[Chaindoc SDK]",...e)}warn(...e){this.debug&&console.warn("[Chaindoc SDK]",...e)}error(...e){this.debug&&console.error("[Chaindoc SDK]",...e)}};function f(i){return typeof i=="object"&&i!==null&&"source"in i&&i.source==="chaindoc-embed"}function v(i){return`

z-index: 2147483647;
`.trim()),this.isFullscreen=!0)}exitFullscreen(){this.isFullscreen&&(this.logger.log("Exiting fullscreen"),this.previousIframeStyle!==null?this.iframe.setAttribute("style",this.previousIframeStyle):this.iframe.removeAttribute("style"),this.previousIframeStyle=null,this.isFullscreen=!1)}sendMessage(e){if(!this.iframe.contentWindow){this.logger.error("Cannot send message: iframe contentWindow not available");return}this.iframe.contentWindow.postMessage(e,this.allowedOrigin),this.logger.log("Sent message to iframe:",e.type)}close(){if(this.state.isClosed){this.logger.warn("Instance already closed");return}this.logger.log("Closing instance"),this.sendMessage({source:"chaindoc-embed",type:"CLOSE"}),setTimeout(()=>{this.state.isClosed||(this.logger.warn("Iframe did not respond to CLOSE, forcing cleanup"),this.cleanup())},3e3)}changeTheme(e){this.logger.log("Changing theme to:",e),this.state.theme=e,this.sendMessage({source:"chaindoc-embed",type:"THEME_CHANGE",data:{theme:e}})}isReady(){return this.state.isReady}getSessionId(){return this.state.sessionId}_internalOn(e,t){let n=this.internalEventHandlers.get(e);if(n){n.add(t);return}this.internalEventHandlers.set(e,new Set([t]))}emit(e){let t=this.internalEventHandlers.get(e);t&&t.forEach(n=>n())}cleanup(){this.state.isClosed||(this.logger.log("Cleaning up instance"),this.isFullscreen&&this.exitFullscreen(),this.state.isClosed=!0,window.removeEventListener("message",this.messageListener),this.overlay&&(this.overlay.remove(),document.body.style.overflow=this.previousOverflow),this.container&&this.container.querySelector("[data-chaindoc-inline]")?.remove(),this.options.onClose?.(),this.emit("close"),this.internalEventHandlers.clear())}};var h=class{constructor(e){this.instances=new Set;if(!e.publicKey)throw new Error("ChaindocEmbed: publicKey is required");if(!e.publicKey.startsWith("pk_"))throw new Error('ChaindocEmbed: publicKey must start with "pk_"');this.config={publicKey:e.publicKey,environment:e.environment||"production",debug:e.debug||!1},this.logger=new l(this.config.debug),this.logger.log("SDK initialized",this.config)}openSignatureFlow(e){if(!e.sessionId)throw new Error("openSignatureFlow: sessionId is required");if(!e.sessionId.startsWith("ses_"))throw new Error('openSignatureFlow: sessionId must start with "ses_"');if((e.mode||"modal")==="inline"&&!e.container)throw new Error("openSignatureFlow: container is required for inline mode");this.logger.log("Opening signature flow",e);let n=new r(this.config,e,this.logger);return this.instances.add(n),n._internalOn("close",()=>{this.instances.delete(n)}),n}destroy(){this.logger.log("Destroying SDK and all instances");for(let e of this.instances)e.close();this.instances.clear()}static get version(){return"2.2.0-alpha.2"}};export{h as ChaindocEmbed,r as EmbedInstance};
`.trim()),this.isFullscreen=!0)}exitFullscreen(){this.isFullscreen&&(this.logger.log("Exiting fullscreen"),this.previousIframeStyle!==null?this.iframe.setAttribute("style",this.previousIframeStyle):this.iframe.removeAttribute("style"),this.previousIframeStyle=null,this.isFullscreen=!1)}sendMessage(e){if(!this.iframe.contentWindow){this.logger.error("Cannot send message: iframe contentWindow not available");return}this.iframe.contentWindow.postMessage(e,this.allowedOrigin),this.logger.log("Sent message to iframe:",e.type)}close(){if(this.state.isClosed){this.logger.warn("Instance already closed");return}this.logger.log("Closing instance"),this.sendMessage({source:"chaindoc-embed",type:"CLOSE"}),setTimeout(()=>{this.state.isClosed||(this.logger.warn("Iframe did not respond to CLOSE, forcing cleanup"),this.cleanup())},3e3)}changeTheme(e){this.logger.log("Changing theme to:",e),this.state.theme=e,this.sendMessage({source:"chaindoc-embed",type:"THEME_CHANGE",data:{theme:e}})}isReady(){return this.state.isReady}getSessionId(){return this.state.sessionId}_internalOn(e,t){let n=this.internalEventHandlers.get(e);if(n){n.add(t);return}this.internalEventHandlers.set(e,new Set([t]))}emit(e){let t=this.internalEventHandlers.get(e);t&&t.forEach(n=>n())}cleanup(){this.state.isClosed||(this.logger.log("Cleaning up instance"),this.isFullscreen&&this.exitFullscreen(),this.state.isClosed=!0,window.removeEventListener("message",this.messageListener),this.overlay&&(this.overlay.remove(),document.body.style.overflow=this.previousOverflow),this.container&&this.container.querySelector("[data-chaindoc-inline]")?.remove(),this.options.onClose?.(),this.emit("close"),this.internalEventHandlers.clear())}};var h=class{constructor(e){this.instances=new Set;if(!e.publicKey)throw new Error("ChaindocEmbed: publicKey is required");if(!e.publicKey.startsWith("pk_"))throw new Error('ChaindocEmbed: publicKey must start with "pk_"');this.config={publicKey:e.publicKey,environment:e.environment||"production",debug:e.debug||!1},this.logger=new l(this.config.debug),this.logger.log("SDK initialized",this.config)}openSignatureFlow(e){if(!e.sessionId)throw new Error("openSignatureFlow: sessionId is required");if(!e.sessionId.startsWith("ses_"))throw new Error('openSignatureFlow: sessionId must start with "ses_"');if((e.mode||"modal")==="inline"&&!e.container)throw new Error("openSignatureFlow: container is required for inline mode");this.logger.log("Opening signature flow",e);let n=new r(this.config,e,this.logger);return this.instances.add(n),n._internalOn("close",()=>{this.instances.delete(n)}),n}destroy(){this.logger.log("Destroying SDK and all instances");for(let e of this.instances)e.close();this.instances.clear()}static get version(){return"2.2.0"}};export{h as ChaindocEmbed,r as EmbedInstance};
//# sourceMappingURL=index.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/utils.ts","../src/styles.ts","../src/EmbedInstance.ts","../src/ChaindocEmbed.ts"],"sourcesContent":["/**\n * Utility functions for Chaindoc Embed SDK\n */\n\nimport type { DisplayMode, Environment } from \"./types\";\n\n/**\n * Get the iframe base URL based on environment\n */\nexport function getIframeBaseUrl(environment: Environment): string {\n switch (environment) {\n case \"production\":\n return \"https://embed.chaindoc.io\";\n case \"staging\":\n return \"https://embed-demo.chaindoc.io\";\n case \"development\":\n return \"https://embed-demo.chaindoc.io\";\n default:\n return \"https://embed.chaindoc.io\";\n }\n}\n\n/**\n * Get allowed origin for postMessage validation\n */\nexport function getAllowedOrigin(environment: Environment): string {\n const baseUrl = getIframeBaseUrl(environment);\n try {\n const url = new URL(baseUrl);\n return url.origin;\n } catch {\n return baseUrl;\n }\n}\n\n/**\n * Build iframe URL with query parameters\n */\nexport function buildIframeUrl(\n baseUrl: string,\n sessionId: string,\n email?: string,\n mode?: DisplayMode,\n theme?: string,\n language?: string,\n closeOnEscape?: boolean\n): string {\n // Session ID goes into the path, not as a query parameter\n const url = new URL(`/embed/sign/${sessionId}`, baseUrl);\n\n const normalizedEmail = email?.trim().toLowerCase();\n if (normalizedEmail) {\n url.searchParams.set(\"email\", normalizedEmail);\n }\n\n if (mode) {\n url.searchParams.set(\"mode\", mode);\n }\n\n if (theme) {\n url.searchParams.set(\"theme\", theme);\n }\n\n if (language) {\n url.searchParams.set(\"lang\", language);\n }\n\n if (closeOnEscape !== undefined) {\n url.searchParams.set(\"closeOnEscape\", String(closeOnEscape));\n }\n\n return url.toString();\n}\n\n/**\n * Resolve container element from HTMLElement or selector string\n */\nexport function resolveContainer(container: HTMLElement | string): HTMLElement {\n if (typeof container === \"string\") {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n return element;\n }\n return container;\n}\n\n/**\n * Debug logger (only logs when debug mode is enabled)\n */\nexport class Logger {\n constructor(private debug: boolean) {}\n\n log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (this.debug) {\n console.error(\"[Chaindoc SDK]\", ...args);\n }\n }\n}\n\n/**\n * Type guard to check if a message is from Chaindoc iframe\n */\nexport function isChaindocMessage(\n message: unknown\n): message is { source: \"chaindoc-embed\" } {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"source\" in message &&\n message.source === \"chaindoc-embed\"\n );\n}\n","/**\n * CSS-in-JS styles for modal and inline modes\n */\n\n/**\n * Get styles for modal overlay\n */\nexport function getOverlayStyles(zIndex: number): string {\n return `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${zIndex};\n padding: 20px;\n `.trim();\n}\n\n/**\n * Get styles for modal container\n */\nexport function getModalContainerStyles(\n width?: number,\n height?: number\n): string {\n const modalWidth = width ?? 450;\n const modalHeight = height ?? 850;\n\n return `\n position: relative;\n width: 100%;\n max-width: ${modalWidth}px;\n height: ${modalHeight}px;\n max-height: 90vh;\n background: white;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n `.trim();\n}\n\n/**\n * Get styles for iframe (common for both modal and inline)\n */\nexport function getIframeStyles(mode: \"modal\" | \"inline\"): string {\n const baseStyles = `\n width: 100%;\n border: none;\n display: block;\n `.trim();\n\n if (mode === \"modal\") {\n return `\n ${baseStyles}\n height: 100%;\n min-height: 400px;\n `.trim();\n }\n\n // Inline mode\n return `\n ${baseStyles}\n height: 0;\n `.trim();\n}\n\n/**\n * Get styles for inline container wrapper\n */\nexport function getInlineContainerStyles(): string {\n return `\n position: relative;\n width: 100%;\n `.trim();\n}\n","/**\n * Instance class for managing individual signature flows\n */\n\nimport type {\n SignatureFlowOptions,\n Theme,\n IframeToSdkMessage,\n SdkToIframeMessage,\n InstanceState,\n Environment,\n} from './types';\nimport {\n getIframeBaseUrl,\n getAllowedOrigin,\n buildIframeUrl,\n resolveContainer,\n isChaindocMessage,\n Logger,\n} from './utils';\nimport {\n getOverlayStyles,\n getModalContainerStyles,\n getIframeStyles,\n getInlineContainerStyles,\n} from './styles';\n\n/**\n * Internal config interface for EmbedInstance\n */\ninterface InternalConfig {\n publicKey: string;\n environment: Environment;\n debug: boolean;\n}\n\ntype InternalEventHandler = () => void;\n\n/**\n * Represents a single signature flow instance\n *\n * @example\n * ```typescript\n * const instance = sdk.openSignatureFlow({ sessionId: 'ses_xxx' });\n * instance.changeTheme('dark');\n * instance.close();\n * ```\n */\nexport class EmbedInstance {\n private config: InternalConfig;\n private options: SignatureFlowOptions;\n private logger: Logger;\n\n private state: InstanceState;\n private iframe: HTMLIFrameElement;\n private overlay: HTMLDivElement | null = null;\n private modalContainer: HTMLDivElement | null = null;\n private container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private isFullscreen: boolean = false;\n private previousIframeStyle: string | null = null;\n\n private internalEventHandlers: Map<string, Set<InternalEventHandler>> = new Map();\n\n constructor(\n config: InternalConfig,\n options: SignatureFlowOptions,\n logger: Logger\n ) {\n this.config = config;\n this.logger = logger;\n\n // Store options\n this.options = options;\n\n // Initialize state\n this.state = {\n sessionId: this.options.sessionId,\n mode: this.options.mode || 'modal',\n theme: this.options.theme || 'light',\n isReady: false,\n isClosed: false,\n hasSucceeded: false,\n };\n\n // Calculate allowed origin\n const baseUrl = getIframeBaseUrl(this.config.environment);\n this.allowedOrigin = getAllowedOrigin(this.config.environment);\n\n // Build iframe URL\n const iframeUrl = buildIframeUrl(\n baseUrl,\n this.options.sessionId,\n this.options.email,\n this.state.mode,\n this.state.theme,\n this.options.language,\n this.options.closeOnEscape\n );\n\n // Create iframe\n this.iframe = this.createIframe(iframeUrl);\n\n // Setup message listener\n this.messageListener = this.handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n\n // Render based on mode\n if (this.state.mode === 'modal') {\n this.renderModal();\n } else {\n this.renderInline();\n }\n\n this.logger.log('Instance created', { sessionId: this.state.sessionId, mode: this.state.mode });\n }\n\n /**\n * Create iframe element\n */\n private createIframe(url: string): HTMLIFrameElement {\n const iframe = document.createElement('iframe');\n iframe.src = url;\n iframe.setAttribute('style', getIframeStyles(this.state.mode));\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads'\n );\n // Permissions for KYC verification (camera/microphone for liveness check, geolocation optional)\n iframe.setAttribute('allow', 'clipboard-write; camera; microphone; geolocation');\n return iframe;\n }\n\n /**\n * Render modal mode\n */\n private renderModal(): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.setAttribute('style', getOverlayStyles(this.options.zIndex ?? 999999));\n this.overlay.setAttribute('data-chaindoc-overlay', 'true');\n\n // Create modal container\n this.modalContainer = document.createElement('div');\n this.modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n this.modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(this.modalContainer);\n\n // Click outside to cancel and close (configurable, default: true)\n if (this.options.closeOnClickOutside !== false) {\n this.overlay.addEventListener('click', (e) => {\n if (e.target === this.overlay) {\n this.logger.log('Clicked outside modal - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n });\n }\n\n // ESC key to cancel and close (configurable, default: true)\n if (this.options.closeOnEscape !== false) {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.logger.log('ESC key pressed - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n };\n document.addEventListener('keydown', handleEscape);\n\n // Store cleanup\n this._internalOn('close', () => {\n document.removeEventListener('keydown', handleEscape);\n });\n }\n\n // Lock body scroll (preserve previous value for restoration)\n this.previousOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n // Append to body\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Render inline mode\n */\n private renderInline(): void {\n if (!this.options.container) {\n throw new Error('Container is required for inline mode');\n }\n\n // Resolve container\n this.container = resolveContainer(this.options.container);\n\n // Create wrapper\n const wrapper = document.createElement('div');\n wrapper.setAttribute('style', getInlineContainerStyles());\n wrapper.setAttribute('data-chaindoc-inline', 'true');\n wrapper.appendChild(this.iframe);\n\n // Inject into container\n this.container.appendChild(wrapper);\n }\n\n /**\n * Handle incoming postMessage events\n */\n private handleMessage(event: MessageEvent): void {\n // Validate origin and source (ensure message comes from our iframe, not another iframe with same origin)\n if (event.origin !== this.allowedOrigin || event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Validate message structure\n if (!isChaindocMessage(event.data)) {\n return;\n }\n\n const message = event.data as IframeToSdkMessage;\n this.logger.log('Received message:', message.type, message);\n\n // Handle message by type\n switch (message.type) {\n case 'READY':\n this.state.isReady = true;\n this.options.onReady?.();\n break;\n\n case 'RESIZE':\n if ('data' in message && !this.isFullscreen) {\n this.iframe.style.height = `${message.data.height}px`;\n }\n break;\n\n case 'SUCCESS':\n this.state.hasSucceeded = true;\n if ('data' in message) {\n this.options.onSuccess?.(message.data);\n }\n break;\n\n case 'ERROR':\n if ('data' in message) {\n this.options.onError?.(message.data);\n }\n break;\n\n case 'CANCEL':\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n break;\n\n case 'CLOSED':\n this.cleanup();\n break;\n\n case 'RESEND_OTP':\n if ('data' in message) {\n this.options.onResendOtp?.(message.data);\n }\n break;\n\n case 'REQUEST_FULLSCREEN':\n this.enterFullscreen();\n break;\n\n case 'EXIT_FULLSCREEN':\n this.exitFullscreen();\n break;\n\n default:\n this.logger.warn('Unknown message type:', message);\n }\n }\n\n /**\n * Expand iframe to cover the entire parent viewport.\n * Works uniformly in modal and inline modes, including iOS Safari\n * (does not rely on the native Fullscreen API).\n *\n * Parent body.overflow is intentionally NOT modified here: it is brittle\n * (easy to leak a `hidden` lock back to the host page if the restore path\n * is missed). Scroll-chaining from the fullscreen iframe is handled inside\n * the iframe itself via `overscroll-behavior: contain` on the scroll area.\n */\n private enterFullscreen(): void {\n if (this.isFullscreen || this.state.isClosed) {\n return;\n }\n\n this.logger.log('Entering fullscreen');\n\n this.previousIframeStyle = this.iframe.getAttribute('style');\n\n this.iframe.setAttribute(\n 'style',\n `\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n max-width: none;\n max-height: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n padding: 0;\n display: block;\n z-index: 2147483647;\n `.trim()\n );\n\n this.isFullscreen = true;\n }\n\n /**\n * Restore iframe to its previous size and position.\n */\n private exitFullscreen(): void {\n if (!this.isFullscreen) {\n return;\n }\n\n this.logger.log('Exiting fullscreen');\n\n if (this.previousIframeStyle !== null) {\n this.iframe.setAttribute('style', this.previousIframeStyle);\n } else {\n this.iframe.removeAttribute('style');\n }\n this.previousIframeStyle = null;\n\n this.isFullscreen = false;\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: SdkToIframeMessage): void {\n if (!this.iframe.contentWindow) {\n this.logger.error('Cannot send message: iframe contentWindow not available');\n return;\n }\n\n this.iframe.contentWindow.postMessage(message, this.allowedOrigin);\n this.logger.log('Sent message to iframe:', message.type);\n }\n\n /**\n * Close the signature flow\n */\n close(): void {\n if (this.state.isClosed) {\n this.logger.warn('Instance already closed');\n return;\n }\n\n this.logger.log('Closing instance');\n\n // Send CLOSE message to iframe\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'CLOSE',\n });\n\n // Force cleanup after timeout if iframe doesn't respond\n setTimeout(() => {\n if (!this.state.isClosed) {\n this.logger.warn('Iframe did not respond to CLOSE, forcing cleanup');\n this.cleanup();\n }\n }, 3000);\n }\n\n /**\n * Change theme\n */\n changeTheme(theme: Theme): void {\n this.logger.log('Changing theme to:', theme);\n\n this.state.theme = theme;\n\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'THEME_CHANGE',\n data: { theme },\n });\n }\n\n /**\n * Check if iframe is ready\n */\n isReady(): boolean {\n return this.state.isReady;\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.state.sessionId;\n }\n\n /**\n * Internal event system (for cleanup tracking)\n * @internal\n */\n _internalOn(event: string, handler: InternalEventHandler): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n return;\n }\n\n this.internalEventHandlers.set(event, new Set([handler]));\n }\n\n private emit(event: string): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => handler());\n }\n }\n\n /**\n * Cleanup all resources\n */\n private cleanup(): void {\n if (this.state.isClosed) {\n return;\n }\n\n this.logger.log('Cleaning up instance');\n\n // Restore body overflow if we are destroyed while fullscreen is active\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.state.isClosed = true;\n\n // Remove message listener\n window.removeEventListener('message', this.messageListener);\n\n // Remove DOM elements\n if (this.overlay) {\n this.overlay.remove();\n document.body.style.overflow = this.previousOverflow;\n }\n\n if (this.container) {\n const wrapper = this.container.querySelector('[data-chaindoc-inline]');\n wrapper?.remove();\n }\n\n // Call onClose callback\n this.options.onClose?.();\n\n // Emit internal close event\n this.emit('close');\n\n // Clear internal handlers\n this.internalEventHandlers.clear();\n }\n}\n","/**\n * Main SDK class for Chaindoc Embed\n */\n\nimport { EmbedInstance } from \"./EmbedInstance\";\nimport type { ChaindocEmbedConfig, SignatureFlowOptions } from \"./types\";\nimport { Logger } from \"./utils\";\n\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Main entry point for Chaindoc Embed SDK\n *\n * @example\n * ```typescript\n * const sdk = new ChaindocEmbed({\n * publicKey: 'pk_test_xxx',\n * environment: 'development',\n * debug: true\n * });\n *\n * const instance = sdk.openSignatureFlow({\n * sessionId: 'ses_xxx',\n * onSuccess: (data) => console.log('Signed!', data)\n * });\n * ```\n */\n/**\n * Internal config type with defaults applied\n */\ninterface InternalConfig {\n publicKey: string;\n environment: \"production\" | \"staging\" | \"development\";\n debug: boolean;\n}\n\nexport class ChaindocEmbed {\n private config: InternalConfig;\n private logger: Logger;\n private instances: Set<EmbedInstance> = new Set();\n\n /**\n * Create a new ChaindocEmbed instance\n *\n * @param config - SDK configuration\n * @throws {Error} If publicKey is missing or invalid\n */\n constructor(config: ChaindocEmbedConfig) {\n // Validate required config\n if (!config.publicKey) {\n throw new Error(\"ChaindocEmbed: publicKey is required\");\n }\n\n if (!config.publicKey.startsWith(\"pk_\")) {\n throw new Error('ChaindocEmbed: publicKey must start with \"pk_\"');\n }\n\n // Set defaults\n this.config = {\n publicKey: config.publicKey,\n environment: config.environment || \"production\",\n debug: config.debug || false,\n };\n\n this.logger = new Logger(this.config.debug);\n this.logger.log(\"SDK initialized\", this.config);\n }\n\n /**\n * Open a signature flow\n *\n * @param options - Signature flow options\n * @returns EmbedInstance for controlling the flow\n * @throws {Error} If sessionId is missing or invalid\n * @throws {Error} If inline mode is used without container\n */\n openSignatureFlow(options: SignatureFlowOptions): EmbedInstance {\n // Validate required options\n if (!options.sessionId) {\n throw new Error(\"openSignatureFlow: sessionId is required\");\n }\n\n if (!options.sessionId.startsWith(\"ses_\")) {\n throw new Error('openSignatureFlow: sessionId must start with \"ses_\"');\n }\n\n const mode = options.mode || \"modal\";\n\n if (mode === \"inline\" && !options.container) {\n throw new Error(\n \"openSignatureFlow: container is required for inline mode\"\n );\n }\n\n this.logger.log(\"Opening signature flow\", options);\n\n // Create instance\n const instance = new EmbedInstance(this.config, options, this.logger);\n\n // Track instance\n this.instances.add(instance);\n\n // Remove from tracking when closed\n instance._internalOn(\"close\", () => {\n this.instances.delete(instance);\n });\n\n return instance;\n }\n\n /**\n * Destroy all instances and cleanup\n */\n destroy(): void {\n this.logger.log(\"Destroying SDK and all instances\");\n\n for (const instance of this.instances) {\n instance.close();\n }\n\n this.instances.clear();\n }\n\n /**\n * Get SDK version\n */\n static get version(): string {\n return __SDK_VERSION__;\n }\n}\n"],"mappings":"AASO,SAASA,EAAiBC,EAAkC,CACjE,OAAQA,EAAa,CACnB,IAAK,aACH,MAAO,4BACT,IAAK,UACH,MAAO,iCACT,IAAK,cACH,MAAO,iCACT,QACE,MAAO,2BACX,CACF,CAKO,SAASC,EAAiBD,EAAkC,CACjE,IAAME,EAAUH,EAAiBC,CAAW,EAC5C,GAAI,CAEF,OADY,IAAI,IAAIE,CAAO,EAChB,MACb,MAAQ,CACN,OAAOA,CACT,CACF,CAKO,SAASC,EACdD,EACAE,EACAC,EACAC,EACAC,EACAC,EACAC,EACQ,CAER,IAAMC,EAAM,IAAI,IAAI,eAAeN,CAAS,GAAIF,CAAO,EAEjDS,EAAkBN,GAAO,KAAK,EAAE,YAAY,EAClD,OAAIM,GACFD,EAAI,aAAa,IAAI,QAASC,CAAe,EAG3CL,GACFI,EAAI,aAAa,IAAI,OAAQJ,CAAI,EAG/BC,GACFG,EAAI,aAAa,IAAI,QAASH,CAAK,EAGjCC,GACFE,EAAI,aAAa,IAAI,OAAQF,CAAQ,EAGnCC,IAAkB,QACpBC,EAAI,aAAa,IAAI,gBAAiB,OAAOD,CAAa,CAAC,EAGtDC,EAAI,SAAS,CACtB,CAKO,SAASE,EAAiBC,EAA8C,CAC7E,GAAI,OAAOA,GAAc,SAAU,CACjC,IAAMC,EAAU,SAAS,cAA2BD,CAAS,EAC7D,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,gCAAgCD,CAAS,EAAE,EAE7D,OAAOC,CACT,CACA,OAAOD,CACT,CAKO,IAAME,EAAN,KAAa,CAClB,YAAoBC,EAAgB,CAAhB,WAAAA,CAAiB,CAErC,OAAOC,EAAuB,CACxB,KAAK,OACP,QAAQ,IAAI,iBAAkB,GAAGA,CAAI,CAEzC,CAEA,QAAQA,EAAuB,CACzB,KAAK,OACP,QAAQ,KAAK,iBAAkB,GAAGA,CAAI,CAE1C,CAEA,SAASA,EAAuB,CAC1B,KAAK,OACP,QAAQ,MAAM,iBAAkB,GAAGA,CAAI,CAE3C,CACF,EAKO,SAASC,EACdC,EACyC,CACzC,OACE,OAAOA,GAAY,UACnBA,IAAY,MACZ,WAAYA,GACZA,EAAQ,SAAW,gBAEvB,CCtHO,SAASC,EAAiBC,EAAwB,CACvD,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAUMA,CAAM;AAAA;AAAA,IAEjB,KAAK,CACT,CAKO,SAASC,EACdC,EACAC,EACQ,CAIR,MAAO;AAAA;AAAA;AAAA,iBAHYD,GAAS,GAMH;AAAA,cALLC,GAAU,GAMP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMrB,KAAK,CACT,CAKO,SAASC,EAAgBC,EAAkC,CAChE,IAAMC,EAAa;AAAA;AAAA;AAAA;AAAA,IAIjB,KAAK,EAEP,OAAID,IAAS,QACJ;AAAA,QACHC,CAAU;AAAA;AAAA;AAAA,MAGZ,KAAK,EAIF;AAAA,MACHA,CAAU;AAAA;AAAA,IAEZ,KAAK,CACT,CAKO,SAASC,GAAmC,CACjD,MAAO;AAAA;AAAA;AAAA,IAGL,KAAK,CACT,CC/BO,IAAMC,EAAN,KAAoB,CAoBzB,YACEC,EACAC,EACAC,EACA,CAjBF,KAAQ,QAAiC,KACzC,KAAQ,eAAwC,KAChD,KAAQ,UAAgC,KAIxC,KAAQ,iBAA2B,GAEnC,KAAQ,aAAwB,GAChC,KAAQ,oBAAqC,KAE7C,KAAQ,sBAAgE,IAAI,IAO1E,KAAK,OAASF,EACd,KAAK,OAASE,EAGd,KAAK,QAAUD,EAGf,KAAK,MAAQ,CACX,UAAW,KAAK,QAAQ,UACxB,KAAM,KAAK,QAAQ,MAAQ,QAC3B,MAAO,KAAK,QAAQ,OAAS,QAC7B,QAAS,GACT,SAAU,GACV,aAAc,EAChB,EAGA,IAAME,EAAUC,EAAiB,KAAK,OAAO,WAAW,EACxD,KAAK,cAAgBC,EAAiB,KAAK,OAAO,WAAW,EAG7D,IAAMC,EAAYC,EAChBJ,EACA,KAAK,QAAQ,UACb,KAAK,QAAQ,MACb,KAAK,MAAM,KACX,KAAK,MAAM,MACX,KAAK,QAAQ,SACb,KAAK,QAAQ,aACf,EAGA,KAAK,OAAS,KAAK,aAAaG,CAAS,EAGzC,KAAK,gBAAkB,KAAK,cAAc,KAAK,IAAI,EACnD,OAAO,iBAAiB,UAAW,KAAK,eAAe,EAGnD,KAAK,MAAM,OAAS,QACtB,KAAK,YAAY,EAEjB,KAAK,aAAa,EAGpB,KAAK,OAAO,IAAI,mBAAoB,CAAE,UAAW,KAAK,MAAM,UAAW,KAAM,KAAK,MAAM,IAAK,CAAC,CAChG,CAKQ,aAAaE,EAAgC,CACnD,IAAMC,EAAS,SAAS,cAAc,QAAQ,EAC9C,OAAAA,EAAO,IAAMD,EACbC,EAAO,aAAa,QAASC,EAAgB,KAAK,MAAM,IAAI,CAAC,EAC7DD,EAAO,aACL,UACA,0EACF,EAEAA,EAAO,aAAa,QAAS,kDAAkD,EACxEA,CACT,CAKQ,aAAoB,CA+B1B,GA7BA,KAAK,QAAU,SAAS,cAAc,KAAK,EAC3C,KAAK,QAAQ,aAAa,QAASE,EAAiB,KAAK,QAAQ,QAAU,MAAM,CAAC,EAClF,KAAK,QAAQ,aAAa,wBAAyB,MAAM,EAGzD,KAAK,eAAiB,SAAS,cAAc,KAAK,EAClD,KAAK,eAAe,aAClB,QACAC,EAAwB,KAAK,QAAQ,WAAY,KAAK,QAAQ,WAAW,CAC3E,EACA,KAAK,eAAe,YAAY,KAAK,MAAM,EAG3C,KAAK,QAAQ,YAAY,KAAK,cAAc,EAGxC,KAAK,QAAQ,sBAAwB,IACvC,KAAK,QAAQ,iBAAiB,QAAU,GAAM,CACxC,EAAE,SAAW,KAAK,UACpB,KAAK,OAAO,IAAI,iCAAiC,EAC5C,KAAK,MAAM,cACd,KAAK,QAAQ,WAAW,EAE1B,KAAK,MAAM,EAEf,CAAC,EAIC,KAAK,QAAQ,gBAAkB,GAAO,CACxC,IAAMC,EAAgBC,GAAqB,CACrCA,EAAE,MAAQ,WACZ,KAAK,OAAO,IAAI,2BAA2B,EACtC,KAAK,MAAM,cACd,KAAK,QAAQ,WAAW,EAE1B,KAAK,MAAM,EAEf,EACA,SAAS,iBAAiB,UAAWD,CAAY,EAGjD,KAAK,YAAY,QAAS,IAAM,CAC9B,SAAS,oBAAoB,UAAWA,CAAY,CACtD,CAAC,CACH,CAGA,KAAK,iBAAmB,SAAS,KAAK,MAAM,SAC5C,SAAS,KAAK,MAAM,SAAW,SAG/B,SAAS,KAAK,YAAY,KAAK,OAAO,CACxC,CAKQ,cAAqB,CAC3B,GAAI,CAAC,KAAK,QAAQ,UAChB,MAAM,IAAI,MAAM,uCAAuC,EAIzD,KAAK,UAAYE,EAAiB,KAAK,QAAQ,SAAS,EAGxD,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,aAAa,QAASC,EAAyB,CAAC,EACxDD,EAAQ,aAAa,uBAAwB,MAAM,EACnDA,EAAQ,YAAY,KAAK,MAAM,EAG/B,KAAK,UAAU,YAAYA,CAAO,CACpC,CAKQ,cAAcE,EAA2B,CAO/C,GALIA,EAAM,SAAW,KAAK,eAAiBA,EAAM,SAAW,KAAK,OAAO,eAKpE,CAACC,EAAkBD,EAAM,IAAI,EAC/B,OAGF,IAAME,EAAUF,EAAM,KAItB,OAHA,KAAK,OAAO,IAAI,oBAAqBE,EAAQ,KAAMA,CAAO,EAGlDA,EAAQ,KAAM,CACpB,IAAK,QACH,KAAK,MAAM,QAAU,GACrB,KAAK,QAAQ,UAAU,EACvB,MAEF,IAAK,SACC,SAAUA,GAAW,CAAC,KAAK,eAC7B,KAAK,OAAO,MAAM,OAAS,GAAGA,EAAQ,KAAK,MAAM,MAEnD,MAEF,IAAK,UACH,KAAK,MAAM,aAAe,GACtB,SAAUA,GACZ,KAAK,QAAQ,YAAYA,EAAQ,IAAI,EAEvC,MAEF,IAAK,QACC,SAAUA,GACZ,KAAK,QAAQ,UAAUA,EAAQ,IAAI,EAErC,MAEF,IAAK,SACE,KAAK,MAAM,cACd,KAAK,QAAQ,WAAW,EAE1B,MAEF,IAAK,SACH,KAAK,QAAQ,EACb,MAEF,IAAK,aACC,SAAUA,GACZ,KAAK,QAAQ,cAAcA,EAAQ,IAAI,EAEzC,MAEF,IAAK,qBACH,KAAK,gBAAgB,EACrB,MAEF,IAAK,kBACH,KAAK,eAAe,EACpB,MAEF,QACE,KAAK,OAAO,KAAK,wBAAyBA,CAAO,CACrD,CACF,CAYQ,iBAAwB,CAC1B,KAAK,cAAgB,KAAK,MAAM,WAIpC,KAAK,OAAO,IAAI,qBAAqB,EAErC,KAAK,oBAAsB,KAAK,OAAO,aAAa,OAAO,EAE3D,KAAK,OAAO,aACV,QACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAcE,KAAK,CACT,EAEA,KAAK,aAAe,GACtB,CAKQ,gBAAuB,CACxB,KAAK,eAIV,KAAK,OAAO,IAAI,oBAAoB,EAEhC,KAAK,sBAAwB,KAC/B,KAAK,OAAO,aAAa,QAAS,KAAK,mBAAmB,EAE1D,KAAK,OAAO,gBAAgB,OAAO,EAErC,KAAK,oBAAsB,KAE3B,KAAK,aAAe,GACtB,CAKQ,YAAYA,EAAmC,CACrD,GAAI,CAAC,KAAK,OAAO,cAAe,CAC9B,KAAK,OAAO,MAAM,yDAAyD,EAC3E,MACF,CAEA,KAAK,OAAO,cAAc,YAAYA,EAAS,KAAK,aAAa,EACjE,KAAK,OAAO,IAAI,0BAA2BA,EAAQ,IAAI,CACzD,CAKA,OAAc,CACZ,GAAI,KAAK,MAAM,SAAU,CACvB,KAAK,OAAO,KAAK,yBAAyB,EAC1C,MACF,CAEA,KAAK,OAAO,IAAI,kBAAkB,EAGlC,KAAK,YAAY,CACf,OAAQ,iBACR,KAAM,OACR,CAAC,EAGD,WAAW,IAAM,CACV,KAAK,MAAM,WACd,KAAK,OAAO,KAAK,kDAAkD,EACnE,KAAK,QAAQ,EAEjB,EAAG,GAAI,CACT,CAKA,YAAYC,EAAoB,CAC9B,KAAK,OAAO,IAAI,qBAAsBA,CAAK,EAE3C,KAAK,MAAM,MAAQA,EAEnB,KAAK,YAAY,CACf,OAAQ,iBACR,KAAM,eACN,KAAM,CAAE,MAAAA,CAAM,CAChB,CAAC,CACH,CAKA,SAAmB,CACjB,OAAO,KAAK,MAAM,OACpB,CAKA,cAAuB,CACrB,OAAO,KAAK,MAAM,SACpB,CAMA,YAAYH,EAAeI,EAAqC,CAC9D,IAAMC,EAAW,KAAK,sBAAsB,IAAIL,CAAK,EACrD,GAAIK,EAAU,CACZA,EAAS,IAAID,CAAO,EACpB,MACF,CAEA,KAAK,sBAAsB,IAAIJ,EAAO,IAAI,IAAI,CAACI,CAAO,CAAC,CAAC,CAC1D,CAEQ,KAAKJ,EAAqB,CAChC,IAAMK,EAAW,KAAK,sBAAsB,IAAIL,CAAK,EACjDK,GACFA,EAAS,QAASD,GAAYA,EAAQ,CAAC,CAE3C,CAKQ,SAAgB,CAClB,KAAK,MAAM,WAIf,KAAK,OAAO,IAAI,sBAAsB,EAGlC,KAAK,cACP,KAAK,eAAe,EAGtB,KAAK,MAAM,SAAW,GAGtB,OAAO,oBAAoB,UAAW,KAAK,eAAe,EAGtD,KAAK,UACP,KAAK,QAAQ,OAAO,EACpB,SAAS,KAAK,MAAM,SAAW,KAAK,kBAGlC,KAAK,WACS,KAAK,UAAU,cAAc,wBAAwB,GAC5D,OAAO,EAIlB,KAAK,QAAQ,UAAU,EAGvB,KAAK,KAAK,OAAO,EAGjB,KAAK,sBAAsB,MAAM,EACnC,CACF,EC5bO,IAAME,EAAN,KAAoB,CAWzB,YAAYC,EAA6B,CARzC,KAAQ,UAAgC,IAAI,IAU1C,GAAI,CAACA,EAAO,UACV,MAAM,IAAI,MAAM,sCAAsC,EAGxD,GAAI,CAACA,EAAO,UAAU,WAAW,KAAK,EACpC,MAAM,IAAI,MAAM,gDAAgD,EAIlE,KAAK,OAAS,CACZ,UAAWA,EAAO,UAClB,YAAaA,EAAO,aAAe,aACnC,MAAOA,EAAO,OAAS,EACzB,EAEA,KAAK,OAAS,IAAIC,EAAO,KAAK,OAAO,KAAK,EAC1C,KAAK,OAAO,IAAI,kBAAmB,KAAK,MAAM,CAChD,CAUA,kBAAkBC,EAA8C,CAE9D,GAAI,CAACA,EAAQ,UACX,MAAM,IAAI,MAAM,0CAA0C,EAG5D,GAAI,CAACA,EAAQ,UAAU,WAAW,MAAM,EACtC,MAAM,IAAI,MAAM,qDAAqD,EAKvE,IAFaA,EAAQ,MAAQ,WAEhB,UAAY,CAACA,EAAQ,UAChC,MAAM,IAAI,MACR,0DACF,EAGF,KAAK,OAAO,IAAI,yBAA0BA,CAAO,EAGjD,IAAMC,EAAW,IAAIC,EAAc,KAAK,OAAQF,EAAS,KAAK,MAAM,EAGpE,YAAK,UAAU,IAAIC,CAAQ,EAG3BA,EAAS,YAAY,QAAS,IAAM,CAClC,KAAK,UAAU,OAAOA,CAAQ,CAChC,CAAC,EAEMA,CACT,CAKA,SAAgB,CACd,KAAK,OAAO,IAAI,kCAAkC,EAElD,QAAWA,KAAY,KAAK,UAC1BA,EAAS,MAAM,EAGjB,KAAK,UAAU,MAAM,CACvB,CAKA,WAAW,SAAkB,CAC3B,MAAO,eACT,CACF","names":["getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","normalizedEmail","resolveContainer","container","element","Logger","debug","args","isChaindocMessage","message","getOverlayStyles","zIndex","getModalContainerStyles","width","height","getIframeStyles","mode","baseStyles","getInlineContainerStyles","EmbedInstance","config","options","logger","baseUrl","getIframeBaseUrl","getAllowedOrigin","iframeUrl","buildIframeUrl","url","iframe","getIframeStyles","getOverlayStyles","getModalContainerStyles","handleEscape","e","resolveContainer","wrapper","getInlineContainerStyles","event","isChaindocMessage","message","theme","handler","handlers","ChaindocEmbed","config","Logger","options","instance","EmbedInstance"]}
{"version":3,"sources":["../src/utils.ts","../src/styles.ts","../src/EmbedInstance.ts","../src/ChaindocEmbed.ts"],"sourcesContent":["/**\n * Utility functions for Chaindoc Embed SDK\n */\n\nimport type { DisplayMode, Environment } from \"./types\";\n\n/**\n * Get the iframe base URL based on environment\n */\nexport function getIframeBaseUrl(environment: Environment): string {\n switch (environment) {\n case \"production\":\n return \"https://embed.chaindoc.io\";\n case \"staging\":\n return \"https://embed-demo.chaindoc.io\";\n case \"development\":\n return \"https://embed-demo.chaindoc.io\";\n default:\n return \"https://embed.chaindoc.io\";\n }\n}\n\n/**\n * Get allowed origin for postMessage validation\n */\nexport function getAllowedOrigin(environment: Environment): string {\n const baseUrl = getIframeBaseUrl(environment);\n try {\n const url = new URL(baseUrl);\n return url.origin;\n } catch {\n return baseUrl;\n }\n}\n\n/**\n * Build iframe URL with query parameters\n */\nexport function buildIframeUrl(\n baseUrl: string,\n sessionId: string,\n email?: string,\n mode?: DisplayMode,\n theme?: string,\n language?: string,\n closeOnEscape?: boolean\n): string {\n // Session ID goes into the path, not as a query parameter\n const url = new URL(`/embed/sign/${sessionId}`, baseUrl);\n\n const normalizedEmail = email?.trim().toLowerCase();\n if (normalizedEmail) {\n url.searchParams.set(\"email\", normalizedEmail);\n }\n\n if (mode) {\n url.searchParams.set(\"mode\", mode);\n }\n\n if (theme) {\n url.searchParams.set(\"theme\", theme);\n }\n\n if (language) {\n url.searchParams.set(\"lang\", language);\n }\n\n if (closeOnEscape !== undefined) {\n url.searchParams.set(\"closeOnEscape\", String(closeOnEscape));\n }\n\n return url.toString();\n}\n\n/**\n * Resolve container element from HTMLElement or selector string\n */\nexport function resolveContainer(container: HTMLElement | string): HTMLElement {\n if (typeof container === \"string\") {\n const element = document.querySelector<HTMLElement>(container);\n if (!element) {\n throw new Error(`Container element not found: ${container}`);\n }\n return element;\n }\n return container;\n}\n\n/**\n * Debug logger (only logs when debug mode is enabled)\n */\nexport class Logger {\n constructor(private debug: boolean) {}\n\n log(...args: unknown[]): void {\n if (this.debug) {\n console.log(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n warn(...args: unknown[]): void {\n if (this.debug) {\n console.warn(\"[Chaindoc SDK]\", ...args);\n }\n }\n\n error(...args: unknown[]): void {\n if (this.debug) {\n console.error(\"[Chaindoc SDK]\", ...args);\n }\n }\n}\n\n/**\n * Type guard to check if a message is from Chaindoc iframe\n */\nexport function isChaindocMessage(\n message: unknown\n): message is { source: \"chaindoc-embed\" } {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"source\" in message &&\n message.source === \"chaindoc-embed\"\n );\n}\n","/**\n * CSS-in-JS styles for modal and inline modes\n */\n\n/**\n * Get styles for modal overlay\n */\nexport function getOverlayStyles(zIndex: number): string {\n return `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: ${zIndex};\n padding: 20px;\n `.trim();\n}\n\n/**\n * Get styles for modal container\n */\nexport function getModalContainerStyles(\n width?: number,\n height?: number\n): string {\n const modalWidth = width ?? 450;\n const modalHeight = height ?? 850;\n\n return `\n position: relative;\n width: 100%;\n max-width: ${modalWidth}px;\n height: ${modalHeight}px;\n max-height: 90vh;\n background: white;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n `.trim();\n}\n\n/**\n * Get styles for iframe (common for both modal and inline)\n */\nexport function getIframeStyles(mode: \"modal\" | \"inline\"): string {\n const baseStyles = `\n width: 100%;\n border: none;\n display: block;\n `.trim();\n\n if (mode === \"modal\") {\n return `\n ${baseStyles}\n height: 100%;\n min-height: 400px;\n `.trim();\n }\n\n // Inline mode\n return `\n ${baseStyles}\n height: 0;\n `.trim();\n}\n\n/**\n * Get styles for inline container wrapper\n */\nexport function getInlineContainerStyles(): string {\n return `\n position: relative;\n width: 100%;\n `.trim();\n}\n","/**\n * Instance class for managing individual signature flows\n */\n\nimport type {\n SignatureFlowOptions,\n Theme,\n IframeToSdkMessage,\n SdkToIframeMessage,\n InstanceState,\n Environment,\n} from './types';\nimport {\n getIframeBaseUrl,\n getAllowedOrigin,\n buildIframeUrl,\n resolveContainer,\n isChaindocMessage,\n Logger,\n} from './utils';\nimport {\n getOverlayStyles,\n getModalContainerStyles,\n getIframeStyles,\n getInlineContainerStyles,\n} from './styles';\n\n/**\n * Internal config interface for EmbedInstance\n */\ninterface InternalConfig {\n publicKey: string;\n environment: Environment;\n debug: boolean;\n}\n\ntype InternalEventHandler = () => void;\n\n/**\n * Represents a single signature flow instance\n *\n * @example\n * ```typescript\n * const instance = sdk.openSignatureFlow({ sessionId: 'ses_xxx' });\n * instance.changeTheme('dark');\n * instance.close();\n * ```\n */\nexport class EmbedInstance {\n private config: InternalConfig;\n private options: SignatureFlowOptions;\n private logger: Logger;\n\n private state: InstanceState;\n private iframe: HTMLIFrameElement;\n private overlay: HTMLDivElement | null = null;\n private modalContainer: HTMLDivElement | null = null;\n private container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private isFullscreen: boolean = false;\n private previousIframeStyle: string | null = null;\n\n private internalEventHandlers: Map<string, Set<InternalEventHandler>> = new Map();\n\n constructor(\n config: InternalConfig,\n options: SignatureFlowOptions,\n logger: Logger\n ) {\n this.config = config;\n this.logger = logger;\n\n // Store options\n this.options = options;\n\n // Initialize state\n this.state = {\n sessionId: this.options.sessionId,\n mode: this.options.mode || 'modal',\n theme: this.options.theme || 'light',\n isReady: false,\n isClosed: false,\n hasSucceeded: false,\n };\n\n // Calculate allowed origin\n const baseUrl = getIframeBaseUrl(this.config.environment);\n this.allowedOrigin = getAllowedOrigin(this.config.environment);\n\n // Build iframe URL\n const iframeUrl = buildIframeUrl(\n baseUrl,\n this.options.sessionId,\n this.options.email,\n this.state.mode,\n this.state.theme,\n this.options.language,\n this.options.closeOnEscape\n );\n\n // Create iframe\n this.iframe = this.createIframe(iframeUrl);\n\n // Setup message listener\n this.messageListener = this.handleMessage.bind(this);\n window.addEventListener('message', this.messageListener);\n\n // Render based on mode\n if (this.state.mode === 'modal') {\n this.renderModal();\n } else {\n this.renderInline();\n }\n\n this.logger.log('Instance created', { sessionId: this.state.sessionId, mode: this.state.mode });\n }\n\n /**\n * Create iframe element\n */\n private createIframe(url: string): HTMLIFrameElement {\n const iframe = document.createElement('iframe');\n iframe.src = url;\n iframe.setAttribute('style', getIframeStyles(this.state.mode));\n iframe.setAttribute(\n 'sandbox',\n 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads'\n );\n // Permissions for KYC verification (camera/microphone for liveness check, geolocation optional)\n iframe.setAttribute('allow', 'clipboard-write; camera; microphone; geolocation');\n return iframe;\n }\n\n /**\n * Render modal mode\n */\n private renderModal(): void {\n // Create overlay\n this.overlay = document.createElement('div');\n this.overlay.setAttribute('style', getOverlayStyles(this.options.zIndex ?? 999999));\n this.overlay.setAttribute('data-chaindoc-overlay', 'true');\n\n // Create modal container\n this.modalContainer = document.createElement('div');\n this.modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n this.modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(this.modalContainer);\n\n // Click outside to cancel and close (configurable, default: true)\n if (this.options.closeOnClickOutside !== false) {\n this.overlay.addEventListener('click', (e) => {\n if (e.target === this.overlay) {\n this.logger.log('Clicked outside modal - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n });\n }\n\n // ESC key to cancel and close (configurable, default: true)\n if (this.options.closeOnEscape !== false) {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.logger.log('ESC key pressed - closing');\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n this.close();\n }\n };\n document.addEventListener('keydown', handleEscape);\n\n // Store cleanup\n this._internalOn('close', () => {\n document.removeEventListener('keydown', handleEscape);\n });\n }\n\n // Lock body scroll (preserve previous value for restoration)\n this.previousOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n\n // Append to body\n document.body.appendChild(this.overlay);\n }\n\n /**\n * Render inline mode\n */\n private renderInline(): void {\n if (!this.options.container) {\n throw new Error('Container is required for inline mode');\n }\n\n // Resolve container\n this.container = resolveContainer(this.options.container);\n\n // Create wrapper\n const wrapper = document.createElement('div');\n wrapper.setAttribute('style', getInlineContainerStyles());\n wrapper.setAttribute('data-chaindoc-inline', 'true');\n wrapper.appendChild(this.iframe);\n\n // Inject into container\n this.container.appendChild(wrapper);\n }\n\n /**\n * Handle incoming postMessage events\n */\n private handleMessage(event: MessageEvent): void {\n // Validate origin and source (ensure message comes from our iframe, not another iframe with same origin)\n if (event.origin !== this.allowedOrigin || event.source !== this.iframe.contentWindow) {\n return;\n }\n\n // Validate message structure\n if (!isChaindocMessage(event.data)) {\n return;\n }\n\n const message = event.data as IframeToSdkMessage;\n this.logger.log('Received message:', message.type, message);\n\n // Handle message by type\n switch (message.type) {\n case 'READY':\n this.state.isReady = true;\n this.options.onReady?.();\n break;\n\n case 'RESIZE':\n if ('data' in message && !this.isFullscreen) {\n this.iframe.style.height = `${message.data.height}px`;\n }\n break;\n\n case 'SUCCESS':\n this.state.hasSucceeded = true;\n if ('data' in message) {\n this.options.onSuccess?.(message.data);\n }\n break;\n\n case 'ERROR':\n if ('data' in message) {\n this.options.onError?.(message.data);\n }\n break;\n\n case 'CANCEL':\n if (!this.state.hasSucceeded) {\n this.options.onCancel?.();\n }\n break;\n\n case 'CLOSED':\n this.cleanup();\n break;\n\n case 'RESEND_OTP':\n if ('data' in message) {\n this.options.onResendOtp?.(message.data);\n }\n break;\n\n case 'REQUEST_FULLSCREEN':\n this.enterFullscreen();\n break;\n\n case 'EXIT_FULLSCREEN':\n this.exitFullscreen();\n break;\n\n default:\n this.logger.warn('Unknown message type:', message);\n }\n }\n\n /**\n * Expand iframe to cover the entire parent viewport.\n * Works uniformly in modal and inline modes, including iOS Safari\n * (does not rely on the native Fullscreen API).\n *\n * Parent body.overflow is intentionally NOT modified here: it is brittle\n * (easy to leak a `hidden` lock back to the host page if the restore path\n * is missed). Scroll-chaining from the fullscreen iframe is handled inside\n * the iframe itself via `overscroll-behavior: contain` on the scroll area.\n */\n private enterFullscreen(): void {\n if (this.isFullscreen || this.state.isClosed) {\n return;\n }\n\n this.logger.log('Entering fullscreen');\n\n this.previousIframeStyle = this.iframe.getAttribute('style');\n\n this.iframe.setAttribute(\n 'style',\n `\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n max-width: none;\n max-height: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n padding: 0;\n display: block;\n z-index: 2147483647;\n `.trim()\n );\n\n this.isFullscreen = true;\n }\n\n /**\n * Restore iframe to its previous size and position.\n */\n private exitFullscreen(): void {\n if (!this.isFullscreen) {\n return;\n }\n\n this.logger.log('Exiting fullscreen');\n\n if (this.previousIframeStyle !== null) {\n this.iframe.setAttribute('style', this.previousIframeStyle);\n } else {\n this.iframe.removeAttribute('style');\n }\n this.previousIframeStyle = null;\n\n this.isFullscreen = false;\n }\n\n /**\n * Send message to iframe\n */\n private sendMessage(message: SdkToIframeMessage): void {\n if (!this.iframe.contentWindow) {\n this.logger.error('Cannot send message: iframe contentWindow not available');\n return;\n }\n\n this.iframe.contentWindow.postMessage(message, this.allowedOrigin);\n this.logger.log('Sent message to iframe:', message.type);\n }\n\n /**\n * Close the signature flow\n */\n close(): void {\n if (this.state.isClosed) {\n this.logger.warn('Instance already closed');\n return;\n }\n\n this.logger.log('Closing instance');\n\n // Send CLOSE message to iframe\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'CLOSE',\n });\n\n // Force cleanup after timeout if iframe doesn't respond\n setTimeout(() => {\n if (!this.state.isClosed) {\n this.logger.warn('Iframe did not respond to CLOSE, forcing cleanup');\n this.cleanup();\n }\n }, 3000);\n }\n\n /**\n * Change theme\n */\n changeTheme(theme: Theme): void {\n this.logger.log('Changing theme to:', theme);\n\n this.state.theme = theme;\n\n this.sendMessage({\n source: 'chaindoc-embed',\n type: 'THEME_CHANGE',\n data: { theme },\n });\n }\n\n /**\n * Check if iframe is ready\n */\n isReady(): boolean {\n return this.state.isReady;\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.state.sessionId;\n }\n\n /**\n * Internal event system (for cleanup tracking)\n * @internal\n */\n _internalOn(event: string, handler: InternalEventHandler): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.add(handler);\n return;\n }\n\n this.internalEventHandlers.set(event, new Set([handler]));\n }\n\n private emit(event: string): void {\n const handlers = this.internalEventHandlers.get(event);\n if (handlers) {\n handlers.forEach((handler) => handler());\n }\n }\n\n /**\n * Cleanup all resources\n */\n private cleanup(): void {\n if (this.state.isClosed) {\n return;\n }\n\n this.logger.log('Cleaning up instance');\n\n // Restore body overflow if we are destroyed while fullscreen is active\n if (this.isFullscreen) {\n this.exitFullscreen();\n }\n\n this.state.isClosed = true;\n\n // Remove message listener\n window.removeEventListener('message', this.messageListener);\n\n // Remove DOM elements\n if (this.overlay) {\n this.overlay.remove();\n document.body.style.overflow = this.previousOverflow;\n }\n\n if (this.container) {\n const wrapper = this.container.querySelector('[data-chaindoc-inline]');\n wrapper?.remove();\n }\n\n // Call onClose callback\n this.options.onClose?.();\n\n // Emit internal close event\n this.emit('close');\n\n // Clear internal handlers\n this.internalEventHandlers.clear();\n }\n}\n","/**\n * Main SDK class for Chaindoc Embed\n */\n\nimport { EmbedInstance } from \"./EmbedInstance\";\nimport type { ChaindocEmbedConfig, SignatureFlowOptions } from \"./types\";\nimport { Logger } from \"./utils\";\n\ndeclare const __SDK_VERSION__: string;\n\n/**\n * Main entry point for Chaindoc Embed SDK\n *\n * @example\n * ```typescript\n * const sdk = new ChaindocEmbed({\n * publicKey: 'pk_test_xxx',\n * environment: 'development',\n * debug: true\n * });\n *\n * const instance = sdk.openSignatureFlow({\n * sessionId: 'ses_xxx',\n * onSuccess: (data) => console.log('Signed!', data)\n * });\n * ```\n */\n/**\n * Internal config type with defaults applied\n */\ninterface InternalConfig {\n publicKey: string;\n environment: \"production\" | \"staging\" | \"development\";\n debug: boolean;\n}\n\nexport class ChaindocEmbed {\n private config: InternalConfig;\n private logger: Logger;\n private instances: Set<EmbedInstance> = new Set();\n\n /**\n * Create a new ChaindocEmbed instance\n *\n * @param config - SDK configuration\n * @throws {Error} If publicKey is missing or invalid\n */\n constructor(config: ChaindocEmbedConfig) {\n // Validate required config\n if (!config.publicKey) {\n throw new Error(\"ChaindocEmbed: publicKey is required\");\n }\n\n if (!config.publicKey.startsWith(\"pk_\")) {\n throw new Error('ChaindocEmbed: publicKey must start with \"pk_\"');\n }\n\n // Set defaults\n this.config = {\n publicKey: config.publicKey,\n environment: config.environment || \"production\",\n debug: config.debug || false,\n };\n\n this.logger = new Logger(this.config.debug);\n this.logger.log(\"SDK initialized\", this.config);\n }\n\n /**\n * Open a signature flow\n *\n * @param options - Signature flow options\n * @returns EmbedInstance for controlling the flow\n * @throws {Error} If sessionId is missing or invalid\n * @throws {Error} If inline mode is used without container\n */\n openSignatureFlow(options: SignatureFlowOptions): EmbedInstance {\n // Validate required options\n if (!options.sessionId) {\n throw new Error(\"openSignatureFlow: sessionId is required\");\n }\n\n if (!options.sessionId.startsWith(\"ses_\")) {\n throw new Error('openSignatureFlow: sessionId must start with \"ses_\"');\n }\n\n const mode = options.mode || \"modal\";\n\n if (mode === \"inline\" && !options.container) {\n throw new Error(\n \"openSignatureFlow: container is required for inline mode\"\n );\n }\n\n this.logger.log(\"Opening signature flow\", options);\n\n // Create instance\n const instance = new EmbedInstance(this.config, options, this.logger);\n\n // Track instance\n this.instances.add(instance);\n\n // Remove from tracking when closed\n instance._internalOn(\"close\", () => {\n this.instances.delete(instance);\n });\n\n return instance;\n }\n\n /**\n * Destroy all instances and cleanup\n */\n destroy(): void {\n this.logger.log(\"Destroying SDK and all instances\");\n\n for (const instance of this.instances) {\n instance.close();\n }\n\n this.instances.clear();\n }\n\n /**\n * Get SDK version\n */\n static get version(): string {\n return __SDK_VERSION__;\n }\n}\n"],"mappings":"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","names":["getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","normalizedEmail","resolveContainer","container","element","Logger","debug","args","isChaindocMessage","message","getOverlayStyles","zIndex","getModalContainerStyles","width","height","getIframeStyles","mode","baseStyles","getInlineContainerStyles","EmbedInstance","config","options","logger","baseUrl","getIframeBaseUrl","getAllowedOrigin","iframeUrl","buildIframeUrl","url","iframe","getIframeStyles","getOverlayStyles","getModalContainerStyles","handleEscape","e","resolveContainer","wrapper","getInlineContainerStyles","event","isChaindocMessage","message","theme","handler","handlers","ChaindocEmbed","config","Logger","options","instance","EmbedInstance"]}
{
"name": "@chaindoc_io/embed-sdk",
"version": "2.2.0-alpha.2",
"version": "2.2.0",
"description": "JavaScript/TypeScript SDK for embedding Chaindoc document signing flow via iframe",

@@ -5,0 +5,0 @@ "main": "./dist/index.cjs",