@alihaiderrana/email-builder-sdk 0.1.9 → 0.1.10

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 C=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ue=Object.prototype.hasOwnProperty;var ce=(r,n)=>{for(var a in n)C(r,a,{get:n[a],enumerable:!0})},de=(r,n,a,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let p of le(n))!ue.call(r,p)&&p!==a&&C(r,p,{get:()=>n[p],enumerable:!(u=oe(n,p))||u.enumerable});return r};var fe=r=>de(C({},"__esModule",{value:!0}),r);var Re={};ce(Re,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>$,EmailBuilder:()=>Te,createMessageMeta:()=>N,isMessageLike:()=>x});module.exports=fe(Re);var e=require("react");var $="1.0.0",pe=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS","AUTH_ERROR"];function x(r){if(typeof r!="object"||r===null)return!1;let n=r;if(typeof n.type!="string"||!pe.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 N(r){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:r,version:$,sentAt:Date.now()}}function j(r,n){if(n){let u=new URL(n);if(u.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return u.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 T(r,n){let a=N(n);return{...r,meta:a}}function v(r){return JSON.stringify(r!=null?r:null)}var R=require("react/jsx-runtime"),ge="allow-scripts allow-same-origin allow-forms",me="<h1>Hello World</h1><p>Start building your email template.</p>",ye="https://pc-email-template-builder.netlify.app",we={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},Me={border:"none",width:"100%",height:"100%"};function Ee(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 Se({src:r,initialHtml:n,embedToken:a,templateId:u,config:p,showFooter:H,includeUnsubscribe:D,className:J,style:Q,iframeTitle:X="Email Builder",sandbox:Z=ge,onChange:I,onSave:U,onUpload:O,onReady:P,onStatusChange:A,onAuthError:m,allowedOrigin:W},ee){let B=(r==null?void 0:r.trim())||ye,re=(0,e.useMemo)(()=>Ee(B,a),[B,a]),L=(0,e.useRef)(null),l=(0,e.useRef)(null),g=(0,e.useRef)(!1),M=(0,e.useRef)("loading"),[te,F]=(0,e.useState)("loading"),[ne,ae]=(0,e.useState)(0),h=(0,e.useRef)([]),E=(0,e.useRef)(null),c=(0,e.useRef)(null),i=(0,e.useRef)(null),k=typeof n=="string"?n:u?"":me,V={html:k,config:p,...u?{templateId:u}:{},showFooter:H,includeUnsubscribe:D},Y=(0,e.useRef)(v(V)),S=(0,e.useRef)({type:"INIT",payload:V}),Ie=(0,e.useMemo)(()=>j(B,W),[B,W]),b=(0,e.useCallback)(()=>"*",[]),d=(0,e.useCallback)(t=>{M.current!==t&&(M.current=t,F(t),A==null||A(t))},[A]),w=(0,e.useCallback)((t,o)=>{var f,y;let s=(y=(f=L.current)==null?void 0:f.contentWindow)!=null?y:l.current;if(s&&(l.current=s),!l.current||!g.current){h.current.push({message:t,correlationId:o});return}l.current.postMessage(T(t,o),b())},[b]),G=(0,e.useCallback)(()=>{if(!g.current||!l.current)return;let t=[...h.current];h.current=[],t.forEach(({message:o,correlationId:s})=>{var f;(f=l.current)==null||f.postMessage(T(o,s),b())})},[b]),z=(0,e.useCallback)(()=>{g.current||(c.current&&(window.clearTimeout(c.current),c.current=null),i.current&&(window.clearInterval(i.current),i.current=null),g.current=!0,d("ready"),P==null||P(),w(S.current),G())},[G,P,w,d]),K=(0,e.useCallback)(async t=>{var o;if(t.type==="UPLOAD"){if(!O){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{d("loading");let s=await O(t.payload.file);w({type:"UPLOAD_SUCCESS",payload:{url:s}},(o=t.meta)==null?void 0:o.id)}catch(s){d("error"),console.error("[EmailBuilderSDK] Upload handler failed",s)}finally{M.current!=="error"&&d("ready")}}},[O,w,d]),_=(0,e.useCallback)(t=>{var f,y,q;let o=(y=(f=L.current)==null?void 0:f.contentWindow)!=null?y:l.current;if(!o||t.source!==o||!x(t.data))return;if(!E.current)E.current=t.origin;else if(t.origin!==E.current)return;let s=t.data;switch(t.source&&t.source!==l.current&&(l.current=t.source),s.type){case"READY":z();break;case"CHANGE":I==null||I(s.payload.html);break;case"SAVE":U==null||U(s.payload.html);break;case"UPLOAD":K(s);break;case"AUTH_ERROR":{let se=((q=s.payload)==null?void 0:q.message)||"Email builder authentication failed";M.current!=="error"&&(M.current="error",F("error"),m==null||m(se));break}default:break}},[z,K,I,U,m,d]);(0,e.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",_),()=>{window.removeEventListener("message",_)}},[_]),(0,e.useEffect)(()=>{let t={html:k,config:p,...u?{templateId:u}:{},showFooter:H,includeUnsubscribe:D},o=v(t);S.current={type:"INIT",payload:t},o!==Y.current&&g.current&&w(S.current),Y.current=o},[p,k,w,u,H,D]);let ie=(0,e.useCallback)(()=>{var s,f;if(l.current=(f=(s=L.current)==null?void 0:s.contentWindow)!=null?f:null,g.current=!1,E.current=null,d("loading"),l.current)try{l.current.postMessage(T(S.current),"*")}catch{}c.current&&window.clearTimeout(c.current),i.current&&window.clearInterval(i.current);let t=0,o=12;i.current=window.setInterval(()=>{var y;if(g.current){i.current&&(window.clearInterval(i.current),i.current=null);return}t+=1;try{(y=l.current)==null||y.postMessage(T(S.current),"*")}catch{}t>=o&&i.current&&(window.clearInterval(i.current),i.current=null)},1e3),c.current=window.setTimeout(()=>{g.current||(i.current&&(window.clearInterval(i.current),i.current=null),d("error"),m==null||m("Builder handshake failed or authentication was rejected."))},12e3)},[m,d]);return(0,e.useImperativeHandle)(ee,()=>({reload(){h.current=[],g.current=!1,l.current=null,E.current=null,c.current&&(window.clearTimeout(c.current),c.current=null),i.current&&(window.clearInterval(i.current),i.current=null),d("loading"),ae(t=>t+1)}}),[d]),(0,e.useEffect)(()=>()=>{c.current&&(window.clearTimeout(c.current),c.current=null),i.current&&(window.clearInterval(i.current),i.current=null)},[]),(0,R.jsxs)("div",{className:J,style:{position:"relative",width:"100%",height:"100%",...Q},children:[(0,R.jsx)("iframe",{ref:L,src:re,title:X,sandbox:Z,style:Me,loading:"lazy",allowFullScreen:!0,onLoad:ie},ne),te!=="ready"&&(0,R.jsx)("div",{style:we,children:"Connecting to builder\u2026"})]})}var Te=(0,e.forwardRef)(Se);0&&(module.exports={EMAIL_BUILDER_PROTOCOL_VERSION,EmailBuilder,createMessageMeta,isMessageLike});
1
+ "use strict";var v=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var pe=(r,n)=>{for(var a in n)v(r,a,{get:n[a],enumerable:!0})},ge=(r,n,a,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let p of de(n))!fe.call(r,p)&&p!==a&&v(r,p,{get:()=>n[p],enumerable:!(u=ce(n,p))||u.enumerable});return r};var me=r=>ge(v({},"__esModule",{value:!0}),r);var Pe={};pe(Pe,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>J,EmailBuilder:()=>Ue,createMessageMeta:()=>N,isMessageLike:()=>x});module.exports=me(Pe);var e=require("react");var J="1.0.0",ye=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS","AUTH_ERROR"];function x(r){if(typeof r!="object"||r===null)return!1;let n=r;if(typeof n.type!="string"||!ye.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 N(r){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:r,version:J,sentAt:Date.now()}}function Q(r,n){if(n){let u=new URL(n);if(u.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return u.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 I(r,n){let a=N(n);return{...r,meta:a}}function W(r){return JSON.stringify(r!=null?r:null)}var R=require("react/jsx-runtime"),we="allow-scripts allow-same-origin allow-forms",Me="<h1>Hello World</h1><p>Start building your email template.</p>",Ee="https://pc-email-template-builder.netlify.app",Se={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},Te={border:"none",width:"100%",height:"100%"};function Ie(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 Re({src:r,initialHtml:n,embedToken:a,templateId:u,config:p,showFooter:H,includeUnsubscribe:O,externalFooterHtml:M,footerInjectionMode:V,className:X,style:Z,iframeTitle:ee="Email Builder",sandbox:re=we,onChange:U,onSave:P,onUpload:k,onReady:A,onStatusChange:B,onAuthError:m,allowedOrigin:Y},te){let L=(r==null?void 0:r.trim())||Ee,ne=(0,e.useMemo)(()=>Ie(L,a),[L,a]),h=(0,e.useRef)(null),l=(0,e.useRef)(null),g=(0,e.useRef)(!1),E=(0,e.useRef)("loading"),[ae,F]=(0,e.useState)("loading"),[ie,se]=(0,e.useState)(0),b=(0,e.useRef)([]),S=(0,e.useRef)(null),c=(0,e.useRef)(null),i=(0,e.useRef)(null),_=typeof n=="string"?n:u?"":Me,oe=V||(M&&M.trim()?"sdk":"default"),G={html:_,config:p,...u?{templateId:u}:{},showFooter:H,includeUnsubscribe:O,...M?{externalFooterHtml:M}:{},footerInjectionMode:oe},z=(0,e.useRef)(W(G)),T=(0,e.useRef)({type:"INIT",payload:G}),Ae=(0,e.useMemo)(()=>Q(L,Y),[L,Y]),D=(0,e.useCallback)(()=>"*",[]),d=(0,e.useCallback)(t=>{E.current!==t&&(E.current=t,F(t),B==null||B(t))},[B]),w=(0,e.useCallback)((t,o)=>{var f,y;let s=(y=(f=h.current)==null?void 0:f.contentWindow)!=null?y:l.current;if(s&&(l.current=s),!l.current||!g.current){b.current.push({message:t,correlationId:o});return}l.current.postMessage(I(t,o),D())},[D]),K=(0,e.useCallback)(()=>{if(!g.current||!l.current)return;let t=[...b.current];b.current=[],t.forEach(({message:o,correlationId:s})=>{var f;(f=l.current)==null||f.postMessage(I(o,s),D())})},[D]),j=(0,e.useCallback)(()=>{g.current||(c.current&&(window.clearTimeout(c.current),c.current=null),i.current&&(window.clearInterval(i.current),i.current=null),g.current=!0,d("ready"),A==null||A(),w(T.current),K())},[K,A,w,d]),q=(0,e.useCallback)(async t=>{var o;if(t.type==="UPLOAD"){if(!k){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{d("loading");let s=await k(t.payload.file);w({type:"UPLOAD_SUCCESS",payload:{url:s}},(o=t.meta)==null?void 0:o.id)}catch(s){d("error"),console.error("[EmailBuilderSDK] Upload handler failed",s)}finally{E.current!=="error"&&d("ready")}}},[k,w,d]),C=(0,e.useCallback)(t=>{var f,y,$;let o=(y=(f=h.current)==null?void 0:f.contentWindow)!=null?y:l.current;if(!o||t.source!==o||!x(t.data))return;if(!S.current)S.current=t.origin;else if(t.origin!==S.current)return;let s=t.data;switch(t.source&&t.source!==l.current&&(l.current=t.source),s.type){case"READY":j();break;case"CHANGE":U==null||U(s.payload.html);break;case"SAVE":P==null||P(s.payload.html);break;case"UPLOAD":q(s);break;case"AUTH_ERROR":{let ue=(($=s.payload)==null?void 0:$.message)||"Email builder authentication failed";E.current!=="error"&&(E.current="error",F("error"),m==null||m(ue));break}default:break}},[j,q,U,P,m,d]);(0,e.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",C),()=>{window.removeEventListener("message",C)}},[C]),(0,e.useEffect)(()=>{let t={html:_,config:p,...u?{templateId:u}:{},showFooter:H,includeUnsubscribe:O},o=W(t);T.current={type:"INIT",payload:t},o!==z.current&&g.current&&w(T.current),z.current=o},[p,_,w,u,H,O,M,V]);let le=(0,e.useCallback)(()=>{var s,f;if(l.current=(f=(s=h.current)==null?void 0:s.contentWindow)!=null?f:null,g.current=!1,S.current=null,d("loading"),l.current)try{l.current.postMessage(I(T.current),"*")}catch{}c.current&&window.clearTimeout(c.current),i.current&&window.clearInterval(i.current);let t=0,o=12;i.current=window.setInterval(()=>{var y;if(g.current){i.current&&(window.clearInterval(i.current),i.current=null);return}t+=1;try{(y=l.current)==null||y.postMessage(I(T.current),"*")}catch{}t>=o&&i.current&&(window.clearInterval(i.current),i.current=null)},1e3),c.current=window.setTimeout(()=>{g.current||(i.current&&(window.clearInterval(i.current),i.current=null),d("error"),m==null||m("Builder handshake failed or authentication was rejected."))},12e3)},[m,d]);return(0,e.useImperativeHandle)(te,()=>({reload(){b.current=[],g.current=!1,l.current=null,S.current=null,c.current&&(window.clearTimeout(c.current),c.current=null),i.current&&(window.clearInterval(i.current),i.current=null),d("loading"),se(t=>t+1)}}),[d]),(0,e.useEffect)(()=>()=>{c.current&&(window.clearTimeout(c.current),c.current=null),i.current&&(window.clearInterval(i.current),i.current=null)},[]),(0,R.jsxs)("div",{className:X,style:{position:"relative",width:"100%",height:"100%",...Z},children:[(0,R.jsx)("iframe",{ref:h,src:ne,title:ee,sandbox:re,style:Te,loading:"lazy",allowFullScreen:!0,onLoad:le},ie),ae!=="ready"&&(0,R.jsx)("div",{style:Se,children:"Connecting to builder\u2026"})]})}var Ue=(0,e.forwardRef)(Re);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 className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\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 initPayload: InitPayload = {\n html: effectiveInitialHtml,\n config,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\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 setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n 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, 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 };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage, templateId, showFooter, includeUnsubscribe]);\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 | '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 /** 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 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: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_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","appendEmbedTokenToSrc","src","embedToken","u","sep","EmailBuilderInner","initialHtml","templateId","config","showFooter","includeUnsubscribe","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","onAuthError","allowedOrigin","ref","resolvedSrc","iframeSrc","iframeRef","builderWindowRef","readyRef","statusRef","status","setStatus","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","handshakeRetryIntervalRef","effectiveInitialHtml","initPayload","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","_c","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 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 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 setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n 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, 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 };\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 | '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 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: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_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","appendEmbedTokenToSrc","src","embedToken","u","sep","EmailBuilderInner","initialHtml","templateId","config","showFooter","includeUnsubscribe","externalFooterHtml","footerInjectionMode","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","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","handleMessage","event","_c","iframeWindow","isMessageLike","msg","nextPayload","signature","handleIframeLoad","attempts","maxAttempts","key","EmailBuilder"]}
package/dist/index.d.cts CHANGED
@@ -15,6 +15,17 @@ interface InitPayload {
15
15
  /** When set, embedded builder fetches HTML from API using embed token + this id. */
16
16
  templateId?: string;
17
17
  config?: BuilderConfig;
18
+ /**
19
+ * Optional: host-provided footer HTML to be rendered by the builder (SDK mode).
20
+ * If set, the builder can avoid importing its own footer and render this exact footer instead.
21
+ */
22
+ externalFooterHtml?: string;
23
+ /**
24
+ * Footer source selection.
25
+ * - `default`: builder uses its existing behavior.
26
+ * - `sdk`: builder uses `externalFooterHtml` (and should avoid importing/auto-generating footer).
27
+ */
28
+ footerInjectionMode?: 'default' | 'sdk';
18
29
  /** Show "Powered by Public Circles" branding in footer. Controlled by host based on add-on purchase. */
19
30
  showFooter?: boolean;
20
31
  /** Include unsubscribe link in footer. Controlled by host toggle. */
@@ -95,6 +106,17 @@ interface EmailBuilderProps {
95
106
  showFooter?: boolean;
96
107
  /** Include unsubscribe link in footer. Defaults to true. */
97
108
  includeUnsubscribe?: boolean;
109
+ /**
110
+ * Optional: host-provided footer HTML to be rendered inside the builder (SDK mode).
111
+ * When provided, the builder can avoid importing/auto-generating its own footer.
112
+ */
113
+ externalFooterHtml?: string;
114
+ /**
115
+ * Footer source selection.
116
+ * - `default`: existing behavior
117
+ * - `sdk`: use `externalFooterHtml`
118
+ */
119
+ footerInjectionMode?: 'default' | 'sdk';
98
120
  className?: string;
99
121
  style?: CSSProperties;
100
122
  iframeTitle?: string;
package/dist/index.d.ts CHANGED
@@ -15,6 +15,17 @@ interface InitPayload {
15
15
  /** When set, embedded builder fetches HTML from API using embed token + this id. */
16
16
  templateId?: string;
17
17
  config?: BuilderConfig;
18
+ /**
19
+ * Optional: host-provided footer HTML to be rendered by the builder (SDK mode).
20
+ * If set, the builder can avoid importing its own footer and render this exact footer instead.
21
+ */
22
+ externalFooterHtml?: string;
23
+ /**
24
+ * Footer source selection.
25
+ * - `default`: builder uses its existing behavior.
26
+ * - `sdk`: builder uses `externalFooterHtml` (and should avoid importing/auto-generating footer).
27
+ */
28
+ footerInjectionMode?: 'default' | 'sdk';
18
29
  /** Show "Powered by Public Circles" branding in footer. Controlled by host based on add-on purchase. */
19
30
  showFooter?: boolean;
20
31
  /** Include unsubscribe link in footer. Controlled by host toggle. */
@@ -95,6 +106,17 @@ interface EmailBuilderProps {
95
106
  showFooter?: boolean;
96
107
  /** Include unsubscribe link in footer. Defaults to true. */
97
108
  includeUnsubscribe?: boolean;
109
+ /**
110
+ * Optional: host-provided footer HTML to be rendered inside the builder (SDK mode).
111
+ * When provided, the builder can avoid importing/auto-generating its own footer.
112
+ */
113
+ externalFooterHtml?: string;
114
+ /**
115
+ * Footer source selection.
116
+ * - `default`: existing behavior
117
+ * - `sdk`: use `externalFooterHtml`
118
+ */
119
+ footerInjectionMode?: 'default' | 'sdk';
98
120
  className?: string;
99
121
  style?: CSSProperties;
100
122
  iframeTitle?: string;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{forwardRef as de,useCallback as y,useEffect as N,useImperativeHandle as fe,useMemo as j,useRef as d,useState as J}from"react";var ue="1.0.0",ce=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS","AUTH_ERROR"];function _(t){if(typeof t!="object"||t===null)return!1;let a=t;if(typeof a.type!="string"||!ce.includes(a.type))return!1;if("meta"in a&&a.meta!==void 0){let r=a.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 q(t){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:t,version:ue,sentAt:Date.now()}}function $(t,a){if(a){let f=new URL(a);if(f.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return f.origin}let r;try{r=new URL(t)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!r.origin||r.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return r.origin}function T(t,a){let r=q(a);return{...t,meta:r}}function C(t){return JSON.stringify(t!=null?t:null)}import{jsx as Q,jsxs as Se}from"react/jsx-runtime";var pe="allow-scripts allow-same-origin allow-forms",ge="<h1>Hello World</h1><p>Start building your email template.</p>",me="https://pc-email-template-builder.netlify.app",ye={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},we={border:"none",width:"100%",height:"100%"};function Me(t,a){if(!a||!a.trim())return t;try{let r=new URL(t,typeof window!="undefined"?window.location.href:"https://example.com");return r.searchParams.set("embedToken",a),r.toString()}catch{let r=t.includes("?")?"&":"?";return`${t}${r}embedToken=${encodeURIComponent(a)}`}}function Ee({src:t,initialHtml:a,embedToken:r,templateId:f,config:b,showFooter:x,includeUnsubscribe:H,className:X,style:Z,iframeTitle:ee="Email Builder",sandbox:re=pe,onChange:R,onSave:I,onUpload:D,onReady:U,onStatusChange:P,onAuthError:g,allowedOrigin:v},te){let A=(t==null?void 0:t.trim())||me,ne=j(()=>Me(A,r),[A,r]),B=d(null),o=d(null),p=d(!1),M=d("loading"),[ae,W]=J("loading"),[ie,se]=J(0),L=d([]),E=d(null),l=d(null),n=d(null),O=typeof a=="string"?a:f?"":ge,F={html:O,config:b,...f?{templateId:f}:{},showFooter:x,includeUnsubscribe:H},V=d(C(F)),S=d({type:"INIT",payload:F}),Te=j(()=>$(A,v),[A,v]),h=y(()=>"*",[]),u=y(e=>{M.current!==e&&(M.current=e,W(e),P==null||P(e))},[P]),w=y((e,s)=>{var c,m;let i=(m=(c=B.current)==null?void 0:c.contentWindow)!=null?m:o.current;if(i&&(o.current=i),!o.current||!p.current){L.current.push({message:e,correlationId:s});return}o.current.postMessage(T(e,s),h())},[h]),Y=y(()=>{if(!p.current||!o.current)return;let e=[...L.current];L.current=[],e.forEach(({message:s,correlationId:i})=>{var c;(c=o.current)==null||c.postMessage(T(s,i),h())})},[h]),G=y(()=>{p.current||(l.current&&(window.clearTimeout(l.current),l.current=null),n.current&&(window.clearInterval(n.current),n.current=null),p.current=!0,u("ready"),U==null||U(),w(S.current),Y())},[Y,U,w,u]),z=y(async e=>{var s;if(e.type==="UPLOAD"){if(!D){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{u("loading");let i=await D(e.payload.file);w({type:"UPLOAD_SUCCESS",payload:{url:i}},(s=e.meta)==null?void 0:s.id)}catch(i){u("error"),console.error("[EmailBuilderSDK] Upload handler failed",i)}finally{M.current!=="error"&&u("ready")}}},[D,w,u]),k=y(e=>{var c,m,K;let s=(m=(c=B.current)==null?void 0:c.contentWindow)!=null?m:o.current;if(!s||e.source!==s||!_(e.data))return;if(!E.current)E.current=e.origin;else if(e.origin!==E.current)return;let i=e.data;switch(e.source&&e.source!==o.current&&(o.current=e.source),i.type){case"READY":G();break;case"CHANGE":R==null||R(i.payload.html);break;case"SAVE":I==null||I(i.payload.html);break;case"UPLOAD":z(i);break;case"AUTH_ERROR":{let le=((K=i.payload)==null?void 0:K.message)||"Email builder authentication failed";M.current!=="error"&&(M.current="error",W("error"),g==null||g(le));break}default:break}},[G,z,R,I,g,u]);N(()=>{if(typeof window!="undefined")return window.addEventListener("message",k),()=>{window.removeEventListener("message",k)}},[k]),N(()=>{let e={html:O,config:b,...f?{templateId:f}:{},showFooter:x,includeUnsubscribe:H},s=C(e);S.current={type:"INIT",payload:e},s!==V.current&&p.current&&w(S.current),V.current=s},[b,O,w,f,x,H]);let oe=y(()=>{var i,c;if(o.current=(c=(i=B.current)==null?void 0:i.contentWindow)!=null?c:null,p.current=!1,E.current=null,u("loading"),o.current)try{o.current.postMessage(T(S.current),"*")}catch{}l.current&&window.clearTimeout(l.current),n.current&&window.clearInterval(n.current);let e=0,s=12;n.current=window.setInterval(()=>{var m;if(p.current){n.current&&(window.clearInterval(n.current),n.current=null);return}e+=1;try{(m=o.current)==null||m.postMessage(T(S.current),"*")}catch{}e>=s&&n.current&&(window.clearInterval(n.current),n.current=null)},1e3),l.current=window.setTimeout(()=>{p.current||(n.current&&(window.clearInterval(n.current),n.current=null),u("error"),g==null||g("Builder handshake failed or authentication was rejected."))},12e3)},[g,u]);return fe(te,()=>({reload(){L.current=[],p.current=!1,o.current=null,E.current=null,l.current&&(window.clearTimeout(l.current),l.current=null),n.current&&(window.clearInterval(n.current),n.current=null),u("loading"),se(e=>e+1)}}),[u]),N(()=>()=>{l.current&&(window.clearTimeout(l.current),l.current=null),n.current&&(window.clearInterval(n.current),n.current=null)},[]),Se("div",{className:X,style:{position:"relative",width:"100%",height:"100%",...Z},children:[Q("iframe",{ref:B,src:ne,title:ee,sandbox:re,style:we,loading:"lazy",allowFullScreen:!0,onLoad:oe},ie),ae!=="ready"&&Q("div",{style:ye,children:"Connecting to builder\u2026"})]})}var xe=de(Ee);export{ue as EMAIL_BUILDER_PROTOCOL_VERSION,xe as EmailBuilder,q as createMessageMeta,_ as isMessageLike};
1
+ import{forwardRef as ge,useCallback as y,useEffect as N,useImperativeHandle as me,useMemo as Q,useRef as d,useState as X}from"react";var fe="1.0.0",pe=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS","AUTH_ERROR"];function C(t){if(typeof t!="object"||t===null)return!1;let a=t;if(typeof a.type!="string"||!pe.includes(a.type))return!1;if("meta"in a&&a.meta!==void 0){let r=a.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 $(t){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:t,version:fe,sentAt:Date.now()}}function J(t,a){if(a){let f=new URL(a);if(f.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return f.origin}let r;try{r=new URL(t)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!r.origin||r.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return r.origin}function I(t,a){let r=$(a);return{...t,meta:r}}function v(t){return JSON.stringify(t!=null?t:null)}import{jsx as Z,jsxs as Re}from"react/jsx-runtime";var ye="allow-scripts allow-same-origin allow-forms",we="<h1>Hello World</h1><p>Start building your email template.</p>",Me="https://pc-email-template-builder.netlify.app",Ee={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},Se={border:"none",width:"100%",height:"100%"};function Te(t,a){if(!a||!a.trim())return t;try{let r=new URL(t,typeof window!="undefined"?window.location.href:"https://example.com");return r.searchParams.set("embedToken",a),r.toString()}catch{let r=t.includes("?")?"&":"?";return`${t}${r}embedToken=${encodeURIComponent(a)}`}}function Ie({src:t,initialHtml:a,embedToken:r,templateId:f,config:D,showFooter:x,includeUnsubscribe:H,externalFooterHtml:M,footerInjectionMode:W,className:ee,style:re,iframeTitle:te="Email Builder",sandbox:ne=ye,onChange:R,onSave:U,onUpload:O,onReady:P,onStatusChange:A,onAuthError:g,allowedOrigin:V},ae){let B=(t==null?void 0:t.trim())||Me,ie=Q(()=>Te(B,r),[B,r]),L=d(null),o=d(null),p=d(!1),E=d("loading"),[se,Y]=X("loading"),[oe,le]=X(0),h=d([]),S=d(null),l=d(null),n=d(null),k=typeof a=="string"?a:f?"":we,ue=W||(M&&M.trim()?"sdk":"default"),F={html:k,config:D,...f?{templateId:f}:{},showFooter:x,includeUnsubscribe:H,...M?{externalFooterHtml:M}:{},footerInjectionMode:ue},G=d(v(F)),T=d({type:"INIT",payload:F}),Ue=Q(()=>J(B,V),[B,V]),b=y(()=>"*",[]),u=y(e=>{E.current!==e&&(E.current=e,Y(e),A==null||A(e))},[A]),w=y((e,s)=>{var c,m;let i=(m=(c=L.current)==null?void 0:c.contentWindow)!=null?m:o.current;if(i&&(o.current=i),!o.current||!p.current){h.current.push({message:e,correlationId:s});return}o.current.postMessage(I(e,s),b())},[b]),z=y(()=>{if(!p.current||!o.current)return;let e=[...h.current];h.current=[],e.forEach(({message:s,correlationId:i})=>{var c;(c=o.current)==null||c.postMessage(I(s,i),b())})},[b]),K=y(()=>{p.current||(l.current&&(window.clearTimeout(l.current),l.current=null),n.current&&(window.clearInterval(n.current),n.current=null),p.current=!0,u("ready"),P==null||P(),w(T.current),z())},[z,P,w,u]),j=y(async e=>{var s;if(e.type==="UPLOAD"){if(!O){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{u("loading");let i=await O(e.payload.file);w({type:"UPLOAD_SUCCESS",payload:{url:i}},(s=e.meta)==null?void 0:s.id)}catch(i){u("error"),console.error("[EmailBuilderSDK] Upload handler failed",i)}finally{E.current!=="error"&&u("ready")}}},[O,w,u]),_=y(e=>{var c,m,q;let s=(m=(c=L.current)==null?void 0:c.contentWindow)!=null?m:o.current;if(!s||e.source!==s||!C(e.data))return;if(!S.current)S.current=e.origin;else if(e.origin!==S.current)return;let i=e.data;switch(e.source&&e.source!==o.current&&(o.current=e.source),i.type){case"READY":K();break;case"CHANGE":R==null||R(i.payload.html);break;case"SAVE":U==null||U(i.payload.html);break;case"UPLOAD":j(i);break;case"AUTH_ERROR":{let de=((q=i.payload)==null?void 0:q.message)||"Email builder authentication failed";E.current!=="error"&&(E.current="error",Y("error"),g==null||g(de));break}default:break}},[K,j,R,U,g,u]);N(()=>{if(typeof window!="undefined")return window.addEventListener("message",_),()=>{window.removeEventListener("message",_)}},[_]),N(()=>{let e={html:k,config:D,...f?{templateId:f}:{},showFooter:x,includeUnsubscribe:H},s=v(e);T.current={type:"INIT",payload:e},s!==G.current&&p.current&&w(T.current),G.current=s},[D,k,w,f,x,H,M,W]);let ce=y(()=>{var i,c;if(o.current=(c=(i=L.current)==null?void 0:i.contentWindow)!=null?c:null,p.current=!1,S.current=null,u("loading"),o.current)try{o.current.postMessage(I(T.current),"*")}catch{}l.current&&window.clearTimeout(l.current),n.current&&window.clearInterval(n.current);let e=0,s=12;n.current=window.setInterval(()=>{var m;if(p.current){n.current&&(window.clearInterval(n.current),n.current=null);return}e+=1;try{(m=o.current)==null||m.postMessage(I(T.current),"*")}catch{}e>=s&&n.current&&(window.clearInterval(n.current),n.current=null)},1e3),l.current=window.setTimeout(()=>{p.current||(n.current&&(window.clearInterval(n.current),n.current=null),u("error"),g==null||g("Builder handshake failed or authentication was rejected."))},12e3)},[g,u]);return me(ae,()=>({reload(){h.current=[],p.current=!1,o.current=null,S.current=null,l.current&&(window.clearTimeout(l.current),l.current=null),n.current&&(window.clearInterval(n.current),n.current=null),u("loading"),le(e=>e+1)}}),[u]),N(()=>()=>{l.current&&(window.clearTimeout(l.current),l.current=null),n.current&&(window.clearInterval(n.current),n.current=null)},[]),Re("div",{className:ee,style:{position:"relative",width:"100%",height:"100%",...re},children:[Z("iframe",{ref:L,src:ie,title:te,sandbox:ne,style:Se,loading:"lazy",allowFullScreen:!0,onLoad:ce},oe),se!=="ready"&&Z("div",{style:Ee,children:"Connecting to builder\u2026"})]})}var Oe=ge(Ie);export{fe as EMAIL_BUILDER_PROTOCOL_VERSION,Oe as EmailBuilder,$ as createMessageMeta,C 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 className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\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 initPayload: InitPayload = {\n html: effectiveInitialHtml,\n config,\n ...(templateId ? { templateId } : {}),\n showFooter,\n includeUnsubscribe,\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 setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n 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, 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 };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage, templateId, showFooter, includeUnsubscribe]);\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 | '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 /** 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 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: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_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","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","onAuthError","allowedOrigin","ref","resolvedSrc","iframeSrc","useMemo","iframeRef","useRef","builderWindowRef","readyRef","statusRef","status","setStatus","useState","reloadKey","setReloadKey","queueRef","runtimeOriginRef","handshakeTimerRef","handshakeRetryIntervalRef","effectiveInitialHtml","initPayload","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","resolveTargetOrigin","useCallback","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","_c","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 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 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 setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n if (!iframeWindow || event.source !== iframeWindow) {\n return;\n }\n if (!isMessageLike(event.data)) {\n return;\n }\n if (!runtimeOriginRef.current) {\n runtimeOriginRef.current = event.origin;\n } else if (event.origin !== runtimeOriginRef.current) {\n return;\n }\n const message = event.data as BuilderToHostMessage;\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n 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, 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 };\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 | '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 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: 'AUTH_ERROR'; payload: AuthErrorPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'AUTH_ERROR' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = [\n 'INIT',\n 'READY',\n 'CHANGE',\n 'SAVE',\n 'UPLOAD',\n 'UPLOAD_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","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","handleMessage","event","_c","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.9",
3
+ "version": "0.1.10",
4
4
  "description": "React iframe SDK for embedding the Circles email template builder",
5
5
  "license": "MIT",
6
6
  "type": "module",