🚀. 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.0.0
to
2.1.0-alpha.0
+8
-0
CHANGELOG.md

@@ -8,2 +8,10 @@ # Changelog

## [2.1.0-alpha.0] - 2026-04-24
Alpha preview for iframe fullscreen support. Published under the `next` dist-tag — stable `latest` remains on 2.0.0.
### Added
- **Iframe fullscreen protocol**: Two new inbound postMessage events (`REQUEST_FULLSCREEN` and `EXIT_FULLSCREEN`) let the embedded UI expand the iframe to cover the entire parent viewport and then restore it. Works uniformly in modal and inline modes and on iOS Safari (no reliance on the native Fullscreen API). The iframe's inline style and the parent `body.overflow` are saved on enter and restored on exit. `RESIZE` messages are ignored while fullscreen is active so the UI cannot clobber the expanded height.
## [2.0.0] - 2026-04-23

@@ -10,0 +18,0 @@

+19
-5

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

"use strict";var ChaindocEmbed=(()=>{var c=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var I=(i,e)=>{for(var t in e)c(i,t,{get:e[t],enumerable:!0})},x=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of S(e))!C.call(i,s)&&s!==t&&c(i,s,{get:()=>e[s],enumerable:!(n=E(e,s))||n.enumerable});return i};var O=i=>x(c({},"__esModule",{value:!0}),i);var M={};I(M,{ChaindocEmbed:()=>d,EmbedInstance:()=>r});function h(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=h(i);try{return new URL(e).origin}catch{return e}}function p(i,e,t,n,s,a,g){let o=new URL(`/embed/sign/${e}`,i);return t&&o.searchParams.set("email",t),n&&o.searchParams.set("mode",n),s&&o.searchParams.set("theme",s),a&&o.searchParams.set("lang",a),g!==void 0&&o.searchParams.set("closeOnEscape",String(g)),o.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`
"use strict";var ChaindocEmbed=(()=>{var h=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var I=(i,e)=>{for(var t in e)h(i,t,{get:e[t],enumerable:!0})},x=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of S(e))!C.call(i,s)&&s!==t&&h(i,s,{get:()=>e[s],enumerable:!(n=E(e,s))||n.enumerable});return i};var O=i=>x(h({},"__esModule",{value:!0}),i);var M={};I(M,{ChaindocEmbed:()=>d,EmbedInstance:()=>r});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 u(i){let e=c(i);try{return new URL(e).origin}catch{return e}}function m(i,e,t,n,s,a,g){let o=new URL(`/embed/sign/${e}`,i);return t&&o.searchParams.set("email",t),n&&o.searchParams.set("mode",n),s&&o.searchParams.set("theme",s),a&&o.searchParams.set("lang",a),g!==void 0&&o.searchParams.set("closeOnEscape",String(g)),o.toString()}function p(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`
position: fixed;

@@ -13,3 +13,3 @@ top: 0;

padding: 20px;
`.trim()}function w(i,e){return`
`.trim()}function y(i,e){return`
position: relative;

@@ -24,3 +24,3 @@ width: 100%;

box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
`.trim()}function b(i){let e=`
`.trim()}function w(i){let e=`
width: 100%;

@@ -36,6 +36,20 @@ border: none;

height: 0;
`.trim()}function y(){return`
`.trim()}function b(){return`
position: relative;
width: 100%;
`.trim()}var r=class{constructor(e,t,n){this.overlay=null;this.container=null;this.previousOverflow="";this.internalEventHandlers=new Map;this.config=e,this.logger=n,this.options=t,this.state={sessionId:this.options.sessionId,mode:this.options.mode||"modal",theme:this.options.theme||"light",isReady:!1,isClosed:!1,hasSucceeded:!1};let s=h(this.config.environment);this.allowedOrigin=m(this.config.environment);let a=p(s,this.options.sessionId,this.options.email,this.state.mode,this.state.theme,this.options.language,this.options.closeOnEscape);this.iframe=this.createIframe(a),this.messageListener=this.handleMessage.bind(this),window.addEventListener("message",this.messageListener),this.state.mode==="modal"?this.renderModal():this.renderInline(),this.logger.log("Instance created",{sessionId:this.state.sessionId,mode:this.state.mode})}createIframe(e){let t=document.createElement("iframe");return t.src=e,t.setAttribute("style",b(this.state.mode)),t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"),t.setAttribute("allow","clipboard-write; camera; microphone; geolocation"),t}renderModal(){this.overlay=document.createElement("div"),this.overlay.setAttribute("style",v(this.options.zIndex??999999)),this.overlay.setAttribute("data-chaindoc-overlay","true");let e=document.createElement("div");if(e.setAttribute("style",w(this.options.modalWidth,this.options.modalHeight)),e.appendChild(this.iframe),this.overlay.appendChild(e),this.options.closeOnClickOutside!==!1&&this.overlay.addEventListener("click",t=>{t.target===this.overlay&&(this.logger.log("Clicked outside modal - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())}),this.options.closeOnEscape!==!1){let t=n=>{n.key==="Escape"&&(this.logger.log("ESC key pressed - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())};document.addEventListener("keydown",t),this._internalOn("close",()=>{document.removeEventListener("keydown",t)})}this.previousOverflow=document.body.style.overflow,document.body.style.overflow="hidden",document.body.appendChild(this.overlay)}renderInline(){if(!this.options.container)throw new Error("Container is required for inline mode");this.container=u(this.options.container);let e=document.createElement("div");e.setAttribute("style",y()),e.setAttribute("data-chaindoc-inline","true"),e.appendChild(this.iframe),this.container.appendChild(e)}handleMessage(e){if(e.origin!==this.allowedOrigin||e.source!==this.iframe.contentWindow||!f(e.data))return;let t=e.data;switch(this.logger.log("Received message:",t.type,t),t.type){case"READY":this.state.isReady=!0,this.options.onReady?.();break;case"RESIZE":"data"in t&&(this.iframe.style.height=`${t.data.height}px`);break;case"SUCCESS":this.state.hasSucceeded=!0,"data"in t&&this.options.onSuccess?.(t.data);break;case"ERROR":"data"in t&&this.options.onError?.(t.data);break;case"CANCEL":this.state.hasSucceeded||this.options.onCancel?.();break;case"CLOSED":this.cleanup();break;case"RESEND_OTP":"data"in t&&this.options.onResendOtp?.(t.data);break;default:this.logger.warn("Unknown message type:",t)}}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){this.internalEventHandlers.has(e)||this.internalEventHandlers.set(e,new Set),this.internalEventHandlers.get(e).add(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.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 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.0.0"}};return O(M);})();
`.trim()}var r=class{constructor(e,t,n){this.overlay=null;this.modalContainer=null;this.container=null;this.previousOverflow="";this.isFullscreen=!1;this.previousIframeStyle=null;this.previousBodyOverflowBeforeFullscreen=null;this.internalEventHandlers=new Map;this.config=e,this.logger=n,this.options=t,this.state={sessionId:this.options.sessionId,mode:this.options.mode||"modal",theme:this.options.theme||"light",isReady:!1,isClosed:!1,hasSucceeded:!1};let s=c(this.config.environment);this.allowedOrigin=u(this.config.environment);let a=m(s,this.options.sessionId,this.options.email,this.state.mode,this.state.theme,this.options.language,this.options.closeOnEscape);this.iframe=this.createIframe(a),this.messageListener=this.handleMessage.bind(this),window.addEventListener("message",this.messageListener),this.state.mode==="modal"?this.renderModal():this.renderInline(),this.logger.log("Instance created",{sessionId:this.state.sessionId,mode:this.state.mode})}createIframe(e){let t=document.createElement("iframe");return t.src=e,t.setAttribute("style",w(this.state.mode)),t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"),t.setAttribute("allow","clipboard-write; camera; microphone; geolocation"),t}renderModal(){if(this.overlay=document.createElement("div"),this.overlay.setAttribute("style",v(this.options.zIndex??999999)),this.overlay.setAttribute("data-chaindoc-overlay","true"),this.modalContainer=document.createElement("div"),this.modalContainer.setAttribute("style",y(this.options.modalWidth,this.options.modalHeight)),this.modalContainer.appendChild(this.iframe),this.overlay.appendChild(this.modalContainer),this.options.closeOnClickOutside!==!1&&this.overlay.addEventListener("click",e=>{e.target===this.overlay&&(this.logger.log("Clicked outside modal - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())}),this.options.closeOnEscape!==!1){let e=t=>{t.key==="Escape"&&(this.logger.log("ESC key pressed - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())};document.addEventListener("keydown",e),this._internalOn("close",()=>{document.removeEventListener("keydown",e)})}this.previousOverflow=document.body.style.overflow,document.body.style.overflow="hidden",document.body.appendChild(this.overlay)}renderInline(){if(!this.options.container)throw new Error("Container is required for inline mode");this.container=p(this.options.container);let e=document.createElement("div");e.setAttribute("style",b()),e.setAttribute("data-chaindoc-inline","true"),e.appendChild(this.iframe),this.container.appendChild(e)}handleMessage(e){if(e.origin!==this.allowedOrigin||e.source!==this.iframe.contentWindow||!f(e.data))return;let t=e.data;switch(this.logger.log("Received message:",t.type,t),t.type){case"READY":this.state.isReady=!0,this.options.onReady?.();break;case"RESIZE":"data"in t&&!this.isFullscreen&&(this.iframe.style.height=`${t.data.height}px`);break;case"SUCCESS":this.state.hasSucceeded=!0,"data"in t&&this.options.onSuccess?.(t.data);break;case"ERROR":"data"in t&&this.options.onError?.(t.data);break;case"CANCEL":this.state.hasSucceeded||this.options.onCancel?.();break;case"CLOSED":this.cleanup();break;case"RESEND_OTP":"data"in t&&this.options.onResendOtp?.(t.data);break;case"REQUEST_FULLSCREEN":this.enterFullscreen();break;case"EXIT_FULLSCREEN":this.exitFullscreen();break;default:this.logger.warn("Unknown message type:",t)}}enterFullscreen(){this.isFullscreen||this.state.isClosed||(this.logger.log("Entering fullscreen"),this.previousIframeStyle=this.iframe.getAttribute("style"),this.previousBodyOverflowBeforeFullscreen=document.body.style.overflow,this.iframe.setAttribute("style",`
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
border: 0;
border-radius: 0;
margin: 0;
padding: 0;
display: block;
z-index: 2147483647;
`.trim()),document.body.style.overflow="hidden",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.previousBodyOverflowBeforeFullscreen!==null&&(document.body.style.overflow=this.previousBodyOverflowBeforeFullscreen,this.previousBodyOverflowBeforeFullscreen=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){this.internalEventHandlers.has(e)||this.internalEventHandlers.set(e,new Set),this.internalEventHandlers.get(e).add(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 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.1.0-alpha.0"}};return O(M);})();
//# 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 if (email) {\n url.searchParams.set(\"email\", email);\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 ?? 400;\n const modalHeight = height ?? 600;\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\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 container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private internalEventHandlers: Map<string, Set<Function>> = 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 const modalContainer = document.createElement('div');\n modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(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) {\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 default:\n this.logger.warn('Unknown message type:', message);\n }\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: Function): void {\n if (!this.internalEventHandlers.has(event)) {\n this.internalEventHandlers.set(event, new Set());\n }\n this.internalEventHandlers.get(event)!.add(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 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","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","modalContainer","getModalContainerStyles","e","handleEscape","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 if (email) {\n url.searchParams.set(\"email\", email);\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 ?? 400;\n const modalHeight = height ?? 600;\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\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 private previousBodyOverflowBeforeFullscreen: string | null = null;\n\n private internalEventHandlers: Map<string, Set<Function>> = 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 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 this.previousBodyOverflowBeforeFullscreen = document.body.style.overflow;\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 document.body.style.overflow = 'hidden';\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 if (this.previousBodyOverflowBeforeFullscreen !== null) {\n document.body.style.overflow = this.previousBodyOverflowBeforeFullscreen;\n this.previousBodyOverflowBeforeFullscreen = null;\n }\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: Function): void {\n if (!this.internalEventHandlers.has(event)) {\n this.internalEventHandlers.set(event, new Set());\n }\n this.internalEventHandlers.get(event)!.add(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","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"]}

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

"use strict";var c=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var I=(i,e)=>{for(var t in e)c(i,t,{get:e[t],enumerable:!0})},x=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of S(e))!C.call(i,s)&&s!==t&&c(i,s,{get:()=>e[s],enumerable:!(n=E(e,s))||n.enumerable});return i};var O=i=>x(c({},"__esModule",{value:!0}),i);var M={};I(M,{ChaindocEmbed:()=>d,EmbedInstance:()=>r});module.exports=O(M);function h(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=h(i);try{return new URL(e).origin}catch{return e}}function p(i,e,t,n,s,a,g){let o=new URL(`/embed/sign/${e}`,i);return t&&o.searchParams.set("email",t),n&&o.searchParams.set("mode",n),s&&o.searchParams.set("theme",s),a&&o.searchParams.set("lang",a),g!==void 0&&o.searchParams.set("closeOnEscape",String(g)),o.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`
"use strict";var h=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var I=(i,e)=>{for(var t in e)h(i,t,{get:e[t],enumerable:!0})},x=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of S(e))!C.call(i,s)&&s!==t&&h(i,s,{get:()=>e[s],enumerable:!(n=E(e,s))||n.enumerable});return i};var O=i=>x(h({},"__esModule",{value:!0}),i);var M={};I(M,{ChaindocEmbed:()=>d,EmbedInstance:()=>r});module.exports=O(M);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 u(i){let e=c(i);try{return new URL(e).origin}catch{return e}}function m(i,e,t,n,s,a,g){let o=new URL(`/embed/sign/${e}`,i);return t&&o.searchParams.set("email",t),n&&o.searchParams.set("mode",n),s&&o.searchParams.set("theme",s),a&&o.searchParams.set("lang",a),g!==void 0&&o.searchParams.set("closeOnEscape",String(g)),o.toString()}function p(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`
position: fixed;

@@ -13,3 +13,3 @@ top: 0;

padding: 20px;
`.trim()}function w(i,e){return`
`.trim()}function y(i,e){return`
position: relative;

@@ -24,3 +24,3 @@ width: 100%;

box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
`.trim()}function b(i){let e=`
`.trim()}function w(i){let e=`
width: 100%;

@@ -36,6 +36,20 @@ border: none;

height: 0;
`.trim()}function y(){return`
`.trim()}function b(){return`
position: relative;
width: 100%;
`.trim()}var r=class{constructor(e,t,n){this.overlay=null;this.container=null;this.previousOverflow="";this.internalEventHandlers=new Map;this.config=e,this.logger=n,this.options=t,this.state={sessionId:this.options.sessionId,mode:this.options.mode||"modal",theme:this.options.theme||"light",isReady:!1,isClosed:!1,hasSucceeded:!1};let s=h(this.config.environment);this.allowedOrigin=m(this.config.environment);let a=p(s,this.options.sessionId,this.options.email,this.state.mode,this.state.theme,this.options.language,this.options.closeOnEscape);this.iframe=this.createIframe(a),this.messageListener=this.handleMessage.bind(this),window.addEventListener("message",this.messageListener),this.state.mode==="modal"?this.renderModal():this.renderInline(),this.logger.log("Instance created",{sessionId:this.state.sessionId,mode:this.state.mode})}createIframe(e){let t=document.createElement("iframe");return t.src=e,t.setAttribute("style",b(this.state.mode)),t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"),t.setAttribute("allow","clipboard-write; camera; microphone; geolocation"),t}renderModal(){this.overlay=document.createElement("div"),this.overlay.setAttribute("style",v(this.options.zIndex??999999)),this.overlay.setAttribute("data-chaindoc-overlay","true");let e=document.createElement("div");if(e.setAttribute("style",w(this.options.modalWidth,this.options.modalHeight)),e.appendChild(this.iframe),this.overlay.appendChild(e),this.options.closeOnClickOutside!==!1&&this.overlay.addEventListener("click",t=>{t.target===this.overlay&&(this.logger.log("Clicked outside modal - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())}),this.options.closeOnEscape!==!1){let t=n=>{n.key==="Escape"&&(this.logger.log("ESC key pressed - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())};document.addEventListener("keydown",t),this._internalOn("close",()=>{document.removeEventListener("keydown",t)})}this.previousOverflow=document.body.style.overflow,document.body.style.overflow="hidden",document.body.appendChild(this.overlay)}renderInline(){if(!this.options.container)throw new Error("Container is required for inline mode");this.container=u(this.options.container);let e=document.createElement("div");e.setAttribute("style",y()),e.setAttribute("data-chaindoc-inline","true"),e.appendChild(this.iframe),this.container.appendChild(e)}handleMessage(e){if(e.origin!==this.allowedOrigin||e.source!==this.iframe.contentWindow||!f(e.data))return;let t=e.data;switch(this.logger.log("Received message:",t.type,t),t.type){case"READY":this.state.isReady=!0,this.options.onReady?.();break;case"RESIZE":"data"in t&&(this.iframe.style.height=`${t.data.height}px`);break;case"SUCCESS":this.state.hasSucceeded=!0,"data"in t&&this.options.onSuccess?.(t.data);break;case"ERROR":"data"in t&&this.options.onError?.(t.data);break;case"CANCEL":this.state.hasSucceeded||this.options.onCancel?.();break;case"CLOSED":this.cleanup();break;case"RESEND_OTP":"data"in t&&this.options.onResendOtp?.(t.data);break;default:this.logger.warn("Unknown message type:",t)}}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){this.internalEventHandlers.has(e)||this.internalEventHandlers.set(e,new Set),this.internalEventHandlers.get(e).add(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.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 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.0.0"}};0&&(module.exports={ChaindocEmbed,EmbedInstance});
`.trim()}var r=class{constructor(e,t,n){this.overlay=null;this.modalContainer=null;this.container=null;this.previousOverflow="";this.isFullscreen=!1;this.previousIframeStyle=null;this.previousBodyOverflowBeforeFullscreen=null;this.internalEventHandlers=new Map;this.config=e,this.logger=n,this.options=t,this.state={sessionId:this.options.sessionId,mode:this.options.mode||"modal",theme:this.options.theme||"light",isReady:!1,isClosed:!1,hasSucceeded:!1};let s=c(this.config.environment);this.allowedOrigin=u(this.config.environment);let a=m(s,this.options.sessionId,this.options.email,this.state.mode,this.state.theme,this.options.language,this.options.closeOnEscape);this.iframe=this.createIframe(a),this.messageListener=this.handleMessage.bind(this),window.addEventListener("message",this.messageListener),this.state.mode==="modal"?this.renderModal():this.renderInline(),this.logger.log("Instance created",{sessionId:this.state.sessionId,mode:this.state.mode})}createIframe(e){let t=document.createElement("iframe");return t.src=e,t.setAttribute("style",w(this.state.mode)),t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"),t.setAttribute("allow","clipboard-write; camera; microphone; geolocation"),t}renderModal(){if(this.overlay=document.createElement("div"),this.overlay.setAttribute("style",v(this.options.zIndex??999999)),this.overlay.setAttribute("data-chaindoc-overlay","true"),this.modalContainer=document.createElement("div"),this.modalContainer.setAttribute("style",y(this.options.modalWidth,this.options.modalHeight)),this.modalContainer.appendChild(this.iframe),this.overlay.appendChild(this.modalContainer),this.options.closeOnClickOutside!==!1&&this.overlay.addEventListener("click",e=>{e.target===this.overlay&&(this.logger.log("Clicked outside modal - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())}),this.options.closeOnEscape!==!1){let e=t=>{t.key==="Escape"&&(this.logger.log("ESC key pressed - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())};document.addEventListener("keydown",e),this._internalOn("close",()=>{document.removeEventListener("keydown",e)})}this.previousOverflow=document.body.style.overflow,document.body.style.overflow="hidden",document.body.appendChild(this.overlay)}renderInline(){if(!this.options.container)throw new Error("Container is required for inline mode");this.container=p(this.options.container);let e=document.createElement("div");e.setAttribute("style",b()),e.setAttribute("data-chaindoc-inline","true"),e.appendChild(this.iframe),this.container.appendChild(e)}handleMessage(e){if(e.origin!==this.allowedOrigin||e.source!==this.iframe.contentWindow||!f(e.data))return;let t=e.data;switch(this.logger.log("Received message:",t.type,t),t.type){case"READY":this.state.isReady=!0,this.options.onReady?.();break;case"RESIZE":"data"in t&&!this.isFullscreen&&(this.iframe.style.height=`${t.data.height}px`);break;case"SUCCESS":this.state.hasSucceeded=!0,"data"in t&&this.options.onSuccess?.(t.data);break;case"ERROR":"data"in t&&this.options.onError?.(t.data);break;case"CANCEL":this.state.hasSucceeded||this.options.onCancel?.();break;case"CLOSED":this.cleanup();break;case"RESEND_OTP":"data"in t&&this.options.onResendOtp?.(t.data);break;case"REQUEST_FULLSCREEN":this.enterFullscreen();break;case"EXIT_FULLSCREEN":this.exitFullscreen();break;default:this.logger.warn("Unknown message type:",t)}}enterFullscreen(){this.isFullscreen||this.state.isClosed||(this.logger.log("Entering fullscreen"),this.previousIframeStyle=this.iframe.getAttribute("style"),this.previousBodyOverflowBeforeFullscreen=document.body.style.overflow,this.iframe.setAttribute("style",`
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
border: 0;
border-radius: 0;
margin: 0;
padding: 0;
display: block;
z-index: 2147483647;
`.trim()),document.body.style.overflow="hidden",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.previousBodyOverflowBeforeFullscreen!==null&&(document.body.style.overflow=this.previousBodyOverflowBeforeFullscreen,this.previousBodyOverflowBeforeFullscreen=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){this.internalEventHandlers.has(e)||this.internalEventHandlers.set(e,new Set),this.internalEventHandlers.get(e).add(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 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.1.0-alpha.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 if (email) {\n url.searchParams.set(\"email\", email);\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 ?? 400;\n const modalHeight = height ?? 600;\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\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 container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private internalEventHandlers: Map<string, Set<Function>> = 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 const modalContainer = document.createElement('div');\n modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(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) {\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 default:\n this.logger.warn('Unknown message type:', message);\n }\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: Function): void {\n if (!this.internalEventHandlers.has(event)) {\n this.internalEventHandlers.set(event, new Set());\n }\n this.internalEventHandlers.get(event)!.add(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 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","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","modalContainer","getModalContainerStyles","e","handleEscape","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 if (email) {\n url.searchParams.set(\"email\", email);\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 ?? 400;\n const modalHeight = height ?? 600;\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\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 private previousBodyOverflowBeforeFullscreen: string | null = null;\n\n private internalEventHandlers: Map<string, Set<Function>> = 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 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 this.previousBodyOverflowBeforeFullscreen = document.body.style.overflow;\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 document.body.style.overflow = 'hidden';\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 if (this.previousBodyOverflowBeforeFullscreen !== null) {\n document.body.style.overflow = this.previousBodyOverflowBeforeFullscreen;\n this.previousBodyOverflowBeforeFullscreen = null;\n }\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: Function): void {\n if (!this.internalEventHandlers.has(event)) {\n this.internalEventHandlers.set(event, new Set());\n }\n this.internalEventHandlers.get(event)!.add(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","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"]}

@@ -71,2 +71,8 @@ type Environment = "production" | "staging" | "development";

data: ResendOtpData;
} | {
source: "chaindoc-embed";
type: "REQUEST_FULLSCREEN";
} | {
source: "chaindoc-embed";
type: "EXIT_FULLSCREEN";
};

@@ -104,2 +110,3 @@ type SdkToIframeMessage = {

private overlay;
private modalContainer;
private container;

@@ -109,2 +116,5 @@ private allowedOrigin;

private previousOverflow;
private isFullscreen;
private previousIframeStyle;
private previousBodyOverflowBeforeFullscreen;
private internalEventHandlers;

@@ -116,2 +126,4 @@ constructor(config: InternalConfig, options: SignatureFlowOptions, logger: Logger);

private handleMessage;
private enterFullscreen;
private exitFullscreen;
private sendMessage;

@@ -118,0 +130,0 @@ close(): void;

@@ -71,2 +71,8 @@ type Environment = "production" | "staging" | "development";

data: ResendOtpData;
} | {
source: "chaindoc-embed";
type: "REQUEST_FULLSCREEN";
} | {
source: "chaindoc-embed";
type: "EXIT_FULLSCREEN";
};

@@ -104,2 +110,3 @@ type SdkToIframeMessage = {

private overlay;
private modalContainer;
private container;

@@ -109,2 +116,5 @@ private allowedOrigin;

private previousOverflow;
private isFullscreen;
private previousIframeStyle;
private previousBodyOverflowBeforeFullscreen;
private internalEventHandlers;

@@ -116,2 +126,4 @@ constructor(config: InternalConfig, options: SignatureFlowOptions, logger: Logger);

private handleMessage;
private enterFullscreen;
private exitFullscreen;
private sendMessage;

@@ -118,0 +130,0 @@ close(): void;

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

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 g(i){let e=d(i);try{return new URL(e).origin}catch{return e}}function m(i,e,t,n,r,a,h){let s=new URL(`/embed/sign/${e}`,i);return t&&s.searchParams.set("email",t),n&&s.searchParams.set("mode",n),r&&s.searchParams.set("theme",r),a&&s.searchParams.set("lang",a),h!==void 0&&s.searchParams.set("closeOnEscape",String(h)),s.toString()}function p(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 u(i){return typeof i=="object"&&i!==null&&"source"in i&&i.source==="chaindoc-embed"}function f(i){return`
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 g(i){let e=d(i);try{return new URL(e).origin}catch{return e}}function u(i,e,t,n,r,a,c){let s=new URL(`/embed/sign/${e}`,i);return t&&s.searchParams.set("email",t),n&&s.searchParams.set("mode",n),r&&s.searchParams.set("theme",r),a&&s.searchParams.set("lang",a),c!==void 0&&s.searchParams.set("closeOnEscape",String(c)),s.toString()}function m(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 p(i){return typeof i=="object"&&i!==null&&"source"in i&&i.source==="chaindoc-embed"}function f(i){return`
position: fixed;

@@ -23,3 +23,3 @@ top: 0;

box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
`.trim()}function w(i){let e=`
`.trim()}function y(i){let e=`
width: 100%;

@@ -35,6 +35,20 @@ border: none;

height: 0;
`.trim()}function b(){return`
`.trim()}function w(){return`
position: relative;
width: 100%;
`.trim()}var o=class{constructor(e,t,n){this.overlay=null;this.container=null;this.previousOverflow="";this.internalEventHandlers=new Map;this.config=e,this.logger=n,this.options=t,this.state={sessionId:this.options.sessionId,mode:this.options.mode||"modal",theme:this.options.theme||"light",isReady:!1,isClosed:!1,hasSucceeded:!1};let r=d(this.config.environment);this.allowedOrigin=g(this.config.environment);let a=m(r,this.options.sessionId,this.options.email,this.state.mode,this.state.theme,this.options.language,this.options.closeOnEscape);this.iframe=this.createIframe(a),this.messageListener=this.handleMessage.bind(this),window.addEventListener("message",this.messageListener),this.state.mode==="modal"?this.renderModal():this.renderInline(),this.logger.log("Instance created",{sessionId:this.state.sessionId,mode:this.state.mode})}createIframe(e){let t=document.createElement("iframe");return t.src=e,t.setAttribute("style",w(this.state.mode)),t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"),t.setAttribute("allow","clipboard-write; camera; microphone; geolocation"),t}renderModal(){this.overlay=document.createElement("div"),this.overlay.setAttribute("style",f(this.options.zIndex??999999)),this.overlay.setAttribute("data-chaindoc-overlay","true");let e=document.createElement("div");if(e.setAttribute("style",v(this.options.modalWidth,this.options.modalHeight)),e.appendChild(this.iframe),this.overlay.appendChild(e),this.options.closeOnClickOutside!==!1&&this.overlay.addEventListener("click",t=>{t.target===this.overlay&&(this.logger.log("Clicked outside modal - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())}),this.options.closeOnEscape!==!1){let t=n=>{n.key==="Escape"&&(this.logger.log("ESC key pressed - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())};document.addEventListener("keydown",t),this._internalOn("close",()=>{document.removeEventListener("keydown",t)})}this.previousOverflow=document.body.style.overflow,document.body.style.overflow="hidden",document.body.appendChild(this.overlay)}renderInline(){if(!this.options.container)throw new Error("Container is required for inline mode");this.container=p(this.options.container);let e=document.createElement("div");e.setAttribute("style",b()),e.setAttribute("data-chaindoc-inline","true"),e.appendChild(this.iframe),this.container.appendChild(e)}handleMessage(e){if(e.origin!==this.allowedOrigin||e.source!==this.iframe.contentWindow||!u(e.data))return;let t=e.data;switch(this.logger.log("Received message:",t.type,t),t.type){case"READY":this.state.isReady=!0,this.options.onReady?.();break;case"RESIZE":"data"in t&&(this.iframe.style.height=`${t.data.height}px`);break;case"SUCCESS":this.state.hasSucceeded=!0,"data"in t&&this.options.onSuccess?.(t.data);break;case"ERROR":"data"in t&&this.options.onError?.(t.data);break;case"CANCEL":this.state.hasSucceeded||this.options.onCancel?.();break;case"CLOSED":this.cleanup();break;case"RESEND_OTP":"data"in t&&this.options.onResendOtp?.(t.data);break;default:this.logger.warn("Unknown message type:",t)}}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){this.internalEventHandlers.has(e)||this.internalEventHandlers.set(e,new Set),this.internalEventHandlers.get(e).add(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.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 c=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.0.0"}};export{c as ChaindocEmbed,o as EmbedInstance};
`.trim()}var o=class{constructor(e,t,n){this.overlay=null;this.modalContainer=null;this.container=null;this.previousOverflow="";this.isFullscreen=!1;this.previousIframeStyle=null;this.previousBodyOverflowBeforeFullscreen=null;this.internalEventHandlers=new Map;this.config=e,this.logger=n,this.options=t,this.state={sessionId:this.options.sessionId,mode:this.options.mode||"modal",theme:this.options.theme||"light",isReady:!1,isClosed:!1,hasSucceeded:!1};let r=d(this.config.environment);this.allowedOrigin=g(this.config.environment);let a=u(r,this.options.sessionId,this.options.email,this.state.mode,this.state.theme,this.options.language,this.options.closeOnEscape);this.iframe=this.createIframe(a),this.messageListener=this.handleMessage.bind(this),window.addEventListener("message",this.messageListener),this.state.mode==="modal"?this.renderModal():this.renderInline(),this.logger.log("Instance created",{sessionId:this.state.sessionId,mode:this.state.mode})}createIframe(e){let t=document.createElement("iframe");return t.src=e,t.setAttribute("style",y(this.state.mode)),t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-downloads"),t.setAttribute("allow","clipboard-write; camera; microphone; geolocation"),t}renderModal(){if(this.overlay=document.createElement("div"),this.overlay.setAttribute("style",f(this.options.zIndex??999999)),this.overlay.setAttribute("data-chaindoc-overlay","true"),this.modalContainer=document.createElement("div"),this.modalContainer.setAttribute("style",v(this.options.modalWidth,this.options.modalHeight)),this.modalContainer.appendChild(this.iframe),this.overlay.appendChild(this.modalContainer),this.options.closeOnClickOutside!==!1&&this.overlay.addEventListener("click",e=>{e.target===this.overlay&&(this.logger.log("Clicked outside modal - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())}),this.options.closeOnEscape!==!1){let e=t=>{t.key==="Escape"&&(this.logger.log("ESC key pressed - closing"),this.state.hasSucceeded||this.options.onCancel?.(),this.close())};document.addEventListener("keydown",e),this._internalOn("close",()=>{document.removeEventListener("keydown",e)})}this.previousOverflow=document.body.style.overflow,document.body.style.overflow="hidden",document.body.appendChild(this.overlay)}renderInline(){if(!this.options.container)throw new Error("Container is required for inline mode");this.container=m(this.options.container);let e=document.createElement("div");e.setAttribute("style",w()),e.setAttribute("data-chaindoc-inline","true"),e.appendChild(this.iframe),this.container.appendChild(e)}handleMessage(e){if(e.origin!==this.allowedOrigin||e.source!==this.iframe.contentWindow||!p(e.data))return;let t=e.data;switch(this.logger.log("Received message:",t.type,t),t.type){case"READY":this.state.isReady=!0,this.options.onReady?.();break;case"RESIZE":"data"in t&&!this.isFullscreen&&(this.iframe.style.height=`${t.data.height}px`);break;case"SUCCESS":this.state.hasSucceeded=!0,"data"in t&&this.options.onSuccess?.(t.data);break;case"ERROR":"data"in t&&this.options.onError?.(t.data);break;case"CANCEL":this.state.hasSucceeded||this.options.onCancel?.();break;case"CLOSED":this.cleanup();break;case"RESEND_OTP":"data"in t&&this.options.onResendOtp?.(t.data);break;case"REQUEST_FULLSCREEN":this.enterFullscreen();break;case"EXIT_FULLSCREEN":this.exitFullscreen();break;default:this.logger.warn("Unknown message type:",t)}}enterFullscreen(){this.isFullscreen||this.state.isClosed||(this.logger.log("Entering fullscreen"),this.previousIframeStyle=this.iframe.getAttribute("style"),this.previousBodyOverflowBeforeFullscreen=document.body.style.overflow,this.iframe.setAttribute("style",`
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
max-width: none;
max-height: none;
border: 0;
border-radius: 0;
margin: 0;
padding: 0;
display: block;
z-index: 2147483647;
`.trim()),document.body.style.overflow="hidden",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.previousBodyOverflowBeforeFullscreen!==null&&(document.body.style.overflow=this.previousBodyOverflowBeforeFullscreen,this.previousBodyOverflowBeforeFullscreen=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){this.internalEventHandlers.has(e)||this.internalEventHandlers.set(e,new Set),this.internalEventHandlers.get(e).add(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 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.1.0-alpha.0"}};export{h as ChaindocEmbed,o 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 if (email) {\n url.searchParams.set(\"email\", email);\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 ?? 400;\n const modalHeight = height ?? 600;\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\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 container: HTMLElement | null = null;\n\n private allowedOrigin: string;\n private messageListener: (event: MessageEvent) => void;\n private previousOverflow: string = '';\n\n private internalEventHandlers: Map<string, Set<Function>> = 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 const modalContainer = document.createElement('div');\n modalContainer.setAttribute(\n 'style',\n getModalContainerStyles(this.options.modalWidth, this.options.modalHeight)\n );\n modalContainer.appendChild(this.iframe);\n\n // Add container to overlay\n this.overlay.appendChild(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) {\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 default:\n this.logger.warn('Unknown message type:', message);\n }\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: Function): void {\n if (!this.internalEventHandlers.has(event)) {\n this.internalEventHandlers.set(event, new Set());\n }\n this.internalEventHandlers.get(event)!.add(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 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,EAEvD,OAAIG,GACFK,EAAI,aAAa,IAAI,QAASL,CAAK,EAGjCC,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,SAASC,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,CCrHO,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,CCjCO,IAAMC,EAAN,KAAoB,CAgBzB,YACEC,EACAC,EACAC,EACA,CAbF,KAAQ,QAAiC,KACzC,KAAQ,UAAgC,KAIxC,KAAQ,iBAA2B,GAEnC,KAAQ,sBAAoD,IAAI,IAO9D,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,CAE1B,KAAK,QAAU,SAAS,cAAc,KAAK,EAC3C,KAAK,QAAQ,aAAa,QAASE,EAAiB,KAAK,QAAQ,QAAU,MAAM,CAAC,EAClF,KAAK,QAAQ,aAAa,wBAAyB,MAAM,EAGzD,IAAMC,EAAiB,SAAS,cAAc,KAAK,EAwBnD,GAvBAA,EAAe,aACb,QACAC,EAAwB,KAAK,QAAQ,WAAY,KAAK,QAAQ,WAAW,CAC3E,EACAD,EAAe,YAAY,KAAK,MAAM,EAGtC,KAAK,QAAQ,YAAYA,CAAc,EAGnC,KAAK,QAAQ,sBAAwB,IACvC,KAAK,QAAQ,iBAAiB,QAAUE,GAAM,CACxCA,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,EAAgBD,GAAqB,CACrCA,EAAE,MAAQ,WACZ,KAAK,OAAO,IAAI,2BAA2B,EACtC,KAAK,MAAM,cACd,KAAK,QAAQ,WAAW,EAE1B,KAAK,MAAM,EAEf,EACA,SAAS,iBAAiB,UAAWC,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,UAAYC,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,IACZ,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,QACE,KAAK,OAAO,KAAK,wBAAyBA,CAAO,CACrD,CACF,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,EAAyB,CAC7C,KAAK,sBAAsB,IAAIJ,CAAK,GACvC,KAAK,sBAAsB,IAAIA,EAAO,IAAI,GAAK,EAEjD,KAAK,sBAAsB,IAAIA,CAAK,EAAG,IAAII,CAAO,CACpD,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,EAEtC,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,ECzWO,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,OACT,CACF","names":["getIframeBaseUrl","environment","getAllowedOrigin","baseUrl","buildIframeUrl","sessionId","email","mode","theme","language","closeOnEscape","url","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","modalContainer","getModalContainerStyles","e","handleEscape","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 if (email) {\n url.searchParams.set(\"email\", email);\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 ?? 400;\n const modalHeight = height ?? 600;\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\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 private previousBodyOverflowBeforeFullscreen: string | null = null;\n\n private internalEventHandlers: Map<string, Set<Function>> = 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 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 this.previousBodyOverflowBeforeFullscreen = document.body.style.overflow;\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 document.body.style.overflow = 'hidden';\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 if (this.previousBodyOverflowBeforeFullscreen !== null) {\n document.body.style.overflow = this.previousBodyOverflowBeforeFullscreen;\n this.previousBodyOverflowBeforeFullscreen = null;\n }\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: Function): void {\n if (!this.internalEventHandlers.has(event)) {\n this.internalEventHandlers.set(event, new Set());\n }\n this.internalEventHandlers.get(event)!.add(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","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.0.0",
"version": "2.1.0-alpha.0",
"description": "JavaScript/TypeScript SDK for embedding Chaindoc document signing flow via iframe",

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