forgeframe 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- (function(h,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(h=typeof globalThis<"u"?globalThis:h||self,p(h.ForgeFrame={}))})(this,(function(h){"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"},v={JSON:"json",BASE64:"base64",DOTIFY:"dotify"},F={REQUEST:"request",RESPONSE:"response"},u={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"},$="__forgeframe__",q="0.0.1";class le{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}once(e,t){const n=i=>(this.off(e,n),t(i));return this.on(e,n)}emit(e,t){const n=this.listeners.get(e);if(n)for(const i of n)try{const r=i(t);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,t){if(!t){this.listeners.delete(e);return}const n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e))}removeAllListeners(){this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function He(){const s=Date.now().toString(36),e=Math.random().toString(36).slice(2,11);return`${s}_${e}`}function J(){return Math.random().toString(36).slice(2,11)}class Ae{tasks=[];cleaned=!1;register(e){if(this.cleaned){try{e()}catch(t){console.error("Error in cleanup task:",t)}return}this.tasks.push(e)}async cleanup(){if(this.cleaned)return;this.cleaned=!0;const e=this.tasks.reverse();this.tasks=[];for(const t of e)try{await t()}catch(n){console.error("Error in cleanup task:",n)}}isCleaned(){return this.cleaned}reset(){this.tasks=[],this.cleaned=!1}}function he(){let s,e;return{promise:new Promise((n,i)=>{s=n,e=i}),resolve:s,reject:e}}function Ue(s,e,t="Operation timed out"){return new Promise((n,i)=>{const r=setTimeout(()=>{i(new Error(`${t} (${e}ms)`))},e);s.then(o=>{clearTimeout(r),n(o)}).catch(o=>{clearTimeout(r),i(o)})})}const X="forgeframe:";function K(s){return X+JSON.stringify(s)}function Me(s){if(typeof s!="string"||!s.startsWith(X))return null;try{const e=s.slice(X.length),t=JSON.parse(e);return!t.id||!t.type||!t.name||!t.source?null:t}catch{return null}}function ue(s,e,t,n){return{id:s,type:F.REQUEST,name:e,data:t,source:n}}function We(s,e,t,n){return{id:s,type:F.RESPONSE,name:"response",data:e,source:t,error:n?{message:n.message,stack:n.stack}:void 0}}class de{constructor(e,t=window,n=window.location.origin,i){this.uid=e,this.win=t,this.domain=n,this.allowedOrigins.add(n),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 t of e)this.allowedOrigins.add(t);else e instanceof RegExp?this.allowedOriginPatterns.push(e):this.allowedOrigins.add(e)}removeTrustedDomain(e){if(Array.isArray(e))for(const t of e)this.allowedOrigins.delete(t);else e instanceof RegExp?this.allowedOriginPatterns=this.allowedOriginPatterns.filter(t=>t!==e):this.allowedOrigins.delete(e)}isOriginTrusted(e){if(this.allowedOrigins.has(e))return!0;for(const t of this.allowedOriginPatterns)if(t.test(e))return!0;return!1}async send(e,t,n,i,r=1e4){if(this.destroyed)throw new Error("Messenger has been destroyed");const o=J(),a=ue(o,n,i,{uid:this.uid,domain:this.domain}),c=he(),l=setTimeout(()=>{this.pending.delete(o),c.reject(new Error(`Message "${n}" timed out after ${r}ms`))},r);this.pending.set(o,{deferred:c,timeout:l});try{e.postMessage(K(a),t)}catch(d){throw this.pending.delete(o),clearTimeout(l),d}return c.promise}post(e,t,n,i){if(this.destroyed)throw new Error("Messenger has been destroyed");const r=J(),o=ue(r,n,i,{uid:this.uid,domain:this.domain});e.postMessage(K(o),t)}on(e,t){return this.handlers.set(e,t),()=>this.handlers.delete(e)}setupListener(){this.listener=e=>{if(e.source===this.win||!this.isOriginTrusted(e.origin))return;const t=Me(e.data);t&&this.handleMessage(t,e.source,e.origin)},this.win.addEventListener("message",this.listener)}async handleMessage(e,t,n){if(e.type===F.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===F.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=We(e.id,r,{uid:this.uid,domain:this.domain},o);try{t.postMessage(K(a),n)}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 fe=500;class Z{constructor(e){this.messenger=e,this.setupCallHandler()}localFunctions=new Map;remoteFunctions=new Map;currentBatchIds=new Set;serialize(e,t){if(this.localFunctions.size>=fe){const i=this.localFunctions.keys().next().value;i&&this.localFunctions.delete(i)}const n=J();return this.localFunctions.set(n,e),this.currentBatchIds.add(n),{__type__:"function",__id__:n,__name__:t||e.name||"anonymous"}}deserialize(e,t,n){const i=`${e.__id__}`,r=this.remoteFunctions.get(i);if(r)return r;if(this.remoteFunctions.size>=fe){const a=this.remoteFunctions.keys().next().value;a&&this.remoteFunctions.delete(a)}const o=async(...a)=>this.messenger.send(t,n,u.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(u.CALL,async({id:e,args:t})=>{const n=this.localFunctions.get(e);if(!n)throw new Error(`Function with id "${e}" not found`);return n(...t)})}removeLocal(e){this.localFunctions.delete(e)}startBatch(){this.currentBatchIds.clear()}finishBatch(e=!1){if(e){this.currentBatchIds.clear();return}for(const t of this.localFunctions.keys())this.currentBatchIds.has(t)||this.localFunctions.delete(t);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 Y(s,e,t=new WeakSet){if(typeof s=="function")return e.serialize(s);if(Array.isArray(s)){if(t.has(s))throw new Error("Circular reference detected in props - arrays cannot contain circular references");return t.add(s),s.map(n=>Y(n,e,t))}if(typeof s=="object"&&s!==null){if(t.has(s))throw new Error("Circular reference detected in props - objects cannot contain circular references");t.add(s);const n={};for(const[i,r]of Object.entries(s))n[i]=Y(r,e,t);return n}return s}function G(s,e,t,n,i=new WeakSet){if(Z.isFunctionRef(s))return e.deserialize(s,t,n);if(Array.isArray(s)){if(i.has(s))throw new Error("Circular reference detected in serialized props");return i.add(s),s.map(r=>G(r,e,t,n,i))}if(typeof s=="object"&&s!==null){if(i.has(s))throw new Error("Circular reference detected in serialized props");i.add(s);const r={};for(const[o,a]of Object.entries(s))r[o]=G(a,e,t,n,i);return r}return s}function Q(s=window){try{return s.location.origin}catch{return""}}function pe(s,e=window){try{return s.location.origin===e.location.origin}catch{return!1}}function k(s,e){return typeof s=="string"?s==="*"?!0:s===e:s instanceof RegExp?s.test(e):Array.isArray(s)?s.some(t=>k(t,e)):!1}function me(s){if(!s)return!0;try{return s.closed}catch{return!0}}function ze(s=window){try{return s.opener}catch{return null}}function je(s=window){try{const e=s.parent;return e&&e!==s?e:null}catch{return null}}function Be(s=window){try{return s.parent!==s}catch{return!0}}function Ve(s=window){try{return s.opener!==null&&s.opener!==void 0}catch{return!1}}const ge=32*1024;function qe(s){const e=Je(s);return`${$}${e}`}function ye(s){if(!s||!s.startsWith($))return null;const e=s.slice($.length);return Xe(e)}function ee(s=window){try{return s.name.startsWith($)}catch{return!1}}function te(s,e=window){return ye(e.name)?.tag===s}function Je(s){try{const e=JSON.stringify(s),t=btoa(encodeURIComponent(e)),n=new Blob([t]).size;if(n>ge)throw new Error(`Payload size (${Math.round(n/1024)}KB) exceeds maximum allowed size (${ge/1024}KB). Consider reducing the amount of data passed via props.`);return t}catch(e){throw e instanceof Error&&e.message.includes("Payload size")?e:new Error(`Failed to encode payload: ${e}`)}}function Xe(s){try{const e=decodeURIComponent(atob(s));return JSON.parse(e)}catch{return null}}function Ke(s){return{uid:s.uid,tag:s.tag,version:q,context:s.context,consumerDomain:s.consumerDomain,props:s.props,exports:s.exports,children:s.children}}function Ze(s=window){return ye(s.name)}const we=100,_=new Map;function Ye(){const s=[];for(const[e,t]of _.entries())me(t)&&s.push(e);for(const e of s)_.delete(e)}function Ge(s,e){if(_.size>=we&&Ye(),_.size>=we){const t=_.keys().next().value;t&&_.delete(t)}_.set(s,e)}function Qe(s){_.delete(s)}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 t=this._clone();return t._default=e,t}}class L extends g{_minLength;_maxLength;_pattern;_patternMessage;_trim=!1;_validate(e){if(typeof e!="string")return{issues:[{message:`Expected string, got ${typeof e}`}]};const t=this._trim?e.trim():e;return this._minLength!==void 0&&t.length<this._minLength?{issues:[{message:`String must be at least ${this._minLength} characters`}]}:this._maxLength!==void 0&&t.length>this._maxLength?{issues:[{message:`String must be at most ${this._maxLength} characters`}]}:this._pattern&&!this._pattern.test(t)?{issues:[{message:this._patternMessage||`String must match pattern ${this._pattern}`}]}:{value:t}}_clone(){const e=new L;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 t=this._clone();return t._minLength=e,t}max(e){const t=this._clone();return t._maxLength=e,t}length(e){const t=this._clone();return t._minLength=e,t._maxLength=e,t}pattern(e,t){const n=this._clone();return n._pattern=e,n._patternMessage=t,n}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 H 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 H;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 t=this._clone();return t._min=e,t}max(e){const t=this._clone();return t._max=e,t}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 A extends g{_validate(e){return typeof e!="boolean"?{issues:[{message:`Expected boolean, got ${typeof e}`}]}:{value:e}}_clone(){const e=new A;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class U extends g{_validate(e){return typeof e!="function"?{issues:[{message:`Expected function, got ${typeof e}`}]}:{value:e}}_clone(){const e=new U;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 t=[];for(let n=0;n<e.length;n++){const i=this._itemSchema["~standard"].validate(e[n]);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:[n,...r.path||[]]}))};t.push(i.value)}return{value:t}}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 t=new C;return t._optional=this._optional,t._nullable=this._nullable,t._itemSchema=e,t._minLength=this._minLength,t._maxLength=this._maxLength,t}min(e){const t=this._clone();return t._minLength=e,t}max(e){const t=this._clone();return t._maxLength=e,t}nonempty(){return this.min(1)}}class I 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 t=e,n={};if(this._shape){if(this._strict){const i=new Set(Object.keys(this._shape));for(const r of Object.keys(t))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(t[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||[]]}))};n[i]=o.value}if(!this._strict)for(const i of Object.keys(t))i in this._shape||(n[i]=t[i]);return{value:n}}return{value:e}}_clone(){const e=new I;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 t=new I;return t._optional=this._optional,t._nullable=this._nullable,t._shape=e,t._strict=this._strict,t}strict(){const e=this._clone();return e._strict=!0,e}}class M 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 M(this._value);return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class W 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(t=>JSON.stringify(t)).join(", ")}], got ${JSON.stringify(e)}`}]}}_clone(){const e=new W(this._values);return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class z extends g{constructor(){super(),this._nullable=!0}_validate(e){return{value:e}}_clone(){const e=new z;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}const f={string:()=>new L,number:()=>new H,boolean:()=>new A,function:()=>new U,array:()=>new C,object:()=>new I,literal:s=>new M(s),enum:s=>new W(s),any:()=>new z},O={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 E(s){return typeof s=="object"&&s!==null&&"~standard"in s&&typeof s["~standard"]=="object"&&s["~standard"]!==null&&s["~standard"].version===1&&typeof s["~standard"].validate=="function"}function et(s,e,t){const n=s["~standard"].validate(e);if(n instanceof Promise)throw new Error(`Prop "${t}" 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(n.issues){const i=n.issues.map(r=>`${tt(r.path,t)}: ${r.message}`);throw new Error(`Validation failed: ${i.join("; ")}`)}return n.value}function tt(s,e){if(!s||s.length===0)return e;const t=s.map(n=>typeof n=="object"&&n!==null&&"key"in n?String(n.key):String(n));return`${e}.${t.join(".")}`}function _e(s,e,t){const n={...O,...e},i={};for(const[r,o]of Object.entries(n)){const c=E(o)?{schema:o}:o;let l;const d=c.alias,b=r in s,P=d&&d in s;if(b)l=s[r];else if(P)l=s[d];else if(c.value)l=c.value(t);else if(c.default!==void 0)l=typeof c.default=="function"?c.default(t):c.default;else if(c.schema&&E(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 st(s,e){const t={...O,...e};for(const[n,i]of Object.entries(t)){const r=E(i),o=r?{schema:i}:i;let a=s[n];if(o.required&&a===void 0)throw new Error(`Prop "${n}" is required but was not provided`);if(o.schema&&E(o.schema))(a!==void 0||r)&&(a=et(o.schema,a,n),s[n]=a);else if(a===void 0)continue;o.validate&&o.validate({value:a,props:s})}}function Ee(s,e,t,n){const i={...O,...e},r={};for(const[o,a]of Object.entries(i)){const l=E(a)?{schema:a}:a,d=s[o];if(l.sendToHost===!1||l.sameDomain&&!n)continue;if(l.trustedDomains){const P=l.trustedDomains;if(!k(P,t))continue}let b=d;l.hostDecorate&&d!==void 0&&(b=l.hostDecorate({value:d,props:s})),r[o]=b}return r}function nt(s,e){const t=new URLSearchParams,n={...O,...e};for(const[i,r]of Object.entries(n)){const a=E(r)?{schema:r}:r,c=s[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),t.set(l,d)}return t}function be(s,e=""){const t=[];for(const[n,i]of Object.entries(s)){const r=e?`${e}.${n}`:n;if(i!==null&&typeof i=="object"&&!Array.isArray(i))t.push(be(i,r));else{const o=encodeURIComponent(JSON.stringify(i));t.push(`${r}=${o}`)}}return t.filter(Boolean).join("&")}function it(s){const e={};if(!s)return e;const t=s.split("&");for(const n of t){const[i,r]=n.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 rt(s){return typeof s=="object"&&s!==null&&s.__type__==="dotify"&&typeof s.__value__=="string"}function Pe(s,e,t){const n={...O,...e},i={};for(const[r,o]of Object.entries(s)){if(o===void 0)continue;const a=n[r];i[r]=ot(o,a,t)}return i}function ot(s,e,t){if(typeof s=="function")return t.serialize(s);const n=e?.serialization??v.JSON;if(n===v.BASE64&&typeof s=="object"){const i=JSON.stringify(s);return{__type__:"base64",__value__:btoa(encodeURIComponent(i))}}return n===v.DOTIFY&&typeof s=="object"&&s!==null&&!Array.isArray(s)?{__type__:"dotify",__value__:be(s)}:Y(s,t)}function Oe(s,e,t,n,i,r){const o={...O,...e},a={};for(const[c,l]of Object.entries(s)){const d=o[c];a[c]=at(l,d,t,n,i,r)}return a}function at(s,e,t,n,i,r){if(ct(s))try{const o=decodeURIComponent(atob(s.__value__));return JSON.parse(o)}catch{return s}if(rt(s))try{return it(s.__value__)}catch{return s}return G(s,n,i,r)}function ct(s){return typeof s=="object"&&s!==null&&s.__type__==="base64"&&typeof s.__value__=="string"}function R(s,e="100%"){return s===void 0?e:typeof s=="number"?`${s}px`:s}function j(s,e){if(s===void 0)return e;if(typeof s=="number")return s;const t=parseInt(s,10);return isNaN(t)?e:t}function lt(s){try{s.src="about:blank",s.parentNode?.removeChild(s)}catch{}}function ht(s,e){ft(s,e)}function ut(s){s.style.display="",s.style.visibility="visible"}function Re(s){s.style.display="none",s.style.visibility="hidden"}function dt(s){try{s.focus(),s.contentWindow?.focus()}catch{}}function ft(s,e){e.width!==void 0&&(s.style.width=R(e.width)),e.height!==void 0&&(s.style.height=R(e.height))}class se extends Error{constructor(e="Popup blocked by browser"){super(e),this.name="PopupOpenError"}}function pt(s){const{url:e,name:t,dimensions:n}=s,i=j(n.width,500),r=j(n.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,t,c);if(!l||yt(l))throw new se;return l}function mt(s){try{s.closed||s.close()}catch{}}function gt(s){try{s.closed||s.focus()}catch{}}function yt(s){if(!s)return!0;try{return!!(s.closed||s.innerHeight===0||s.innerWidth===0)}catch{return!0}}function wt(s,e,t={}){const{initialInterval:n=100,maxInterval:i=2e3,multiplier:r=1.5}=t;let o=n,a,c=!1;const l=()=>{try{e()}catch(b){console.error("Error in popup close callback:",b)}},d=()=>{if(!c){try{if(s.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 _t(s,e){try{const t=j(e.width,s.outerWidth),n=j(e.height,s.outerHeight);s.resizeTo(t,n)}catch{}}function Et(s){const{doc:e,dimensions:t,uid:n,tag:i}=s,r=e.createElement("div");return r.id=`forgeframe-container-${n}`,r.setAttribute("data-forgeframe-tag",i),Object.assign(r.style,{display:"inline-block",position:"relative",width:R(t.width),height:R(t.height),overflow:"hidden"}),r}function bt(s){const{doc:e,dimensions:t,cspNonce:n}=s,i=e.createElement("div");Object.assign(i.style,{display:"flex",alignItems:"center",justifyContent:"center",width:R(t.width),height:R(t.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 n&&o.setAttribute("nonce",n),o.textContent=`
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"},v={JSON:"json",BASE64:"base64",DOTIFY:"dotify"},$={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"},H="__forgeframe__",J=(()=>{if("0.0.4".trim().length===0)throw new Error("ForgeFrame VERSION injection is missing. Configure __FORGEFRAME_VERSION__ in build/test tooling.");return"0.0.4"})();class le{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}once(e,t){const n=i=>(this.off(e,n),t(i));return this.on(e,n)}emit(e,t){const n=this.listeners.get(e);if(n)for(const i of n)try{const r=i(t);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,t){if(!t){this.listeners.delete(e);return}const n=this.listeners.get(e);n&&(n.delete(t),n.size===0&&this.listeners.delete(e))}removeAllListeners(){this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function Me(){const s=Date.now().toString(36),e=Math.random().toString(36).slice(2,11);return`${s}_${e}`}function L(){return Math.random().toString(36).slice(2,11)}class We{tasks=[];cleaned=!1;register(e){if(this.cleaned){try{e()}catch(t){console.error("Error in cleanup task:",t)}return}this.tasks.push(e)}async cleanup(){if(this.cleaned)return;this.cleaned=!0;const e=this.tasks.reverse();this.tasks=[];for(const t of e)try{await t()}catch(n){console.error("Error in cleanup task:",n)}}isCleaned(){return this.cleaned}reset(){this.tasks=[],this.cleaned=!1}}function ue(){let s,e;return{promise:new Promise((n,i)=>{s=n,e=i}),resolve:s,reject:e}}function ze(s,e,t="Operation timed out"){return new Promise((n,i)=>{const r=setTimeout(()=>{i(new Error(`${t} (${e}ms)`))},e);s.then(o=>{clearTimeout(r),n(o)}).catch(o=>{clearTimeout(r),i(o)})})}const X="forgeframe:";function K(s){return X+JSON.stringify(s)}function je(s){if(typeof s!="string"||!s.startsWith(X))return null;try{const e=s.slice(X.length),t=JSON.parse(e);return!t.id||!t.type||!t.name||!t.source?null:t}catch{return null}}function he(s,e,t,n){return{id:s,type:$.REQUEST,name:e,data:t,source:n}}function Be(s,e,t,n){return{id:s,type:$.RESPONSE,name:"response",data:e,source:t,error:n?{message:n.message,stack:n.stack}:void 0}}function Ve(s){return s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function qe(s){if(!s.includes("*"))return null;const e=s.split("*").map(t=>Ve(t)).join(".*");return new RegExp(`^${e}$`)}function Je(s,e){return s.global||s.sticky?new RegExp(s.source,s.flags.replace(/[gy]/g,"")).test(e):s.test(e)}class de{constructor(e,t=window,n=window.location.origin,i){this.uid=e,this.win=t,this.domain=n,this.allowedOrigins.add(n),i&&this.addTrustedDomain(i),this.setupListener()}pending=new Map;handlers=new Map;listener=null;destroyed=!1;allowedOrigins=new Set;allowedOriginPatterns=[];wildcardPatternRegistry=new Map;sourceUidRegistry=new WeakMap;addTrustedDomain(e){if(Array.isArray(e))for(const t of e)this.addTrustedDomain(t);else if(e instanceof RegExp)this.allowedOriginPatterns.push(e);else{const t=qe(e);t?this.wildcardPatternRegistry.has(e)||(this.wildcardPatternRegistry.set(e,t),this.allowedOriginPatterns.push(t)):this.allowedOrigins.add(e)}}removeTrustedDomain(e){if(Array.isArray(e))for(const t of e)this.removeTrustedDomain(t);else if(e instanceof RegExp)this.allowedOriginPatterns=this.allowedOriginPatterns.filter(t=>t!==e);else{const t=this.wildcardPatternRegistry.get(e);t&&(this.allowedOriginPatterns=this.allowedOriginPatterns.filter(n=>n!==t),this.wildcardPatternRegistry.delete(e)),this.allowedOrigins.delete(e)}}isOriginTrusted(e){if(this.allowedOrigins.has(e))return!0;for(const t of this.allowedOriginPatterns)if(Je(t,e))return!0;return!1}resolveVerifiedSource(e,t,n){const i=e,r=this.sourceUidRegistry.get(i);if(r)return{uid:r,domain:t};const o=n&&typeof n.uid=="string"&&n.uid.length>0?n.uid:L();return this.sourceUidRegistry.set(i,o),{uid:o,domain:t}}async send(e,t,n,i,r=1e4){if(this.destroyed)throw new Error("Messenger has been destroyed");const o=L(),a=he(o,n,i,{uid:this.uid,domain:this.domain}),c=ue(),l=setTimeout(()=>{this.pending.delete(o),c.reject(new Error(`Message "${n}" timed out after ${r}ms`))},r);this.pending.set(o,{deferred:c,timeout:l});try{e.postMessage(K(a),t)}catch(d){throw this.pending.delete(o),clearTimeout(l),d}return c.promise}post(e,t,n,i){if(this.destroyed)throw new Error("Messenger has been destroyed");const r=L(),o=he(r,n,i,{uid:this.uid,domain:this.domain});e.postMessage(K(o),t)}on(e,t){return this.handlers.set(e,t),()=>this.handlers.delete(e)}setupListener(){this.listener=e=>{if(e.source===this.win||!this.isOriginTrusted(e.origin))return;const t=je(e.data);if(!t)return;const n=e.source;!n||typeof n.postMessage!="function"||this.handleMessage(t,n,e.origin)},this.win.addEventListener("message",this.listener)}async handleMessage(e,t,n){if(e.type===$.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===$.REQUEST){const i=this.handlers.get(e.name);if(!i)return;let r,o;try{const c=this.resolveVerifiedSource(t,n,e.source);r=await i(e.data,c)}catch(c){o=c instanceof Error?c:new Error(String(c))}const a=Be(e.id,r,{uid:this.uid,domain:this.domain},o);try{t.postMessage(K(a),n)}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 fe=500;class Y{constructor(e){this.messenger=e,this.setupCallHandler()}localFunctions=new Map;remoteFunctions=new Map;currentBatchIds=new Set;serialize(e,t){if(this.localFunctions.size>=fe){const i=this.localFunctions.keys().next().value;i&&this.localFunctions.delete(i)}const n=L();return this.localFunctions.set(n,e),this.currentBatchIds.add(n),{__type__:"function",__id__:n,__name__:t||e.name||"anonymous"}}deserialize(e,t,n){const i=`${e.__id__}`,r=this.remoteFunctions.get(i);if(r)return r;if(this.remoteFunctions.size>=fe){const a=this.remoteFunctions.keys().next().value;a&&this.remoteFunctions.delete(a)}const o=async(...a)=>this.messenger.send(t,n,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:t})=>{const n=this.localFunctions.get(e);if(!n)throw new Error(`Function with id "${e}" not found`);return n(...t)})}removeLocal(e){this.localFunctions.delete(e)}startBatch(){this.currentBatchIds.clear()}finishBatch(e=!1){if(e){this.currentBatchIds.clear();return}for(const t of this.localFunctions.keys())this.currentBatchIds.has(t)||this.localFunctions.delete(t);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 Z(s,e,t=new WeakSet){if(typeof s=="function")return e.serialize(s);if(Array.isArray(s)){if(t.has(s))throw new Error("Circular reference detected in props - arrays cannot contain circular references");t.add(s);try{return s.map(n=>Z(n,e,t))}finally{t.delete(s)}}if(typeof s=="object"&&s!==null){if(t.has(s))throw new Error("Circular reference detected in props - objects cannot contain circular references");t.add(s);try{const n={};for(const[i,r]of Object.entries(s))n[i]=Z(r,e,t);return n}finally{t.delete(s)}}return s}function G(s,e,t,n,i=new WeakSet){if(Y.isFunctionRef(s))return e.deserialize(s,t,n);if(Array.isArray(s)){if(i.has(s))throw new Error("Circular reference detected in serialized props");i.add(s);try{return s.map(r=>G(r,e,t,n,i))}finally{i.delete(s)}}if(typeof s=="object"&&s!==null){if(i.has(s))throw new Error("Circular reference detected in serialized props");i.add(s);try{const r={};for(const[o,a]of Object.entries(s))r[o]=G(a,e,t,n,i);return r}finally{i.delete(s)}}return s}function Xe(s){return s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Ke(s){if(!s.includes("*"))return null;const e=s.split("*").map(t=>Xe(t)).join(".*");return new RegExp(`^${e}$`)}function Ye(s,e){return s.global||s.sticky?new RegExp(s.source,s.flags.replace(/[gy]/g,"")).test(e):s.test(e)}function Q(s=window){try{return s.location.origin}catch{return""}}function pe(s,e=window){try{return s.location.origin===e.location.origin}catch{return!1}}function I(s,e){if(typeof s=="string"){if(s==="*")return!0;const t=Ke(s);return t?t.test(e):s===e}return s instanceof RegExp?Ye(s,e):Array.isArray(s)?s.some(t=>I(t,e)):!1}function me(s){if(!s)return!0;try{return s.closed}catch{return!0}}function Ze(s=window){try{return s.opener}catch{return null}}function Ge(s=window){try{const e=s.parent;return e&&e!==s?e:null}catch{return null}}function Qe(s=window){try{return s.parent!==s}catch{return!0}}function et(s=window){try{return s.opener!==null&&s.opener!==void 0}catch{return!1}}const ge=32*1024;function tt(s){const e=st(s);return`${H}${e}`}function ye(s){if(!s||!s.startsWith(H))return null;const e=s.slice(H.length);return nt(e)}function ee(s=window){try{return s.name.startsWith(H)}catch{return!1}}function te(s,e=window){return ye(e.name)?.tag===s}function st(s){try{const e=JSON.stringify(s),t=btoa(encodeURIComponent(e)),n=new Blob([t]).size;if(n>ge)throw new Error(`Payload size (${Math.round(n/1024)}KB) exceeds maximum allowed size (${ge/1024}KB). Consider reducing the amount of data passed via props.`);return t}catch(e){throw e instanceof Error&&e.message.includes("Payload size")?e:new Error(`Failed to encode payload: ${e}`)}}function nt(s){try{const e=decodeURIComponent(atob(s));return JSON.parse(e)}catch{return null}}function it(s){return{uid:s.uid,tag:s.tag,version:J,context:s.context,consumerDomain:s.consumerDomain,props:s.props,exports:s.exports,children:s.children}}function rt(s=window){return ye(s.name)}const we=100,E=new Map;function ot(){const s=[];for(const[e,t]of E.entries())me(t)&&s.push(e);for(const e of s)E.delete(e)}function at(s,e){if(E.size>=we&&ot(),E.size>=we){const t=E.keys().next().value;t&&E.delete(t)}E.set(s,e)}function ct(s){E.delete(s)}function lt(s,e){return s.global||s.sticky?new RegExp(s.source,s.flags.replace(/[gy]/g,"")).test(e):s.test(e)}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 t=this._clone();return t._default=e,t}}class A extends g{_minLength;_maxLength;_pattern;_patternMessage;_trim=!1;_validate(e){if(typeof e!="string")return{issues:[{message:`Expected string, got ${typeof e}`}]};const t=this._trim?e.trim():e;return this._minLength!==void 0&&t.length<this._minLength?{issues:[{message:`String must be at least ${this._minLength} characters`}]}:this._maxLength!==void 0&&t.length>this._maxLength?{issues:[{message:`String must be at most ${this._maxLength} characters`}]}:this._pattern&&!lt(this._pattern,t)?{issues:[{message:this._patternMessage||`String must match pattern ${this._pattern}`}]}:{value:t}}_clone(){const e=new A;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 t=this._clone();return t._minLength=e,t}max(e){const t=this._clone();return t._maxLength=e,t}length(e){const t=this._clone();return t._minLength=e,t._maxLength=e,t}pattern(e,t){const n=this._clone();return n._pattern=e,n._patternMessage=t,n}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 k 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 k;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 t=this._clone();return t._min=e,t}max(e){const t=this._clone();return t._max=e,t}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 U extends g{_validate(e){return typeof e!="boolean"?{issues:[{message:`Expected boolean, got ${typeof e}`}]}:{value:e}}_clone(){const e=new U;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class M extends g{_validate(e){return typeof e!="function"?{issues:[{message:`Expected function, got ${typeof e}`}]}:{value:e}}_clone(){const e=new M;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class D 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 t=[];for(let n=0;n<e.length;n++){const i=this._itemSchema["~standard"].validate(e[n]);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:[n,...r.path||[]]}))};t.push(i.value)}return{value:t}}return{value:e}}_clone(){const e=new D;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 t=new D;return t._optional=this._optional,t._nullable=this._nullable,t._itemSchema=e,t._minLength=this._minLength,t._maxLength=this._maxLength,t}min(e){const t=this._clone();return t._minLength=e,t}max(e){const t=this._clone();return t._maxLength=e,t}nonempty(){return this.min(1)}}class C 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 t=e,n={};if(this._shape){if(this._strict){const i=new Set(Object.keys(this._shape));for(const r of Object.keys(t))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(t[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||[]]}))};n[i]=o.value}if(!this._strict)for(const i of Object.keys(t))i in this._shape||(n[i]=t[i]);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._shape=this._shape,e._strict=this._strict,e}shape(e){const t=new C;return t._optional=this._optional,t._nullable=this._nullable,t._shape=e,t._strict=this._strict,t}strict(){const e=this._clone();return e._strict=!0,e}}class W 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 W(this._value);return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class z 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(t=>JSON.stringify(t)).join(", ")}], got ${JSON.stringify(e)}`}]}}_clone(){const e=new z(this._values);return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}class j extends g{constructor(){super(),this._nullable=!0}_validate(e){return{value:e}}_clone(){const e=new j;return e._optional=this._optional,e._nullable=this._nullable,e._default=this._default,e}}const f={string:()=>new A,number:()=>new k,boolean:()=>new U,function:()=>new M,array:()=>new D,object:()=>new C,literal:s=>new W(s),enum:s=>new z(s),any:()=>new j},R={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 w(s){return typeof s=="object"&&s!==null&&"~standard"in s&&typeof s["~standard"]=="object"&&s["~standard"]!==null&&s["~standard"].version===1&&typeof s["~standard"].vendor=="string"&&typeof s["~standard"].validate=="function"}function ut(s,e,t){const n=s["~standard"].validate(e);if(n instanceof Promise)throw new Error(`Prop "${t}" 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(n.issues){const i=n.issues.map(r=>`${ht(r.path,t)}: ${r.message}`);throw new Error(`Validation failed: ${i.join("; ")}`)}return n.value}function ht(s,e){if(!s||s.length===0)return e;const t=s.map(n=>{if(typeof n=="object"&&n!==null){if("key"in n&&n.key!==void 0)return String(n.key);if("index"in n&&typeof n.index=="number")return String(n.index)}return String(n)});return`${e}.${t.join(".")}`}function _e(s,e,t){const n={...R,...e},i={};for(const[r,o]of Object.entries(n)){const c=w(o)?{schema:o}:o;let l;const d=c.alias,b=r in s,P=d&&d in s;if(b)l=s[r];else if(P)l=s[d];else if(c.value)l=c.value(t);else if(c.default!==void 0)l=typeof c.default=="function"?c.default(t):c.default;else if(c.schema&&w(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 Ee(s,e){const t={...R,...e};for(const[n,i]of Object.entries(t)){const r=w(i),o=r?{schema:i}:i;let a=s[n];if(o.required&&a===void 0)throw new Error(`Prop "${n}" is required but was not provided`);if(o.schema&&w(o.schema))(a!==void 0||r)&&(a=ut(o.schema,a,n),s[n]=a);else if(a===void 0)continue;o.validate&&o.validate({value:a,props:s})}}function be(s,e,t,n){const i={...R,...e},r={};for(const[o,a]of Object.entries(i)){const l=w(a)?{schema:a}:a,d=s[o];if(l.sendToHost===!1||l.sameDomain&&!n)continue;if(l.trustedDomains){const P=l.trustedDomains;if(!I(P,t))continue}let b=d;l.hostDecorate&&d!==void 0&&(b=l.hostDecorate({value:d,props:s})),r[o]=b}return r}function dt(s,e){const t=new URLSearchParams,n={...R,...e};for(const[i,r]of Object.entries(n)){const a=w(r)?{schema:r}:r,c=s[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),t.set(l,d)}return t}function ft(s,e){const t=new URLSearchParams,n={...R,...e};for(const[i,r]of Object.entries(n)){const a=w(r)?{schema:r}:r,c=s[i];if(c===void 0||typeof c=="function"||!a.bodyParam)continue;const l=typeof a.bodyParam=="string"?a.bodyParam:i;let d;typeof a.bodyParam=="function"?d=a.bodyParam({value:c}):typeof c=="object"?d=JSON.stringify(c):d=String(c),t.set(l,d)}return t}function Pe(s,e=""){const t=[];for(const[n,i]of Object.entries(s)){const r=e?`${e}.${n}`:n;if(i!==null&&typeof i=="object"&&!Array.isArray(i))t.push(Pe(i,r));else{const o=encodeURIComponent(JSON.stringify(i));t.push(`${r}=${o}`)}}return t.filter(Boolean).join("&")}function pt(s){const e={};if(!s)return e;const t=s.split("&");for(const n of t){const[i,r]=n.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 mt(s){return typeof s=="object"&&s!==null&&s.__type__==="dotify"&&typeof s.__value__=="string"}function Re(s,e,t){const n={...R,...e},i={};for(const[r,o]of Object.entries(s)){if(o===void 0)continue;const a=n[r];i[r]=gt(o,a,t)}return i}function gt(s,e,t){if(typeof s=="function")return t.serialize(s);const n=e?.serialization??v.JSON;if(n===v.BASE64&&typeof s=="object"){const i=JSON.stringify(s);return{__type__:"base64",__value__:btoa(encodeURIComponent(i))}}return n===v.DOTIFY&&typeof s=="object"&&s!==null&&!Array.isArray(s)?{__type__:"dotify",__value__:Pe(s)}:Z(s,t)}function Oe(s,e,t,n,i,r){const o={...R,...e},a={};for(const[c,l]of Object.entries(s)){const d=o[c];a[c]=yt(l,d,t,n,i,r)}return a}function yt(s,e,t,n,i,r){if(wt(s))try{const o=decodeURIComponent(atob(s.__value__));return JSON.parse(o)}catch{return s}if(mt(s))try{return pt(s.__value__)}catch{return s}return G(s,n,i,r)}function wt(s){return typeof s=="object"&&s!==null&&s.__type__==="base64"&&typeof s.__value__=="string"}function O(s,e="100%"){return s===void 0?e:typeof s=="number"?`${s}px`:s}function B(s,e){if(s===void 0)return e;if(typeof s=="number")return s;const t=parseInt(s,10);return isNaN(t)?e:t}function _t(s){try{s.src="about:blank",s.parentNode?.removeChild(s)}catch{}}function Et(s,e){Rt(s,e)}function bt(s){s.style.display="",s.style.visibility="visible"}function Se(s){s.style.display="none",s.style.visibility="hidden"}function Pt(s){try{s.focus(),s.contentWindow?.focus()}catch{}}function Rt(s,e){e.width!==void 0&&(s.style.width=O(e.width)),e.height!==void 0&&(s.style.height=O(e.height))}class se extends Error{constructor(e="Popup blocked by browser"){super(e),this.name="PopupOpenError"}}function Ot(s){const{url:e,name:t,dimensions:n}=s,i=B(n.width,500),r=B(n.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,t,c);if(!l||It(l))throw new se;return l}function St(s){try{s.closed||s.close()}catch{}}function vt(s){try{s.closed||s.focus()}catch{}}function It(s){if(!s)return!0;try{return!!(s.closed||s.innerHeight===0||s.innerWidth===0)}catch{return!0}}function Dt(s,e,t={}){const{initialInterval:n=100,maxInterval:i=2e3,multiplier:r=1.5}=t;let o=n,a,c=!1;const l=()=>{try{e()}catch(b){console.error("Error in popup close callback:",b)}},d=()=>{if(!c){try{if(s.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 Ct(s,e){try{const t=B(e.width,s.outerWidth),n=B(e.height,s.outerHeight);s.resizeTo(t,n)}catch{}}const ve="forgeframe-spinner-style";function xt(s,e){const t=s.getElementById(ve);if(t){const i=t.getAttribute("nonce");if(!e||i===e)return;t.remove()}const n=s.createElement("style");n.id=ve,e&&n.setAttribute("nonce",e),n.textContent=`
2
2
  @keyframes forgeframe-spin {
3
3
  to { transform: rotate(360deg); }
4
4
  }
5
- `,i.appendChild(o),i.appendChild(r),i}function Pt(s,e=200){return new Promise(t=>{s.style.opacity="0",s.style.transition=`opacity ${e}ms ease-in`,s.offsetHeight,s.style.opacity="1",setTimeout(t,e)})}function Ot(s,e=200){return new Promise(t=>{s.style.transition=`opacity ${e}ms ease-out`,s.style.opacity="0",setTimeout(t,e)})}async function Rt(s,e,t){e&&(await Ot(e,150),e.remove()),t.style.display="",t.style.visibility="visible",t.style.opacity="0",await Pt(t,150)}class ne{event;state={};exports;consumerExports;_uid;get uid(){return this._uid}options;props;context;messenger;bridge;cleanup;hostWindow=null;openedHostDomain=null;dynamicUrlTrustedOrigin=null;iframe=null;container=null;prerenderElement=null;initPromise=null;rendered=!1;destroyed=!1;constructor(e,t={}){this._uid=He(),this.options=this.normalizeOptions(e),this.context=this.options.defaultContext,this.event=new le,this.cleanup=new Ae;const n=this.createPropContext();this.props=_e(t,this.options.props,n);const i=this.buildTrustedDomains();this.messenger=new de(this.uid,window,Q(),i),this.bridge=new Z(this.messenger),this.setupMessageHandlers(),this.setupCleanup()}buildTrustedDomains(){const e=[],t=this.resolveUrlOrigin(this.resolveUrl());if(t&&(e.push(t),this.dynamicUrlTrustedOrigin=t),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,t){if(this.destroyed)throw new Error("Component has been destroyed");if(this.rendered)throw new Error("Component has already been rendered");this.context=t??this.options.defaultContext,this.checkEligibility(),st(this.props,this.options.props),this.options.validate?.({props:this.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 Rt(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,t,n){return this.render(t,n)}async close(){this.destroyed||(this.event.emit(m.CLOSE),await this.destroy())}async focus(){this.context===p.IFRAME&&this.iframe?dt(this.iframe):this.context===p.POPUP&&this.hostWindow&&gt(this.hostWindow),this.event.emit(m.FOCUS),this.callPropCallback("onFocus")}async resize(e){this.context===p.IFRAME&&this.iframe?ht(this.iframe,e):this.context===p.POPUP&&this.hostWindow&&_t(this.hostWindow,e),this.event.emit(m.RESIZE,e),this.callPropCallback("onResize",e)}async show(){this.context===p.IFRAME&&this.iframe&&ut(this.iframe)}async hide(){this.context===p.IFRAME&&this.iframe&&Re(this.iframe)}async updateProps(e){const t=this.createPropContext(),n=_e({...this.props,...e},this.options.props,t);this.options.validate?.({props:n});const i=this.resolveUrl(n),r=this.resolveUrlOrigin(i);if(this.rendered&&this.openedHostDomain&&r&&r!==this.openedHostDomain)throw new Error(`Cannot change component URL origin after render (from "${this.openedHostDomain}" to "${r}")`);if(this.props=n,this.rendered||this.syncTrustedDomainForUrl(i),this.hostWindow&&!me(this.hostWindow)){const o=this.openedHostDomain??this.getHostDomain(),a=Ee(n,this.options.props,o,pe(this.hostWindow)),c=Pe(a,this.options.props,this.bridge);await this.messenger.send(this.hostWindow,o,u.PROPS,c)}this.event.emit(m.PROPS,this.props),this.callPropCallback("onProps",this.props)}clone(){return new ne(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:e.dimensions??{width:"100%",height:"100%"},timeout:e.timeout??1e4,children:e.children}}resolveUrl(e=this.props){return typeof this.options.url=="function"?this.options.url(e):this.options.url}resolveDimensions(){return typeof this.options.dimensions=="function"?this.options.dimensions(this.props):this.options.dimensions}resolveUrlOrigin(e){try{return new URL(e,window.location.origin).origin}catch{return null}}isExplicitDomainTrust(e){return!this.options.domain||this.options.domain instanceof RegExp?!1:typeof this.options.domain=="string"?this.options.domain===e:this.options.domain.includes(e)}syncTrustedDomainForUrl(e){const t=this.resolveUrlOrigin(e);if(!t)return;const n=this.dynamicUrlTrustedOrigin;n&&n!==t&&!this.isExplicitDomainTrust(n)&&this.messenger.removeTrustedDomain(n),this.messenger.addTrustedDomain(t),this.dynamicUrlTrustedOrigin=t}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 t=document.querySelector(e);if(!t)throw new Error(`Container "${e}" not found`);return t}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??bt,t=this.options.containerTemplate??Et,n=this.resolveDimensions(),i=this.props.cspNonce;if(this.context===p.IFRAME){const c=this.buildWindowName();this.iframe=this.createIframeElement(c),Re(this.iframe)}const r={uid:this.uid,tag:this.options.tag,context:this.context,dimensions:n,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:n,props:this.props,doc:document,container:this.container,frame:this.iframe,prerenderFrame:this.prerenderElement,close:()=>this.close(),focus:()=>this.focus(),cspNonce:i},a=t(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 t=document.createElement("iframe"),n=this.resolveDimensions(),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??{};t.name=e,t.setAttribute("frameborder","0"),t.setAttribute("allowtransparency","true"),t.setAttribute("scrolling","auto"),n.width!==void 0&&(t.style.width=typeof n.width=="number"?`${n.width}px`:n.width),n.height!==void 0&&(t.style.height=typeof n.height=="number"?`${n.height}px`:n.height);for(const[o,a]of Object.entries(i))a!==void 0&&(typeof a=="boolean"?a&&t.setAttribute(o,""):t.setAttribute(o,a));for(const[o,a]of Object.entries(r)){if(a===void 0)continue;const c=typeof a=="number"?`${a}px`:a;t.style.setProperty(o.replace(/([A-Z])/g,"-$1").toLowerCase(),String(c))}return i.sandbox||t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"),t}async open(){const e=this.resolveUrl();this.syncTrustedDomainForUrl(e),this.openedHostDomain=this.resolveUrlOrigin(e);const t=this.buildUrl(e);if(this.context===p.IFRAME){if(!this.iframe)throw new Error("Iframe not created during prerender");this.iframe.src=t,this.hostWindow=this.iframe.contentWindow}else{const n=this.buildWindowName();this.hostWindow=pt({url:t,name:n,dimensions:this.resolveDimensions()});const i=wt(this.hostWindow,()=>{this.destroy()});this.cleanup.register(i)}this.hostWindow&&Ge(this.uid,this.hostWindow)}buildUrl(e=this.resolveUrl()){const n=nt(this.props,this.options.props).toString();if(!n)return e;const i=e.includes("?")?"&":"?";return`${e}${i}${n}`}buildWindowName(){const e=this.getHostDomain(),t=Ee(this.props,this.options.props,e,!1),n=Pe(t,this.options.props,this.bridge),i=this.buildNestedHostRefs(),r=Ke({uid:this.uid,tag:this.options.tag,context:this.context,consumerDomain:Q(),props:n,exports:this.createConsumerExports(),children:i});return qe(r)}buildNestedHostRefs(){if(!this.options.children)return;const e=this.options.children({props:this.props}),t={};for(const[n,i]of Object.entries(e)){const r=Dt(i);if(!r)throw new Error(`Nested component "${n}" is missing component metadata`);if(typeof r.url!="string")throw new Error(`Nested component "${n}" must use a static string URL. Function URLs are not supported in children.`);t[n]={tag:r.tag,url:r.url,props:r.props,dimensions:typeof r.dimensions=="function"?void 0:r.dimensions,defaultContext:r.defaultContext}}return Object.keys(t).length>0?t:void 0}createConsumerExports(){return{init:u.INIT,close:u.CLOSE,resize:u.RESIZE,show:u.SHOW,hide:u.HIDE,onError:u.ERROR,updateProps:u.PROPS,export:u.EXPORT}}getHostDomain(){return this.openedHostDomain?this.openedHostDomain:this.resolveUrlOrigin(this.resolveUrl())??"*"}async waitForHost(){this.initPromise=he();try{await Ue(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(u.INIT,()=>(this.initPromise&&this.initPromise.resolve(),{success:!0})),this.messenger.on(u.CLOSE,async()=>(await this.close(),{success:!0})),this.messenger.on(u.RESIZE,async e=>(await this.resize(e),{success:!0})),this.messenger.on(u.FOCUS,async()=>(await this.focus(),{success:!0})),this.messenger.on(u.SHOW,async()=>(await this.show(),{success:!0})),this.messenger.on(u.HIDE,async()=>(await this.hide(),{success:!0})),this.messenger.on(u.ERROR,async e=>{const t=new Error(e.message);return t.stack=e.stack,this.handleError(t),{success:!0}}),this.messenger.on(u.EXPORT,async e=>(this.exports=e,{success:!0})),this.messenger.on(u.CONSUMER_EXPORT,async e=>(this.consumerExports=e,{success:!0})),this.messenger.on(u.GET_SIBLINGS,async e=>{const t=[],n=It(e.tag);if(n)for(const i of n.instances)i.uid!==e.uid&&t.push({uid:i.uid,tag:e.tag,exports:i.exports});return t})}setupCleanup(){this.cleanup.register(()=>{this.messenger.destroy(),this.bridge.destroy(),Qe(this.uid)})}handleError(e){this.event.emit(m.ERROR,e),this.callPropCallback("onError",e)}callPropCallback(e,...t){const n=this.props[e];if(typeof n=="function")try{const i=n(...t);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&&(lt(this.iframe),this.iframe=null),this.context===p.POPUP&&this.hostWindow&&mt(this.hostWindow),this.hostWindow=null,this.openedHostDomain=null,this.dynamicUrlTrustedOrigin=null,this.prerenderElement&&(this.prerenderElement.remove(),this.prerenderElement=null),await this.cleanup.cleanup(),this.event.emit(m.DESTROY),this.callPropCallback("onDestroy"),this.event.removeAllListeners())}}class St{constructor(e,t={},n,i=!1){this.propDefinitions=t,this.allowedConsumerDomains=n,this.deferInit=i,this.uid=e.uid,this.tag=e.tag,this.consumerDomain=e.consumerDomain,this.validateConsumerDomain(),this.event=new le,this.messenger=new de(this.uid,window,Q(),this.consumerDomain),this.setupMessageHandlers(),this.consumerWindow=this.resolveConsumerWindow(),this.bridge=new Z(this.messenger),this.hostProps=this.buildHostProps(e),this.exposeHostProps(),this.deferInit||this.flushInit()}hostProps;event;uid;tag;consumerWindow;consumerDomain;messenger;bridge;propsHandlers=new Set;consumerProps;initError=null;destroyed=!1;initSent=!1;deferredInitFlushScheduled=!1;flushInit(){this.destroyed||this.initSent||(this.initSent=!0,this.sendInit())}scheduleDeferredInitFlush(){this.deferredInitFlushScheduled||this.destroyed||this.initSent||(this.deferredInitFlushScheduled=!0,queueMicrotask(()=>{this.deferredInitFlushScheduled=!1,this.flushInit()}))}exposeHostProps(){const e=window;try{Object.defineProperty(e,"hostProps",{configurable:!0,enumerable:!0,get:()=>(this.deferInit&&!this.initSent&&!this.destroyed&&this.scheduleDeferredInitFlush(),this.hostProps),set:t=>{t&&(this.hostProps=t)}})}catch{e.hostProps=this.hostProps}}validateConsumerDomain(){if(this.allowedConsumerDomains&&!k(this.allowedConsumerDomains,this.consumerDomain))throw new Error(`Consumer domain "${this.consumerDomain}" is not allowed for component "${this.tag}"`)}getProps(){return this.hostProps}resolveConsumerWindow(){if(Be()){const e=je();if(e)return e}if(Ve()){const e=ze();if(e)return e}throw new Error("Could not resolve consumer window")}buildHostProps(e){const t=Oe(e.props,this.propDefinitions,this.messenger,this.bridge,this.consumerWindow,this.consumerDomain);return this.consumerProps=t,{...t,uid:this.uid,tag:this.tag,close:()=>this.close(),focus:()=>this.focus(),resize:n=>this.resize(n),show:()=>this.show(),hide:()=>this.hide(),onProps:n=>this.onProps(n),onError:n=>this.onError(n),getConsumer:()=>this.consumerWindow,getConsumerDomain:()=>this.consumerDomain,export:n=>this.exportData(n),consumer:{props:this.consumerProps,export:n=>this.consumerExport(n)},getPeerInstances:n=>this.getPeerInstances(n),children:this.buildNestedComponents(e.children)}}async sendInit(){try{await this.messenger.send(this.consumerWindow,this.consumerDomain,u.INIT,{uid:this.uid,tag:this.tag})}catch(e){const t=e instanceof Error?e:new Error(String(e));this.initError=t,this.event.emit(m.ERROR,{type:"init_failed",message:`Failed to initialize host component: ${t.message}`,error:t}),console.error("Failed to send init message:",e)}}getInitError(){return this.initError}async close(){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.CLOSE,{})}async focus(){window.focus(),await this.messenger.send(this.consumerWindow,this.consumerDomain,u.FOCUS,{})}async resize(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.RESIZE,e)}async show(){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.SHOW,{})}async hide(){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.HIDE,{})}onProps(e){return this.propsHandlers.add(e),{cancel:()=>this.propsHandlers.delete(e)}}async onError(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.ERROR,{message:e.message,stack:e.stack})}async exportData(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.EXPORT,e)}async consumerExport(e){await this.messenger.send(this.consumerWindow,this.consumerDomain,u.CONSUMER_EXPORT,e)}async getPeerInstances(e){return await this.messenger.send(this.consumerWindow,this.consumerDomain,u.GET_SIBLINGS,{uid:this.uid,tag:this.tag,options:e})??[]}buildNestedComponents(e){if(!e)return;const t={};for(const[n,i]of Object.entries(e))try{t[n]=ie({tag:i.tag,url:i.url,props:i.props,dimensions:i.dimensions,defaultContext:i.defaultContext})}catch(r){console.warn(`Failed to create nested component "${n}":`,r)}return Object.keys(t).length>0?t:void 0}setupMessageHandlers(){this.messenger.on(u.PROPS,e=>{try{const t=Oe(e,this.propDefinitions,this.messenger,this.bridge,this.consumerWindow,this.consumerDomain);Object.assign(this.hostProps,t);for(const n of this.propsHandlers)try{n(t)}catch(i){console.error("Error in props handler:",i)}return this.event.emit(m.PROPS,t),{success:!0}}catch(t){const n=t instanceof Error?t:new Error(String(t));throw console.error("Error deserializing props:",n),this.event.emit(m.ERROR,n),n}})}destroy(){this.destroyed||(this.destroyed=!0,this.deferredInitFlushScheduled=!1,this.messenger.destroy(),this.bridge.destroy(),this.event.removeAllListeners(),this.propsHandlers.clear())}}let w=null;function B(s,e,t={}){if(w){if(e){const i=w.getProps().getConsumerDomain();if(!k(e,i))throw vt(),new Error(`Consumer domain "${i}" is not allowed for this host component`)}return t.deferInit||w.flushInit(),w}if(!ee())return null;const n=Ze();return n?(w=new St(n,s,e,t.deferInit??!1),w):(console.error("Failed to parse ForgeFrame payload from window.name"),null)}function Se(){return ee()}function ve(){return ee()}function Ce(){return window.hostProps}function vt(){w&&(w.destroy(),w=null),delete window.hostProps}const D=new Map,Ie=Symbol("forgeframe.component.options");function Ct(s){if(!s.tag)throw new Error("Component tag is required");if(!/^[a-z][a-z0-9-]*$/.test(s.tag))throw new Error(`Invalid component tag "${s.tag}". Must start with lowercase letter and contain only lowercase letters, numbers, and hyphens.`);if(!s.url)throw new Error("Component url is required");if(typeof s.url=="string")try{new URL(s.url,window.location.origin)}catch{throw new Error(`Invalid component URL "${s.url}". Must be a valid absolute or relative URL.`)}if(D.has(s.tag))throw new Error(`Component "${s.tag}" is already registered`)}function ie(s){Ct(s);const e=[];let t;if(te(s.tag)){const i=B(s.props,s.allowedConsumerDomains);i&&(t=i.hostProps)}const n=function(i={}){const r=new ne(s,i);return e.push(r),r.event.once("destroy",()=>{const o=e.indexOf(r);o!==-1&&e.splice(o,1)}),r};return n.instances=e,n.isHost=()=>te(s.tag),n.isEmbedded=()=>te(s.tag),n.hostProps=t,n[Ie]=s,n.canRenderTo=async i=>{try{return!!(pe(i)||s.domain)}catch{return!1}},D.set(s.tag,n),n}function It(s){return D.get(s)}function Dt(s){return s[Ie]}async function De(s){await s.close()}async function re(s){const e=D.get(s);if(!e)return;const t=[...e.instances];await Promise.all(t.map(n=>n.close()))}async function xe(){const s=Array.from(D.keys());await Promise.all(s.map(e=>re(e)))}function xt(s,e){const t=Object.keys(s),n=Object.keys(e);if(t.length!==n.length)return!1;for(const i of t)if(!Object.prototype.hasOwnProperty.call(e,i)||!Object.is(s[i],e[i]))return!1;return!0}function Te(s,e){const{React:t}=e,{createElement:n,useRef:i,useEffect:r,useState:o,forwardRef:a}=t,c=a(function(b,P){const{onRendered:S,onError:x,onClose:Fe,context:Nt,className:$e,style:ke,...oe}=b,V=i(null),ae=i(null),ce=i(null),[Le,Ft]=o(null);return r(()=>{const T=V.current;if(!T)return;const y=s(oe);return ae.current=y,S&&y.event.once("rendered",S),Fe&&y.event.once("close",Fe),x&&y.event.on("error",x),y.render(T,Nt).catch(N=>{Ft(N),x?.(N)}),()=>{y.close().catch(()=>{}),ae.current=null,ce.current=null}},[]),r(()=>{const T=ae.current;if(!T)return;const y=oe,N=ce.current;N&&xt(N,y)||(ce.current=y,T.updateProps(y).catch($t=>{x?.($t)}))},[oe,x]),r(()=>{P&&typeof P=="object"&&V.current&&(P.current=V.current)},[P]),Le?n("div",{className:$e,style:{color:"red",padding:"16px",...ke}},`Error: ${Le.message}`):n("div",{ref:V,className:$e,style:{display:"inline-block",...ke}})}),l=`ForgeFrame(${s.name||"Component"})`;return c.displayName=l,c}function Tt(s){return function(t){return Te(t,{React:s})}}B(void 0,void 0,{deferInit:!0});const Ne={create:ie,destroy:De,destroyByTag:re,destroyAll:xe,isHost:Se,isEmbedded:ve,getHostProps:Ce,initHost:B,PROP_SERIALIZATION:v,CONTEXT:p,EVENT:m,PopupOpenError:se,VERSION:q,isStandardSchema:E,prop:f};h.AnySchema=z,h.ArraySchema=C,h.BooleanSchema=A,h.CONTEXT=p,h.EVENT=m,h.EnumSchema=W,h.ForgeFrame=Ne,h.FunctionSchema=U,h.LiteralSchema=M,h.NumberSchema=H,h.ObjectSchema=I,h.PROP_SERIALIZATION=v,h.PopupOpenError=se,h.PropSchema=g,h.StringSchema=L,h.VERSION=q,h.create=ie,h.createReactComponent=Te,h.default=Ne,h.destroy=De,h.destroyAll=xe,h.destroyByTag=re,h.getHostProps=Ce,h.initHost=B,h.isEmbedded=ve,h.isHost=Se,h.isStandardSchema=E,h.prop=f,h.withReactComponent=Tt,Object.defineProperties(h,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
5
+ `,(s.head??s.documentElement).appendChild(n)}function Tt(s){const{doc:e,dimensions:t,uid:n,tag:i}=s,r=e.createElement("div");return r.id=`forgeframe-container-${n}`,r.setAttribute("data-forgeframe-tag",i),Object.assign(r.style,{display:"inline-block",position:"relative",width:O(t.width),height:O(t.height),overflow:"hidden"}),r}function Nt(s){const{doc:e,dimensions:t,cspNonce:n}=s;xt(e,n);const i=e.createElement("div");Object.assign(i.style,{display:"flex",alignItems:"center",justifyContent:"center",width:O(t.width),height:O(t.height),backgroundColor:"#f5f5f5",position:"absolute",top:"0",left:"0",zIndex:"100"});const r=e.createElement("div");return Object.assign(r.style,{width:"40px",height:"40px",border:"3px solid #e0e0e0",borderTopColor:"#3498db",borderRadius:"50%",animation:"forgeframe-spin 1s linear infinite"}),i.appendChild(r),i}function Ft(s,e=200){return new Promise(t=>{s.style.opacity="0",s.style.transition=`opacity ${e}ms ease-in`,s.offsetHeight,s.style.opacity="1",setTimeout(t,e)})}function $t(s,e=200){return new Promise(t=>{s.style.transition=`opacity ${e}ms ease-out`,s.style.opacity="0",setTimeout(t,e)})}async function Ht(s,e,t){e&&(await $t(e,150),e.remove()),t.style.display="",t.style.visibility="visible",t.style.opacity="0",await Ft(t,150)}class ne{event;state={};exports;consumerExports;_uid;get uid(){return this._uid}options;props;context;messenger;bridge;cleanup;hostWindow=null;openedHostDomain=null;dynamicUrlTrustedOrigin=null;iframe=null;container=null;prerenderElement=null;initPromise=null;hostInitialized=!1;rendered=!1;destroyed=!1;constructor(e,t={}){this._uid=Me(),this.options=this.normalizeOptions(e),this.context=this.options.defaultContext,this.event=new le,this.cleanup=new We;const n=this.createPropContext();this.props=_e(t,this.options.props,n);const i=this.buildTrustedDomains();this.messenger=new de(this.uid,window,Q(),i),this.bridge=new Y(this.messenger),this.setupMessageHandlers(),this.setupCleanup()}buildTrustedDomains(){const e=[],t=this.resolveUrlOrigin(this.resolveUrl());if(t&&(e.push(t),this.dynamicUrlTrustedOrigin=t),this.options.domain&&(typeof this.options.domain=="string"?e.push(this.options.domain):Array.isArray(this.options.domain)?e.push(...this.options.domain):this.options.domain instanceof RegExp&&e.push(this.options.domain)),e.length!==0)return e.length===1?e[0]:e}async render(e,t){if(this.destroyed)throw new Error("Component has been destroyed");if(this.rendered)throw new Error("Component has already been rendered");this.context=t??this.options.defaultContext,this.checkEligibility(),Ee(this.props,this.options.props),this.options.validate?.({props:this.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");try{await this.open(),await this.waitForHost(),this.context===p.IFRAME&&this.iframe&&this.prerenderElement&&(await Ht(this.container,this.prerenderElement,this.iframe),this.prerenderElement=null)}catch(n){throw await this.destroy().catch(()=>{}),n}this.rendered=!0,this.event.emit(m.RENDERED),this.callPropCallback("onRendered"),this.event.emit(m.DISPLAY),this.callPropCallback("onDisplay")}async renderTo(e,t,n){return this.render(t,n)}async close(){this.destroyed||(this.event.emit(m.CLOSE),await this.destroy())}async focus(){this.context===p.IFRAME&&this.iframe?Pt(this.iframe):this.context===p.POPUP&&this.hostWindow&&vt(this.hostWindow),this.event.emit(m.FOCUS),this.callPropCallback("onFocus")}async resize(e){this.context===p.IFRAME&&this.iframe?Et(this.iframe,e):this.context===p.POPUP&&this.hostWindow&&Ct(this.hostWindow,e),this.event.emit(m.RESIZE,e),this.callPropCallback("onResize",e)}async show(){this.context===p.IFRAME&&this.iframe&&bt(this.iframe)}async hide(){this.context===p.IFRAME&&this.iframe&&Se(this.iframe)}async updateProps(e){const t=this.createPropContext(),n=_e({...this.props,...e},this.options.props,t);Ee(n,this.options.props),this.options.validate?.({props:n});const i=this.resolveUrl(n),r=this.resolveUrlOrigin(i);if(this.rendered&&this.openedHostDomain&&r&&r!==this.openedHostDomain)throw new Error(`Cannot change component URL origin after render (from "${this.openedHostDomain}" to "${r}")`);if(this.props=n,this.rendered||this.syncTrustedDomainForUrl(i),this.hostWindow&&!me(this.hostWindow)){const o=this.openedHostDomain??this.getHostDomain(),a=be(n,this.options.props,o,pe(this.hostWindow)),c=Re(a,this.options.props,this.bridge);await this.messenger.send(this.hostWindow,o,h.PROPS,c)}this.event.emit(m.PROPS,this.props),this.callPropCallback("onProps",this.props)}clone(){return new ne(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:e.dimensions??{width:"100%",height:"100%"},timeout:e.timeout??1e4,children:e.children}}resolveUrl(e=this.props){return typeof this.options.url=="function"?this.options.url(e):this.options.url}resolveDimensions(){return typeof this.options.dimensions=="function"?this.options.dimensions(this.props):this.options.dimensions}resolveUrlOrigin(e){try{return new URL(e,window.location.origin).origin}catch{return null}}isExplicitDomainTrust(e){return this.options.domain?I(this.options.domain,e):!1}syncTrustedDomainForUrl(e){const t=this.resolveUrlOrigin(e);if(!t)return;const n=this.dynamicUrlTrustedOrigin;n&&n!==t&&!this.isExplicitDomainTrust(n)&&this.messenger.removeTrustedDomain(n),this.messenger.addTrustedDomain(t),this.dynamicUrlTrustedOrigin=t}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 t=document.querySelector(e);if(!t)throw new Error(`Container "${e}" not found`);return t}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??Nt,t=this.options.containerTemplate??Tt,n=this.resolveDimensions(),i=this.props.cspNonce;if(this.context===p.IFRAME){const c=this.buildWindowName();this.iframe=this.createIframeElement(c),Se(this.iframe)}const r={uid:this.uid,tag:this.options.tag,context:this.context,dimensions:n,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:n,props:this.props,doc:document,container:this.container,frame:this.iframe,prerenderFrame:this.prerenderElement,close:()=>this.close(),focus:()=>this.focus(),cspNonce:i},a=t(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 t=document.createElement("iframe"),n=this.resolveDimensions(),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??{};t.name=e,t.setAttribute("frameborder","0"),t.setAttribute("allowtransparency","true"),t.setAttribute("scrolling","auto"),n.width!==void 0&&(t.style.width=typeof n.width=="number"?`${n.width}px`:n.width),n.height!==void 0&&(t.style.height=typeof n.height=="number"?`${n.height}px`:n.height);for(const[o,a]of Object.entries(i))a!==void 0&&(typeof a=="boolean"?a&&t.setAttribute(o,""):t.setAttribute(o,a));for(const[o,a]of Object.entries(r)){if(a===void 0)continue;const c=typeof a=="number"?`${a}px`:a;t.style.setProperty(o.replace(/([A-Z])/g,"-$1").toLowerCase(),String(c))}return i.sandbox||t.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"),t}async open(){const e=this.resolveUrl();this.syncTrustedDomainForUrl(e),this.openedHostDomain=this.resolveUrlOrigin(e);const t=this.buildUrl(e),n=this.buildBodyParams(),i=n.toString().length>0;if(this.context===p.IFRAME){if(!this.iframe)throw new Error("Iframe not created during prerender");i?this.submitBodyForm(this.iframe.name,t,n):this.iframe.src=t,this.hostWindow=this.iframe.contentWindow}else{const r=this.buildWindowName();this.hostWindow=Ot({url:i?"about:blank":t,name:r,dimensions:this.resolveDimensions()}),i&&this.submitBodyForm(r,t,n);const o=Dt(this.hostWindow,()=>{this.close()});this.cleanup.register(o)}this.hostWindow&&at(this.uid,this.hostWindow)}buildUrl(e=this.resolveUrl()){const n=dt(this.props,this.options.props).toString();if(!n)return e;const i=e.includes("?")?"&":"?";return`${e}${i}${n}`}buildBodyParams(){return ft(this.props,this.options.props)}submitBodyForm(e,t,n){const i=this.container?.ownerDocument??document,r=i.body??i.documentElement;if(!r)throw new Error("Document root is unavailable for bodyParam form submission");const o=i.createElement("form");o.method="POST",o.action=t,o.target=e,o.style.display="none";for(const[a,c]of n.entries()){const l=i.createElement("input");l.type="hidden",l.name=a,l.value=c,o.appendChild(l)}r.appendChild(o);try{o.submit()}finally{o.remove()}}buildWindowName(){const e=this.getHostDomain(),t=be(this.props,this.options.props,e,!1),n=Re(t,this.options.props,this.bridge),i=this.buildNestedHostRefs(),r=it({uid:this.uid,tag:this.options.tag,context:this.context,consumerDomain:Q(),props:n,exports:this.createConsumerExports(),children:i});return tt(r)}buildNestedHostRefs(){if(!this.options.children)return;const e=this.options.children({props:this.props}),t={};for(const[n,i]of Object.entries(e)){const r=Mt(i);if(!r)throw new Error(`Nested component "${n}" is missing component metadata`);if(typeof r.url!="string")throw new Error(`Nested component "${n}" must use a static string URL. Function URLs are not supported in children.`);t[n]={tag:r.tag,url:r.url,props:r.props,dimensions:typeof r.dimensions=="function"?void 0:r.dimensions,defaultContext:r.defaultContext}}return Object.keys(t).length>0?t: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(){return this.openedHostDomain?this.openedHostDomain:this.resolveUrlOrigin(this.resolveUrl())??"*"}async waitForHost(){if(this.hostInitialized)return;const e=ue();this.initPromise=e;try{await ze(e.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(t){throw this.handleError(t),t}finally{this.initPromise===e&&(this.initPromise=null)}}setupMessageHandlers(){this.setupHostLifecycleHandlers(),this.setupHostDataHandlers()}setupHostLifecycleHandlers(){this.messenger.on(h.INIT,()=>(this.hostInitialized=!0,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 t=new Error(e.message);return t.stack=e.stack,this.handleError(t),{success:!0}})}setupHostDataHandlers(){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=>this.getSiblingInstances(e))}getSiblingInstances(e){const t=[],n=Ut(e.tag);if(!n)return t;for(const i of n.instances)i.uid!==e.uid&&t.push({uid:i.uid,tag:e.tag,exports:i.exports});return t}setupCleanup(){this.cleanup.register(()=>{this.messenger.destroy(),this.bridge.destroy(),ct(this.uid)})}handleError(e){this.event.emit(m.ERROR,e),this.callPropCallback("onError",e)}callPropCallback(e,...t){const n=this.props[e];if(typeof n=="function")try{const i=n(...t);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.hostInitialized=!1,this.iframe&&(_t(this.iframe),this.iframe=null),this.context===p.POPUP&&this.hostWindow&&St(this.hostWindow),this.hostWindow=null,this.openedHostDomain=null,this.dynamicUrlTrustedOrigin=null,this.prerenderElement&&(this.prerenderElement.remove(),this.prerenderElement=null),await this.cleanup.cleanup(),this.event.emit(m.DESTROY),this.callPropCallback("onDestroy"),this.event.removeAllListeners())}}const Ie="Could not resolve consumer window";class Lt{constructor(e,t={},n,i=!1){this.propDefinitions=t,this.allowedConsumerDomains=n,this.deferInit=i,this.uid=e.uid,this.tag=e.tag,this.consumerDomain=e.consumerDomain,this.validateConsumerDomain(),this.event=new le,this.messenger=new de(this.uid,window,Q(),this.consumerDomain);let r=null;try{this.setupMessageHandlers(),this.consumerWindow=this.resolveConsumerWindow(),r=new Y(this.messenger),this.bridge=r,this.hostProps=this.buildHostProps(e),this.exposeHostProps(),this.deferInit||this.flushInit()}catch(o){throw r?.destroy(),this.messenger.destroy(),this.event.removeAllListeners(),this.propsHandlers.clear(),o}}hostProps;event;uid;tag;consumerWindow;consumerDomain;messenger;bridge;propsHandlers=new Set;consumerProps;initError=null;destroyed=!1;initSent=!1;deferredInitFlushScheduled=!1;flushInit(){this.destroyed||this.initSent||(this.initSent=!0,this.sendInit())}scheduleDeferredInitFlush(){this.deferredInitFlushScheduled||this.destroyed||this.initSent||(this.deferredInitFlushScheduled=!0,queueMicrotask(()=>{this.deferredInitFlushScheduled=!1,this.flushInit()}))}exposeHostProps(){const e=window;try{Object.defineProperty(e,"hostProps",{configurable:!0,enumerable:!0,get:()=>(this.deferInit&&!this.initSent&&!this.destroyed&&this.scheduleDeferredInitFlush(),this.hostProps),set:t=>{t&&(this.hostProps=t)}})}catch{e.hostProps=this.hostProps}}validateConsumerDomain(){if(this.allowedConsumerDomains&&!I(this.allowedConsumerDomains,this.consumerDomain))throw new Error(`Consumer domain "${this.consumerDomain}" is not allowed for component "${this.tag}"`)}getProps(){return this.hostProps}resolveConsumerWindow(){if(Qe()){const e=Ge();if(e)return e}if(et()){const e=Ze();if(e)return e}throw new Error(Ie)}buildHostProps(e){const t=Oe(e.props,this.propDefinitions,this.messenger,this.bridge,this.consumerWindow,this.consumerDomain);return this.consumerProps=t,{...t,uid:this.uid,tag:this.tag,close:()=>this.close(),focus:()=>this.focus(),resize:n=>this.resize(n),show:()=>this.show(),hide:()=>this.hide(),onProps:n=>this.onProps(n),onError:n=>this.onError(n),getConsumer:()=>this.consumerWindow,getConsumerDomain:()=>this.consumerDomain,export:n=>this.exportData(n),consumer:{props:this.consumerProps,export:n=>this.consumerExport(n)},getPeerInstances:n=>this.getPeerInstances(n),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 t=e instanceof Error?e:new Error(String(e));this.initError=t,this.event.emit(m.ERROR,{type:"init_failed",message:`Failed to initialize host component: ${t.message}`,error:t}),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 t={};for(const[n,i]of Object.entries(e))try{t[n]=ie({tag:i.tag,url:i.url,props:i.props,dimensions:i.dimensions,defaultContext:i.defaultContext})}catch(r){console.warn(`Failed to create nested component "${n}":`,r)}return Object.keys(t).length>0?t:void 0}setupMessageHandlers(){this.messenger.on(h.PROPS,e=>{try{const t=Oe(e,this.propDefinitions,this.messenger,this.bridge,this.consumerWindow,this.consumerDomain);this.consumerProps=t,Object.assign(this.hostProps,t),this.hostProps.consumer.props=this.consumerProps;for(const n of this.propsHandlers)try{n(t)}catch(i){console.error("Error in props handler:",i)}return this.event.emit(m.PROPS,t),{success:!0}}catch(t){const n=t instanceof Error?t:new Error(String(t));throw console.error("Error deserializing props:",n),this.event.emit(m.ERROR,n),n}})}destroy(){this.destroyed||(this.destroyed=!0,this.deferredInitFlushScheduled=!1,this.messenger.destroy(),this.bridge.destroy(),this.event.removeAllListeners(),this.propsHandlers.clear())}}let _=null;function V(s,e,t={}){if(_){if(e){const i=_.getProps().getConsumerDomain();if(!I(e,i))throw At(),new Error(`Consumer domain "${i}" is not allowed for this host component`)}return t.deferInit||_.flushInit(),_}if(!ee())return null;const n=rt();if(!n)return console.error("Failed to parse ForgeFrame payload from window.name"),null;try{_=new Lt(n,s,e,t.deferInit??!1)}catch(i){if(i instanceof Error&&i.message===Ie)return null;throw i}return _}function De(){return ee()}function Ce(){return ee()}function xe(){return window.hostProps}function At(){_&&(_.destroy(),_=null),delete window.hostProps}const x=new Map,Te=Symbol("forgeframe.component.options");function kt(s){if(!s.tag)throw new Error("Component tag is required");if(!/^[a-z][a-z0-9-]*$/.test(s.tag))throw new Error(`Invalid component tag "${s.tag}". Must start with lowercase letter and contain only lowercase letters, numbers, and hyphens.`);if(!s.url)throw new Error("Component url is required");if(typeof s.url=="string")try{new URL(s.url,window.location.origin)}catch{throw new Error(`Invalid component URL "${s.url}". Must be a valid absolute or relative URL.`)}if(x.has(s.tag))throw new Error(`Component "${s.tag}" is already registered`)}function ie(s){kt(s);const e=[];let t;if(te(s.tag)){const i=V(s.props,s.allowedConsumerDomains);i&&(t=i.hostProps)}const n=function(i={}){const r=new ne(s,i);return e.push(r),r.event.once("destroy",()=>{const o=e.indexOf(r);o!==-1&&e.splice(o,1)}),r};return n.instances=e,n.isHost=()=>te(s.tag),n.isEmbedded=()=>te(s.tag),n.hostProps=t,n[Te]=s,n.canRenderTo=async i=>{try{return!!(pe(i)||s.domain)}catch{return!1}},x.set(s.tag,n),n}function Ut(s){return x.get(s)}function Mt(s){return s[Te]}async function Ne(s){await s.close()}async function re(s){const e=x.get(s);if(!e)return;const t=[...e.instances];await Promise.all(t.map(n=>n.close()))}async function Fe(){const s=Array.from(x.keys());await Promise.all(s.map(e=>re(e)))}function Wt(s,e){const t=Object.keys(s),n=Object.keys(e);if(t.length!==n.length)return!1;for(const i of t)if(!Object.prototype.hasOwnProperty.call(e,i)||!Object.is(s[i],e[i]))return!1;return!0}function $e(s,e){const{React:t}=e,{createElement:n,useRef:i,useEffect:r,useState:o,forwardRef:a}=t,c=a(function(b,P){const{onRendered:S,onError:T,onClose:Le,context:jt,className:Ae,style:ke,...oe}=b,q=i(null),ae=i(null),ce=i(null),[Ue,Bt]=o(null);return r(()=>{const N=q.current;if(!N)return;const y=s(oe);return ae.current=y,S&&y.event.once("rendered",S),Le&&y.event.once("close",Le),T&&y.event.on("error",T),y.render(N,jt).catch(F=>{Bt(F),T?.(F)}),()=>{y.close().catch(()=>{}),ae.current=null,ce.current=null}},[]),r(()=>{const N=ae.current;if(!N)return;const y=oe,F=ce.current;F&&Wt(F,y)||(ce.current=y,N.updateProps(y).catch(Vt=>{T?.(Vt)}))},[oe,T]),r(()=>{P&&typeof P=="object"&&q.current&&(P.current=q.current)},[P]),Ue?n("div",{className:Ae,style:{color:"red",padding:"16px",...ke}},`Error: ${Ue.message}`):n("div",{ref:q,className:Ae,style:{display:"inline-block",...ke}})}),l=`ForgeFrame(${s.name||"Component"})`;return c.displayName=l,c}function zt(s){return function(t){return $e(t,{React:s})}}V(void 0,void 0,{deferInit:!0});const He={create:ie,destroy:Ne,destroyByTag:re,destroyAll:Fe,isHost:De,isEmbedded:Ce,getHostProps:xe,initHost:V,PROP_SERIALIZATION:v,CONTEXT:p,EVENT:m,PopupOpenError:se,VERSION:J,isStandardSchema:w,prop:f};u.AnySchema=j,u.ArraySchema=D,u.BooleanSchema=U,u.CONTEXT=p,u.EVENT=m,u.EnumSchema=z,u.ForgeFrame=He,u.FunctionSchema=M,u.LiteralSchema=W,u.NumberSchema=k,u.ObjectSchema=C,u.PROP_SERIALIZATION=v,u.PopupOpenError=se,u.PropSchema=g,u.StringSchema=A,u.VERSION=J,u.create=ie,u.createReactComponent=$e,u.default=He,u.destroy=Ne,u.destroyAll=Fe,u.destroyByTag=re,u.getHostProps=xe,u.initHost=V,u.isEmbedded=Ce,u.isHost=De,u.isStandardSchema=w,u.prop=f,u.withReactComponent=zt,Object.defineProperties(u,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
package/dist/index.d.ts CHANGED
@@ -174,7 +174,7 @@ export declare const ForgeFrame: {
174
174
  /**
175
175
  * Current library version.
176
176
  */
177
- readonly VERSION: "0.0.1";
177
+ readonly VERSION: string;
178
178
  /**
179
179
  * Check if a value is a Standard Schema (Zod, Valibot, ArkType, etc.)
180
180
  *
@@ -7,7 +7,7 @@
7
7
  * deserialization for cross-domain component communication.
8
8
  */
9
9
  export { BUILTIN_PROP_DEFINITIONS, type BuiltinProps, } from './definitions';
10
- export { normalizeProps, validateProps, getPropsForHost, propsToQueryParams, } from './normalize';
10
+ export { normalizeProps, validateProps, getPropsForHost, propsToQueryParams, propsToBodyParams, } from './normalize';
11
11
  export { serializeProps, deserializeProps, cloneProps, } from './serialize';
12
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
13
  export { prop, PropSchema, StringSchema, NumberSchema, BooleanSchema, FunctionSchema, ArraySchema, ObjectSchema, LiteralSchema, EnumSchema, AnySchema, type Prop, type InferObjectShape, } from './prop';
@@ -57,3 +57,14 @@ export declare function getPropsForHost<P extends Record<string, unknown>>(props
57
57
  * @public
58
58
  */
59
59
  export declare function propsToQueryParams<P extends Record<string, unknown>>(props: P, definitions: PropsDefinition<P>): URLSearchParams;
60
+ /**
61
+ * Builds POST body parameters from props with bodyParam option.
62
+ *
63
+ * @typeParam P - The props type
64
+ * @param props - Props to convert
65
+ * @param definitions - Prop definitions
66
+ * @returns URLSearchParams with body parameters
67
+ *
68
+ * @public
69
+ */
70
+ export declare function propsToBodyParams<P extends Record<string, unknown>>(props: P, definitions: PropsDefinition<P>): URLSearchParams;
@@ -47,7 +47,7 @@ export interface StandardSchemaV1Props<Input = unknown, Output = Input> {
47
47
  /** The name of the schema library (e.g., "zod", "valibot", "arktype") */
48
48
  readonly vendor: string;
49
49
  /** Optional type metadata for input and output types */
50
- readonly types?: StandardSchemaV1Types<Input, Output>;
50
+ readonly types?: StandardSchemaV1Types<Input, Output> | undefined;
51
51
  /** Validates an unknown value and returns a result */
52
52
  readonly validate: (value: unknown) => StandardSchemaV1Result<Output> | Promise<StandardSchemaV1Result<Output>>;
53
53
  }
@@ -98,6 +98,8 @@ export interface StandardSchemaV1SuccessResult<Output> {
98
98
  export interface StandardSchemaV1FailureResult {
99
99
  /** Array of validation issues */
100
100
  readonly issues: ReadonlyArray<StandardSchemaV1Issue>;
101
+ /** Undefined on failure */
102
+ readonly value?: undefined;
101
103
  }
102
104
  /**
103
105
  * A validation issue from a Standard Schema.
@@ -109,6 +111,10 @@ export interface StandardSchemaV1Issue {
109
111
  readonly message: string;
110
112
  /** Path to the invalid value (for nested objects/arrays) */
111
113
  readonly path?: ReadonlyArray<PropertyKey | StandardSchemaV1PathSegment>;
114
+ /** Optional machine-readable error code */
115
+ readonly code?: string | undefined;
116
+ /** The input value that caused this issue */
117
+ readonly input?: unknown;
112
118
  }
113
119
  /**
114
120
  * A path segment for nested validation issues.
@@ -116,8 +122,10 @@ export interface StandardSchemaV1Issue {
116
122
  * @public
117
123
  */
118
124
  export interface StandardSchemaV1PathSegment {
119
- /** The property key or array index */
120
- readonly key: PropertyKey;
125
+ /** The property key in an object path segment */
126
+ readonly key?: PropertyKey | undefined;
127
+ /** The numeric index in an array path segment */
128
+ readonly index?: number | undefined;
121
129
  }
122
130
  /**
123
131
  * Infers the input type from a Standard Schema.
package/dist/types.d.ts CHANGED
@@ -13,7 +13,8 @@ import type { StandardSchemaV1, InferOutput } from './props/schema';
13
13
  * Pattern for matching domains in security configurations.
14
14
  *
15
15
  * @remarks
16
- * Can be a single domain string, a RegExp pattern, or an array of domain strings.
16
+ * Can be a single domain string, a RegExp pattern, or an array of string/RegExp patterns.
17
+ * String patterns support `*` wildcards (for example, `'https://*.example.com'`).
17
18
  *
18
19
  * @example
19
20
  * ```typescript
@@ -23,13 +24,14 @@ import type { StandardSchemaV1, InferOutput } from './props/schema';
23
24
  * // RegExp pattern
24
25
  * const pattern: DomainMatcher = /^https:\/\/.*\.example\.com$/;
25
26
  *
26
- * // Multiple domains
27
- * const domains: DomainMatcher = ['https://a.com', 'https://b.com'];
27
+ * // Multiple patterns (can mix strings and RegExp)
28
+ * const domains: DomainMatcher = ['https://*.example.com', /^https:\/\/api\d+\.example\.com$/];
28
29
  * ```
29
30
  *
30
31
  * @public
31
32
  */
32
- export type DomainMatcher = string | RegExp | string[];
33
+ type DomainPattern = string | RegExp;
34
+ export type DomainMatcher = DomainPattern | DomainPattern[];
33
35
  /**
34
36
  * Component dimension specification.
35
37
  *
@@ -606,6 +608,9 @@ export interface ForgeFrameComponentInstance<P = Record<string, unknown>, X = un
606
608
  /**
607
609
  * Update the component's props.
608
610
  *
611
+ * @remarks
612
+ * Props are normalized and validated before being sent to the host.
613
+ *
609
614
  * @param props - Partial props to merge with existing
610
615
  * @returns Promise that resolves when props are updated
611
616
  */
@@ -54,7 +54,8 @@ export declare function isSameDomain(win: Window, reference?: Window): boolean;
54
54
  * @remarks
55
55
  * Pattern matching rules:
56
56
  * - `"*"` matches any domain
57
- * - String patterns require exact match
57
+ * - String patterns without wildcards require exact match
58
+ * - String patterns with `*` use wildcard matching (for example, `'https://*.example.com'`)
58
59
  * - RegExp patterns use `.test()` method
59
60
  * - Array patterns return `true` if any element matches (OR logic)
60
61
  *
@@ -66,6 +67,9 @@ export declare function isSameDomain(win: Window, reference?: Window): boolean;
66
67
  * // Exact match
67
68
  * matchDomain('https://example.com', 'https://example.com'); // true
68
69
  *
70
+ * // Wildcard string match
71
+ * matchDomain('https://*.example.com', 'https://sub.example.com'); // true
72
+ *
69
73
  * // RegExp match
70
74
  * matchDomain(/\.example\.com$/, 'https://sub.example.com'); // true
71
75
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgeframe",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Modern cross-domain iframe component framework - a TypeScript alternative to zoid",
5
5
  "type": "module",
6
6
  "module": "./dist/forgeframe.js",
@@ -20,7 +20,8 @@
20
20
  "scripts": {
21
21
  "clean": "rm -rf dist",
22
22
  "build": "vite build && tsc --emitDeclarationOnly",
23
- "typecheck": "tsc --noEmit",
23
+ "typecheck": "tsc --noEmit && npm run typecheck:tests",
24
+ "typecheck:tests": "tsc -p tests/typecheck/tsconfig.json --noEmit",
24
25
  "test": "vitest",
25
26
  "test:run": "vitest run",
26
27
  "test:coverage": "vitest run --coverage"
@@ -43,5 +44,9 @@
43
44
  "repository": {
44
45
  "type": "git",
45
46
  "url": "git+https://github.com/jshsmth/ForgeFrame.git"
47
+ },
48
+ "devDependencies": {
49
+ "valibot": "^1.2.0",
50
+ "zod": "^4.3.6"
46
51
  }
47
52
  }