forgeframe 0.0.1
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/LICENSE +21 -0
- package/README.md +868 -0
- package/dist/communication/bridge.d.ts +167 -0
- package/dist/communication/index.d.ts +12 -0
- package/dist/communication/messenger.d.ts +142 -0
- package/dist/communication/protocol.d.ts +75 -0
- package/dist/constants.d.ts +161 -0
- package/dist/core/component.d.ts +137 -0
- package/dist/core/consumer.d.ts +263 -0
- package/dist/core/host.d.ts +249 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/drivers/index.d.ts +18 -0
- package/dist/drivers/react.d.ts +224 -0
- package/dist/events/emitter.d.ts +150 -0
- package/dist/forgeframe.js +3179 -0
- package/dist/forgeframe.umd.cjs +5 -0
- package/dist/index.d.ts +230 -0
- package/dist/props/definitions.d.ts +63 -0
- package/dist/props/index.d.ts +13 -0
- package/dist/props/normalize.d.ts +59 -0
- package/dist/props/prop.d.ts +636 -0
- package/dist/props/schema.d.ts +196 -0
- package/dist/props/serialize.d.ts +60 -0
- package/dist/render/iframe.d.ts +213 -0
- package/dist/render/index.d.ts +38 -0
- package/dist/render/popup.d.ts +215 -0
- package/dist/render/templates.d.ts +202 -0
- package/dist/types.d.ts +1008 -0
- package/dist/utils/cleanup.d.ts +122 -0
- package/dist/utils/dimension.d.ts +50 -0
- package/dist/utils/index.d.ts +37 -0
- package/dist/utils/promise.d.ts +155 -0
- package/dist/utils/uid.d.ts +60 -0
- package/dist/window/helpers.d.ts +316 -0
- package/dist/window/index.d.ts +13 -0
- package/dist/window/name-payload.d.ts +188 -0
- package/dist/window/proxy.d.ts +168 -0
- package/package.json +47 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
(function(u,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(u=typeof globalThis<"u"?globalThis:u||self,p(u.ForgeFrame={}))})(this,(function(u){"use strict";const p={IFRAME:"iframe",POPUP:"popup"},m={RENDER:"render",RENDERED:"rendered",PRERENDER:"prerender",PRERENDERED:"prerendered",DISPLAY:"display",ERROR:"error",CLOSE:"close",DESTROY:"destroy",PROPS:"props",RESIZE:"resize",FOCUS:"focus"},O={JSON:"json",BASE64:"base64",DOTIFY:"dotify"},D={REQUEST:"request",RESPONSE:"response"},h={INIT:"forgeframe_init",PROPS:"forgeframe_props",CLOSE:"forgeframe_close",RESIZE:"forgeframe_resize",FOCUS:"forgeframe_focus",SHOW:"forgeframe_show",HIDE:"forgeframe_hide",ERROR:"forgeframe_error",EXPORT:"forgeframe_export",CALL:"forgeframe_call",CONSUMER_EXPORT:"forgeframe_consumer_export",GET_SIBLINGS:"forgeframe_get_siblings"},N="__forgeframe__",j="0.0.1";class re{listeners=new Map;on(e,n){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(n),()=>this.off(e,n)}once(e,n){const s=i=>(this.off(e,s),n(i));return this.on(e,s)}emit(e,n){const s=this.listeners.get(e);if(s)for(const i of s)try{const r=i(n);r&&typeof r=="object"&&"catch"in r&&typeof r.catch=="function"&&r.catch(o=>{console.error(`Error in async event handler for "${e}":`,o)})}catch(r){console.error(`Error in event handler for "${e}":`,r)}}off(e,n){if(!n){this.listeners.delete(e);return}const s=this.listeners.get(e);s&&(s.delete(n),s.size===0&&this.listeners.delete(e))}removeAllListeners(){this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function $e(){const t=Date.now().toString(36),e=Math.random().toString(36).slice(2,11);return`${t}_${e}`}function B(){return Math.random().toString(36).slice(2,11)}class Le{tasks=[];cleaned=!1;register(e){if(this.cleaned){try{e()}catch(n){console.error("Error in cleanup task:",n)}return}this.tasks.push(e)}async cleanup(){if(this.cleaned)return;this.cleaned=!0;const e=this.tasks.reverse();this.tasks=[];for(const n of e)try{await n()}catch(s){console.error("Error in cleanup task:",s)}}isCleaned(){return this.cleaned}reset(){this.tasks=[],this.cleaned=!1}}function oe(){let t,e;return{promise:new Promise((s,i)=>{t=s,e=i}),resolve:t,reject:e}}function Ae(t,e,n="Operation timed out"){return new Promise((s,i)=>{const r=setTimeout(()=>{i(new Error(`${n} (${e}ms)`))},e);t.then(o=>{clearTimeout(r),s(o)}).catch(o=>{clearTimeout(r),i(o)})})}const V="forgeframe:";function J(t){return V+JSON.stringify(t)}function He(t){if(typeof t!="string"||!t.startsWith(V))return null;try{const e=t.slice(V.length),n=JSON.parse(e);return!n.id||!n.type||!n.name||!n.source?null:n}catch{return null}}function ae(t,e,n,s){return{id:t,type:D.REQUEST,name:e,data:n,source:s}}function Me(t,e,n,s){return{id:t,type:D.RESPONSE,name:"response",data:e,source:n,error:s?{message:s.message,stack:s.stack}:void 0}}class ce{constructor(e,n=window,s=window.location.origin,i){this.uid=e,this.win=n,this.domain=s,this.allowedOrigins.add(s),i&&this.addTrustedDomain(i),this.setupListener()}pending=new Map;handlers=new Map;listener=null;destroyed=!1;allowedOrigins=new Set;allowedOriginPatterns=[];addTrustedDomain(e){if(Array.isArray(e))for(const n of e)this.allowedOrigins.add(n);else e instanceof RegExp?this.allowedOriginPatterns.push(e):this.allowedOrigins.add(e)}isOriginTrusted(e){if(this.allowedOrigins.has(e))return!0;for(const n of this.allowedOriginPatterns)if(n.test(e))return!0;return!1}async send(e,n,s,i,r=1e4){if(this.destroyed)throw new Error("Messenger has been destroyed");const o=B(),a=ae(o,s,i,{uid:this.uid,domain:this.domain}),c=oe(),l=setTimeout(()=>{this.pending.delete(o),c.reject(new Error(`Message "${s}" timed out after ${r}ms`))},r);this.pending.set(o,{deferred:c,timeout:l});try{e.postMessage(J(a),n)}catch(d){throw this.pending.delete(o),clearTimeout(l),d}return c.promise}post(e,n,s,i){if(this.destroyed)throw new Error("Messenger has been destroyed");const r=B(),o=ae(r,s,i,{uid:this.uid,domain:this.domain});e.postMessage(J(o),n)}on(e,n){return this.handlers.set(e,n),()=>this.handlers.delete(e)}setupListener(){this.listener=e=>{if(e.source===this.win||!this.isOriginTrusted(e.origin))return;const n=He(e.data);n&&this.handleMessage(n,e.source,e.origin)},this.win.addEventListener("message",this.listener)}async handleMessage(e,n,s){if(e.type===D.RESPONSE){const i=this.pending.get(e.id);if(i)if(this.pending.delete(e.id),clearTimeout(i.timeout),e.error){const r=new Error(e.error.message);r.stack=e.error.stack,i.deferred.reject(r)}else i.deferred.resolve(e.data);return}if(e.type===D.REQUEST){const i=this.handlers.get(e.name);if(!i)return;let r,o;try{r=await i(e.data,e.source)}catch(c){o=c instanceof Error?c:new Error(String(c))}const a=Me(e.id,r,{uid:this.uid,domain:this.domain},o);try{n.postMessage(J(a),s)}catch{}}}destroy(){if(!this.destroyed){this.destroyed=!0,this.listener&&(this.win.removeEventListener("message",this.listener),this.listener=null);for(const e of this.pending.values())clearTimeout(e.timeout),e.deferred.reject(new Error("Messenger destroyed"));this.pending.clear(),this.handlers.clear()}}isDestroyed(){return this.destroyed}}const le=500;class q{constructor(e){this.messenger=e,this.setupCallHandler()}localFunctions=new Map;remoteFunctions=new Map;currentBatchIds=new Set;serialize(e,n){if(this.localFunctions.size>=le){const i=this.localFunctions.keys().next().value;i&&this.localFunctions.delete(i)}const s=B();return this.localFunctions.set(s,e),this.currentBatchIds.add(s),{__type__:"function",__id__:s,__name__:n||e.name||"anonymous"}}deserialize(e,n,s){const i=`${e.__id__}`,r=this.remoteFunctions.get(i);if(r)return r;if(this.remoteFunctions.size>=le){const a=this.remoteFunctions.keys().next().value;a&&this.remoteFunctions.delete(a)}const o=async(...a)=>this.messenger.send(n,s,h.CALL,{id:e.__id__,args:a});return Object.defineProperty(o,"name",{value:e.__name__,configurable:!0}),this.remoteFunctions.set(i,o),o}static isFunctionRef(e){return typeof e=="object"&&e!==null&&e.__type__==="function"&&typeof e.__id__=="string"}setupCallHandler(){this.messenger.on(h.CALL,async({id:e,args:n})=>{const s=this.localFunctions.get(e);if(!s)throw new Error(`Function with id "${e}" not found`);return s(...n)})}removeLocal(e){this.localFunctions.delete(e)}startBatch(){this.currentBatchIds.clear()}finishBatch(e=!1){if(e){this.currentBatchIds.clear();return}for(const n of this.localFunctions.keys())this.currentBatchIds.has(n)||this.localFunctions.delete(n);this.currentBatchIds.clear()}clearRemote(){this.remoteFunctions.clear()}get localFunctionCount(){return this.localFunctions.size}get remoteFunctionCount(){return this.remoteFunctions.size}destroy(){this.localFunctions.clear(),this.remoteFunctions.clear(),this.currentBatchIds.clear()}}function X(t,e,n=new WeakSet){if(typeof t=="function")return e.serialize(t);if(Array.isArray(t)){if(n.has(t))throw new Error("Circular reference detected in props - arrays cannot contain circular references");return n.add(t),t.map(s=>X(s,e,n))}if(typeof t=="object"&&t!==null){if(n.has(t))throw new Error("Circular reference detected in props - objects cannot contain circular references");n.add(t);const s={};for(const[i,r]of Object.entries(t))s[i]=X(r,e,n);return s}return t}function Z(t,e,n,s,i=new WeakSet){if(q.isFunctionRef(t))return e.deserialize(t,n,s);if(Array.isArray(t)){if(i.has(t))throw new Error("Circular reference detected in serialized props");return i.add(t),t.map(r=>Z(r,e,n,s,i))}if(typeof t=="object"&&t!==null){if(i.has(t))throw new Error("Circular reference detected in serialized props");i.add(t);const r={};for(const[o,a]of Object.entries(t))r[o]=Z(a,e,n,s,i);return r}return t}function Y(t=window){try{return t.location.origin}catch{return""}}function ue(t,e=window){try{return t.location.origin===e.location.origin}catch{return!1}}function he(t,e){return typeof t=="string"?t==="*"?!0:t===e:t instanceof RegExp?t.test(e):Array.isArray(t)?t.some(n=>he(n,e)):!1}function de(t){if(!t)return!0;try{return t.closed}catch{return!0}}function We(t=window){try{return t.opener}catch{return null}}function ze(t=window){try{const e=t.parent;return e&&e!==t?e:null}catch{return null}}function Ue(t=window){try{return t.parent!==t}catch{return!0}}function je(t=window){try{return t.opener!==null&&t.opener!==void 0}catch{return!1}}const fe=32*1024;function Be(t){const e=Ve(t);return`${N}${e}`}function pe(t){if(!t||!t.startsWith(N))return null;const e=t.slice(N.length);return Je(e)}function G(t=window){try{return t.name.startsWith(N)}catch{return!1}}function K(t,e=window){return pe(e.name)?.tag===t}function Ve(t){try{const e=JSON.stringify(t),n=btoa(encodeURIComponent(e)),s=new Blob([n]).size;if(s>fe)throw new Error(`Payload size (${Math.round(s/1024)}KB) exceeds maximum allowed size (${fe/1024}KB). Consider reducing the amount of data passed via props.`);return n}catch(e){throw e instanceof Error&&e.message.includes("Payload size")?e:new Error(`Failed to encode payload: ${e}`)}}function Je(t){try{const e=decodeURIComponent(atob(t));return JSON.parse(e)}catch{return null}}function qe(t){return{uid:t.uid,tag:t.tag,version:j,context:t.context,consumerDomain:t.consumerDomain,props:t.props,exports:t.exports,children:t.children}}function Xe(t=window){return pe(t.name)}const me=100,y=new Map;function Ze(){const t=[];for(const[e,n]of y.entries())de(n)&&t.push(e);for(const e of t)y.delete(e)}function Ye(t,e){if(y.size>=me&&Ze(),y.size>=me){const n=y.keys().next().value;n&&y.delete(n)}y.set(t,e)}function Ge(t){y.delete(t)}class g{_optional=!1;_nullable=!1;_default;"~standard"={version:1,vendor:"forgeframe",validate:e=>e===null?this._nullable?{value:null}:{issues:[{message:"Expected a value, got null"}]}:e===void 0?this._default!==void 0?{value:typeof this._default=="function"?this._default():this._default}:this._optional?{value:void 0}:{issues:[{message:"Required"}]}:this._validate(e)};optional(){const e=this._clone();return e._optional=!0,e}nullable(){const e=this._clone();return e._nullable=!0,e}default(e){const n=this._clone();return n._default=e,n}}class T extends g{_minLength;_maxLength;_pattern;_patternMessage;_trim=!1;_validate(e){if(typeof e!="string")return{issues:[{message:`Expected string, got ${typeof e}`}]};const n=this._trim?e.trim():e;return this._minLength!==void 0&&n.length<this._minLength?{issues:[{message:`String must be at least ${this._minLength} characters`}]}:this._maxLength!==void 0&&n.length>this._maxLength?{issues:[{message:`String must be at most ${this._maxLength} characters`}]}:this._pattern&&!this._pattern.test(n)?{issues:[{message:this._patternMessage||`String must match pattern ${this._pattern}`}]}:{value:n}}_clone(){const e=new T;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e._minLength=this._minLength,e._maxLength=this._maxLength,e._pattern=this._pattern,e._patternMessage=this._patternMessage,e._trim=this._trim,e}min(e){const n=this._clone();return n._minLength=e,n}max(e){const n=this._clone();return n._maxLength=e,n}length(e){const n=this._clone();return n._minLength=e,n._maxLength=e,n}pattern(e,n){const s=this._clone();return s._pattern=e,s._patternMessage=n,s}email(){return this.pattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/,"Invalid email address")}url(){return this.pattern(/^https?:\/\/.+/,"Invalid URL")}uuid(){return this.pattern(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,"Invalid UUID")}trim(){const e=this._clone();return e._trim=!0,e}nonempty(){const e=this._clone();return e._minLength=1,e}}class F extends g{_min;_max;_int=!1;_validate(e){return typeof e!="number"||Number.isNaN(e)?{issues:[{message:`Expected number, got ${typeof e}`}]}:this._int&&!Number.isInteger(e)?{issues:[{message:"Expected integer"}]}:this._min!==void 0&&e<this._min?{issues:[{message:`Number must be >= ${this._min}`}]}:this._max!==void 0&&e>this._max?{issues:[{message:`Number must be <= ${this._max}`}]}:{value:e}}_clone(){const e=new F;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e._min=this._min,e._max=this._max,e._int=this._int,e}min(e){const n=this._clone();return n._min=e,n}max(e){const n=this._clone();return n._max=e,n}int(){const e=this._clone();return e._int=!0,e}positive(){const e=this._clone();return e._min=Number.MIN_VALUE,e}nonnegative(){const e=this._clone();return e._min=0,e}negative(){const e=this._clone();return e._max=-Number.MIN_VALUE,e}}class k extends g{_validate(e){return typeof e!="boolean"?{issues:[{message:`Expected boolean, got ${typeof e}`}]}:{value:e}}_clone(){const e=new k;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class $ extends g{_validate(e){return typeof e!="function"?{issues:[{message:`Expected function, got ${typeof e}`}]}:{value:e}}_clone(){const e=new $;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class C extends g{_itemSchema;_minLength;_maxLength;_validate(e){if(!Array.isArray(e))return{issues:[{message:`Expected array, got ${typeof e}`}]};if(this._minLength!==void 0&&e.length<this._minLength)return{issues:[{message:`Array must have at least ${this._minLength} items`}]};if(this._maxLength!==void 0&&e.length>this._maxLength)return{issues:[{message:`Array must have at most ${this._maxLength} items`}]};if(this._itemSchema){const n=[];for(let s=0;s<e.length;s++){const i=this._itemSchema["~standard"].validate(e[s]);if(i instanceof Promise)throw new Error("Async schema validation is not supported. Use synchronous schemas.");if(i.issues)return{issues:i.issues.map(r=>({...r,path:[s,...r.path||[]]}))};n.push(i.value)}return{value:n}}return{value:e}}_clone(){const e=new C;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e._itemSchema=this._itemSchema,e._minLength=this._minLength,e._maxLength=this._maxLength,e}of(e){const n=new C;return n._optional=this._optional,n._nullable=this._nullable,n._itemSchema=e,n._minLength=this._minLength,n._maxLength=this._maxLength,n}min(e){const n=this._clone();return n._minLength=e,n}max(e){const n=this._clone();return n._maxLength=e,n}nonempty(){return this.min(1)}}class v extends g{_shape;_strict=!1;_validate(e){if(typeof e!="object"||e===null||Array.isArray(e))return{issues:[{message:`Expected object, got ${Array.isArray(e)?"array":typeof e}`}]};const n=e,s={};if(this._shape){if(this._strict){const i=new Set(Object.keys(this._shape));for(const r of Object.keys(n))if(!i.has(r))return{issues:[{message:`Unknown key: ${r}`,path:[r]}]}}for(const[i,r]of Object.entries(this._shape)){const o=r["~standard"].validate(n[i]);if(o instanceof Promise)throw new Error("Async schema validation is not supported. Use synchronous schemas.");if(o.issues)return{issues:o.issues.map(a=>({...a,path:[i,...a.path||[]]}))};s[i]=o.value}if(!this._strict)for(const i of Object.keys(n))i in this._shape||(s[i]=n[i]);return{value:s}}return{value:e}}_clone(){const e=new v;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e._shape=this._shape,e._strict=this._strict,e}shape(e){const n=new v;return n._optional=this._optional,n._nullable=this._nullable,n._shape=e,n._strict=this._strict,n}strict(){const e=this._clone();return e._strict=!0,e}}class L extends g{_value;constructor(e){super(),this._value=e}_validate(e){return e!==this._value?{issues:[{message:`Expected ${JSON.stringify(this._value)}, got ${JSON.stringify(e)}`}]}:{value:e}}_clone(){const e=new L(this._value);return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class A extends g{_values;constructor(e){super(),this._values=e}_validate(e){return this._values.includes(e)?{value:e}:{issues:[{message:`Expected one of [${this._values.map(n=>JSON.stringify(n)).join(", ")}], got ${JSON.stringify(e)}`}]}}_clone(){const e=new A(this._values);return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class H extends g{constructor(){super(),this._nullable=!0}_validate(e){return{value:e}}_clone(){const e=new H;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}const f={string:()=>new T,number:()=>new F,boolean:()=>new k,function:()=>new $,array:()=>new C,object:()=>new v,literal:t=>new L(t),enum:t=>new A(t),any:()=>new H},P={uid:{schema:f.string().optional(),sendToHost:!0},tag:{schema:f.string().optional(),sendToHost:!0},dimensions:{schema:f.object().default(()=>({width:"100%",height:"100%"})),sendToHost:!1},timeout:{schema:f.number().default(1e4),sendToHost:!1},cspNonce:{schema:f.string().optional(),sendToHost:!0},onDisplay:{schema:f.function().optional(),sendToHost:!1},onRendered:{schema:f.function().optional(),sendToHost:!1},onRender:{schema:f.function().optional(),sendToHost:!1},onPrerendered:{schema:f.function().optional(),sendToHost:!1},onPrerender:{schema:f.function().optional(),sendToHost:!1},onClose:{schema:f.function().optional(),sendToHost:!1},onDestroy:{schema:f.function().optional(),sendToHost:!1},onResize:{schema:f.function().optional(),sendToHost:!1},onFocus:{schema:f.function().optional(),sendToHost:!1},onError:{schema:f.function().optional(),sendToHost:!1},onProps:{schema:f.function().optional(),sendToHost:!1}};function _(t){return typeof t=="object"&&t!==null&&"~standard"in t&&typeof t["~standard"]=="object"&&t["~standard"]!==null&&t["~standard"].version===1&&typeof t["~standard"].validate=="function"}function Ke(t,e,n){const s=t["~standard"].validate(e);if(s instanceof Promise)throw new Error(`Prop "${n}" uses an async schema. ForgeFrame only supports synchronous schema validation. Please use a synchronous schema or remove async operations (like database lookups) from your schema definition.`);if(s.issues){const i=s.issues.map(r=>`${Qe(r.path,n)}: ${r.message}`);throw new Error(`Validation failed: ${i.join("; ")}`)}return s.value}function Qe(t,e){if(!t||t.length===0)return e;const n=t.map(s=>typeof s=="object"&&s!==null&&"key"in s?String(s.key):String(s));return`${e}.${n.join(".")}`}function ge(t,e,n){const s={...P,...e},i={};for(const[r,o]of Object.entries(s)){const c=_(o)?{schema:o}:o;let l;const d=c.alias,w=r in t,E=d&&d in t;if(w)l=t[r];else if(E)l=t[d];else if(c.value)l=c.value(n);else if(c.default!==void 0)l=typeof c.default=="function"?c.default(n):c.default;else if(c.schema&&_(c.schema)){const S=c.schema["~standard"].validate(void 0);!(S instanceof Promise)&&!S.issues&&(l=S.value)}l!==void 0&&c.decorate&&(l=c.decorate({value:l,props:i})),i[r]=l}return i}function et(t,e){const n={...P,...e};for(const[s,i]of Object.entries(n)){const r=_(i),o=r?{schema:i}:i;let a=t[s];if(o.required&&a===void 0)throw new Error(`Prop "${s}" is required but was not provided`);if(o.schema&&_(o.schema))(a!==void 0||r)&&(a=Ke(o.schema,a,s),t[s]=a);else if(a===void 0)continue;o.validate&&o.validate({value:a,props:t})}}function ye(t,e,n,s){const i={...P,...e},r={};for(const[o,a]of Object.entries(i)){const l=_(a)?{schema:a}:a,d=t[o];if(l.sendToHost===!1||l.sameDomain&&!s)continue;if(l.trustedDomains){const E=l.trustedDomains;if(!he(E,n))continue}let w=d;l.hostDecorate&&d!==void 0&&(w=l.hostDecorate({value:d,props:t})),r[o]=w}return r}function tt(t,e){const n=new URLSearchParams,s={...P,...e};for(const[i,r]of Object.entries(s)){const a=_(r)?{schema:r}:r,c=t[i];if(c===void 0||typeof c=="function"||!a.queryParam)continue;const l=typeof a.queryParam=="string"?a.queryParam:i;let d;typeof a.queryParam=="function"?d=a.queryParam({value:c}):typeof c=="object"?d=JSON.stringify(c):d=String(c),n.set(l,d)}return n}function _e(t,e=""){const n=[];for(const[s,i]of Object.entries(t)){const r=e?`${e}.${s}`:s;if(i!==null&&typeof i=="object"&&!Array.isArray(i))n.push(_e(i,r));else{const o=encodeURIComponent(JSON.stringify(i));n.push(`${r}=${o}`)}}return n.filter(Boolean).join("&")}function nt(t){const e={};if(!t)return e;const n=t.split("&");for(const s of n){const[i,r]=s.split("=");if(!i||r===void 0)continue;let o;try{o=JSON.parse(decodeURIComponent(r))}catch{o=decodeURIComponent(r)}const a=i.split(".");let c=e;for(let l=0;l<a.length-1;l++){const d=a[l];(!(d in c)||typeof c[d]!="object")&&(c[d]={}),c=c[d]}c[a[a.length-1]]=o}return e}function st(t){return typeof t=="object"&&t!==null&&t.__type__==="dotify"&&typeof t.__value__=="string"}function we(t,e,n){const s={...P,...e},i={};for(const[r,o]of Object.entries(t)){if(o===void 0)continue;const a=s[r];i[r]=it(o,a,n)}return i}function it(t,e,n){if(typeof t=="function")return n.serialize(t);const s=e?.serialization??O.JSON;if(s===O.BASE64&&typeof t=="object"){const i=JSON.stringify(t);return{__type__:"base64",__value__:btoa(encodeURIComponent(i))}}return s===O.DOTIFY&&typeof t=="object"&&t!==null&&!Array.isArray(t)?{__type__:"dotify",__value__:_e(t)}:X(t,n)}function Ee(t,e,n,s,i,r){const o={...P,...e},a={};for(const[c,l]of Object.entries(t)){const d=o[c];a[c]=rt(l,d,n,s,i,r)}return a}function rt(t,e,n,s,i,r){if(ot(t))try{const o=decodeURIComponent(atob(t.__value__));return JSON.parse(o)}catch{return t}if(st(t))try{return nt(t.__value__)}catch{return t}return Z(t,s,i,r)}function ot(t){return typeof t=="object"&&t!==null&&t.__type__==="base64"&&typeof t.__value__=="string"}function R(t,e="100%"){return t===void 0?e:typeof t=="number"?`${t}px`:t}function M(t,e){if(t===void 0)return e;if(typeof t=="number")return t;const n=parseInt(t,10);return isNaN(n)?e:n}function at(t){try{t.src="about:blank",t.parentNode?.removeChild(t)}catch{}}function ct(t,e){ht(t,e)}function lt(t){t.style.display="",t.style.visibility="visible"}function be(t){t.style.display="none",t.style.visibility="hidden"}function ut(t){try{t.focus(),t.contentWindow?.focus()}catch{}}function ht(t,e){e.width!==void 0&&(t.style.width=R(e.width)),e.height!==void 0&&(t.style.height=R(e.height))}class Q extends Error{constructor(e="Popup blocked by browser"){super(e),this.name="PopupOpenError"}}function dt(t){const{url:e,name:n,dimensions:s}=t,i=M(s.width,500),r=M(s.height,500),o=Math.floor(window.screenX+(window.outerWidth-i)/2),a=Math.floor(window.screenY+(window.outerHeight-r)/2),c=[`width=${i}`,`height=${r}`,`left=${o}`,`top=${a}`,"menubar=no","toolbar=no","location=yes","status=no","resizable=yes","scrollbars=yes"].join(","),l=window.open(e,n,c);if(!l||mt(l))throw new Q;return l}function ft(t){try{t.closed||t.close()}catch{}}function pt(t){try{t.closed||t.focus()}catch{}}function mt(t){if(!t)return!0;try{return!!(t.closed||t.innerHeight===0||t.innerWidth===0)}catch{return!0}}function gt(t,e,n={}){const{initialInterval:s=100,maxInterval:i=2e3,multiplier:r=1.5}=n;let o=s,a,c=!1;const l=()=>{try{e()}catch(w){console.error("Error in popup close callback:",w)}},d=()=>{if(!c){try{if(t.closed){l();return}}catch{l();return}o=Math.min(o*r,i),a=setTimeout(d,o)}};return a=setTimeout(d,o),()=>{c=!0,clearTimeout(a)}}function yt(t,e){try{const n=M(e.width,t.outerWidth),s=M(e.height,t.outerHeight);t.resizeTo(n,s)}catch{}}function _t(t){const{doc:e,dimensions:n,uid:s,tag:i}=t,r=e.createElement("div");return r.id=`forgeframe-container-${s}`,r.setAttribute("data-forgeframe-tag",i),Object.assign(r.style,{display:"inline-block",position:"relative",width:R(n.width),height:R(n.height),overflow:"hidden"}),r}function wt(t){const{doc:e,dimensions:n,cspNonce:s}=t,i=e.createElement("div");Object.assign(i.style,{display:"flex",alignItems:"center",justifyContent:"center",width:R(n.width),height:R(n.height),backgroundColor:"#f5f5f5",position:"absolute",top:"0",left:"0",zIndex:"100"});const r=e.createElement("div");Object.assign(r.style,{width:"40px",height:"40px",border:"3px solid #e0e0e0",borderTopColor:"#3498db",borderRadius:"50%",animation:"forgeframe-spin 1s linear infinite"});const o=e.createElement("style");return s&&o.setAttribute("nonce",s),o.textContent=`
|
|
2
|
+
@keyframes forgeframe-spin {
|
|
3
|
+
to { transform: rotate(360deg); }
|
|
4
|
+
}
|
|
5
|
+
`,i.appendChild(o),i.appendChild(r),i}function Et(t,e=200){return new Promise(n=>{t.style.opacity="0",t.style.transition=`opacity ${e}ms ease-in`,t.offsetHeight,t.style.opacity="1",setTimeout(n,e)})}function bt(t,e=200){return new Promise(n=>{t.style.transition=`opacity ${e}ms ease-out`,t.style.opacity="0",setTimeout(n,e)})}async function Pt(t,e,n){e&&(await bt(e,150),e.remove()),n.style.display="",n.style.visibility="visible",n.style.opacity="0",await Et(n,150)}class ee{event;state={};exports;consumerExports;_uid;get uid(){return this._uid}options;props;context;messenger;bridge;cleanup;hostWindow=null;iframe=null;container=null;prerenderElement=null;initPromise=null;rendered=!1;destroyed=!1;constructor(e,n={}){this._uid=$e(),this.options=this.normalizeOptions(e),this.context=this.options.defaultContext,this.event=new re,this.cleanup=new Le;const s=this.buildTrustedDomains();this.messenger=new ce(this.uid,window,Y(),s),this.bridge=new q(this.messenger);const i=this.createPropContext();this.props=ge(n,this.options.props,i),this.setupMessageHandlers(),this.setupCleanup()}buildTrustedDomains(){const e=[],n=typeof this.options.url=="function"?this.options.url(this.props):this.options.url;try{const s=new URL(n);e.push(s.origin)}catch{}if(this.options.domain){if(typeof this.options.domain=="string")e.push(this.options.domain);else if(Array.isArray(this.options.domain))e.push(...this.options.domain);else if(this.options.domain instanceof RegExp)return this.options.domain}return e.length>0?e:void 0}async render(e,n){if(this.destroyed)throw new Error("Component has been destroyed");if(this.rendered)throw new Error("Component has already been rendered");this.context=n??this.options.defaultContext,this.checkEligibility(),et(this.props,this.options.props),this.container=this.resolveContainer(e),this.event.emit(m.PRERENDER),this.callPropCallback("onPrerender"),await this.prerender(),this.event.emit(m.PRERENDERED),this.callPropCallback("onPrerendered"),this.event.emit(m.RENDER),this.callPropCallback("onRender"),await this.open(),await this.waitForHost(),this.context===p.IFRAME&&this.iframe&&this.prerenderElement&&(await Pt(this.container,this.prerenderElement,this.iframe),this.prerenderElement=null),this.rendered=!0,this.event.emit(m.RENDERED),this.callPropCallback("onRendered"),this.event.emit(m.DISPLAY),this.callPropCallback("onDisplay")}async renderTo(e,n,s){return this.render(n,s)}async close(){this.destroyed||(this.event.emit(m.CLOSE),await this.destroy())}async focus(){this.context===p.IFRAME&&this.iframe?ut(this.iframe):this.context===p.POPUP&&this.hostWindow&&pt(this.hostWindow),this.event.emit(m.FOCUS),this.callPropCallback("onFocus")}async resize(e){this.context===p.IFRAME&&this.iframe?ct(this.iframe,e):this.context===p.POPUP&&this.hostWindow&&yt(this.hostWindow,e),this.event.emit(m.RESIZE,e),this.callPropCallback("onResize",e)}async show(){this.context===p.IFRAME&&this.iframe&<(this.iframe)}async hide(){this.context===p.IFRAME&&this.iframe&&be(this.iframe)}async updateProps(e){const n=this.createPropContext();if(this.props=ge({...this.props,...e},this.options.props,n),this.hostWindow&&!de(this.hostWindow)){const s=this.getHostDomain(),i=ye(this.props,this.options.props,s,ue(this.hostWindow)),r=we(i,this.options.props,this.bridge);await this.messenger.send(this.hostWindow,s,h.PROPS,r)}this.event.emit(m.PROPS,this.props),this.callPropCallback("onProps",this.props)}clone(){return new ee(this.options,this.props)}isEligible(){return this.options.eligible?this.options.eligible({props:this.props}).eligible:!0}normalizeOptions(e){return{...e,props:e.props??{},defaultContext:e.defaultContext??p.IFRAME,dimensions:typeof e.dimensions=="function"?e.dimensions(this.props):e.dimensions??{width:"100%",height:"100%"},timeout:e.timeout??1e4,children:e.children}}createPropContext(){return{props:this.props,state:this.state,close:()=>this.close(),focus:()=>this.focus(),onError:e=>this.handleError(e),container:this.container,uid:this.uid,tag:this.options.tag}}resolveContainer(e){if(!e)throw new Error("Container is required for rendering");if(typeof e=="string"){const n=document.querySelector(e);if(!n)throw new Error(`Container "${e}" not found`);return n}return e}checkEligibility(){if(!this.options.eligible)return;const e=this.options.eligible({props:this.props});if(!e.eligible)throw new Error(`Component not eligible: ${e.reason??"Unknown reason"}`)}async prerender(){if(!this.container)return;const e=this.options.prerenderTemplate??wt,n=this.options.containerTemplate??_t,s=this.options.dimensions,i=this.props.cspNonce;if(this.context===p.IFRAME){const c=this.buildWindowName();this.iframe=this.createIframeElement(c),be(this.iframe)}const r={uid:this.uid,tag:this.options.tag,context:this.context,dimensions:s,props:this.props,doc:document,container:this.container,frame:this.iframe,prerenderFrame:null,close:()=>this.close(),focus:()=>this.focus(),cspNonce:i};this.prerenderElement=e(r);const o={uid:this.uid,tag:this.options.tag,context:this.context,dimensions:s,props:this.props,doc:document,container:this.container,frame:this.iframe,prerenderFrame:this.prerenderElement,close:()=>this.close(),focus:()=>this.focus(),cspNonce:i},a=n(o);a&&(this.container.appendChild(a),this.container=a),this.prerenderElement&&!this.prerenderElement.parentNode&&this.container.appendChild(this.prerenderElement),this.iframe&&!this.iframe.parentNode&&this.container.appendChild(this.iframe)}createIframeElement(e){const n=document.createElement("iframe"),s=this.options.dimensions,i=typeof this.options.attributes=="function"?this.options.attributes(this.props):this.options.attributes??{},r=typeof this.options.style=="function"?this.options.style(this.props):this.options.style??{};n.name=e,n.setAttribute("frameborder","0"),n.setAttribute("allowtransparency","true"),n.setAttribute("scrolling","auto"),s.width!==void 0&&(n.style.width=typeof s.width=="number"?`${s.width}px`:s.width),s.height!==void 0&&(n.style.height=typeof s.height=="number"?`${s.height}px`:s.height);for(const[o,a]of Object.entries(i))a!==void 0&&(typeof a=="boolean"?a&&n.setAttribute(o,""):n.setAttribute(o,a));for(const[o,a]of Object.entries(r)){if(a===void 0)continue;const c=typeof a=="number"?`${a}px`:a;n.style.setProperty(o.replace(/([A-Z])/g,"-$1").toLowerCase(),String(c))}return i.sandbox||n.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"),n}async open(){const e=this.buildUrl();if(this.context===p.IFRAME){if(!this.iframe)throw new Error("Iframe not created during prerender");this.iframe.src=e,this.hostWindow=this.iframe.contentWindow}else{const n=this.buildWindowName();this.hostWindow=dt({url:e,name:n,dimensions:this.options.dimensions});const s=gt(this.hostWindow,()=>{this.destroy()});this.cleanup.register(s)}this.hostWindow&&Ye(this.uid,this.hostWindow)}buildUrl(){const e=typeof this.options.url=="function"?this.options.url(this.props):this.options.url,s=tt(this.props,this.options.props).toString();if(!s)return e;const i=e.includes("?")?"&":"?";return`${e}${i}${s}`}buildWindowName(){const e=this.getHostDomain(),n=ye(this.props,this.options.props,e,!1),s=we(n,this.options.props,this.bridge),i=this.buildNestedHostRefs(),r=qe({uid:this.uid,tag:this.options.tag,context:this.context,consumerDomain:Y(),props:s,exports:this.createConsumerExports(),children:i});return Be(r)}buildNestedHostRefs(){if(!this.options.children)return;const e=this.options.children({props:this.props}),n={};for(const[s,i]of Object.entries(e)){const r=i;n[s]={tag:r.tag??s,url:typeof r.url=="function"?r.url.toString():r.url??""}}return Object.keys(n).length>0?n:void 0}createConsumerExports(){return{init:h.INIT,close:h.CLOSE,resize:h.RESIZE,show:h.SHOW,hide:h.HIDE,onError:h.ERROR,updateProps:h.PROPS,export:h.EXPORT}}getHostDomain(){const e=typeof this.options.url=="function"?this.options.url(this.props):this.options.url;try{return new URL(e,window.location.origin).origin}catch{return"*"}}async waitForHost(){this.initPromise=oe();try{await Ae(this.initPromise.promise,this.options.timeout,`Host component "${this.options.tag}" (uid: ${this._uid}) did not initialize within ${this.options.timeout}ms. Check that the host page loads correctly and calls the initialization code.`)}catch(e){throw this.handleError(e),e}}setupMessageHandlers(){this.messenger.on(h.INIT,()=>(this.initPromise&&this.initPromise.resolve(),{success:!0})),this.messenger.on(h.CLOSE,async()=>(await this.close(),{success:!0})),this.messenger.on(h.RESIZE,async e=>(await this.resize(e),{success:!0})),this.messenger.on(h.FOCUS,async()=>(await this.focus(),{success:!0})),this.messenger.on(h.SHOW,async()=>(await this.show(),{success:!0})),this.messenger.on(h.HIDE,async()=>(await this.hide(),{success:!0})),this.messenger.on(h.ERROR,async e=>{const n=new Error(e.message);return n.stack=e.stack,this.handleError(n),{success:!0}}),this.messenger.on(h.EXPORT,async e=>(this.exports=e,{success:!0})),this.messenger.on(h.CONSUMER_EXPORT,async e=>(this.consumerExports=e,{success:!0})),this.messenger.on(h.GET_SIBLINGS,async e=>{const n=[],s=Ot(e.tag);if(s)for(const i of s.instances)i.uid!==e.uid&&n.push({uid:i.uid,tag:e.tag,exports:i.exports});return n})}setupCleanup(){this.cleanup.register(()=>{this.messenger.destroy(),this.bridge.destroy(),this.event.removeAllListeners(),Ge(this.uid)})}handleError(e){this.event.emit(m.ERROR,e),this.callPropCallback("onError",e)}callPropCallback(e,...n){const s=this.props[e];if(typeof s=="function")try{const i=s(...n);i&&typeof i=="object"&&"catch"in i&&typeof i.catch=="function"&&i.catch(r=>{console.error(`Error in async ${e} callback:`,r)})}catch(i){console.error(`Error in ${e} callback:`,i)}}async destroy(){this.destroyed||(this.destroyed=!0,this.initPromise&&(this.initPromise.reject(new Error(`Component "${this.options.tag}" was destroyed before initialization completed`)),this.initPromise=null),this.iframe&&(at(this.iframe),this.iframe=null),this.context===p.POPUP&&this.hostWindow&&ft(this.hostWindow),this.hostWindow=null,this.prerenderElement&&(this.prerenderElement.remove(),this.prerenderElement=null),await this.cleanup.cleanup(),this.event.emit(m.DESTROY),this.callPropCallback("onDestroy"))}}class Rt{constructor(e,n={}){this.propDefinitions=n,this.uid=e.uid,this.tag=e.tag,this.consumerDomain=e.consumerDomain,this.event=new re,this.messenger=new ce(this.uid,window,Y(),this.consumerDomain),this.setupMessageHandlers(),this.consumerWindow=this.resolveConsumerWindow(),this.bridge=new q(this.messenger),this.hostProps=this.buildHostProps(e),window.hostProps=this.hostProps,this.sendInit()}hostProps;event;uid;tag;consumerWindow;consumerDomain;messenger;bridge;propsHandlers=new Set;consumerProps;initError=null;getProps(){return this.hostProps}resolveConsumerWindow(){if(Ue()){const e=ze();if(e)return e}if(je()){const e=We();if(e)return e}throw new Error("Could not resolve consumer window")}buildHostProps(e){const n=Ee(e.props,this.propDefinitions,this.messenger,this.bridge,this.consumerWindow,this.consumerDomain);return this.consumerProps=n,{...n,uid:this.uid,tag:this.tag,close:()=>this.close(),focus:()=>this.focus(),resize:s=>this.resize(s),show:()=>this.show(),hide:()=>this.hide(),onProps:s=>this.onProps(s),onError:s=>this.onError(s),getConsumer:()=>this.consumerWindow,getConsumerDomain:()=>this.consumerDomain,export:s=>this.exportData(s),consumer:{props:this.consumerProps,export:s=>this.consumerExport(s)},getPeerInstances:s=>this.getPeerInstances(s),children:this.buildNestedComponents(e.children)}}async sendInit(){try{await this.messenger.send(this.consumerWindow,this.consumerDomain,h.INIT,{uid:this.uid,tag:this.tag})}catch(e){const n=e instanceof Error?e:new Error(String(e));this.initError=n,this.event.emit(m.ERROR,{type:"init_failed",message:`Failed to initialize host component: ${n.message}`,error:n}),console.error("Failed to send init message:",e)}}getInitError(){return this.initError}async close(){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.CLOSE,{})}async focus(){window.focus(),await this.messenger.send(this.consumerWindow,this.consumerDomain,h.FOCUS,{})}async resize(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.RESIZE,e)}async show(){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.SHOW,{})}async hide(){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.HIDE,{})}onProps(e){return this.propsHandlers.add(e),{cancel:()=>this.propsHandlers.delete(e)}}async onError(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.ERROR,{message:e.message,stack:e.stack})}async exportData(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.EXPORT,e)}async consumerExport(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,h.CONSUMER_EXPORT,e)}async getPeerInstances(e){return await this.messenger.send(this.consumerWindow,this.consumerDomain,h.GET_SIBLINGS,{uid:this.uid,tag:this.tag,options:e})??[]}buildNestedComponents(e){if(!e)return;const n={};for(const[s,i]of Object.entries(e))try{n[s]=te({tag:i.tag,url:i.url,props:i.props,dimensions:i.dimensions,defaultContext:i.defaultContext})}catch(r){console.warn(`Failed to create nested component "${s}":`,r)}return Object.keys(n).length>0?n:void 0}setupMessageHandlers(){this.messenger.on(h.PROPS,e=>{try{const n=Ee(e,this.propDefinitions,this.messenger,this.bridge,this.consumerWindow,this.consumerDomain);Object.assign(this.hostProps,n);for(const s of this.propsHandlers)try{s(n)}catch(i){console.error("Error in props handler:",i)}return this.event.emit(m.PROPS,n),{success:!0}}catch(n){const s=n instanceof Error?n:new Error(String(n));throw console.error("Error deserializing props:",s),this.event.emit(m.ERROR,s),s}})}destroy(){this.messenger.destroy(),this.bridge.destroy(),this.event.removeAllListeners(),this.propsHandlers.clear()}}let W=null;function Pe(t){if(W)return W;if(!G())return null;const e=Xe();return e?(W=new Rt(e,t),W):(console.error("Failed to parse ForgeFrame payload from window.name"),null)}function Re(){return G()}function Se(){return G()}function Oe(){return window.hostProps}const I=new Map;function St(t){if(!t.tag)throw new Error("Component tag is required");if(!/^[a-z][a-z0-9-]*$/.test(t.tag))throw new Error(`Invalid component tag "${t.tag}". Must start with lowercase letter and contain only lowercase letters, numbers, and hyphens.`);if(!t.url)throw new Error("Component url is required");if(typeof t.url=="string")try{new URL(t.url,window.location.origin)}catch{throw new Error(`Invalid component URL "${t.url}". Must be a valid absolute or relative URL.`)}if(I.has(t.tag))throw new Error(`Component "${t.tag}" is already registered`)}function te(t){St(t);const e=[];let n;if(K(t.tag)){const i=Pe(t.props);i&&(n=i.hostProps)}const s=function(i={}){const r=new ee(t,i);return e.push(r),r.event.once("destroy",()=>{const o=e.indexOf(r);o!==-1&&e.splice(o,1)}),r};return s.instances=e,s.isHost=()=>K(t.tag),s.isEmbedded=()=>K(t.tag),s.hostProps=n,s.canRenderTo=async i=>{try{return!!(ue(i)||t.domain)}catch{return!1}},I.set(t.tag,s),s}function Ot(t){return I.get(t)}async function Ce(t){await t.close()}async function ne(t){const e=I.get(t);if(!e)return;const n=[...e.instances];await Promise.all(n.map(s=>s.close()))}async function ve(){const t=Array.from(I.keys());await Promise.all(t.map(e=>ne(e)))}function Ie(t,e){const{React:n}=e,{createElement:s,useRef:i,useEffect:r,useState:o,forwardRef:a}=n,c=a(function(w,E){const{onRendered:S,onError:z,onClose:De,context:vt,className:Ne,style:Te,...se}=w,U=i(null),ie=i(null),[Fe,It]=o(null);return r(()=>{const x=U.current;if(!x)return;const b=t(se);return ie.current=b,S&&b.event.once("rendered",S),De&&b.event.once("close",De),z&&b.event.on("error",z),b.render(x,vt).catch(ke=>{It(ke),z?.(ke)}),()=>{b.close().catch(()=>{}),ie.current=null}},[]),r(()=>{const x=ie.current;x&&x.updateProps(se).catch(b=>{z?.(b)})},[JSON.stringify(se)]),r(()=>{E&&typeof E=="object"&&U.current&&(E.current=U.current)},[E]),Fe?s("div",{className:Ne,style:{color:"red",padding:"16px",...Te}},`Error: ${Fe.message}`):s("div",{ref:U,className:Ne,style:{display:"inline-block",...Te}})}),l=`ForgeFrame(${t.name||"Component"})`;return c.displayName=l,c}function Ct(t){return function(n){return Ie(n,{React:t})}}Pe();const xe={create:te,destroy:Ce,destroyByTag:ne,destroyAll:ve,isHost:Re,isEmbedded:Se,getHostProps:Oe,PROP_SERIALIZATION:O,CONTEXT:p,EVENT:m,PopupOpenError:Q,VERSION:j,isStandardSchema:_,prop:f};u.AnySchema=H,u.ArraySchema=C,u.BooleanSchema=k,u.CONTEXT=p,u.EVENT=m,u.EnumSchema=A,u.ForgeFrame=xe,u.FunctionSchema=$,u.LiteralSchema=L,u.NumberSchema=F,u.ObjectSchema=v,u.PROP_SERIALIZATION=O,u.PopupOpenError=Q,u.PropSchema=g,u.StringSchema=T,u.VERSION=j,u.create=te,u.createReactComponent=Ie,u.default=xe,u.destroy=Ce,u.destroyAll=ve,u.destroyByTag=ne,u.getHostProps=Oe,u.isEmbedded=Se,u.isHost=Re,u.isStandardSchema=_,u.prop=f,u.withReactComponent=Ct,Object.defineProperties(u,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* ForgeFrame - Modern cross-domain component framework.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* A minimal, TypeScript-first alternative to zoid with zero runtime dependencies.
|
|
7
|
+
* Enables rendering components in iframes or popups across domains while
|
|
8
|
+
* seamlessly passing props (including functions) between consumer and host.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import ForgeFrame, { prop } from 'forgeframe';
|
|
13
|
+
*
|
|
14
|
+
* // Define a component with schema-based props
|
|
15
|
+
* const LoginComponent = ForgeFrame.create({
|
|
16
|
+
* tag: 'login-component',
|
|
17
|
+
* url: 'https://auth.example.com/login',
|
|
18
|
+
* props: {
|
|
19
|
+
* email: prop.string().email(),
|
|
20
|
+
* rememberMe: prop.boolean().default(false),
|
|
21
|
+
* onLogin: prop.function<(user: { id: string }) => void>(),
|
|
22
|
+
* },
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Render the component
|
|
26
|
+
* LoginComponent({
|
|
27
|
+
* email: 'user@example.com',
|
|
28
|
+
* onLogin: (user) => console.log('Logged in:', user),
|
|
29
|
+
* }).render('#container');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
import { create, destroy, destroyByTag, destroyAll, isHost, isEmbedded, getHostProps } from './core';
|
|
33
|
+
import { PopupOpenError } from './render/popup';
|
|
34
|
+
import { isStandardSchema } from './props/schema';
|
|
35
|
+
/**
|
|
36
|
+
* Main ForgeFrame API object.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* Provides a zoid-compatible interface for creating and managing
|
|
40
|
+
* cross-domain components. All methods and constants are accessible
|
|
41
|
+
* through this object.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import ForgeFrame from 'forgeframe';
|
|
46
|
+
*
|
|
47
|
+
* const Component = ForgeFrame.create({
|
|
48
|
+
* tag: 'my-component',
|
|
49
|
+
* url: '/component.html',
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export declare const ForgeFrame: {
|
|
56
|
+
/**
|
|
57
|
+
* Create a new component definition.
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* This is the main entry point for defining components. Returns a
|
|
61
|
+
* component factory function that can be called to create instances.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import ForgeFrame, { prop } from 'forgeframe';
|
|
66
|
+
*
|
|
67
|
+
* const MyComponent = ForgeFrame.create({
|
|
68
|
+
* tag: 'my-component',
|
|
69
|
+
* url: 'https://example.com/component',
|
|
70
|
+
* props: {
|
|
71
|
+
* email: prop.string().email(),
|
|
72
|
+
* onLogin: prop.function<(user: { id: string }) => void>(),
|
|
73
|
+
* },
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* const instance = MyComponent({ email: 'user@example.com', onLogin: (user) => {} });
|
|
77
|
+
* await instance.render('#container');
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
readonly create: typeof create;
|
|
81
|
+
/**
|
|
82
|
+
* Destroy a single component instance.
|
|
83
|
+
*
|
|
84
|
+
* @param instance - The component instance to destroy
|
|
85
|
+
*/
|
|
86
|
+
readonly destroy: typeof destroy;
|
|
87
|
+
/**
|
|
88
|
+
* Destroy all instances of a specific component by tag.
|
|
89
|
+
*
|
|
90
|
+
* @param tag - The component tag name
|
|
91
|
+
*/
|
|
92
|
+
readonly destroyByTag: typeof destroyByTag;
|
|
93
|
+
/**
|
|
94
|
+
* Destroy all ForgeFrame component instances.
|
|
95
|
+
*/
|
|
96
|
+
readonly destroyAll: typeof destroyAll;
|
|
97
|
+
/**
|
|
98
|
+
* Check if the current window is a host component context.
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* A "host" is the embedded iframe or popup window that receives props
|
|
102
|
+
* from the consumer (the embedding app).
|
|
103
|
+
*
|
|
104
|
+
* @returns True if running inside a ForgeFrame iframe/popup
|
|
105
|
+
*/
|
|
106
|
+
readonly isHost: typeof isHost;
|
|
107
|
+
/**
|
|
108
|
+
* Check if the current window is embedded by ForgeFrame.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* This is an alias for {@link isHost} that uses more intuitive terminology.
|
|
112
|
+
*
|
|
113
|
+
* @returns True if running inside a ForgeFrame iframe/popup
|
|
114
|
+
*/
|
|
115
|
+
readonly isEmbedded: typeof isEmbedded;
|
|
116
|
+
/**
|
|
117
|
+
* Get hostProps from the current host window.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* Returns the props passed from the consumer plus built-in control methods.
|
|
121
|
+
*
|
|
122
|
+
* @returns The hostProps object if in host context, undefined otherwise
|
|
123
|
+
*/
|
|
124
|
+
readonly getHostProps: typeof getHostProps;
|
|
125
|
+
/**
|
|
126
|
+
* Serialization strategy constants.
|
|
127
|
+
* @see {@link PROP_SERIALIZATION}
|
|
128
|
+
*/
|
|
129
|
+
readonly PROP_SERIALIZATION: {
|
|
130
|
+
readonly JSON: "json";
|
|
131
|
+
readonly BASE64: "base64";
|
|
132
|
+
readonly DOTIFY: "dotify";
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Rendering context constants (IFRAME, POPUP).
|
|
136
|
+
* @see {@link CONTEXT}
|
|
137
|
+
*/
|
|
138
|
+
readonly CONTEXT: {
|
|
139
|
+
readonly IFRAME: "iframe";
|
|
140
|
+
readonly POPUP: "popup";
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Lifecycle event name constants.
|
|
144
|
+
* @see {@link EVENT}
|
|
145
|
+
*/
|
|
146
|
+
readonly EVENT: {
|
|
147
|
+
readonly RENDER: "render";
|
|
148
|
+
readonly RENDERED: "rendered";
|
|
149
|
+
readonly PRERENDER: "prerender";
|
|
150
|
+
readonly PRERENDERED: "prerendered";
|
|
151
|
+
readonly DISPLAY: "display";
|
|
152
|
+
readonly ERROR: "error";
|
|
153
|
+
readonly CLOSE: "close";
|
|
154
|
+
readonly DESTROY: "destroy";
|
|
155
|
+
readonly PROPS: "props";
|
|
156
|
+
readonly RESIZE: "resize";
|
|
157
|
+
readonly FOCUS: "focus";
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Error thrown when popup window fails to open.
|
|
161
|
+
*/
|
|
162
|
+
readonly PopupOpenError: typeof PopupOpenError;
|
|
163
|
+
/**
|
|
164
|
+
* Current library version.
|
|
165
|
+
*/
|
|
166
|
+
readonly VERSION: "0.0.1";
|
|
167
|
+
/**
|
|
168
|
+
* Check if a value is a Standard Schema (Zod, Valibot, ArkType, etc.)
|
|
169
|
+
*
|
|
170
|
+
* @param value - The value to check
|
|
171
|
+
* @returns True if the value implements StandardSchemaV1
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* import { z } from 'zod';
|
|
176
|
+
*
|
|
177
|
+
* const schema = z.string();
|
|
178
|
+
* if (ForgeFrame.isStandardSchema(schema)) {
|
|
179
|
+
* // schema is StandardSchemaV1
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
readonly isStandardSchema: typeof isStandardSchema;
|
|
184
|
+
/**
|
|
185
|
+
* Prop schema builders for defining component props.
|
|
186
|
+
*
|
|
187
|
+
* @remarks
|
|
188
|
+
* Provides a fluent, Zod-like API for defining prop schemas with built-in
|
|
189
|
+
* validation. All schemas implement StandardSchemaV1.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* import ForgeFrame from 'forgeframe';
|
|
194
|
+
*
|
|
195
|
+
* const Component = ForgeFrame.create({
|
|
196
|
+
* tag: 'my-component',
|
|
197
|
+
* url: '/component',
|
|
198
|
+
* props: {
|
|
199
|
+
* name: ForgeFrame.prop.string(),
|
|
200
|
+
* count: ForgeFrame.prop.number().default(0),
|
|
201
|
+
* onSubmit: ForgeFrame.prop.function().optional(),
|
|
202
|
+
* },
|
|
203
|
+
* });
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
readonly prop: {
|
|
207
|
+
readonly string: () => import("./props").StringSchema;
|
|
208
|
+
readonly number: () => import("./props").NumberSchema;
|
|
209
|
+
readonly boolean: () => import("./props").BooleanSchema;
|
|
210
|
+
readonly function: <T extends (...args: any[]) => any = (...args: any[]) => any>() => import("./props").FunctionSchema<T>;
|
|
211
|
+
readonly array: <T = unknown>() => import("./props").ArraySchema<T>;
|
|
212
|
+
readonly object: <T extends object = Record<string, unknown>>() => import("./props").ObjectSchema<T>;
|
|
213
|
+
readonly literal: <T extends string | number | boolean>(value: T) => import("./props").LiteralSchema<T>;
|
|
214
|
+
readonly enum: <T extends string | number>(values: readonly T[]) => import("./props").EnumSchema<T>;
|
|
215
|
+
readonly any: () => import("./props").AnySchema;
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Default export of the ForgeFrame API object.
|
|
220
|
+
* @public
|
|
221
|
+
*/
|
|
222
|
+
export default ForgeFrame;
|
|
223
|
+
export { create, destroy, destroyByTag, destroyAll, isHost, isEmbedded, getHostProps, } from './core';
|
|
224
|
+
export { PROP_SERIALIZATION, CONTEXT, EVENT, VERSION, } from './constants';
|
|
225
|
+
export { PopupOpenError } from './render/popup';
|
|
226
|
+
export { isStandardSchema } from './props/schema';
|
|
227
|
+
export { prop, PropSchema, StringSchema, NumberSchema, BooleanSchema, FunctionSchema, ArraySchema, ObjectSchema, LiteralSchema, EnumSchema, AnySchema, type Prop, type InferObjectShape, } from './props/prop';
|
|
228
|
+
export type { ComponentOptions, ForgeFrameComponent, ForgeFrameComponentInstance, HostProps, HostPropsBuiltins, PropDefinition, PropsDefinition, PropContext, StandardSchemaV1, InferSchemaOutput, SchemaPropDefinition, TemplateContext, ContainerTemplate, PrerenderTemplate, Dimensions, DomainMatcher, AutoResizeOptions, IframeAttributes, IframeStyles, EligibilityResult, SiblingInfo, GetPeerInstancesOptions, EventHandler, EventEmitterInterface, } from './types';
|
|
229
|
+
export type { ContextType, EventType, SerializationType, } from './constants';
|
|
230
|
+
export { createReactComponent, withReactComponent, type ReactDriverOptions, type ReactComponentProps, type ReactComponentType, } from './drivers/react';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Built-in prop definitions for ForgeFrame components.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This module defines the standard props that are automatically available
|
|
7
|
+
* to all ForgeFrame components, including identifiers, dimensions, and
|
|
8
|
+
* lifecycle callbacks.
|
|
9
|
+
*/
|
|
10
|
+
import type { PropDefinition, Dimensions } from '../types';
|
|
11
|
+
/**
|
|
12
|
+
* Built-in props that are automatically provided to all components.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* These props are always available regardless of the component's prop definitions.
|
|
16
|
+
* They include component identifiers, dimensions, timeouts, and lifecycle callbacks.
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export interface BuiltinProps {
|
|
21
|
+
/** Unique component instance identifier. */
|
|
22
|
+
uid: string;
|
|
23
|
+
/** Component tag name. */
|
|
24
|
+
tag: string;
|
|
25
|
+
/** Component dimensions. */
|
|
26
|
+
dimensions: Dimensions;
|
|
27
|
+
/** Initialization timeout in milliseconds. */
|
|
28
|
+
timeout: number;
|
|
29
|
+
/** CSP nonce for inline scripts/styles. */
|
|
30
|
+
cspNonce?: string;
|
|
31
|
+
/** Called when component becomes visible. */
|
|
32
|
+
onDisplay?: () => void;
|
|
33
|
+
/** Called when component is fully rendered. */
|
|
34
|
+
onRendered?: () => void;
|
|
35
|
+
/** Called when rendering starts. */
|
|
36
|
+
onRender?: () => void;
|
|
37
|
+
/** Called when prerender phase completes. */
|
|
38
|
+
onPrerendered?: () => void;
|
|
39
|
+
/** Called when prerender phase starts. */
|
|
40
|
+
onPrerender?: () => void;
|
|
41
|
+
/** Called when component is closing. */
|
|
42
|
+
onClose?: () => void;
|
|
43
|
+
/** Called when component is destroyed. */
|
|
44
|
+
onDestroy?: () => void;
|
|
45
|
+
/** Called when component is resized. */
|
|
46
|
+
onResize?: (dimensions: Dimensions) => void;
|
|
47
|
+
/** Called when component receives focus. */
|
|
48
|
+
onFocus?: () => void;
|
|
49
|
+
/** Called when an error occurs. */
|
|
50
|
+
onError?: (err: Error) => void;
|
|
51
|
+
/** Called when props are updated. */
|
|
52
|
+
onProps?: (props: Record<string, unknown>) => void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Default prop definitions for all built-in props.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* These definitions specify the type, required status, and default values
|
|
59
|
+
* for built-in props.
|
|
60
|
+
*
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
export declare const BUILTIN_PROP_DEFINITIONS: Record<string, PropDefinition>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Props handling module for ForgeFrame.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This module handles prop normalization, validation, serialization, and
|
|
7
|
+
* deserialization for cross-domain component communication.
|
|
8
|
+
*/
|
|
9
|
+
export { BUILTIN_PROP_DEFINITIONS, type BuiltinProps, } from './definitions';
|
|
10
|
+
export { normalizeProps, validateProps, getPropsForHost, propsToQueryParams, } from './normalize';
|
|
11
|
+
export { serializeProps, deserializeProps, cloneProps, } from './serialize';
|
|
12
|
+
export { isStandardSchema, validateWithSchema, type StandardSchemaV1, type StandardSchemaV1Props, type StandardSchemaV1Result, type StandardSchemaV1SuccessResult, type StandardSchemaV1FailureResult, type StandardSchemaV1Issue, type StandardSchemaV1PathSegment, type StandardSchemaV1Types, type InferInput, type InferOutput, } from './schema';
|
|
13
|
+
export { prop, PropSchema, StringSchema, NumberSchema, BooleanSchema, FunctionSchema, ArraySchema, ObjectSchema, LiteralSchema, EnumSchema, AnySchema, type Prop, type InferObjectShape, } from './prop';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Props normalization and validation module.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This module handles merging user props with defaults, validating prop
|
|
7
|
+
* types, and filtering props for sending to host components.
|
|
8
|
+
*/
|
|
9
|
+
import type { PropsDefinition, PropContext } from '../types';
|
|
10
|
+
/**
|
|
11
|
+
* Merges user props with defaults and computes derived values.
|
|
12
|
+
*
|
|
13
|
+
* @typeParam P - The props type
|
|
14
|
+
* @param userProps - Props provided by the user
|
|
15
|
+
* @param definitions - Prop definitions from component config
|
|
16
|
+
* @param context - Context for computed props
|
|
17
|
+
* @returns Normalized props object
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare function normalizeProps<P extends Record<string, unknown>>(userProps: Partial<P>, definitions: PropsDefinition<P>, context: PropContext<P>): P;
|
|
22
|
+
/**
|
|
23
|
+
* Validates props against their definitions.
|
|
24
|
+
*
|
|
25
|
+
* @typeParam P - The props type
|
|
26
|
+
* @param props - Props to validate
|
|
27
|
+
* @param definitions - Prop definitions to validate against
|
|
28
|
+
* @throws Error if a required prop is missing or type is invalid
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateProps<P extends Record<string, unknown>>(props: P, definitions: PropsDefinition<P>): void;
|
|
33
|
+
/**
|
|
34
|
+
* Filters props for sending to the host component.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* Respects sendToHost, sameDomain, and trustedDomains settings.
|
|
38
|
+
*
|
|
39
|
+
* @typeParam P - The props type
|
|
40
|
+
* @param props - All props
|
|
41
|
+
* @param definitions - Prop definitions
|
|
42
|
+
* @param hostDomain - The host's domain
|
|
43
|
+
* @param isSameDomain - Whether host is same domain as consumer
|
|
44
|
+
* @returns Filtered props for the host
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare function getPropsForHost<P extends Record<string, unknown>>(props: P, definitions: PropsDefinition<P>, hostDomain: string, isSameDomain: boolean): Partial<P>;
|
|
49
|
+
/**
|
|
50
|
+
* Builds URL query parameters from props with queryParam option.
|
|
51
|
+
*
|
|
52
|
+
* @typeParam P - The props type
|
|
53
|
+
* @param props - Props to convert
|
|
54
|
+
* @param definitions - Prop definitions
|
|
55
|
+
* @returns URLSearchParams with query parameters
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export declare function propsToQueryParams<P extends Record<string, unknown>>(props: P, definitions: PropsDefinition<P>): URLSearchParams;
|