@alihaiderrana/email-builder-sdk 0.1.12 → 0.1.14

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 W=Object.defineProperty;var Se=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var Ee=Object.prototype.hasOwnProperty;var ge=(r,a)=>{for(var n in a)W(r,n,{get:a[n],enumerable:!0})},me=(r,a,n,p)=>{if(a&&typeof a=="object"||typeof a=="function")for(let S of ye(a))!Ee.call(r,S)&&S!==n&&W(r,S,{get:()=>a[S],enumerable:!(p=Se(a,S))||p.enumerable});return r};var Te=r=>me(W({},"__esModule",{value:!0}),r);var Re={};ge(Re,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>te,EmailBuilder:()=>De,createMessageMeta:()=>V,isMessageLike:()=>b});module.exports=Te(Re);var t=require("react");var te="1.0.0",we=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS","LIST_ASSETS","ASSETS_LIST","DELETE_ASSET","DELETE_ASSET_SUCCESS","AUTH_ERROR"];function b(r){if(typeof r!="object"||r===null)return!1;let a=r;if(typeof a.type!="string"||!we.includes(a.type))return!1;if("meta"in a&&a.meta!==void 0){let n=a.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 V(r){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:r,version:te,sentAt:Date.now()}}function re(r,a){if(a){let p=new URL(a);if(p.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return p.origin}let n;try{n=new URL(r)}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 A(r,a){let n=V(a);return{...r,meta:n}}function K(r){return JSON.stringify(r!=null?r:null)}var M=require("react/jsx-runtime"),Ae="allow-scripts allow-same-origin allow-forms",Me="<h1>Hello World</h1><p>Start building your email template.</p>",Le="https://pc-email-template-builder.netlify.app",Ie={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},_e={border:"none",width:"100%",height:"100%"};function Ue(r,a){if(!a||!a.trim())return r;try{let n=new URL(r,typeof window!="undefined"?window.location.href:"https://example.com");return n.searchParams.set("embedToken",a),n.toString()}catch{let n=r.includes("?")?"&":"?";return`${r}${n}embedToken=${encodeURIComponent(a)}`}}function Pe({src:r,initialHtml:a,embedToken:n,templateId:p,config:S,showFooter:C,includeUnsubscribe:x,externalFooterHtml:m,footerInjectionMode:Y,className:ae,style:ne,iframeTitle:se="Email Builder",sandbox:ie=Ae,onChange:L,onSave:I,onUpload:O,onListAssets:H,onDeleteAsset:k,onReady:_,onStatusChange:U,onAuthError:E,allowedOrigin:G},oe){let P=(r==null?void 0:r.trim())||Le,le=(0,t.useMemo)(()=>Ue(P,n),[P,n]),D=(0,t.useRef)(null),d=(0,t.useRef)(null),y=(0,t.useRef)(!1),R=(0,t.useRef)("loading"),[ue,j]=(0,t.useState)("loading"),[ce,de]=(0,t.useState)(0),B=(0,t.useRef)([]),T=(0,t.useRef)(null),f=(0,t.useRef)(null),i=(0,t.useRef)(null),N=typeof a=="string"?a:p?"":Me,z=Y||(m&&m.trim()?"sdk":"default"),q={html:N,config:S,...p?{templateId:p}:{},showFooter:C,includeUnsubscribe:x,...m?{externalFooterHtml:m}:{},footerInjectionMode:z},F=(0,t.useRef)(K(q)),w=(0,t.useRef)({type:"INIT",payload:q}),Be=(0,t.useMemo)(()=>re(P,G),[P,G]),h=(0,t.useCallback)(()=>"*",[]),g=(0,t.useCallback)(e=>{R.current!==e&&(R.current=e,j(e),U==null||U(e))},[U]),c=(0,t.useCallback)((e,o)=>{var l,u;let s=(u=(l=D.current)==null?void 0:l.contentWindow)!=null?u:d.current;if(s&&(d.current=s),!d.current||!y.current){B.current.push({message:e,correlationId:o});return}d.current.postMessage(A(e,o),h())},[h]),$=(0,t.useCallback)(()=>{if(!y.current||!d.current)return;let e=[...B.current];B.current=[],e.forEach(({message:o,correlationId:s})=>{var l;(l=d.current)==null||l.postMessage(A(o,s),h())})},[h]),J=(0,t.useCallback)(()=>{y.current||(f.current&&(window.clearTimeout(f.current),f.current=null),i.current&&(window.clearInterval(i.current),i.current=null),y.current=!0,g("ready"),_==null||_(),c(w.current),$())},[$,_,c,g]),Q=(0,t.useCallback)(async e=>{var o,s;if(e.type==="UPLOAD"){if(!O){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{let l=await O(e.payload.file);c({type:"UPLOAD_SUCCESS",payload:{url:l}},(o=e.meta)==null?void 0:o.id)}catch(l){console.error("[EmailBuilderSDK] Upload handler failed",l),c({type:"UPLOAD_SUCCESS",payload:{url:""}},(s=e.meta)==null?void 0:s.id)}}},[O,c]),X=(0,t.useCallback)(async e=>{var o,s,l;if(e.type==="LIST_ASSETS"){if(!H){c({type:"ASSETS_LIST",payload:{assets:[]}},(o=e.meta)==null?void 0:o.id);return}try{let u=await H(e.payload);c({type:"ASSETS_LIST",payload:{assets:Array.isArray(u)?u:[]}},(s=e.meta)==null?void 0:s.id)}catch(u){console.error("[EmailBuilderSDK] list assets handler failed",u),c({type:"ASSETS_LIST",payload:{assets:[]}},(l=e.meta)==null?void 0:l.id)}}},[H,c]),Z=(0,t.useCallback)(async e=>{var o,s,l;if(e.type==="DELETE_ASSET"){if(!k){c({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(o=e.meta)==null?void 0:o.id);return}try{let u=await k(e.payload||{});c({type:"DELETE_ASSET_SUCCESS",payload:{success:!!u}},(s=e.meta)==null?void 0:s.id)}catch(u){console.error("[EmailBuilderSDK] delete asset handler failed",u),c({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(l=e.meta)==null?void 0:l.id)}}},[k,c]),v=(0,t.useCallback)(e=>{var l,u,ee;let o=(u=(l=D.current)==null?void 0:l.contentWindow)!=null?u:d.current;if(!o||e.source!==o||!b(e.data))return;if(!T.current)T.current=e.origin;else if(e.origin!==T.current)return;let s=e.data;switch(e.source&&e.source!==d.current&&(d.current=e.source),s.type){case"READY":J();break;case"CHANGE":L==null||L(s.payload.html);break;case"SAVE":I==null||I(s.payload.html);break;case"UPLOAD":Q(s);break;case"LIST_ASSETS":X(s);break;case"DELETE_ASSET":Z(s);break;case"AUTH_ERROR":{let fe=((ee=s.payload)==null?void 0:ee.message)||"Email builder authentication failed";R.current!=="error"&&(R.current="error",j("error"),E==null||E(fe));break}default:break}},[J,Q,X,Z,L,I,E,g]);(0,t.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",v),()=>{window.removeEventListener("message",v)}},[v]),(0,t.useEffect)(()=>{let e={html:N,config:S,...p?{templateId:p}:{},showFooter:C,includeUnsubscribe:x,...m!==void 0?{externalFooterHtml:m}:{},footerInjectionMode:z},o=K(e);w.current={type:"INIT",payload:e},o!==F.current&&y.current&&c(w.current),F.current=o},[S,N,c,p,C,x,m,Y]);let pe=(0,t.useCallback)(()=>{var s,l;if(d.current=(l=(s=D.current)==null?void 0:s.contentWindow)!=null?l:null,y.current=!1,T.current=null,g("loading"),d.current)try{d.current.postMessage(A(w.current),"*")}catch{}f.current&&window.clearTimeout(f.current),i.current&&window.clearInterval(i.current);let e=0,o=12;i.current=window.setInterval(()=>{var u;if(y.current){i.current&&(window.clearInterval(i.current),i.current=null);return}e+=1;try{(u=d.current)==null||u.postMessage(A(w.current),"*")}catch{}e>=o&&i.current&&(window.clearInterval(i.current),i.current=null)},1e3),f.current=window.setTimeout(()=>{y.current||(i.current&&(window.clearInterval(i.current),i.current=null),g("error"),E==null||E("Builder handshake failed or authentication was rejected."))},12e3)},[E,g]);return(0,t.useImperativeHandle)(oe,()=>({reload(){B.current=[],y.current=!1,d.current=null,T.current=null,f.current&&(window.clearTimeout(f.current),f.current=null),i.current&&(window.clearInterval(i.current),i.current=null),g("loading"),de(e=>e+1)}}),[g]),(0,t.useEffect)(()=>()=>{f.current&&(window.clearTimeout(f.current),f.current=null),i.current&&(window.clearInterval(i.current),i.current=null)},[]),(0,M.jsxs)("div",{className:ae,style:{position:"relative",width:"100%",height:"100%",...ne},children:[(0,M.jsx)("iframe",{ref:D,src:le,title:se,sandbox:ie,style:_e,loading:"lazy",allowFullScreen:!0,onLoad:pe},ce),ue!=="ready"&&(0,M.jsx)("div",{style:Ie,children:"Connecting to builder\u2026"})]})}var De=(0,t.forwardRef)(Pe);0&&(module.exports={EMAIL_BUILDER_PROTOCOL_VERSION,EmailBuilder,createMessageMeta,isMessageLike});
1
+ "use strict";var Y=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var Ae=Object.prototype.hasOwnProperty;var Me=(r,n)=>{for(var a in n)Y(r,a,{get:n[a],enumerable:!0})},Le=(r,n,a,p)=>{if(n&&typeof n=="object"||typeof n=="function")for(let S of we(n))!Ae.call(r,S)&&S!==a&&Y(r,S,{get:()=>n[S],enumerable:!(p=Te(n,S))||p.enumerable});return r};var Ie=r=>Le(Y({},"__esModule",{value:!0}),r);var xe={};Me(xe,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>ne,EmailBuilder:()=>Ce,createMessageMeta:()=>G,isMessageLike:()=>C});module.exports=Ie(xe);var t=require("react");var ne="1.0.0",De=["INIT","READY","CHANGE","LOADED","SAVE","UPLOAD","UPLOAD_SUCCESS","LIST_ASSETS","ASSETS_LIST","DELETE_ASSET","DELETE_ASSET_SUCCESS","AUTH_ERROR"];function C(r){if(typeof r!="object"||r===null)return!1;let n=r;if(typeof n.type!="string"||!De.includes(n.type))return!1;if("meta"in n&&n.meta!==void 0){let a=n.meta;if(a.id&&typeof a.id!="string"||a.correlationId&&typeof a.correlationId!="string"||a.version&&typeof a.version!="string"||a.sentAt&&typeof a.sentAt!="number")return!1}return!0}function G(r){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:r,version:ne,sentAt:Date.now()}}function se(r,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 a;try{a=new URL(r)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!a.origin||a.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return a.origin}function A(r,n){let a=G(n);return{...r,meta:a}}function $(r){return JSON.stringify(r!=null?r:null)}var M=require("react/jsx-runtime"),Pe="allow-scripts allow-same-origin allow-forms",Ue="<h1>Hello World</h1><p>Start building your email template.</p>",_e="https://pc-email-template-builder.netlify.app",Re={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},he={border:"none",width:"100%",height:"100%"};function Be(r,n){if(!n)return r;try{let a=new URL(r,typeof window!="undefined"?window.location.href:"https://example.com");return a.searchParams.set("preview","true"),a.searchParams.set("previewOnly","true"),a.toString()}catch{let a=r.includes("?")?"&":"?";return`${r}${a}preview=true&previewOnly=true`}}function be(r,n){if(!n||!n.trim())return r;try{let a=new URL(r,typeof window!="undefined"?window.location.href:"https://example.com");return a.searchParams.set("embedToken",n),a.toString()}catch{let a=r.includes("?")?"&":"?";return`${r}${a}embedToken=${encodeURIComponent(n)}`}}function Oe({src:r,initialHtml:n,embedToken:a,templateId:p,config:S,showFooter:x,includeUnsubscribe:H,externalFooterHtml:m,footerInjectionMode:j,preview:ie=!1,previewOnly:oe=!1,className:le,style:ue,iframeTitle:ce="Email Builder",sandbox:de=Pe,onChange:L,onLoad:I,onSave:D,onUpload:k,onListAssets:v,onDeleteAsset:N,onReady:P,onStatusChange:U,onAuthError:E,allowedOrigin:z},pe){let _=(r==null?void 0:r.trim())||_e,R=ie||oe,W=(0,t.useMemo)(()=>R?{...S!=null?S:{},preview:!0,previewOnly:!0}:S,[S,R]),fe=(0,t.useMemo)(()=>be(Be(_,R),a),[_,a,R]),h=(0,t.useRef)(null),d=(0,t.useRef)(null),y=(0,t.useRef)(!1),B=(0,t.useRef)("loading"),[Se,q]=(0,t.useState)("loading"),[ye,Ee]=(0,t.useState)(0),b=(0,t.useRef)([]),T=(0,t.useRef)(null),f=(0,t.useRef)(null),i=(0,t.useRef)(null),V=typeof n=="string"?n:p?"":Ue,F=j||(m&&m.trim()?"sdk":"default"),J={html:V,config:W,...p?{templateId:p}:{},showFooter:x,includeUnsubscribe:H,...m?{externalFooterHtml:m}:{},footerInjectionMode:F},Q=(0,t.useRef)($(J)),w=(0,t.useRef)({type:"INIT",payload:J}),He=(0,t.useMemo)(()=>se(_,z),[_,z]),O=(0,t.useCallback)(()=>"*",[]),g=(0,t.useCallback)(e=>{B.current!==e&&(B.current=e,q(e),U==null||U(e))},[U]),c=(0,t.useCallback)((e,o)=>{var l,u;let s=(u=(l=h.current)==null?void 0:l.contentWindow)!=null?u:d.current;if(s&&(d.current=s),!d.current||!y.current){b.current.push({message:e,correlationId:o});return}d.current.postMessage(A(e,o),O())},[O]),X=(0,t.useCallback)(()=>{if(!y.current||!d.current)return;let e=[...b.current];b.current=[],e.forEach(({message:o,correlationId:s})=>{var l;(l=d.current)==null||l.postMessage(A(o,s),O())})},[O]),Z=(0,t.useCallback)(()=>{y.current||(f.current&&(window.clearTimeout(f.current),f.current=null),i.current&&(window.clearInterval(i.current),i.current=null),y.current=!0,g("ready"),P==null||P(),c(w.current),X())},[X,P,c,g]),ee=(0,t.useCallback)(async e=>{var o,s;if(e.type==="UPLOAD"){if(!k){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{let l=await k(e.payload.file);c({type:"UPLOAD_SUCCESS",payload:{url:l}},(o=e.meta)==null?void 0:o.id)}catch(l){console.error("[EmailBuilderSDK] Upload handler failed",l),c({type:"UPLOAD_SUCCESS",payload:{url:""}},(s=e.meta)==null?void 0:s.id)}}},[k,c]),te=(0,t.useCallback)(async e=>{var o,s,l;if(e.type==="LIST_ASSETS"){if(!v){c({type:"ASSETS_LIST",payload:{assets:[]}},(o=e.meta)==null?void 0:o.id);return}try{let u=await v(e.payload);c({type:"ASSETS_LIST",payload:{assets:Array.isArray(u)?u:[]}},(s=e.meta)==null?void 0:s.id)}catch(u){console.error("[EmailBuilderSDK] list assets handler failed",u),c({type:"ASSETS_LIST",payload:{assets:[]}},(l=e.meta)==null?void 0:l.id)}}},[v,c]),re=(0,t.useCallback)(async e=>{var o,s,l;if(e.type==="DELETE_ASSET"){if(!N){c({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(o=e.meta)==null?void 0:o.id);return}try{let u=await N(e.payload||{});c({type:"DELETE_ASSET_SUCCESS",payload:{success:!!u}},(s=e.meta)==null?void 0:s.id)}catch(u){console.error("[EmailBuilderSDK] delete asset handler failed",u),c({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(l=e.meta)==null?void 0:l.id)}}},[N,c]),K=(0,t.useCallback)(e=>{var l,u,ae;let o=(u=(l=h.current)==null?void 0:l.contentWindow)!=null?u:d.current;if(!o||e.source!==o||!C(e.data))return;if(!T.current)T.current=e.origin;else if(e.origin!==T.current)return;let s=e.data;switch(e.source&&e.source!==d.current&&(d.current=e.source),s.type){case"READY":Z();break;case"CHANGE":L==null||L(s.payload.html);break;case"LOADED":I==null||I(s.payload.html);break;case"SAVE":D==null||D(s.payload.html);break;case"UPLOAD":ee(s);break;case"LIST_ASSETS":te(s);break;case"DELETE_ASSET":re(s);break;case"AUTH_ERROR":{let me=((ae=s.payload)==null?void 0:ae.message)||"Email builder authentication failed";B.current!=="error"&&(B.current="error",q("error"),E==null||E(me));break}default:break}},[Z,ee,te,re,L,I,D,E,g]);(0,t.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",K),()=>{window.removeEventListener("message",K)}},[K]),(0,t.useEffect)(()=>{let e={html:V,config:W,...p?{templateId:p}:{},showFooter:x,includeUnsubscribe:H,...m!==void 0?{externalFooterHtml:m}:{},footerInjectionMode:F},o=$(e);w.current={type:"INIT",payload:e},o!==Q.current&&y.current&&c(w.current),Q.current=o},[W,V,c,p,x,H,m,j]);let ge=(0,t.useCallback)(()=>{var s,l;if(d.current=(l=(s=h.current)==null?void 0:s.contentWindow)!=null?l:null,y.current=!1,T.current=null,g("loading"),d.current)try{d.current.postMessage(A(w.current),"*")}catch{}f.current&&window.clearTimeout(f.current),i.current&&window.clearInterval(i.current);let e=0,o=12;i.current=window.setInterval(()=>{var u;if(y.current){i.current&&(window.clearInterval(i.current),i.current=null);return}e+=1;try{(u=d.current)==null||u.postMessage(A(w.current),"*")}catch{}e>=o&&i.current&&(window.clearInterval(i.current),i.current=null)},1e3),f.current=window.setTimeout(()=>{y.current||(i.current&&(window.clearInterval(i.current),i.current=null),g("error"),E==null||E("Builder handshake failed or authentication was rejected."))},12e3)},[E,g]);return(0,t.useImperativeHandle)(pe,()=>({reload(){b.current=[],y.current=!1,d.current=null,T.current=null,f.current&&(window.clearTimeout(f.current),f.current=null),i.current&&(window.clearInterval(i.current),i.current=null),g("loading"),Ee(e=>e+1)}}),[g]),(0,t.useEffect)(()=>()=>{f.current&&(window.clearTimeout(f.current),f.current=null),i.current&&(window.clearInterval(i.current),i.current=null)},[]),(0,M.jsxs)("div",{className:le,style:{position:"relative",width:"100%",height:"100%",...ue},children:[(0,M.jsx)("iframe",{ref:h,src:fe,title:ce,sandbox:de,style:he,loading:"lazy",allowFullScreen:!0,onLoad:ge},ye),Se!=="ready"&&(0,M.jsx)("div",{style:Re,children:"Connecting to builder\u2026"})]})}var Ce=(0,t.forwardRef)(Oe);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, InitPayload } 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>';\nconst DEFAULT_BUILDER_SRC = 'https://pc-email-template-builder.netlify.app';\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 appendEmbedTokenToSrc(src: string, embedToken: string | undefined): string {\n if (!embedToken || !embedToken.trim()) {\n return src;\n }\n try {\n const u = new URL(src, typeof window !== 'undefined' ? window.location.href : 'https://example.com');\n u.searchParams.set('embedToken', embedToken);\n return u.toString();\n } catch {\n const sep = src.includes('?') ? '&' : '?';\n return `${src}${sep}embedToken=${encodeURIComponent(embedToken)}`;\n }\n}\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n embedToken,\n templateId,\n config,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onListAssets,\n onDeleteAsset,\n onReady,\n onStatusChange,\n onAuthError,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const resolvedSrc = src?.trim() || DEFAULT_BUILDER_SRC;\n const iframeSrc = useMemo(() => appendEmbedTokenToSrc(resolvedSrc, embedToken), [resolvedSrc, embedToken]);\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 handshakeRetryIntervalRef = useRef<number | null>(null);\n\n const effectiveInitialHtml =\n typeof initialHtml === 'string'\n ? initialHtml\n : templateId\n ? ''\n : DEFAULT_INITIAL_HTML;\n\n const effectiveFooterMode =\n footerInjectionMode ||\n (externalFooterHtml && externalFooterHtml.trim() ? 'sdk' : 'default');\n\n const initPayload: InitPayload = {\n html: effectiveInitialHtml,\n config,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\n\n const initSignatureRef = useRef(stableSignature(initPayload));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: initPayload,\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(resolvedSrc, allowedOrigin), [resolvedSrc, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => '*', []);\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n // Keep builder session ready; upload failure should not flip global iframe status.\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url: '' } }, eventMessage.meta?.id);\n }\n },\n [onUpload, postMessage]\n );\n\n const handleListAssets = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'LIST_ASSETS') {\n return;\n }\n if (!onListAssets) {\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n return;\n }\n try {\n const assets = await onListAssets(eventMessage.payload);\n postMessage(\n { type: 'ASSETS_LIST', payload: { assets: Array.isArray(assets) ? assets : [] } },\n eventMessage.meta?.id\n );\n } catch (error) {\n console.error('[EmailBuilderSDK] list assets handler failed', error);\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n }\n },\n [onListAssets, postMessage]\n );\n\n const handleDeleteAsset = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'DELETE_ASSET') {\n return;\n }\n if (!onDeleteAsset) {\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n return;\n }\n try {\n const success = await onDeleteAsset(eventMessage.payload || {});\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: !!success } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] delete asset handler failed', error);\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n }\n },\n [onDeleteAsset, postMessage]\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 case 'LIST_ASSETS':\n void handleListAssets(message);\n break;\n case 'DELETE_ASSET':\n void handleDeleteAsset(message);\n break;\n case 'AUTH_ERROR': {\n const msg = message.payload?.message || 'Email builder authentication failed';\n if (statusRef.current !== 'error') {\n statusRef.current = 'error';\n setStatus('error');\n onAuthError?.(msg);\n }\n break;\n }\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, handleListAssets, handleDeleteAsset, onChange, onSave, onAuthError, setStatusSafely]\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: InitPayload = {\n html: effectiveInitialHtml,\n config,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml !== undefined ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\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 }, [\n config,\n effectiveInitialHtml,\n postMessage,\n templateId,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n ]);\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 if (builderWindowRef.current) {\n try {\n builderWindowRef.current.postMessage(buildEnvelope(latestInitRef.current), '*');\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n }\n\n let attempts = 0;\n const maxAttempts = 12;\n handshakeRetryIntervalRef.current = window.setInterval(() => {\n if (readyRef.current) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n return;\n }\n attempts += 1;\n try {\n builderWindowRef.current?.postMessage(buildEnvelope(latestInitRef.current), '*');\n } catch {\n // Keep retrying until timeout.\n }\n if (attempts >= maxAttempts) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n }\n }, 1000);\n\n handshakeTimerRef.current = window.setTimeout(() => {\n if (readyRef.current) {\n return;\n }\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n setStatusSafely('error');\n onAuthError?.('Builder handshake failed or authentication was rejected.');\n }, 12000);\n }, [onAuthError, 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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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={iframeSrc}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && (\n <div style={overlayStyle}>Connecting to builder…</div>\n )}\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 | 'LIST_ASSETS'\n | 'ASSETS_LIST'\n | 'DELETE_ASSET'\n | 'DELETE_ASSET_SUCCESS'\n | 'AUTH_ERROR';\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 /** Inline HTML to import (optional if templateId is set and builder fetches server-side). */\n html?: string;\n /** When set, embedded builder fetches HTML from API using embed token + this id. */\n templateId?: string;\n config?: BuilderConfig;\n /**\n * Optional: host-provided footer HTML to be rendered by the builder (SDK mode).\n * If set, the builder can avoid importing its own footer and render this exact footer instead.\n */\n externalFooterHtml?: string;\n /**\n * Footer source selection.\n * - `default`: builder uses its existing behavior.\n * - `sdk`: builder uses `externalFooterHtml` (and should avoid importing/auto-generating footer).\n */\n footerInjectionMode?: 'default' | 'sdk';\n /** Show \"Powered by Public Circles\" branding in footer. Controlled by host based on add-on purchase. */\n showFooter?: boolean;\n /** Include unsubscribe link in footer. Controlled by host toggle. */\n includeUnsubscribe?: boolean;\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 interface AssetItem {\n url: string;\n id?: string;\n name?: string;\n thumbnailUrl?: string;\n}\n\nexport interface ListAssetsPayload {\n limit?: number;\n}\n\nexport interface AssetsListPayload {\n assets: AssetItem[];\n}\n\nexport interface DeleteAssetPayload {\n id?: string;\n url?: string;\n}\n\nexport interface DeleteAssetSuccessPayload {\n success: boolean;\n}\n\nexport interface AuthErrorPayload {\n message: 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 | { type: 'LIST_ASSETS'; payload?: ListAssetsPayload; meta?: MessageMeta }\n | { type: 'ASSETS_LIST'; payload: AssetsListPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET'; payload: DeleteAssetPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET_SUCCESS'; payload: DeleteAssetSuccessPayload; meta?: MessageMeta }\n | { type: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' | 'ASSETS_LIST' | 'DELETE_ASSET_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_SUCCESS',\n 'LIST_ASSETS',\n 'ASSETS_LIST',\n 'DELETE_ASSET',\n 'DELETE_ASSET_SUCCESS',\n 'AUTH_ERROR',\n];\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":"mbAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,oCAAAE,GAAA,iBAAAC,GAAA,sBAAAC,EAAA,kBAAAC,IAAA,eAAAC,GAAAN,ICAA,IAAAO,EAUO,iBCVA,IAAMC,GAAiC,QAkHxCC,GAA6B,CACjC,OACA,QACA,SACA,OACA,SACA,iBACA,cACA,cACA,eACA,uBACA,YACF,EAEO,SAASC,EAAcC,EAAkC,CAC9D,GAAI,OAAOA,GAAU,UAAYA,IAAU,KACzC,MAAO,GAGT,IAAMC,EAAYD,EAClB,GAAI,OAAOC,EAAU,MAAS,UAAY,CAACH,GAAY,SAASG,EAAU,IAAmB,EAC3F,MAAO,GAGT,GAAI,SAAUA,GAAaA,EAAU,OAAS,OAAW,CACvD,IAAMC,EAAOD,EAAU,KACvB,GACGC,EAAK,IAAM,OAAOA,EAAK,IAAO,UAC9BA,EAAK,eAAiB,OAAOA,EAAK,eAAkB,UACpDA,EAAK,SAAW,OAAOA,EAAK,SAAY,UACxCA,EAAK,QAAU,OAAOA,EAAK,QAAW,SAEvC,MAAO,EAEX,CAEA,MAAO,EACT,CAEO,SAASC,EAAkBC,EAAqC,CAIrE,MAAO,CACL,GAJS,OAAO,QAAW,aAAe,eAAgB,OACxD,OAAO,WAAW,EAClB,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,EAGpC,cAAAA,EACA,QAASP,GACT,OAAQ,KAAK,IAAI,CACnB,CACF,CChKO,SAASQ,GAAoBC,EAAaC,EAA2B,CAC1E,GAAIA,EAAU,CACZ,IAAMC,EAAS,IAAI,IAAID,CAAQ,EAC/B,GAAIC,EAAO,SAAW,OACpB,MAAM,IAAI,MAAM,8CAA8C,EAEhE,OAAOA,EAAO,MAChB,CAEA,IAAIA,EACJ,GAAI,CACFA,EAAS,IAAI,IAAIF,CAAG,CACtB,MAAQ,CACN,MAAM,IAAI,MAAM,uEAAuE,CACzF,CACA,GAAI,CAACE,EAAO,QAAUA,EAAO,SAAW,OACtC,MAAM,IAAI,MAAM,+DAA+D,EAEjF,OAAOA,EAAO,MAChB,CAEO,SAASC,EAA8CC,EAAYC,EAA2B,CACnG,IAAMC,EAAoBC,EAAkBF,CAAa,EACzD,MAAO,CAAE,GAAGD,EAAS,KAAAE,CAAK,CAC5B,CAsBO,SAASE,EAAgBC,EAAwB,CACtD,OAAO,KAAK,UAAUA,GAAA,KAAAA,EAAS,IAAI,CACrC,CFwYI,IAAAC,EAAA,6BA3aEC,GAAkB,8CAClBC,GAAuB,iEACvBC,GAAsB,gDAOtBC,GAA8B,CAClC,SAAU,WACV,MAAO,EACP,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,SAAU,WACV,WAAY,IACZ,WAAY,iEACZ,MAAO,OACP,OAAQ,CACV,EAEMC,GAA6B,CACjC,OAAQ,OACR,MAAO,OACP,OAAQ,MACV,EAEA,SAASC,GAAsBC,EAAaC,EAAwC,CAClF,GAAI,CAACA,GAAc,CAACA,EAAW,KAAK,EAClC,OAAOD,EAET,GAAI,CACF,IAAME,EAAI,IAAI,IAAIF,EAAK,OAAO,QAAW,YAAc,OAAO,SAAS,KAAO,qBAAqB,EACnG,OAAAE,EAAE,aAAa,IAAI,aAAcD,CAAU,EACpCC,EAAE,SAAS,CACpB,MAAQ,CACN,IAAMC,EAAMH,EAAI,SAAS,GAAG,EAAI,IAAM,IACtC,MAAO,GAAGA,CAAG,GAAGG,CAAG,cAAc,mBAAmBF,CAAU,CAAC,EACjE,CACF,CAEA,SAASG,GACP,CACE,IAAAJ,EACA,YAAAK,EACA,WAAAJ,EACA,WAAAK,EACA,OAAAC,EACA,WAAAC,EACA,mBAAAC,EACA,mBAAAC,EACA,oBAAAC,EACA,UAAAC,GACA,MAAAC,GACA,YAAAC,GAAc,gBACd,QAAAC,GAAUrB,GACV,SAAAsB,EACA,OAAAC,EACA,SAAAC,EACA,aAAAC,EACA,cAAAC,EACA,QAAAC,EACA,eAAAC,EACA,YAAAC,EACA,cAAAC,CACF,EACAC,GACA,CACA,IAAMC,GAAc1B,GAAA,YAAAA,EAAK,SAAUJ,GAC7B+B,MAAY,WAAQ,IAAM5B,GAAsB2B,EAAazB,CAAU,EAAG,CAACyB,EAAazB,CAAU,CAAC,EAEnG2B,KAAY,UAA0B,IAAI,EAC1CC,KAAmB,UAAsB,IAAI,EAC7CC,KAAW,UAAO,EAAK,EACvBC,KAAY,UAA2B,SAAS,EAChD,CAACC,GAAQC,CAAS,KAAI,YAA6B,SAAS,EAC5D,CAACC,GAAWC,EAAY,KAAI,YAAS,CAAC,EACtCC,KAAW,UAAyB,CAAC,CAAC,EACtCC,KAAmB,UAAsB,IAAI,EAC7CC,KAAoB,UAAsB,IAAI,EAC9CC,KAA4B,UAAsB,IAAI,EAEtDC,EACJ,OAAOnC,GAAgB,SACnBA,EACAC,EACE,GACAX,GAEF8C,EACJ9B,IACCD,GAAsBA,EAAmB,KAAK,EAAI,MAAQ,WAEvDgC,EAA2B,CAC/B,KAAMF,EACN,OAAAjC,EACA,GAAID,EAAa,CAAE,WAAAA,CAAW,EAAI,CAAC,EACnC,WAAAE,EACA,mBAAAC,EACA,GAAIC,EAAqB,CAAE,mBAAAA,CAAmB,EAAI,CAAC,EACnD,oBAAqB+B,CACvB,EAEME,KAAmB,UAAOC,EAAgBF,CAAW,CAAC,EACtDG,KAAgB,UAA6B,CACjD,KAAM,OACN,QAASH,CACX,CAAC,EAEKI,MAAiB,WAAQ,IAAMC,GAAoBrB,EAAaF,CAAa,EAAG,CAACE,EAAaF,CAAa,CAAC,EAE5GwB,KAAsB,eAAY,IAAM,IAAK,CAAC,CAAC,EAE/CC,KAAkB,eACrBC,GAA6B,CACxBnB,EAAU,UAAYmB,IAG1BnB,EAAU,QAAUmB,EACpBjB,EAAUiB,CAAI,EACd5B,GAAA,MAAAA,EAAiB4B,GACnB,EACA,CAAC5B,CAAc,CACjB,EAEM6B,KAAc,eAClB,CAACC,EAA+BC,IAA2B,CA/I/D,IAAAC,EAAAC,EAgJM,IAAMC,GAASD,GAAAD,EAAA1B,EAAU,UAAV,YAAA0B,EAAmB,gBAAnB,KAAAC,EAAoC1B,EAAiB,QAKpE,GAJI2B,IACF3B,EAAiB,QAAU2B,GAGzB,CAAC3B,EAAiB,SAAW,CAACC,EAAS,QAAS,CAClDM,EAAS,QAAQ,KAAK,CAAE,QAAAgB,EAAS,cAAAC,CAAc,CAAC,EAChD,MACF,CAEAxB,EAAiB,QAAQ,YAAY4B,EAAcL,EAASC,CAAa,EAAGL,EAAoB,CAAC,CACnG,EACA,CAACA,CAAmB,CACtB,EAEMU,KAAa,eAAY,IAAM,CACnC,GAAI,CAAC5B,EAAS,SAAW,CAACD,EAAiB,QACzC,OAEF,IAAM8B,EAAU,CAAC,GAAGvB,EAAS,OAAO,EACpCA,EAAS,QAAU,CAAC,EACpBuB,EAAQ,QAAQ,CAAC,CAAE,QAAAP,EAAS,cAAAC,CAAc,IAAM,CArKpD,IAAAC,GAsKMA,EAAAzB,EAAiB,UAAjB,MAAAyB,EAA0B,YACxBG,EAAcL,EAASC,CAAa,EACpCL,EAAoB,EAExB,CAAC,CACH,EAAG,CAACA,CAAmB,CAAC,EAElBY,KAAqB,eAAY,IAAM,CACvC9B,EAAS,UAGTQ,EAAkB,UACpB,OAAO,aAAaA,EAAkB,OAAO,EAC7CA,EAAkB,QAAU,MAE1BC,EAA0B,UAC5B,OAAO,cAAcA,EAA0B,OAAO,EACtDA,EAA0B,QAAU,MAEtCT,EAAS,QAAU,GACnBmB,EAAgB,OAAO,EACvB5B,GAAA,MAAAA,IACA8B,EAAYN,EAAc,OAAO,EACjCa,EAAW,EACb,EAAG,CAACA,EAAYrC,EAAS8B,EAAaF,CAAe,CAAC,EAEhDY,KAAe,eACnB,MAAOC,GAAuC,CAjMlD,IAAAR,EAAAC,EAkMM,GAAIO,EAAa,OAAS,SAG1B,IAAI,CAAC5C,EAAU,CACb,QAAQ,KAAK,2EAA2E,EACxF,MACF,CACA,GAAI,CACF,IAAM6C,EAAM,MAAM7C,EAAS4C,EAAa,QAAQ,IAAI,EACpDX,EAAY,CAAE,KAAM,iBAAkB,QAAS,CAAE,IAAAY,CAAI,CAAE,GAAGT,EAAAQ,EAAa,OAAb,YAAAR,EAAmB,EAAE,CACjF,OAASU,EAAO,CACd,QAAQ,MAAM,0CAA2CA,CAAK,EAE9Db,EAAY,CAAE,KAAM,iBAAkB,QAAS,CAAE,IAAK,EAAG,CAAE,GAAGI,EAAAO,EAAa,OAAb,YAAAP,EAAmB,EAAE,CACrF,EACF,EACA,CAACrC,EAAUiC,CAAW,CACxB,EAEMc,KAAmB,eACvB,MAAOH,GAAuC,CAtNlD,IAAAR,EAAAC,EAAAW,EAuNM,GAAIJ,EAAa,OAAS,cAG1B,IAAI,CAAC3C,EAAc,CACjBgC,EAAY,CAAE,KAAM,cAAe,QAAS,CAAE,OAAQ,CAAC,CAAE,CAAE,GAAGG,EAAAQ,EAAa,OAAb,YAAAR,EAAmB,EAAE,EACnF,MACF,CACA,GAAI,CACF,IAAMa,EAAS,MAAMhD,EAAa2C,EAAa,OAAO,EACtDX,EACE,CAAE,KAAM,cAAe,QAAS,CAAE,OAAQ,MAAM,QAAQgB,CAAM,EAAIA,EAAS,CAAC,CAAE,CAAE,GAChFZ,EAAAO,EAAa,OAAb,YAAAP,EAAmB,EACrB,CACF,OAASS,EAAO,CACd,QAAQ,MAAM,+CAAgDA,CAAK,EACnEb,EAAY,CAAE,KAAM,cAAe,QAAS,CAAE,OAAQ,CAAC,CAAE,CAAE,GAAGe,EAAAJ,EAAa,OAAb,YAAAI,EAAmB,EAAE,CACrF,EACF,EACA,CAAC/C,EAAcgC,CAAW,CAC5B,EAEMiB,KAAoB,eACxB,MAAON,GAAuC,CA7OlD,IAAAR,EAAAC,EAAAW,EA8OM,GAAIJ,EAAa,OAAS,eAG1B,IAAI,CAAC1C,EAAe,CAClB+B,EAAY,CAAE,KAAM,uBAAwB,QAAS,CAAE,QAAS,EAAM,CAAE,GAAGG,EAAAQ,EAAa,OAAb,YAAAR,EAAmB,EAAE,EAChG,MACF,CACA,GAAI,CACF,IAAMe,EAAU,MAAMjD,EAAc0C,EAAa,SAAW,CAAC,CAAC,EAC9DX,EAAY,CAAE,KAAM,uBAAwB,QAAS,CAAE,QAAS,CAAC,CAACkB,CAAQ,CAAE,GAAGd,EAAAO,EAAa,OAAb,YAAAP,EAAmB,EAAE,CACtG,OAASS,EAAO,CACd,QAAQ,MAAM,gDAAiDA,CAAK,EACpEb,EAAY,CAAE,KAAM,uBAAwB,QAAS,CAAE,QAAS,EAAM,CAAE,GAAGe,EAAAJ,EAAa,OAAb,YAAAI,EAAmB,EAAE,CAClG,EACF,EACA,CAAC9C,EAAe+B,CAAW,CAC7B,EAEMmB,KAAgB,eACnBC,GAAwB,CAjQ7B,IAAAjB,EAAAC,EAAAW,GAkQM,IAAMM,GAAejB,GAAAD,EAAA1B,EAAU,UAAV,YAAA0B,EAAmB,gBAAnB,KAAAC,EAAoC1B,EAAiB,QAI1E,GAHI,CAAC2C,GAAgBD,EAAM,SAAWC,GAGlC,CAACC,EAAcF,EAAM,IAAI,EAC3B,OAEF,GAAI,CAAClC,EAAiB,QACpBA,EAAiB,QAAUkC,EAAM,eACxBA,EAAM,SAAWlC,EAAiB,QAC3C,OAEF,IAAMe,EAAUmB,EAAM,KAMtB,OAJIA,EAAM,QAAUA,EAAM,SAAW1C,EAAiB,UACpDA,EAAiB,QAAU0C,EAAM,QAG3BnB,EAAQ,KAAM,CACpB,IAAK,QACHQ,EAAmB,EACnB,MACF,IAAK,SACH5C,GAAA,MAAAA,EAAWoC,EAAQ,QAAQ,MAC3B,MACF,IAAK,OACHnC,GAAA,MAAAA,EAASmC,EAAQ,QAAQ,MACzB,MACF,IAAK,SACES,EAAaT,CAAO,EACzB,MACF,IAAK,cACEa,EAAiBb,CAAO,EAC7B,MACF,IAAK,eACEgB,EAAkBhB,CAAO,EAC9B,MACF,IAAK,aAAc,CACjB,IAAMsB,KAAMR,GAAAd,EAAQ,UAAR,YAAAc,GAAiB,UAAW,sCACpCnC,EAAU,UAAY,UACxBA,EAAU,QAAU,QACpBE,EAAU,OAAO,EACjBV,GAAA,MAAAA,EAAcmD,KAEhB,KACF,CACA,QACE,KACJ,CACF,EACA,CAACd,EAAoBC,EAAcI,EAAkBG,EAAmBpD,EAAUC,EAAQM,EAAa0B,CAAe,CACxH,KAEA,aAAU,IAAM,CACd,GAAI,OAAO,QAAW,YAGtB,cAAO,iBAAiB,UAAWqB,CAAa,EACzC,IAAM,CACX,OAAO,oBAAoB,UAAWA,CAAa,CACrD,CACF,EAAG,CAACA,CAAa,CAAC,KAElB,aAAU,IAAM,CACd,IAAMK,EAA2B,CAC/B,KAAMnC,EACN,OAAAjC,EACA,GAAID,EAAa,CAAE,WAAAA,CAAW,EAAI,CAAC,EACnC,WAAAE,EACA,mBAAAC,EACA,GAAIC,IAAuB,OAAY,CAAE,mBAAAA,CAAmB,EAAI,CAAC,EACjE,oBAAqB+B,CACvB,EACMmC,EAAYhC,EAAgB+B,CAAW,EAC7C9B,EAAc,QAAU,CAAE,KAAM,OAAQ,QAAS8B,CAAY,EACzDC,IAAcjC,EAAiB,SAAWb,EAAS,SACrDqB,EAAYN,EAAc,OAAO,EAEnCF,EAAiB,QAAUiC,CAC7B,EAAG,CACDrE,EACAiC,EACAW,EACA7C,EACAE,EACAC,EACAC,EACAC,CACF,CAAC,EAED,IAAMkE,MAAmB,eAAY,IAAM,CA5V7C,IAAAvB,EAAAC,EAkWI,GALA1B,EAAiB,SAAU0B,GAAAD,EAAA1B,EAAU,UAAV,YAAA0B,EAAmB,gBAAnB,KAAAC,EAAoC,KAC/DzB,EAAS,QAAU,GACnBO,EAAiB,QAAU,KAC3BY,EAAgB,SAAS,EAErBpB,EAAiB,QACnB,GAAI,CACFA,EAAiB,QAAQ,YAAY4B,EAAcZ,EAAc,OAAO,EAAG,GAAG,CAChF,MAAQ,CAER,CAGEP,EAAkB,SACpB,OAAO,aAAaA,EAAkB,OAAO,EAE3CC,EAA0B,SAC5B,OAAO,cAAcA,EAA0B,OAAO,EAGxD,IAAIuC,EAAW,EACTC,EAAc,GACpBxC,EAA0B,QAAU,OAAO,YAAY,IAAM,CAnXjE,IAAAe,EAoXM,GAAIxB,EAAS,QAAS,CAChBS,EAA0B,UAC5B,OAAO,cAAcA,EAA0B,OAAO,EACtDA,EAA0B,QAAU,MAEtC,MACF,CACAuC,GAAY,EACZ,GAAI,EACFxB,EAAAzB,EAAiB,UAAjB,MAAAyB,EAA0B,YAAYG,EAAcZ,EAAc,OAAO,EAAG,IAC9E,MAAQ,CAER,CACIiC,GAAYC,GACVxC,EAA0B,UAC5B,OAAO,cAAcA,EAA0B,OAAO,EACtDA,EAA0B,QAAU,KAG1C,EAAG,GAAI,EAEPD,EAAkB,QAAU,OAAO,WAAW,IAAM,CAC9CR,EAAS,UAGTS,EAA0B,UAC5B,OAAO,cAAcA,EAA0B,OAAO,EACtDA,EAA0B,QAAU,MAEtCU,EAAgB,OAAO,EACvB1B,GAAA,MAAAA,EAAc,4DAChB,EAAG,IAAK,CACV,EAAG,CAACA,EAAa0B,CAAe,CAAC,EAEjC,gCACExB,GACA,KAAO,CACL,QAAS,CACPW,EAAS,QAAU,CAAC,EACpBN,EAAS,QAAU,GACnBD,EAAiB,QAAU,KAC3BQ,EAAiB,QAAU,KACvBC,EAAkB,UACpB,OAAO,aAAaA,EAAkB,OAAO,EAC7CA,EAAkB,QAAU,MAE1BC,EAA0B,UAC5B,OAAO,cAAcA,EAA0B,OAAO,EACtDA,EAA0B,QAAU,MAEtCU,EAAgB,SAAS,EACzBd,GAAc6C,GAAQA,EAAM,CAAC,CAC/B,CACF,GACA,CAAC/B,CAAe,CAClB,KAEA,aAAU,IACD,IAAM,CACPX,EAAkB,UACpB,OAAO,aAAaA,EAAkB,OAAO,EAC7CA,EAAkB,QAAU,MAE1BC,EAA0B,UAC5B,OAAO,cAAcA,EAA0B,OAAO,EACtDA,EAA0B,QAAU,KAExC,EACC,CAAC,CAAC,KAGH,QAAC,OAAI,UAAW3B,GAAW,MAAO,CAAE,SAAU,WAAY,MAAO,OAAQ,OAAQ,OAAQ,GAAGC,EAAM,EAChG,oBAAC,UAEC,IAAKe,EACL,IAAKD,GACL,MAAOb,GACP,QAASC,GACT,MAAOjB,GACP,QAAQ,OACR,gBAAe,GACf,OAAQ+E,IARH3C,EASP,EACCF,KAAW,YACV,OAAC,OAAI,MAAOnC,GAAc,uCAAsB,GAEpD,CAEJ,CAEO,IAAMoF,MAAe,cAAW7E,EAAiB","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","DEFAULT_BUILDER_SRC","overlayStyle","iframeStyle","appendEmbedTokenToSrc","src","embedToken","u","sep","EmailBuilderInner","initialHtml","templateId","config","showFooter","includeUnsubscribe","externalFooterHtml","footerInjectionMode","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onListAssets","onDeleteAsset","onReady","onStatusChange","onAuthError","allowedOrigin","ref","resolvedSrc","iframeSrc","iframeRef","builderWindowRef","readyRef","statusRef","status","setStatus","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","handshakeRetryIntervalRef","effectiveInitialHtml","effectiveFooterMode","initPayload","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleListAssets","_c","assets","handleDeleteAsset","success","handleMessage","event","iframeWindow","isMessageLike","msg","nextPayload","signature","handleIframeLoad","attempts","maxAttempts","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, InitPayload } 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>';\nconst DEFAULT_BUILDER_SRC = 'https://pc-email-template-builder.netlify.app';\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 appendPreviewParamsToSrc(src: string, preview: boolean): string {\n if (!preview) {\n return src;\n }\n try {\n const u = new URL(src, typeof window !== 'undefined' ? window.location.href : 'https://example.com');\n u.searchParams.set('preview', 'true');\n u.searchParams.set('previewOnly', 'true');\n return u.toString();\n } catch {\n const sep = src.includes('?') ? '&' : '?';\n return `${src}${sep}preview=true&previewOnly=true`;\n }\n}\n\nfunction appendEmbedTokenToSrc(src: string, embedToken: string | undefined): string {\n if (!embedToken || !embedToken.trim()) {\n return src;\n }\n try {\n const u = new URL(src, typeof window !== 'undefined' ? window.location.href : 'https://example.com');\n u.searchParams.set('embedToken', embedToken);\n return u.toString();\n } catch {\n const sep = src.includes('?') ? '&' : '?';\n return `${src}${sep}embedToken=${encodeURIComponent(embedToken)}`;\n }\n}\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n embedToken,\n templateId,\n config,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n preview = false,\n previewOnly = false,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onLoad,\n onSave,\n onUpload,\n onListAssets,\n onDeleteAsset,\n onReady,\n onStatusChange,\n onAuthError,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const resolvedSrc = src?.trim() || DEFAULT_BUILDER_SRC;\n const isPreviewMode = preview || previewOnly;\n const effectiveConfig = useMemo(\n () => (isPreviewMode ? { ...(config ?? {}), preview: true, previewOnly: true } : config),\n [config, isPreviewMode]\n );\n const iframeSrc = useMemo(\n () => appendEmbedTokenToSrc(appendPreviewParamsToSrc(resolvedSrc, isPreviewMode), embedToken),\n [resolvedSrc, embedToken, isPreviewMode]\n );\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 handshakeRetryIntervalRef = useRef<number | null>(null);\n\n const effectiveInitialHtml =\n typeof initialHtml === 'string'\n ? initialHtml\n : templateId\n ? ''\n : DEFAULT_INITIAL_HTML;\n\n const effectiveFooterMode =\n footerInjectionMode ||\n (externalFooterHtml && externalFooterHtml.trim() ? 'sdk' : 'default');\n\n const initPayload: InitPayload = {\n html: effectiveInitialHtml,\n config: effectiveConfig,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\n\n const initSignatureRef = useRef(stableSignature(initPayload));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: initPayload,\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(resolvedSrc, allowedOrigin), [resolvedSrc, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => '*', []);\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n // Keep builder session ready; upload failure should not flip global iframe status.\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url: '' } }, eventMessage.meta?.id);\n }\n },\n [onUpload, postMessage]\n );\n\n const handleListAssets = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'LIST_ASSETS') {\n return;\n }\n if (!onListAssets) {\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n return;\n }\n try {\n const assets = await onListAssets(eventMessage.payload);\n postMessage(\n { type: 'ASSETS_LIST', payload: { assets: Array.isArray(assets) ? assets : [] } },\n eventMessage.meta?.id\n );\n } catch (error) {\n console.error('[EmailBuilderSDK] list assets handler failed', error);\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n }\n },\n [onListAssets, postMessage]\n );\n\n const handleDeleteAsset = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'DELETE_ASSET') {\n return;\n }\n if (!onDeleteAsset) {\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n return;\n }\n try {\n const success = await onDeleteAsset(eventMessage.payload || {});\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: !!success } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] delete asset handler failed', error);\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n }\n },\n [onDeleteAsset, postMessage]\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 'LOADED':\n onLoad?.(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 case 'LIST_ASSETS':\n void handleListAssets(message);\n break;\n case 'DELETE_ASSET':\n void handleDeleteAsset(message);\n break;\n case 'AUTH_ERROR': {\n const msg = message.payload?.message || 'Email builder authentication failed';\n if (statusRef.current !== 'error') {\n statusRef.current = 'error';\n setStatus('error');\n onAuthError?.(msg);\n }\n break;\n }\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, handleListAssets, handleDeleteAsset, onChange, onLoad, onSave, onAuthError, setStatusSafely]\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: InitPayload = {\n html: effectiveInitialHtml,\n config: effectiveConfig,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml !== undefined ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\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 }, [\n effectiveConfig,\n effectiveInitialHtml,\n postMessage,\n templateId,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n ]);\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 if (builderWindowRef.current) {\n try {\n builderWindowRef.current.postMessage(buildEnvelope(latestInitRef.current), '*');\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n }\n\n let attempts = 0;\n const maxAttempts = 12;\n handshakeRetryIntervalRef.current = window.setInterval(() => {\n if (readyRef.current) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n return;\n }\n attempts += 1;\n try {\n builderWindowRef.current?.postMessage(buildEnvelope(latestInitRef.current), '*');\n } catch {\n // Keep retrying until timeout.\n }\n if (attempts >= maxAttempts) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n }\n }, 1000);\n\n handshakeTimerRef.current = window.setTimeout(() => {\n if (readyRef.current) {\n return;\n }\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n setStatusSafely('error');\n onAuthError?.('Builder handshake failed or authentication was rejected.');\n }, 12000);\n }, [onAuthError, 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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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={iframeSrc}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && (\n <div style={overlayStyle}>Connecting to builder…</div>\n )}\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 | 'LOADED'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS'\n | 'LIST_ASSETS'\n | 'ASSETS_LIST'\n | 'DELETE_ASSET'\n | 'DELETE_ASSET_SUCCESS'\n | 'AUTH_ERROR';\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 /** Inline HTML to import (optional if templateId is set and builder fetches server-side). */\n html?: string;\n /** When set, embedded builder fetches HTML from API using embed token + this id. */\n templateId?: string;\n config?: BuilderConfig;\n /**\n * Optional: host-provided footer HTML to be rendered by the builder (SDK mode).\n * If set, the builder can avoid importing its own footer and render this exact footer instead.\n */\n externalFooterHtml?: string;\n /**\n * Footer source selection.\n * - `default`: builder uses its existing behavior.\n * - `sdk`: builder uses `externalFooterHtml` (and should avoid importing/auto-generating footer).\n */\n footerInjectionMode?: 'default' | 'sdk';\n /** Show \"Powered by Public Circles\" branding in footer. Controlled by host based on add-on purchase. */\n showFooter?: boolean;\n /** Include unsubscribe link in footer. Controlled by host toggle. */\n includeUnsubscribe?: boolean;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface LoadedPayload {\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 interface AssetItem {\n url: string;\n id?: string;\n name?: string;\n thumbnailUrl?: string;\n}\n\nexport interface ListAssetsPayload {\n limit?: number;\n}\n\nexport interface AssetsListPayload {\n assets: AssetItem[];\n}\n\nexport interface DeleteAssetPayload {\n id?: string;\n url?: string;\n}\n\nexport interface DeleteAssetSuccessPayload {\n success: boolean;\n}\n\nexport interface AuthErrorPayload {\n message: 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: 'LOADED'; payload: LoadedPayload; 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 | { type: 'LIST_ASSETS'; payload?: ListAssetsPayload; meta?: MessageMeta }\n | { type: 'ASSETS_LIST'; payload: AssetsListPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET'; payload: DeleteAssetPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET_SUCCESS'; payload: DeleteAssetSuccessPayload; meta?: MessageMeta }\n | { type: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'LOADED' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' | 'ASSETS_LIST' | 'DELETE_ASSET_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'LOADED',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_SUCCESS',\n 'LIST_ASSETS',\n 'ASSETS_LIST',\n 'DELETE_ASSET',\n 'DELETE_ASSET_SUCCESS',\n 'AUTH_ERROR',\n];\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","DEFAULT_BUILDER_SRC","overlayStyle","iframeStyle","appendPreviewParamsToSrc","src","preview","u","sep","appendEmbedTokenToSrc","embedToken","EmailBuilderInner","initialHtml","templateId","config","showFooter","includeUnsubscribe","externalFooterHtml","footerInjectionMode","previewOnly","className","style","iframeTitle","sandbox","onChange","onLoad","onSave","onUpload","onListAssets","onDeleteAsset","onReady","onStatusChange","onAuthError","allowedOrigin","ref","resolvedSrc","isPreviewMode","effectiveConfig","iframeSrc","iframeRef","builderWindowRef","readyRef","statusRef","status","setStatus","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","handshakeRetryIntervalRef","effectiveInitialHtml","effectiveFooterMode","initPayload","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleListAssets","_c","assets","handleDeleteAsset","success","handleMessage","event","iframeWindow","isMessageLike","msg","nextPayload","signature","handleIframeLoad","attempts","maxAttempts","key","EmailBuilder"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import React, { CSSProperties } from 'react';
2
2
 
3
3
  declare const EMAIL_BUILDER_PROTOCOL_VERSION = "1.0.0";
4
- type MessageType = 'INIT' | 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'UPLOAD_SUCCESS' | 'LIST_ASSETS' | 'ASSETS_LIST' | 'DELETE_ASSET' | 'DELETE_ASSET_SUCCESS' | 'AUTH_ERROR';
4
+ type MessageType = 'INIT' | 'READY' | 'CHANGE' | 'LOADED' | 'SAVE' | 'UPLOAD' | 'UPLOAD_SUCCESS' | 'LIST_ASSETS' | 'ASSETS_LIST' | 'DELETE_ASSET' | 'DELETE_ASSET_SUCCESS' | 'AUTH_ERROR';
5
5
  interface MessageMeta {
6
6
  id: string;
7
7
  correlationId?: string;
@@ -34,6 +34,9 @@ interface InitPayload {
34
34
  interface ChangePayload {
35
35
  html: string;
36
36
  }
37
+ interface LoadedPayload {
38
+ html: string;
39
+ }
37
40
  interface SavePayload {
38
41
  html: string;
39
42
  }
@@ -76,6 +79,10 @@ type Message = {
76
79
  type: 'CHANGE';
77
80
  payload: ChangePayload;
78
81
  meta?: MessageMeta;
82
+ } | {
83
+ type: 'LOADED';
84
+ payload: LoadedPayload;
85
+ meta?: MessageMeta;
79
86
  } | {
80
87
  type: 'SAVE';
81
88
  payload: SavePayload;
@@ -110,7 +117,7 @@ type Message = {
110
117
  meta?: MessageMeta;
111
118
  };
112
119
  type BuilderToHostMessage = Extract<Message, {
113
- type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR';
120
+ type: 'READY' | 'CHANGE' | 'LOADED' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR';
114
121
  }>;
115
122
  type HostToBuilderMessage = Extract<Message, {
116
123
  type: 'INIT' | 'UPLOAD_SUCCESS' | 'ASSETS_LIST' | 'DELETE_ASSET_SUCCESS';
@@ -154,11 +161,18 @@ interface EmailBuilderProps {
154
161
  * - `sdk`: use `externalFooterHtml`
155
162
  */
156
163
  footerInjectionMode?: 'default' | 'sdk';
164
+ /** Render the embedded builder in preview-only mode with just the desktop/mobile switcher. */
165
+ preview?: boolean;
166
+ /** Backwards-compatible alias for `preview`. */
167
+ previewOnly?: boolean;
157
168
  className?: string;
158
169
  style?: CSSProperties;
159
170
  iframeTitle?: string;
160
171
  sandbox?: string;
161
172
  onChange?: (html: string) => void;
173
+ /** Called once after the editor finishes processing the initially imported HTML.
174
+ * Updates internal state without marking the template as user-modified. */
175
+ onLoad?: (html: string) => void;
162
176
  onSave?: (html: string) => void;
163
177
  onUpload?: UploadHandler;
164
178
  onListAssets?: ListAssetsHandler;
@@ -178,4 +192,4 @@ interface EmailBuilderHandle {
178
192
 
179
193
  declare const EmailBuilder: React.ForwardRefExoticComponent<EmailBuilderProps & React.RefAttributes<EmailBuilderHandle>>;
180
194
 
181
- export { type AssetItem, type AssetsListPayload, type AuthErrorPayload, type BuilderConfig, type BuilderToHostMessage, type ChangePayload, type DeleteAssetHandler, type DeleteAssetPayload, type DeleteAssetSuccessPayload, EMAIL_BUILDER_PROTOCOL_VERSION, EmailBuilder, type EmailBuilderHandle, type EmailBuilderProps, type EmailBuilderStatus, type HostToBuilderMessage, type InitPayload, type ListAssetsHandler, type ListAssetsPayload, type Message, type MessageMeta, type MessageType, type SavePayload, type UploadHandler, type UploadPayload, type UploadSuccessPayload, createMessageMeta, isMessageLike };
195
+ export { type AssetItem, type AssetsListPayload, type AuthErrorPayload, type BuilderConfig, type BuilderToHostMessage, type ChangePayload, type DeleteAssetHandler, type DeleteAssetPayload, type DeleteAssetSuccessPayload, EMAIL_BUILDER_PROTOCOL_VERSION, EmailBuilder, type EmailBuilderHandle, type EmailBuilderProps, type EmailBuilderStatus, type HostToBuilderMessage, type InitPayload, type ListAssetsHandler, type ListAssetsPayload, type LoadedPayload, type Message, type MessageMeta, type MessageType, type SavePayload, type UploadHandler, type UploadPayload, type UploadSuccessPayload, createMessageMeta, isMessageLike };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import React, { CSSProperties } from 'react';
2
2
 
3
3
  declare const EMAIL_BUILDER_PROTOCOL_VERSION = "1.0.0";
4
- type MessageType = 'INIT' | 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'UPLOAD_SUCCESS' | 'LIST_ASSETS' | 'ASSETS_LIST' | 'DELETE_ASSET' | 'DELETE_ASSET_SUCCESS' | 'AUTH_ERROR';
4
+ type MessageType = 'INIT' | 'READY' | 'CHANGE' | 'LOADED' | 'SAVE' | 'UPLOAD' | 'UPLOAD_SUCCESS' | 'LIST_ASSETS' | 'ASSETS_LIST' | 'DELETE_ASSET' | 'DELETE_ASSET_SUCCESS' | 'AUTH_ERROR';
5
5
  interface MessageMeta {
6
6
  id: string;
7
7
  correlationId?: string;
@@ -34,6 +34,9 @@ interface InitPayload {
34
34
  interface ChangePayload {
35
35
  html: string;
36
36
  }
37
+ interface LoadedPayload {
38
+ html: string;
39
+ }
37
40
  interface SavePayload {
38
41
  html: string;
39
42
  }
@@ -76,6 +79,10 @@ type Message = {
76
79
  type: 'CHANGE';
77
80
  payload: ChangePayload;
78
81
  meta?: MessageMeta;
82
+ } | {
83
+ type: 'LOADED';
84
+ payload: LoadedPayload;
85
+ meta?: MessageMeta;
79
86
  } | {
80
87
  type: 'SAVE';
81
88
  payload: SavePayload;
@@ -110,7 +117,7 @@ type Message = {
110
117
  meta?: MessageMeta;
111
118
  };
112
119
  type BuilderToHostMessage = Extract<Message, {
113
- type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR';
120
+ type: 'READY' | 'CHANGE' | 'LOADED' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR';
114
121
  }>;
115
122
  type HostToBuilderMessage = Extract<Message, {
116
123
  type: 'INIT' | 'UPLOAD_SUCCESS' | 'ASSETS_LIST' | 'DELETE_ASSET_SUCCESS';
@@ -154,11 +161,18 @@ interface EmailBuilderProps {
154
161
  * - `sdk`: use `externalFooterHtml`
155
162
  */
156
163
  footerInjectionMode?: 'default' | 'sdk';
164
+ /** Render the embedded builder in preview-only mode with just the desktop/mobile switcher. */
165
+ preview?: boolean;
166
+ /** Backwards-compatible alias for `preview`. */
167
+ previewOnly?: boolean;
157
168
  className?: string;
158
169
  style?: CSSProperties;
159
170
  iframeTitle?: string;
160
171
  sandbox?: string;
161
172
  onChange?: (html: string) => void;
173
+ /** Called once after the editor finishes processing the initially imported HTML.
174
+ * Updates internal state without marking the template as user-modified. */
175
+ onLoad?: (html: string) => void;
162
176
  onSave?: (html: string) => void;
163
177
  onUpload?: UploadHandler;
164
178
  onListAssets?: ListAssetsHandler;
@@ -178,4 +192,4 @@ interface EmailBuilderHandle {
178
192
 
179
193
  declare const EmailBuilder: React.ForwardRefExoticComponent<EmailBuilderProps & React.RefAttributes<EmailBuilderHandle>>;
180
194
 
181
- export { type AssetItem, type AssetsListPayload, type AuthErrorPayload, type BuilderConfig, type BuilderToHostMessage, type ChangePayload, type DeleteAssetHandler, type DeleteAssetPayload, type DeleteAssetSuccessPayload, EMAIL_BUILDER_PROTOCOL_VERSION, EmailBuilder, type EmailBuilderHandle, type EmailBuilderProps, type EmailBuilderStatus, type HostToBuilderMessage, type InitPayload, type ListAssetsHandler, type ListAssetsPayload, type Message, type MessageMeta, type MessageType, type SavePayload, type UploadHandler, type UploadPayload, type UploadSuccessPayload, createMessageMeta, isMessageLike };
195
+ export { type AssetItem, type AssetsListPayload, type AuthErrorPayload, type BuilderConfig, type BuilderToHostMessage, type ChangePayload, type DeleteAssetHandler, type DeleteAssetPayload, type DeleteAssetSuccessPayload, EMAIL_BUILDER_PROTOCOL_VERSION, EmailBuilder, type EmailBuilderHandle, type EmailBuilderProps, type EmailBuilderStatus, type HostToBuilderMessage, type InitPayload, type ListAssetsHandler, type ListAssetsPayload, type LoadedPayload, type Message, type MessageMeta, type MessageType, type SavePayload, type UploadHandler, type UploadPayload, type UploadSuccessPayload, createMessageMeta, isMessageLike };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{forwardRef as me,useCallback as p,useEffect as V,useImperativeHandle as Te,useMemo as re,useRef as f,useState as ae}from"react";var Ee="1.0.0",ge=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS","LIST_ASSETS","ASSETS_LIST","DELETE_ASSET","DELETE_ASSET_SUCCESS","AUTH_ERROR"];function v(a){if(typeof a!="object"||a===null)return!1;let o=a;if(typeof o.type!="string"||!ge.includes(o.type))return!1;if("meta"in o&&o.meta!==void 0){let r=o.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 ee(a){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:a,version:Ee,sentAt:Date.now()}}function te(a,o){if(o){let S=new URL(o);if(S.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return S.origin}let r;try{r=new URL(a)}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 A(a,o){let r=ee(o);return{...a,meta:r}}function W(a){return JSON.stringify(a!=null?a:null)}import{jsx as ne,jsxs as Pe}from"react/jsx-runtime";var we="allow-scripts allow-same-origin allow-forms",Ae="<h1>Hello World</h1><p>Start building your email template.</p>",Me="https://pc-email-template-builder.netlify.app",Le={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 _e(a,o){if(!o||!o.trim())return a;try{let r=new URL(a,typeof window!="undefined"?window.location.href:"https://example.com");return r.searchParams.set("embedToken",o),r.toString()}catch{let r=a.includes("?")?"&":"?";return`${a}${r}embedToken=${encodeURIComponent(o)}`}}function Ue({src:a,initialHtml:o,embedToken:r,templateId:S,config:h,showFooter:b,includeUnsubscribe:C,externalFooterHtml:m,footerInjectionMode:K,className:se,style:ie,iframeTitle:oe="Email Builder",sandbox:le=we,onChange:M,onSave:L,onUpload:x,onListAssets:O,onDeleteAsset:H,onReady:I,onStatusChange:_,onAuthError:E,allowedOrigin:Y},ue){let U=(a==null?void 0:a.trim())||Me,ce=re(()=>_e(U,r),[U,r]),P=f(null),c=f(null),y=f(!1),D=f("loading"),[de,G]=ae("loading"),[pe,fe]=ae(0),R=f([]),T=f(null),d=f(null),n=f(null),k=typeof o=="string"?o:S?"":Ae,j=K||(m&&m.trim()?"sdk":"default"),z={html:k,config:h,...S?{templateId:S}:{},showFooter:b,includeUnsubscribe:C,...m?{externalFooterHtml:m}:{},footerInjectionMode:j},q=f(W(z)),w=f({type:"INIT",payload:z}),De=re(()=>te(U,Y),[U,Y]),B=p(()=>"*",[]),g=p(e=>{D.current!==e&&(D.current=e,G(e),_==null||_(e))},[_]),u=p((e,s)=>{var i,l;let t=(l=(i=P.current)==null?void 0:i.contentWindow)!=null?l:c.current;if(t&&(c.current=t),!c.current||!y.current){R.current.push({message:e,correlationId:s});return}c.current.postMessage(A(e,s),B())},[B]),F=p(()=>{if(!y.current||!c.current)return;let e=[...R.current];R.current=[],e.forEach(({message:s,correlationId:t})=>{var i;(i=c.current)==null||i.postMessage(A(s,t),B())})},[B]),$=p(()=>{y.current||(d.current&&(window.clearTimeout(d.current),d.current=null),n.current&&(window.clearInterval(n.current),n.current=null),y.current=!0,g("ready"),I==null||I(),u(w.current),F())},[F,I,u,g]),J=p(async e=>{var s,t;if(e.type==="UPLOAD"){if(!x){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{let i=await x(e.payload.file);u({type:"UPLOAD_SUCCESS",payload:{url:i}},(s=e.meta)==null?void 0:s.id)}catch(i){console.error("[EmailBuilderSDK] Upload handler failed",i),u({type:"UPLOAD_SUCCESS",payload:{url:""}},(t=e.meta)==null?void 0:t.id)}}},[x,u]),Q=p(async e=>{var s,t,i;if(e.type==="LIST_ASSETS"){if(!O){u({type:"ASSETS_LIST",payload:{assets:[]}},(s=e.meta)==null?void 0:s.id);return}try{let l=await O(e.payload);u({type:"ASSETS_LIST",payload:{assets:Array.isArray(l)?l:[]}},(t=e.meta)==null?void 0:t.id)}catch(l){console.error("[EmailBuilderSDK] list assets handler failed",l),u({type:"ASSETS_LIST",payload:{assets:[]}},(i=e.meta)==null?void 0:i.id)}}},[O,u]),X=p(async e=>{var s,t,i;if(e.type==="DELETE_ASSET"){if(!H){u({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(s=e.meta)==null?void 0:s.id);return}try{let l=await H(e.payload||{});u({type:"DELETE_ASSET_SUCCESS",payload:{success:!!l}},(t=e.meta)==null?void 0:t.id)}catch(l){console.error("[EmailBuilderSDK] delete asset handler failed",l),u({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(i=e.meta)==null?void 0:i.id)}}},[H,u]),N=p(e=>{var i,l,Z;let s=(l=(i=P.current)==null?void 0:i.contentWindow)!=null?l:c.current;if(!s||e.source!==s||!v(e.data))return;if(!T.current)T.current=e.origin;else if(e.origin!==T.current)return;let t=e.data;switch(e.source&&e.source!==c.current&&(c.current=e.source),t.type){case"READY":$();break;case"CHANGE":M==null||M(t.payload.html);break;case"SAVE":L==null||L(t.payload.html);break;case"UPLOAD":J(t);break;case"LIST_ASSETS":Q(t);break;case"DELETE_ASSET":X(t);break;case"AUTH_ERROR":{let ye=((Z=t.payload)==null?void 0:Z.message)||"Email builder authentication failed";D.current!=="error"&&(D.current="error",G("error"),E==null||E(ye));break}default:break}},[$,J,Q,X,M,L,E,g]);V(()=>{if(typeof window!="undefined")return window.addEventListener("message",N),()=>{window.removeEventListener("message",N)}},[N]),V(()=>{let e={html:k,config:h,...S?{templateId:S}:{},showFooter:b,includeUnsubscribe:C,...m!==void 0?{externalFooterHtml:m}:{},footerInjectionMode:j},s=W(e);w.current={type:"INIT",payload:e},s!==q.current&&y.current&&u(w.current),q.current=s},[h,k,u,S,b,C,m,K]);let Se=p(()=>{var t,i;if(c.current=(i=(t=P.current)==null?void 0:t.contentWindow)!=null?i:null,y.current=!1,T.current=null,g("loading"),c.current)try{c.current.postMessage(A(w.current),"*")}catch{}d.current&&window.clearTimeout(d.current),n.current&&window.clearInterval(n.current);let e=0,s=12;n.current=window.setInterval(()=>{var l;if(y.current){n.current&&(window.clearInterval(n.current),n.current=null);return}e+=1;try{(l=c.current)==null||l.postMessage(A(w.current),"*")}catch{}e>=s&&n.current&&(window.clearInterval(n.current),n.current=null)},1e3),d.current=window.setTimeout(()=>{y.current||(n.current&&(window.clearInterval(n.current),n.current=null),g("error"),E==null||E("Builder handshake failed or authentication was rejected."))},12e3)},[E,g]);return Te(ue,()=>({reload(){R.current=[],y.current=!1,c.current=null,T.current=null,d.current&&(window.clearTimeout(d.current),d.current=null),n.current&&(window.clearInterval(n.current),n.current=null),g("loading"),fe(e=>e+1)}}),[g]),V(()=>()=>{d.current&&(window.clearTimeout(d.current),d.current=null),n.current&&(window.clearInterval(n.current),n.current=null)},[]),Pe("div",{className:se,style:{position:"relative",width:"100%",height:"100%",...ie},children:[ne("iframe",{ref:P,src:ce,title:oe,sandbox:le,style:Ie,loading:"lazy",allowFullScreen:!0,onLoad:Se},pe),de!=="ready"&&ne("div",{style:Le,children:"Connecting to builder\u2026"})]})}var Ne=me(Ue);export{Ee as EMAIL_BUILDER_PROTOCOL_VERSION,Ne as EmailBuilder,ee as createMessageMeta,v as isMessageLike};
1
+ import{forwardRef as Le,useCallback as p,useEffect as G,useImperativeHandle as Ie,useMemo as $,useRef as f,useState as ie}from"react";var Ae="1.0.0",Me=["INIT","READY","CHANGE","LOADED","SAVE","UPLOAD","UPLOAD_SUCCESS","LIST_ASSETS","ASSETS_LIST","DELETE_ASSET","DELETE_ASSET_SUCCESS","AUTH_ERROR"];function K(r){if(typeof r!="object"||r===null)return!1;let n=r;if(typeof n.type!="string"||!Me.includes(n.type))return!1;if("meta"in n&&n.meta!==void 0){let t=n.meta;if(t.id&&typeof t.id!="string"||t.correlationId&&typeof t.correlationId!="string"||t.version&&typeof t.version!="string"||t.sentAt&&typeof t.sentAt!="number")return!1}return!0}function ne(r){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:r,version:Ae,sentAt:Date.now()}}function se(r,n){if(n){let S=new URL(n);if(S.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return S.origin}let t;try{t=new URL(r)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!t.origin||t.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return t.origin}function M(r,n){let t=ne(n);return{...r,meta:t}}function Y(r){return JSON.stringify(r!=null?r:null)}import{jsx as oe,jsxs as Oe}from"react/jsx-runtime";var De="allow-scripts allow-same-origin allow-forms",Pe="<h1>Hello World</h1><p>Start building your email template.</p>",Ue="https://pc-email-template-builder.netlify.app",_e={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},Re={border:"none",width:"100%",height:"100%"};function he(r,n){if(!n)return r;try{let t=new URL(r,typeof window!="undefined"?window.location.href:"https://example.com");return t.searchParams.set("preview","true"),t.searchParams.set("previewOnly","true"),t.toString()}catch{let t=r.includes("?")?"&":"?";return`${r}${t}preview=true&previewOnly=true`}}function Be(r,n){if(!n||!n.trim())return r;try{let t=new URL(r,typeof window!="undefined"?window.location.href:"https://example.com");return t.searchParams.set("embedToken",n),t.toString()}catch{let t=r.includes("?")?"&":"?";return`${r}${t}embedToken=${encodeURIComponent(n)}`}}function be({src:r,initialHtml:n,embedToken:t,templateId:S,config:T,showFooter:C,includeUnsubscribe:x,externalFooterHtml:m,footerInjectionMode:j,preview:le=!1,previewOnly:ue=!1,className:ce,style:de,iframeTitle:pe="Email Builder",sandbox:fe=De,onChange:L,onLoad:I,onSave:D,onUpload:H,onListAssets:k,onDeleteAsset:v,onReady:P,onStatusChange:U,onAuthError:E,allowedOrigin:z},Se){let _=(r==null?void 0:r.trim())||Ue,R=le||ue,N=$(()=>R?{...T!=null?T:{},preview:!0,previewOnly:!0}:T,[T,R]),ye=$(()=>Be(he(_,R),t),[_,t,R]),h=f(null),c=f(null),y=f(!1),B=f("loading"),[Ee,q]=ie("loading"),[ge,me]=ie(0),b=f([]),w=f(null),d=f(null),s=f(null),W=typeof n=="string"?n:S?"":Pe,F=j||(m&&m.trim()?"sdk":"default"),J={html:W,config:N,...S?{templateId:S}:{},showFooter:C,includeUnsubscribe:x,...m?{externalFooterHtml:m}:{},footerInjectionMode:F},Q=f(Y(J)),A=f({type:"INIT",payload:J}),Ce=$(()=>se(_,z),[_,z]),O=p(()=>"*",[]),g=p(e=>{B.current!==e&&(B.current=e,q(e),U==null||U(e))},[U]),u=p((e,i)=>{var o,l;let a=(l=(o=h.current)==null?void 0:o.contentWindow)!=null?l:c.current;if(a&&(c.current=a),!c.current||!y.current){b.current.push({message:e,correlationId:i});return}c.current.postMessage(M(e,i),O())},[O]),X=p(()=>{if(!y.current||!c.current)return;let e=[...b.current];b.current=[],e.forEach(({message:i,correlationId:a})=>{var o;(o=c.current)==null||o.postMessage(M(i,a),O())})},[O]),Z=p(()=>{y.current||(d.current&&(window.clearTimeout(d.current),d.current=null),s.current&&(window.clearInterval(s.current),s.current=null),y.current=!0,g("ready"),P==null||P(),u(A.current),X())},[X,P,u,g]),ee=p(async e=>{var i,a;if(e.type==="UPLOAD"){if(!H){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{let o=await H(e.payload.file);u({type:"UPLOAD_SUCCESS",payload:{url:o}},(i=e.meta)==null?void 0:i.id)}catch(o){console.error("[EmailBuilderSDK] Upload handler failed",o),u({type:"UPLOAD_SUCCESS",payload:{url:""}},(a=e.meta)==null?void 0:a.id)}}},[H,u]),te=p(async e=>{var i,a,o;if(e.type==="LIST_ASSETS"){if(!k){u({type:"ASSETS_LIST",payload:{assets:[]}},(i=e.meta)==null?void 0:i.id);return}try{let l=await k(e.payload);u({type:"ASSETS_LIST",payload:{assets:Array.isArray(l)?l:[]}},(a=e.meta)==null?void 0:a.id)}catch(l){console.error("[EmailBuilderSDK] list assets handler failed",l),u({type:"ASSETS_LIST",payload:{assets:[]}},(o=e.meta)==null?void 0:o.id)}}},[k,u]),re=p(async e=>{var i,a,o;if(e.type==="DELETE_ASSET"){if(!v){u({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(i=e.meta)==null?void 0:i.id);return}try{let l=await v(e.payload||{});u({type:"DELETE_ASSET_SUCCESS",payload:{success:!!l}},(a=e.meta)==null?void 0:a.id)}catch(l){console.error("[EmailBuilderSDK] delete asset handler failed",l),u({type:"DELETE_ASSET_SUCCESS",payload:{success:!1}},(o=e.meta)==null?void 0:o.id)}}},[v,u]),V=p(e=>{var o,l,ae;let i=(l=(o=h.current)==null?void 0:o.contentWindow)!=null?l:c.current;if(!i||e.source!==i||!K(e.data))return;if(!w.current)w.current=e.origin;else if(e.origin!==w.current)return;let a=e.data;switch(e.source&&e.source!==c.current&&(c.current=e.source),a.type){case"READY":Z();break;case"CHANGE":L==null||L(a.payload.html);break;case"LOADED":I==null||I(a.payload.html);break;case"SAVE":D==null||D(a.payload.html);break;case"UPLOAD":ee(a);break;case"LIST_ASSETS":te(a);break;case"DELETE_ASSET":re(a);break;case"AUTH_ERROR":{let we=((ae=a.payload)==null?void 0:ae.message)||"Email builder authentication failed";B.current!=="error"&&(B.current="error",q("error"),E==null||E(we));break}default:break}},[Z,ee,te,re,L,I,D,E,g]);G(()=>{if(typeof window!="undefined")return window.addEventListener("message",V),()=>{window.removeEventListener("message",V)}},[V]),G(()=>{let e={html:W,config:N,...S?{templateId:S}:{},showFooter:C,includeUnsubscribe:x,...m!==void 0?{externalFooterHtml:m}:{},footerInjectionMode:F},i=Y(e);A.current={type:"INIT",payload:e},i!==Q.current&&y.current&&u(A.current),Q.current=i},[N,W,u,S,C,x,m,j]);let Te=p(()=>{var a,o;if(c.current=(o=(a=h.current)==null?void 0:a.contentWindow)!=null?o:null,y.current=!1,w.current=null,g("loading"),c.current)try{c.current.postMessage(M(A.current),"*")}catch{}d.current&&window.clearTimeout(d.current),s.current&&window.clearInterval(s.current);let e=0,i=12;s.current=window.setInterval(()=>{var l;if(y.current){s.current&&(window.clearInterval(s.current),s.current=null);return}e+=1;try{(l=c.current)==null||l.postMessage(M(A.current),"*")}catch{}e>=i&&s.current&&(window.clearInterval(s.current),s.current=null)},1e3),d.current=window.setTimeout(()=>{y.current||(s.current&&(window.clearInterval(s.current),s.current=null),g("error"),E==null||E("Builder handshake failed or authentication was rejected."))},12e3)},[E,g]);return Ie(Se,()=>({reload(){b.current=[],y.current=!1,c.current=null,w.current=null,d.current&&(window.clearTimeout(d.current),d.current=null),s.current&&(window.clearInterval(s.current),s.current=null),g("loading"),me(e=>e+1)}}),[g]),G(()=>()=>{d.current&&(window.clearTimeout(d.current),d.current=null),s.current&&(window.clearInterval(s.current),s.current=null)},[]),Oe("div",{className:ce,style:{position:"relative",width:"100%",height:"100%",...de},children:[oe("iframe",{ref:h,src:ye,title:pe,sandbox:fe,style:Re,loading:"lazy",allowFullScreen:!0,onLoad:Te},ge),Ee!=="ready"&&oe("div",{style:_e,children:"Connecting to builder\u2026"})]})}var Ge=Le(be);export{Ae as EMAIL_BUILDER_PROTOCOL_VERSION,Ge as EmailBuilder,ne as createMessageMeta,K 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, InitPayload } 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>';\nconst DEFAULT_BUILDER_SRC = 'https://pc-email-template-builder.netlify.app';\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 appendEmbedTokenToSrc(src: string, embedToken: string | undefined): string {\n if (!embedToken || !embedToken.trim()) {\n return src;\n }\n try {\n const u = new URL(src, typeof window !== 'undefined' ? window.location.href : 'https://example.com');\n u.searchParams.set('embedToken', embedToken);\n return u.toString();\n } catch {\n const sep = src.includes('?') ? '&' : '?';\n return `${src}${sep}embedToken=${encodeURIComponent(embedToken)}`;\n }\n}\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n embedToken,\n templateId,\n config,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onListAssets,\n onDeleteAsset,\n onReady,\n onStatusChange,\n onAuthError,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const resolvedSrc = src?.trim() || DEFAULT_BUILDER_SRC;\n const iframeSrc = useMemo(() => appendEmbedTokenToSrc(resolvedSrc, embedToken), [resolvedSrc, embedToken]);\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 handshakeRetryIntervalRef = useRef<number | null>(null);\n\n const effectiveInitialHtml =\n typeof initialHtml === 'string'\n ? initialHtml\n : templateId\n ? ''\n : DEFAULT_INITIAL_HTML;\n\n const effectiveFooterMode =\n footerInjectionMode ||\n (externalFooterHtml && externalFooterHtml.trim() ? 'sdk' : 'default');\n\n const initPayload: InitPayload = {\n html: effectiveInitialHtml,\n config,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\n\n const initSignatureRef = useRef(stableSignature(initPayload));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: initPayload,\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(resolvedSrc, allowedOrigin), [resolvedSrc, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => '*', []);\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n // Keep builder session ready; upload failure should not flip global iframe status.\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url: '' } }, eventMessage.meta?.id);\n }\n },\n [onUpload, postMessage]\n );\n\n const handleListAssets = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'LIST_ASSETS') {\n return;\n }\n if (!onListAssets) {\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n return;\n }\n try {\n const assets = await onListAssets(eventMessage.payload);\n postMessage(\n { type: 'ASSETS_LIST', payload: { assets: Array.isArray(assets) ? assets : [] } },\n eventMessage.meta?.id\n );\n } catch (error) {\n console.error('[EmailBuilderSDK] list assets handler failed', error);\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n }\n },\n [onListAssets, postMessage]\n );\n\n const handleDeleteAsset = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'DELETE_ASSET') {\n return;\n }\n if (!onDeleteAsset) {\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n return;\n }\n try {\n const success = await onDeleteAsset(eventMessage.payload || {});\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: !!success } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] delete asset handler failed', error);\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n }\n },\n [onDeleteAsset, postMessage]\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 case 'LIST_ASSETS':\n void handleListAssets(message);\n break;\n case 'DELETE_ASSET':\n void handleDeleteAsset(message);\n break;\n case 'AUTH_ERROR': {\n const msg = message.payload?.message || 'Email builder authentication failed';\n if (statusRef.current !== 'error') {\n statusRef.current = 'error';\n setStatus('error');\n onAuthError?.(msg);\n }\n break;\n }\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, handleListAssets, handleDeleteAsset, onChange, onSave, onAuthError, setStatusSafely]\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: InitPayload = {\n html: effectiveInitialHtml,\n config,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml !== undefined ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\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 }, [\n config,\n effectiveInitialHtml,\n postMessage,\n templateId,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n ]);\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 if (builderWindowRef.current) {\n try {\n builderWindowRef.current.postMessage(buildEnvelope(latestInitRef.current), '*');\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n }\n\n let attempts = 0;\n const maxAttempts = 12;\n handshakeRetryIntervalRef.current = window.setInterval(() => {\n if (readyRef.current) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n return;\n }\n attempts += 1;\n try {\n builderWindowRef.current?.postMessage(buildEnvelope(latestInitRef.current), '*');\n } catch {\n // Keep retrying until timeout.\n }\n if (attempts >= maxAttempts) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n }\n }, 1000);\n\n handshakeTimerRef.current = window.setTimeout(() => {\n if (readyRef.current) {\n return;\n }\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n setStatusSafely('error');\n onAuthError?.('Builder handshake failed or authentication was rejected.');\n }, 12000);\n }, [onAuthError, 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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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={iframeSrc}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && (\n <div style={overlayStyle}>Connecting to builder…</div>\n )}\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 | 'LIST_ASSETS'\n | 'ASSETS_LIST'\n | 'DELETE_ASSET'\n | 'DELETE_ASSET_SUCCESS'\n | 'AUTH_ERROR';\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 /** Inline HTML to import (optional if templateId is set and builder fetches server-side). */\n html?: string;\n /** When set, embedded builder fetches HTML from API using embed token + this id. */\n templateId?: string;\n config?: BuilderConfig;\n /**\n * Optional: host-provided footer HTML to be rendered by the builder (SDK mode).\n * If set, the builder can avoid importing its own footer and render this exact footer instead.\n */\n externalFooterHtml?: string;\n /**\n * Footer source selection.\n * - `default`: builder uses its existing behavior.\n * - `sdk`: builder uses `externalFooterHtml` (and should avoid importing/auto-generating footer).\n */\n footerInjectionMode?: 'default' | 'sdk';\n /** Show \"Powered by Public Circles\" branding in footer. Controlled by host based on add-on purchase. */\n showFooter?: boolean;\n /** Include unsubscribe link in footer. Controlled by host toggle. */\n includeUnsubscribe?: boolean;\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 interface AssetItem {\n url: string;\n id?: string;\n name?: string;\n thumbnailUrl?: string;\n}\n\nexport interface ListAssetsPayload {\n limit?: number;\n}\n\nexport interface AssetsListPayload {\n assets: AssetItem[];\n}\n\nexport interface DeleteAssetPayload {\n id?: string;\n url?: string;\n}\n\nexport interface DeleteAssetSuccessPayload {\n success: boolean;\n}\n\nexport interface AuthErrorPayload {\n message: 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 | { type: 'LIST_ASSETS'; payload?: ListAssetsPayload; meta?: MessageMeta }\n | { type: 'ASSETS_LIST'; payload: AssetsListPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET'; payload: DeleteAssetPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET_SUCCESS'; payload: DeleteAssetSuccessPayload; meta?: MessageMeta }\n | { type: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' | 'ASSETS_LIST' | 'DELETE_ASSET_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_SUCCESS',\n 'LIST_ASSETS',\n 'ASSETS_LIST',\n 'DELETE_ASSET',\n 'DELETE_ASSET_SUCCESS',\n 'AUTH_ERROR',\n];\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","DEFAULT_BUILDER_SRC","overlayStyle","iframeStyle","appendEmbedTokenToSrc","src","embedToken","u","sep","EmailBuilderInner","initialHtml","templateId","config","showFooter","includeUnsubscribe","externalFooterHtml","footerInjectionMode","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onListAssets","onDeleteAsset","onReady","onStatusChange","onAuthError","allowedOrigin","ref","resolvedSrc","iframeSrc","useMemo","iframeRef","useRef","builderWindowRef","readyRef","statusRef","status","setStatus","useState","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","handshakeRetryIntervalRef","effectiveInitialHtml","effectiveFooterMode","initPayload","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","useCallback","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleListAssets","_c","assets","handleDeleteAsset","success","handleMessage","event","iframeWindow","isMessageLike","msg","useEffect","nextPayload","signature","handleIframeLoad","attempts","maxAttempts","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, InitPayload } 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>';\nconst DEFAULT_BUILDER_SRC = 'https://pc-email-template-builder.netlify.app';\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 appendPreviewParamsToSrc(src: string, preview: boolean): string {\n if (!preview) {\n return src;\n }\n try {\n const u = new URL(src, typeof window !== 'undefined' ? window.location.href : 'https://example.com');\n u.searchParams.set('preview', 'true');\n u.searchParams.set('previewOnly', 'true');\n return u.toString();\n } catch {\n const sep = src.includes('?') ? '&' : '?';\n return `${src}${sep}preview=true&previewOnly=true`;\n }\n}\n\nfunction appendEmbedTokenToSrc(src: string, embedToken: string | undefined): string {\n if (!embedToken || !embedToken.trim()) {\n return src;\n }\n try {\n const u = new URL(src, typeof window !== 'undefined' ? window.location.href : 'https://example.com');\n u.searchParams.set('embedToken', embedToken);\n return u.toString();\n } catch {\n const sep = src.includes('?') ? '&' : '?';\n return `${src}${sep}embedToken=${encodeURIComponent(embedToken)}`;\n }\n}\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n embedToken,\n templateId,\n config,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n preview = false,\n previewOnly = false,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onLoad,\n onSave,\n onUpload,\n onListAssets,\n onDeleteAsset,\n onReady,\n onStatusChange,\n onAuthError,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const resolvedSrc = src?.trim() || DEFAULT_BUILDER_SRC;\n const isPreviewMode = preview || previewOnly;\n const effectiveConfig = useMemo(\n () => (isPreviewMode ? { ...(config ?? {}), preview: true, previewOnly: true } : config),\n [config, isPreviewMode]\n );\n const iframeSrc = useMemo(\n () => appendEmbedTokenToSrc(appendPreviewParamsToSrc(resolvedSrc, isPreviewMode), embedToken),\n [resolvedSrc, embedToken, isPreviewMode]\n );\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 handshakeRetryIntervalRef = useRef<number | null>(null);\n\n const effectiveInitialHtml =\n typeof initialHtml === 'string'\n ? initialHtml\n : templateId\n ? ''\n : DEFAULT_INITIAL_HTML;\n\n const effectiveFooterMode =\n footerInjectionMode ||\n (externalFooterHtml && externalFooterHtml.trim() ? 'sdk' : 'default');\n\n const initPayload: InitPayload = {\n html: effectiveInitialHtml,\n config: effectiveConfig,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\n\n const initSignatureRef = useRef(stableSignature(initPayload));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: initPayload,\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(resolvedSrc, allowedOrigin), [resolvedSrc, allowedOrigin]);\n\n const resolveTargetOrigin = useCallback(() => '*', []);\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n // Keep builder session ready; upload failure should not flip global iframe status.\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url: '' } }, eventMessage.meta?.id);\n }\n },\n [onUpload, postMessage]\n );\n\n const handleListAssets = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'LIST_ASSETS') {\n return;\n }\n if (!onListAssets) {\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n return;\n }\n try {\n const assets = await onListAssets(eventMessage.payload);\n postMessage(\n { type: 'ASSETS_LIST', payload: { assets: Array.isArray(assets) ? assets : [] } },\n eventMessage.meta?.id\n );\n } catch (error) {\n console.error('[EmailBuilderSDK] list assets handler failed', error);\n postMessage({ type: 'ASSETS_LIST', payload: { assets: [] } }, eventMessage.meta?.id);\n }\n },\n [onListAssets, postMessage]\n );\n\n const handleDeleteAsset = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'DELETE_ASSET') {\n return;\n }\n if (!onDeleteAsset) {\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n return;\n }\n try {\n const success = await onDeleteAsset(eventMessage.payload || {});\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: !!success } }, eventMessage.meta?.id);\n } catch (error) {\n console.error('[EmailBuilderSDK] delete asset handler failed', error);\n postMessage({ type: 'DELETE_ASSET_SUCCESS', payload: { success: false } }, eventMessage.meta?.id);\n }\n },\n [onDeleteAsset, postMessage]\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 'LOADED':\n onLoad?.(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 case 'LIST_ASSETS':\n void handleListAssets(message);\n break;\n case 'DELETE_ASSET':\n void handleDeleteAsset(message);\n break;\n case 'AUTH_ERROR': {\n const msg = message.payload?.message || 'Email builder authentication failed';\n if (statusRef.current !== 'error') {\n statusRef.current = 'error';\n setStatus('error');\n onAuthError?.(msg);\n }\n break;\n }\n default:\n break;\n }\n },\n [handleReadyMessage, handleUpload, handleListAssets, handleDeleteAsset, onChange, onLoad, onSave, onAuthError, setStatusSafely]\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: InitPayload = {\n html: effectiveInitialHtml,\n config: effectiveConfig,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\n ...(externalFooterHtml !== undefined ? { externalFooterHtml } : {}),\n footerInjectionMode: effectiveFooterMode,\n };\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 }, [\n effectiveConfig,\n effectiveInitialHtml,\n postMessage,\n templateId,\n showFooter,\n includeUnsubscribe,\n externalFooterHtml,\n footerInjectionMode,\n ]);\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 if (builderWindowRef.current) {\n try {\n builderWindowRef.current.postMessage(buildEnvelope(latestInitRef.current), '*');\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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n }\n\n let attempts = 0;\n const maxAttempts = 12;\n handshakeRetryIntervalRef.current = window.setInterval(() => {\n if (readyRef.current) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n return;\n }\n attempts += 1;\n try {\n builderWindowRef.current?.postMessage(buildEnvelope(latestInitRef.current), '*');\n } catch {\n // Keep retrying until timeout.\n }\n if (attempts >= maxAttempts) {\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n }\n }, 1000);\n\n handshakeTimerRef.current = window.setTimeout(() => {\n if (readyRef.current) {\n return;\n }\n if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.current = null;\n }\n setStatusSafely('error');\n onAuthError?.('Builder handshake failed or authentication was rejected.');\n }, 12000);\n }, [onAuthError, 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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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 if (handshakeRetryIntervalRef.current) {\n window.clearInterval(handshakeRetryIntervalRef.current);\n handshakeRetryIntervalRef.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={iframeSrc}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && (\n <div style={overlayStyle}>Connecting to builder…</div>\n )}\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 | 'LOADED'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS'\n | 'LIST_ASSETS'\n | 'ASSETS_LIST'\n | 'DELETE_ASSET'\n | 'DELETE_ASSET_SUCCESS'\n | 'AUTH_ERROR';\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 /** Inline HTML to import (optional if templateId is set and builder fetches server-side). */\n html?: string;\n /** When set, embedded builder fetches HTML from API using embed token + this id. */\n templateId?: string;\n config?: BuilderConfig;\n /**\n * Optional: host-provided footer HTML to be rendered by the builder (SDK mode).\n * If set, the builder can avoid importing its own footer and render this exact footer instead.\n */\n externalFooterHtml?: string;\n /**\n * Footer source selection.\n * - `default`: builder uses its existing behavior.\n * - `sdk`: builder uses `externalFooterHtml` (and should avoid importing/auto-generating footer).\n */\n footerInjectionMode?: 'default' | 'sdk';\n /** Show \"Powered by Public Circles\" branding in footer. Controlled by host based on add-on purchase. */\n showFooter?: boolean;\n /** Include unsubscribe link in footer. Controlled by host toggle. */\n includeUnsubscribe?: boolean;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface LoadedPayload {\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 interface AssetItem {\n url: string;\n id?: string;\n name?: string;\n thumbnailUrl?: string;\n}\n\nexport interface ListAssetsPayload {\n limit?: number;\n}\n\nexport interface AssetsListPayload {\n assets: AssetItem[];\n}\n\nexport interface DeleteAssetPayload {\n id?: string;\n url?: string;\n}\n\nexport interface DeleteAssetSuccessPayload {\n success: boolean;\n}\n\nexport interface AuthErrorPayload {\n message: 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: 'LOADED'; payload: LoadedPayload; 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 | { type: 'LIST_ASSETS'; payload?: ListAssetsPayload; meta?: MessageMeta }\n | { type: 'ASSETS_LIST'; payload: AssetsListPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET'; payload: DeleteAssetPayload; meta?: MessageMeta }\n | { type: 'DELETE_ASSET_SUCCESS'; payload: DeleteAssetSuccessPayload; meta?: MessageMeta }\n | { type: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'LOADED' | 'SAVE' | 'UPLOAD' | 'LIST_ASSETS' | 'DELETE_ASSET' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' | 'ASSETS_LIST' | 'DELETE_ASSET_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'LOADED',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_SUCCESS',\n 'LIST_ASSETS',\n 'ASSETS_LIST',\n 'DELETE_ASSET',\n 'DELETE_ASSET_SUCCESS',\n 'AUTH_ERROR',\n];\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","DEFAULT_BUILDER_SRC","overlayStyle","iframeStyle","appendPreviewParamsToSrc","src","preview","u","sep","appendEmbedTokenToSrc","embedToken","EmailBuilderInner","initialHtml","templateId","config","showFooter","includeUnsubscribe","externalFooterHtml","footerInjectionMode","previewOnly","className","style","iframeTitle","sandbox","onChange","onLoad","onSave","onUpload","onListAssets","onDeleteAsset","onReady","onStatusChange","onAuthError","allowedOrigin","ref","resolvedSrc","isPreviewMode","effectiveConfig","useMemo","iframeSrc","iframeRef","useRef","builderWindowRef","readyRef","statusRef","status","setStatus","useState","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","handshakeRetryIntervalRef","effectiveInitialHtml","effectiveFooterMode","initPayload","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","useCallback","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleListAssets","_c","assets","handleDeleteAsset","success","handleMessage","event","iframeWindow","isMessageLike","msg","useEffect","nextPayload","signature","handleIframeLoad","attempts","maxAttempts","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.12",
3
+ "version": "0.1.14",
4
4
  "description": "React iframe SDK for embedding the Circles email template builder",
5
5
  "license": "MIT",
6
6
  "type": "module",