@djvlc/runtime-core 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- var t=require("@djvlc/contracts-types"),e=class extends Error{constructor(e,s,i,r){super(s||t.ErrorMessages[e]||"Unknown error"),this.name="DjvlcRuntimeError",this.code=e,this.details=i,this.traceId=r,this.timestamp=Date.now()}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,traceId:this.traceId,timestamp:this.timestamp}}},s=class extends e{constructor(e,s,i){super(t.ErrorCode.RESOURCE_PAGE_NOT_FOUND,e,s,i),this.name="PageLoadError"}},i=class extends e{constructor(e,s,i,r=t.ErrorCode.COMPONENT_LOAD_FAILED,n){super(r,i,{...n,componentName:e,componentVersion:s}),this.name="ComponentLoadError",this.componentName=e,this.componentVersion=s}},r=class extends e{constructor(e,s,i,r){super(t.ErrorCode.COMPONENT_INTEGRITY_MISMATCH,`Integrity check failed for ${e}@${s}`,{expectedHash:i,actualHash:r}),this.name="IntegrityError",this.componentName=e,this.componentVersion=s,this.expectedHash=i,this.actualHash=r}},n=class extends e{constructor(e,s,i){super(t.ErrorCode.COMPONENT_BLOCKED,`Component ${e}@${s} is blocked`,{componentName:e,componentVersion:s,reason:i}),this.name="ComponentBlockedError",this.componentName=e,this.componentVersion=s,this.reason=i}},o=class extends e{constructor(e,s,i,r){super(t.ErrorCode.VALIDATION_EXPRESSION_ERROR,s,{...r,expression:e,position:i}),this.name="ExpressionError",this.expression=e,this.position=i}},a=class extends e{constructor(e,s,i=t.ErrorCode.SYSTEM_INTERNAL_ERROR,r,n){super(i,s,{...n,actionType:e,actionId:r}),this.name="ActionError",this.actionType=e,this.actionId=r}},c=class extends e{constructor(e,s,i=t.ErrorCode.SYSTEM_INTERNAL_ERROR,r){super(i,s,{...r,queryId:e}),this.name="QueryError",this.queryId=e}},h=class{constructor(t){this.cache=new Map,this.options={channel:"prod",cache:{enabled:!0,maxAge:300},...t}}async resolve(t,e){const i=this.getCacheKey(t,e);if(this.options.cache?.enabled){const e=this.cache.get(i);if(e&&this.isCacheValid(e.timestamp))return this.log("debug",`Page ${t} loaded from cache`),e.data}const r=performance.now();try{const n=this.buildResolveUrl(t,e),o=await fetch(n,{method:"GET",headers:this.buildHeaders()});if(!o.ok)throw new s(`Failed to resolve page: ${o.status} ${o.statusText}`,{pageUid:t,status:o.status});const a=await o.json();if(!this.isValidPageResolveResult(a))throw new s("Invalid page resolve response",{pageUid:t});const c=a.data;this.options.cache?.enabled&&this.cache.set(i,{data:c,timestamp:Date.now()});const h=performance.now()-r;return this.log("info",`Page ${t} resolved in ${h.toFixed(2)}ms`),c}catch(e){if(e instanceof s)throw e;throw new s(`Failed to resolve page: ${e instanceof Error?e.message:"Unknown error"}`,{pageUid:t})}}preconnect(){const t=document.createElement("link");t.rel="preconnect",t.href=this.options.apiBaseUrl,document.head.appendChild(t)}clearCache(t){if(t)for(const e of this.cache.keys())e.startsWith(t)&&this.cache.delete(e);else this.cache.clear()}buildResolveUrl(t,e){const s=new URL(`${this.options.apiBaseUrl}/page/resolve`);return s.searchParams.set("pageUid",t),this.options.channel&&s.searchParams.set("channel",this.options.channel),this.options.previewToken&&s.searchParams.set("previewToken",this.options.previewToken),e?.uid&&s.searchParams.set("uid",e.uid),e?.deviceId&&s.searchParams.set("deviceId",e.deviceId),s.toString()}buildHeaders(){const t={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(t.Authorization=`Bearer ${this.options.authToken}`),t}getCacheKey(t,e){const s=[t,this.options.channel];return e?.uid&&s.push(e.uid),e?.deviceId&&s.push(e.deviceId),s.join(":")}isCacheValid(t){const e=1e3*(this.options.cache?.maxAge??300);return Date.now()-t<e}isValidPageResolveResult(t){if(!t||"object"!=typeof t)return!1;const e=t;if(!e.data||"object"!=typeof e.data)return!1;const s=e.data;return"string"==typeof s.pageUid&&"string"==typeof s.pageVersionId&&void 0!==s.pageJson&&void 0!==s.manifest}log(t,e){this.options.logger&&this.options.logger[t](e)}},u=class{constructor(t){this.loadedComponents=new Map,this.loadingPromises=new Map,this.options={enableSRI:!0,concurrency:4,timeout:3e4,blockedComponents:[],...t},this.blockedSet=new Set(this.options.blockedComponents)}async load(t){const e=this.getComponentKey(t.name,t.version);if(this.isBlocked(t.name,t.version))throw new n(t.name,t.version,"Component is blocked");const s=this.loadedComponents.get(e);if(s)return s;const i=this.loadingPromises.get(e);if(i)return i;const r=this.loadComponent(t);this.loadingPromises.set(e,r);try{const t=await r;return this.loadedComponents.set(e,t),t}finally{this.loadingPromises.delete(e)}}async loadAll(t){const e=new Map,{concurrency:s=4}=this.options,i=t.components;for(let t=0;t<i.length;t+=s){const r=i.slice(t,t+s).map(async t=>{const s=this.getComponentKey(t.name,t.version),i=performance.now();try{const r=await this.load(t);e.set(s,{name:t.name,version:t.version,status:"loaded",component:r.Component,loadTime:performance.now()-i})}catch(r){const o=r instanceof n?"blocked":"failed";if(e.set(s,{name:t.name,version:t.version,status:o,error:r instanceof Error?r.message:"Unknown error",loadTime:performance.now()-i}),"critical"===t.priority)throw r}});await Promise.all(r)}return e}preload(t){t.forEach(t=>{const e=document.createElement("link");e.rel="preload",e.as="script",e.href=this.resolveUrl(t.entry),this.options.enableSRI&&t.integrity&&(e.integrity=t.integrity,e.crossOrigin="anonymous"),document.head.appendChild(e)})}isLoaded(t,e){return this.loadedComponents.has(this.getComponentKey(t,e))}get(t,e){return this.loadedComponents.get(this.getComponentKey(t,e))}isBlocked(t,e){return this.blockedSet.has(`${t}@${e}`)||this.blockedSet.has(t)}updateBlockedList(t){this.blockedSet=new Set(t)}async loadComponent(t){const e=performance.now(),s=this.resolveUrl(t.entry);this.log("debug",`Loading component ${t.name}@${t.version}`);try{const r=await this.fetchWithTimeout(s);if(!r.ok)throw new i(t.name,t.version,`Failed to fetch component: ${r.status} ${r.statusText}`);const n=await r.text();this.options.enableSRI&&t.integrity&&await this.validateIntegrity(t,n);const o=await this.executeScript(n,t),a=performance.now()-e;return this.log("info",`Component ${t.name}@${t.version} loaded in ${a.toFixed(2)}ms`),{name:t.name,version:t.version,Component:o,loadTime:a}}catch(e){if(e instanceof i||e instanceof r||e instanceof n)throw e;throw new i(t.name,t.version,`Failed to load component: ${e instanceof Error?e.message:"Unknown error"}`)}}async fetchWithTimeout(t){const e=new AbortController,s=setTimeout(()=>e.abort(),this.options.timeout);try{return await fetch(t,{signal:e.signal,credentials:"omit"})}finally{clearTimeout(s)}}async validateIntegrity(t,e){if(!t.integrity)return;const[s,i]=t.integrity.split("-");if(!s||!i)throw new r(t.name,t.version,t.integrity,"Invalid format");const n=await crypto.subtle.digest(s.toUpperCase(),(new TextEncoder).encode(e)),o=Array.from(new Uint8Array(n)),a=btoa(String.fromCharCode(...o));if(a!==i)throw new r(t.name,t.version,i,a)}async executeScript(t,e){const s=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(s);try{const t=await import(r),s=t.default||t[e.name]||t.Component;if(!s)throw new i(e.name,e.version,"Component module does not export a valid component");return s}finally{URL.revokeObjectURL(r)}}resolveUrl(t){return t.startsWith("http://")||t.startsWith("https://")?t:`${this.options.cdnBaseUrl}/${t.replace(/^\//,"")}`}getComponentKey(t,e){return`${t}@${e}`}log(t,e){this.options.logger&&this.options.logger[t](e)}},l=class{constructor(t){this.preconnectedHosts=new Set,this.preloadedAssets=new Set,this.options=t}preconnectAll(){[...this.options.cdnHosts,...this.options.apiHosts].forEach(t=>this.preconnect(t))}preconnect(t){if(this.preconnectedHosts.has(t))return;const e=document.createElement("link");e.rel="preconnect",e.href=t.startsWith("http")?t:`https://${t}`,e.crossOrigin="anonymous",document.head.appendChild(e),this.preconnectedHosts.add(t)}dnsPrefetch(t){const e=document.createElement("link");e.rel="dns-prefetch",e.href=t.startsWith("http")?t:`https://${t}`,document.head.appendChild(e)}preloadScript(t,e){if(this.preloadedAssets.has(t))return;const s=document.createElement("link");s.rel="preload",s.as="script",s.href=t,e&&(s.integrity=e,s.crossOrigin="anonymous"),document.head.appendChild(s),this.preloadedAssets.add(t)}preloadStyle(t,e){if(this.preloadedAssets.has(t))return;const s=document.createElement("link");s.rel="preload",s.as="style",s.href=t,e&&(s.integrity=e,s.crossOrigin="anonymous"),document.head.appendChild(s),this.preloadedAssets.add(t)}preloadImage(t){if(this.preloadedAssets.has(t))return;const e=document.createElement("link");e.rel="preload",e.as="image",e.href=t,document.head.appendChild(e),this.preloadedAssets.add(t)}prefetch(t,e){const s=document.createElement("link");s.rel="prefetch",s.href=t,e&&(s.as=e),document.head.appendChild(s)}loadStylesheet(t,e){return new Promise((s,i)=>{const r=document.createElement("link");r.rel="stylesheet",r.href=t,e&&(r.integrity=e,r.crossOrigin="anonymous"),r.onload=()=>s(),r.onerror=()=>i(new Error(`Failed to load stylesheet: ${t}`)),document.head.appendChild(r)})}loadScript(t,e){return new Promise((s,i)=>{const r=document.createElement("script");r.src=t,r.async=!0,e&&(r.integrity=e,r.crossOrigin="anonymous"),r.onload=()=>s(),r.onerror=()=>i(new Error(`Failed to load script: ${t}`)),document.body.appendChild(r)})}},d=class{constructor(){this.listeners=new Set,this.changeCallbacks=new Set,this.state=this.createInitialState()}getState(){return this.state}getPhase(){return this.state.phase}setPhase(t){this.setState({phase:t})}setPage(t){const e=t.pageJson,s=this.initializePageState(e);t.preloadedData&&Object.assign(s,t.preloadedData),this.setState({page:t,variables:s})}initializePageState(t){const e={};if(t.state&&t.state.fields)for(const[s,i]of Object.entries(t.state.fields))if(i&&"object"==typeof i){const t=i;e[s]=t.initialValue}return e}setError(t){this.setState({phase:"error",error:t})}clearError(){this.state.error&&this.setState({error:null})}getVariable(t){return t.includes(".")?this.getNestedValue(this.state.variables,t):this.state.variables[t]}setVariable(t,e){const s=this.getVariable(t);if(t.includes(".")){const s={...this.state.variables};this.setNestedValue(s,t,e),this.setState({variables:s})}else this.setState({variables:{...this.state.variables,[t]:e}});this.notifyChange({key:t,oldValue:s,newValue:e})}setVariables(t){const e=[];for(const[s,i]of Object.entries(t)){const t=this.getVariable(s);e.push({key:s,oldValue:t,newValue:i})}this.setState({variables:{...this.state.variables,...t}}),e.forEach(t=>this.notifyChange(t))}getQuery(t){return this.state.queries[t]}setQuery(t,e){this.setState({queries:{...this.state.queries,[t]:e}})}clearQuery(t){const{[t]:e,...s}=this.state.queries;this.setState({queries:s})}setComponentStatus(t,e){const s=new Map(this.state.components);s.set(t,e),this.setState({components:s})}getComponentStatus(t){return this.state.components.get(t)}setDestroyed(){this.setState({phase:"destroyed",destroyed:!0})}isDestroyed(){return this.state.destroyed}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}onStateChange(t){return this.changeCallbacks.add(t),()=>{this.changeCallbacks.delete(t)}}reset(){this.state=this.createInitialState(),this.notifyListeners()}getExpressionContext(){return{state:this.state.variables,binding:this.state.queries,local:{},context:{pageVersionId:this.state.page?.pageVersionId,pageUid:this.state.page?.pageUid,phase:this.state.phase,$now:Date.now()}}}setState(t){this.state={...this.state,...t},this.notifyListeners()}notifyListeners(){this.listeners.forEach(t=>{try{t(this.state)}catch(t){}})}notifyChange(t){this.changeCallbacks.forEach(e=>{try{e(t)}catch(t){}})}getNestedValue(t,e){const s=e.split(".");let i=t;for(const t of s){if(null==i)return;i=i[t]}return i}setNestedValue(t,e,s){const i=e.split(".");let r=t;for(let t=0;t<i.length-1;t++){const e=i[t];void 0!==r[e]&&null!==r[e]||(r[e]={}),r=r[e]}r[i[i.length-1]]=s}createInitialState(){return{phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}}},p=class{constructor(t){this.bindings=new Map,this.dependencyGraph=new Map,this.bindingDependencies=new Map,this.options=t}registerBindings(t){for(const e of t)this.registerBinding(e)}registerBinding(t){if(this.bindings.set(t.id,{binding:t,loading:!1,retryCount:0}),t.dependencies)for(const e of t.dependencies)this.dependencyGraph.has(e)||this.dependencyGraph.set(e,new Set),this.dependencyGraph.get(e).add(t.id);this.updateBindingDependencies(t),this.log("debug",`Registered data binding: ${t.id}`)}updateBindingDependencies(t){for(const[e,s]of this.bindings){if(e===t.id)continue;const i=s.binding;i.dependencies?.includes(t.targetState)&&(this.bindingDependencies.has(t.id)||this.bindingDependencies.set(t.id,new Set),this.bindingDependencies.get(t.id).add(e))}if(t.dependencies)for(const e of t.dependencies)for(const[s,i]of this.bindings)s!==t.id&&i.binding.targetState===e&&(this.bindingDependencies.has(s)||this.bindingDependencies.set(s,new Set),this.bindingDependencies.get(s).add(t.id))}async initializeBindings(t){const e=[];for(const t of this.bindings.values())"eager"===t.binding.loadStrategy&&e.push(t.binding);const s=this.topologicalSort(e),i=this.createLoadBatches(s);for(const e of i){const s=await Promise.allSettled(e.map(e=>this.loadBinding(e.id,t))),i=new Map;s.forEach((t,s)=>{const r=e[s].id;"fulfilled"===t.status?i.set(r,{success:!0,data:t.value}):i.set(r,{success:!1,error:t.reason})}),this.options.onBatchComplete?.(i)}}topologicalSort(t){const e=new Map(t.map(t=>[t.id,t])),s=new Set,i=[],r=t=>{if(!s.has(t.id)){if(s.add(t.id),t.dependencies)for(const i of t.dependencies)for(const[t,n]of e)n.targetState!==i||s.has(t)||r(n);i.push(t)}};for(const e of t)r(e);return i}createLoadBatches(t){const e=[],s=new Set;for(;s.size<t.length;){const i=[];for(const e of t){if(s.has(e.id))continue;let r=!0;if(e.dependencies)for(const i of e.dependencies){for(const e of t)if(e.targetState===i&&!s.has(e.id)){r=!1;break}if(!r)break}r&&i.push(e)}if(0===i.length)for(const e of t)if(!s.has(e.id)){i.push(e),this.log("warn",`Possible circular dependency detected at binding: ${e.id}`);break}i.forEach(t=>s.add(t.id)),i.length>0&&e.push(i)}return e}async loadBinding(t,e,s=!1){const i=this.bindings.get(t);if(!i)throw new c(t,`Data binding not found: ${t}`);const{binding:r}=i;if(!r.condition||this.evaluateCondition(r.condition,e)){if(!s&&this.isCacheValid(i))return this.log("debug",`Binding ${t} returned from cache`),i.cachedData;if(i.loading)this.log("debug",`Binding ${t} is already loading`);else{i.loading=!0;try{const s=this.resolveParams(r.params||{},e),n=await this.executeWithRetry(r,s),o=r.transform?this.applyTransform(n,r.transform,e):n;return i.cachedData=o,i.lastLoadTime=Date.now(),r.cache?.ttl&&(i.cacheExpireTime=Date.now()+1e3*r.cache.ttl),i.retryCount=0,this.options.stateSetter.setVariable(r.targetState,o),this.setupAutoRefresh(i,e),this.options.onDataLoaded?.(t,o),this.log("info",`Binding ${t} loaded successfully`),o}catch(t){throw await this.handleLoadError(i,t,e),t}finally{i.loading=!1}}}else this.log("debug",`Binding ${t} skipped by condition`)}async refreshBinding(t,e){await this.loadBinding(t,e,!0)}async refreshAll(t){const e=Array.from(this.bindings.keys()).map(e=>this.loadBinding(e,t,!0));await Promise.allSettled(e)}async onStateChange(t,e){const s=this.dependencyGraph.get(t);if(!s||0===s.size)return;this.log("debug",`State ${t} changed, refreshing dependent bindings`);const i=Array.from(s).map(t=>this.loadBinding(t,e,!0));await Promise.allSettled(i)}async triggerManualLoad(t,e){const s=this.bindings.get(t);if(!s)throw new c(t,`Data binding not found: ${t}`);return"manual"!==s.binding.loadStrategy&&this.log("warn",`Binding ${t} is not manual strategy`),this.loadBinding(t,e,!0)}checkVisibility(t,e,s){const i=this.bindings.get(t);i&&"lazy"===i.binding.loadStrategy&&e&&!i.lastLoadTime&&this.loadBinding(t,s).catch(e=>{this.log("error",`Lazy binding ${t} failed to load`,e)})}destroy(){for(const t of this.bindings.values())t.refreshTimer&&clearInterval(t.refreshTimer);this.bindings.clear(),this.dependencyGraph.clear(),this.log("debug","DataBindingManager destroyed")}async executeWithRetry(t,e){const s=t.onError?.retry?.maxRetries??0,i=t.onError?.retry?.backoffMs??1e3,r=t.onError?.retry?.backoff??"fixed";let n;for(let o=0;o<=s;o++)try{const s=await this.options.requester.requestData(t.queryVersionId,e);if(!s.success)throw new c(t.queryVersionId,s.message||"Query failed",void 0,{params:e});return s.data}catch(t){if(n=t,this.log("warn",`Query attempt ${o+1}/${s+1} failed:`,t),o<s){const t="exponential"===r?i*Math.pow(2,o):i;await this.delay(t)}}throw n||new Error("Query failed after all retries")}async handleLoadError(t,e,s){const{binding:i}=t,r=i.onError;t.retryCount++,void 0!==r?.fallbackValue&&this.options.stateSetter.setVariable(i.targetState,r.fallbackValue),r?.showError&&this.options.onDataError?.(i.id,e),this.log("error",`Binding ${i.id} load failed:`,e)}setupAutoRefresh(t,e){t.refreshTimer&&(clearInterval(t.refreshTimer),t.refreshTimer=void 0);const s=t.binding.refreshInterval;!s||s<=0||(t.refreshTimer=setInterval(()=>{this.loadBinding(t.binding.id,e,!0).catch(e=>{this.log("error",`Auto refresh for ${t.binding.id} failed:`,e)})},1e3*s))}isCacheValid(t){return!(!t.cachedData||!t.lastLoadTime||t.cacheExpireTime&&Date.now()>t.cacheExpireTime)}resolveParams(t,e){const s={};for(const[i,r]of Object.entries(t))s[i]=this.resolveValue(r,e);return s}resolveValue(t,e){if(null==t)return t;if("object"==typeof t&&!Array.isArray(t)){const s=t;if("expression"===s.type||"binding"===s.type)return this.options.expressionEngine.evaluateWithFallback(s.expression,e,s.fallback);const i={};for(const[t,r]of Object.entries(s))i[t]=this.resolveValue(r,e);return i}return"string"==typeof t&&t.includes("${")?this.options.expressionEngine.evaluateTemplate(t,e):t}evaluateCondition(t,e){const s=void 0===t.fallback||t.fallback,i=this.options.expressionEngine.evaluateWithFallback(t.value,e,s);return Boolean(i)}applyTransform(t,e,s){const i={...s,local:{...s.local||{},$data:t,$response:t}},r=void 0!==e.fallback?e.fallback:t;return this.options.expressionEngine.evaluateWithFallback(e.value,i,r)}delay(t){return new Promise(e=>setTimeout(e,t))}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},f=class{constructor(t={}){this.handlers=new Map,this.options={debug:!1,maxListeners:100,...t}}emit(t){this.options.debug&&this.log("debug",`Event emitted: ${t.type}`,t);const e=this.handlers.get(t.type);e&&e.forEach(e=>{try{e(t)}catch(e){this.log("error",`Error in event handler for ${t.type}:`,e)}})}on(t,e){let s=this.handlers.get(t);return s||(s=new Set,this.handlers.set(t,s)),s.size>=(this.options.maxListeners??100)&&this.log("warn",`Max listeners (${this.options.maxListeners}) reached for event: ${t}`),s.add(e),()=>{s?.delete(e),0===s?.size&&this.handlers.delete(t)}}off(t,e){const s=this.handlers.get(t);s&&(s.delete(e),0===s.size&&this.handlers.delete(t))}once(t,e){const s=this.on(t,t=>{s(),e(t)});return s}clear(t){t?this.handlers.delete(t):this.handlers.clear()}listenerCount(t){return this.handlers.get(t)?.size??0}static createEvent(t,e,s){return{type:t,data:e,timestamp:Date.now(),traceId:s}}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},m=class t{constructor(t){this.debounceTimers=new Map,this.throttleTimers=new Map,this.options=t}async handleEvent(t,e,s){if(t.condition&&!this.evaluateCondition(t.condition,s,e))return void this.log("debug",`Handler ${t.id} skipped by condition`);if(t.throttle&&t.throttle>0&&!this.throttle(t.id,t.throttle))return void this.log("debug",`Handler ${t.id} throttled`);t.debounce&&t.debounce>0&&await this.debounce(t.id,t.debounce);const i={$event:e,$prevResult:void 0,$results:{}};await this.executeActionChain(t.actions,s,i)}async executeActionChain(t,e,s){const i=[];for(let r=0;r<t.length;r++){const n=t[r];if(n.condition){const t=this.buildActionContext(e,s);if(!this.evaluateCondition(n.condition,t,s.$event)){this.log("debug",`Action ${n.id||r} skipped by condition`);continue}}const o=this.executeSingleAction(n,e,s);n.async?i.push(o):await o}i.length>0&&await Promise.allSettled(i)}async executeSingleAction(t,e,s){const i=t.id||t.alias||t.builtinAction||t.actionDefinitionVersionId||"unknown";t.silent||this.options.executor.showLoading();try{const r=this.buildActionContext(e,s),n=this.resolveParams(t.params||{},r);this.options.onActionStart?.(t,n);const o=await this.executeWithRetry(t,n);s.$prevResult=o,t.id&&(s.$results[t.id]=o),this.options.onActionComplete?.(t,{success:!0,data:o}),this.log("debug",`Action ${i} completed successfully`),t.onSuccess&&t.onSuccess.length>0&&await this.executeActionChain(t.onSuccess,e,s)}catch(r){this.log("error",`Action ${i} failed:`,r),this.options.onActionComplete?.(t,{success:!1,error:r}),t.onError&&t.onError.length>0&&await this.executeActionChain(t.onError,e,{...s,$prevResult:{error:r.message}})}finally{t.silent||this.options.executor.hideLoading(),t.onFinally&&t.onFinally.length>0&&await this.executeActionChain(t.onFinally,e,s)}}async executeWithRetry(t,e){const s=t.policy?.retry?.maxAttempts??1,i=t.policy?.retry?.backoffMs??1e3,r=t.policy?.timeoutMs;let n;for(let o=1;o<=s;o++)try{let s;if(t.builtinAction)s=this.executeBuiltinAction(t.builtinAction,e);else{if(!t.actionDefinitionVersionId)throw new a("unknown","Action must specify builtinAction or actionDefinitionVersionId");s=this.executeCustomAction(t.actionDefinitionVersionId,e)}return r&&(s=this.withTimeout(s,r)),await s}catch(t){n=t,this.log("warn",`Action attempt ${o}/${s} failed:`,t),o<s&&await this.delay(i*o)}throw n||new Error("Action failed after all retries")}async executeBuiltinAction(t,e){switch(t){case"setState":return this.options.executor.setState(e.key,e.value),{success:!0};case"navigate":return this.options.executor.navigate({to:e.to??e.url,type:e.replace?"replace":e.external?"external":"push",params:e.params,query:e.query,newWindow:e.newWindow??e.newTab}),{success:!0};case"openDialog":return await this.options.executor.openDialog({type:e.type,content:e.content,title:e.title});case"closeDialog":return this.options.executor.closeDialog(e.dialogId),{success:!0};case"showToast":return this.options.executor.showToast({message:e.message,type:e.type,duration:e.duration}),{success:!0};case"showLoading":return this.options.executor.showLoading(e.message),{success:!0};case"hideLoading":return this.options.executor.hideLoading(),{success:!0};case"refreshData":return await this.options.executor.refreshData(e.queryId),{success:!0};case"track":return this.options.executor.track({eventName:e.eventName,params:e.params}),{success:!0};default:throw new a(t,`Unknown builtin action: ${t}`)}}async executeCustomAction(t,e){const s=t.split("@")[0],i=await this.options.executor.executeAction(s,{...e,actionDefinitionVersionId:t});if(!i.success)throw new a(s,i.errorMessage||"Action execution failed",void 0,t,{errorCode:i.errorCode});return i.data}resolveParams(t,e){const s={};for(const[i,r]of Object.entries(t))s[i]=this.resolveValue(r,e);return s}resolveValue(e,s){if(null==e)return e;if("string"==typeof e){if(e.startsWith("${")&&e.endsWith("}")){const t=e.slice(2,-1);return this.options.expressionEngine.evaluateWithFallback(t,s,e)}return e.includes("${")?this.options.expressionEngine.evaluateTemplate(e,s):e}if("number"==typeof e||"boolean"==typeof e)return e;if(Array.isArray(e))return e.map(t=>this.resolveValue(t,s));if("object"==typeof e){const i=e;if("string"==typeof i.type&&t.EXPRESSION_TYPES.includes(i.type)&&"string"==typeof i.value){const t=i;return this.options.expressionEngine.evaluateWithFallback(t.value,s,t.fallback)}const r={};for(const[t,e]of Object.entries(i))r[t]=this.resolveValue(e,s);return r}return e}evaluateCondition(t,e,s){const i={...e,local:{...e.local||{},$event:s}},r=void 0===t.fallback||t.fallback,n=this.options.expressionEngine.evaluateWithFallback(t.value,i,r);return Boolean(n)}buildActionContext(t,e){return{...t,local:{...t.local||{},$event:e.$event,$prevResult:e.$prevResult,$results:e.$results}}}withTimeout(t,e){return new Promise((s,i)=>{const r=setTimeout(()=>{i(new Error(`Action timed out after ${e}ms`))},e);t.then(t=>{clearTimeout(r),s(t)}).catch(t=>{clearTimeout(r),i(t)})})}debounce(t,e){return new Promise(s=>{const i=this.debounceTimers.get(t);i&&clearTimeout(i);const r=setTimeout(()=>{this.debounceTimers.delete(t),s()},e);this.debounceTimers.set(t,r)})}throttle(t,e){const s=Date.now();return!(s-(this.throttleTimers.get(t)??0)<e||(this.throttleTimers.set(t,s),0))}delay(t){return new Promise(e=>setTimeout(e,t))}destroy(){this.debounceTimers.forEach(t=>clearTimeout(t)),this.debounceTimers.clear(),this.throttleTimers.clear()}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}};m.EXPRESSION_TYPES=["state","binding","local","template","computed"];var g=m,y=class{constructor(t){this.pos=0,this.tokens=[],this.input=t}tokenize(){for(this.pos=0,this.tokens=[];this.pos<this.input.length&&(this.skipWhitespace(),!(this.pos>=this.input.length));){const t=this.readToken();t&&this.tokens.push(t)}return this.tokens.push({type:"EOF",value:null,start:this.input.length,end:this.input.length}),this.tokens}readToken(){const t=this.input[this.pos],e=this.pos;if(this.isDigit(t)||"-"===t&&this.isDigit(this.peek(1)))return this.readNumber();if('"'===t||"'"===t)return this.readString(t);if(this.isIdentifierStart(t))return this.readIdentifier();const s=this.readOperator();if(s)return s;switch(t){case".":return this.pos++,{type:"DOT",value:".",start:e,end:this.pos};case"[":return this.pos++,{type:"LBRACKET",value:"[",start:e,end:this.pos};case"]":return this.pos++,{type:"RBRACKET",value:"]",start:e,end:this.pos};case"(":return this.pos++,{type:"LPAREN",value:"(",start:e,end:this.pos};case")":return this.pos++,{type:"RPAREN",value:")",start:e,end:this.pos};case",":return this.pos++,{type:"COMMA",value:",",start:e,end:this.pos};case"?":return this.pos++,{type:"QUESTION",value:"?",start:e,end:this.pos};case":":return this.pos++,{type:"COLON",value:":",start:e,end:this.pos}}throw new Error(`Unexpected character '${t}' at position ${this.pos}`)}readNumber(){const t=this.pos;let e="";for("-"===this.input[this.pos]&&(e+="-",this.pos++);this.isDigit(this.input[this.pos]);)e+=this.input[this.pos],this.pos++;if("."===this.input[this.pos]&&this.isDigit(this.peek(1)))for(e+=".",this.pos++;this.isDigit(this.input[this.pos]);)e+=this.input[this.pos],this.pos++;return{type:"NUMBER",value:parseFloat(e),start:t,end:this.pos}}readString(t){const e=this.pos;this.pos++;let s="";for(;this.pos<this.input.length&&this.input[this.pos]!==t;){if("\\"===this.input[this.pos]){this.pos++;const t=this.input[this.pos];switch(t){case"n":s+="\n";break;case"t":s+="\t";break;case"r":s+="\r";break;case"\\":s+="\\";break;case'"':s+='"';break;case"'":s+="'";break;default:s+=t}}else s+=this.input[this.pos];this.pos++}if(this.input[this.pos]!==t)throw new Error(`Unterminated string at position ${e}`);return this.pos++,{type:"STRING",value:s,start:e,end:this.pos}}readIdentifier(){const t=this.pos;let e="";for(;this.pos<this.input.length&&this.isIdentifierChar(this.input[this.pos]);)e+=this.input[this.pos],this.pos++;return"true"===e?{type:"BOOLEAN",value:!0,start:t,end:this.pos}:"false"===e?{type:"BOOLEAN",value:!1,start:t,end:this.pos}:"null"===e?{type:"NULL",value:null,start:t,end:this.pos}:{type:"IDENTIFIER",value:e,start:t,end:this.pos}}readOperator(){const t=this.pos,e=this.input.slice(this.pos,this.pos+2),s=this.input[this.pos];return["==","!=",">=","<=","&&","||","??"].includes(e)?(this.pos+=2,{type:"OPERATOR",value:e,start:t,end:this.pos}):["+","-","*","/","%",">","<","!"].includes(s)?(this.pos++,{type:"OPERATOR",value:s,start:t,end:this.pos}):null}skipWhitespace(){for(;this.pos<this.input.length&&/\s/.test(this.input[this.pos]);)this.pos++}isDigit(t){return/[0-9]/.test(t)}isIdentifierStart(t){return/[a-zA-Z_$]/.test(t)}isIdentifierChar(t){return/[a-zA-Z0-9_$]/.test(t)}peek(t=1){return this.input[this.pos+t]||""}},b={"||":1,"??":1,"&&":2,"==":3,"!=":3,"<":4,">":4,"<=":4,">=":4,"+":5,"-":5,"*":6,"/":6,"%":6},w=class{constructor(t){this.pos=0,this.tokens=t}parse(){const t=this.parseExpression();if("EOF"!==this.current().type)throw new Error(`Unexpected token '${this.current().value}' at position ${this.current().start}`);return t}parseExpression(){return this.parseTernary()}parseTernary(){const t=this.parseBinary(0);if("QUESTION"===this.current().type){this.advance();const e=this.parseExpression();return this.expect("COLON"),{type:"conditional",test:t,consequent:e,alternate:this.parseExpression(),raw:void 0}}return t}parseBinary(t){let e=this.parseUnary();for(;;){const s=this.current();if("OPERATOR"!==s.type)break;const i=b[s.value];if(void 0===i||i<t)break;this.advance();const r=this.parseBinary(i+1);e={type:"binary",operator:s.value,left:e,right:r,raw:void 0}}return e}parseUnary(){const t=this.current();if("OPERATOR"===t.type&&("!"===t.value||"-"===t.value)){this.advance();const e=this.parseUnary();return{type:"unary",operator:t.value,argument:e,raw:void 0}}return this.parsePostfix()}parsePostfix(){let e=this.parsePrimary();for(;;){const s=this.current();if("DOT"===s.type)this.advance(),e={type:"member",object:e,property:this.expect("IDENTIFIER").value,computed:!1,raw:void 0};else if("LBRACKET"===s.type){this.advance();const t=this.parseExpression();this.expect("RBRACKET"),e={type:"member",object:e,property:t,computed:!0,raw:void 0}}else{if("LPAREN"!==s.type||"identifier"!==e.type)break;{const i=e.name;if(!t.ALLOWED_FUNCTION_NAMES.includes(i))throw new Error(`Unknown function '${i}' at position ${s.start}`);this.advance();const r=this.parseArguments();this.expect("RPAREN"),e={type:"call",callee:i,arguments:r,raw:void 0}}}}return e}parsePrimary(){const t=this.current();if("NUMBER"===t.type||"STRING"===t.type||"BOOLEAN"===t.type||"NULL"===t.type)return this.advance(),{type:"literal",value:t.value,start:t.start,end:t.end,raw:void 0};if("IDENTIFIER"===t.type)return this.advance(),{type:"identifier",name:t.value,start:t.start,end:t.end,raw:void 0};if("LBRACKET"===t.type)return this.parseArray();if("LPAREN"===t.type){this.advance();const t=this.parseExpression();return this.expect("RPAREN"),t}throw new Error(`Unexpected token '${t.value}' at position ${t.start}`)}parseArray(){const t=this.current().start;this.advance();const e=[];for(;"RBRACKET"!==this.current().type&&(e.push(this.parseExpression()),"COMMA"===this.current().type);)this.advance();const s=this.current().end;return this.expect("RBRACKET"),{type:"array",elements:e,start:t,end:s,raw:void 0}}parseArguments(){const t=[];if("RPAREN"!==this.current().type)for(t.push(this.parseExpression());"COMMA"===this.current().type;)this.advance(),t.push(this.parseExpression());return t}current(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}expect(t){const e=this.current();if(e.type!==t)throw new Error(`Expected '${t}' but got '${e.type}' at position ${e.start}`);return this.advance()}},v={len:t=>"string"==typeof t||Array.isArray(t)?t.length:0,trim:t=>String(t??"").trim(),upper:t=>String(t??"").toUpperCase(),lower:t=>String(t??"").toLowerCase(),substr:(t,e,s)=>{const i=String(t??""),r=Number(e)||0,n=void 0!==s?Number(s):void 0;return i.substring(r,void 0!==n?r+n:void 0)},concat:(...t)=>t.map(t=>String(t??"")).join(""),replace:(t,e,s)=>String(t??"").split(String(e)).join(String(s)),split:(t,e)=>String(t??"").split(String(e)),join:(t,e)=>Array.isArray(t)?t.join(void 0!==e?String(e):","):"",startsWith:(t,e)=>String(t??"").startsWith(String(e)),endsWith:(t,e)=>String(t??"").endsWith(String(e)),contains:(t,e)=>String(t??"").includes(String(e)),toNumber:t=>{const e=Number(t);return isNaN(e)?0:e},toString:t=>String(t??""),toInt:t=>Math.trunc(Number(t)||0),toFloat:t=>parseFloat(String(t))||0,round:(t,e)=>{const s=Number(t)||0,i=Number(e)||0,r=Math.pow(10,i);return Math.round(s*r)/r},floor:t=>Math.floor(Number(t)||0),ceil:t=>Math.ceil(Number(t)||0),abs:t=>Math.abs(Number(t)||0),min:(...t)=>{const e=t.map(t=>Number(t)).filter(t=>!isNaN(t));return e.length>0?Math.min(...e):0},max:(...t)=>{const e=t.map(t=>Number(t)).filter(t=>!isNaN(t));return e.length>0?Math.max(...e):0},sum:t=>Array.isArray(t)?t.reduce((t,e)=>t+(Number(e)||0),0):0,avg:t=>Array.isArray(t)&&0!==t.length?t.reduce((t,e)=>t+(Number(e)||0),0)/t.length:0,random:()=>Math.random(),randomInt:(t,e)=>{const s=Math.ceil(Number(t)||0),i=Math.floor(Number(e)||100);return Math.floor(Math.random()*(i-s+1))+s},now:()=>Date.now(),today:()=>(new Date).toISOString().split("T")[0],dateFormat:(t,e)=>{const s=new Date(Number(t)||Date.now()),i=t=>t.toString().padStart(2,"0");return String(e||"YYYY-MM-DD").replace("YYYY",s.getFullYear().toString()).replace("MM",i(s.getMonth()+1)).replace("DD",i(s.getDate())).replace("HH",i(s.getHours())).replace("mm",i(s.getMinutes())).replace("ss",i(s.getSeconds()))},dateParse:t=>new Date(String(t)).getTime(),year:t=>new Date(Number(t)||Date.now()).getFullYear(),month:t=>new Date(Number(t)||Date.now()).getMonth()+1,day:t=>new Date(Number(t)||Date.now()).getDate(),addDays:(t,e)=>{const s=new Date(Number(t)||Date.now());return s.setDate(s.getDate()+(Number(e)||0)),s.getTime()},diffDays:(t,e)=>{const s=new Date(Number(t)||Date.now()),i=new Date(Number(e)||Date.now()),r=Math.abs(i.getTime()-s.getTime());return Math.floor(r/864e5)},isNull:t=>null==t,isUndefined:t=>void 0===t,isEmpty:t=>null==t||("string"==typeof t||Array.isArray(t)?0===t.length:"object"==typeof t&&0===Object.keys(t).length),isArray:t=>Array.isArray(t),isObject:t=>null!==t&&"object"==typeof t&&!Array.isArray(t),isString:t=>"string"==typeof t,isNumber:t=>"number"==typeof t&&!isNaN(t),isBoolean:t=>"boolean"==typeof t,typeOf:t=>null===t?"null":Array.isArray(t)?"array":typeof t,default:(t,e)=>t??e,coalesce:(...t)=>{for(const e of t)if(null!=e)return e;return null},ifElse:(t,e,s)=>t?e:s,first:t=>{if(Array.isArray(t))return t[0]},last:t=>{if(Array.isArray(t))return t[t.length-1]},at:(t,e)=>{if(Array.isArray(t))return t[Number(e)||0]},slice:(t,e,s)=>Array.isArray(t)?t.slice(Number(e)||0,void 0!==s?Number(s):void 0):[],includes:(t,e)=>!!Array.isArray(t)&&t.includes(e),indexOf:(t,e)=>Array.isArray(t)?t.indexOf(e):-1,reverse:t=>Array.isArray(t)?[...t].reverse():[],sort:t=>Array.isArray(t)?[...t].sort():[],unique:t=>Array.isArray(t)?[...new Set(t)]:[],flatten:t=>Array.isArray(t)?t.flat():[],count:t=>Array.isArray(t)?t.length:0,get:(t,e,s)=>{if(null==t)return s;const i=String(e).split(".");let r=t;for(const t of i){if(null==r)return s;r=r[t]}return r??s},keys:t=>"object"!=typeof t||null===t?[]:Object.keys(t),values:t=>"object"!=typeof t||null===t?[]:Object.values(t),entries:t=>"object"!=typeof t||null===t?[]:Object.entries(t),has:(t,e)=>"object"==typeof t&&null!==t&&String(e)in t,merge:(...t)=>{const e={};for(const s of t)"object"==typeof s&&null!==s&&Object.assign(e,s);return e},and:(...t)=>t.every(t=>Boolean(t)),or:(...t)=>t.some(t=>Boolean(t)),not:t=>!t,eq:(t,e)=>t===e,ne:(t,e)=>t!==e,gt:(t,e)=>Number(t)>Number(e),gte:(t,e)=>Number(t)>=Number(e),lt:(t,e)=>Number(t)<Number(e),lte:(t,e)=>Number(t)<=Number(e),between:(t,e,s)=>{const i=Number(t);return i>=Number(e)&&i<=Number(s)},formatNumber:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return s.toLocaleString(void 0,{minimumFractionDigits:i,maximumFractionDigits:i})},formatCurrency:(t,e)=>{const s=Number(t)||0,i=String(e||"CNY");return s.toLocaleString("zh-CN",{style:"currency",currency:i})},formatPercent:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return(100*s).toFixed(i)+"%"},currency:(t,e,s)=>{const i=Number(t)||0,r=String(e??"¥"),n=Number(s)??2;return`${r}${i.toLocaleString(void 0,{minimumFractionDigits:n,maximumFractionDigits:n})}`},percent:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return(100*s).toFixed(i)+"%"},number:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return s.toLocaleString(void 0,{minimumFractionDigits:i,maximumFractionDigits:i})},pluralize:(t,e,s)=>{const i=Number(t)||0;return`${i} ${String(1===i?e:s)}`},mask:(t,e,s,i)=>{const r=String(t??""),n=Number(e)||3,o=Number(s)||4,a=String(i??"*");if(r.length<=n+o)return r;const c=r.slice(0,n),h=r.slice(-o);return c+a.repeat(r.length-n-o)+h},jsonParse:t=>{try{return JSON.parse(String(t))}catch{return null}},jsonStringify:t=>JSON.stringify(t),toJSON:t=>JSON.stringify(t),fromJSON:t=>{try{return JSON.parse(String(t))}catch{return null}},clamp:(t,e,s)=>{const i=Number(t)||0,r=Number(e)||0,n=Number(s)||100;return Math.min(Math.max(i,r),n)},length:t=>Array.isArray(t)||"string"==typeof t?t.length:0,average:t=>Array.isArray(t)&&0!==t.length?t.reduce((t,e)=>t+(Number(e)||0),0)/t.length:0,dateAdd:(t,e,s)=>{const i=new Date(Number(t)||Date.now()),r=Number(e)||0;switch(String(s??"day").toLowerCase()){case"year":case"years":i.setFullYear(i.getFullYear()+r);break;case"month":case"months":i.setMonth(i.getMonth()+r);break;case"week":case"weeks":i.setDate(i.getDate()+7*r);break;case"day":case"days":default:i.setDate(i.getDate()+r);break;case"hour":case"hours":i.setHours(i.getHours()+r);break;case"minute":case"minutes":i.setMinutes(i.getMinutes()+r)}return i.getTime()},dateDiff:(t,e,s)=>{const i=new Date(Number(t)||Date.now()),r=new Date(Number(e)||Date.now()).getTime()-i.getTime();switch(String(s??"day").toLowerCase()){case"year":case"years":return Math.floor(r/31536e6);case"month":case"months":return Math.floor(r/2592e6);case"week":case"weeks":return Math.floor(r/6048e5);case"day":case"days":default:return Math.floor(r/864e5);case"hour":case"hours":return Math.floor(r/36e5);case"minute":case"minutes":return Math.floor(r/6e4)}},$if:(t,e,s)=>t?e:s,toBoolean:t=>"string"==typeof t?"false"!==t.toLowerCase()&&"0"!==t&&""!==t:Boolean(t),substring:(t,e,s)=>{const i=String(t??""),r=Number(e)||0,n=void 0!==s?Number(s):void 0;return i.substring(r,n)},padStart:(t,e,s)=>{const i=String(t??""),r=Number(e)||0,n=String(s??" ");return i.padStart(r,n)},padEnd:(t,e,s)=>{const i=String(t??""),r=Number(e)||0,n=String(s??" ");return i.padEnd(r,n)},repeat:(t,e)=>{const s=String(t??""),i=Math.max(0,Math.floor(Number(e)||0));return s.repeat(i)}},$=class{constructor(t={}){this.depth=0,this.startTime=0,this.options={maxDepth:100,timeout:1e3,debug:!1,...t}}evaluate(t,e){this.depth=0,this.startTime=Date.now();try{return{value:this.evaluateNode(t,e)}}catch(t){return{value:void 0,error:t instanceof Error?t:new Error(String(t))}}}evaluateNode(t,e){switch(this.checkLimits(),t.type){case"literal":return this.evaluateLiteral(t);case"identifier":return this.evaluateIdentifier(t,e);case"member":return this.evaluateMember(t,e);case"call":return this.evaluateCall(t,e);case"binary":return this.evaluateBinary(t,e);case"unary":return this.evaluateUnary(t,e);case"conditional":return this.evaluateConditional(t,e);case"array":return this.evaluateArray(t,e);default:throw new o("",`Unknown node type: ${t.type}`)}}evaluateLiteral(t){return t.value}evaluateIdentifier(t,e){const s=t.name;switch(s){case"state":return e.state;case"binding":case"query":return e.binding;case"local":return e.local;case"props":return e.props;case"event":return e.event;case"item":return e.local?.item;case"index":return e.local?.index;default:if(e.local&&s in e.local)return e.local[s];throw new o("",`Unknown variable '${s}'. Available: state, binding, local, props, event`)}}evaluateMember(t,e){const s=this.evaluateNode(t.object,e);if(null==s)return;let i;return i=t.computed?this.evaluateNode(t.property,e):t.property,"object"==typeof s&&null!==s?s[i]:void 0}evaluateCall(t,e){const s=v[t.callee];if(!s)throw new o("",`Unknown function '${t.callee}'`);return s(...t.arguments.map(t=>this.evaluateNode(t,e)))}evaluateBinary(t,e){const s=t.operator;if("&&"===s){const s=this.evaluateNode(t.left,e);return s?this.evaluateNode(t.right,e):s}if("||"===s){return this.evaluateNode(t.left,e)||this.evaluateNode(t.right,e)}if("??"===s){const s=this.evaluateNode(t.left,e);return null!=s?s:this.evaluateNode(t.right,e)}const i=this.evaluateNode(t.left,e),r=this.evaluateNode(t.right,e);switch(s){case"+":return"string"==typeof i||"string"==typeof r?String(i)+String(r):i+r;case"-":return i-r;case"*":return i*r;case"/":return i/r;case"%":return i%r;case"==":return i===r;case"!=":return i!==r;case"<":return i<r;case">":return i>r;case"<=":return i<=r;case">=":return i>=r;default:throw new o("",`Unknown operator '${s}'`)}}evaluateUnary(t,e){const s=this.evaluateNode(t.argument,e);switch(t.operator){case"!":return!s;case"-":return-s;default:throw new o("",`Unknown unary operator '${t.operator}'`)}}evaluateConditional(t,e){return this.evaluateNode(t.test,e)?this.evaluateNode(t.consequent,e):this.evaluateNode(t.alternate,e)}evaluateArray(t,e){return t.elements.map(t=>this.evaluateNode(t,e))}checkLimits(){if(this.depth++,this.depth>(this.options.maxDepth??100))throw new o("","Maximum recursion depth exceeded");if(Date.now()-this.startTime>(this.options.timeout??1e3))throw new o("","Expression evaluation timeout")}},x=class{constructor(t={}){this.astCache=new Map,this.options={cacheAST:!0,maxCacheSize:1e3,...t},this.evaluator=new $(t)}evaluate(t,e){try{const s=this.parse(t);return this.evaluator.evaluate(s,e)}catch(t){return{value:void 0,error:t instanceof Error?t:new Error(String(t))}}}evaluateWithFallback(t,e,s){const i="string"==typeof t?t:t.value,r="object"==typeof t&&void 0!==t.fallback?t.fallback:s,n=this.evaluate(i,e);return n.error?(this.log("warn",`Expression evaluation failed: ${n.error.message}`,i),r):n.value}evaluateTemplate(t,e){return t.replace(/\$\{([^}]+)\}/g,(t,s)=>{const i=this.evaluate(s.trim(),e);return i.error?(this.log("warn",`Template expression failed: ${i.error.message}`,s),""):String(i.value??"")})}parse(t){if(this.options.cacheAST){const e=this.astCache.get(t);if(e)return e}try{const e=new y(t).tokenize(),s=new w(e).parse();return this.options.cacheAST&&(this.astCache.size>=(this.options.maxCacheSize??1e3)&&Array.from(this.astCache.keys()).slice(0,Math.floor(this.astCache.size/2)).forEach(t=>this.astCache.delete(t)),this.astCache.set(t,s)),s}catch(e){throw new o(t,e instanceof Error?e.message:"Parse error")}}validate(t){const e=[],s=[],i=[],r=[];try{const e=this.parse(t);return this.collectReferences(e,i,r),{valid:!0,errors:[],warnings:s,referencedPaths:i,usedFunctions:r}}catch(t){return e.push({type:"invalid_syntax",message:t instanceof Error?t.message:"Parse error"}),{valid:!1,errors:e,warnings:s,referencedPaths:i,usedFunctions:r}}}clearCache(){this.astCache.clear()}collectReferences(t,e,s){switch(t.type){case"identifier":e.push(t.name);break;case"member":{const s=this.buildMemberPath(t);s&&e.push(s);break}case"call":s.push(t.callee),t.arguments.forEach(t=>this.collectReferences(t,e,s));break;case"binary":this.collectReferences(t.left,e,s),this.collectReferences(t.right,e,s);break;case"unary":this.collectReferences(t.argument,e,s);break;case"conditional":this.collectReferences(t.test,e,s),this.collectReferences(t.consequent,e,s),this.collectReferences(t.alternate,e,s);break;case"array":t.elements.forEach(t=>this.collectReferences(t,e,s))}}buildMemberPath(t){if("identifier"===t.type)return t.name;if("member"===t.type&&!t.computed){const e=this.buildMemberPath(t.object);if(e)return`${e}.${t.property}`}return null}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},S=class{constructor(t){this.loadingCount=0,this.loadingElement=null,this.clipboard={write:async t=>{try{return await navigator.clipboard.writeText(t),!0}catch(e){return this.log("error","Clipboard write failed:",e),this.fallbackCopy(t)}},read:async()=>{try{return await navigator.clipboard.readText()}catch(t){return this.log("error","Clipboard read failed:",t),null}}},this.storage={get:t=>{const e=`${this.storageNamespace}:${t}`,s=localStorage.getItem(e);if(!s)return null;try{const t=JSON.parse(s);return t.expires&&Date.now()>t.expires?(localStorage.removeItem(e),null):t.value}catch{return null}},set:(t,e,s)=>{const i=`${this.storageNamespace}:${t}`,r={value:e,expires:s?.ttlSeconds?Date.now()+1e3*s.ttlSeconds:void 0};("session"===s?.level?sessionStorage:localStorage).setItem(i,JSON.stringify(r))},remove:t=>{const e=`${this.storageNamespace}:${t}`;localStorage.removeItem(e),sessionStorage.removeItem(e)},clear:()=>{const t=`${this.storageNamespace}:`;for(let e=localStorage.length-1;e>=0;e--){const s=localStorage.key(e);s?.startsWith(t)&&localStorage.removeItem(s)}for(let e=sessionStorage.length-1;e>=0;e--){const s=sessionStorage.key(e);s?.startsWith(t)&&sessionStorage.removeItem(s)}}},this.options=t,this.storageNamespace=`djvlc:${t.context.appId}`}async navigate(t){this.log("debug","Navigate:",t),this.track({eventName:"djvlc_navigate",params:{to:t.to,type:t.type},type:"click"});let e=t.to;if(t.query){const s=new URLSearchParams(t.query);e+=(e.includes("?")?"&":"?")+s.toString()}switch(t.type){case"external":t.newWindow?window.open(e,"_blank","noopener,noreferrer"):window.location.href=e;break;case"replace":window.location.replace(e);break;default:t.newWindow?window.open(e,"_blank"):window.location.href=e}}track(t){this.log("debug","Track event:",t);const e=this.options.context;fetch(`${this.options.apiBaseUrl}/track`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({eventName:t.eventName,params:t.params,type:t.type||"custom",timestamp:Date.now(),context:{pageVersionId:e.pageVersionId,runtimeVersion:e.runtimeVersion,userId:e.userId,deviceId:e.deviceId,channel:e.channel,appId:e.appId,env:e.env}}),keepalive:!0}).catch(t=>{this.log("warn","Track failed:",t)})}async requestData(t,e){this.log("debug",`Requesting data: ${t}`,e);const s=performance.now(),i=this.options.context;try{const r=await fetch(`${this.options.apiBaseUrl}/data/query`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({queryVersionId:t,params:e||{},context:{pageVersionId:i.pageVersionId,uid:i.userId,deviceId:i.deviceId}})});if(!r.ok){const t=await r.text();throw new Error(`HTTP ${r.status}: ${t||r.statusText}`)}const n=await r.json(),o=performance.now()-s;if(this.log("debug",`Data query completed in ${o.toFixed(2)}ms`),!n.success)throw new Error(n.message||n.errorMessage||"Query failed");return this.options.stateManager.setQuery(t,n.data),n.data}catch(e){const i=performance.now()-s;throw this.log("error",`Data query failed: ${t} (${i.toFixed(2)}ms)`,e),e}}async executeAction(t,e={}){this.log("debug",`Executing action: ${t}`,e);const s=performance.now(),i=this.options.context,r=this.generateIdempotencyKey(t,e);this.track({eventName:"djvlc_action_start",params:{actionType:t,idempotencyKey:r},type:"custom"});try{const n=await fetch(`${this.options.apiBaseUrl}/actions/execute`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({actionType:t,params:e||{},context:{pageVersionId:i.pageVersionId,uid:i.userId,deviceId:i.deviceId,channel:i.channel,appId:i.appId},idempotencyKey:r})});if(!n.ok){const e=await n.text(),i=performance.now()-s;return this.log("error",`Action HTTP error: ${t} (${i.toFixed(2)}ms)`,e),{success:!1,errorCode:`HTTP_${n.status}`,errorMessage:e||n.statusText}}const o=await n.json(),a=performance.now()-s;return this.log("debug",`Action completed in ${a.toFixed(2)}ms`,{success:o.success}),this.track({eventName:o.success?"djvlc_action_success":"djvlc_action_fail",params:{actionType:t,idempotencyKey:r,duration:Math.round(a),errorCode:o.errorCode},type:"custom"}),{success:o.success,data:o.data,errorCode:o.errorCode,errorMessage:o.errorMessage}}catch(e){const i=performance.now()-s;return this.log("error",`Action failed: ${t} (${i.toFixed(2)}ms)`,e),this.track({eventName:"djvlc_action_error",params:{actionType:t,idempotencyKey:r,duration:Math.round(i),errorMessage:e instanceof Error?e.message:"Unknown error"},type:"custom"}),{success:!1,errorCode:"NETWORK_ERROR",errorMessage:e instanceof Error?e.message:"Action failed"}}}async openDialog(t){return this.log("debug","Open dialog:",t),new Promise(e=>{const s=new CustomEvent("djvlc:openDialog",{detail:{options:t,resolve:t=>e(t)}});document.dispatchEvent(s),setTimeout(()=>{e({confirmed:!1})},6e4)})}closeDialog(t){this.log("debug","Close dialog:",t);const e=new CustomEvent("djvlc:closeDialog",{detail:{dialogId:t}});document.dispatchEvent(e)}showToast(t){this.log("debug","Show toast:",t);const e=document.createElement("div");switch(e.className=`djvlc-toast djvlc-toast-${t.type||"info"} djvlc-toast-${t.position||"top"}`,e.setAttribute("role","alert"),e.textContent=t.message,Object.assign(e.style,{position:"fixed",left:"50%",transform:"translateX(-50%)",padding:"12px 24px",borderRadius:"8px",color:"#fff",fontSize:"14px",zIndex:"10000",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",transition:"opacity 0.3s, transform 0.3s",opacity:"0"}),e.style.backgroundColor={success:"#52c41a",error:"#ff4d4f",warning:"#faad14",info:"#1890ff"}[t.type||"info"],t.position){case"center":e.style.top="50%",e.style.transform="translate(-50%, -50%)";break;case"bottom":e.style.bottom="20px";break;default:e.style.top="20px"}document.body.appendChild(e),requestAnimationFrame(()=>{e.style.opacity="1"}),setTimeout(()=>{e.style.opacity="0",setTimeout(()=>e.remove(),300)},t.duration||3e3)}showLoading(t){this.loadingCount++,1===this.loadingCount&&(this.loadingElement=document.createElement("div"),this.loadingElement.className="djvlc-loading-overlay",this.loadingElement.innerHTML=`\n <div class="djvlc-loading-content">\n <div class="djvlc-loading-spinner"></div>\n <div class="djvlc-loading-message">${t||"加载中..."}</div>\n </div>\n `,Object.assign(this.loadingElement.style,{position:"fixed",top:"0",left:"0",right:"0",bottom:"0",backgroundColor:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:"10001"}),document.body.appendChild(this.loadingElement))}hideLoading(){this.loadingCount=Math.max(0,this.loadingCount-1),0===this.loadingCount&&this.loadingElement&&(this.loadingElement.remove(),this.loadingElement=null)}async share(t){if(this.log("debug","Share:",t),navigator.share)try{return await navigator.share({title:t.title,text:t.description,url:t.url}),{success:!0,channel:"native"}}catch(t){if("AbortError"===t.name)return{success:!1,cancelReason:"User cancelled"};throw t}return t.url&&await this.clipboard.write(t.url)?(this.showToast({message:"链接已复制",type:"success"}),{success:!0,channel:"link"}):{success:!1,cancelReason:"Share not supported"}}async confirm(t){return this.log("debug","Confirm:",t),window.confirm(t.content)}async showActionSheet(t){return this.log("debug","Show action sheet:",t),new Promise(e=>{const s=new CustomEvent("djvlc:showActionSheet",{detail:{options:t,resolve:t=>e(t)}});document.dispatchEvent(s),setTimeout(()=>{e({cancelled:!0})},6e4)})}previewImage(t){this.log("debug","Preview image:",t);const e=new CustomEvent("djvlc:previewImage",{detail:t});document.dispatchEvent(e)}async scanCode(){return this.log("debug","Scan code"),new Promise(t=>{const e=new CustomEvent("djvlc:scanCode",{detail:{resolve:e=>t(e)}});document.dispatchEvent(e),setTimeout(()=>{t({success:!1,cancelReason:"Timeout"})},6e4)})}getState(t){return this.options.stateManager.getVariable(t)}setState(t,e){this.options.stateManager.setVariable(t,e)}getContext(){const t=this.options.context;return{pageVersionId:t.pageVersionId,componentVersionId:"",instanceId:"",userId:t.userId,deviceId:t.deviceId,channel:t.channel,appId:t.appId,env:t.env}}buildHeaders(){const t={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(t.Authorization=`Bearer ${this.options.authToken}`),t}generateIdempotencyKey(t,e){const s=Date.now(),i=JSON.stringify(e||{});return`${t}:${s}:${this.simpleHash(i)}`}simpleHash(t){let e=0;for(let s=0;s<t.length;s++)e=(e<<5)-e+t.charCodeAt(s),e&=e;return Math.abs(e).toString(36)}fallbackCopy(t){const e=document.createElement("textarea");e.value=t,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{return document.execCommand("copy"),!0}catch{return!1}finally{document.body.removeChild(e)}}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},k=class{constructor(t={}){this.blockedComponentsMap=new Map,this.blockedActionsSet=new Set,this.allowedCapabilitiesSet=null,this.options={enableSRI:!0,cdnDomains:[],apiDomains:[],blockedComponents:[],blockedActions:[],applyCSPOnInit:!1,...t},this.updateBlockedList(t.blockedComponents?.map(t=>`${t.name}@${t.version}`)||[],t.blockedActions||[]),t.allowedCapabilities&&(this.allowedCapabilitiesSet=new Set(t.allowedCapabilities)),t.applyCSPOnInit&&this.applyCSP()}updateBlockedList(t,e){this.blockedComponentsMap.clear(),t.forEach(t=>{const[e,s]=t.split("@");e&&s&&this.blockedComponentsMap.set(t,{name:e,version:s,reason:"Blocked by registry"})}),this.blockedActionsSet=new Set(e)}addBlockedComponent(t){const e=`${t.name}@${t.version}`;this.blockedComponentsMap.set(e,t),this.log("warn",`Component blocked: ${e} - ${t.reason}`)}removeBlockedComponent(t,e){const s=`${t}@${e}`;this.blockedComponentsMap.delete(s),this.log("info",`Component unblocked: ${s}`)}isComponentBlocked(t,e){return this.blockedComponentsMap.has(`${t}@${e}`)}getBlockedInfo(t,e){return this.blockedComponentsMap.get(`${t}@${e}`)}getAllBlockedComponents(){return Array.from(this.blockedComponentsMap.values())}isActionBlocked(t){return this.blockedActionsSet.has(t)}isCapabilityAllowed(t){return!this.allowedCapabilitiesSet||this.allowedCapabilitiesSet.has(t)}validateCapabilities(t,e,s){if(!this.allowedCapabilitiesSet)return{valid:!0,disallowed:[]};const i=s.filter(t=>!this.allowedCapabilitiesSet.has(t));return i.length>0&&this.log("warn",`Component ${t}@${e} uses disallowed capabilities: ${i.join(", ")}`),{valid:0===i.length,disallowed:i}}async validateIntegrity(t,e,s,i){if(!this.options.enableSRI)return;const[n,o]=i.split("-");if(!n||!o)throw new r(t,e,i,"Invalid integrity format");const a=await this.computeHash(s,n);if(a!==o)throw this.log("error",`Integrity check failed for ${t}@${e}`),new r(t,e,o,a);this.log("debug",`Integrity check passed for ${t}@${e}`)}async generateIntegrity(t,e="sha384"){return`${e}-${await this.computeHash(t,e)}`}isAllowedUrl(t,e){const s="cdn"===e?this.options.cdnDomains:this.options.apiDomains;if(!s||0===s.length)return!0;try{const e=new URL(t);return s.some(t=>{if(t.startsWith("*.")){const s=t.slice(2);return e.hostname.endsWith(s)||e.hostname===s.slice(1)}return e.hostname===t})}catch{return!1}}validateExternalUrl(t){try{const e=new URL(t);if(!["http:","https:"].includes(e.protocol))return{safe:!1,reason:`Unsafe protocol: ${e.protocol}`};const s=e.hostname;return"localhost"===s||"127.0.0.1"===s||s.startsWith("192.168.")||s.startsWith("10.")||s.startsWith("172.16.")?{safe:!1,reason:"Internal network address not allowed"}:{safe:!0}}catch{return{safe:!1,reason:"Invalid URL format"}}}generateCSPPolicy(){const t=this.options.cdnDomains||[],e=this.options.apiDomains||[],s=["'self'",...t].join(" "),i=["'self'",...e,...t].join(" ");return["default-src 'self'",`script-src ${s}`,`style-src ${["'self'","'unsafe-inline'",...t].join(" ")}`,`img-src ${["'self'","data:","blob:",...t].join(" ")}`,`font-src ${["'self'","data:",...t].join(" ")}`,`connect-src ${i}`,"frame-ancestors 'self'","base-uri 'self'","form-action 'self'","upgrade-insecure-requests"].join("; ")}applyCSP(){if(document.querySelector('meta[http-equiv="Content-Security-Policy"]'))return void this.log("debug","CSP meta tag already exists, skipping");const t=document.createElement("meta");t.httpEquiv="Content-Security-Policy",t.content=this.generateCSPPolicy(),document.head.appendChild(t),this.log("info","CSP policy applied")}assertNotBlocked(t,e){const s=this.getBlockedInfo(t,e);if(s)throw new n(t,e,s.reason)}createSafeEvaluator(){return(t,e)=>{const s=Object.keys(e),i=Object.values(e);return new Function(...s,`"use strict"; return (${t});`)(...i)}}async computeHash(t,e){const s=(new TextEncoder).encode(t),i=await crypto.subtle.digest(e.toUpperCase(),s),r=Array.from(new Uint8Array(i));return btoa(String.fromCharCode(...r))}log(t,e,...s){this.options.logger&&this.options.logger[t](e,...s)}},E=class{constructor(t){this.spans=new Map,this.metrics=[],this.errors=[],this.options={enabled:!0,sampleRate:1,batchSize:50,flushInterval:3e4,...t},this.traceId=this.generateTraceId(),this.shouldSample=Math.random()<(this.options.sampleRate??1),this.options.enabled&&this.options.endpoint&&this.startAutoFlush(),"undefined"!=typeof window&&(window.addEventListener("beforeunload",()=>this.flush()),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()}))}getTraceId(){return this.traceId}getTraceparent(t){const e=t||this.generateSpanId(),s=this.shouldSample?"01":"00";return`00-${this.traceId}-${e}-${s}`}parseTraceparent(t){const e=t.split("-");if(4!==e.length)return null;const[,s,i,r]=e;return{traceId:s,parentSpanId:i,sampled:"01"===r}}startSpan(t,e,s){const i={spanId:this.generateSpanId(),traceId:this.traceId,parentSpanId:e,name:t,startTime:performance.now(),attributes:{pageVersionId:this.options.pageVersionId,...s}};return this.spans.set(i.spanId,i),this.log("debug",`Span started: ${t} (${i.spanId})`),i}endSpan(t,e="ok",s){const i=this.spans.get(t);if(i){i.endTime=performance.now(),i.status=e,s&&(i.attributes={...i.attributes,...s});const r=i.endTime-i.startTime;this.log("debug",`Span ended: ${i.name} (${t}) - ${r.toFixed(2)}ms [${e}]`)}}recordPageLoad(t){this.recordMetricInternal({type:"pageLoadTime",value:t,pageVersionId:this.options.pageVersionId,timestamp:Date.now()})}recordComponentLoad(t,e,s,i){this.recordMetricInternal({type:"componentLoadTime",value:s,pageVersionId:this.options.pageVersionId,componentName:t,componentVersion:e,timestamp:Date.now()}),i||this.recordError(new Error(`Component load failed: ${t}@${e}`),{componentVersion:`${t}@${e}`})}recordFirstRender(t){this.recordMetricInternal({type:"firstRenderTime",value:t,pageVersionId:this.options.pageVersionId,timestamp:Date.now()})}recordActionExecute(t,e,s,i){this.recordMetricInternal({type:"actionExecuteTime",value:s,pageVersionId:this.options.pageVersionId,actionType:t,timestamp:Date.now()}),i||this.recordError(new Error(`Action failed: ${t}`),{actionId:e})}recordQueryExecute(t,e,s,i=!1){this.recordMetricInternal({type:"queryFetchTime",value:e,pageVersionId:this.options.pageVersionId,queryId:t,timestamp:Date.now()}),this.log("debug",`Query ${t}: ${e.toFixed(2)}ms, cache: ${i}, success: ${s}`)}recordExpressionEval(t,e,s){e>1&&this.recordMetricInternal({type:"expressionEvalTime",value:e,pageVersionId:this.options.pageVersionId,timestamp:Date.now()})}recordError(t,e){const s={type:t.name||"Error",message:t.message,stack:t.stack,traceId:this.traceId,pageVersionId:this.options.pageVersionId,componentVersion:e?.componentVersion,actionId:e?.actionId,context:e,timestamp:Date.now()};this.errors.push(s),this.log("error",`Error recorded: ${t.message}`),this.options.onError?.(s),this.errors.length>=(this.options.batchSize??50)&&this.flush()}getMetrics(){return[...this.metrics]}getSpans(){return Array.from(this.spans.values())}getErrors(){return[...this.errors]}getPerformanceSummary(){const t=this.metrics.filter(t=>"componentLoadTime"===t.type),e=this.metrics.find(t=>"pageLoadTime"===t.type),s=this.metrics.find(t=>"firstRenderTime"===t.type);return{pageLoadTime:e?.value,firstRenderTime:s?.value,componentCount:t.length,avgComponentLoadTime:t.length>0?t.reduce((t,e)=>t+e.value,0)/t.length:0,errorCount:this.errors.length}}clear(){this.spans.clear(),this.metrics=[],this.errors=[]}async flush(){if(!this.shouldSample||!this.options.enabled)return;if(0===this.metrics.length&&0===this.errors.length&&0===this.spans.size)return;const t={traceId:this.traceId,pageVersionId:this.options.pageVersionId,appId:this.options.appId,runtimeVersion:this.options.runtimeVersion,spans:this.getSpans(),metrics:this.metrics,errors:this.errors,timestamp:Date.now()};if(this.clear(),this.options.endpoint)try{await fetch(this.options.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),keepalive:!0}),this.log("debug","Telemetry flushed successfully")}catch(t){this.log("warn","Failed to flush telemetry:",t)}else this.log("debug","No endpoint configured, telemetry data discarded")}destroy(){this.flushTimer&&clearInterval(this.flushTimer),this.flush()}recordMetricInternal(t){this.metrics.push(t),this.options.onMetric?.(t),this.metrics.length>=(this.options.batchSize??50)&&this.flush()}startAutoFlush(){const t=this.options.flushInterval??3e4;this.flushTimer=setInterval(()=>this.flush(),t)}generateTraceId(){const t=new Uint8Array(16);return crypto.getRandomValues(t),Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}generateSpanId(){const t=new Uint8Array(8);return crypto.getRandomValues(t),Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},N=class t{constructor(t){this.container=null,this.renderedElements=new Map,this.componentEventListeners=new Map,this.expressionContext={state:{},binding:{},local:{}},this.loopContextStack=[],this.styleElement=null,this.options=t}init(){this.log("debug","Renderer initialized")}render(t,e){this.container=e,this.log("debug","Rendering page",t.pageId),this.cleanup(),e.innerHTML="",this.applyPageConfig(t,e),this.initializePageState(t);const s=this.renderNode(t.root);s&&e.appendChild(s),this.log("info",`Page rendered with root component: ${t.root.componentType}`)}updateComponent(t,e){const s=this.renderedElements.get(t);s?this.applyProps(s,e):this.log("warn",`Component not found: ${t}`)}updateContext(t){this.expressionContext={...this.expressionContext,...t}}getContext(){return{...this.expressionContext}}destroy(){this.cleanup(),this.container&&(this.container.innerHTML=""),this.log("debug","Renderer destroyed")}cleanup(){this.componentEventListeners.forEach((t,e)=>{const s=this.renderedElements.get(e);s&&t.forEach(({event:t,handler:e})=>{s.removeEventListener(t,e)})}),this.componentEventListeners.clear(),this.renderedElements.forEach(t=>{t.remove()}),this.renderedElements.clear(),this.styleElement&&(this.styleElement.remove(),this.styleElement=null),this.loopContextStack=[]}renderNode(t){const{id:e,componentType:s,componentVersion:i}=t;try{if(t.condition&&!this.evaluateCondition(t.condition))return this.log("debug",`Component ${e} hidden by condition`),null;if(t.loop)return this.renderLoop(t);const r=this.createElement(t);if(!r)return null;r.setAttribute("data-component-id",e),r.setAttribute("data-component-type",s),i&&r.setAttribute("data-component-version",i);const n=this.resolveProps(t.props);if(this.applyProps(r,n),t.style&&this.applyStyles(r,t.style),t.layout&&this.applyLayout(r,t.layout),this.options.injectHostApi(r,e),t.eventHandlers&&t.eventHandlers.length>0&&this.bindEventHandlers(r,e,t.eventHandlers),this.renderChildren(r,t),t.ref){const e=this.expressionContext.local,s=e.$refs||{};s[t.ref]=r,this.expressionContext={...this.expressionContext,local:{...e,$refs:s}}}return this.renderedElements.set(e,r),r}catch(t){return this.log("error",`Failed to render component: ${e}`,t),this.options.onRenderError?this.options.onRenderError(e,t):this.createErrorFallback(e,s,t)}}createElement(t){const{componentType:e}=t,s=this.options.components.get(e);if(s&&customElements.get(e))return document.createElement(e);const i=`${e}-${t.componentVersion?.replace(/\./g,"-")}`;if(customElements.get(i))return document.createElement(i);const r=document.createElement("div");return r.className=`djvlc-component djvlc-${e}`,s||(this.log("warn",`Component not loaded: ${e}`),r.classList.add("djvlc-component-fallback")),r}renderLoop(t){const{loop:e}=t;if(!e)return null;const s=this.evaluateExpression(e.items);if(!Array.isArray(s))return this.log("warn",`Loop items is not an array for ${t.id}`),null;const i=document.createDocumentFragment();s.forEach((s,r)=>{this.loopContextStack.push({item:s,index:r,loopConfig:e});const n={...this.expressionContext},o={...this.expressionContext.local,[e.itemName]:s,item:s,index:r};e.indexName&&(o[e.indexName]=r),this.expressionContext={...this.expressionContext,local:o};const a={...t,id:`${t.id}_${r}`,loop:void 0},c=this.renderNode(a);if(c){const t=this.evaluateExpression(e.key);c.setAttribute("data-loop-key",String(t??r)),i.appendChild(c)}this.expressionContext=n,this.loopContextStack.pop()});const r=document.createElement("div");return r.className="djvlc-loop-container",r.setAttribute("data-loop-id",t.id),r.appendChild(i),r}renderChildren(t,e){if(e.slots&&Object.keys(e.slots).length>0)for(const[s,i]of Object.entries(e.slots)){const e=this.createSlotContainer(s);for(const t of i){const s=this.renderNode(t);s&&e.appendChild(s)}t.appendChild(e)}}createSlotContainer(t){const e=document.createElement("div");return e.className=`djvlc-slot djvlc-slot-${t}`,e.setAttribute("data-slot",t),e}bindEventHandlers(t,e,s){const i=[];for(const r of s){const{eventName:s,preventDefault:n,stopPropagation:o,throttle:a,debounce:c,condition:h}=r;let u=t=>{if(h&&!this.evaluateCondition(h))return;n&&t.preventDefault(),o&&t.stopPropagation();const i=t.detail||{};this.options.onComponentEvent&&this.options.onComponentEvent(e,s,[r],i)};a&&a>0&&(u=this.createThrottledHandler(u,a)),c&&c>0&&(u=this.createDebouncedHandler(u,c)),t.addEventListener(s,u),i.push({event:s,handler:u})}this.componentEventListeners.set(e,i)}createThrottledHandler(t,e){let s=0;return i=>{const r=Date.now();r-s>=e&&(s=r,t(i))}}createDebouncedHandler(t,e){let s=null;return i=>{s&&clearTimeout(s),s=setTimeout(()=>{t(i),s=null},e)}}evaluateCondition(t){const e=this.evaluateExpression(t);return Boolean(e)}evaluateExpression(t){if(null==t)return t;if("object"==typeof t&&"type"in t&&"value"in t){const e=t,s=this.buildExpressionContext();return this.options.expressionEngine.evaluateWithFallback(e.value,s,e.fallback)}if("string"==typeof t){const e=this.buildExpressionContext();return this.options.expressionEngine.evaluateWithFallback(t,e,void 0)}return t}buildExpressionContext(){const t={};for(const e of this.loopContextStack)t[e.loopConfig.itemName]=e.item,t.item=e.item,t.index=e.index,e.loopConfig.indexName&&(t[e.loopConfig.indexName]=e.index);return{...this.expressionContext,local:{...this.expressionContext.local,...t}}}resolveProps(t){const e={};for(const[s,i]of Object.entries(t))e[s]=this.resolveValue(i);return e}resolveValue(e){if(null==e)return e;if("string"==typeof e)return e.includes("${")?this.options.expressionEngine.evaluateTemplate(e,this.buildExpressionContext()):e;if("number"==typeof e||"boolean"==typeof e)return e;if(Array.isArray(e))return e.map(t=>this.resolveValue(t));if("object"==typeof e){const s=e;if("string"==typeof s.type&&t.EXPRESSION_TYPES.includes(s.type)&&"string"==typeof s.value){const t=s;return this.options.expressionEngine.evaluateWithFallback(t.value,this.buildExpressionContext(),t.fallback)}const i={};for(const[t,e]of Object.entries(s))i[t]=this.resolveValue(e);return i}return e}applyProps(t,e){for(const[s,i]of Object.entries(e))null!=i&&(t.tagName.includes("-")?t[s]=i:"boolean"==typeof i?i?t.setAttribute(s,""):t.removeAttribute(s):"object"==typeof i?t.setAttribute(s,JSON.stringify(i)):t.setAttribute(s,String(i)))}applyStyles(t,e){if(e.inline)for(const[s,i]of Object.entries(e.inline)){if(null==i)continue;const e=this.resolveValue(i);let r;r="number"==typeof e?["zIndex","opacity","flex","fontWeight","lineHeight"].includes(s)?String(e):`${e}px`:String(e);const n=s.replace(/([A-Z])/g,"-$1").toLowerCase();t.style.setProperty(n,r)}e.className&&t.classList.add(...String(e.className).split(" ").filter(Boolean))}applyLayout(t,e){const{x:s,y:i,width:r,height:n,rotation:o,zIndex:a,responsive:c}=e;t.style.position="absolute",void 0!==s&&(t.style.left=`${s}px`),void 0!==i&&(t.style.top=`${i}px`),void 0!==r&&(t.style.width=`${r}px`),void 0!==n&&(t.style.height=`${n}px`),void 0!==o&&(t.style.transform=`rotate(${o}deg)`),void 0!==a&&(t.style.zIndex=String(a)),c&&this.applyResponsiveLayout(t,c)}applyResponsiveLayout(t,e){const s=t.getAttribute("data-component-id");if(!s)return;let i="";if(e.mobile&&(i+=`\n @media (max-width: 767px) {\n [data-component-id="${s}"] {\n ${this.layoutToCSS(e.mobile)}\n }\n }\n `),e.tablet&&(i+=`\n @media (min-width: 768px) and (max-width: 1023px) {\n [data-component-id="${s}"] {\n ${this.layoutToCSS(e.tablet)}\n }\n }\n `),e.desktop&&(i+=`\n @media (min-width: 1440px) {\n [data-component-id="${s}"] {\n ${this.layoutToCSS(e.desktop)}\n }\n }\n `),i){const t=document.createElement("style");t.setAttribute("data-djvlc-responsive",s),t.textContent=i,document.head.appendChild(t)}}layoutToCSS(t){const e=[];return void 0!==t.x&&e.push(`left: ${t.x}px`),void 0!==t.y&&e.push(`top: ${t.y}px`),void 0!==t.width&&e.push(`width: ${t.width}px`),void 0!==t.height&&e.push(`height: ${t.height}px`),void 0!==t.rotation&&e.push(`transform: rotate(${t.rotation}deg)`),void 0!==t.zIndex&&e.push(`z-index: ${t.zIndex}`),e.join("; ")}applyPageConfig(t,e){e.classList.add("djvlc-page"),e.setAttribute("data-page-id",t.pageId),e.setAttribute("data-page-version",t.pageVersion),e.setAttribute("data-schema-version",t.schemaVersion);const s=t.config;s&&(this.applyLayoutConfig(e,s.layout),s.styles&&this.applyStylesConfig(e,s.styles),s.behavior&&this.applyBehaviorConfig(e,s.behavior))}applyBehaviorConfig(t,e){e.debug&&t.setAttribute("data-debug","true"),e.i18n&&this.applyI18nConfig(t,e.i18n)}applyI18nConfig(t,e){const s=this.detectLocale(e);t.setAttribute("lang",s),t.setAttribute("data-locale",s),t.setAttribute("data-default-locale",e.defaultLocale),t.setAttribute("data-supported-locales",e.supportedLocales.join(",")),e.translationBundleId&&t.setAttribute("data-translation-bundle",e.translationBundleId),t.style.setProperty("--djvlc-locale",s),t.style.setProperty("--djvlc-dir",this.getTextDirection(s)),"rtl"===this.getTextDirection(s)?(t.setAttribute("dir","rtl"),t.classList.add("djvlc-rtl")):t.setAttribute("dir","ltr"),this.expressionContext={...this.expressionContext,local:{...this.expressionContext.local,$locale:s,$defaultLocale:e.defaultLocale,$supportedLocales:e.supportedLocales}},this.log("debug",`I18n configured: locale=${s}, default=${e.defaultLocale}`)}detectLocale(t){const{defaultLocale:e,supportedLocales:s,detection:i="browser"}=t;let r=null;switch(i){case"browser":case"header":r=this.detectBrowserLocale(s);break;case"url":r=this.detectUrlLocale(s);break;case"path":r=this.detectPathLocale(s);break;case"cookie":r=this.detectCookieLocale(s);break;case"manual":r=e;break;default:r=null}return r&&s.includes(r)?r:e}detectBrowserLocale(t){if("undefined"==typeof navigator)return null;const e=navigator.languages||[navigator.language];for(const s of e){if(t.includes(s))return s;const e=s.split("-")[0],i=t.find(t=>t===e||t.startsWith(`${e}-`));if(i)return i}return null}detectUrlLocale(t){if("undefined"==typeof window)return null;const e=new URLSearchParams(window.location.search),s=e.get("lang")||e.get("locale");return s&&t.includes(s)?s:null}detectPathLocale(t){if("undefined"==typeof window)return null;const e=window.location.pathname.split("/").filter(Boolean);if(e.length>0){const s=e[0];if(t.includes(s))return s}return null}detectCookieLocale(t){if("undefined"==typeof document)return null;const e=document.cookie.split(";");for(const s of e){const[e,i]=s.trim().split("=");if("lang"===e||"locale"===e||"language"===e){const e=decodeURIComponent(i);if(t.includes(e))return e}}return null}getTextDirection(t){const e=t.split("-")[0];return["ar","ar-SA","ar-EG","ar-AE","he","he-IL","fa","fa-IR","ur","ur-PK","yi","ps","dv"].some(s=>s===t||s===e)?"rtl":"ltr"}applyLayoutConfig(t,e){if(t.setAttribute("data-canvas-type",e.canvasType),e.canvasSize&&"responsive"!==e.canvasType&&(t.style.width=`${e.canvasSize.width}px`,t.style.minHeight=`${e.canvasSize.height}px`),e.maxWidth&&(t.style.maxWidth=`${e.maxWidth}px`,t.style.marginLeft="auto",t.style.marginRight="auto"),e.padding){const{top:s=0,right:i=0,bottom:r=0,left:n=0}=e.padding;t.style.padding=`${s}px ${i}px ${r}px ${n}px`}e.viewport&&(e.viewport.mobile&&t.style.setProperty("--djvlc-breakpoint-mobile",`${e.viewport.mobile}px`),e.viewport.tablet&&t.style.setProperty("--djvlc-breakpoint-tablet",`${e.viewport.tablet}px`),e.viewport.desktop&&t.style.setProperty("--djvlc-breakpoint-desktop",`${e.viewport.desktop}px`))}applyStylesConfig(t,e){if(e.theme&&this.applyThemeConfig(t,e.theme),e.background&&this.applyBackgroundConfig(t,e.background),e.cssVariables)for(const[s,i]of Object.entries(e.cssVariables)){const e=s.startsWith("--")?s:`--${s}`;t.style.setProperty(e,i)}e.customCSS&&this.injectCustomCSS(e.customCSS)}applyThemeConfig(t,e){if(e.preset&&(t.setAttribute("data-theme",e.preset),"system"===e.preset)){const e=window.matchMedia("(prefers-color-scheme: dark)").matches;t.setAttribute("data-theme-resolved",e?"dark":"light")}if(e.variables)for(const[s,i]of Object.entries(e.variables)){const e=s.startsWith("--")?s:`--theme-${s}`;t.style.setProperty(e,i)}e.transition&&t.style.setProperty("--djvlc-theme-transition","all 0.3s ease")}applyBackgroundConfig(t,e){switch(e.type){case"color":t.style.backgroundColor=e.value;break;case"image":t.style.backgroundImage=`url(${e.value})`,t.style.backgroundSize=e.size||"cover",t.style.backgroundPosition=e.position||"center",t.style.backgroundRepeat=e.repeat||"no-repeat";break;case"gradient":t.style.backgroundImage=e.value}}injectCustomCSS(t){t.trim()&&(this.styleElement=document.createElement("style"),this.styleElement.setAttribute("data-djvlc-custom","true"),this.styleElement.textContent=t,document.head.appendChild(this.styleElement))}initializePageState(t){if(t.state&&t.state.fields){const e={};for(const[s,i]of Object.entries(t.state.fields))i&&"object"==typeof i&&(e[s]=i.initialValue);this.expressionContext={...this.expressionContext,state:e}}}createErrorFallback(t,e,s){const i=document.createElement("div");return i.className="djvlc-error-boundary",i.setAttribute("data-component-id",t),i.setAttribute("data-error","true"),i.innerHTML=`\n <div class="djvlc-error-content">\n <span class="djvlc-error-icon">⚠️</span>\n <span class="djvlc-error-message">组件渲染失败: ${e}</span>\n ${this.options.debug?`<pre class="djvlc-error-detail">${s.message}</pre>`:""}\n </div>\n `,i}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}};N.EXPRESSION_TYPES=["state","binding","local","template","computed"];var C=N;function A(){customElements.get("djvlc-fallback")||customElements.define("djvlc-fallback",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).innerHTML='\n <style>\n :host {\n display: block;\n padding: 16px;\n background: #fff2f0;\n border: 1px solid #ffccc7;\n border-radius: 4px;\n color: #ff4d4f;\n font-size: 14px;\n }\n .title {\n font-weight: 600;\n margin-bottom: 8px;\n }\n .message {\n color: #666;\n }\n </style>\n <div class="title">组件加载失败</div>\n <div class="message"><slot>请刷新页面重试</slot></div>\n '}static get observedAttributes(){return["message","component-name"]}attributeChangedCallback(t,e,s){if("message"===t&&this.shadowRoot){const t=this.shadowRoot.querySelector(".message");t&&(t.textContent=s)}if("component-name"===t&&this.shadowRoot){const t=this.shadowRoot.querySelector(".title");t&&(t.textContent=`组件 ${s} 加载失败`)}}}),customElements.get("djvlc-blocked")||customElements.define("djvlc-blocked",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).innerHTML='\n <style>\n :host {\n display: block;\n padding: 16px;\n background: #fffbe6;\n border: 1px solid #ffe58f;\n border-radius: 4px;\n color: #faad14;\n font-size: 14px;\n }\n .icon {\n margin-right: 8px;\n }\n </style>\n <span class="icon">⚠️</span>\n <span>此组件已被暂停使用</span>\n '}}),customElements.get("djvlc-error-boundary")||customElements.define("djvlc-error-boundary",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).innerHTML="\n <style>\n :host {\n display: block;\n padding: 16px;\n background: #f5f5f5;\n border: 1px dashed #d9d9d9;\n border-radius: 4px;\n color: #999;\n font-size: 14px;\n text-align: center;\n }\n </style>\n <slot>渲染出错</slot>\n "}})}function I(t,e,s){const i=`djvlc-${"error"===t?"error-boundary":t}`,r=document.createElement(i);return e&&r.setAttribute("message",e),s&&r.setAttribute("component-name",s),r}var T=class{constructor(t){this.lifecycle=null,this.mounted=!1,this.destroyed=!1,this.cleanupFns=[],this.options=t}register(t){t?(this.lifecycle=t,this.log("debug","Lifecycle hooks registered",{onMounted:t.onMounted?.length??0,onBeforeUnmount:t.onBeforeUnmount?.length??0,onVisibilityChange:t.onVisibilityChange?.length??0}),t.onVisibilityChange&&t.onVisibilityChange.length>0&&this.setupVisibilityListener()):this.log("debug","No lifecycle hooks defined")}async triggerMounted(){this.mounted||this.destroyed||(this.mounted=!0,this.log("debug","Triggering onMounted lifecycle"),await this.executeLifecycleActions("mounted",this.lifecycle?.onMounted),this.options.onLifecycleEvent?.("mounted"))}async triggerBeforeUnmount(){this.mounted&&!this.destroyed&&(this.log("debug","Triggering onBeforeUnmount lifecycle"),await this.executeLifecycleActions("beforeUnmount",this.lifecycle?.onBeforeUnmount),this.options.onLifecycleEvent?.("beforeUnmount"))}async triggerVisibilityChange(t){if(!this.mounted||this.destroyed)return;this.log("debug","Triggering onVisibilityChange lifecycle",{isVisible:t});const e=this.options.getContext(),s={...e,local:{...e.local,$visible:t,$hidden:!t}};await this.executeLifecycleActionsWithContext("visibilityChange",this.lifecycle?.onVisibilityChange,s),this.options.onLifecycleEvent?.("visibilityChange",{isVisible:t})}async destroy(){this.destroyed||(await this.triggerBeforeUnmount(),this.cleanupFns.forEach(t=>t()),this.cleanupFns=[],this.destroyed=!0,this.lifecycle=null,this.log("debug","LifecycleManager destroyed"))}isMounted(){return this.mounted&&!this.destroyed}isDestroyed(){return this.destroyed}setupVisibilityListener(){const t=()=>{const t="visible"===document.visibilityState;this.triggerVisibilityChange(t).catch(t=>{this.log("error","Failed to handle visibility change",t)})};document.addEventListener("visibilitychange",t),this.cleanupFns.push(()=>{document.removeEventListener("visibilitychange",t)}),this.log("debug","Visibility listener registered")}async executeLifecycleActions(t,e){if(!e||0===e.length)return;const s=this.options.getContext();await this.executeLifecycleActionsWithContext(t,e,s)}async executeLifecycleActionsWithContext(t,e,s){if(e&&0!==e.length){this.log("debug",`Executing ${e.length} actions for ${t}`);try{const i={id:`lifecycle_${t}`,eventName:t,actions:e};await this.options.actionBridge.handleEvent(i,{lifecycle:t},s),this.log("debug",`Lifecycle ${t} actions completed`)}catch(e){this.log("error",`Failed to execute lifecycle ${t} actions`,e)}}}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},j=t.CURRENT_SCHEMA_VERSION,D="1.0.0",R=class{constructor(t){this.container=null,this.options={channel:"prod",debug:!1,enableSRI:!0,env:"production",...t},this.logger=this.createLogger(),this.stateManager=new d,this.eventBus=new f({debug:t.debug,logger:this.logger}),this.expressionEngine=new x({debug:t.debug,logger:this.logger}),this.pageLoader=new h({apiBaseUrl:t.apiBaseUrl,channel:t.channel,authToken:t.authToken,previewToken:t.previewToken,headers:t.headers,logger:this.logger}),this.componentLoader=new u({cdnBaseUrl:t.cdnBaseUrl,enableSRI:t.enableSRI,logger:this.logger}),this.assetLoader=new l({cdnHosts:[new URL(t.cdnBaseUrl).host],apiHosts:[new URL(t.apiBaseUrl).host]}),this.securityManager=new k({enableSRI:t.enableSRI,cdnDomains:[new URL(t.cdnBaseUrl).host],apiDomains:[new URL(t.apiBaseUrl).host],logger:this.logger}),this.log("info","Runtime created",{version:D})}async init(){this.log("info","Initializing runtime");const t=performance.now();try{this.container=this.resolveContainer(),this.assetLoader.preconnectAll(),this.pageLoader.preconnect(),A(),this.stateManager.setPhase("resolving");const e=performance.now()-t;this.log("info",`Runtime initialized in ${e.toFixed(2)}ms`)}catch(t){throw this.handleError(t),t}}async load(){this.log("info","Loading page:",this.options.pageUid);const t=performance.now();try{this.stateManager.setPhase("resolving");const e=await this.pageLoader.resolve(this.options.pageUid,{uid:this.options.userId,deviceId:this.options.deviceId});if(this.validateSchemaVersion(e.pageJson),this.stateManager.setPage(e),this.telemetryManager=new E({pageVersionId:e.pageVersionId,appId:this.options.appId,debug:this.options.debug,logger:this.logger,onMetric:this.options.onMetric}),e.runtimeConfig){const t=e.runtimeConfig.blockedComponents?.map(t=>`${t.name}@${t.version}`)||[];this.securityManager.updateBlockedList(t,[]),this.componentLoader.updateBlockedList(t)}this.stateManager.setPhase("loading"),this.componentLoader.preload(e.manifest.components),(await this.componentLoader.loadAll(e.manifest)).forEach((t,e)=>{this.stateManager.setComponentStatus(e,t),this.telemetryManager.recordComponentLoad(t.name,t.version,t.loadTime||0,"loaded"===t.status)}),this.initHostApi(e),this.initActionBridge(),this.initDataBindingManager(e.pageJson),this.initRenderer(),this.initLifecycleManager(e.pageJson);const s=performance.now()-t;return this.telemetryManager.recordPageLoad(s),this.log("info",`Page loaded in ${s.toFixed(2)}ms`),this.emitEvent("page:loaded",{page:e,loadTime:s}),this.options.onLoad?.(e),e}catch(t){throw this.stateManager.setPhase("error"),this.handleError(t),t}}async render(){const t=this.stateManager.getState();if(!t.page||!this.container)throw new s("Page not loaded");this.log("info","Rendering page");const e=performance.now();try{this.stateManager.setPhase("rendering"),this.renderer.updateContext(this.stateManager.getExpressionContext()),this.renderer.render(t.page.pageJson,this.container),await this.dataBindingManager.initializeBindings(this.stateManager.getExpressionContext()),this.stateManager.setPhase("ready");const s=performance.now()-e;this.telemetryManager.recordFirstRender(s),this.log("info",`Page rendered in ${s.toFixed(2)}ms`),await this.lifecycleManager.triggerMounted(),this.emitEvent("page:rendered",{renderTime:s})}catch(t){throw this.stateManager.setPhase("error"),this.handleError(t),t}}getHostApi(){return this.hostApi}getState(){return this.stateManager.getState()}onStateChange(t){return this.stateManager.subscribe(t)}on(t,e){return this.eventBus.on(t,e)}updateComponent(t,e){this.renderer.updateComponent(t,e)}setVariable(t,e){this.stateManager.setVariable(t,e),this.renderer.updateContext(this.stateManager.getExpressionContext()),this.dataBindingManager.onStateChange(t,this.stateManager.getExpressionContext())}getVariable(t){return this.stateManager.getVariable(t)}async refreshData(t){await this.dataBindingManager.refreshBinding(t,this.stateManager.getExpressionContext()),this.renderer.updateContext(this.stateManager.getExpressionContext())}async executeAction(t,e){return this.hostApi.executeAction(t,e)}async destroy(){this.log("info","Destroying runtime"),await(this.lifecycleManager?.destroy()),this.telemetryManager?.flush(),this.dataBindingManager?.destroy(),this.actionBridge?.destroy(),this.renderer?.destroy(),this.eventBus.clear(),this.stateManager.setDestroyed(),this.container&&(this.container.innerHTML=""),this.emitEvent("page:destroyed",{}),this.log("info","Runtime destroyed")}validateSchemaVersion(t){if(t.schemaVersion!==j)throw new s(`Unsupported schema version: ${t.schemaVersion}. Only ${j} is supported.`,{schemaVersion:t.schemaVersion,supportedVersion:j})}resolveContainer(){const{container:t}=this.options;if("string"==typeof t){const e=document.querySelector(t);if(!e)throw new Error(`Container not found: ${t}`);return e}return t}initHostApi(t){this.hostApi=new S({apiBaseUrl:this.options.apiBaseUrl,authToken:this.options.authToken,headers:this.options.headers,stateManager:this.stateManager,eventBus:this.eventBus,expressionEngine:this.expressionEngine,context:{pageUid:t.pageUid,pageVersionId:t.pageVersionId,runtimeVersion:D,userId:this.options.userId,deviceId:this.options.deviceId,channel:this.options.channel,appId:this.options.appId||"",env:this.options.env||"production",isEditMode:!1,isPreviewMode:t.isPreview||!1},debug:this.options.debug,logger:this.logger})}initActionBridge(){this.actionBridge=new g({executor:{executeAction:(t,e)=>this.hostApi.executeAction(t,e),requestData:(t,e)=>this.hostApi.requestData(t,e),navigate:t=>this.hostApi.navigate(t),openDialog:t=>this.hostApi.openDialog(t),closeDialog:()=>this.hostApi.closeDialog(),showToast:t=>this.hostApi.showToast(t),showLoading:t=>this.hostApi.showLoading(t),hideLoading:()=>this.hostApi.hideLoading(),track:t=>this.hostApi.track(t),setState:(t,e)=>this.stateManager.setVariable(t,e),getState:t=>this.stateManager.getVariable(t),refreshData:t=>this.refreshData(t)},expressionEngine:this.expressionEngine,debug:this.options.debug,logger:this.logger,onActionStart:(t,e)=>{this.emitEvent("action:executing",{action:t,params:e})},onActionComplete:(t,e)=>{e.success?this.emitEvent("action:executed",{action:t,data:e.data}):this.emitEvent("action:error",{action:t,error:e.error?.message})}})}initDataBindingManager(t){this.dataBindingManager=new p({requester:{requestData:(t,e)=>this.hostApi.requestData(t,e)},stateSetter:{setVariable:(t,e)=>this.stateManager.setVariable(t,e),getVariable:t=>this.stateManager.getVariable(t)},expressionEngine:this.expressionEngine,debug:this.options.debug,logger:this.logger,onDataLoaded:(t,e)=>{this.emitEvent("query:fetched",{bindingId:t,data:e}),this.renderer?.updateContext(this.stateManager.getExpressionContext())},onDataError:(t,e)=>{this.emitEvent("query:error",{bindingId:t,error:e.message})}}),t.dataBindings&&this.dataBindingManager.registerBindings(t.dataBindings),this.stateManager.onStateChange(({key:t})=>{this.dataBindingManager.onStateChange(t,this.stateManager.getExpressionContext())})}initLifecycleManager(t){this.lifecycleManager=new T({actionBridge:this.actionBridge,getContext:()=>this.stateManager.getExpressionContext(),debug:this.options.debug,logger:this.logger,onLifecycleEvent:(t,e)=>{this.emitEvent(`page:lifecycle:${t}`,e??{})}}),this.lifecycleManager.register(t.lifecycle)}initRenderer(){const t=new Map;this.stateManager.getState().components.forEach((e,s)=>{if("loaded"===e.status&&e.component){const[i,r]=s.split("@");t.set(i,{name:i,version:r,Component:e.component,loadTime:e.loadTime||0})}}),this.renderer=new C({expressionEngine:this.expressionEngine,components:t,injectHostApi:(t,e)=>{t.hostApi=this.hostApi,t.componentId=e},onComponentEvent:(t,e,s,i)=>{this.handleComponentEvent(t,e,s,i)},debug:this.options.debug,logger:this.logger,onRenderError:(t,e)=>(this.log("error",`Render error in ${t}:`,e),this.emitEvent("component:error",{componentId:t,error:e.message}),I("error",e.message))}),this.renderer.init()}handleComponentEvent(t,e,s,i){this.log("debug",`Component event: ${t}.${e}`,i);for(const t of s)this.actionBridge.handleEvent(t,i,this.stateManager.getExpressionContext())}handleError(t){const s=t instanceof e?{type:"LOAD_ERROR",message:t.message,code:t.code,details:t.details,traceId:t.traceId,timestamp:t.timestamp}:{type:"UNKNOWN_ERROR",message:t.message,cause:t,timestamp:Date.now()};this.stateManager.setError(s),this.telemetryManager?.recordError(t),this.emitEvent("page:error",{error:t.message}),this.options.onError&&this.options.onError(s)}emitEvent(t,e){const s=f.createEvent(t,e,this.telemetryManager?.getTraceId());this.eventBus.emit(s),this.options.onEvent&&this.options.onEvent(s)}createLogger(){return{debug:(...t)=>{this.options.debug},info:(...t)=>{},warn:(...t)=>{},error:(...t)=>{}}}log(t,e,...s){this.logger[t](e,...s)}};Object.defineProperty(exports,"ErrorCode",{enumerable:!0,get:function(){return t.ErrorCode}}),Object.defineProperty(exports,"ErrorMessages",{enumerable:!0,get:function(){return t.ErrorMessages}}),exports.ActionBridge=g,exports.ActionError=a,exports.AssetLoader=l,exports.BaseRenderer=C,exports.ComponentBlockedError=n,exports.ComponentLoadError=i,exports.ComponentLoader=u,exports.DjvlcRuntime=R,exports.DjvlcRuntimeError=e,exports.Evaluator=$,exports.EventBus=f,exports.ExpressionEngine=x,exports.ExpressionError=o,exports.HostAPIImpl=S,exports.IntegrityError=r,exports.Lexer=y,exports.LifecycleManager=T,exports.PageLoadError=s,exports.PageLoader=h,exports.Parser=w,exports.QueryError=c,exports.RUNTIME_VERSION="1.0.0",exports.RenderError=class extends e{constructor(e,s,i,r){super(t.ErrorCode.SYSTEM_INTERNAL_ERROR,i,{...r,componentId:e,componentType:s}),this.name="RenderError",this.componentId=e,this.componentType=s}},exports.SCHEMA_VERSION=j,exports.SUPPORTED_SCHEMA_VERSION=j,exports.SecurityManager=k,exports.StateManager=d,exports.TelemetryManager=E,exports.builtinFunctions=v,exports.createFallbackElement=I,exports.createRuntime=function(t){return new R(t)},exports.registerFallbackComponents=A;
1
+ var t=require("@djvlc/contracts-types"),e=class extends Error{constructor(e,s,i,n){super(s||t.ErrorMessages[e]||"Unknown error"),this.name="DjvlcRuntimeError",this.code=e,this.details=i,this.traceId=n,this.timestamp=Date.now()}toJSON(){return{name:this.name,code:this.code,message:this.message,details:this.details,traceId:this.traceId,timestamp:this.timestamp}}},s=class extends e{constructor(e,s,i){super(t.ErrorCode.RESOURCE_PAGE_NOT_FOUND,e,s,i),this.name="PageLoadError"}},i=class extends e{constructor(e,s,i,n=t.ErrorCode.COMPONENT_LOAD_FAILED,r){super(n,i,{...r,componentName:e,componentVersion:s}),this.name="ComponentLoadError",this.componentName=e,this.componentVersion=s}},n=class extends e{constructor(e,s,i,n){super(t.ErrorCode.COMPONENT_INTEGRITY_MISMATCH,`Integrity check failed for ${e}@${s}`,{expectedHash:i,actualHash:n}),this.name="IntegrityError",this.componentName=e,this.componentVersion=s,this.expectedHash=i,this.actualHash=n}},r=class extends e{constructor(e,s,i){super(t.ErrorCode.COMPONENT_BLOCKED,`Component ${e}@${s} is blocked`,{componentName:e,componentVersion:s,reason:i}),this.name="ComponentBlockedError",this.componentName=e,this.componentVersion=s,this.reason=i}},o=class extends e{constructor(e,s,i,n){super(t.ErrorCode.VALIDATION_EXPRESSION_ERROR,s,{...n,expression:e,position:i}),this.name="ExpressionError",this.expression=e,this.position=i}},a=class extends e{constructor(e,s,i=t.ErrorCode.SYSTEM_INTERNAL_ERROR,n,r){super(i,s,{...r,actionType:e,actionId:n}),this.name="ActionError",this.actionType=e,this.actionId=n}},c=class extends e{constructor(e,s,i=t.ErrorCode.SYSTEM_INTERNAL_ERROR,n){super(i,s,{...n,queryId:e}),this.name="QueryError",this.queryId=e}},h=class{constructor(t){this.cache=new Map,this.options={env:"prod",cache:{enabled:!0,maxAge:300},...t}}async resolve(t,e){const i=this.getCacheKey(t,e);if(this.options.cache?.enabled){const e=this.cache.get(i);if(e&&this.isCacheValid(e.timestamp))return this.log("debug",`Page ${t} loaded from cache`),e.data}const n=performance.now();try{const s=await this.callResolveApi(t,e),r=await this.loadFromCdn(s,t);this.options.cache?.enabled&&this.cache.set(i,{data:r,timestamp:Date.now()});const o=performance.now()-n;return this.log("info",`Page ${t} resolved in ${o.toFixed(2)}ms`),r}catch(e){if(e instanceof s)throw e;throw new s(`Failed to resolve page: ${e instanceof Error?e.message:"Unknown error"}`,{pageId:t})}}async callResolveApi(t,e){const i=new URL(`${this.options.apiBaseUrl}/page/resolve`);i.searchParams.set("pageId",t),this.options.env&&i.searchParams.set("env",this.options.env),this.options.channel&&i.searchParams.set("channel",this.options.channel),this.options.previewToken&&i.searchParams.set("previewToken",this.options.previewToken),e?.uid&&i.searchParams.set("uid",e.uid),e?.deviceId&&i.searchParams.set("deviceId",e.deviceId);const n={"Content-Type":"application/json",...this.options.headers};this.options.authToken&&(n.Authorization=`Bearer ${this.options.authToken}`),this.log("debug","Calling resolve API:"+i.toString());const r=await fetch(i.toString(),{method:"GET",headers:n});if(!r.ok)throw new s(`Failed to resolve page: ${r.status} ${r.statusText}`,{pageId:t,status:r.status});const o=await r.json();if(!this.isValidPageResolveResponse(o))throw new s("Invalid page resolve response",{pageId:t});return o}async loadFromCdn(t,e){try{const i=await fetch(t.snapshotUrl,{headers:this.buildHeaders()});if(!i.ok)throw new s(`Failed to load snapshot: ${i.status}`,{pageId:e});const n=await i.json();return this.convertSnapshotToResult(n,t,e)}catch(t){if(t instanceof s)throw t;throw new s(`Failed to load from CDN: ${t instanceof Error?t.message:"Unknown error"}`,{pageId:e})}}convertSnapshotToResult(t,e,s){const i=this.convertSnapshotPageToPageSchema(t.page),n=this.convertSnapshotManifestToPageManifest(t.manifest),r=t.definitionsDigest?.actions?.map(t=>t.versionId)||[],o=t.definitionsDigest?.queries?.map(t=>t.versionId)||[];return n.actionDefinitionVersionIds=r,n.dataQueryVersionIds=o,{pageId:e.pageId,pageVersionId:e.resolvedVersionId,pageJson:i,manifest:n,runtimeConfig:{blockedComponents:e.ops.blockedComponents.map(t=>({name:t.name,version:t.version||"",reason:t.reason})),killSwitches:e.ops.killSwitch.map(t=>({type:t.targetType,enabled:t.enabled})),features:e.ops.flags},isPreview:"preview"===this.options.env||!!this.options.previewToken}}convertSnapshotPageToPageSchema(t){const e={layout:{canvasType:t.config.canvasType,canvasSize:t.config.canvasSize},styles:t.config.background||t.config.cssVariables?{background:t.config.background,cssVariables:t.config.cssVariables}:void 0},s=Object.keys(t.initialState).length>0?{fields:Object.keys(t.initialState).reduce((e,s)=>{const i=t.initialState[s];let n="string";return"number"==typeof i?n="number":"boolean"==typeof i?n="boolean":Array.isArray(i)?n="array":null!==i&&"object"==typeof i&&(n="object"),e[s]={type:n,initialValue:i},e},{})}:void 0,i={title:t.title};return{schemaVersion:t.schemaVersion,pageId:t.pageId,pageVersion:t.pageVersion,runtime:{name:"djvlc-runtime",version:"1.0.0"},meta:i,config:e,seo:t.seo,state:s,dataBindings:t.bindings,root:t.root}}convertSnapshotManifestToPageManifest(t){return{id:"",pageVersionId:"",manifestVersion:"1.0.0",createdAt:(new Date).toISOString(),contentHash:"",components:t.components.map(t=>({componentId:"",name:t.name,version:t.version,entry:`${t.assetsUrl}/${t.entrypoints.js}`,styleEntry:t.entrypoints.css?`${t.assetsUrl}/${t.entrypoints.css}`:void 0,integrity:t.integrity,preload:t.preload,priority:t.priority})),actionDefinitionVersionIds:[],dataQueryVersionIds:[],runtimeVersion:{min:t.runtime.minVersion,recommended:t.runtime.version}}}isValidPageResolveResponse(t){if(!t||"object"!=typeof t)return!1;const e=t;return"string"==typeof e.pageId&&"string"==typeof e.resolvedVersionId&&"string"==typeof e.cdnBase&&"string"==typeof e.snapshotUrl&&"string"==typeof e.manifestUrl&&void 0!==e.ops&&"string"==typeof e.etag&&"number"==typeof e.cacheTtlSeconds}preconnect(){const t=document.createElement("link");t.rel="preconnect",t.href=this.options.apiBaseUrl,document.head.appendChild(t)}clearCache(t){if(t)for(const e of this.cache.keys())e.startsWith(t)&&this.cache.delete(e);else this.cache.clear()}buildHeaders(){const t={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(t.Authorization=`Bearer ${this.options.authToken}`),t}getCacheKey(t,e){const s=[t,this.options.env,this.options.channel];return e?.uid&&s.push(e.uid),e?.deviceId&&s.push(e.deviceId),s.filter(Boolean).join(":")}isCacheValid(t){const e=1e3*(this.options.cache?.maxAge??300);return Date.now()-t<e}log(t,e){this.options.logger&&this.options.logger[t](e)}},l=class{constructor(t){this.loadedComponents=new Map,this.loadingPromises=new Map,this.options={enableSRI:!0,concurrency:4,timeout:3e4,blockedComponents:[],...t},this.blockedSet=new Set(this.options.blockedComponents)}async load(t){const e=this.getComponentKey(t.name,t.version);if(this.isBlocked(t.name,t.version))throw new r(t.name,t.version,"Component is blocked");const s=this.loadedComponents.get(e);if(s)return s;const i=this.loadingPromises.get(e);if(i)return i;const n=this.loadComponent(t);this.loadingPromises.set(e,n);try{const t=await n;return this.loadedComponents.set(e,t),t}finally{this.loadingPromises.delete(e)}}async loadAll(t){const e=new Map,{concurrency:s=4}=this.options,i=t.components;for(let t=0;t<i.length;t+=s){const n=i.slice(t,t+s).map(async t=>{const s=this.getComponentKey(t.name,t.version),i=performance.now();try{const n=await this.load(t);e.set(s,{name:t.name,version:t.version,status:"loaded",component:n.Component,loadTime:performance.now()-i})}catch(n){const o=n instanceof r?"blocked":"failed";if(e.set(s,{name:t.name,version:t.version,status:o,error:n instanceof Error?n.message:"Unknown error",loadTime:performance.now()-i}),"critical"===t.priority)throw n}});await Promise.all(n)}return e}preload(t){t.forEach(t=>{const e=document.createElement("link");e.rel="preload",e.as="script",e.href=this.resolveUrl(t.entry),this.options.enableSRI&&t.integrity&&(e.integrity=t.integrity,e.crossOrigin="anonymous"),document.head.appendChild(e)})}isLoaded(t,e){return this.loadedComponents.has(this.getComponentKey(t,e))}get(t,e){return this.loadedComponents.get(this.getComponentKey(t,e))}isBlocked(t,e){return this.blockedSet.has(`${t}@${e}`)||this.blockedSet.has(t)}updateBlockedList(t){this.blockedSet=new Set(t)}async loadComponent(t){const e=performance.now(),s=this.resolveUrl(t.entry);this.log("debug",`Loading component ${t.name}@${t.version}`);try{const n=await this.fetchWithTimeout(s);if(!n.ok)throw new i(t.name,t.version,`Failed to fetch component: ${n.status} ${n.statusText}`);const r=await n.text();this.options.enableSRI&&t.integrity&&await this.validateIntegrity(t,r);const o=await this.executeScript(r,t),a=performance.now()-e;return this.log("info",`Component ${t.name}@${t.version} loaded in ${a.toFixed(2)}ms`),{name:t.name,version:t.version,Component:o,loadTime:a}}catch(e){if(e instanceof i||e instanceof n||e instanceof r)throw e;throw new i(t.name,t.version,`Failed to load component: ${e instanceof Error?e.message:"Unknown error"}`)}}async fetchWithTimeout(t){const e=new AbortController,s=setTimeout(()=>e.abort(),this.options.timeout);try{return await fetch(t,{signal:e.signal,credentials:"omit"})}finally{clearTimeout(s)}}async validateIntegrity(t,e){if(!t.integrity)return;const[s,i]=t.integrity.split("-");if(!s||!i)throw new n(t.name,t.version,t.integrity,"Invalid format");const r=await crypto.subtle.digest(s.toUpperCase(),(new TextEncoder).encode(e)),o=Array.from(new Uint8Array(r)),a=btoa(String.fromCharCode(...o));if(a!==i)throw new n(t.name,t.version,i,a)}async executeScript(t,e){const s=new Blob([t],{type:"application/javascript"}),n=URL.createObjectURL(s);try{const t=await import(n),s=t.default||t[e.name]||t.Component;if(!s)throw new i(e.name,e.version,"Component module does not export a valid component");return s}finally{URL.revokeObjectURL(n)}}resolveUrl(t){return t.startsWith("http://")||t.startsWith("https://")?t:`${this.options.cdnBaseUrl}/${t.replace(/^\//,"")}`}getComponentKey(t,e){return`${t}@${e}`}log(t,e){this.options.logger&&this.options.logger[t](e)}},u=class{constructor(t){this.preconnectedHosts=new Set,this.preloadedAssets=new Set,this.options=t}preconnectAll(){[...this.options.cdnHosts,...this.options.apiHosts].forEach(t=>this.preconnect(t))}preconnect(t){if(this.preconnectedHosts.has(t))return;const e=document.createElement("link");e.rel="preconnect",e.href=t.startsWith("http")?t:`https://${t}`,e.crossOrigin="anonymous",document.head.appendChild(e),this.preconnectedHosts.add(t)}dnsPrefetch(t){const e=document.createElement("link");e.rel="dns-prefetch",e.href=t.startsWith("http")?t:`https://${t}`,document.head.appendChild(e)}preloadScript(t,e){if(this.preloadedAssets.has(t))return;const s=document.createElement("link");s.rel="preload",s.as="script",s.href=t,e&&(s.integrity=e,s.crossOrigin="anonymous"),document.head.appendChild(s),this.preloadedAssets.add(t)}preloadStyle(t,e){if(this.preloadedAssets.has(t))return;const s=document.createElement("link");s.rel="preload",s.as="style",s.href=t,e&&(s.integrity=e,s.crossOrigin="anonymous"),document.head.appendChild(s),this.preloadedAssets.add(t)}preloadImage(t){if(this.preloadedAssets.has(t))return;const e=document.createElement("link");e.rel="preload",e.as="image",e.href=t,document.head.appendChild(e),this.preloadedAssets.add(t)}prefetch(t,e){const s=document.createElement("link");s.rel="prefetch",s.href=t,e&&(s.as=e),document.head.appendChild(s)}loadStylesheet(t,e){return new Promise((s,i)=>{const n=document.createElement("link");n.rel="stylesheet",n.href=t,e&&(n.integrity=e,n.crossOrigin="anonymous"),n.onload=()=>s(),n.onerror=()=>i(new Error(`Failed to load stylesheet: ${t}`)),document.head.appendChild(n)})}loadScript(t,e){return new Promise((s,i)=>{const n=document.createElement("script");n.src=t,n.async=!0,e&&(n.integrity=e,n.crossOrigin="anonymous"),n.onload=()=>s(),n.onerror=()=>i(new Error(`Failed to load script: ${t}`)),document.body.appendChild(n)})}},d=class{constructor(){this.listeners=new Set,this.changeCallbacks=new Set,this.state=this.createInitialState()}getState(){return this.state}getPhase(){return this.state.phase}setPhase(t){this.setState({phase:t})}setPage(t){const e=t.pageJson,s=this.initializePageState(e);t.preloadedData&&Object.assign(s,t.preloadedData),this.setState({page:t,variables:s})}initializePageState(t){const e={};if(t.state&&t.state.fields)for(const[s,i]of Object.entries(t.state.fields))if(i&&"object"==typeof i){const t=i;e[s]=t.initialValue}return e}setError(t){this.setState({phase:"error",error:t})}clearError(){this.state.error&&this.setState({error:null})}getVariable(t){return t.includes(".")?this.getNestedValue(this.state.variables,t):this.state.variables[t]}setVariable(t,e){const s=this.getVariable(t);if(t.includes(".")){const s={...this.state.variables};this.setNestedValue(s,t,e),this.setState({variables:s})}else this.setState({variables:{...this.state.variables,[t]:e}});this.notifyChange({key:t,oldValue:s,newValue:e})}setVariables(t){const e=[];for(const[s,i]of Object.entries(t)){const t=this.getVariable(s);e.push({key:s,oldValue:t,newValue:i})}this.setState({variables:{...this.state.variables,...t}}),e.forEach(t=>this.notifyChange(t))}getQuery(t){return this.state.queries[t]}setQuery(t,e){this.setState({queries:{...this.state.queries,[t]:e}})}clearQuery(t){const{[t]:e,...s}=this.state.queries;this.setState({queries:s})}setComponentStatus(t,e){const s=new Map(this.state.components);s.set(t,e),this.setState({components:s})}getComponentStatus(t){return this.state.components.get(t)}setDestroyed(){this.setState({phase:"destroyed",destroyed:!0})}isDestroyed(){return this.state.destroyed}subscribe(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}onStateChange(t){return this.changeCallbacks.add(t),()=>{this.changeCallbacks.delete(t)}}reset(){this.state=this.createInitialState(),this.notifyListeners()}getExpressionContext(){return{state:this.state.variables,binding:this.state.queries,local:{},context:{pageVersionId:this.state.page?.pageVersionId,pageId:this.state.page?.pageId,phase:this.state.phase,$now:Date.now()}}}setState(t){this.state={...this.state,...t},this.notifyListeners()}notifyListeners(){this.listeners.forEach(t=>{try{t(this.state)}catch(t){}})}notifyChange(t){this.changeCallbacks.forEach(e=>{try{e(t)}catch(t){}})}getNestedValue(t,e){const s=e.split(".");let i=t;for(const t of s){if(null==i)return;i=i[t]}return i}setNestedValue(t,e,s){const i=e.split(".");let n=t;for(let t=0;t<i.length-1;t++){const e=i[t];void 0!==n[e]&&null!==n[e]||(n[e]={}),n=n[e]}n[i[i.length-1]]=s}createInitialState(){return{phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}}},p=class{constructor(t){this.bindings=new Map,this.dependencyGraph=new Map,this.bindingDependencies=new Map,this.options=t}registerBindings(t){for(const e of t)this.registerBinding(e)}registerBinding(t){if(this.bindings.set(t.id,{binding:t,loading:!1,retryCount:0}),t.dependencies)for(const e of t.dependencies)this.dependencyGraph.has(e)||this.dependencyGraph.set(e,new Set),this.dependencyGraph.get(e).add(t.id);this.updateBindingDependencies(t),this.log("debug",`Registered data binding: ${t.id}`)}updateBindingDependencies(t){for(const[e,s]of this.bindings){if(e===t.id)continue;const i=s.binding;i.dependencies?.includes(t.targetState)&&(this.bindingDependencies.has(t.id)||this.bindingDependencies.set(t.id,new Set),this.bindingDependencies.get(t.id).add(e))}if(t.dependencies)for(const e of t.dependencies)for(const[s,i]of this.bindings)s!==t.id&&i.binding.targetState===e&&(this.bindingDependencies.has(s)||this.bindingDependencies.set(s,new Set),this.bindingDependencies.get(s).add(t.id))}async initializeBindings(t){const e=[];for(const t of this.bindings.values())"eager"===t.binding.loadStrategy&&e.push(t.binding);const s=this.topologicalSort(e),i=this.createLoadBatches(s);for(const e of i){const s=await Promise.allSettled(e.map(e=>this.loadBinding(e.id,t))),i=new Map;s.forEach((t,s)=>{const n=e[s].id;"fulfilled"===t.status?i.set(n,{success:!0,data:t.value}):i.set(n,{success:!1,error:t.reason})}),this.options.onBatchComplete?.(i)}}topologicalSort(t){const e=new Map(t.map(t=>[t.id,t])),s=new Set,i=[],n=t=>{if(!s.has(t.id)){if(s.add(t.id),t.dependencies)for(const i of t.dependencies)for(const[t,r]of e)r.targetState!==i||s.has(t)||n(r);i.push(t)}};for(const e of t)n(e);return i}createLoadBatches(t){const e=[],s=new Set;for(;s.size<t.length;){const i=[];for(const e of t){if(s.has(e.id))continue;let n=!0;if(e.dependencies)for(const i of e.dependencies){for(const e of t)if(e.targetState===i&&!s.has(e.id)){n=!1;break}if(!n)break}n&&i.push(e)}if(0===i.length)for(const e of t)if(!s.has(e.id)){i.push(e),this.log("warn",`Possible circular dependency detected at binding: ${e.id}`);break}i.forEach(t=>s.add(t.id)),i.length>0&&e.push(i)}return e}async loadBinding(t,e,s=!1){const i=this.bindings.get(t);if(!i)throw new c(t,`Data binding not found: ${t}`);const{binding:n}=i;if(!n.condition||this.evaluateCondition(n.condition,e)){if(!s&&this.isCacheValid(i))return this.log("debug",`Binding ${t} returned from cache`),i.cachedData;if(i.loading)this.log("debug",`Binding ${t} is already loading`);else{i.loading=!0;try{const s=this.resolveParams(n.params||{},e),r=await this.executeWithRetry(n,s),o=n.transform?this.applyTransform(r,n.transform,e):r;return i.cachedData=o,i.lastLoadTime=Date.now(),n.cache?.ttl&&(i.cacheExpireTime=Date.now()+1e3*n.cache.ttl),i.retryCount=0,this.options.stateSetter.setVariable(n.targetState,o),this.setupAutoRefresh(i,e),this.options.onDataLoaded?.(t,o),this.log("info",`Binding ${t} loaded successfully`),o}catch(t){throw await this.handleLoadError(i,t,e),t}finally{i.loading=!1}}}else this.log("debug",`Binding ${t} skipped by condition`)}async refreshBinding(t,e){await this.loadBinding(t,e,!0)}async refreshAll(t){const e=Array.from(this.bindings.keys()).map(e=>this.loadBinding(e,t,!0));await Promise.allSettled(e)}async onStateChange(t,e){const s=this.dependencyGraph.get(t);if(!s||0===s.size)return;this.log("debug",`State ${t} changed, refreshing dependent bindings`);const i=Array.from(s).map(t=>this.loadBinding(t,e,!0));await Promise.allSettled(i)}async triggerManualLoad(t,e){const s=this.bindings.get(t);if(!s)throw new c(t,`Data binding not found: ${t}`);return"manual"!==s.binding.loadStrategy&&this.log("warn",`Binding ${t} is not manual strategy`),this.loadBinding(t,e,!0)}checkVisibility(t,e,s){const i=this.bindings.get(t);i&&"lazy"===i.binding.loadStrategy&&e&&!i.lastLoadTime&&this.loadBinding(t,s).catch(e=>{this.log("error",`Lazy binding ${t} failed to load`,e)})}destroy(){for(const t of this.bindings.values())t.refreshTimer&&clearInterval(t.refreshTimer);this.bindings.clear(),this.dependencyGraph.clear(),this.log("debug","DataBindingManager destroyed")}async executeWithRetry(t,e){const s=t.onError?.retry?.maxRetries??0,i=t.onError?.retry?.backoffMs??1e3,n=t.onError?.retry?.backoff??"fixed";let r;for(let o=0;o<=s;o++)try{const s=await this.options.requester.requestData(t.queryVersionId,e);if(!s.success)throw new c(t.queryVersionId,s.message||"Query failed",void 0,{params:e});return s.data}catch(t){if(r=t,this.log("warn",`Query attempt ${o+1}/${s+1} failed:`,t),o<s){const t="exponential"===n?i*Math.pow(2,o):i;await this.delay(t)}}throw r||new Error("Query failed after all retries")}async handleLoadError(t,e,s){const{binding:i}=t,n=i.onError;t.retryCount++,void 0!==n?.fallbackValue&&this.options.stateSetter.setVariable(i.targetState,n.fallbackValue),n?.showError&&this.options.onDataError?.(i.id,e),this.log("error",`Binding ${i.id} load failed:`,e)}setupAutoRefresh(t,e){t.refreshTimer&&(clearInterval(t.refreshTimer),t.refreshTimer=void 0);const s=t.binding.refreshInterval;!s||s<=0||(t.refreshTimer=setInterval(()=>{this.loadBinding(t.binding.id,e,!0).catch(e=>{this.log("error",`Auto refresh for ${t.binding.id} failed:`,e)})},1e3*s))}isCacheValid(t){return!(!t.cachedData||!t.lastLoadTime||t.cacheExpireTime&&Date.now()>t.cacheExpireTime)}resolveParams(t,e){const s={};for(const[i,n]of Object.entries(t))s[i]=this.resolveValue(n,e);return s}resolveValue(t,e){if(null==t)return t;if("object"==typeof t&&!Array.isArray(t)){const s=t;if("expression"===s.type||"binding"===s.type)return this.options.expressionEngine.evaluateWithFallback(s.expression,e,s.fallback);const i={};for(const[t,n]of Object.entries(s))i[t]=this.resolveValue(n,e);return i}return"string"==typeof t&&t.includes("${")?this.options.expressionEngine.evaluateTemplate(t,e):t}evaluateCondition(t,e){const s=void 0===t.fallback||t.fallback,i=this.options.expressionEngine.evaluateWithFallback(t.value,e,s);return Boolean(i)}applyTransform(t,e,s){const i={...s,local:{...s.local||{},$data:t,$response:t}},n=void 0!==e.fallback?e.fallback:t;return this.options.expressionEngine.evaluateWithFallback(e.value,i,n)}delay(t){return new Promise(e=>setTimeout(e,t))}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},f=class{constructor(t={}){this.handlers=new Map,this.options={debug:!1,maxListeners:100,...t}}emit(t){this.options.debug&&this.log("debug",`Event emitted: ${t.type}`,t);const e=this.handlers.get(t.type);e&&e.forEach(e=>{try{e(t)}catch(e){this.log("error",`Error in event handler for ${t.type}:`,e)}})}on(t,e){let s=this.handlers.get(t);return s||(s=new Set,this.handlers.set(t,s)),s.size>=(this.options.maxListeners??100)&&this.log("warn",`Max listeners (${this.options.maxListeners}) reached for event: ${t}`),s.add(e),()=>{s?.delete(e),0===s?.size&&this.handlers.delete(t)}}off(t,e){const s=this.handlers.get(t);s&&(s.delete(e),0===s.size&&this.handlers.delete(t))}once(t,e){const s=this.on(t,t=>{s(),e(t)});return s}clear(t){t?this.handlers.delete(t):this.handlers.clear()}listenerCount(t){return this.handlers.get(t)?.size??0}static createEvent(t,e,s){return{type:t,data:e,timestamp:Date.now(),traceId:s}}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},m=class t{constructor(t){this.debounceTimers=new Map,this.throttleTimers=new Map,this.options=t}async handleEvent(t,e,s){if(t.condition&&!this.evaluateCondition(t.condition,s,e))return void this.log("debug",`Handler ${t.id} skipped by condition`);if(t.throttle&&t.throttle>0&&!this.throttle(t.id,t.throttle))return void this.log("debug",`Handler ${t.id} throttled`);t.debounce&&t.debounce>0&&await this.debounce(t.id,t.debounce);const i={$event:e,$prevResult:void 0,$results:{}};await this.executeActionChain(t.actions,s,i)}async executeActionChain(t,e,s){const i=[];for(let n=0;n<t.length;n++){const r=t[n];if(r.condition){const t=this.buildActionContext(e,s);if(!this.evaluateCondition(r.condition,t,s.$event)){this.log("debug",`Action ${r.id||n} skipped by condition`);continue}}const o=this.executeSingleAction(r,e,s);r.async?i.push(o):await o}i.length>0&&await Promise.allSettled(i)}async executeSingleAction(t,e,s){const i=t.id||t.alias||t.builtinAction||t.actionDefinitionVersionId||"unknown";t.silent||this.options.executor.showLoading();try{const n=this.buildActionContext(e,s),r=this.resolveParams(t.params||{},n);this.options.onActionStart?.(t,r);const o=await this.executeWithRetry(t,r);s.$prevResult=o,t.id&&(s.$results[t.id]=o),this.options.onActionComplete?.(t,{success:!0,data:o}),this.log("debug",`Action ${i} completed successfully`),t.onSuccess&&t.onSuccess.length>0&&await this.executeActionChain(t.onSuccess,e,s)}catch(n){this.log("error",`Action ${i} failed:`,n),this.options.onActionComplete?.(t,{success:!1,error:n}),t.onError&&t.onError.length>0&&await this.executeActionChain(t.onError,e,{...s,$prevResult:{error:n.message}})}finally{t.silent||this.options.executor.hideLoading(),t.onFinally&&t.onFinally.length>0&&await this.executeActionChain(t.onFinally,e,s)}}async executeWithRetry(t,e){const s=t.policy?.retry?.maxAttempts??1,i=t.policy?.retry?.backoffMs??1e3,n=t.policy?.timeoutMs;let r;for(let o=1;o<=s;o++)try{let s;if(t.builtinAction)s=this.executeBuiltinAction(t.builtinAction,e);else{if(!t.actionDefinitionVersionId)throw new a("unknown","Action must specify builtinAction or actionDefinitionVersionId");s=this.executeCustomAction(t.actionDefinitionVersionId,e)}return n&&(s=this.withTimeout(s,n)),await s}catch(t){r=t,this.log("warn",`Action attempt ${o}/${s} failed:`,t),o<s&&await this.delay(i*o)}throw r||new Error("Action failed after all retries")}async executeBuiltinAction(t,e){switch(t){case"setState":return this.options.executor.setState(e.key,e.value),{success:!0};case"navigate":return this.options.executor.navigate({to:e.to??e.url,type:e.replace?"replace":e.external?"external":"push",params:e.params,query:e.query,newWindow:e.newWindow??e.newTab}),{success:!0};case"openDialog":return await this.options.executor.openDialog({type:e.type,content:e.content,title:e.title});case"closeDialog":return this.options.executor.closeDialog(e.dialogId),{success:!0};case"showToast":return this.options.executor.showToast({message:e.message,type:e.type,duration:e.duration}),{success:!0};case"showLoading":return this.options.executor.showLoading(e.message),{success:!0};case"hideLoading":return this.options.executor.hideLoading(),{success:!0};case"refreshData":return await this.options.executor.refreshData(e.queryId),{success:!0};case"track":return this.options.executor.track({eventName:e.eventName,params:e.params}),{success:!0};default:throw new a(t,`Unknown builtin action: ${t}`)}}async executeCustomAction(t,e){const s=t.split("@")[0],i=await this.options.executor.executeAction(s,{...e,actionDefinitionVersionId:t});if(!i.success)throw new a(s,i.errorMessage||"Action execution failed",void 0,t,{errorCode:i.errorCode});return i.data}resolveParams(t,e){const s={};for(const[i,n]of Object.entries(t))s[i]=this.resolveValue(n,e);return s}resolveValue(e,s){if(null==e)return e;if("string"==typeof e){if(e.startsWith("${")&&e.endsWith("}")){const t=e.slice(2,-1);return this.options.expressionEngine.evaluateWithFallback(t,s,e)}return e.includes("${")?this.options.expressionEngine.evaluateTemplate(e,s):e}if("number"==typeof e||"boolean"==typeof e)return e;if(Array.isArray(e))return e.map(t=>this.resolveValue(t,s));if("object"==typeof e){const i=e;if("string"==typeof i.type&&t.EXPRESSION_TYPES.includes(i.type)&&"string"==typeof i.value){const t=i;return this.options.expressionEngine.evaluateWithFallback(t.value,s,t.fallback)}const n={};for(const[t,e]of Object.entries(i))n[t]=this.resolveValue(e,s);return n}return e}evaluateCondition(t,e,s){const i={...e,local:{...e.local||{},$event:s}},n=void 0===t.fallback||t.fallback,r=this.options.expressionEngine.evaluateWithFallback(t.value,i,n);return Boolean(r)}buildActionContext(t,e){return{...t,local:{...t.local||{},$event:e.$event,$prevResult:e.$prevResult,$results:e.$results}}}withTimeout(t,e){return new Promise((s,i)=>{const n=setTimeout(()=>{i(new Error(`Action timed out after ${e}ms`))},e);t.then(t=>{clearTimeout(n),s(t)}).catch(t=>{clearTimeout(n),i(t)})})}debounce(t,e){return new Promise(s=>{const i=this.debounceTimers.get(t);i&&clearTimeout(i);const n=setTimeout(()=>{this.debounceTimers.delete(t),s()},e);this.debounceTimers.set(t,n)})}throttle(t,e){const s=Date.now();return!(s-(this.throttleTimers.get(t)??0)<e||(this.throttleTimers.set(t,s),0))}delay(t){return new Promise(e=>setTimeout(e,t))}destroy(){this.debounceTimers.forEach(t=>clearTimeout(t)),this.debounceTimers.clear(),this.throttleTimers.clear()}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}};m.EXPRESSION_TYPES=["state","binding","local","template","computed"];var g=m,y=class{constructor(t){this.pos=0,this.tokens=[],this.input=t}tokenize(){for(this.pos=0,this.tokens=[];this.pos<this.input.length&&(this.skipWhitespace(),!(this.pos>=this.input.length));){const t=this.readToken();t&&this.tokens.push(t)}return this.tokens.push({type:"EOF",value:null,start:this.input.length,end:this.input.length}),this.tokens}readToken(){const t=this.input[this.pos],e=this.pos;if(this.isDigit(t)||"-"===t&&this.isDigit(this.peek(1)))return this.readNumber();if('"'===t||"'"===t)return this.readString(t);if(this.isIdentifierStart(t))return this.readIdentifier();const s=this.readOperator();if(s)return s;switch(t){case".":return this.pos++,{type:"DOT",value:".",start:e,end:this.pos};case"[":return this.pos++,{type:"LBRACKET",value:"[",start:e,end:this.pos};case"]":return this.pos++,{type:"RBRACKET",value:"]",start:e,end:this.pos};case"(":return this.pos++,{type:"LPAREN",value:"(",start:e,end:this.pos};case")":return this.pos++,{type:"RPAREN",value:")",start:e,end:this.pos};case",":return this.pos++,{type:"COMMA",value:",",start:e,end:this.pos};case"?":return this.pos++,{type:"QUESTION",value:"?",start:e,end:this.pos};case":":return this.pos++,{type:"COLON",value:":",start:e,end:this.pos}}throw new Error(`Unexpected character '${t}' at position ${this.pos}`)}readNumber(){const t=this.pos;let e="";for("-"===this.input[this.pos]&&(e+="-",this.pos++);this.isDigit(this.input[this.pos]);)e+=this.input[this.pos],this.pos++;if("."===this.input[this.pos]&&this.isDigit(this.peek(1)))for(e+=".",this.pos++;this.isDigit(this.input[this.pos]);)e+=this.input[this.pos],this.pos++;return{type:"NUMBER",value:parseFloat(e),start:t,end:this.pos}}readString(t){const e=this.pos;this.pos++;let s="";for(;this.pos<this.input.length&&this.input[this.pos]!==t;){if("\\"===this.input[this.pos]){this.pos++;const t=this.input[this.pos];switch(t){case"n":s+="\n";break;case"t":s+="\t";break;case"r":s+="\r";break;case"\\":s+="\\";break;case'"':s+='"';break;case"'":s+="'";break;default:s+=t}}else s+=this.input[this.pos];this.pos++}if(this.input[this.pos]!==t)throw new Error(`Unterminated string at position ${e}`);return this.pos++,{type:"STRING",value:s,start:e,end:this.pos}}readIdentifier(){const t=this.pos;let e="";for(;this.pos<this.input.length&&this.isIdentifierChar(this.input[this.pos]);)e+=this.input[this.pos],this.pos++;return"true"===e?{type:"BOOLEAN",value:!0,start:t,end:this.pos}:"false"===e?{type:"BOOLEAN",value:!1,start:t,end:this.pos}:"null"===e?{type:"NULL",value:null,start:t,end:this.pos}:{type:"IDENTIFIER",value:e,start:t,end:this.pos}}readOperator(){const t=this.pos,e=this.input.slice(this.pos,this.pos+2),s=this.input[this.pos];return["==","!=",">=","<=","&&","||","??"].includes(e)?(this.pos+=2,{type:"OPERATOR",value:e,start:t,end:this.pos}):["+","-","*","/","%",">","<","!"].includes(s)?(this.pos++,{type:"OPERATOR",value:s,start:t,end:this.pos}):null}skipWhitespace(){for(;this.pos<this.input.length&&/\s/.test(this.input[this.pos]);)this.pos++}isDigit(t){return/[0-9]/.test(t)}isIdentifierStart(t){return/[a-zA-Z_$]/.test(t)}isIdentifierChar(t){return/[a-zA-Z0-9_$]/.test(t)}peek(t=1){return this.input[this.pos+t]||""}},b={len:t=>"string"==typeof t||Array.isArray(t)?t.length:0,trim:t=>String(t??"").trim(),upper:t=>String(t??"").toUpperCase(),lower:t=>String(t??"").toLowerCase(),substr:(t,e,s)=>{const i=String(t??""),n=Number(e)||0,r=void 0!==s?Number(s):void 0;return i.substring(n,void 0!==r?n+r:void 0)},concat:(...t)=>t.map(t=>String(t??"")).join(""),replace:(t,e,s)=>String(t??"").split(String(e)).join(String(s)),split:(t,e)=>String(t??"").split(String(e)),join:(t,e)=>Array.isArray(t)?t.join(void 0!==e?String(e):","):"",startsWith:(t,e)=>String(t??"").startsWith(String(e)),endsWith:(t,e)=>String(t??"").endsWith(String(e)),contains:(t,e)=>String(t??"").includes(String(e)),toNumber:t=>{const e=Number(t);return isNaN(e)?0:e},toString:t=>String(t??""),toInt:t=>Math.trunc(Number(t)||0),toFloat:t=>parseFloat(String(t))||0,round:(t,e)=>{const s=Number(t)||0,i=Number(e)||0,n=Math.pow(10,i);return Math.round(s*n)/n},floor:t=>Math.floor(Number(t)||0),ceil:t=>Math.ceil(Number(t)||0),abs:t=>Math.abs(Number(t)||0),min:(...t)=>{const e=t.map(t=>Number(t)).filter(t=>!isNaN(t));return e.length>0?Math.min(...e):0},max:(...t)=>{const e=t.map(t=>Number(t)).filter(t=>!isNaN(t));return e.length>0?Math.max(...e):0},sum:t=>Array.isArray(t)?t.reduce((t,e)=>t+(Number(e)||0),0):0,avg:t=>Array.isArray(t)&&0!==t.length?t.reduce((t,e)=>t+(Number(e)||0),0)/t.length:0,random:()=>Math.random(),randomInt:(t,e)=>{const s=Math.ceil(Number(t)||0),i=Math.floor(Number(e)||100);return Math.floor(Math.random()*(i-s+1))+s},now:()=>Date.now(),today:()=>(new Date).toISOString().split("T")[0],dateFormat:(t,e)=>{const s=new Date(Number(t)||Date.now()),i=t=>t.toString().padStart(2,"0");return String(e||"YYYY-MM-DD").replace("YYYY",s.getFullYear().toString()).replace("MM",i(s.getMonth()+1)).replace("DD",i(s.getDate())).replace("HH",i(s.getHours())).replace("mm",i(s.getMinutes())).replace("ss",i(s.getSeconds()))},dateParse:t=>new Date(String(t)).getTime(),year:t=>new Date(Number(t)||Date.now()).getFullYear(),month:t=>new Date(Number(t)||Date.now()).getMonth()+1,day:t=>new Date(Number(t)||Date.now()).getDate(),addDays:(t,e)=>{const s=new Date(Number(t)||Date.now());return s.setDate(s.getDate()+(Number(e)||0)),s.getTime()},diffDays:(t,e)=>{const s=new Date(Number(t)||Date.now()),i=new Date(Number(e)||Date.now()),n=Math.abs(i.getTime()-s.getTime());return Math.floor(n/864e5)},isNull:t=>null==t,isUndefined:t=>void 0===t,isEmpty:t=>null==t||("string"==typeof t||Array.isArray(t)?0===t.length:"object"==typeof t&&0===Object.keys(t).length),isArray:t=>Array.isArray(t),isObject:t=>null!==t&&"object"==typeof t&&!Array.isArray(t),isString:t=>"string"==typeof t,isNumber:t=>"number"==typeof t&&!isNaN(t),isBoolean:t=>"boolean"==typeof t,typeOf:t=>null===t?"null":Array.isArray(t)?"array":typeof t,default:(t,e)=>t??e,coalesce:(...t)=>{for(const e of t)if(null!=e)return e;return null},ifElse:(t,e,s)=>t?e:s,first:t=>{if(Array.isArray(t))return t[0]},last:t=>{if(Array.isArray(t))return t[t.length-1]},at:(t,e)=>{if(Array.isArray(t))return t[Number(e)||0]},slice:(t,e,s)=>Array.isArray(t)?t.slice(Number(e)||0,void 0!==s?Number(s):void 0):[],includes:(t,e)=>!!Array.isArray(t)&&t.includes(e),indexOf:(t,e)=>Array.isArray(t)?t.indexOf(e):-1,reverse:t=>Array.isArray(t)?[...t].reverse():[],sort:t=>Array.isArray(t)?[...t].sort():[],unique:t=>Array.isArray(t)?[...new Set(t)]:[],flatten:t=>Array.isArray(t)?t.flat():[],count:t=>Array.isArray(t)?t.length:0,get:(t,e,s)=>{if(null==t)return s;const i=String(e).split(".");let n=t;for(const t of i){if(null==n)return s;n=n[t]}return n??s},keys:t=>"object"!=typeof t||null===t?[]:Object.keys(t),values:t=>"object"!=typeof t||null===t?[]:Object.values(t),entries:t=>"object"!=typeof t||null===t?[]:Object.entries(t),has:(t,e)=>"object"==typeof t&&null!==t&&String(e)in t,merge:(...t)=>{const e={};for(const s of t)"object"==typeof s&&null!==s&&Object.assign(e,s);return e},and:(...t)=>t.every(t=>Boolean(t)),or:(...t)=>t.some(t=>Boolean(t)),not:t=>!t,eq:(t,e)=>t===e,ne:(t,e)=>t!==e,gt:(t,e)=>Number(t)>Number(e),gte:(t,e)=>Number(t)>=Number(e),lt:(t,e)=>Number(t)<Number(e),lte:(t,e)=>Number(t)<=Number(e),between:(t,e,s)=>{const i=Number(t);return i>=Number(e)&&i<=Number(s)},formatNumber:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return s.toLocaleString(void 0,{minimumFractionDigits:i,maximumFractionDigits:i})},formatCurrency:(t,e)=>{const s=Number(t)||0,i=String(e||"CNY");return s.toLocaleString("zh-CN",{style:"currency",currency:i})},formatPercent:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return(100*s).toFixed(i)+"%"},currency:(t,e,s)=>{const i=Number(t)||0,n=String(e??"¥"),r=Number(s)??2;return`${n}${i.toLocaleString(void 0,{minimumFractionDigits:r,maximumFractionDigits:r})}`},percent:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return(100*s).toFixed(i)+"%"},number:(t,e)=>{const s=Number(t)||0,i=Number(e)??0;return s.toLocaleString(void 0,{minimumFractionDigits:i,maximumFractionDigits:i})},pluralize:(t,e,s)=>{const i=Number(t)||0;return`${i} ${String(1===i?e:s)}`},mask:(t,e,s,i)=>{const n=String(t??""),r=Number(e)||3,o=Number(s)||4,a=String(i??"*");if(n.length<=r+o)return n;const c=n.slice(0,r),h=n.slice(-o);return c+a.repeat(n.length-r-o)+h},jsonParse:t=>{try{return JSON.parse(String(t))}catch{return null}},jsonStringify:t=>JSON.stringify(t),toJSON:t=>JSON.stringify(t),fromJSON:t=>{try{return JSON.parse(String(t))}catch{return null}},clamp:(t,e,s)=>{const i=Number(t)||0,n=Number(e)||0,r=Number(s)||100;return Math.min(Math.max(i,n),r)},length:t=>Array.isArray(t)||"string"==typeof t?t.length:0,average:t=>Array.isArray(t)&&0!==t.length?t.reduce((t,e)=>t+(Number(e)||0),0)/t.length:0,dateAdd:(t,e,s)=>{const i=new Date(Number(t)||Date.now()),n=Number(e)||0;switch(String(s??"day").toLowerCase()){case"year":case"years":i.setFullYear(i.getFullYear()+n);break;case"month":case"months":i.setMonth(i.getMonth()+n);break;case"week":case"weeks":i.setDate(i.getDate()+7*n);break;case"day":case"days":default:i.setDate(i.getDate()+n);break;case"hour":case"hours":i.setHours(i.getHours()+n);break;case"minute":case"minutes":i.setMinutes(i.getMinutes()+n)}return i.getTime()},dateDiff:(t,e,s)=>{const i=new Date(Number(t)||Date.now()),n=new Date(Number(e)||Date.now()).getTime()-i.getTime();switch(String(s??"day").toLowerCase()){case"year":case"years":return Math.floor(n/31536e6);case"month":case"months":return Math.floor(n/2592e6);case"week":case"weeks":return Math.floor(n/6048e5);case"day":case"days":default:return Math.floor(n/864e5);case"hour":case"hours":return Math.floor(n/36e5);case"minute":case"minutes":return Math.floor(n/6e4)}},$if:(t,e,s)=>t?e:s,toBoolean:t=>"string"==typeof t?"false"!==t.toLowerCase()&&"0"!==t&&""!==t:Boolean(t),substring:(t,e,s)=>{const i=String(t??""),n=Number(e)||0,r=void 0!==s?Number(s):void 0;return i.substring(n,r)},padStart:(t,e,s)=>{const i=String(t??""),n=Number(e)||0,r=String(s??" ");return i.padStart(n,r)},padEnd:(t,e,s)=>{const i=String(t??""),n=Number(e)||0,r=String(s??" ");return i.padEnd(n,r)},repeat:(t,e)=>{const s=String(t??""),i=Math.max(0,Math.floor(Number(e)||0));return s.repeat(i)}},w={"||":1,"??":1,"&&":2,"==":3,"!=":3,"<":4,">":4,"<=":4,">=":4,"+":5,"-":5,"*":6,"/":6,"%":6},v=class{constructor(t){this.pos=0,this.tokens=t}parse(){const t=this.parseExpression();if("EOF"!==this.current().type)throw new Error(`Unexpected token '${this.current().value}' at position ${this.current().start}`);return t}parseExpression(){return this.parseTernary()}parseTernary(){const t=this.parseBinary(0);if("QUESTION"===this.current().type){this.advance();const e=this.parseExpression();return this.expect("COLON"),{type:"conditional",test:t,consequent:e,alternate:this.parseExpression(),raw:void 0}}return t}parseBinary(t){let e=this.parseUnary();for(;;){const s=this.current();if("OPERATOR"!==s.type)break;const i=w[s.value];if(void 0===i||i<t)break;this.advance();const n=this.parseBinary(i+1);e={type:"binary",operator:s.value,left:e,right:n,raw:void 0}}return e}parseUnary(){const t=this.current();if("OPERATOR"===t.type&&("!"===t.value||"-"===t.value)){this.advance();const e=this.parseUnary();return{type:"unary",operator:t.value,argument:e,raw:void 0}}return this.parsePostfix()}parsePostfix(){let t=this.parsePrimary();for(;;){const e=this.current();if("DOT"===e.type)this.advance(),t={type:"member",object:t,property:this.expect("IDENTIFIER").value,computed:!1,raw:void 0};else if("LBRACKET"===e.type){this.advance();const e=this.parseExpression();this.expect("RBRACKET"),t={type:"member",object:t,property:e,computed:!0,raw:void 0}}else{if("LPAREN"!==e.type||"identifier"!==t.type)break;{const s=t.name;if(!(s in b))throw new Error(`Unknown function '${s}' at position ${e.start}`);this.advance();const i=this.parseArguments();this.expect("RPAREN"),t={type:"call",callee:s,arguments:i,raw:void 0}}}}return t}parsePrimary(){const t=this.current();if("NUMBER"===t.type||"STRING"===t.type||"BOOLEAN"===t.type||"NULL"===t.type)return this.advance(),{type:"literal",value:t.value,start:t.start,end:t.end,raw:void 0};if("IDENTIFIER"===t.type)return this.advance(),{type:"identifier",name:t.value,start:t.start,end:t.end,raw:void 0};if("LBRACKET"===t.type)return this.parseArray();if("LPAREN"===t.type){this.advance();const t=this.parseExpression();return this.expect("RPAREN"),t}throw new Error(`Unexpected token '${t.value}' at position ${t.start}`)}parseArray(){const t=this.current().start;this.advance();const e=[];for(;"RBRACKET"!==this.current().type&&(e.push(this.parseExpression()),"COMMA"===this.current().type);)this.advance();const s=this.current().end;return this.expect("RBRACKET"),{type:"array",elements:e,start:t,end:s,raw:void 0}}parseArguments(){const t=[];if("RPAREN"!==this.current().type)for(t.push(this.parseExpression());"COMMA"===this.current().type;)this.advance(),t.push(this.parseExpression());return t}current(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}expect(t){const e=this.current();if(e.type!==t)throw new Error(`Expected '${t}' but got '${e.type}' at position ${e.start}`);return this.advance()}},$=class{constructor(t={}){this.depth=0,this.startTime=0,this.options={maxDepth:100,timeout:1e3,debug:!1,...t}}evaluate(t,e){this.depth=0,this.startTime=Date.now();try{return{value:this.evaluateNode(t,e)}}catch(t){return{value:void 0,error:t instanceof Error?t:new Error(String(t))}}}evaluateNode(t,e){switch(this.checkLimits(),t.type){case"literal":return this.evaluateLiteral(t);case"identifier":return this.evaluateIdentifier(t,e);case"member":return this.evaluateMember(t,e);case"call":return this.evaluateCall(t,e);case"binary":return this.evaluateBinary(t,e);case"unary":return this.evaluateUnary(t,e);case"conditional":return this.evaluateConditional(t,e);case"array":return this.evaluateArray(t,e);default:throw new o("",`Unknown node type: ${t.type}`)}}evaluateLiteral(t){return t.value}evaluateIdentifier(t,e){const s=t.name;switch(s){case"state":return e.state;case"binding":case"query":return e.binding;case"local":return e.local;case"props":return e.props;case"event":return e.event;case"item":return e.local?.item;case"index":return e.local?.index;default:if(e.local&&s in e.local)return e.local[s];throw new o("",`Unknown variable '${s}'. Available: state, binding, local, props, event`)}}evaluateMember(t,e){const s=this.evaluateNode(t.object,e);if(null==s)return;let i;return i=t.computed?this.evaluateNode(t.property,e):t.property,"object"==typeof s&&null!==s?s[i]:void 0}evaluateCall(t,e){const s=b[t.callee];if(!s)throw new o("",`Unknown function '${t.callee}'`);return s(...t.arguments.map(t=>this.evaluateNode(t,e)))}evaluateBinary(t,e){const s=t.operator;if("&&"===s){const s=this.evaluateNode(t.left,e);return s?this.evaluateNode(t.right,e):s}if("||"===s){return this.evaluateNode(t.left,e)||this.evaluateNode(t.right,e)}if("??"===s){const s=this.evaluateNode(t.left,e);return null!=s?s:this.evaluateNode(t.right,e)}const i=this.evaluateNode(t.left,e),n=this.evaluateNode(t.right,e);switch(s){case"+":return"string"==typeof i||"string"==typeof n?String(i)+String(n):i+n;case"-":return i-n;case"*":return i*n;case"/":return i/n;case"%":return i%n;case"==":return i===n;case"!=":return i!==n;case"<":return i<n;case">":return i>n;case"<=":return i<=n;case">=":return i>=n;default:throw new o("",`Unknown operator '${s}'`)}}evaluateUnary(t,e){const s=this.evaluateNode(t.argument,e);switch(t.operator){case"!":return!s;case"-":return-s;default:throw new o("",`Unknown unary operator '${t.operator}'`)}}evaluateConditional(t,e){return this.evaluateNode(t.test,e)?this.evaluateNode(t.consequent,e):this.evaluateNode(t.alternate,e)}evaluateArray(t,e){return t.elements.map(t=>this.evaluateNode(t,e))}checkLimits(){if(this.depth++,this.depth>(this.options.maxDepth??100))throw new o("","Maximum recursion depth exceeded");if(Date.now()-this.startTime>(this.options.timeout??1e3))throw new o("","Expression evaluation timeout")}},x=class{constructor(t={}){this.astCache=new Map,this.options={cacheAST:!0,maxCacheSize:1e3,...t},this.evaluator=new $(t)}evaluate(t,e){try{const s=this.parse(t);return this.evaluator.evaluate(s,e)}catch(t){return{value:void 0,error:t instanceof Error?t:new Error(String(t))}}}evaluateWithFallback(t,e,s){const i="string"==typeof t?t:t.value,n="object"==typeof t&&void 0!==t.fallback?t.fallback:s,r=this.evaluate(i,e);return r.error?(this.log("warn",`Expression evaluation failed: ${r.error.message}`,i),n):r.value}evaluateTemplate(t,e){return t.replace(/\$\{([^}]+)\}/g,(t,s)=>{const i=this.evaluate(s.trim(),e);return i.error?(this.log("warn",`Template expression failed: ${i.error.message}`,s),""):String(i.value??"")})}parse(t){if(this.options.cacheAST){const e=this.astCache.get(t);if(e)return e}try{const e=new y(t).tokenize(),s=new v(e).parse();return this.options.cacheAST&&(this.astCache.size>=(this.options.maxCacheSize??1e3)&&Array.from(this.astCache.keys()).slice(0,Math.floor(this.astCache.size/2)).forEach(t=>this.astCache.delete(t)),this.astCache.set(t,s)),s}catch(e){throw new o(t,e instanceof Error?e.message:"Parse error")}}validate(t){const e=[],s=[],i=[],n=[];try{const e=this.parse(t);return this.collectReferences(e,i,n),{valid:!0,errors:[],warnings:s,referencedPaths:i,usedFunctions:n}}catch(t){return e.push({type:"invalid_syntax",message:t instanceof Error?t.message:"Parse error"}),{valid:!1,errors:e,warnings:s,referencedPaths:i,usedFunctions:n}}}clearCache(){this.astCache.clear()}collectReferences(t,e,s){switch(t.type){case"identifier":e.push(t.name);break;case"member":{const s=this.buildMemberPath(t);s&&e.push(s);break}case"call":s.push(t.callee),t.arguments.forEach(t=>this.collectReferences(t,e,s));break;case"binary":this.collectReferences(t.left,e,s),this.collectReferences(t.right,e,s);break;case"unary":this.collectReferences(t.argument,e,s);break;case"conditional":this.collectReferences(t.test,e,s),this.collectReferences(t.consequent,e,s),this.collectReferences(t.alternate,e,s);break;case"array":t.elements.forEach(t=>this.collectReferences(t,e,s))}}buildMemberPath(t){if("identifier"===t.type)return t.name;if("member"===t.type&&!t.computed){const e=this.buildMemberPath(t.object);if(e)return`${e}.${t.property}`}return null}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},S=class{constructor(t){this.loadingCount=0,this.loadingElement=null,this.clipboard={write:async t=>{try{return await navigator.clipboard.writeText(t),!0}catch(e){return this.log("error","Clipboard write failed:",e),this.fallbackCopy(t)}},read:async()=>{try{return await navigator.clipboard.readText()}catch(t){return this.log("error","Clipboard read failed:",t),null}}},this.storage={get:t=>{const e=`${this.storageNamespace}:${t}`,s=localStorage.getItem(e);if(!s)return null;try{const t=JSON.parse(s);return t.expires&&Date.now()>t.expires?(localStorage.removeItem(e),null):t.value}catch{return null}},set:(t,e,s)=>{const i=`${this.storageNamespace}:${t}`,n={value:e,expires:s?.ttlSeconds?Date.now()+1e3*s.ttlSeconds:void 0};("session"===s?.level?sessionStorage:localStorage).setItem(i,JSON.stringify(n))},remove:t=>{const e=`${this.storageNamespace}:${t}`;localStorage.removeItem(e),sessionStorage.removeItem(e)},clear:()=>{const t=`${this.storageNamespace}:`;for(let e=localStorage.length-1;e>=0;e--){const s=localStorage.key(e);s?.startsWith(t)&&localStorage.removeItem(s)}for(let e=sessionStorage.length-1;e>=0;e--){const s=sessionStorage.key(e);s?.startsWith(t)&&sessionStorage.removeItem(s)}}},this.options=t,this.storageNamespace=`djvlc:${t.context.appId}`}async navigate(t){this.log("debug","Navigate:",t),this.track({eventName:"djvlc_navigate",params:{to:t.to,type:t.type},type:"click"});let e=t.to;if(t.query){const s=new URLSearchParams(t.query);e+=(e.includes("?")?"&":"?")+s.toString()}switch(t.type){case"external":t.newWindow?window.open(e,"_blank","noopener,noreferrer"):window.location.href=e;break;case"replace":window.location.replace(e);break;default:t.newWindow?window.open(e,"_blank"):window.location.href=e}}track(t){this.log("debug","Track event:",t);const e=this.options.context;fetch(`${this.options.apiBaseUrl}/track`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({eventName:t.eventName,params:t.params,type:t.type||"custom",timestamp:Date.now(),context:{pageVersionId:e.pageVersionId,runtimeVersion:e.runtimeVersion,userId:e.userId,deviceId:e.deviceId,channel:e.channel,appId:e.appId,env:e.env}}),keepalive:!0}).catch(t=>{this.log("warn","Track failed:",t)})}async requestData(t,e){this.log("debug",`Requesting data: ${t}`,e);const s=performance.now(),i=this.options.context;try{const n=await fetch(`${this.options.apiBaseUrl}/data/query`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({queryVersionId:t,params:e||{},context:{pageVersionId:i.pageVersionId,uid:i.userId,deviceId:i.deviceId}})});if(!n.ok){const t=await n.text();throw new Error(`HTTP ${n.status}: ${t||n.statusText}`)}const r=await n.json(),o=performance.now()-s;if(this.log("debug",`Data query completed in ${o.toFixed(2)}ms`),!r.success)throw new Error(r.message||r.errorMessage||"Query failed");return this.options.stateManager.setQuery(t,r.data),r.data}catch(e){const i=performance.now()-s;throw this.log("error",`Data query failed: ${t} (${i.toFixed(2)}ms)`,e),e}}async executeAction(t,e={}){this.log("debug",`Executing action: ${t}`,e);const s=performance.now(),i=this.options.context,n=this.generateIdempotencyKey(t,e);this.track({eventName:"djvlc_action_start",params:{actionType:t,idempotencyKey:n},type:"custom"});try{const r=await fetch(`${this.options.apiBaseUrl}/actions/execute`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({actionType:t,params:e||{},context:{pageVersionId:i.pageVersionId,uid:i.userId,deviceId:i.deviceId,channel:i.channel,appId:i.appId},idempotencyKey:n})});if(!r.ok){const e=await r.text(),i=performance.now()-s;return this.log("error",`Action HTTP error: ${t} (${i.toFixed(2)}ms)`,e),{success:!1,errorCode:`HTTP_${r.status}`,errorMessage:e||r.statusText}}const o=await r.json(),a=performance.now()-s;return this.log("debug",`Action completed in ${a.toFixed(2)}ms`,{success:o.success}),this.track({eventName:o.success?"djvlc_action_success":"djvlc_action_fail",params:{actionType:t,idempotencyKey:n,duration:Math.round(a),errorCode:o.errorCode},type:"custom"}),{success:o.success,data:o.data,errorCode:o.errorCode,errorMessage:o.errorMessage}}catch(e){const i=performance.now()-s;return this.log("error",`Action failed: ${t} (${i.toFixed(2)}ms)`,e),this.track({eventName:"djvlc_action_error",params:{actionType:t,idempotencyKey:n,duration:Math.round(i),errorMessage:e instanceof Error?e.message:"Unknown error"},type:"custom"}),{success:!1,errorCode:"NETWORK_ERROR",errorMessage:e instanceof Error?e.message:"Action failed"}}}async openDialog(t){return this.log("debug","Open dialog:",t),new Promise(e=>{const s=new CustomEvent("djvlc:openDialog",{detail:{options:t,resolve:t=>e(t)}});document.dispatchEvent(s),setTimeout(()=>{e({confirmed:!1})},6e4)})}closeDialog(t){this.log("debug","Close dialog:",t);const e=new CustomEvent("djvlc:closeDialog",{detail:{dialogId:t}});document.dispatchEvent(e)}showToast(t){this.log("debug","Show toast:",t);const e=document.createElement("div");switch(e.className=`djvlc-toast djvlc-toast-${t.type||"info"} djvlc-toast-${t.position||"top"}`,e.setAttribute("role","alert"),e.textContent=t.message,Object.assign(e.style,{position:"fixed",left:"50%",transform:"translateX(-50%)",padding:"12px 24px",borderRadius:"8px",color:"#fff",fontSize:"14px",zIndex:"10000",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",transition:"opacity 0.3s, transform 0.3s",opacity:"0"}),e.style.backgroundColor={success:"#52c41a",error:"#ff4d4f",warning:"#faad14",info:"#1890ff"}[t.type||"info"],t.position){case"center":e.style.top="50%",e.style.transform="translate(-50%, -50%)";break;case"bottom":e.style.bottom="20px";break;default:e.style.top="20px"}document.body.appendChild(e),requestAnimationFrame(()=>{e.style.opacity="1"}),setTimeout(()=>{e.style.opacity="0",setTimeout(()=>e.remove(),300)},t.duration||3e3)}showLoading(t){this.loadingCount++,1===this.loadingCount&&(this.loadingElement=document.createElement("div"),this.loadingElement.className="djvlc-loading-overlay",this.loadingElement.innerHTML=`\n <div class="djvlc-loading-content">\n <div class="djvlc-loading-spinner"></div>\n <div class="djvlc-loading-message">${t||"加载中..."}</div>\n </div>\n `,Object.assign(this.loadingElement.style,{position:"fixed",top:"0",left:"0",right:"0",bottom:"0",backgroundColor:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:"10001"}),document.body.appendChild(this.loadingElement))}hideLoading(){this.loadingCount=Math.max(0,this.loadingCount-1),0===this.loadingCount&&this.loadingElement&&(this.loadingElement.remove(),this.loadingElement=null)}async share(t){if(this.log("debug","Share:",t),navigator.share)try{return await navigator.share({title:t.title,text:t.description,url:t.url}),{success:!0,channel:"native"}}catch(t){if("AbortError"===t.name)return{success:!1,cancelReason:"User cancelled"};throw t}return t.url&&await this.clipboard.write(t.url)?(this.showToast({message:"链接已复制",type:"success"}),{success:!0,channel:"link"}):{success:!1,cancelReason:"Share not supported"}}async confirm(t){return this.log("debug","Confirm:",t),window.confirm(t.content)}async showActionSheet(t){return this.log("debug","Show action sheet:",t),new Promise(e=>{const s=new CustomEvent("djvlc:showActionSheet",{detail:{options:t,resolve:t=>e(t)}});document.dispatchEvent(s),setTimeout(()=>{e({cancelled:!0})},6e4)})}previewImage(t){this.log("debug","Preview image:",t);const e=new CustomEvent("djvlc:previewImage",{detail:t});document.dispatchEvent(e)}async scanCode(){return this.log("debug","Scan code"),new Promise(t=>{const e=new CustomEvent("djvlc:scanCode",{detail:{resolve:e=>t(e)}});document.dispatchEvent(e),setTimeout(()=>{t({success:!1,cancelReason:"Timeout"})},6e4)})}getState(t){return this.options.stateManager.getVariable(t)}setState(t,e){this.options.stateManager.setVariable(t,e)}getContext(){const t=this.options.context;return{pageVersionId:t.pageVersionId,componentVersionId:"",instanceId:"",userId:t.userId,deviceId:t.deviceId,channel:t.channel,appId:t.appId,env:t.env}}buildHeaders(){const t={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(t.Authorization=`Bearer ${this.options.authToken}`),t}generateIdempotencyKey(t,e){const s=Date.now(),i=JSON.stringify(e||{});return`${t}:${s}:${this.simpleHash(i)}`}simpleHash(t){let e=0;for(let s=0;s<t.length;s++)e=(e<<5)-e+t.charCodeAt(s),e&=e;return Math.abs(e).toString(36)}fallbackCopy(t){const e=document.createElement("textarea");e.value=t,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{return document.execCommand("copy"),!0}catch{return!1}finally{document.body.removeChild(e)}}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},k=class{constructor(t={}){this.blockedComponentsMap=new Map,this.blockedActionsSet=new Set,this.allowedCapabilitiesSet=null,this.options={enableSRI:!0,cdnDomains:[],apiDomains:[],blockedComponents:[],blockedActions:[],applyCSPOnInit:!1,...t},this.updateBlockedList(t.blockedComponents?.map(t=>`${t.name}@${t.version}`)||[],t.blockedActions||[]),t.allowedCapabilities&&(this.allowedCapabilitiesSet=new Set(t.allowedCapabilities)),t.applyCSPOnInit&&this.applyCSP()}updateBlockedList(t,e){this.blockedComponentsMap.clear(),t.forEach(t=>{const[e,s]=t.split("@");e&&s&&this.blockedComponentsMap.set(t,{name:e,version:s,reason:"Blocked by registry"})}),this.blockedActionsSet=new Set(e)}addBlockedComponent(t){const e=`${t.name}@${t.version}`;this.blockedComponentsMap.set(e,t),this.log("warn",`Component blocked: ${e} - ${t.reason}`)}removeBlockedComponent(t,e){const s=`${t}@${e}`;this.blockedComponentsMap.delete(s),this.log("info",`Component unblocked: ${s}`)}isComponentBlocked(t,e){return this.blockedComponentsMap.has(`${t}@${e}`)}getBlockedInfo(t,e){return this.blockedComponentsMap.get(`${t}@${e}`)}getAllBlockedComponents(){return Array.from(this.blockedComponentsMap.values())}isActionBlocked(t){return this.blockedActionsSet.has(t)}isCapabilityAllowed(t){return!this.allowedCapabilitiesSet||this.allowedCapabilitiesSet.has(t)}validateCapabilities(t,e,s){if(!this.allowedCapabilitiesSet)return{valid:!0,disallowed:[]};const i=s.filter(t=>!this.allowedCapabilitiesSet.has(t));return i.length>0&&this.log("warn",`Component ${t}@${e} uses disallowed capabilities: ${i.join(", ")}`),{valid:0===i.length,disallowed:i}}async validateIntegrity(t,e,s,i){if(!this.options.enableSRI)return;const[r,o]=i.split("-");if(!r||!o)throw new n(t,e,i,"Invalid integrity format");const a=await this.computeHash(s,r);if(a!==o)throw this.log("error",`Integrity check failed for ${t}@${e}`),new n(t,e,o,a);this.log("debug",`Integrity check passed for ${t}@${e}`)}async generateIntegrity(t,e="sha384"){return`${e}-${await this.computeHash(t,e)}`}isAllowedUrl(t,e){const s="cdn"===e?this.options.cdnDomains:this.options.apiDomains;if(!s||0===s.length)return!0;try{const e=new URL(t);return s.some(t=>{if(t.startsWith("*.")){const s=t.slice(2);return e.hostname.endsWith(s)||e.hostname===s.slice(1)}return e.hostname===t})}catch{return!1}}validateExternalUrl(t){try{const e=new URL(t);if(!["http:","https:"].includes(e.protocol))return{safe:!1,reason:`Unsafe protocol: ${e.protocol}`};const s=e.hostname;return"localhost"===s||"127.0.0.1"===s||s.startsWith("192.168.")||s.startsWith("10.")||s.startsWith("172.16.")?{safe:!1,reason:"Internal network address not allowed"}:{safe:!0}}catch{return{safe:!1,reason:"Invalid URL format"}}}generateCSPPolicy(){const t=this.options.cdnDomains||[],e=this.options.apiDomains||[],s=["'self'",...t].join(" "),i=["'self'",...e,...t].join(" ");return["default-src 'self'",`script-src ${s}`,`style-src ${["'self'","'unsafe-inline'",...t].join(" ")}`,`img-src ${["'self'","data:","blob:",...t].join(" ")}`,`font-src ${["'self'","data:",...t].join(" ")}`,`connect-src ${i}`,"frame-ancestors 'self'","base-uri 'self'","form-action 'self'","upgrade-insecure-requests"].join("; ")}applyCSP(){if(document.querySelector('meta[http-equiv="Content-Security-Policy"]'))return void this.log("debug","CSP meta tag already exists, skipping");const t=document.createElement("meta");t.httpEquiv="Content-Security-Policy",t.content=this.generateCSPPolicy(),document.head.appendChild(t),this.log("info","CSP policy applied")}assertNotBlocked(t,e){const s=this.getBlockedInfo(t,e);if(s)throw new r(t,e,s.reason)}createSafeEvaluator(){return(t,e)=>{const s=Object.keys(e),i=Object.values(e);return new Function(...s,`"use strict"; return (${t});`)(...i)}}async computeHash(t,e){const s=(new TextEncoder).encode(t),i=await crypto.subtle.digest(e.toUpperCase(),s),n=Array.from(new Uint8Array(i));return btoa(String.fromCharCode(...n))}log(t,e,...s){this.options.logger&&this.options.logger[t](e,...s)}},E=class{constructor(t){this.spans=new Map,this.metrics=[],this.errors=[],this.options={enabled:!0,sampleRate:1,batchSize:50,flushInterval:3e4,...t},this.traceId=this.generateTraceId(),this.shouldSample=Math.random()<(this.options.sampleRate??1),this.options.enabled&&this.options.endpoint&&this.startAutoFlush(),"undefined"!=typeof window&&(window.addEventListener("beforeunload",()=>this.flush()),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()}))}getTraceId(){return this.traceId}getTraceparent(t){const e=t||this.generateSpanId(),s=this.shouldSample?"01":"00";return`00-${this.traceId}-${e}-${s}`}parseTraceparent(t){const e=t.split("-");if(4!==e.length)return null;const[,s,i,n]=e;return{traceId:s,parentSpanId:i,sampled:"01"===n}}startSpan(t,e,s){const i={spanId:this.generateSpanId(),traceId:this.traceId,parentSpanId:e,name:t,startTime:performance.now(),attributes:{pageVersionId:this.options.pageVersionId,...s}};return this.spans.set(i.spanId,i),this.log("debug",`Span started: ${t} (${i.spanId})`),i}endSpan(t,e="ok",s){const i=this.spans.get(t);if(i){i.endTime=performance.now(),i.status=e,s&&(i.attributes={...i.attributes,...s});const n=i.endTime-i.startTime;this.log("debug",`Span ended: ${i.name} (${t}) - ${n.toFixed(2)}ms [${e}]`)}}recordPageLoad(t){this.recordMetricInternal({type:"pageLoadTime",value:t,pageVersionId:this.options.pageVersionId,timestamp:Date.now()})}recordComponentLoad(t,e,s,i){this.recordMetricInternal({type:"componentLoadTime",value:s,pageVersionId:this.options.pageVersionId,componentName:t,componentVersion:e,timestamp:Date.now()}),i||this.recordError(new Error(`Component load failed: ${t}@${e}`),{componentVersion:`${t}@${e}`})}recordFirstRender(t){this.recordMetricInternal({type:"firstRenderTime",value:t,pageVersionId:this.options.pageVersionId,timestamp:Date.now()})}recordActionExecute(t,e,s,i){this.recordMetricInternal({type:"actionExecuteTime",value:s,pageVersionId:this.options.pageVersionId,actionType:t,timestamp:Date.now()}),i||this.recordError(new Error(`Action failed: ${t}`),{actionId:e})}recordQueryExecute(t,e,s,i=!1){this.recordMetricInternal({type:"queryFetchTime",value:e,pageVersionId:this.options.pageVersionId,queryId:t,timestamp:Date.now()}),this.log("debug",`Query ${t}: ${e.toFixed(2)}ms, cache: ${i}, success: ${s}`)}recordExpressionEval(t,e,s){e>1&&this.recordMetricInternal({type:"expressionEvalTime",value:e,pageVersionId:this.options.pageVersionId,timestamp:Date.now()})}recordError(t,e){const s={type:t.name||"Error",message:t.message,stack:t.stack,traceId:this.traceId,pageVersionId:this.options.pageVersionId,componentVersion:e?.componentVersion,actionId:e?.actionId,context:e,timestamp:Date.now()};this.errors.push(s),this.log("error",`Error recorded: ${t.message}`),this.options.onError?.(s),this.errors.length>=(this.options.batchSize??50)&&this.flush()}getMetrics(){return[...this.metrics]}getSpans(){return Array.from(this.spans.values())}getErrors(){return[...this.errors]}getPerformanceSummary(){const t=this.metrics.filter(t=>"componentLoadTime"===t.type),e=this.metrics.find(t=>"pageLoadTime"===t.type),s=this.metrics.find(t=>"firstRenderTime"===t.type);return{pageLoadTime:e?.value,firstRenderTime:s?.value,componentCount:t.length,avgComponentLoadTime:t.length>0?t.reduce((t,e)=>t+e.value,0)/t.length:0,errorCount:this.errors.length}}clear(){this.spans.clear(),this.metrics=[],this.errors=[]}async flush(){if(!this.shouldSample||!this.options.enabled)return;if(0===this.metrics.length&&0===this.errors.length&&0===this.spans.size)return;const t={traceId:this.traceId,pageVersionId:this.options.pageVersionId,appId:this.options.appId,runtimeVersion:this.options.runtimeVersion,spans:this.getSpans(),metrics:this.metrics,errors:this.errors,timestamp:Date.now()};if(this.clear(),this.options.endpoint)try{await fetch(this.options.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),keepalive:!0}),this.log("debug","Telemetry flushed successfully")}catch(t){this.log("warn","Failed to flush telemetry:",t)}else this.log("debug","No endpoint configured, telemetry data discarded")}destroy(){this.flushTimer&&clearInterval(this.flushTimer),this.flush()}recordMetricInternal(t){this.metrics.push(t),this.options.onMetric?.(t),this.metrics.length>=(this.options.batchSize??50)&&this.flush()}startAutoFlush(){const t=this.options.flushInterval??3e4;this.flushTimer=setInterval(()=>this.flush(),t)}generateTraceId(){const t=new Uint8Array(16);return crypto.getRandomValues(t),Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}generateSpanId(){const t=new Uint8Array(8);return crypto.getRandomValues(t),Array.from(t,t=>t.toString(16).padStart(2,"0")).join("")}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},C=class t{constructor(t){this.container=null,this.renderedElements=new Map,this.componentEventListeners=new Map,this.expressionContext={state:{},binding:{},local:{}},this.loopContextStack=[],this.styleElement=null,this.options=t}init(){this.log("debug","Renderer initialized")}render(t,e){this.container=e,this.log("debug","Rendering page",t.pageId),this.cleanup(),e.innerHTML="",this.applyPageConfig(t,e),this.initializePageState(t);const s=this.renderNode(t.root);s&&e.appendChild(s),this.log("info",`Page rendered with root component: ${t.root.componentType}`)}updateComponent(t,e){const s=this.renderedElements.get(t);s?this.applyProps(s,e):this.log("warn",`Component not found: ${t}`)}updateContext(t){this.expressionContext={...this.expressionContext,...t}}getContext(){return{...this.expressionContext}}destroy(){this.cleanup(),this.container&&(this.container.innerHTML=""),this.log("debug","Renderer destroyed")}cleanup(){this.componentEventListeners.forEach((t,e)=>{const s=this.renderedElements.get(e);s&&t.forEach(({event:t,handler:e})=>{s.removeEventListener(t,e)})}),this.componentEventListeners.clear(),this.renderedElements.forEach(t=>{t.remove()}),this.renderedElements.clear(),this.styleElement&&(this.styleElement.remove(),this.styleElement=null),this.loopContextStack=[]}renderNode(t){const{id:e,componentType:s,componentVersion:i}=t;try{if(t.condition&&!this.evaluateCondition(t.condition))return this.log("debug",`Component ${e} hidden by condition`),null;if(t.loop)return this.renderLoop(t);const n=this.createElement(t);if(!n)return null;n.setAttribute("data-component-id",e),n.setAttribute("data-component-type",s),i&&n.setAttribute("data-component-version",i);const r=this.resolveProps(t.props);if(this.applyProps(n,r),t.style&&this.applyStyles(n,t.style),t.layout&&this.applyLayout(n,t.layout),this.options.injectHostApi(n,e),t.eventHandlers&&t.eventHandlers.length>0&&this.bindEventHandlers(n,e,t.eventHandlers),this.renderChildren(n,t),t.ref){const e=this.expressionContext.local,s=e.$refs||{};s[t.ref]=n,this.expressionContext={...this.expressionContext,local:{...e,$refs:s}}}return this.renderedElements.set(e,n),n}catch(t){return this.log("error",`Failed to render component: ${e}`,t),this.options.onRenderError?this.options.onRenderError(e,t):this.createErrorFallback(e,s,t)}}createElement(t){const{componentType:e}=t,s=this.options.components.get(e);if(s&&customElements.get(e))return document.createElement(e);const i=`${e}-${t.componentVersion?.replace(/\./g,"-")}`;if(customElements.get(i))return document.createElement(i);const n=document.createElement("div");return n.className=`djvlc-component djvlc-${e}`,s||(this.log("warn",`Component not loaded: ${e}`),n.classList.add("djvlc-component-fallback")),n}renderLoop(t){const{loop:e}=t;if(!e)return null;const s=this.evaluateExpression(e.items);if(!Array.isArray(s))return this.log("warn",`Loop items is not an array for ${t.id}`),null;const i=document.createDocumentFragment();s.forEach((s,n)=>{this.loopContextStack.push({item:s,index:n,loopConfig:e});const r={...this.expressionContext},o={...this.expressionContext.local,[e.itemName]:s,item:s,index:n};e.indexName&&(o[e.indexName]=n),this.expressionContext={...this.expressionContext,local:o};const a={...t,id:`${t.id}_${n}`,loop:void 0},c=this.renderNode(a);if(c){const t=this.evaluateExpression(e.key);c.setAttribute("data-loop-key",String(t??n)),i.appendChild(c)}this.expressionContext=r,this.loopContextStack.pop()});const n=document.createElement("div");return n.className="djvlc-loop-container",n.setAttribute("data-loop-id",t.id),n.appendChild(i),n}renderChildren(t,e){if(e.slots&&Object.keys(e.slots).length>0)for(const[s,i]of Object.entries(e.slots)){const e=this.createSlotContainer(s);for(const t of i){const s=this.renderNode(t);s&&e.appendChild(s)}t.appendChild(e)}}createSlotContainer(t){const e=document.createElement("div");return e.className=`djvlc-slot djvlc-slot-${t}`,e.setAttribute("data-slot",t),e}bindEventHandlers(t,e,s){const i=[];for(const n of s){const{eventName:s,preventDefault:r,stopPropagation:o,throttle:a,debounce:c,condition:h}=n;let l=t=>{if(h&&!this.evaluateCondition(h))return;r&&t.preventDefault(),o&&t.stopPropagation();const i=t.detail||{};this.options.onComponentEvent&&this.options.onComponentEvent(e,s,[n],i)};a&&a>0&&(l=this.createThrottledHandler(l,a)),c&&c>0&&(l=this.createDebouncedHandler(l,c)),t.addEventListener(s,l),i.push({event:s,handler:l})}this.componentEventListeners.set(e,i)}createThrottledHandler(t,e){let s=0;return i=>{const n=Date.now();n-s>=e&&(s=n,t(i))}}createDebouncedHandler(t,e){let s=null;return i=>{s&&clearTimeout(s),s=setTimeout(()=>{t(i),s=null},e)}}evaluateCondition(t){const e=this.evaluateExpression(t);return Boolean(e)}evaluateExpression(t){if(null==t)return t;if("object"==typeof t&&"type"in t&&"value"in t){const e=t,s=this.buildExpressionContext();return this.options.expressionEngine.evaluateWithFallback(e.value,s,e.fallback)}if("string"==typeof t){const e=this.buildExpressionContext();return this.options.expressionEngine.evaluateWithFallback(t,e,void 0)}return t}buildExpressionContext(){const t={};for(const e of this.loopContextStack)t[e.loopConfig.itemName]=e.item,t.item=e.item,t.index=e.index,e.loopConfig.indexName&&(t[e.loopConfig.indexName]=e.index);return{...this.expressionContext,local:{...this.expressionContext.local,...t}}}resolveProps(t){const e={};for(const[s,i]of Object.entries(t))e[s]=this.resolveValue(i);return e}resolveValue(e){if(null==e)return e;if("string"==typeof e)return e.includes("${")?this.options.expressionEngine.evaluateTemplate(e,this.buildExpressionContext()):e;if("number"==typeof e||"boolean"==typeof e)return e;if(Array.isArray(e))return e.map(t=>this.resolveValue(t));if("object"==typeof e){const s=e;if("string"==typeof s.type&&t.EXPRESSION_TYPES.includes(s.type)&&"string"==typeof s.value){const t=s;return this.options.expressionEngine.evaluateWithFallback(t.value,this.buildExpressionContext(),t.fallback)}const i={};for(const[t,e]of Object.entries(s))i[t]=this.resolveValue(e);return i}return e}applyProps(t,e){for(const[s,i]of Object.entries(e))null!=i&&(t.tagName.includes("-")?t[s]=i:"boolean"==typeof i?i?t.setAttribute(s,""):t.removeAttribute(s):"object"==typeof i?t.setAttribute(s,JSON.stringify(i)):t.setAttribute(s,String(i)))}applyStyles(t,e){if(e.inline)for(const[s,i]of Object.entries(e.inline)){if(null==i)continue;const e=this.resolveValue(i);let n;n="number"==typeof e?["zIndex","opacity","flex","fontWeight","lineHeight"].includes(s)?String(e):`${e}px`:String(e);const r=s.replace(/([A-Z])/g,"-$1").toLowerCase();t.style.setProperty(r,n)}e.className&&t.classList.add(...String(e.className).split(" ").filter(Boolean))}applyLayout(t,e){const{x:s,y:i,width:n,height:r,rotation:o,zIndex:a,responsive:c}=e;t.style.position="absolute",void 0!==s&&(t.style.left=`${s}px`),void 0!==i&&(t.style.top=`${i}px`),void 0!==n&&(t.style.width=`${n}px`),void 0!==r&&(t.style.height=`${r}px`),void 0!==o&&(t.style.transform=`rotate(${o}deg)`),void 0!==a&&(t.style.zIndex=String(a)),c&&this.applyResponsiveLayout(t,c)}applyResponsiveLayout(t,e){const s=t.getAttribute("data-component-id");if(!s)return;let i="";if(e.mobile&&(i+=`\n @media (max-width: 767px) {\n [data-component-id="${s}"] {\n ${this.layoutToCSS(e.mobile)}\n }\n }\n `),e.tablet&&(i+=`\n @media (min-width: 768px) and (max-width: 1023px) {\n [data-component-id="${s}"] {\n ${this.layoutToCSS(e.tablet)}\n }\n }\n `),e.desktop&&(i+=`\n @media (min-width: 1440px) {\n [data-component-id="${s}"] {\n ${this.layoutToCSS(e.desktop)}\n }\n }\n `),i){const t=document.createElement("style");t.setAttribute("data-djvlc-responsive",s),t.textContent=i,document.head.appendChild(t)}}layoutToCSS(t){const e=[];return void 0!==t.x&&e.push(`left: ${t.x}px`),void 0!==t.y&&e.push(`top: ${t.y}px`),void 0!==t.width&&e.push(`width: ${t.width}px`),void 0!==t.height&&e.push(`height: ${t.height}px`),void 0!==t.rotation&&e.push(`transform: rotate(${t.rotation}deg)`),void 0!==t.zIndex&&e.push(`z-index: ${t.zIndex}`),e.join("; ")}applyPageConfig(t,e){e.classList.add("djvlc-page"),e.setAttribute("data-page-id",t.pageId),e.setAttribute("data-page-version",t.pageVersion),e.setAttribute("data-schema-version",t.schemaVersion);const s=t.config;s&&(this.applyLayoutConfig(e,s.layout),s.styles&&this.applyStylesConfig(e,s.styles),s.behavior&&this.applyBehaviorConfig(e,s.behavior))}applyBehaviorConfig(t,e){e.debug&&t.setAttribute("data-debug","true"),e.i18n&&this.applyI18nConfig(t,e.i18n)}applyI18nConfig(t,e){const s=this.detectLocale(e);t.setAttribute("lang",s),t.setAttribute("data-locale",s),t.setAttribute("data-default-locale",e.defaultLocale),t.setAttribute("data-supported-locales",e.supportedLocales.join(",")),e.translationBundleId&&t.setAttribute("data-translation-bundle",e.translationBundleId),t.style.setProperty("--djvlc-locale",s),t.style.setProperty("--djvlc-dir",this.getTextDirection(s)),"rtl"===this.getTextDirection(s)?(t.setAttribute("dir","rtl"),t.classList.add("djvlc-rtl")):t.setAttribute("dir","ltr"),this.expressionContext={...this.expressionContext,local:{...this.expressionContext.local,$locale:s,$defaultLocale:e.defaultLocale,$supportedLocales:e.supportedLocales}},this.log("debug",`I18n configured: locale=${s}, default=${e.defaultLocale}`)}detectLocale(t){const{defaultLocale:e,supportedLocales:s,detection:i="browser"}=t;let n=null;switch(i){case"browser":case"header":n=this.detectBrowserLocale(s);break;case"url":n=this.detectUrlLocale(s);break;case"path":n=this.detectPathLocale(s);break;case"cookie":n=this.detectCookieLocale(s);break;case"manual":n=e;break;default:n=null}return n&&s.includes(n)?n:e}detectBrowserLocale(t){if("undefined"==typeof navigator)return null;const e=navigator.languages||[navigator.language];for(const s of e){if(t.includes(s))return s;const e=s.split("-")[0],i=t.find(t=>t===e||t.startsWith(`${e}-`));if(i)return i}return null}detectUrlLocale(t){if("undefined"==typeof window)return null;const e=new URLSearchParams(window.location.search),s=e.get("lang")||e.get("locale");return s&&t.includes(s)?s:null}detectPathLocale(t){if("undefined"==typeof window)return null;const e=window.location.pathname.split("/").filter(Boolean);if(e.length>0){const s=e[0];if(t.includes(s))return s}return null}detectCookieLocale(t){if("undefined"==typeof document)return null;const e=document.cookie.split(";");for(const s of e){const[e,i]=s.trim().split("=");if("lang"===e||"locale"===e||"language"===e){const e=decodeURIComponent(i);if(t.includes(e))return e}}return null}getTextDirection(t){const e=t.split("-")[0];return["ar","ar-SA","ar-EG","ar-AE","he","he-IL","fa","fa-IR","ur","ur-PK","yi","ps","dv"].some(s=>s===t||s===e)?"rtl":"ltr"}applyLayoutConfig(t,e){if(t.setAttribute("data-canvas-type",e.canvasType),e.canvasSize&&"responsive"!==e.canvasType&&(t.style.width=`${e.canvasSize.width}px`,t.style.minHeight=`${e.canvasSize.height}px`),e.maxWidth&&(t.style.maxWidth=`${e.maxWidth}px`,t.style.marginLeft="auto",t.style.marginRight="auto"),e.padding){const{top:s=0,right:i=0,bottom:n=0,left:r=0}=e.padding;t.style.padding=`${s}px ${i}px ${n}px ${r}px`}e.viewport&&(e.viewport.mobile&&t.style.setProperty("--djvlc-breakpoint-mobile",`${e.viewport.mobile}px`),e.viewport.tablet&&t.style.setProperty("--djvlc-breakpoint-tablet",`${e.viewport.tablet}px`),e.viewport.desktop&&t.style.setProperty("--djvlc-breakpoint-desktop",`${e.viewport.desktop}px`))}applyStylesConfig(t,e){if(e.theme&&this.applyThemeConfig(t,e.theme),e.background&&this.applyBackgroundConfig(t,e.background),e.cssVariables)for(const[s,i]of Object.entries(e.cssVariables)){const e=s.startsWith("--")?s:`--${s}`;t.style.setProperty(e,i)}e.customCSS&&this.injectCustomCSS(e.customCSS)}applyThemeConfig(t,e){if(e.preset&&(t.setAttribute("data-theme",e.preset),"system"===e.preset)){const e=window.matchMedia("(prefers-color-scheme: dark)").matches;t.setAttribute("data-theme-resolved",e?"dark":"light")}if(e.variables)for(const[s,i]of Object.entries(e.variables)){const e=s.startsWith("--")?s:`--theme-${s}`;t.style.setProperty(e,i)}e.transition&&t.style.setProperty("--djvlc-theme-transition","all 0.3s ease")}applyBackgroundConfig(t,e){switch(e.type){case"color":t.style.backgroundColor=e.value;break;case"image":t.style.backgroundImage=`url(${e.value})`,t.style.backgroundSize=e.size||"cover",t.style.backgroundPosition=e.position||"center",t.style.backgroundRepeat=e.repeat||"no-repeat";break;case"gradient":t.style.backgroundImage=e.value}}injectCustomCSS(t){t.trim()&&(this.styleElement=document.createElement("style"),this.styleElement.setAttribute("data-djvlc-custom","true"),this.styleElement.textContent=t,document.head.appendChild(this.styleElement))}initializePageState(t){if(t.state&&t.state.fields){const e={};for(const[s,i]of Object.entries(t.state.fields))i&&"object"==typeof i&&(e[s]=i.initialValue);this.expressionContext={...this.expressionContext,state:e}}}createErrorFallback(t,e,s){const i=document.createElement("div");return i.className="djvlc-error-boundary",i.setAttribute("data-component-id",t),i.setAttribute("data-error","true"),i.innerHTML=`\n <div class="djvlc-error-content">\n <span class="djvlc-error-icon">⚠️</span>\n <span class="djvlc-error-message">组件渲染失败: ${e}</span>\n ${this.options.debug?`<pre class="djvlc-error-detail">${s.message}</pre>`:""}\n </div>\n `,i}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}};C.EXPRESSION_TYPES=["state","binding","local","template","computed"];var N=C;function I(){customElements.get("djvlc-fallback")||customElements.define("djvlc-fallback",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).innerHTML='\n <style>\n :host {\n display: block;\n padding: 16px;\n background: #fff2f0;\n border: 1px solid #ffccc7;\n border-radius: 4px;\n color: #ff4d4f;\n font-size: 14px;\n }\n .title {\n font-weight: 600;\n margin-bottom: 8px;\n }\n .message {\n color: #666;\n }\n </style>\n <div class="title">组件加载失败</div>\n <div class="message"><slot>请刷新页面重试</slot></div>\n '}static get observedAttributes(){return["message","component-name"]}attributeChangedCallback(t,e,s){if("message"===t&&this.shadowRoot){const t=this.shadowRoot.querySelector(".message");t&&(t.textContent=s)}if("component-name"===t&&this.shadowRoot){const t=this.shadowRoot.querySelector(".title");t&&(t.textContent=`组件 ${s} 加载失败`)}}}),customElements.get("djvlc-blocked")||customElements.define("djvlc-blocked",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).innerHTML='\n <style>\n :host {\n display: block;\n padding: 16px;\n background: #fffbe6;\n border: 1px solid #ffe58f;\n border-radius: 4px;\n color: #faad14;\n font-size: 14px;\n }\n .icon {\n margin-right: 8px;\n }\n </style>\n <span class="icon">⚠️</span>\n <span>此组件已被暂停使用</span>\n '}}),customElements.get("djvlc-error-boundary")||customElements.define("djvlc-error-boundary",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).innerHTML="\n <style>\n :host {\n display: block;\n padding: 16px;\n background: #f5f5f5;\n border: 1px dashed #d9d9d9;\n border-radius: 4px;\n color: #999;\n font-size: 14px;\n text-align: center;\n }\n </style>\n <slot>渲染出错</slot>\n "}})}function A(t,e,s){const i=`djvlc-${"error"===t?"error-boundary":t}`,n=document.createElement(i);return e&&n.setAttribute("message",e),s&&n.setAttribute("component-name",s),n}var T=class{constructor(t){this.lifecycle=null,this.mounted=!1,this.destroyed=!1,this.cleanupFns=[],this.options=t}register(t){t?(this.lifecycle=t,this.log("debug","Lifecycle hooks registered",{onMounted:t.onMounted?.length??0,onBeforeUnmount:t.onBeforeUnmount?.length??0,onVisibilityChange:t.onVisibilityChange?.length??0}),t.onVisibilityChange&&t.onVisibilityChange.length>0&&this.setupVisibilityListener()):this.log("debug","No lifecycle hooks defined")}async triggerMounted(){this.mounted||this.destroyed||(this.mounted=!0,this.log("debug","Triggering onMounted lifecycle"),await this.executeLifecycleActions("mounted",this.lifecycle?.onMounted),this.options.onLifecycleEvent?.("mounted"))}async triggerBeforeUnmount(){this.mounted&&!this.destroyed&&(this.log("debug","Triggering onBeforeUnmount lifecycle"),await this.executeLifecycleActions("beforeUnmount",this.lifecycle?.onBeforeUnmount),this.options.onLifecycleEvent?.("beforeUnmount"))}async triggerVisibilityChange(t){if(!this.mounted||this.destroyed)return;this.log("debug","Triggering onVisibilityChange lifecycle",{isVisible:t});const e=this.options.getContext(),s={...e,local:{...e.local,$visible:t,$hidden:!t}};await this.executeLifecycleActionsWithContext("visibilityChange",this.lifecycle?.onVisibilityChange,s),this.options.onLifecycleEvent?.("visibilityChange",{isVisible:t})}async destroy(){this.destroyed||(await this.triggerBeforeUnmount(),this.cleanupFns.forEach(t=>t()),this.cleanupFns=[],this.destroyed=!0,this.lifecycle=null,this.log("debug","LifecycleManager destroyed"))}isMounted(){return this.mounted&&!this.destroyed}isDestroyed(){return this.destroyed}setupVisibilityListener(){const t=()=>{const t="visible"===document.visibilityState;this.triggerVisibilityChange(t).catch(t=>{this.log("error","Failed to handle visibility change",t)})};document.addEventListener("visibilitychange",t),this.cleanupFns.push(()=>{document.removeEventListener("visibilitychange",t)}),this.log("debug","Visibility listener registered")}async executeLifecycleActions(t,e){if(!e||0===e.length)return;const s=this.options.getContext();await this.executeLifecycleActionsWithContext(t,e,s)}async executeLifecycleActionsWithContext(t,e,s){if(e&&0!==e.length){this.log("debug",`Executing ${e.length} actions for ${t}`);try{const i={id:`lifecycle_${t}`,eventName:t,actions:e};await this.options.actionBridge.handleEvent(i,{lifecycle:t},s),this.log("debug",`Lifecycle ${t} actions completed`)}catch(e){this.log("error",`Failed to execute lifecycle ${t} actions`,e)}}}log(t,e,...s){this.options.logger?this.options.logger[t](e,...s):this.options.debug}},j=t.CURRENT_SCHEMA_VERSION,D="1.0.0",R=class{constructor(t){if(this.container=null,!t.pageId)throw new Error("pageId is required");this.options={channel:"prod",debug:!1,enableSRI:!0,env:"production",...t},this.logger=this.createLogger(),this.stateManager=new d,this.eventBus=new f({debug:t.debug,logger:this.logger}),this.expressionEngine=new x({debug:t.debug,logger:this.logger}),this.pageLoader=new h({apiBaseUrl:t.apiBaseUrl,channel:t.channel,authToken:t.authToken,previewToken:t.previewToken,headers:t.headers,logger:this.logger}),this.componentLoader=new l({cdnBaseUrl:t.cdnBaseUrl,enableSRI:t.enableSRI,logger:this.logger}),this.assetLoader=new u({cdnHosts:[new URL(t.cdnBaseUrl).host],apiHosts:[new URL(t.apiBaseUrl).host]}),this.securityManager=new k({enableSRI:t.enableSRI,cdnDomains:[new URL(t.cdnBaseUrl).host],apiDomains:[new URL(t.apiBaseUrl).host],logger:this.logger}),this.log("info","Runtime created",{version:D})}async init(){this.log("info","Initializing runtime");const t=performance.now();try{this.container=this.resolveContainer(),this.assetLoader.preconnectAll(),this.pageLoader.preconnect(),I(),this.stateManager.setPhase("resolving");const e=performance.now()-t;this.log("info",`Runtime initialized in ${e.toFixed(2)}ms`)}catch(t){throw this.handleError(t),t}}async load(){this.log("info","Loading page:",this.options.pageId);const t=performance.now();try{this.stateManager.setPhase("resolving");const e=await this.pageLoader.resolve(this.options.pageId,{uid:this.options.userId,deviceId:this.options.deviceId});if(this.validateSchemaVersion(e.pageJson),this.stateManager.setPage(e),this.telemetryManager=new E({pageVersionId:e.pageVersionId,appId:this.options.appId,debug:this.options.debug,logger:this.logger,onMetric:this.options.onMetric}),e.runtimeConfig){const t=e.runtimeConfig.blockedComponents?.map(t=>`${t.name}@${t.version}`)||[];this.securityManager.updateBlockedList(t,[]),this.componentLoader.updateBlockedList(t)}this.stateManager.setPhase("loading"),this.componentLoader.preload(e.manifest.components),(await this.componentLoader.loadAll(e.manifest)).forEach((t,e)=>{this.stateManager.setComponentStatus(e,t),this.telemetryManager.recordComponentLoad(t.name,t.version,t.loadTime||0,"loaded"===t.status)}),this.initHostApi(e),this.initActionBridge(),this.initDataBindingManager(e.pageJson),this.initRenderer(),this.initLifecycleManager(e.pageJson);const s=performance.now()-t;return this.telemetryManager.recordPageLoad(s),this.log("info",`Page loaded in ${s.toFixed(2)}ms`),this.emitEvent("page:loaded",{page:e,loadTime:s}),this.options.onLoad?.(e),e}catch(t){throw this.stateManager.setPhase("error"),this.handleError(t),t}}async render(){const t=this.stateManager.getState();if(!t.page||!this.container)throw new s("Page not loaded");this.log("info","Rendering page");const e=performance.now();try{this.stateManager.setPhase("rendering"),this.renderer.updateContext(this.stateManager.getExpressionContext()),this.renderer.render(t.page.pageJson,this.container),await this.dataBindingManager.initializeBindings(this.stateManager.getExpressionContext()),this.stateManager.setPhase("ready");const s=performance.now()-e;this.telemetryManager.recordFirstRender(s),this.log("info",`Page rendered in ${s.toFixed(2)}ms`),await this.lifecycleManager.triggerMounted(),this.emitEvent("page:rendered",{renderTime:s})}catch(t){throw this.stateManager.setPhase("error"),this.handleError(t),t}}getHostApi(){return this.hostApi}getState(){return this.stateManager.getState()}onStateChange(t){return this.stateManager.subscribe(t)}on(t,e){return this.eventBus.on(t,e)}updateComponent(t,e){this.renderer.updateComponent(t,e)}setVariable(t,e){this.stateManager.setVariable(t,e),this.renderer.updateContext(this.stateManager.getExpressionContext()),this.dataBindingManager.onStateChange(t,this.stateManager.getExpressionContext())}getVariable(t){return this.stateManager.getVariable(t)}async refreshData(t){await this.dataBindingManager.refreshBinding(t,this.stateManager.getExpressionContext()),this.renderer.updateContext(this.stateManager.getExpressionContext())}async executeAction(t,e){return this.hostApi.executeAction(t,e)}async destroy(){this.log("info","Destroying runtime"),await(this.lifecycleManager?.destroy()),this.telemetryManager?.flush(),this.dataBindingManager?.destroy(),this.actionBridge?.destroy(),this.renderer?.destroy(),this.eventBus.clear(),this.stateManager.setDestroyed(),this.container&&(this.container.innerHTML=""),this.emitEvent("page:destroyed",{}),this.log("info","Runtime destroyed")}validateSchemaVersion(t){if(t.schemaVersion!==j)throw new s(`Unsupported schema version: ${t.schemaVersion}. Only ${j} is supported.`,{schemaVersion:t.schemaVersion,supportedVersion:j})}resolveContainer(){const{container:t}=this.options;if("string"==typeof t){const e=document.querySelector(t);if(!e)throw new Error(`Container not found: ${t}`);return e}return t}initHostApi(t){this.hostApi=new S({apiBaseUrl:this.options.apiBaseUrl,authToken:this.options.authToken,headers:this.options.headers,stateManager:this.stateManager,eventBus:this.eventBus,expressionEngine:this.expressionEngine,context:{pageId:t.pageId,pageVersionId:t.pageVersionId,runtimeVersion:D,userId:this.options.userId,deviceId:this.options.deviceId,channel:this.options.channel,appId:this.options.appId||"",env:this.options.env||"production",isEditMode:!1,isPreviewMode:t.isPreview||!1},debug:this.options.debug,logger:this.logger})}initActionBridge(){this.actionBridge=new g({executor:{executeAction:(t,e)=>this.hostApi.executeAction(t,e),requestData:(t,e)=>this.hostApi.requestData(t,e),navigate:t=>this.hostApi.navigate(t),openDialog:t=>this.hostApi.openDialog(t),closeDialog:()=>this.hostApi.closeDialog(),showToast:t=>this.hostApi.showToast(t),showLoading:t=>this.hostApi.showLoading(t),hideLoading:()=>this.hostApi.hideLoading(),track:t=>this.hostApi.track(t),setState:(t,e)=>this.stateManager.setVariable(t,e),getState:t=>this.stateManager.getVariable(t),refreshData:t=>this.refreshData(t)},expressionEngine:this.expressionEngine,debug:this.options.debug,logger:this.logger,onActionStart:(t,e)=>{this.emitEvent("action:executing",{action:t,params:e})},onActionComplete:(t,e)=>{e.success?this.emitEvent("action:executed",{action:t,data:e.data}):this.emitEvent("action:error",{action:t,error:e.error?.message})}})}initDataBindingManager(t){this.dataBindingManager=new p({requester:{requestData:(t,e)=>this.hostApi.requestData(t,e)},stateSetter:{setVariable:(t,e)=>this.stateManager.setVariable(t,e),getVariable:t=>this.stateManager.getVariable(t)},expressionEngine:this.expressionEngine,debug:this.options.debug,logger:this.logger,onDataLoaded:(t,e)=>{this.emitEvent("query:fetched",{bindingId:t,data:e}),this.renderer?.updateContext(this.stateManager.getExpressionContext())},onDataError:(t,e)=>{this.emitEvent("query:error",{bindingId:t,error:e.message})}}),t.dataBindings&&this.dataBindingManager.registerBindings(t.dataBindings),this.stateManager.onStateChange(({key:t})=>{this.dataBindingManager.onStateChange(t,this.stateManager.getExpressionContext())})}initLifecycleManager(t){this.lifecycleManager=new T({actionBridge:this.actionBridge,getContext:()=>this.stateManager.getExpressionContext(),debug:this.options.debug,logger:this.logger,onLifecycleEvent:(t,e)=>{this.emitEvent(`page:lifecycle:${t}`,e??{})}}),this.lifecycleManager.register(t.lifecycle)}initRenderer(){const t=new Map;this.stateManager.getState().components.forEach((e,s)=>{if("loaded"===e.status&&e.component){const[i,n]=s.split("@");t.set(i,{name:i,version:n,Component:e.component,loadTime:e.loadTime||0})}}),this.renderer=new N({expressionEngine:this.expressionEngine,components:t,injectHostApi:(t,e)=>{t.hostApi=this.hostApi,t.componentId=e},onComponentEvent:(t,e,s,i)=>{this.handleComponentEvent(t,e,s,i)},debug:this.options.debug,logger:this.logger,onRenderError:(t,e)=>(this.log("error",`Render error in ${t}:`,e),this.emitEvent("component:error",{componentId:t,error:e.message}),A("error",e.message))}),this.renderer.init()}handleComponentEvent(t,e,s,i){this.log("debug",`Component event: ${t}.${e}`,i);for(const t of s)this.actionBridge.handleEvent(t,i,this.stateManager.getExpressionContext())}handleError(t){const s=t instanceof e?{type:"LOAD_ERROR",message:t.message,code:t.code,details:t.details,traceId:t.traceId,timestamp:t.timestamp}:{type:"UNKNOWN_ERROR",message:t.message,cause:t,timestamp:Date.now()};this.stateManager.setError(s),this.telemetryManager?.recordError(t),this.emitEvent("page:error",{error:t.message}),this.options.onError&&this.options.onError(s)}emitEvent(t,e){const s=f.createEvent(t,e,this.telemetryManager?.getTraceId());this.eventBus.emit(s),this.options.onEvent&&this.options.onEvent(s)}createLogger(){return{debug:(...t)=>{this.options.debug},info:(...t)=>{},warn:(...t)=>{},error:(...t)=>{}}}log(t,e,...s){this.logger[t](e,...s)}};Object.defineProperty(exports,"ErrorCode",{enumerable:!0,get:function(){return t.ErrorCode}}),Object.defineProperty(exports,"ErrorMessages",{enumerable:!0,get:function(){return t.ErrorMessages}}),exports.ActionBridge=g,exports.ActionError=a,exports.AssetLoader=u,exports.BaseRenderer=N,exports.ComponentBlockedError=r,exports.ComponentLoadError=i,exports.ComponentLoader=l,exports.DjvlcRuntime=R,exports.DjvlcRuntimeError=e,exports.Evaluator=$,exports.EventBus=f,exports.ExpressionEngine=x,exports.ExpressionError=o,exports.HostAPIImpl=S,exports.IntegrityError=n,exports.Lexer=y,exports.LifecycleManager=T,exports.PageLoadError=s,exports.PageLoader=h,exports.Parser=v,exports.QueryError=c,exports.RUNTIME_VERSION="1.0.0",exports.RenderError=class extends e{constructor(e,s,i,n){super(t.ErrorCode.SYSTEM_INTERNAL_ERROR,i,{...n,componentId:e,componentType:s}),this.name="RenderError",this.componentId=e,this.componentType=s}},exports.SCHEMA_VERSION=j,exports.SUPPORTED_SCHEMA_VERSION=j,exports.SecurityManager=k,exports.StateManager=d,exports.TelemetryManager=E,exports.builtinFunctions=b,exports.createFallbackElement=A,exports.createRuntime=function(t){return new R(t)},exports.registerFallbackComponents=I;
package/dist/index.d.cts CHANGED
@@ -8,8 +8,8 @@ export { ActionExecuteRequest, ActionExecuteResponse, ActionPolicy, ActionRef, A
8
8
  interface RuntimeOptions {
9
9
  /** 容器元素或选择器 */
10
10
  container: string | HTMLElement;
11
- /** 页面 UID(pageId) */
12
- pageUid: string;
11
+ /** 页面 ID(对应 contracts 中的 pageId) */
12
+ pageId: string;
13
13
  /** API 基础 URL */
14
14
  apiBaseUrl: string;
15
15
  /** CDN 基础 URL */
@@ -68,17 +68,21 @@ interface RuntimeState {
68
68
  }
69
69
  /**
70
70
  * 页面解析结果(Runtime 使用)
71
+ *
72
+ * @description
73
+ * 这是 Runtime 内部使用的类型,从 PageResolveResponse 和 PageSnapshotJson 转换而来。
74
+ * 使用 pageId 符合 contracts 定义。
71
75
  */
72
76
  interface PageResolveResult {
73
- /** 页面 UID */
74
- pageUid: string;
77
+ /** 页面 ID(对应 contracts 中的 pageId) */
78
+ pageId: string;
75
79
  /** 页面版本 ID */
76
80
  pageVersionId: string;
77
81
  /** 页面 JSON(PageSchema) */
78
82
  pageJson: _djvlc_contracts_types.PageSchema;
79
83
  /** 组件清单 */
80
84
  manifest: _djvlc_contracts_types.PageManifest;
81
- /** 运行时配置 */
85
+ /** 运行时配置(从 OpsConfig 转换而来) */
82
86
  runtimeConfig?: {
83
87
  /** 被阻断的组件列表 */
84
88
  blockedComponents?: Array<{
@@ -852,7 +856,7 @@ declare class ActionBridge {
852
856
  * 运行时上下文
853
857
  */
854
858
  interface RuntimeContext {
855
- pageUid: string;
859
+ pageId: string;
856
860
  pageVersionId: string;
857
861
  runtimeVersion: string;
858
862
  userId?: string;
@@ -1130,7 +1134,7 @@ declare class RenderError extends DjvlcRuntimeError {
1130
1134
 
1131
1135
  /**
1132
1136
  * 页面加载器
1133
- * 负责从 API 解析页面配置
1137
+ * 负责从 API 解析页面配置,严格按照 @djvlc/contracts-types 定义
1134
1138
  */
1135
1139
 
1136
1140
  /**
@@ -1139,8 +1143,10 @@ declare class RenderError extends DjvlcRuntimeError {
1139
1143
  interface PageLoaderOptions {
1140
1144
  /** API 基础 URL */
1141
1145
  apiBaseUrl: string;
1146
+ /** 环境 */
1147
+ env?: 'preview' | 'staging' | 'prod';
1142
1148
  /** 渠道 */
1143
- channel?: 'preview' | 'prod' | 'gray';
1149
+ channel?: string;
1144
1150
  /** 认证 Token */
1145
1151
  authToken?: string;
1146
1152
  /** 预览 Token */
@@ -1158,6 +1164,7 @@ interface PageLoaderOptions {
1158
1164
  /**
1159
1165
  * 页面加载器
1160
1166
  * 负责调用 /page/resolve 接口获取页面数据
1167
+ * 严格按照 contracts 中的 PageResolveResponse 定义
1161
1168
  */
1162
1169
  declare class PageLoader {
1163
1170
  private options;
@@ -1165,13 +1172,40 @@ declare class PageLoader {
1165
1172
  constructor(options: PageLoaderOptions);
1166
1173
  /**
1167
1174
  * 解析页面
1168
- * @param pageUid 页面 UID
1175
+ * @param pageId 页面 ID(对应 contracts 中的 pageId)
1169
1176
  * @param params 额外参数
1170
1177
  */
1171
- resolve(pageUid: string, params?: {
1178
+ resolve(pageId: string, params?: {
1172
1179
  uid?: string;
1173
1180
  deviceId?: string;
1174
1181
  }): Promise<PageResolveResult>;
1182
+ /**
1183
+ * 调用 Resolve API
1184
+ * 严格按照 contracts 中的 PageResolveRequest 和 PageResolveResponse
1185
+ */
1186
+ private callResolveApi;
1187
+ /**
1188
+ * 从 CDN 加载 snapshot 和 manifest
1189
+ */
1190
+ private loadFromCdn;
1191
+ /**
1192
+ * 转换 PageSnapshotJson 为 PageResolveResult
1193
+ */
1194
+ private convertSnapshotToResult;
1195
+ /**
1196
+ * 转换 PageSnapshotPage 为 PageSchema
1197
+ * 严格按照 contracts 定义进行转换
1198
+ */
1199
+ private convertSnapshotPageToPageSchema;
1200
+ /**
1201
+ * 转换 PageSnapshotManifest 为 PageManifest
1202
+ * 注意:PageSnapshotManifest 是简化版本,缺少一些字段,需要从其他地方获取或使用默认值
1203
+ */
1204
+ private convertSnapshotManifestToPageManifest;
1205
+ /**
1206
+ * 验证 PageResolveResponse(严格按照 contracts 定义)
1207
+ */
1208
+ private isValidPageResolveResponse;
1175
1209
  /**
1176
1210
  * 预连接 API 服务器
1177
1211
  */
@@ -1179,12 +1213,10 @@ declare class PageLoader {
1179
1213
  /**
1180
1214
  * 清除缓存
1181
1215
  */
1182
- clearCache(pageUid?: string): void;
1183
- private buildResolveUrl;
1216
+ clearCache(pageId?: string): void;
1184
1217
  private buildHeaders;
1185
1218
  private getCacheKey;
1186
1219
  private isCacheValid;
1187
- private isValidPageResolveResult;
1188
1220
  private log;
1189
1221
  }
1190
1222