@alihaiderrana/email-builder-sdk 0.1.0
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/README.md +70 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +87 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @circles/email-builder-sdk
|
|
2
|
+
|
|
3
|
+
React SDK for embedding the Circles Email Builder in your app.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @circles/email-builder-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { EmailBuilder } from '@circles/email-builder-sdk';
|
|
15
|
+
|
|
16
|
+
export function EmailEditor() {
|
|
17
|
+
return (
|
|
18
|
+
<div style={{ height: '100vh' }}>
|
|
19
|
+
<EmailBuilder
|
|
20
|
+
src="https://pc-email-template-builder.netlify.app"
|
|
21
|
+
initialHtml="<h1>Welcome</h1><p>Edit this email template</p>"
|
|
22
|
+
onChange={(html) => console.log('changed', html)}
|
|
23
|
+
onSave={(html) => console.log('saved', html)}
|
|
24
|
+
onUpload={async (file) => {
|
|
25
|
+
const body = new FormData();
|
|
26
|
+
body.append('asset', file);
|
|
27
|
+
const response = await fetch('/api/uploads', { method: 'POST', body });
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
return data.url;
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
If `initialHtml` is not provided, the editor starts with a default Hello World template.
|
|
38
|
+
|
|
39
|
+
## Props
|
|
40
|
+
|
|
41
|
+
| Prop | Type | Required | Description |
|
|
42
|
+
| --- | --- | --- | --- |
|
|
43
|
+
| `src` | `string` | Yes | Absolute URL of the hosted email builder app. |
|
|
44
|
+
| `initialHtml` | `string` | No | Initial HTML content to load in the editor. |
|
|
45
|
+
| `config` | `Record<string, unknown>` | No | Optional builder configuration object. |
|
|
46
|
+
| `className` | `string` | No | Class for the wrapper container. |
|
|
47
|
+
| `style` | `React.CSSProperties` | No | Inline styles for the wrapper container. |
|
|
48
|
+
| `iframeTitle` | `string` | No | Accessible title for the iframe. |
|
|
49
|
+
| `sandbox` | `string` | No | Custom iframe sandbox value. |
|
|
50
|
+
| `allowedOrigin` | `string` | No | Override allowed origin for message validation. |
|
|
51
|
+
| `onReady` | `() => void` | No | Called when editor is ready. |
|
|
52
|
+
| `onStatusChange` | `(status) => void` | No | Called on status changes (`loading`, `ready`, `error`). |
|
|
53
|
+
| `onChange` | `(html: string) => void` | No | Called when editor content changes. |
|
|
54
|
+
| `onSave` | `(html: string) => void` | No | Called when user saves content. |
|
|
55
|
+
| `onUpload` | `(file: File) => Promise<string>` | No | Upload handler that returns a public URL for inserted assets. |
|
|
56
|
+
|
|
57
|
+
## Ref API
|
|
58
|
+
|
|
59
|
+
`EmailBuilder` supports a ref with:
|
|
60
|
+
|
|
61
|
+
- `reload(): void` - Reloads the embedded editor iframe.
|
|
62
|
+
|
|
63
|
+
## Requirements
|
|
64
|
+
|
|
65
|
+
- React `>=18.2.0`
|
|
66
|
+
- ReactDOM `>=18.2.0`
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var h=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,s)=>{for(var t in s)h(e,t,{get:s[t],enumerable:!0})},$=(e,s,t,d)=>{if(s&&typeof s=="object"||typeof s=="function")for(let c of Q(s))!X.call(e,c)&&c!==t&&h(e,c,{get:()=>s[c],enumerable:!(d=J(s,c))||d.enumerable});return e};var ee=e=>$(h({},"__esModule",{value:!0}),e);var le={};Z(le,{EMAIL_BUILDER_PROTOCOL_VERSION:()=>_,EmailBuilder:()=>ie,createMessageMeta:()=>b,isMessageLike:()=>x});module.exports=ee(le);var r=require("react");var _="1.0.0",te=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS"];function x(e){if(typeof e!="object"||e===null)return!1;let s=e;if(typeof s.type!="string"||!te.includes(s.type))return!1;if("meta"in s&&s.meta!==void 0){let t=s.meta;if(t.id&&typeof t.id!="string"||t.correlationId&&typeof t.correlationId!="string"||t.version&&typeof t.version!="string"||t.sentAt&&typeof t.sentAt!="number")return!1}return!0}function b(e){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:e,version:_,sentAt:Date.now()}}function W(e,s){if(s){let d=new URL(s);if(d.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return d.origin}let t;try{t=new URL(e)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!t.origin||t.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return t.origin}function D(e,s){let t=b(s);return{...e,meta:t}}function v(e,s,t){return e.origin!==s||!t||e.source!==t||!x(e.data)?null:e.data}function R(e){return JSON.stringify(e!=null?e:null)}var m=require("react/jsx-runtime"),re="allow-scripts allow-same-origin allow-forms",se="<h1>Hello World</h1><p>Start building your email template.</p>",ne={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",fontSize:"0.875rem",fontWeight:500,background:"linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))",color:"#fff",zIndex:2},oe={border:"none",width:"100%",height:"100%"};function ae({src:e,initialHtml:s,config:t,className:d,style:c,iframeTitle:F="Email Builder",sandbox:V=re,onChange:M,onSave:E,onUpload:T,onReady:w,onStatusChange:S,allowedOrigin:H},Y){let A=(0,r.useRef)(null),i=(0,r.useRef)(null),p=(0,r.useRef)(!1),B=(0,r.useRef)("loading"),[z,G]=(0,r.useState)("loading"),[K,q]=(0,r.useState)(0),I=(0,r.useRef)([]),U=s!=null?s:se,O=(0,r.useRef)(R({html:U,config:t})),P=(0,r.useRef)({type:"INIT",payload:{html:U,config:t}}),g=(0,r.useMemo)(()=>W(e,H),[e,H]),l=(0,r.useCallback)(n=>{B.current!==n&&(B.current=n,G(n),S==null||S(n))},[S]),f=(0,r.useCallback)((n,o)=>{var u,y;let a=(y=(u=A.current)==null?void 0:u.contentWindow)!=null?y:i.current;if(a&&(i.current=a),!i.current||!p.current){I.current.push({message:n,correlationId:o});return}i.current.postMessage(D(n,o),g)},[g]),k=(0,r.useCallback)(()=>{if(!p.current||!i.current)return;let n=[...I.current];I.current=[],n.forEach(({message:o,correlationId:a})=>{var u;(u=i.current)==null||u.postMessage(D(o,a),g)})},[g]),C=(0,r.useCallback)(()=>{p.current=!0,l("ready"),w==null||w(),f(P.current),k()},[k,w,f,l]),N=(0,r.useCallback)(async n=>{var o;if(n.type==="UPLOAD"){if(!T){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{l("loading");let a=await T(n.payload.file);f({type:"UPLOAD_SUCCESS",payload:{url:a}},(o=n.meta)==null?void 0:o.id)}catch(a){l("error"),console.error("[EmailBuilderSDK] Upload handler failed",a)}finally{B.current!=="error"&&l("ready")}}},[T,f,l]),L=(0,r.useCallback)(n=>{var u,y;let o=(y=(u=A.current)==null?void 0:u.contentWindow)!=null?y:i.current,a=v(n,g,o);if(a)switch(n.source&&n.source!==i.current&&(i.current=n.source),a.type){case"READY":C();break;case"CHANGE":M==null||M(a.payload.html);break;case"SAVE":E==null||E(a.payload.html);break;case"UPLOAD":N(a);break;default:break}},[g,C,N,M,E]);(0,r.useEffect)(()=>{if(typeof window!="undefined")return window.addEventListener("message",L),()=>{window.removeEventListener("message",L)}},[L]),(0,r.useEffect)(()=>{let n={html:U,config:t},o=R(n);P.current={type:"INIT",payload:n},o!==O.current&&p.current&&f(P.current),O.current=o},[t,U,f]);let j=(0,r.useCallback)(()=>{var n,o;i.current=(o=(n=A.current)==null?void 0:n.contentWindow)!=null?o:null,p.current=!1,l("loading")},[l]);return(0,r.useImperativeHandle)(Y,()=>({reload(){I.current=[],p.current=!1,i.current=null,l("loading"),q(n=>n+1)}}),[l]),(0,m.jsxs)("div",{className:d,style:{position:"relative",width:"100%",height:"100%",...c},children:[(0,m.jsx)("iframe",{ref:A,src:e,title:F,sandbox:V,style:oe,loading:"lazy",allowFullScreen:!0,onLoad:j},K),z!=="ready"&&(0,m.jsx)("div",{style:ne,children:"Connecting to builder\u2026"})]})}var ie=(0,r.forwardRef)(ae);0&&(module.exports={EMAIL_BUILDER_PROTOCOL_VERSION,EmailBuilder,createMessageMeta,isMessageLike});
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/EmailBuilder.tsx","../src/protocol.ts","../src/utils.ts"],"sourcesContent":["export * from './EmailBuilder';\nexport * from './types';\nexport * from './protocol';\n","import React, {\n CSSProperties,\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { BuilderToHostMessage, HostToBuilderMessage } from './protocol';\nimport { buildEnvelope, deriveAllowedOrigin, sanitizeIncomingMessage, stableSignature } from './utils';\nimport type { EmailBuilderHandle, EmailBuilderProps, EmailBuilderStatus } from './types';\n\nconst DEFAULT_SANDBOX = 'allow-scripts allow-same-origin allow-forms';\nconst DEFAULT_INITIAL_HTML = '<h1>Hello World</h1><p>Start building your email template.</p>';\n\ntype PendingMessage = {\n message: HostToBuilderMessage;\n correlationId?: string;\n};\n\nconst overlayStyle: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '0.875rem',\n fontWeight: 500,\n background: 'linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))',\n color: '#fff',\n zIndex: 2,\n};\n\nconst iframeStyle: CSSProperties = {\n border: 'none',\n width: '100%',\n height: '100%',\n};\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n config,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onReady,\n onStatusChange,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const builderWindowRef = useRef<Window | null>(null);\n const readyRef = useRef(false);\n const statusRef = useRef<EmailBuilderStatus>('loading');\n const [status, setStatus] = useState<EmailBuilderStatus>('loading');\n const [reloadKey, setReloadKey] = useState(0);\n const queueRef = useRef<PendingMessage[]>([]);\n const effectiveInitialHtml = initialHtml ?? DEFAULT_INITIAL_HTML;\n const initSignatureRef = useRef(stableSignature({ html: effectiveInitialHtml, config }));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: { html: effectiveInitialHtml, config },\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(src, allowedOrigin), [src, allowedOrigin]);\n\n const 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), expectedOrigin);\n },\n [expectedOrigin]\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(buildEnvelope(message, correlationId), expectedOrigin);\n });\n }, [expectedOrigin]);\n\n const handleReadyMessage = useCallback(() => {\n readyRef.current = true;\n setStatusSafely('ready');\n onReady?.();\n postMessage(latestInitRef.current);\n flushQueue();\n }, [flushQueue, onReady, postMessage, setStatusSafely]);\n\n const handleUpload = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'UPLOAD') {\n return;\n }\n if (!onUpload) {\n console.warn('[EmailBuilderSDK] Upload requested but no onUpload handler is configured.');\n return;\n }\n try {\n setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n const message = sanitizeIncomingMessage(event, expectedOrigin, iframeWindow);\n if (!message) {\n return;\n }\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n default:\n break;\n }\n },\n [expectedOrigin, handleReadyMessage, handleUpload, onChange, onSave]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [handleMessage]);\n\n useEffect(() => {\n const nextPayload = { html: effectiveInitialHtml, config };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage]);\n\n const handleIframeLoad = useCallback(() => {\n builderWindowRef.current = iframeRef.current?.contentWindow ?? null;\n readyRef.current = false;\n setStatusSafely('loading');\n }, [setStatusSafely]);\n\n useImperativeHandle(\n ref,\n () => ({\n reload() {\n queueRef.current = [];\n readyRef.current = false;\n builderWindowRef.current = null;\n setStatusSafely('loading');\n setReloadKey((key) => key + 1);\n },\n }),\n [setStatusSafely]\n );\n\n return (\n <div className={className} style={{ position: 'relative', width: '100%', height: '100%', ...style }}>\n <iframe\n key={reloadKey}\n ref={iframeRef}\n src={src}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && <div style={overlayStyle}>Connecting to builder…</div>}\n </div>\n );\n}\n\nexport const EmailBuilder = forwardRef(EmailBuilderInner);\n","export const EMAIL_BUILDER_PROTOCOL_VERSION = '1.0.0';\n\nexport type MessageType =\n | 'INIT'\n | 'READY'\n | 'CHANGE'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS';\n\nexport interface MessageMeta {\n id: string;\n correlationId?: string;\n version: string;\n sentAt: number;\n}\n\nexport type BuilderConfig = Record<string, unknown> | undefined;\n\nexport interface InitPayload {\n html: string;\n config?: BuilderConfig;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface SavePayload {\n html: string;\n}\n\nexport interface UploadPayload {\n file: File;\n}\n\nexport interface UploadSuccessPayload {\n url: string;\n}\n\nexport type Message =\n | { type: 'INIT'; payload: InitPayload; meta?: MessageMeta }\n | { type: 'READY'; meta?: MessageMeta }\n | { type: 'CHANGE'; payload: ChangePayload; meta?: MessageMeta }\n | { type: 'SAVE'; payload: SavePayload; meta?: MessageMeta }\n | { type: 'UPLOAD'; payload: UploadPayload; meta?: MessageMeta }\n | { type: 'UPLOAD_SUCCESS'; payload: UploadSuccessPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = ['INIT', 'READY', 'CHANGE', 'SAVE', 'UPLOAD', 'UPLOAD_SUCCESS'];\n\nexport function isMessageLike(value: unknown): value is Message {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as { type?: unknown; payload?: unknown; meta?: unknown };\n if (typeof candidate.type !== 'string' || !VALID_TYPES.includes(candidate.type as MessageType)) {\n return false;\n }\n\n if ('meta' in candidate && candidate.meta !== undefined) {\n const meta = candidate.meta as Partial<MessageMeta>;\n if (\n (meta.id && typeof meta.id !== 'string') ||\n (meta.correlationId && typeof meta.correlationId !== 'string') ||\n (meta.version && typeof meta.version !== 'string') ||\n (meta.sentAt && typeof meta.sentAt !== 'number')\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function createMessageMeta(correlationId?: string): MessageMeta {\n const id = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n return {\n id,\n correlationId,\n version: EMAIL_BUILDER_PROTOCOL_VERSION,\n sentAt: Date.now(),\n };\n}\n","import type { BuilderToHostMessage, HostToBuilderMessage, MessageMeta } from './protocol';\nimport { createMessageMeta, isMessageLike } from './protocol';\n\nexport function deriveAllowedOrigin(src: string, override?: string): string {\n if (override) {\n const parsed = new URL(override);\n if (parsed.origin === 'null') {\n throw new Error('allowedOrigin must resolve to a valid origin');\n }\n return parsed.origin;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(src);\n } catch {\n throw new Error('EmailBuilder `src` must be an absolute URL (e.g. https://example.com)');\n }\n if (!parsed.origin || parsed.origin === 'null') {\n throw new Error('EmailBuilder requires an absolute src URL with a valid origin');\n }\n return parsed.origin;\n}\n\nexport function buildEnvelope<T extends HostToBuilderMessage>(message: T, correlationId?: string): T {\n const meta: MessageMeta = createMessageMeta(correlationId);\n return { ...message, meta } as T;\n}\n\nexport function sanitizeIncomingMessage(\n event: MessageEvent,\n allowedOrigin: string,\n iframeWindow: Window | null\n): BuilderToHostMessage | null {\n if (event.origin !== allowedOrigin) {\n return null;\n }\n\n if (!iframeWindow || event.source !== iframeWindow) {\n return null;\n }\n\n if (!isMessageLike(event.data)) {\n return null;\n }\n\n return event.data as BuilderToHostMessage;\n}\n\nexport function stableSignature(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["index_exports","__export","EMAIL_BUILDER_PROTOCOL_VERSION","EmailBuilder","createMessageMeta","isMessageLike","__toCommonJS","import_react","EMAIL_BUILDER_PROTOCOL_VERSION","VALID_TYPES","isMessageLike","value","candidate","meta","createMessageMeta","correlationId","deriveAllowedOrigin","src","override","parsed","buildEnvelope","message","correlationId","meta","createMessageMeta","sanitizeIncomingMessage","event","allowedOrigin","iframeWindow","isMessageLike","stableSignature","value","import_jsx_runtime","DEFAULT_SANDBOX","DEFAULT_INITIAL_HTML","overlayStyle","iframeStyle","EmailBuilderInner","src","initialHtml","config","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","allowedOrigin","ref","iframeRef","builderWindowRef","readyRef","statusRef","status","setStatus","reloadKey","setReloadKey","queueRef","effectiveInitialHtml","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","deriveAllowedOrigin","setStatusSafely","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","iframeWindow","sanitizeIncomingMessage","nextPayload","signature","handleIframeLoad","key","EmailBuilder"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
|
|
3
|
+
declare const EMAIL_BUILDER_PROTOCOL_VERSION = "1.0.0";
|
|
4
|
+
type MessageType = 'INIT' | 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'UPLOAD_SUCCESS';
|
|
5
|
+
interface MessageMeta {
|
|
6
|
+
id: string;
|
|
7
|
+
correlationId?: string;
|
|
8
|
+
version: string;
|
|
9
|
+
sentAt: number;
|
|
10
|
+
}
|
|
11
|
+
type BuilderConfig = Record<string, unknown> | undefined;
|
|
12
|
+
interface InitPayload {
|
|
13
|
+
html: string;
|
|
14
|
+
config?: BuilderConfig;
|
|
15
|
+
}
|
|
16
|
+
interface ChangePayload {
|
|
17
|
+
html: string;
|
|
18
|
+
}
|
|
19
|
+
interface SavePayload {
|
|
20
|
+
html: string;
|
|
21
|
+
}
|
|
22
|
+
interface UploadPayload {
|
|
23
|
+
file: File;
|
|
24
|
+
}
|
|
25
|
+
interface UploadSuccessPayload {
|
|
26
|
+
url: string;
|
|
27
|
+
}
|
|
28
|
+
type Message = {
|
|
29
|
+
type: 'INIT';
|
|
30
|
+
payload: InitPayload;
|
|
31
|
+
meta?: MessageMeta;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'READY';
|
|
34
|
+
meta?: MessageMeta;
|
|
35
|
+
} | {
|
|
36
|
+
type: 'CHANGE';
|
|
37
|
+
payload: ChangePayload;
|
|
38
|
+
meta?: MessageMeta;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'SAVE';
|
|
41
|
+
payload: SavePayload;
|
|
42
|
+
meta?: MessageMeta;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'UPLOAD';
|
|
45
|
+
payload: UploadPayload;
|
|
46
|
+
meta?: MessageMeta;
|
|
47
|
+
} | {
|
|
48
|
+
type: 'UPLOAD_SUCCESS';
|
|
49
|
+
payload: UploadSuccessPayload;
|
|
50
|
+
meta?: MessageMeta;
|
|
51
|
+
};
|
|
52
|
+
type BuilderToHostMessage = Extract<Message, {
|
|
53
|
+
type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD';
|
|
54
|
+
}>;
|
|
55
|
+
type HostToBuilderMessage = Extract<Message, {
|
|
56
|
+
type: 'INIT' | 'UPLOAD_SUCCESS';
|
|
57
|
+
}>;
|
|
58
|
+
declare function isMessageLike(value: unknown): value is Message;
|
|
59
|
+
declare function createMessageMeta(correlationId?: string): MessageMeta;
|
|
60
|
+
|
|
61
|
+
type UploadHandler = (file: File) => Promise<string>;
|
|
62
|
+
type EmailBuilderStatus = 'idle' | 'loading' | 'ready' | 'error';
|
|
63
|
+
interface EmailBuilderProps {
|
|
64
|
+
src: string;
|
|
65
|
+
initialHtml?: string;
|
|
66
|
+
config?: BuilderConfig;
|
|
67
|
+
className?: string;
|
|
68
|
+
style?: CSSProperties;
|
|
69
|
+
iframeTitle?: string;
|
|
70
|
+
sandbox?: string;
|
|
71
|
+
onChange?: (html: string) => void;
|
|
72
|
+
onSave?: (html: string) => void;
|
|
73
|
+
onUpload?: UploadHandler;
|
|
74
|
+
onReady?: () => void;
|
|
75
|
+
onStatusChange?: (status: EmailBuilderStatus) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Optionally override the derived origin (defaults to src origin)
|
|
78
|
+
*/
|
|
79
|
+
allowedOrigin?: string;
|
|
80
|
+
}
|
|
81
|
+
interface EmailBuilderHandle {
|
|
82
|
+
reload: () => void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
declare const EmailBuilder: React.ForwardRefExoticComponent<EmailBuilderProps & React.RefAttributes<EmailBuilderHandle>>;
|
|
86
|
+
|
|
87
|
+
export { type BuilderConfig, type BuilderToHostMessage, type ChangePayload, EMAIL_BUILDER_PROTOCOL_VERSION, EmailBuilder, type EmailBuilderHandle, type EmailBuilderProps, type EmailBuilderStatus, type HostToBuilderMessage, type InitPayload, type Message, type MessageMeta, type MessageType, type SavePayload, type UploadHandler, type UploadPayload, type UploadSuccessPayload, createMessageMeta, isMessageLike };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
|
|
3
|
+
declare const EMAIL_BUILDER_PROTOCOL_VERSION = "1.0.0";
|
|
4
|
+
type MessageType = 'INIT' | 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' | 'UPLOAD_SUCCESS';
|
|
5
|
+
interface MessageMeta {
|
|
6
|
+
id: string;
|
|
7
|
+
correlationId?: string;
|
|
8
|
+
version: string;
|
|
9
|
+
sentAt: number;
|
|
10
|
+
}
|
|
11
|
+
type BuilderConfig = Record<string, unknown> | undefined;
|
|
12
|
+
interface InitPayload {
|
|
13
|
+
html: string;
|
|
14
|
+
config?: BuilderConfig;
|
|
15
|
+
}
|
|
16
|
+
interface ChangePayload {
|
|
17
|
+
html: string;
|
|
18
|
+
}
|
|
19
|
+
interface SavePayload {
|
|
20
|
+
html: string;
|
|
21
|
+
}
|
|
22
|
+
interface UploadPayload {
|
|
23
|
+
file: File;
|
|
24
|
+
}
|
|
25
|
+
interface UploadSuccessPayload {
|
|
26
|
+
url: string;
|
|
27
|
+
}
|
|
28
|
+
type Message = {
|
|
29
|
+
type: 'INIT';
|
|
30
|
+
payload: InitPayload;
|
|
31
|
+
meta?: MessageMeta;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'READY';
|
|
34
|
+
meta?: MessageMeta;
|
|
35
|
+
} | {
|
|
36
|
+
type: 'CHANGE';
|
|
37
|
+
payload: ChangePayload;
|
|
38
|
+
meta?: MessageMeta;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'SAVE';
|
|
41
|
+
payload: SavePayload;
|
|
42
|
+
meta?: MessageMeta;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'UPLOAD';
|
|
45
|
+
payload: UploadPayload;
|
|
46
|
+
meta?: MessageMeta;
|
|
47
|
+
} | {
|
|
48
|
+
type: 'UPLOAD_SUCCESS';
|
|
49
|
+
payload: UploadSuccessPayload;
|
|
50
|
+
meta?: MessageMeta;
|
|
51
|
+
};
|
|
52
|
+
type BuilderToHostMessage = Extract<Message, {
|
|
53
|
+
type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD';
|
|
54
|
+
}>;
|
|
55
|
+
type HostToBuilderMessage = Extract<Message, {
|
|
56
|
+
type: 'INIT' | 'UPLOAD_SUCCESS';
|
|
57
|
+
}>;
|
|
58
|
+
declare function isMessageLike(value: unknown): value is Message;
|
|
59
|
+
declare function createMessageMeta(correlationId?: string): MessageMeta;
|
|
60
|
+
|
|
61
|
+
type UploadHandler = (file: File) => Promise<string>;
|
|
62
|
+
type EmailBuilderStatus = 'idle' | 'loading' | 'ready' | 'error';
|
|
63
|
+
interface EmailBuilderProps {
|
|
64
|
+
src: string;
|
|
65
|
+
initialHtml?: string;
|
|
66
|
+
config?: BuilderConfig;
|
|
67
|
+
className?: string;
|
|
68
|
+
style?: CSSProperties;
|
|
69
|
+
iframeTitle?: string;
|
|
70
|
+
sandbox?: string;
|
|
71
|
+
onChange?: (html: string) => void;
|
|
72
|
+
onSave?: (html: string) => void;
|
|
73
|
+
onUpload?: UploadHandler;
|
|
74
|
+
onReady?: () => void;
|
|
75
|
+
onStatusChange?: (status: EmailBuilderStatus) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Optionally override the derived origin (defaults to src origin)
|
|
78
|
+
*/
|
|
79
|
+
allowedOrigin?: string;
|
|
80
|
+
}
|
|
81
|
+
interface EmailBuilderHandle {
|
|
82
|
+
reload: () => void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
declare const EmailBuilder: React.ForwardRefExoticComponent<EmailBuilderProps & React.RefAttributes<EmailBuilderHandle>>;
|
|
86
|
+
|
|
87
|
+
export { type BuilderConfig, type BuilderToHostMessage, type ChangePayload, EMAIL_BUILDER_PROTOCOL_VERSION, EmailBuilder, type EmailBuilderHandle, type EmailBuilderProps, type EmailBuilderStatus, type HostToBuilderMessage, type InitPayload, type Message, type MessageMeta, type MessageType, type SavePayload, type UploadHandler, type UploadPayload, type UploadSuccessPayload, createMessageMeta, isMessageLike };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{forwardRef as Z,useCallback as u,useEffect as _,useImperativeHandle as $,useMemo as ee,useRef as d,useState as W}from"react";var Q="1.0.0",X=["INIT","READY","CHANGE","SAVE","UPLOAD","UPLOAD_SUCCESS"];function O(r){if(typeof r!="object"||r===null)return!1;let s=r;if(typeof s.type!="string"||!X.includes(s.type))return!1;if("meta"in s&&s.meta!==void 0){let t=s.meta;if(t.id&&typeof t.id!="string"||t.correlationId&&typeof t.correlationId!="string"||t.version&&typeof t.version!="string"||t.sentAt&&typeof t.sentAt!="number")return!1}return!0}function k(r){return{id:typeof crypto!="undefined"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2),correlationId:r,version:Q,sentAt:Date.now()}}function C(r,s){if(s){let y=new URL(s);if(y.origin==="null")throw new Error("allowedOrigin must resolve to a valid origin");return y.origin}let t;try{t=new URL(r)}catch{throw new Error("EmailBuilder `src` must be an absolute URL (e.g. https://example.com)")}if(!t.origin||t.origin==="null")throw new Error("EmailBuilder requires an absolute src URL with a valid origin");return t.origin}function L(r,s){let t=k(s);return{...r,meta:t}}function N(r,s,t){return r.origin!==s||!t||r.source!==t||!O(r.data)?null:r.data}function h(r){return JSON.stringify(r!=null?r:null)}import{jsx as v,jsxs as ae}from"react/jsx-runtime";var te="allow-scripts allow-same-origin allow-forms",re="<h1>Hello World</h1><p>Start building your email template.</p>",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},ne={border:"none",width:"100%",height:"100%"};function oe({src:r,initialHtml:s,config:t,className:y,style:F,iframeTitle:V="Email Builder",sandbox:Y=te,onChange:m,onSave:M,onUpload:U,onReady:E,onStatusChange:w,allowedOrigin:x},z){let S=d(null),a=d(null),c=d(!1),T=d("loading"),[G,K]=W("loading"),[q,j]=W(0),A=d([]),I=s!=null?s:re,b=d(h({html:I,config:t})),B=d({type:"INIT",payload:{html:I,config:t}}),p=ee(()=>C(r,x),[r,x]),i=u(e=>{T.current!==e&&(T.current=e,K(e),w==null||w(e))},[w]),g=u((e,n)=>{var l,f;let o=(f=(l=S.current)==null?void 0:l.contentWindow)!=null?f:a.current;if(o&&(a.current=o),!a.current||!c.current){A.current.push({message:e,correlationId:n});return}a.current.postMessage(L(e,n),p)},[p]),D=u(()=>{if(!c.current||!a.current)return;let e=[...A.current];A.current=[],e.forEach(({message:n,correlationId:o})=>{var l;(l=a.current)==null||l.postMessage(L(n,o),p)})},[p]),R=u(()=>{c.current=!0,i("ready"),E==null||E(),g(B.current),D()},[D,E,g,i]),H=u(async e=>{var n;if(e.type==="UPLOAD"){if(!U){console.warn("[EmailBuilderSDK] Upload requested but no onUpload handler is configured.");return}try{i("loading");let o=await U(e.payload.file);g({type:"UPLOAD_SUCCESS",payload:{url:o}},(n=e.meta)==null?void 0:n.id)}catch(o){i("error"),console.error("[EmailBuilderSDK] Upload handler failed",o)}finally{T.current!=="error"&&i("ready")}}},[U,g,i]),P=u(e=>{var l,f;let n=(f=(l=S.current)==null?void 0:l.contentWindow)!=null?f:a.current,o=N(e,p,n);if(o)switch(e.source&&e.source!==a.current&&(a.current=e.source),o.type){case"READY":R();break;case"CHANGE":m==null||m(o.payload.html);break;case"SAVE":M==null||M(o.payload.html);break;case"UPLOAD":H(o);break;default:break}},[p,R,H,m,M]);_(()=>{if(typeof window!="undefined")return window.addEventListener("message",P),()=>{window.removeEventListener("message",P)}},[P]),_(()=>{let e={html:I,config:t},n=h(e);B.current={type:"INIT",payload:e},n!==b.current&&c.current&&g(B.current),b.current=n},[t,I,g]);let J=u(()=>{var e,n;a.current=(n=(e=S.current)==null?void 0:e.contentWindow)!=null?n:null,c.current=!1,i("loading")},[i]);return $(z,()=>({reload(){A.current=[],c.current=!1,a.current=null,i("loading"),j(e=>e+1)}}),[i]),ae("div",{className:y,style:{position:"relative",width:"100%",height:"100%",...F},children:[v("iframe",{ref:S,src:r,title:V,sandbox:Y,style:ne,loading:"lazy",allowFullScreen:!0,onLoad:J},q),G!=="ready"&&v("div",{style:se,children:"Connecting to builder\u2026"})]})}var ye=Z(oe);export{Q as EMAIL_BUILDER_PROTOCOL_VERSION,ye as EmailBuilder,k as createMessageMeta,O as isMessageLike};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/EmailBuilder.tsx","../src/protocol.ts","../src/utils.ts"],"sourcesContent":["import React, {\n CSSProperties,\n ForwardedRef,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { BuilderToHostMessage, HostToBuilderMessage } from './protocol';\nimport { buildEnvelope, deriveAllowedOrigin, sanitizeIncomingMessage, stableSignature } from './utils';\nimport type { EmailBuilderHandle, EmailBuilderProps, EmailBuilderStatus } from './types';\n\nconst DEFAULT_SANDBOX = 'allow-scripts allow-same-origin allow-forms';\nconst DEFAULT_INITIAL_HTML = '<h1>Hello World</h1><p>Start building your email template.</p>';\n\ntype PendingMessage = {\n message: HostToBuilderMessage;\n correlationId?: string;\n};\n\nconst overlayStyle: CSSProperties = {\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '0.875rem',\n fontWeight: 500,\n background: 'linear-gradient(135deg, rgba(9,9,9,0.65), rgba(33,33,33,0.85))',\n color: '#fff',\n zIndex: 2,\n};\n\nconst iframeStyle: CSSProperties = {\n border: 'none',\n width: '100%',\n height: '100%',\n};\n\nfunction EmailBuilderInner(\n {\n src,\n initialHtml,\n config,\n className,\n style,\n iframeTitle = 'Email Builder',\n sandbox = DEFAULT_SANDBOX,\n onChange,\n onSave,\n onUpload,\n onReady,\n onStatusChange,\n allowedOrigin,\n }: EmailBuilderProps,\n ref: ForwardedRef<EmailBuilderHandle>\n) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const builderWindowRef = useRef<Window | null>(null);\n const readyRef = useRef(false);\n const statusRef = useRef<EmailBuilderStatus>('loading');\n const [status, setStatus] = useState<EmailBuilderStatus>('loading');\n const [reloadKey, setReloadKey] = useState(0);\n const queueRef = useRef<PendingMessage[]>([]);\n const effectiveInitialHtml = initialHtml ?? DEFAULT_INITIAL_HTML;\n const initSignatureRef = useRef(stableSignature({ html: effectiveInitialHtml, config }));\n const latestInitRef = useRef<HostToBuilderMessage>({\n type: 'INIT',\n payload: { html: effectiveInitialHtml, config },\n });\n\n const expectedOrigin = useMemo(() => deriveAllowedOrigin(src, allowedOrigin), [src, allowedOrigin]);\n\n const 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), expectedOrigin);\n },\n [expectedOrigin]\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(buildEnvelope(message, correlationId), expectedOrigin);\n });\n }, [expectedOrigin]);\n\n const handleReadyMessage = useCallback(() => {\n readyRef.current = true;\n setStatusSafely('ready');\n onReady?.();\n postMessage(latestInitRef.current);\n flushQueue();\n }, [flushQueue, onReady, postMessage, setStatusSafely]);\n\n const handleUpload = useCallback(\n async (eventMessage: BuilderToHostMessage) => {\n if (eventMessage.type !== 'UPLOAD') {\n return;\n }\n if (!onUpload) {\n console.warn('[EmailBuilderSDK] Upload requested but no onUpload handler is configured.');\n return;\n }\n try {\n setStatusSafely('loading');\n const url = await onUpload(eventMessage.payload.file);\n postMessage({ type: 'UPLOAD_SUCCESS', payload: { url } }, eventMessage.meta?.id);\n } catch (error) {\n setStatusSafely('error');\n console.error('[EmailBuilderSDK] Upload handler failed', error);\n } finally {\n if (statusRef.current !== 'error') {\n setStatusSafely('ready');\n }\n }\n },\n [onUpload, postMessage, setStatusSafely]\n );\n\n const handleMessage = useCallback(\n (event: MessageEvent) => {\n const iframeWindow = iframeRef.current?.contentWindow ?? builderWindowRef.current;\n const message = sanitizeIncomingMessage(event, expectedOrigin, iframeWindow);\n if (!message) {\n return;\n }\n\n if (event.source && event.source !== builderWindowRef.current) {\n builderWindowRef.current = event.source as Window;\n }\n\n switch (message.type) {\n case 'READY':\n handleReadyMessage();\n break;\n case 'CHANGE':\n onChange?.(message.payload.html);\n break;\n case 'SAVE':\n onSave?.(message.payload.html);\n break;\n case 'UPLOAD':\n void handleUpload(message);\n break;\n default:\n break;\n }\n },\n [expectedOrigin, handleReadyMessage, handleUpload, onChange, onSave]\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n window.addEventListener('message', handleMessage);\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [handleMessage]);\n\n useEffect(() => {\n const nextPayload = { html: effectiveInitialHtml, config };\n const signature = stableSignature(nextPayload);\n latestInitRef.current = { type: 'INIT', payload: nextPayload };\n if (signature !== initSignatureRef.current && readyRef.current) {\n postMessage(latestInitRef.current);\n }\n initSignatureRef.current = signature;\n }, [config, effectiveInitialHtml, postMessage]);\n\n const handleIframeLoad = useCallback(() => {\n builderWindowRef.current = iframeRef.current?.contentWindow ?? null;\n readyRef.current = false;\n setStatusSafely('loading');\n }, [setStatusSafely]);\n\n useImperativeHandle(\n ref,\n () => ({\n reload() {\n queueRef.current = [];\n readyRef.current = false;\n builderWindowRef.current = null;\n setStatusSafely('loading');\n setReloadKey((key) => key + 1);\n },\n }),\n [setStatusSafely]\n );\n\n return (\n <div className={className} style={{ position: 'relative', width: '100%', height: '100%', ...style }}>\n <iframe\n key={reloadKey}\n ref={iframeRef}\n src={src}\n title={iframeTitle}\n sandbox={sandbox}\n style={iframeStyle}\n loading=\"lazy\"\n allowFullScreen\n onLoad={handleIframeLoad}\n />\n {status !== 'ready' && <div style={overlayStyle}>Connecting to builder…</div>}\n </div>\n );\n}\n\nexport const EmailBuilder = forwardRef(EmailBuilderInner);\n","export const EMAIL_BUILDER_PROTOCOL_VERSION = '1.0.0';\n\nexport type MessageType =\n | 'INIT'\n | 'READY'\n | 'CHANGE'\n | 'SAVE'\n | 'UPLOAD'\n | 'UPLOAD_SUCCESS';\n\nexport interface MessageMeta {\n id: string;\n correlationId?: string;\n version: string;\n sentAt: number;\n}\n\nexport type BuilderConfig = Record<string, unknown> | undefined;\n\nexport interface InitPayload {\n html: string;\n config?: BuilderConfig;\n}\n\nexport interface ChangePayload {\n html: string;\n}\n\nexport interface SavePayload {\n html: string;\n}\n\nexport interface UploadPayload {\n file: File;\n}\n\nexport interface UploadSuccessPayload {\n url: string;\n}\n\nexport type Message =\n | { type: 'INIT'; payload: InitPayload; meta?: MessageMeta }\n | { type: 'READY'; meta?: MessageMeta }\n | { type: 'CHANGE'; payload: ChangePayload; meta?: MessageMeta }\n | { type: 'SAVE'; payload: SavePayload; meta?: MessageMeta }\n | { type: 'UPLOAD'; payload: UploadPayload; meta?: MessageMeta }\n | { type: 'UPLOAD_SUCCESS'; payload: UploadSuccessPayload; meta?: MessageMeta };\n\nexport type BuilderToHostMessage = Extract<\n Message,\n { type: 'READY' | 'CHANGE' | 'SAVE' | 'UPLOAD' }\n>;\n\nexport type HostToBuilderMessage = Extract<\n Message,\n { type: 'INIT' | 'UPLOAD_SUCCESS' }\n>;\n\nconst VALID_TYPES: MessageType[] = ['INIT', 'READY', 'CHANGE', 'SAVE', 'UPLOAD', 'UPLOAD_SUCCESS'];\n\nexport function isMessageLike(value: unknown): value is Message {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const candidate = value as { type?: unknown; payload?: unknown; meta?: unknown };\n if (typeof candidate.type !== 'string' || !VALID_TYPES.includes(candidate.type as MessageType)) {\n return false;\n }\n\n if ('meta' in candidate && candidate.meta !== undefined) {\n const meta = candidate.meta as Partial<MessageMeta>;\n if (\n (meta.id && typeof meta.id !== 'string') ||\n (meta.correlationId && typeof meta.correlationId !== 'string') ||\n (meta.version && typeof meta.version !== 'string') ||\n (meta.sentAt && typeof meta.sentAt !== 'number')\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function createMessageMeta(correlationId?: string): MessageMeta {\n const id = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : Math.random().toString(36).slice(2);\n return {\n id,\n correlationId,\n version: EMAIL_BUILDER_PROTOCOL_VERSION,\n sentAt: Date.now(),\n };\n}\n","import type { BuilderToHostMessage, HostToBuilderMessage, MessageMeta } from './protocol';\nimport { createMessageMeta, isMessageLike } from './protocol';\n\nexport function deriveAllowedOrigin(src: string, override?: string): string {\n if (override) {\n const parsed = new URL(override);\n if (parsed.origin === 'null') {\n throw new Error('allowedOrigin must resolve to a valid origin');\n }\n return parsed.origin;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(src);\n } catch {\n throw new Error('EmailBuilder `src` must be an absolute URL (e.g. https://example.com)');\n }\n if (!parsed.origin || parsed.origin === 'null') {\n throw new Error('EmailBuilder requires an absolute src URL with a valid origin');\n }\n return parsed.origin;\n}\n\nexport function buildEnvelope<T extends HostToBuilderMessage>(message: T, correlationId?: string): T {\n const meta: MessageMeta = createMessageMeta(correlationId);\n return { ...message, meta } as T;\n}\n\nexport function sanitizeIncomingMessage(\n event: MessageEvent,\n allowedOrigin: string,\n iframeWindow: Window | null\n): BuilderToHostMessage | null {\n if (event.origin !== allowedOrigin) {\n return null;\n }\n\n if (!iframeWindow || event.source !== iframeWindow) {\n return null;\n }\n\n if (!isMessageLike(event.data)) {\n return null;\n }\n\n return event.data as BuilderToHostMessage;\n}\n\nexport function stableSignature(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useMemo","useRef","useState","EMAIL_BUILDER_PROTOCOL_VERSION","VALID_TYPES","isMessageLike","value","candidate","meta","createMessageMeta","correlationId","deriveAllowedOrigin","src","override","parsed","buildEnvelope","message","correlationId","meta","createMessageMeta","sanitizeIncomingMessage","event","allowedOrigin","iframeWindow","isMessageLike","stableSignature","value","jsx","jsxs","DEFAULT_SANDBOX","DEFAULT_INITIAL_HTML","overlayStyle","iframeStyle","EmailBuilderInner","src","initialHtml","config","className","style","iframeTitle","sandbox","onChange","onSave","onUpload","onReady","onStatusChange","allowedOrigin","ref","iframeRef","useRef","builderWindowRef","readyRef","statusRef","status","setStatus","useState","reloadKey","setReloadKey","queueRef","effectiveInitialHtml","initSignatureRef","stableSignature","latestInitRef","expectedOrigin","useMemo","deriveAllowedOrigin","setStatusSafely","useCallback","next","postMessage","message","correlationId","_a","_b","target","buildEnvelope","flushQueue","pending","handleReadyMessage","handleUpload","eventMessage","url","error","handleMessage","event","iframeWindow","sanitizeIncomingMessage","useEffect","nextPayload","signature","handleIframeLoad","useImperativeHandle","key","EmailBuilder","forwardRef"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alihaiderrana/email-builder-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React iframe SDK for embedding the Circles email template builder",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.mjs",
|
|
17
|
+
"require": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"dev": "tsup --watch",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "npm run clean && npm run build && npm run typecheck"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"email",
|
|
30
|
+
"builder",
|
|
31
|
+
"react",
|
|
32
|
+
"sdk",
|
|
33
|
+
"iframe",
|
|
34
|
+
"template"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": ">=18.2.0",
|
|
41
|
+
"react-dom": ">=18.2.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/react": "^18.3.12",
|
|
45
|
+
"@types/react-dom": "^18.3.5",
|
|
46
|
+
"tsup": "^8.0.1",
|
|
47
|
+
"typescript": "^5.6.3"
|
|
48
|
+
}
|
|
49
|
+
}
|