@alihaiderrana/email-builder-sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var b=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var $=(t,s)=>{for(var n in s)b(t,n,{get:s[n],enumerable:!0})},ee=(t,s,n,d)=>{if(s&&typeof s=="object"||typeof s=="function")for(let c of X(s))!Z.call(t,c)&&c!==n&&b(t,c,{get:()=>s[c],enumerable:!(d=Q(s,c))||d.enumerable});return t};var re=t=>ee(b({},"__esModule",{value:!0}),t);var ue={};$(ue,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>F,EmailBuilder:()=>le,createMessageMeta:()=>D,isMessageLike:()=>B});module.exports=re(ue);var r=require("react");var F="1.0.0",te=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS"];function B(t){if(typeof t!="object"||t===null)return!1;let s=t;if(typeof s.type!="string"||!te.includes(s.type))return!1;if("meta"in s&&s.meta!==void 0){let n=s.meta;if(n.id&&typeof n.id!="string"||n.correlationId&&typeof n.correlationId!="string"||n.version&&typeof n.version!="string"||n.sentAt&&typeof n.sentAt!="number")return!1}return!0}function D(t){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:t,version:F,sentAt:Date.now()}}function V(t,s){if(s){let d=new URL(s);if(d.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return d.origin}let n;try{n=new URL(t)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!n.origin||n.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return n.origin}function R(t,s){let n=D(s);return{...t,meta:n}}function H(t){return JSON.stringify(t!=null?t:null)}var m=require("react/jsx-runtime"),se="allow-scripts allow-same-origin allow-forms",ne="<h1>Hello World</h1><p>Start building your email template.</p>",oe={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",fontSize:"0.875rem",fontWeight:500,background:"linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))",color:"#fff",zIndex:2},ae={border:"none",width:"100%",height:"100%"};function ie({src:t,initialHtml:s,config:n,className:d,style:c,iframeTitle:Y="Email Builder",sandbox:v=se,onChange:M,onSave:E,onUpload:L,onReady:w,onStatusChange:S,allowedOrigin:O},G){let A=(0,r.useRef)(null),i=(0,r.useRef)(null),p=(0,r.useRef)(!1),P=(0,r.useRef)("loading"),[z,K]=(0,r.useState)("loading"),[q,j]=(0,r.useState)(0),I=(0,r.useRef)([]),g=(0,r.useRef)(null),T=s!=null?s:ne,k=(0,r.useRef)(H({html:T,config:n})),h=(0,r.useRef)({type:"INIT",payload:{html:T,config:n}}),C=(0,r.useMemo)(()=>V(t,O),[t,O]),U=(0,r.useCallback)(()=>{var e;return(e=g.current)!=null?e:C},[C]),l=(0,r.useCallback)(e=>{P.current!==e&&(P.current=e,K(e),S==null||S(e))},[S]),f=(0,r.useCallback)((e,o)=>{var u,y;let a=(y=(u=A.current)==null?void 0:u.contentWindow)!=null?y:i.current;if(a&&(i.current=a),!i.current||!p.current){I.current.push({message:e,correlationId:o});return}i.current.postMessage(R(e,o),U())},[U]),N=(0,r.useCallback)(()=>{if(!p.current||!i.current)return;let e=[...I.current];I.current=[],e.forEach(({message:o,correlationId:a})=>{var u;(u=i.current)==null||u.postMessage(R(o,a),U())})},[U]),_=(0,r.useCallback)(()=>{p.current=!0,l("ready"),w==null||w(),f(h.current),N()},[N,w,f,l]),W=(0,r.useCallback)(async e=>{var o;if(e.type==="UPLOAD"){if(!L){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{l("loading");let a=await L(e.payload.file);f({type:"UPLOAD_SUCCESS",payload:{url:a}},(o=e.meta)==null?void 0:o.id)}catch(a){l("error"),console.error("[EmailBuilderSDK] Upload handler failed",a)}finally{P.current!=="error"&&l("ready")}}},[L,f,l]),x=(0,r.useCallback)(e=>{var u,y;let o=(y=(u=A.current)==null?void 0:u.contentWindow)!=null?y:i.current;if(!o||e.source!==o||!B(e.data))return;if(!g.current)g.current=e.origin;else if(e.origin!==g.current)return;let a=e.data;switch(e.source&&e.source!==i.current&&(i.current=e.source),a.type){case"READY":_();break;case"CHANGE":M==null||M(a.payload.html);break;case"SAVE":E==null||E(a.payload.html);break;case"UPLOAD":W(a);break;default:break}},[_,W,M,E]);(0,r.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",x),()=>{window.removeEventListener("message",x)}},[x]),(0,r.useEffect)(()=>{let e={html:T,config:n},o=H(e);h.current={type:"INIT",payload:e},o!==k.current&&p.current&&f(h.current),k.current=o},[n,T,f]);let J=(0,r.useCallback)(()=>{var e,o;i.current=(o=(e=A.current)==null?void 0:e.contentWindow)!=null?o:null,p.current=!1,g.current=null,l("loading")},[l]);return(0,r.useImperativeHandle)(G,()=>({reload(){I.current=[],p.current=!1,i.current=null,g.current=null,l("loading"),j(e=>e+1)}}),[l]),(0,m.jsxs)("div",{className:d,style:{position:"relative",width:"100%",height:"100%",...c},children:[(0,m.jsx)("iframe",{ref:A,src:t,title:Y,sandbox:v,style:ae,loading:"lazy",allowFullScreen:!0,onLoad:J},q),z!=="ready"&&(0,m.jsx)("div",{style:oe,children:"Connecting to builder\u2026"})]})}var le=(0,r.forwardRef)(ie);0&&(module.exports={EMAIL_BUILDER_PROTOCOL_VERSION,EmailBuilder,createMessageMeta,isMessageLike});
1
+ "use strict";var O=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var ee=(t,n)=>{for(var s in n)O(t,s,{get:n[s],enumerable:!0})},re=(t,n,s,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let f of Z(n))!$.call(t,f)&&f!==s&&O(t,f,{get:()=>n[f],enumerable:!(p=X(n,f))||p.enumerable});return t};var te=t=>re(O({},"__esModule",{value:!0}),t);var ce={};ee(ce,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>V,EmailBuilder:()=>ue,createMessageMeta:()=>k,isMessageLike:()=>b});module.exports=te(ce);var r=require("react");var V="1.0.0",ne=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS"];function b(t){if(typeof t!="object"||t===null)return!1;let n=t;if(typeof n.type!="string"||!ne.includes(n.type))return!1;if("meta"in n&&n.meta!==void 0){let s=n.meta;if(s.id&&typeof s.id!="string"||s.correlationId&&typeof s.correlationId!="string"||s.version&&typeof s.version!="string"||s.sentAt&&typeof s.sentAt!="number")return!1}return!0}function k(t){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:t,version:V,sentAt:Date.now()}}function Y(t,n){if(n){let p=new URL(n);if(p.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return p.origin}let s;try{s=new URL(t)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!s.origin||s.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return s.origin}function x(t,n){let s=k(n);return{...t,meta:s}}function C(t){return JSON.stringify(t!=null?t:null)}var M=require("react/jsx-runtime"),se="allow-scripts allow-same-origin allow-forms",oe="<h1>Hello World</h1><p>Start building your email template.</p>",ae={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",fontSize:"0.875rem",fontWeight:500,background:"linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))",color:"#fff",zIndex:2},ie={border:"none",width:"100%",height:"100%"};function le({src:t,initialHtml:n,config:s,className:p,style:f,iframeTitle:v="Email Builder",sandbox:G=se,onChange:E,onSave:w,onUpload:D,onReady:S,onStatusChange:T,allowedOrigin:N},z){let A=(0,r.useRef)(null),a=(0,r.useRef)(null),c=(0,r.useRef)(!1),R=(0,r.useRef)("loading"),[K,q]=(0,r.useState)("loading"),[j,J]=(0,r.useState)(0),I=(0,r.useRef)([]),g=(0,r.useRef)(null),l=(0,r.useRef)(null),U=n!=null?n:oe,_=(0,r.useRef)(C({html:U,config:s})),B=(0,r.useRef)({type:"INIT",payload:{html:U,config:s}}),L=(0,r.useMemo)(()=>Y(t,N),[t,N]),P=(0,r.useCallback)(()=>{var e;return(e=g.current)!=null?e:L},[L]),u=(0,r.useCallback)(e=>{R.current!==e&&(R.current=e,q(e),T==null||T(e))},[T]),m=(0,r.useCallback)((e,o)=>{var d,y;let i=(y=(d=A.current)==null?void 0:d.contentWindow)!=null?y:a.current;if(i&&(a.current=i),!a.current||!c.current){I.current.push({message:e,correlationId:o});return}a.current.postMessage(x(e,o),P())},[P]),W=(0,r.useCallback)(()=>{if(!c.current||!a.current)return;let e=[...I.current];I.current=[],e.forEach(({message:o,correlationId:i})=>{var d;(d=a.current)==null||d.postMessage(x(o,i),P())})},[P]),h=(0,r.useCallback)(()=>{c.current||(l.current&&(window.clearTimeout(l.current),l.current=null),c.current=!0,u("ready"),S==null||S(),m(B.current),W())},[W,S,m,u]),F=(0,r.useCallback)(async e=>{var o;if(e.type==="UPLOAD"){if(!D){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{u("loading");let i=await D(e.payload.file);m({type:"UPLOAD_SUCCESS",payload:{url:i}},(o=e.meta)==null?void 0:o.id)}catch(i){u("error"),console.error("[EmailBuilderSDK] Upload handler failed",i)}finally{R.current!=="error"&&u("ready")}}},[D,m,u]),H=(0,r.useCallback)(e=>{var d,y;let o=(y=(d=A.current)==null?void 0:d.contentWindow)!=null?y:a.current;if(!o||e.source!==o||!b(e.data))return;if(!g.current)g.current=e.origin;else if(e.origin!==g.current)return;let i=e.data;switch(e.source&&e.source!==a.current&&(a.current=e.source),i.type){case"READY":h();break;case"CHANGE":E==null||E(i.payload.html);break;case"SAVE":w==null||w(i.payload.html);break;case"UPLOAD":F(i);break;default:break}},[h,F,E,w]);(0,r.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",H),()=>{window.removeEventListener("message",H)}},[H]),(0,r.useEffect)(()=>{let e={html:U,config:s},o=C(e);B.current={type:"INIT",payload:e},o!==_.current&&c.current&&m(B.current),_.current=o},[s,U,m]);let Q=(0,r.useCallback)(()=>{var e,o;if(a.current=(o=(e=A.current)==null?void 0:e.contentWindow)!=null?o:null,c.current=!1,g.current=null,u("loading"),a.current)try{a.current.postMessage(x(B.current),L)}catch{}l.current&&window.clearTimeout(l.current),l.current=window.setTimeout(()=>{c.current||h()},4e3)},[L,h,u]);return(0,r.useImperativeHandle)(z,()=>({reload(){I.current=[],c.current=!1,a.current=null,g.current=null,l.current&&(window.clearTimeout(l.current),l.current=null),u("loading"),J(e=>e+1)}}),[u]),(0,r.useEffect)(()=>()=>{l.current&&(window.clearTimeout(l.current),l.current=null)},[]),(0,M.jsxs)("div",{className:p,style:{position:"relative",width:"100%",height:"100%",...f},children:[(0,M.jsx)("iframe",{ref:A,src:t,title:v,sandbox:G,style:ie,loading:"lazy",allowFullScreen:!0,onLoad:Q},j),K!=="ready"&&(0,M.jsx)("div",{style:ae,children:"Connecting to builder\u2026"})]})}var ue=(0,r.forwardRef)(le);0&&(module.exports={EMAIL_BUILDER_PROTOCOL_VERSION,EmailBuilder,createMessageMeta,isMessageLike});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/EmailBuilder.tsx","../src/protocol.ts","../src/utils.ts"],"sourcesContent":["export * from './EmailBuilder';\nexport * from './types';\nexport * from './protocol';\n","import React, {\n CSSProperties,\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { BuilderToHostMessage, HostToBuilderMessage } from './protocol';\nimport { isMessageLike } from './protocol';\nimport { buildEnvelope, deriveAllowedOrigin, stableSignature } from './utils';\nimport type { EmailBuilderHandle, EmailBuilderProps, EmailBuilderStatus } from './types';\n\nconst DEFAULT_SANDBOX = 'allow-scripts allow-same-origin allow-forms';\nconst DEFAULT_INITIAL_HTML = '<h1>Hello World</h1><p>Start building your email template.</p>';\n\ntype PendingMessage = {\n message: HostToBuilderMessage;\n correlationId?: string;\n};\n\nconst overlayStyle: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '0.875rem',\n fontWeight: 500,\n background: 'linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))',\n color: '#fff',\n zIndex: 2,\n};\n\nconst iframeStyle: CSSProperties = {\n border: 'none',\n width: '100%',\n height: '100%',\n};\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n config,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onReady,\n onStatusChange,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const builderWindowRef = useRef<Window | null>(null);\n const readyRef = useRef(false);\n const statusRef = useRef<EmailBuilderStatus>('loading');\n const [status, setStatus] = useState<EmailBuilderStatus>('loading');\n const [reloadKey, setReloadKey] = useState(0);\n const queueRef = useRef<PendingMessage[]>([]);\n const runtimeOriginRef = useRef<string | null>(null);\n const effectiveInitialHtml = initialHtml ?? DEFAULT_INITIAL_HTML;\n const initSignatureRef = useRef(stableSignature({ html: effectiveInitialHtml, config }));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: { html: effectiveInitialHtml, config },\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(src, allowedOrigin), [src, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => runtimeOriginRef.current ?? expectedOrigin, [expectedOrigin]);\n\n const setStatusSafely = useCallback(\n (next: EmailBuilderStatus) => {\n if (statusRef.current === next) {\n return;\n }\n statusRef.current = next;\n setStatus(next);\n onStatusChange?.(next);\n },\n [onStatusChange]\n );\n\n const postMessage = useCallback(\n (message: HostToBuilderMessage, correlationId?: string) => {\n const target = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (target) {\n builderWindowRef.current = target;\n }\n\n if (!builderWindowRef.current || !readyRef.current) {\n queueRef.current.push({ message, correlationId });\n return;\n }\n\n builderWindowRef.current.postMessage(buildEnvelope(message, correlationId), resolveTargetOrigin());\n },\n [resolveTargetOrigin]\n );\n\n const flushQueue = useCallback(() => {\n if (!readyRef.current || !builderWindowRef.current) {\n return;\n }\n const pending = [...queueRef.current];\n queueRef.current = [];\n pending.forEach(({ message, correlationId }) => {\n builderWindowRef.current?.postMessage(\n buildEnvelope(message, correlationId),\n resolveTargetOrigin()\n );\n });\n }, [resolveTargetOrigin]);\n\n const handleReadyMessage = useCallback(() => {\n readyRef.current = true;\n setStatusSafely('ready');\n onReady?.();\n postMessage(latestInitRef.current);\n flushQueue();\n }, [flushQueue, onReady, postMessage, setStatusSafely]);\n\n const handleUpload = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'UPLOAD') {\n return;\n }\n if (!onUpload) {\n console.warn('[EmailBuilderSDK] Upload requested but no onUpload handler is configured.');\n return;\n }\n try {\n setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, onChange, onSave]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [handleMessage]);\n\n useEffect(() => {\n const nextPayload = { html: effectiveInitialHtml, config };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage]);\n\n const handleIframeLoad = useCallback(() => {\n builderWindowRef.current = iframeRef.current?.contentWindow ?? null;\n readyRef.current = false;\n runtimeOriginRef.current = null;\n setStatusSafely('loading');\n }, [setStatusSafely]);\n\n useImperativeHandle(\n ref,\n () => ({\n reload() {\n queueRef.current = [];\n readyRef.current = false;\n builderWindowRef.current = null;\n runtimeOriginRef.current = null;\n setStatusSafely('loading');\n setReloadKey((key) => key + 1);\n },\n }),\n [setStatusSafely]\n );\n\n return (\n <div className={className} style={{ position: 'relative', width: '100%', height: '100%', ...style }}>\n <iframe\n key={reloadKey}\n ref={iframeRef}\n src={src}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && <div style={overlayStyle}>Connecting to builder…</div>}\n </div>\n );\n}\n\nexport const EmailBuilder = forwardRef(EmailBuilderInner);\n","export const EMAIL_BUILDER_PROTOCOL_VERSION = '1.0.0';\n\nexport type MessageType =\n | 'INIT'\n | 'READY'\n | 'CHANGE'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS';\n\nexport interface MessageMeta {\n id: string;\n correlationId?: string;\n version: string;\n sentAt: number;\n}\n\nexport type BuilderConfig = Record<string, unknown> | undefined;\n\nexport interface InitPayload {\n html: string;\n config?: BuilderConfig;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface SavePayload {\n html: string;\n}\n\nexport interface UploadPayload {\n file: File;\n}\n\nexport interface UploadSuccessPayload {\n url: string;\n}\n\nexport type Message =\n | { type: 'INIT'; payload: InitPayload; meta?: MessageMeta }\n | { type: 'READY'; meta?: MessageMeta }\n | { type: 'CHANGE'; payload: ChangePayload; meta?: MessageMeta }\n | { type: 'SAVE'; payload: SavePayload; meta?: MessageMeta }\n | { type: 'UPLOAD'; payload: UploadPayload; meta?: MessageMeta }\n | { type: 'UPLOAD_SUCCESS'; payload: UploadSuccessPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = ['INIT', 'READY', 'CHANGE', 'SAVE', 'UPLOAD', 'UPLOAD_SUCCESS'];\n\nexport function isMessageLike(value: unknown): value is Message {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as { type?: unknown; payload?: unknown; meta?: unknown };\n if (typeof candidate.type !== 'string' || !VALID_TYPES.includes(candidate.type as MessageType)) {\n return false;\n }\n\n if ('meta' in candidate && candidate.meta !== undefined) {\n const meta = candidate.meta as Partial<MessageMeta>;\n if (\n (meta.id && typeof meta.id !== 'string') ||\n (meta.correlationId && typeof meta.correlationId !== 'string') ||\n (meta.version && typeof meta.version !== 'string') ||\n (meta.sentAt && typeof meta.sentAt !== 'number')\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function createMessageMeta(correlationId?: string): MessageMeta {\n const id = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n return {\n id,\n correlationId,\n version: EMAIL_BUILDER_PROTOCOL_VERSION,\n sentAt: Date.now(),\n };\n}\n","import type { BuilderToHostMessage, HostToBuilderMessage, MessageMeta } from './protocol';\nimport { createMessageMeta, isMessageLike } from './protocol';\n\nexport function deriveAllowedOrigin(src: string, override?: string): string {\n if (override) {\n const parsed = new URL(override);\n if (parsed.origin === 'null') {\n throw new Error('allowedOrigin must resolve to a valid origin');\n }\n return parsed.origin;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(src);\n } catch {\n throw new Error('EmailBuilder `src` must be an absolute URL (e.g. https://example.com)');\n }\n if (!parsed.origin || parsed.origin === 'null') {\n throw new Error('EmailBuilder requires an absolute src URL with a valid origin');\n }\n return parsed.origin;\n}\n\nexport function buildEnvelope<T extends HostToBuilderMessage>(message: T, correlationId?: string): T {\n const meta: MessageMeta = createMessageMeta(correlationId);\n return { ...message, meta } as T;\n}\n\nexport function sanitizeIncomingMessage(\n event: MessageEvent,\n allowedOrigin: string,\n iframeWindow: Window | null\n): BuilderToHostMessage | null {\n if (event.origin !== allowedOrigin) {\n return null;\n }\n\n if (!iframeWindow || event.source !== iframeWindow) {\n return null;\n }\n\n if (!isMessageLike(event.data)) {\n return null;\n }\n\n return event.data as BuilderToHostMessage;\n}\n\nexport function stableSignature(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["index_exports","__export","EMAIL_BUILDER_PROTOCOL_VERSION","EmailBuilder","createMessageMeta","isMessageLike","__toCommonJS","import_react","EMAIL_BUILDER_PROTOCOL_VERSION","VALID_TYPES","isMessageLike","value","candidate","meta","createMessageMeta","correlationId","deriveAllowedOrigin","src","override","parsed","buildEnvelope","message","correlationId","meta","createMessageMeta","stableSignature","value","import_jsx_runtime","DEFAULT_SANDBOX","DEFAULT_INITIAL_HTML","overlayStyle","iframeStyle","EmailBuilderInner","src","initialHtml","config","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","allowedOrigin","ref","iframeRef","builderWindowRef","readyRef","statusRef","status","setStatus","reloadKey","setReloadKey","queueRef","runtimeOriginRef","effectiveInitialHtml","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","_a","setStatusSafely","next","postMessage","message","correlationId","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","iframeWindow","isMessageLike","nextPayload","signature","handleIframeLoad","key","EmailBuilder"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/EmailBuilder.tsx","../src/protocol.ts","../src/utils.ts"],"sourcesContent":["export * from './EmailBuilder';\nexport * from './types';\nexport * from './protocol';\n","import React, {\n CSSProperties,\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { BuilderToHostMessage, HostToBuilderMessage } from './protocol';\nimport { isMessageLike } from './protocol';\nimport { buildEnvelope, deriveAllowedOrigin, stableSignature } from './utils';\nimport type { EmailBuilderHandle, EmailBuilderProps, EmailBuilderStatus } from './types';\n\nconst DEFAULT_SANDBOX = 'allow-scripts allow-same-origin allow-forms';\nconst DEFAULT_INITIAL_HTML = '<h1>Hello World</h1><p>Start building your email template.</p>';\n\ntype PendingMessage = {\n message: HostToBuilderMessage;\n correlationId?: string;\n};\n\nconst overlayStyle: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '0.875rem',\n fontWeight: 500,\n background: 'linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))',\n color: '#fff',\n zIndex: 2,\n};\n\nconst iframeStyle: CSSProperties = {\n border: 'none',\n width: '100%',\n height: '100%',\n};\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n config,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onReady,\n onStatusChange,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const builderWindowRef = useRef<Window | null>(null);\n const readyRef = useRef(false);\n const statusRef = useRef<EmailBuilderStatus>('loading');\n const [status, setStatus] = useState<EmailBuilderStatus>('loading');\n const [reloadKey, setReloadKey] = useState(0);\n const queueRef = useRef<PendingMessage[]>([]);\n const runtimeOriginRef = useRef<string | null>(null);\n const handshakeTimerRef = useRef<number | null>(null);\n const effectiveInitialHtml = initialHtml ?? DEFAULT_INITIAL_HTML;\n const initSignatureRef = useRef(stableSignature({ html: effectiveInitialHtml, config }));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: { html: effectiveInitialHtml, config },\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(src, allowedOrigin), [src, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => runtimeOriginRef.current ?? expectedOrigin, [expectedOrigin]);\n\n const setStatusSafely = useCallback(\n (next: EmailBuilderStatus) => {\n if (statusRef.current === next) {\n return;\n }\n statusRef.current = next;\n setStatus(next);\n onStatusChange?.(next);\n },\n [onStatusChange]\n );\n\n const postMessage = useCallback(\n (message: HostToBuilderMessage, correlationId?: string) => {\n const target = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (target) {\n builderWindowRef.current = target;\n }\n\n if (!builderWindowRef.current || !readyRef.current) {\n queueRef.current.push({ message, correlationId });\n return;\n }\n\n builderWindowRef.current.postMessage(buildEnvelope(message, correlationId), resolveTargetOrigin());\n },\n [resolveTargetOrigin]\n );\n\n const flushQueue = useCallback(() => {\n if (!readyRef.current || !builderWindowRef.current) {\n return;\n }\n const pending = [...queueRef.current];\n queueRef.current = [];\n pending.forEach(({ message, correlationId }) => {\n builderWindowRef.current?.postMessage(\n buildEnvelope(message, correlationId),\n resolveTargetOrigin()\n );\n });\n }, [resolveTargetOrigin]);\n\n const handleReadyMessage = useCallback(() => {\n if (readyRef.current) {\n return;\n }\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n handshakeTimerRef.current = null;\n }\n readyRef.current = true;\n setStatusSafely('ready');\n onReady?.();\n postMessage(latestInitRef.current);\n flushQueue();\n }, [flushQueue, onReady, postMessage, setStatusSafely]);\n\n const handleUpload = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'UPLOAD') {\n return;\n }\n if (!onUpload) {\n console.warn('[EmailBuilderSDK] Upload requested but no onUpload handler is configured.');\n return;\n }\n try {\n setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, onChange, onSave]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [handleMessage]);\n\n useEffect(() => {\n const nextPayload = { html: effectiveInitialHtml, config };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage]);\n\n const handleIframeLoad = useCallback(() => {\n builderWindowRef.current = iframeRef.current?.contentWindow ?? null;\n readyRef.current = false;\n runtimeOriginRef.current = null;\n setStatusSafely('loading');\n\n // Kick off handshake immediately so we don't rely only on READY timing.\n // Some embeds can miss READY due to mount-order races.\n if (builderWindowRef.current) {\n try {\n builderWindowRef.current.postMessage(buildEnvelope(latestInitRef.current), expectedOrigin);\n } catch {\n // Ignore and wait for normal READY/message flow.\n }\n }\n\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n }\n handshakeTimerRef.current = window.setTimeout(() => {\n // Fallback: if iframe loaded but READY wasn't observed, mark connected.\n // Builder still drives real interactions via subsequent CHANGE/SAVE/UPLOAD.\n if (!readyRef.current) {\n handleReadyMessage();\n }\n }, 4000);\n }, [expectedOrigin, handleReadyMessage, setStatusSafely]);\n\n useImperativeHandle(\n ref,\n () => ({\n reload() {\n queueRef.current = [];\n readyRef.current = false;\n builderWindowRef.current = null;\n runtimeOriginRef.current = null;\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n handshakeTimerRef.current = null;\n }\n setStatusSafely('loading');\n setReloadKey((key) => key + 1);\n },\n }),\n [setStatusSafely]\n );\n\n useEffect(() => {\n return () => {\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n handshakeTimerRef.current = null;\n }\n };\n }, []);\n\n return (\n <div className={className} style={{ position: 'relative', width: '100%', height: '100%', ...style }}>\n <iframe\n key={reloadKey}\n ref={iframeRef}\n src={src}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && <div style={overlayStyle}>Connecting to builder…</div>}\n </div>\n );\n}\n\nexport const EmailBuilder = forwardRef(EmailBuilderInner);\n","export const EMAIL_BUILDER_PROTOCOL_VERSION = '1.0.0';\n\nexport type MessageType =\n | 'INIT'\n | 'READY'\n | 'CHANGE'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS';\n\nexport interface MessageMeta {\n id: string;\n correlationId?: string;\n version: string;\n sentAt: number;\n}\n\nexport type BuilderConfig = Record<string, unknown> | undefined;\n\nexport interface InitPayload {\n html: string;\n config?: BuilderConfig;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface SavePayload {\n html: string;\n}\n\nexport interface UploadPayload {\n file: File;\n}\n\nexport interface UploadSuccessPayload {\n url: string;\n}\n\nexport type Message =\n | { type: 'INIT'; payload: InitPayload; meta?: MessageMeta }\n | { type: 'READY'; meta?: MessageMeta }\n | { type: 'CHANGE'; payload: ChangePayload; meta?: MessageMeta }\n | { type: 'SAVE'; payload: SavePayload; meta?: MessageMeta }\n | { type: 'UPLOAD'; payload: UploadPayload; meta?: MessageMeta }\n | { type: 'UPLOAD_SUCCESS'; payload: UploadSuccessPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = ['INIT', 'READY', 'CHANGE', 'SAVE', 'UPLOAD', 'UPLOAD_SUCCESS'];\n\nexport function isMessageLike(value: unknown): value is Message {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as { type?: unknown; payload?: unknown; meta?: unknown };\n if (typeof candidate.type !== 'string' || !VALID_TYPES.includes(candidate.type as MessageType)) {\n return false;\n }\n\n if ('meta' in candidate && candidate.meta !== undefined) {\n const meta = candidate.meta as Partial<MessageMeta>;\n if (\n (meta.id && typeof meta.id !== 'string') ||\n (meta.correlationId && typeof meta.correlationId !== 'string') ||\n (meta.version && typeof meta.version !== 'string') ||\n (meta.sentAt && typeof meta.sentAt !== 'number')\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function createMessageMeta(correlationId?: string): MessageMeta {\n const id = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n return {\n id,\n correlationId,\n version: EMAIL_BUILDER_PROTOCOL_VERSION,\n sentAt: Date.now(),\n };\n}\n","import type { BuilderToHostMessage, HostToBuilderMessage, MessageMeta } from './protocol';\nimport { createMessageMeta, isMessageLike } from './protocol';\n\nexport function deriveAllowedOrigin(src: string, override?: string): string {\n if (override) {\n const parsed = new URL(override);\n if (parsed.origin === 'null') {\n throw new Error('allowedOrigin must resolve to a valid origin');\n }\n return parsed.origin;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(src);\n } catch {\n throw new Error('EmailBuilder `src` must be an absolute URL (e.g. https://example.com)');\n }\n if (!parsed.origin || parsed.origin === 'null') {\n throw new Error('EmailBuilder requires an absolute src URL with a valid origin');\n }\n return parsed.origin;\n}\n\nexport function buildEnvelope<T extends HostToBuilderMessage>(message: T, correlationId?: string): T {\n const meta: MessageMeta = createMessageMeta(correlationId);\n return { ...message, meta } as T;\n}\n\nexport function sanitizeIncomingMessage(\n event: MessageEvent,\n allowedOrigin: string,\n iframeWindow: Window | null\n): BuilderToHostMessage | null {\n if (event.origin !== allowedOrigin) {\n return null;\n }\n\n if (!iframeWindow || event.source !== iframeWindow) {\n return null;\n }\n\n if (!isMessageLike(event.data)) {\n return null;\n }\n\n return event.data as BuilderToHostMessage;\n}\n\nexport function stableSignature(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["index_exports","__export","EMAIL_BUILDER_PROTOCOL_VERSION","EmailBuilder","createMessageMeta","isMessageLike","__toCommonJS","import_react","EMAIL_BUILDER_PROTOCOL_VERSION","VALID_TYPES","isMessageLike","value","candidate","meta","createMessageMeta","correlationId","deriveAllowedOrigin","src","override","parsed","buildEnvelope","message","correlationId","meta","createMessageMeta","stableSignature","value","import_jsx_runtime","DEFAULT_SANDBOX","DEFAULT_INITIAL_HTML","overlayStyle","iframeStyle","EmailBuilderInner","src","initialHtml","config","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","allowedOrigin","ref","iframeRef","builderWindowRef","readyRef","statusRef","status","setStatus","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","effectiveInitialHtml","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","_a","setStatusSafely","next","postMessage","message","correlationId","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","iframeWindow","isMessageLike","nextPayload","signature","handleIframeLoad","key","EmailBuilder"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{forwardRef as $,useCallback as u,useEffect as W,useImperativeHandle as ee,useMemo as re,useRef as d,useState as F}from"react";var X="1.0.0",Z=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS"];function h(t){if(typeof t!="object"||t===null)return!1;let n=t;if(typeof n.type!="string"||!Z.includes(n.type))return!1;if("meta"in n&&n.meta!==void 0){let r=n.meta;if(r.id&&typeof r.id!="string"||r.correlationId&&typeof r.correlationId!="string"||r.version&&typeof r.version!="string"||r.sentAt&&typeof r.sentAt!="number")return!1}return!0}function N(t){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:t,version:X,sentAt:Date.now()}}function _(t,n){if(n){let y=new URL(n);if(y.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return y.origin}let r;try{r=new URL(t)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!r.origin||r.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return r.origin}function x(t,n){let r=N(n);return{...t,meta:r}}function b(t){return JSON.stringify(t!=null?t:null)}import{jsx as V,jsxs as ie}from"react/jsx-runtime";var te="allow-scripts allow-same-origin allow-forms",se="<h1>Hello World</h1><p>Start building your email template.</p>",ne={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",fontSize:"0.875rem",fontWeight:500,background:"linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))",color:"#fff",zIndex:2},oe={border:"none",width:"100%",height:"100%"};function ae({src:t,initialHtml:n,config:r,className:y,style:Y,iframeTitle:v="Email Builder",sandbox:G=te,onChange:m,onSave:M,onUpload:U,onReady:E,onStatusChange:w,allowedOrigin:D},z){let S=d(null),a=d(null),c=d(!1),B=d("loading"),[K,q]=F("loading"),[j,J]=F(0),A=d([]),p=d(null),I=n!=null?n:se,R=d(b({html:I,config:r})),L=d({type:"INIT",payload:{html:I,config:r}}),H=re(()=>_(t,D),[t,D]),T=u(()=>{var e;return(e=p.current)!=null?e:H},[H]),i=u(e=>{B.current!==e&&(B.current=e,q(e),w==null||w(e))},[w]),g=u((e,s)=>{var l,f;let o=(f=(l=S.current)==null?void 0:l.contentWindow)!=null?f:a.current;if(o&&(a.current=o),!a.current||!c.current){A.current.push({message:e,correlationId:s});return}a.current.postMessage(x(e,s),T())},[T]),O=u(()=>{if(!c.current||!a.current)return;let e=[...A.current];A.current=[],e.forEach(({message:s,correlationId:o})=>{var l;(l=a.current)==null||l.postMessage(x(s,o),T())})},[T]),k=u(()=>{c.current=!0,i("ready"),E==null||E(),g(L.current),O()},[O,E,g,i]),C=u(async e=>{var s;if(e.type==="UPLOAD"){if(!U){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{i("loading");let o=await U(e.payload.file);g({type:"UPLOAD_SUCCESS",payload:{url:o}},(s=e.meta)==null?void 0:s.id)}catch(o){i("error"),console.error("[EmailBuilderSDK] Upload handler failed",o)}finally{B.current!=="error"&&i("ready")}}},[U,g,i]),P=u(e=>{var l,f;let s=(f=(l=S.current)==null?void 0:l.contentWindow)!=null?f:a.current;if(!s||e.source!==s||!h(e.data))return;if(!p.current)p.current=e.origin;else if(e.origin!==p.current)return;let o=e.data;switch(e.source&&e.source!==a.current&&(a.current=e.source),o.type){case"READY":k();break;case"CHANGE":m==null||m(o.payload.html);break;case"SAVE":M==null||M(o.payload.html);break;case"UPLOAD":C(o);break;default:break}},[k,C,m,M]);W(()=>{if(typeof window!="undefined")return window.addEventListener("message",P),()=>{window.removeEventListener("message",P)}},[P]),W(()=>{let e={html:I,config:r},s=b(e);L.current={type:"INIT",payload:e},s!==R.current&&c.current&&g(L.current),R.current=s},[r,I,g]);let Q=u(()=>{var e,s;a.current=(s=(e=S.current)==null?void 0:e.contentWindow)!=null?s:null,c.current=!1,p.current=null,i("loading")},[i]);return ee(z,()=>({reload(){A.current=[],c.current=!1,a.current=null,p.current=null,i("loading"),J(e=>e+1)}}),[i]),ie("div",{className:y,style:{position:"relative",width:"100%",height:"100%",...Y},children:[V("iframe",{ref:S,src:t,title:v,sandbox:G,style:oe,loading:"lazy",allowFullScreen:!0,onLoad:Q},j),K!=="ready"&&V("div",{style:ne,children:"Connecting to builder\u2026"})]})}var Me=$(ae);export{X as EMAIL_BUILDER_PROTOCOL_VERSION,Me as EmailBuilder,N as createMessageMeta,h as isMessageLike};
1
+ import{forwardRef as ee,useCallback as p,useEffect as O,useImperativeHandle as re,useMemo as te,useRef as u,useState as V}from"react";var Z="1.0.0",$=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS"];function R(t){if(typeof t!="object"||t===null)return!1;let s=t;if(typeof s.type!="string"||!$.includes(s.type))return!1;if("meta"in s&&s.meta!==void 0){let r=s.meta;if(r.id&&typeof r.id!="string"||r.correlationId&&typeof r.correlationId!="string"||r.version&&typeof r.version!="string"||r.sentAt&&typeof r.sentAt!="number")return!1}return!0}function W(t){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:t,version:Z,sentAt:Date.now()}}function F(t,s){if(s){let y=new URL(s);if(y.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return y.origin}let r;try{r=new URL(t)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!r.origin||r.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return r.origin}function h(t,s){let r=W(s);return{...t,meta:r}}function H(t){return JSON.stringify(t!=null?t:null)}import{jsx as Y,jsxs as le}from"react/jsx-runtime";var ne="allow-scripts allow-same-origin allow-forms",se="<h1>Hello World</h1><p>Start building your email template.</p>",oe={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",fontSize:"0.875rem",fontWeight:500,background:"linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))",color:"#fff",zIndex:2},ae={border:"none",width:"100%",height:"100%"};function ie({src:t,initialHtml:s,config:r,className:y,style:v,iframeTitle:G="Email Builder",sandbox:z=ne,onChange:M,onSave:E,onUpload:b,onReady:w,onStatusChange:S,allowedOrigin:k},K){let T=u(null),o=u(null),c=u(!1),x=u("loading"),[q,j]=V("loading"),[J,Q]=V(0),A=u([]),f=u(null),i=u(null),I=s!=null?s:se,C=u(H({html:I,config:r})),U=u({type:"INIT",payload:{html:I,config:r}}),B=te(()=>F(t,k),[t,k]),L=p(()=>{var e;return(e=f.current)!=null?e:B},[B]),l=p(e=>{x.current!==e&&(x.current=e,j(e),S==null||S(e))},[S]),g=p((e,n)=>{var d,m;let a=(m=(d=T.current)==null?void 0:d.contentWindow)!=null?m:o.current;if(a&&(o.current=a),!o.current||!c.current){A.current.push({message:e,correlationId:n});return}o.current.postMessage(h(e,n),L())},[L]),N=p(()=>{if(!c.current||!o.current)return;let e=[...A.current];A.current=[],e.forEach(({message:n,correlationId:a})=>{var d;(d=o.current)==null||d.postMessage(h(n,a),L())})},[L]),P=p(()=>{c.current||(i.current&&(window.clearTimeout(i.current),i.current=null),c.current=!0,l("ready"),w==null||w(),g(U.current),N())},[N,w,g,l]),_=p(async e=>{var n;if(e.type==="UPLOAD"){if(!b){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{l("loading");let a=await b(e.payload.file);g({type:"UPLOAD_SUCCESS",payload:{url:a}},(n=e.meta)==null?void 0:n.id)}catch(a){l("error"),console.error("[EmailBuilderSDK] Upload handler failed",a)}finally{x.current!=="error"&&l("ready")}}},[b,g,l]),D=p(e=>{var d,m;let n=(m=(d=T.current)==null?void 0:d.contentWindow)!=null?m:o.current;if(!n||e.source!==n||!R(e.data))return;if(!f.current)f.current=e.origin;else if(e.origin!==f.current)return;let a=e.data;switch(e.source&&e.source!==o.current&&(o.current=e.source),a.type){case"READY":P();break;case"CHANGE":M==null||M(a.payload.html);break;case"SAVE":E==null||E(a.payload.html);break;case"UPLOAD":_(a);break;default:break}},[P,_,M,E]);O(()=>{if(typeof window!="undefined")return window.addEventListener("message",D),()=>{window.removeEventListener("message",D)}},[D]),O(()=>{let e={html:I,config:r},n=H(e);U.current={type:"INIT",payload:e},n!==C.current&&c.current&&g(U.current),C.current=n},[r,I,g]);let X=p(()=>{var e,n;if(o.current=(n=(e=T.current)==null?void 0:e.contentWindow)!=null?n:null,c.current=!1,f.current=null,l("loading"),o.current)try{o.current.postMessage(h(U.current),B)}catch{}i.current&&window.clearTimeout(i.current),i.current=window.setTimeout(()=>{c.current||P()},4e3)},[B,P,l]);return re(K,()=>({reload(){A.current=[],c.current=!1,o.current=null,f.current=null,i.current&&(window.clearTimeout(i.current),i.current=null),l("loading"),Q(e=>e+1)}}),[l]),O(()=>()=>{i.current&&(window.clearTimeout(i.current),i.current=null)},[]),le("div",{className:y,style:{position:"relative",width:"100%",height:"100%",...v},children:[Y("iframe",{ref:T,src:t,title:G,sandbox:z,style:ae,loading:"lazy",allowFullScreen:!0,onLoad:X},J),q!=="ready"&&Y("div",{style:oe,children:"Connecting to builder\u2026"})]})}var Ee=ee(ie);export{Z as EMAIL_BUILDER_PROTOCOL_VERSION,Ee as EmailBuilder,W as createMessageMeta,R as isMessageLike};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/EmailBuilder.tsx","../src/protocol.ts","../src/utils.ts"],"sourcesContent":["import React, {\n CSSProperties,\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { BuilderToHostMessage, HostToBuilderMessage } from './protocol';\nimport { isMessageLike } from './protocol';\nimport { buildEnvelope, deriveAllowedOrigin, stableSignature } from './utils';\nimport type { EmailBuilderHandle, EmailBuilderProps, EmailBuilderStatus } from './types';\n\nconst DEFAULT_SANDBOX = 'allow-scripts allow-same-origin allow-forms';\nconst DEFAULT_INITIAL_HTML = '<h1>Hello World</h1><p>Start building your email template.</p>';\n\ntype PendingMessage = {\n message: HostToBuilderMessage;\n correlationId?: string;\n};\n\nconst overlayStyle: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '0.875rem',\n fontWeight: 500,\n background: 'linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))',\n color: '#fff',\n zIndex: 2,\n};\n\nconst iframeStyle: CSSProperties = {\n border: 'none',\n width: '100%',\n height: '100%',\n};\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n config,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onReady,\n onStatusChange,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const builderWindowRef = useRef<Window | null>(null);\n const readyRef = useRef(false);\n const statusRef = useRef<EmailBuilderStatus>('loading');\n const [status, setStatus] = useState<EmailBuilderStatus>('loading');\n const [reloadKey, setReloadKey] = useState(0);\n const queueRef = useRef<PendingMessage[]>([]);\n const runtimeOriginRef = useRef<string | null>(null);\n const effectiveInitialHtml = initialHtml ?? DEFAULT_INITIAL_HTML;\n const initSignatureRef = useRef(stableSignature({ html: effectiveInitialHtml, config }));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: { html: effectiveInitialHtml, config },\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(src, allowedOrigin), [src, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => runtimeOriginRef.current ?? expectedOrigin, [expectedOrigin]);\n\n const setStatusSafely = useCallback(\n (next: EmailBuilderStatus) => {\n if (statusRef.current === next) {\n return;\n }\n statusRef.current = next;\n setStatus(next);\n onStatusChange?.(next);\n },\n [onStatusChange]\n );\n\n const postMessage = useCallback(\n (message: HostToBuilderMessage, correlationId?: string) => {\n const target = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (target) {\n builderWindowRef.current = target;\n }\n\n if (!builderWindowRef.current || !readyRef.current) {\n queueRef.current.push({ message, correlationId });\n return;\n }\n\n builderWindowRef.current.postMessage(buildEnvelope(message, correlationId), resolveTargetOrigin());\n },\n [resolveTargetOrigin]\n );\n\n const flushQueue = useCallback(() => {\n if (!readyRef.current || !builderWindowRef.current) {\n return;\n }\n const pending = [...queueRef.current];\n queueRef.current = [];\n pending.forEach(({ message, correlationId }) => {\n builderWindowRef.current?.postMessage(\n buildEnvelope(message, correlationId),\n resolveTargetOrigin()\n );\n });\n }, [resolveTargetOrigin]);\n\n const handleReadyMessage = useCallback(() => {\n readyRef.current = true;\n setStatusSafely('ready');\n onReady?.();\n postMessage(latestInitRef.current);\n flushQueue();\n }, [flushQueue, onReady, postMessage, setStatusSafely]);\n\n const handleUpload = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'UPLOAD') {\n return;\n }\n if (!onUpload) {\n console.warn('[EmailBuilderSDK] Upload requested but no onUpload handler is configured.');\n return;\n }\n try {\n setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, onChange, onSave]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [handleMessage]);\n\n useEffect(() => {\n const nextPayload = { html: effectiveInitialHtml, config };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage]);\n\n const handleIframeLoad = useCallback(() => {\n builderWindowRef.current = iframeRef.current?.contentWindow ?? null;\n readyRef.current = false;\n runtimeOriginRef.current = null;\n setStatusSafely('loading');\n }, [setStatusSafely]);\n\n useImperativeHandle(\n ref,\n () => ({\n reload() {\n queueRef.current = [];\n readyRef.current = false;\n builderWindowRef.current = null;\n runtimeOriginRef.current = null;\n setStatusSafely('loading');\n setReloadKey((key) => key + 1);\n },\n }),\n [setStatusSafely]\n );\n\n return (\n <div className={className} style={{ position: 'relative', width: '100%', height: '100%', ...style }}>\n <iframe\n key={reloadKey}\n ref={iframeRef}\n src={src}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && <div style={overlayStyle}>Connecting to builder…</div>}\n </div>\n );\n}\n\nexport const EmailBuilder = forwardRef(EmailBuilderInner);\n","export const EMAIL_BUILDER_PROTOCOL_VERSION = '1.0.0';\n\nexport type MessageType =\n | 'INIT'\n | 'READY'\n | 'CHANGE'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS';\n\nexport interface MessageMeta {\n id: string;\n correlationId?: string;\n version: string;\n sentAt: number;\n}\n\nexport type BuilderConfig = Record<string, unknown> | undefined;\n\nexport interface InitPayload {\n html: string;\n config?: BuilderConfig;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface SavePayload {\n html: string;\n}\n\nexport interface UploadPayload {\n file: File;\n}\n\nexport interface UploadSuccessPayload {\n url: string;\n}\n\nexport type Message =\n | { type: 'INIT'; payload: InitPayload; meta?: MessageMeta }\n | { type: 'READY'; meta?: MessageMeta }\n | { type: 'CHANGE'; payload: ChangePayload; meta?: MessageMeta }\n | { type: 'SAVE'; payload: SavePayload; meta?: MessageMeta }\n | { type: 'UPLOAD'; payload: UploadPayload; meta?: MessageMeta }\n | { type: 'UPLOAD_SUCCESS'; payload: UploadSuccessPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = ['INIT', 'READY', 'CHANGE', 'SAVE', 'UPLOAD', 'UPLOAD_SUCCESS'];\n\nexport function isMessageLike(value: unknown): value is Message {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as { type?: unknown; payload?: unknown; meta?: unknown };\n if (typeof candidate.type !== 'string' || !VALID_TYPES.includes(candidate.type as MessageType)) {\n return false;\n }\n\n if ('meta' in candidate && candidate.meta !== undefined) {\n const meta = candidate.meta as Partial<MessageMeta>;\n if (\n (meta.id && typeof meta.id !== 'string') ||\n (meta.correlationId && typeof meta.correlationId !== 'string') ||\n (meta.version && typeof meta.version !== 'string') ||\n (meta.sentAt && typeof meta.sentAt !== 'number')\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function createMessageMeta(correlationId?: string): MessageMeta {\n const id = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n return {\n id,\n correlationId,\n version: EMAIL_BUILDER_PROTOCOL_VERSION,\n sentAt: Date.now(),\n };\n}\n","import type { BuilderToHostMessage, HostToBuilderMessage, MessageMeta } from './protocol';\nimport { createMessageMeta, isMessageLike } from './protocol';\n\nexport function deriveAllowedOrigin(src: string, override?: string): string {\n if (override) {\n const parsed = new URL(override);\n if (parsed.origin === 'null') {\n throw new Error('allowedOrigin must resolve to a valid origin');\n }\n return parsed.origin;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(src);\n } catch {\n throw new Error('EmailBuilder `src` must be an absolute URL (e.g. https://example.com)');\n }\n if (!parsed.origin || parsed.origin === 'null') {\n throw new Error('EmailBuilder requires an absolute src URL with a valid origin');\n }\n return parsed.origin;\n}\n\nexport function buildEnvelope<T extends HostToBuilderMessage>(message: T, correlationId?: string): T {\n const meta: MessageMeta = createMessageMeta(correlationId);\n return { ...message, meta } as T;\n}\n\nexport function sanitizeIncomingMessage(\n event: MessageEvent,\n allowedOrigin: string,\n iframeWindow: Window | null\n): BuilderToHostMessage | null {\n if (event.origin !== allowedOrigin) {\n return null;\n }\n\n if (!iframeWindow || event.source !== iframeWindow) {\n return null;\n }\n\n if (!isMessageLike(event.data)) {\n return null;\n }\n\n return event.data as BuilderToHostMessage;\n}\n\nexport function stableSignature(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useMemo","useRef","useState","EMAIL_BUILDER_PROTOCOL_VERSION","VALID_TYPES","isMessageLike","value","candidate","meta","createMessageMeta","correlationId","deriveAllowedOrigin","src","override","parsed","buildEnvelope","message","correlationId","meta","createMessageMeta","stableSignature","value","jsx","jsxs","DEFAULT_SANDBOX","DEFAULT_INITIAL_HTML","overlayStyle","iframeStyle","EmailBuilderInner","src","initialHtml","config","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","allowedOrigin","ref","iframeRef","useRef","builderWindowRef","readyRef","statusRef","status","setStatus","useState","reloadKey","setReloadKey","queueRef","runtimeOriginRef","effectiveInitialHtml","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","useMemo","deriveAllowedOrigin","resolveTargetOrigin","useCallback","_a","setStatusSafely","next","postMessage","message","correlationId","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","iframeWindow","isMessageLike","useEffect","nextPayload","signature","handleIframeLoad","useImperativeHandle","key","EmailBuilder","forwardRef"]}
1
+ {"version":3,"sources":["../src/EmailBuilder.tsx","../src/protocol.ts","../src/utils.ts"],"sourcesContent":["import React, {\n CSSProperties,\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { BuilderToHostMessage, HostToBuilderMessage } from './protocol';\nimport { isMessageLike } from './protocol';\nimport { buildEnvelope, deriveAllowedOrigin, stableSignature } from './utils';\nimport type { EmailBuilderHandle, EmailBuilderProps, EmailBuilderStatus } from './types';\n\nconst DEFAULT_SANDBOX = 'allow-scripts allow-same-origin allow-forms';\nconst DEFAULT_INITIAL_HTML = '<h1>Hello World</h1><p>Start building your email template.</p>';\n\ntype PendingMessage = {\n message: HostToBuilderMessage;\n correlationId?: string;\n};\n\nconst overlayStyle: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '0.875rem',\n fontWeight: 500,\n background: 'linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))',\n color: '#fff',\n zIndex: 2,\n};\n\nconst iframeStyle: CSSProperties = {\n border: 'none',\n width: '100%',\n height: '100%',\n};\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n config,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onReady,\n onStatusChange,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const builderWindowRef = useRef<Window | null>(null);\n const readyRef = useRef(false);\n const statusRef = useRef<EmailBuilderStatus>('loading');\n const [status, setStatus] = useState<EmailBuilderStatus>('loading');\n const [reloadKey, setReloadKey] = useState(0);\n const queueRef = useRef<PendingMessage[]>([]);\n const runtimeOriginRef = useRef<string | null>(null);\n const handshakeTimerRef = useRef<number | null>(null);\n const effectiveInitialHtml = initialHtml ?? DEFAULT_INITIAL_HTML;\n const initSignatureRef = useRef(stableSignature({ html: effectiveInitialHtml, config }));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: { html: effectiveInitialHtml, config },\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(src, allowedOrigin), [src, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => runtimeOriginRef.current ?? expectedOrigin, [expectedOrigin]);\n\n const setStatusSafely = useCallback(\n (next: EmailBuilderStatus) => {\n if (statusRef.current === next) {\n return;\n }\n statusRef.current = next;\n setStatus(next);\n onStatusChange?.(next);\n },\n [onStatusChange]\n );\n\n const postMessage = useCallback(\n (message: HostToBuilderMessage, correlationId?: string) => {\n const target = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (target) {\n builderWindowRef.current = target;\n }\n\n if (!builderWindowRef.current || !readyRef.current) {\n queueRef.current.push({ message, correlationId });\n return;\n }\n\n builderWindowRef.current.postMessage(buildEnvelope(message, correlationId), resolveTargetOrigin());\n },\n [resolveTargetOrigin]\n );\n\n const flushQueue = useCallback(() => {\n if (!readyRef.current || !builderWindowRef.current) {\n return;\n }\n const pending = [...queueRef.current];\n queueRef.current = [];\n pending.forEach(({ message, correlationId }) => {\n builderWindowRef.current?.postMessage(\n buildEnvelope(message, correlationId),\n resolveTargetOrigin()\n );\n });\n }, [resolveTargetOrigin]);\n\n const handleReadyMessage = useCallback(() => {\n if (readyRef.current) {\n return;\n }\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n handshakeTimerRef.current = null;\n }\n readyRef.current = true;\n setStatusSafely('ready');\n onReady?.();\n postMessage(latestInitRef.current);\n flushQueue();\n }, [flushQueue, onReady, postMessage, setStatusSafely]);\n\n const handleUpload = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'UPLOAD') {\n return;\n }\n if (!onUpload) {\n console.warn('[EmailBuilderSDK] Upload requested but no onUpload handler is configured.');\n return;\n }\n try {\n setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, onChange, onSave]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [handleMessage]);\n\n useEffect(() => {\n const nextPayload = { html: effectiveInitialHtml, config };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage]);\n\n const handleIframeLoad = useCallback(() => {\n builderWindowRef.current = iframeRef.current?.contentWindow ?? null;\n readyRef.current = false;\n runtimeOriginRef.current = null;\n setStatusSafely('loading');\n\n // Kick off handshake immediately so we don't rely only on READY timing.\n // Some embeds can miss READY due to mount-order races.\n if (builderWindowRef.current) {\n try {\n builderWindowRef.current.postMessage(buildEnvelope(latestInitRef.current), expectedOrigin);\n } catch {\n // Ignore and wait for normal READY/message flow.\n }\n }\n\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n }\n handshakeTimerRef.current = window.setTimeout(() => {\n // Fallback: if iframe loaded but READY wasn't observed, mark connected.\n // Builder still drives real interactions via subsequent CHANGE/SAVE/UPLOAD.\n if (!readyRef.current) {\n handleReadyMessage();\n }\n }, 4000);\n }, [expectedOrigin, handleReadyMessage, setStatusSafely]);\n\n useImperativeHandle(\n ref,\n () => ({\n reload() {\n queueRef.current = [];\n readyRef.current = false;\n builderWindowRef.current = null;\n runtimeOriginRef.current = null;\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n handshakeTimerRef.current = null;\n }\n setStatusSafely('loading');\n setReloadKey((key) => key + 1);\n },\n }),\n [setStatusSafely]\n );\n\n useEffect(() => {\n return () => {\n if (handshakeTimerRef.current) {\n window.clearTimeout(handshakeTimerRef.current);\n handshakeTimerRef.current = null;\n }\n };\n }, []);\n\n return (\n <div className={className} style={{ position: 'relative', width: '100%', height: '100%', ...style }}>\n <iframe\n key={reloadKey}\n ref={iframeRef}\n src={src}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && <div style={overlayStyle}>Connecting to builder…</div>}\n </div>\n );\n}\n\nexport const EmailBuilder = forwardRef(EmailBuilderInner);\n","export const EMAIL_BUILDER_PROTOCOL_VERSION = '1.0.0';\n\nexport type MessageType =\n | 'INIT'\n | 'READY'\n | 'CHANGE'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS';\n\nexport interface MessageMeta {\n id: string;\n correlationId?: string;\n version: string;\n sentAt: number;\n}\n\nexport type BuilderConfig = Record<string, unknown> | undefined;\n\nexport interface InitPayload {\n html: string;\n config?: BuilderConfig;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface SavePayload {\n html: string;\n}\n\nexport interface UploadPayload {\n file: File;\n}\n\nexport interface UploadSuccessPayload {\n url: string;\n}\n\nexport type Message =\n | { type: 'INIT'; payload: InitPayload; meta?: MessageMeta }\n | { type: 'READY'; meta?: MessageMeta }\n | { type: 'CHANGE'; payload: ChangePayload; meta?: MessageMeta }\n | { type: 'SAVE'; payload: SavePayload; meta?: MessageMeta }\n | { type: 'UPLOAD'; payload: UploadPayload; meta?: MessageMeta }\n | { type: 'UPLOAD_SUCCESS'; payload: UploadSuccessPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = ['INIT', 'READY', 'CHANGE', 'SAVE', 'UPLOAD', 'UPLOAD_SUCCESS'];\n\nexport function isMessageLike(value: unknown): value is Message {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as { type?: unknown; payload?: unknown; meta?: unknown };\n if (typeof candidate.type !== 'string' || !VALID_TYPES.includes(candidate.type as MessageType)) {\n return false;\n }\n\n if ('meta' in candidate && candidate.meta !== undefined) {\n const meta = candidate.meta as Partial<MessageMeta>;\n if (\n (meta.id && typeof meta.id !== 'string') ||\n (meta.correlationId && typeof meta.correlationId !== 'string') ||\n (meta.version && typeof meta.version !== 'string') ||\n (meta.sentAt && typeof meta.sentAt !== 'number')\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function createMessageMeta(correlationId?: string): MessageMeta {\n const id = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n return {\n id,\n correlationId,\n version: EMAIL_BUILDER_PROTOCOL_VERSION,\n sentAt: Date.now(),\n };\n}\n","import type { BuilderToHostMessage, HostToBuilderMessage, MessageMeta } from './protocol';\nimport { createMessageMeta, isMessageLike } from './protocol';\n\nexport function deriveAllowedOrigin(src: string, override?: string): string {\n if (override) {\n const parsed = new URL(override);\n if (parsed.origin === 'null') {\n throw new Error('allowedOrigin must resolve to a valid origin');\n }\n return parsed.origin;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(src);\n } catch {\n throw new Error('EmailBuilder `src` must be an absolute URL (e.g. https://example.com)');\n }\n if (!parsed.origin || parsed.origin === 'null') {\n throw new Error('EmailBuilder requires an absolute src URL with a valid origin');\n }\n return parsed.origin;\n}\n\nexport function buildEnvelope<T extends HostToBuilderMessage>(message: T, correlationId?: string): T {\n const meta: MessageMeta = createMessageMeta(correlationId);\n return { ...message, meta } as T;\n}\n\nexport function sanitizeIncomingMessage(\n event: MessageEvent,\n allowedOrigin: string,\n iframeWindow: Window | null\n): BuilderToHostMessage | null {\n if (event.origin !== allowedOrigin) {\n return null;\n }\n\n if (!iframeWindow || event.source !== iframeWindow) {\n return null;\n }\n\n if (!isMessageLike(event.data)) {\n return null;\n }\n\n return event.data as BuilderToHostMessage;\n}\n\nexport function stableSignature(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useMemo","useRef","useState","EMAIL_BUILDER_PROTOCOL_VERSION","VALID_TYPES","isMessageLike","value","candidate","meta","createMessageMeta","correlationId","deriveAllowedOrigin","src","override","parsed","buildEnvelope","message","correlationId","meta","createMessageMeta","stableSignature","value","jsx","jsxs","DEFAULT_SANDBOX","DEFAULT_INITIAL_HTML","overlayStyle","iframeStyle","EmailBuilderInner","src","initialHtml","config","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","allowedOrigin","ref","iframeRef","useRef","builderWindowRef","readyRef","statusRef","status","setStatus","useState","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","effectiveInitialHtml","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","useMemo","deriveAllowedOrigin","resolveTargetOrigin","useCallback","_a","setStatusSafely","next","postMessage","message","correlationId","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","iframeWindow","isMessageLike","useEffect","nextPayload","signature","handleIframeLoad","useImperativeHandle","key","EmailBuilder","forwardRef"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alihaiderrana/email-builder-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "React iframe SDK for embedding the Circles email template builder",
5
5
  "license": "MIT",
6
6
  "type": "module",