@djvlc/runtime-web 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3727,7 +3727,7 @@ var DjvlcRuntime = class {
3727
3727
  this.logger[level](message, ...args);
3728
3728
  }
3729
3729
  };
3730
- const RUNTIME_VERSION = "0.1.0";
3730
+ const RUNTIME_VERSION = "1.0.0";
3731
3731
  async function mount(container, options) {
3732
3732
  var _a, _b;
3733
3733
  const runtimeOptions = {
@@ -3838,4 +3838,3 @@ export {
3838
3838
  preconnect,
3839
3839
  preloadAssets
3840
3840
  };
3841
- //# sourceMappingURL=runtime.esm.js.map
@@ -1,2 +1 @@
1
- var DJVRuntime=function(e){"use strict";var t=(e=>(e[e.UNKNOWN=1e3]="UNKNOWN",e[e.INVALID_REQUEST=1001]="INVALID_REQUEST",e[e.UNAUTHORIZED=1002]="UNAUTHORIZED",e[e.FORBIDDEN=1003]="FORBIDDEN",e[e.NOT_FOUND=1004]="NOT_FOUND",e[e.RATE_LIMITED=1005]="RATE_LIMITED",e[e.VALIDATION_ERROR=1006]="VALIDATION_ERROR",e[e.INTERNAL_ERROR=1007]="INTERNAL_ERROR",e[e.SERVICE_UNAVAILABLE=1008]="SERVICE_UNAVAILABLE",e[e.TIMEOUT=1009]="TIMEOUT",e[e.ACTION_NOT_FOUND=2001]="ACTION_NOT_FOUND",e[e.ACTION_INVALID_PARAMS=2002]="ACTION_INVALID_PARAMS",e[e.ACTION_EXECUTION_FAILED=2003]="ACTION_EXECUTION_FAILED",e[e.ACTION_IDEMPOTENCY_CONFLICT=2004]="ACTION_IDEMPOTENCY_CONFLICT",e[e.ACTION_BLOCKED=2005]="ACTION_BLOCKED",e[e.ACTION_RISK_REJECTED=2006]="ACTION_RISK_REJECTED",e[e.ACTION_EXPIRED=2007]="ACTION_EXPIRED",e[e.ACTION_QUOTA_EXCEEDED=2008]="ACTION_QUOTA_EXCEEDED",e[e.QUERY_NOT_FOUND=3001]="QUERY_NOT_FOUND",e[e.QUERY_INVALID_PARAMS=3002]="QUERY_INVALID_PARAMS",e[e.QUERY_EXECUTION_FAILED=3003]="QUERY_EXECUTION_FAILED",e[e.QUERY_FIELD_NOT_ALLOWED=3004]="QUERY_FIELD_NOT_ALLOWED",e[e.QUERY_TIMEOUT=3005]="QUERY_TIMEOUT",e[e.QUERY_DISABLED=3006]="QUERY_DISABLED",e[e.COMPONENT_NOT_FOUND=4001]="COMPONENT_NOT_FOUND",e[e.COMPONENT_VERSION_NOT_FOUND=4002]="COMPONENT_VERSION_NOT_FOUND",e[e.COMPONENT_BLOCKED=4003]="COMPONENT_BLOCKED",e[e.COMPONENT_INTEGRITY_MISMATCH=4004]="COMPONENT_INTEGRITY_MISMATCH",e[e.COMPONENT_INCOMPATIBLE=4005]="COMPONENT_INCOMPATIBLE",e[e.COMPONENT_LOAD_FAILED=4006]="COMPONENT_LOAD_FAILED",e[e.COMPONENT_RENDER_ERROR=4007]="COMPONENT_RENDER_ERROR",e[e.PAGE_NOT_FOUND=5001]="PAGE_NOT_FOUND",e[e.PAGE_VERSION_NOT_FOUND=5002]="PAGE_VERSION_NOT_FOUND",e[e.PAGE_SCHEMA_INVALID=5003]="PAGE_SCHEMA_INVALID",e[e.PAGE_MANIFEST_INVALID=5004]="PAGE_MANIFEST_INVALID",e[e.PAGE_PUBLISH_FAILED=5005]="PAGE_PUBLISH_FAILED",e[e.PAGE_ROLLBACK_FAILED=5006]="PAGE_ROLLBACK_FAILED",e[e.ACTIVITY_NOT_FOUND=6001]="ACTIVITY_NOT_FOUND",e[e.ACTIVITY_NOT_STARTED=6002]="ACTIVITY_NOT_STARTED",e[e.ACTIVITY_ENDED=6003]="ACTIVITY_ENDED",e[e.ACTIVITY_ALREADY_CLAIMED=6004]="ACTIVITY_ALREADY_CLAIMED",e[e.ACTIVITY_ALREADY_SIGNED=6005]="ACTIVITY_ALREADY_SIGNED",e[e.ACTIVITY_LIMIT_EXCEEDED=6006]="ACTIVITY_LIMIT_EXCEEDED",e[e.ACTIVITY_DISABLED=6007]="ACTIVITY_DISABLED",e[e.EXPRESSION_SYNTAX_ERROR=7001]="EXPRESSION_SYNTAX_ERROR",e[e.EXPRESSION_UNKNOWN_FUNCTION=7002]="EXPRESSION_UNKNOWN_FUNCTION",e[e.EXPRESSION_INVALID_ARGUMENT=7003]="EXPRESSION_INVALID_ARGUMENT",e[e.EXPRESSION_UNKNOWN_VARIABLE=7004]="EXPRESSION_UNKNOWN_VARIABLE",e[e.EXPRESSION_TYPE_MISMATCH=7005]="EXPRESSION_TYPE_MISMATCH",e[e.EXPRESSION_ACCESS_DENIED=7006]="EXPRESSION_ACCESS_DENIED",e[e.SCHEMA_VERSION_MISMATCH=8001]="SCHEMA_VERSION_MISMATCH",e[e.MIGRATION_FAILED=8002]="MIGRATION_FAILED",e[e.MIGRATION_NOT_FOUND=8003]="MIGRATION_NOT_FOUND",e[e.VERSION_INCOMPATIBLE=8004]="VERSION_INCOMPATIBLE",e))(t||{}),r={1e3:"未知错误",1001:"请求参数无效",1002:"未授权访问",1003:"禁止访问",1004:"资源不存在",1005:"请求频率超限",1006:"数据校验失败",1007:"服务内部错误",1008:"服务暂不可用",1009:"请求超时",2001:"动作不存在",2002:"动作参数无效",2003:"动作执行失败",2004:"重复请求",2005:"动作已被禁用",2006:"风控拒绝",2007:"动作已过期",2008:"配额已用尽",3001:"查询不存在",3002:"查询参数无效",3003:"查询执行失败",3004:"字段访问被拒绝",3005:"查询超时",3006:"查询已禁用",4001:"组件不存在",4002:"组件版本不存在",4003:"组件已被禁用",4004:"组件完整性校验失败",4005:"组件版本不兼容",4006:"组件加载失败",4007:"组件渲染错误",5001:"页面不存在",5002:"页面版本不存在",5003:"页面 Schema 无效",5004:"页面 Manifest 无效",5005:"页面发布失败",5006:"页面回滚失败",6001:"活动不存在",6002:"活动未开始",6003:"活动已结束",6004:"已领取过",6005:"今日已签到",6006:"超出领取限制",6007:"活动已禁用",7001:"表达式语法错误",7002:"未知函数",7003:"无效参数",7004:"未知变量",7005:"类型不匹配",7006:"访问被拒绝",8001:"Schema 版本不匹配",8002:"迁移失败",8003:"迁移脚本不存在",8004:"版本不兼容"},s=new Set([{name:"len",description:"获取字符串或数组长度",params:[{name:"value",type:"any",required:!0}],returnType:"number",examples:['len("hello")',"len([1,2,3])"]},{name:"trim",description:"去除字符串首尾空格",params:[{name:"str",type:"string",required:!0}],returnType:"string",examples:['trim(" hello ")']},{name:"upper",description:"转为大写",params:[{name:"str",type:"string",required:!0}],returnType:"string",examples:['upper("hello")']},{name:"lower",description:"转为小写",params:[{name:"str",type:"string",required:!0}],returnType:"string",examples:['lower("HELLO")']},{name:"substr",description:"截取子字符串",params:[{name:"str",type:"string",required:!0},{name:"start",type:"number",required:!0},{name:"length",type:"number",required:!1}],returnType:"string",examples:['substr("hello", 0, 2)']},{name:"concat",description:"连接字符串",params:[{name:"values",type:"any",required:!0,description:"可变参数"}],returnType:"string",examples:['concat("a", "b", "c")']},{name:"replace",description:"替换字符串",params:[{name:"str",type:"string",required:!0},{name:"search",type:"string",required:!0},{name:"replacement",type:"string",required:!0}],returnType:"string",examples:['replace("hello", "l", "x")']},{name:"split",description:"分割字符串",params:[{name:"str",type:"string",required:!0},{name:"separator",type:"string",required:!0}],returnType:"array",examples:['split("a,b,c", ",")']},{name:"join",description:"连接数组为字符串",params:[{name:"arr",type:"array",required:!0},{name:"separator",type:"string",required:!1,defaultValue:","}],returnType:"string",examples:['join(["a","b","c"], "-")']},{name:"toNumber",description:"转为数字",params:[{name:"value",type:"any",required:!0}],returnType:"number",examples:['toNumber("123")']},{name:"toString",description:"转为字符串",params:[{name:"value",type:"any",required:!0}],returnType:"string",examples:["toString(123)"]},{name:"round",description:"四舍五入",params:[{name:"value",type:"number",required:!0},{name:"decimals",type:"number",required:!1,defaultValue:0}],returnType:"number",examples:["round(3.14159, 2)"]},{name:"floor",description:"向下取整",params:[{name:"value",type:"number",required:!0}],returnType:"number",examples:["floor(3.7)"]},{name:"ceil",description:"向上取整",params:[{name:"value",type:"number",required:!0}],returnType:"number",examples:["ceil(3.2)"]},{name:"abs",description:"绝对值",params:[{name:"value",type:"number",required:!0}],returnType:"number",examples:["abs(-5)"]},{name:"min",description:"最小值",params:[{name:"values",type:"number",required:!0,description:"可变参数"}],returnType:"number",examples:["min(1, 2, 3)"]},{name:"max",description:"最大值",params:[{name:"values",type:"number",required:!0,description:"可变参数"}],returnType:"number",examples:["max(1, 2, 3)"]},{name:"now",description:"当前时间戳(毫秒)",params:[],returnType:"number",examples:["now()"]},{name:"dateFormat",description:"格式化日期",params:[{name:"timestamp",type:"number",required:!0},{name:"format",type:"string",required:!1,defaultValue:"YYYY-MM-DD"}],returnType:"string",examples:['dateFormat(now(), "YYYY-MM-DD HH:mm:ss")']},{name:"dateParse",description:"解析日期字符串",params:[{name:"dateStr",type:"string",required:!0},{name:"format",type:"string",required:!1}],returnType:"number",examples:['dateParse("2024-01-01")']},{name:"first",description:"获取数组第一个元素",params:[{name:"arr",type:"array",required:!0}],returnType:"any",examples:["first([1,2,3])"]},{name:"last",description:"获取数组最后一个元素",params:[{name:"arr",type:"array",required:!0}],returnType:"any",examples:["last([1,2,3])"]},{name:"includes",description:"检查数组是否包含元素",params:[{name:"arr",type:"array",required:!0},{name:"value",type:"any",required:!0}],returnType:"boolean",examples:["includes([1,2,3], 2)"]},{name:"slice",description:"截取数组",params:[{name:"arr",type:"array",required:!0},{name:"start",type:"number",required:!0},{name:"end",type:"number",required:!1}],returnType:"array",examples:["slice([1,2,3,4], 1, 3)"]},{name:"default",description:"提供默认值",params:[{name:"value",type:"any",required:!0},{name:"defaultValue",type:"any",required:!0}],returnType:"any",examples:['default(null, "fallback")']},{name:"ifElse",description:"条件判断",params:[{name:"condition",type:"boolean",required:!0},{name:"trueValue",type:"any",required:!0},{name:"falseValue",type:"any",required:!0}],returnType:"any",examples:['ifElse(age > 18, "成年", "未成年")']},{name:"isEmpty",description:"检查是否为空",params:[{name:"value",type:"any",required:!0}],returnType:"boolean",examples:['isEmpty("")',"isEmpty([])"]},{name:"isNull",description:"检查是否为 null 或 undefined",params:[{name:"value",type:"any",required:!0}],returnType:"boolean",examples:["isNull(null)"]},{name:"jsonParse",description:"解析 JSON 字符串",params:[{name:"str",type:"string",required:!0}],returnType:"any",examples:["jsonParse('{\"a\":1}')"]},{name:"jsonStringify",description:"序列化为 JSON",params:[{name:"value",type:"any",required:!0}],returnType:"string",examples:["jsonStringify({a:1})"]}].map(e=>e.name));function n(e){return null!==e&&"object"==typeof e&&!0===e.__isExpression&&"string"==typeof e.expression}var o=[];function a(e){if(o.some(t=>t.from===e.from&&t.to===e.to))throw new Error(`Migration from ${e.from} to ${e.to} already exists`);o.push(e)}a({from:"1.0.0",to:"1.1.0",description:"添加 Definition 版本绑定字段",migrate:e=>({...e,actionDefVersionIds:e.actionDefVersionIds||[],dataQueryVersionIds:e.dataQueryVersionIds||[]})}),a({from:"1.1.0",to:"2.0.0",description:"重构组件事件结构",breaking:!0,migrate:e=>({...e,components:e.components.map(e=>{var t;return{...e,events:null==(t=e.events)?void 0:t.map(e=>({...e,enabled:e.enabled??!0}))}})})});var i=class extends Error{constructor(e,t,s,n){super(t||r[e]||"Unknown error"),this.name="DjvlcRuntimeError",this.code=e,this.details=s,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}}},c=class extends i{constructor(e,r,s){super(t.PAGE_NOT_FOUND,e,r,s),this.name="PageLoadError"}},l=class extends i{constructor(e,r,s,n=t.COMPONENT_NOT_FOUND,o){super(n,s,{...o,componentName:e,componentVersion:r}),this.name="ComponentLoadError",this.componentName=e,this.componentVersion=r}},p=class extends i{constructor(e,r,s,n){super(t.COMPONENT_INTEGRITY_MISMATCH,`Integrity check failed for ${e}@${r}`,{expectedHash:s,actualHash:n}),this.name="IntegrityError",this.componentName=e,this.componentVersion=r,this.expectedHash=s,this.actualHash=n}},d=class extends i{constructor(e,r,s){super(t.COMPONENT_BLOCKED,`Component ${e}@${r} is blocked`,{componentName:e,componentVersion:r,reason:s}),this.name="ComponentBlockedError",this.componentName=e,this.componentVersion=r,this.reason=s}},h=class extends i{constructor(e,r,s,n){super(t.UNKNOWN,r,{...n,expression:e,position:s}),this.name="ExpressionError",this.expression=e,this.position=s}},u=class{constructor(e){this.cache=new Map,this.options={channel:"prod",cache:{enabled:!0,maxAge:300},...e}}async resolve(e,t){var r,s;const n=this.getCacheKey(e,t);if(null==(r=this.options.cache)?void 0:r.enabled){const t=this.cache.get(n);if(t&&this.isCacheValid(t.timestamp))return this.log("debug",`Page ${e} loaded from cache`),t.data}const o=performance.now();try{const r=this.buildResolveUrl(e,t),a=await fetch(r,{method:"GET",headers:this.buildHeaders()});if(!a.ok)throw new c(`Failed to resolve page: ${a.status} ${a.statusText}`,{pageUid:e,status:a.status});const i=await a.json();if(!this.isValidPageResolveResult(i))throw new c("Invalid page resolve response",{pageUid:e});const l=i.data;(null==(s=this.options.cache)?void 0:s.enabled)&&this.cache.set(n,{data:l,timestamp:Date.now()});const p=performance.now()-o;return this.log("info",`Page ${e} resolved in ${p.toFixed(2)}ms`),l}catch(a){if(a instanceof c)throw a;throw new c(`Failed to resolve page: ${a instanceof Error?a.message:"Unknown error"}`,{pageUid:e})}}preconnect(){const e=document.createElement("link");e.rel="preconnect",e.href=this.options.apiBaseUrl,document.head.appendChild(e)}clearCache(e){if(e)for(const t of this.cache.keys())t.startsWith(e)&&this.cache.delete(t);else this.cache.clear()}buildResolveUrl(e,t){const r=new URL(`${this.options.apiBaseUrl}/page/resolve`);return r.searchParams.set("pageUid",e),this.options.channel&&r.searchParams.set("channel",this.options.channel),this.options.previewToken&&r.searchParams.set("previewToken",this.options.previewToken),(null==t?void 0:t.uid)&&r.searchParams.set("uid",t.uid),(null==t?void 0:t.deviceId)&&r.searchParams.set("deviceId",t.deviceId),r.toString()}buildHeaders(){const e={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(e.Authorization=`Bearer ${this.options.authToken}`),e}getCacheKey(e,t){const r=[e,this.options.channel];return(null==t?void 0:t.uid)&&r.push(t.uid),(null==t?void 0:t.deviceId)&&r.push(t.deviceId),r.join(":")}isCacheValid(e){var t;const r=1e3*((null==(t=this.options.cache)?void 0:t.maxAge)??300);return Date.now()-e<r}isValidPageResolveResult(e){if(!e||"object"!=typeof e)return!1;const t=e;if(!t.data||"object"!=typeof t.data)return!1;const r=t.data;return"string"==typeof r.pageUid&&"string"==typeof r.pageVersionId&&void 0!==r.pageJson&&void 0!==r.manifest}log(e,t){this.options.logger&&this.options.logger[e](t)}},m=class{constructor(e){this.loadedComponents=new Map,this.loadingPromises=new Map,this.options={enableSRI:!0,concurrency:4,timeout:3e4,blockedComponents:[],...e},this.blockedSet=new Set(this.options.blockedComponents)}async load(e){const t=this.getComponentKey(e.name,e.version);if(this.isBlocked(e.name,e.version))throw new d(e.name,e.version,"Component is blocked");const r=this.loadedComponents.get(t);if(r)return r;const s=this.loadingPromises.get(t);if(s)return s;const n=this.loadComponent(e);this.loadingPromises.set(t,n);try{const e=await n;return this.loadedComponents.set(t,e),e}finally{this.loadingPromises.delete(t)}}async loadAll(e){const t=new Map,{concurrency:r=4}=this.options,s=e.components;for(let n=0;n<s.length;n+=r){const e=s.slice(n,n+r).map(async e=>{const r=this.getComponentKey(e.name,e.version),s=performance.now();try{const n=await this.load(e);t.set(r,{name:e.name,version:e.version,status:"loaded",component:n.Component,loadTime:performance.now()-s})}catch(n){const o=n instanceof d?"blocked":"failed";if(t.set(r,{name:e.name,version:e.version,status:o,error:n instanceof Error?n.message:"Unknown error",loadTime:performance.now()-s}),e.critical)throw n}});await Promise.all(e)}return t}preload(e){e.forEach(e=>{const t=document.createElement("link");t.rel="preload",t.as="script",t.href=this.resolveUrl(e.entryUrl),this.options.enableSRI&&e.integrity&&(t.integrity=e.integrity,t.crossOrigin="anonymous"),document.head.appendChild(t)})}isLoaded(e,t){return this.loadedComponents.has(this.getComponentKey(e,t))}get(e,t){return this.loadedComponents.get(this.getComponentKey(e,t))}isBlocked(e,t){return this.blockedSet.has(`${e}@${t}`)||this.blockedSet.has(e)}updateBlockedList(e){this.blockedSet=new Set(e)}async loadComponent(e){const t=performance.now(),r=this.resolveUrl(e.entryUrl);this.log("debug",`Loading component ${e.name}@${e.version}`);try{const s=await this.fetchWithTimeout(r);if(!s.ok)throw new l(e.name,e.version,`Failed to fetch component: ${s.status} ${s.statusText}`);const n=await s.text();this.options.enableSRI&&e.integrity&&await this.validateIntegrity(e,n);const o=await this.executeScript(n,e),a=performance.now()-t;return this.log("info",`Component ${e.name}@${e.version} loaded in ${a.toFixed(2)}ms`),{name:e.name,version:e.version,Component:o,loadTime:a}}catch(s){if(s instanceof l||s instanceof p||s instanceof d)throw s;throw new l(e.name,e.version,`Failed to load component: ${s instanceof Error?s.message:"Unknown error"}`)}}async fetchWithTimeout(e){const t=new AbortController,r=setTimeout(()=>t.abort(),this.options.timeout);try{return await fetch(e,{signal:t.signal,credentials:"omit"})}finally{clearTimeout(r)}}async validateIntegrity(e,t){if(!e.integrity)return;const[r,s]=e.integrity.split("-");if(!r||!s)throw new p(e.name,e.version,e.integrity,"Invalid format");const n=await crypto.subtle.digest(r.toUpperCase(),(new TextEncoder).encode(t)),o=Array.from(new Uint8Array(n)),a=btoa(String.fromCharCode(...o));if(a!==s)throw new p(e.name,e.version,s,a)}async executeScript(e,t){const r=new Blob([e],{type:"application/javascript"}),s=URL.createObjectURL(r);try{const e=await import(s),r=e.default||e[t.name]||e.Component;if(!r)throw new l(t.name,t.version,"Component module does not export a valid component");return r}finally{URL.revokeObjectURL(s)}}resolveUrl(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.options.cdnBaseUrl}/${e.replace(/^\//,"")}`}getComponentKey(e,t){return`${e}@${t}`}log(e,t){this.options.logger&&this.options.logger[e](t)}},g=class{constructor(e){this.preconnectedHosts=new Set,this.preloadedAssets=new Set,this.options=e}preconnectAll(){[...this.options.cdnHosts,...this.options.apiHosts].forEach(e=>this.preconnect(e))}preconnect(e){if(this.preconnectedHosts.has(e))return;const t=document.createElement("link");t.rel="preconnect",t.href=e.startsWith("http")?e:`https://${e}`,t.crossOrigin="anonymous",document.head.appendChild(t),this.preconnectedHosts.add(e)}dnsPrefetch(e){const t=document.createElement("link");t.rel="dns-prefetch",t.href=e.startsWith("http")?e:`https://${e}`,document.head.appendChild(t)}preloadScript(e,t){if(this.preloadedAssets.has(e))return;const r=document.createElement("link");r.rel="preload",r.as="script",r.href=e,t&&(r.integrity=t,r.crossOrigin="anonymous"),document.head.appendChild(r),this.preloadedAssets.add(e)}preloadStyle(e,t){if(this.preloadedAssets.has(e))return;const r=document.createElement("link");r.rel="preload",r.as="style",r.href=e,t&&(r.integrity=t,r.crossOrigin="anonymous"),document.head.appendChild(r),this.preloadedAssets.add(e)}preloadImage(e){if(this.preloadedAssets.has(e))return;const t=document.createElement("link");t.rel="preload",t.as="image",t.href=e,document.head.appendChild(t),this.preloadedAssets.add(e)}prefetch(e,t){const r=document.createElement("link");r.rel="prefetch",r.href=e,t&&(r.as=t),document.head.appendChild(r)}loadStylesheet(e,t){return new Promise((r,s)=>{const n=document.createElement("link");n.rel="stylesheet",n.href=e,t&&(n.integrity=t,n.crossOrigin="anonymous"),n.onload=()=>r(),n.onerror=()=>s(new Error(`Failed to load stylesheet: ${e}`)),document.head.appendChild(n)})}loadScript(e,t){return new Promise((r,s)=>{const n=document.createElement("script");n.src=e,n.async=!0,t&&(n.integrity=t,n.crossOrigin="anonymous"),n.onload=()=>r(),n.onerror=()=>s(new Error(`Failed to load script: ${e}`)),document.body.appendChild(n)})}},y=class{constructor(){this.listeners=new Set,this.state=this.createInitialState()}getState(){return this.state}getPhase(){return this.state.phase}setPhase(e){this.setState({phase:e})}setPage(e){this.setState({page:e,variables:e.pageJson.page.variables||{}})}setError(e){this.setState({phase:"error",error:e})}getVariable(e){return this.state.variables[e]}setVariable(e,t){this.setState({variables:{...this.state.variables,[e]:t}})}setVariables(e){this.setState({variables:{...this.state.variables,...e}})}getQuery(e){return this.state.queries[e]}setQuery(e,t){this.setState({queries:{...this.state.queries,[e]:t}})}setComponentStatus(e,t){const r=new Map(this.state.components);r.set(e,t),this.setState({components:r})}setDestroyed(){this.setState({destroyed:!0})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}reset(){this.state=this.createInitialState(),this.notifyListeners()}setState(e){this.state={...this.state,...e},this.notifyListeners()}notifyListeners(){this.listeners.forEach(e=>{try{e(this.state)}catch(t){}})}createInitialState(){return{phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}}},f=class{constructor(e={}){this.handlers=new Map,this.options={debug:!1,maxListeners:100,...e}}emit(e){this.options.debug&&this.log("debug",`Event emitted: ${e.type}`,e);const t=this.handlers.get(e.type);t&&t.forEach(t=>{try{t(e)}catch(r){this.log("error",`Error in event handler for ${e.type}:`,r)}})}on(e,t){let r=this.handlers.get(e);return r||(r=new Set,this.handlers.set(e,r)),r.size>=(this.options.maxListeners??100)&&this.log("warn",`Max listeners (${this.options.maxListeners}) reached for event: ${e}`),r.add(t),()=>{null==r||r.delete(t),0===(null==r?void 0:r.size)&&this.handlers.delete(e)}}off(e,t){const r=this.handlers.get(e);r&&(r.delete(t),0===r.size&&this.handlers.delete(e))}once(e,t){const r=this.on(e,e=>{r(),t(e)});return r}clear(e){e?this.handlers.delete(e):this.handlers.clear()}listenerCount(e){var t;return(null==(t=this.handlers.get(e))?void 0:t.size)??0}static createEvent(e,t,r){return{type:e,data:t,timestamp:Date.now(),traceId:r}}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},E=class{constructor(e){this.pos=0,this.tokens=[],this.input=e}tokenize(){for(this.pos=0,this.tokens=[];this.pos<this.input.length&&(this.skipWhitespace(),!(this.pos>=this.input.length));){const e=this.readToken();e&&this.tokens.push(e)}return this.tokens.push({type:"EOF",value:null,start:this.input.length,end:this.input.length}),this.tokens}readToken(){const e=this.input[this.pos],t=this.pos;if(this.isDigit(e)||"-"===e&&this.isDigit(this.peek(1)))return this.readNumber();if('"'===e||"'"===e)return this.readString(e);if(this.isIdentifierStart(e))return this.readIdentifier();const r=this.readOperator();if(r)return r;switch(e){case".":return this.pos++,{type:"DOT",value:".",start:t,end:this.pos};case"[":return this.pos++,{type:"LBRACKET",value:"[",start:t,end:this.pos};case"]":return this.pos++,{type:"RBRACKET",value:"]",start:t,end:this.pos};case"(":return this.pos++,{type:"LPAREN",value:"(",start:t,end:this.pos};case")":return this.pos++,{type:"RPAREN",value:")",start:t,end:this.pos};case",":return this.pos++,{type:"COMMA",value:",",start:t,end:this.pos};case"?":return this.pos++,{type:"QUESTION",value:"?",start:t,end:this.pos};case":":return this.pos++,{type:"COLON",value:":",start:t,end:this.pos}}throw new Error(`Unexpected character '${e}' at position ${this.pos}`)}readNumber(){const e=this.pos;let t="";for("-"===this.input[this.pos]&&(t+="-",this.pos++);this.isDigit(this.input[this.pos]);)t+=this.input[this.pos],this.pos++;if("."===this.input[this.pos]&&this.isDigit(this.peek(1)))for(t+=".",this.pos++;this.isDigit(this.input[this.pos]);)t+=this.input[this.pos],this.pos++;return{type:"NUMBER",value:parseFloat(t),start:e,end:this.pos}}readString(e){const t=this.pos;this.pos++;let r="";for(;this.pos<this.input.length&&this.input[this.pos]!==e;){if("\\"===this.input[this.pos]){this.pos++;const e=this.input[this.pos];switch(e){case"n":r+="\n";break;case"t":r+="\t";break;case"r":r+="\r";break;case"\\":r+="\\";break;case'"':r+='"';break;case"'":r+="'";break;default:r+=e}}else r+=this.input[this.pos];this.pos++}if(this.input[this.pos]!==e)throw new Error(`Unterminated string at position ${t}`);return this.pos++,{type:"STRING",value:r,start:t,end:this.pos}}readIdentifier(){const e=this.pos;let t="";for(;this.pos<this.input.length&&this.isIdentifierChar(this.input[this.pos]);)t+=this.input[this.pos],this.pos++;return"true"===t?{type:"BOOLEAN",value:!0,start:e,end:this.pos}:"false"===t?{type:"BOOLEAN",value:!1,start:e,end:this.pos}:"null"===t?{type:"NULL",value:null,start:e,end:this.pos}:{type:"IDENTIFIER",value:t,start:e,end:this.pos}}readOperator(){const e=this.pos,t=this.input.slice(this.pos,this.pos+2),r=this.input[this.pos];if(["==","!=",">=","<=","&&","||","??"].includes(t))return this.pos+=2,{type:"OPERATOR",value:t,start:e,end:this.pos};return["+","-","*","/","%",">","<","!"].includes(r)?(this.pos++,{type:"OPERATOR",value:r,start:e,end:this.pos}):null}skipWhitespace(){for(;this.pos<this.input.length&&/\s/.test(this.input[this.pos]);)this.pos++}isDigit(e){return/[0-9]/.test(e)}isIdentifierStart(e){return/[a-zA-Z_$]/.test(e)}isIdentifierChar(e){return/[a-zA-Z0-9_$]/.test(e)}peek(e=1){return this.input[this.pos+e]||""}},v={"||":1,"??":1,"&&":2,"==":3,"!=":3,"<":4,">":4,"<=":4,">=":4,"+":5,"-":5,"*":6,"/":6,"%":6},b=class{constructor(e){this.pos=0,this.tokens=e}parse(){const e=this.parseExpression();if("EOF"!==this.current().type)throw new Error(`Unexpected token '${this.current().value}' at position ${this.current().start}`);return e}parseExpression(){return this.parseTernary()}parseTernary(){const e=this.parseBinary(0);if("QUESTION"===this.current().type){this.advance();const t=this.parseExpression();this.expect("COLON");return{type:"conditional",test:e,consequent:t,alternate:this.parseExpression(),raw:void 0}}return e}parseBinary(e){let t=this.parseUnary();for(;;){const r=this.current();if("OPERATOR"!==r.type)break;const s=v[r.value];if(void 0===s||s<e)break;this.advance();const n=this.parseBinary(s+1);t={type:"binary",operator:r.value,left:t,right:n,raw:void 0}}return t}parseUnary(){const e=this.current();if("OPERATOR"===e.type&&("!"===e.value||"-"===e.value)){this.advance();const t=this.parseUnary();return{type:"unary",operator:e.value,argument:t,raw:void 0}}return this.parsePostfix()}parsePostfix(){let e=this.parsePrimary();for(;;){const t=this.current();if("DOT"===t.type){this.advance();e={type:"member",object:e,property:this.expect("IDENTIFIER").value,computed:!1,raw:void 0}}else if("LBRACKET"===t.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"!==t.type||"identifier"!==e.type)break;{const r=e.name;if(!s.has(r))throw new Error(`Unknown function '${r}' at position ${t.start}`);this.advance();const n=this.parseArguments();this.expect("RPAREN"),e={type:"call",callee:r,arguments:n,raw:void 0}}}}return e}parsePrimary(){const e=this.current();if("NUMBER"===e.type||"STRING"===e.type||"BOOLEAN"===e.type||"NULL"===e.type)return this.advance(),{type:"literal",value:e.value,start:e.start,end:e.end,raw:void 0};if("IDENTIFIER"===e.type)return this.advance(),{type:"identifier",name:e.value,start:e.start,end:e.end,raw:void 0};if("LBRACKET"===e.type)return this.parseArray();if("LPAREN"===e.type){this.advance();const e=this.parseExpression();return this.expect("RPAREN"),e}throw new Error(`Unexpected token '${e.value}' at position ${e.start}`)}parseArray(){const e=this.current().start;this.advance();const t=[];for(;"RBRACKET"!==this.current().type&&(t.push(this.parseExpression()),"COMMA"===this.current().type);)this.advance();const r=this.current().end;return this.expect("RBRACKET"),{type:"array",elements:t,start:e,end:r,raw:void 0}}parseArguments(){const e=[];if("RPAREN"!==this.current().type)for(e.push(this.parseExpression());"COMMA"===this.current().type;)this.advance(),e.push(this.parseExpression());return e}current(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}expect(e){const t=this.current();if(t.type!==e)throw new Error(`Expected '${e}' but got '${t.type}' at position ${t.start}`);return this.advance()}},I={len:e=>"string"==typeof e||Array.isArray(e)?e.length:0,trim:e=>String(e??"").trim(),upper:e=>String(e??"").toUpperCase(),lower:e=>String(e??"").toLowerCase(),substr:(e,t,r)=>{const s=String(e??""),n=Number(t)||0,o=void 0!==r?Number(r):void 0;return s.substring(n,void 0!==o?n+o:void 0)},concat:(...e)=>e.map(e=>String(e??"")).join(""),replace:(e,t,r)=>String(e??"").split(String(t)).join(String(r)),split:(e,t)=>String(e??"").split(String(t)),join:(e,t)=>Array.isArray(e)?e.join(void 0!==t?String(t):","):"",startsWith:(e,t)=>String(e??"").startsWith(String(t)),endsWith:(e,t)=>String(e??"").endsWith(String(t)),contains:(e,t)=>String(e??"").includes(String(t)),toNumber:e=>{const t=Number(e);return isNaN(t)?0:t},toString:e=>String(e??""),toInt:e=>Math.trunc(Number(e)||0),toFloat:e=>parseFloat(String(e))||0,round:(e,t)=>{const r=Number(e)||0,s=Number(t)||0,n=Math.pow(10,s);return Math.round(r*n)/n},floor:e=>Math.floor(Number(e)||0),ceil:e=>Math.ceil(Number(e)||0),abs:e=>Math.abs(Number(e)||0),min:(...e)=>{const t=e.map(e=>Number(e)).filter(e=>!isNaN(e));return t.length>0?Math.min(...t):0},max:(...e)=>{const t=e.map(e=>Number(e)).filter(e=>!isNaN(e));return t.length>0?Math.max(...t):0},sum:e=>Array.isArray(e)?e.reduce((e,t)=>e+(Number(t)||0),0):0,avg:e=>{if(!Array.isArray(e)||0===e.length)return 0;return e.reduce((e,t)=>e+(Number(t)||0),0)/e.length},random:()=>Math.random(),randomInt:(e,t)=>{const r=Math.ceil(Number(e)||0),s=Math.floor(Number(t)||100);return Math.floor(Math.random()*(s-r+1))+r},now:()=>Date.now(),today:()=>(new Date).toISOString().split("T")[0],dateFormat:(e,t)=>{const r=new Date(Number(e)||Date.now()),s=e=>e.toString().padStart(2,"0");return String(t||"YYYY-MM-DD").replace("YYYY",r.getFullYear().toString()).replace("MM",s(r.getMonth()+1)).replace("DD",s(r.getDate())).replace("HH",s(r.getHours())).replace("mm",s(r.getMinutes())).replace("ss",s(r.getSeconds()))},dateParse:e=>new Date(String(e)).getTime(),year:e=>new Date(Number(e)||Date.now()).getFullYear(),month:e=>new Date(Number(e)||Date.now()).getMonth()+1,day:e=>new Date(Number(e)||Date.now()).getDate(),addDays:(e,t)=>{const r=new Date(Number(e)||Date.now());return r.setDate(r.getDate()+(Number(t)||0)),r.getTime()},diffDays:(e,t)=>{const r=new Date(Number(e)||Date.now()),s=new Date(Number(t)||Date.now()),n=Math.abs(s.getTime()-r.getTime());return Math.floor(n/864e5)},isNull:e=>null==e,isUndefined:e=>void 0===e,isEmpty:e=>null==e||("string"==typeof e||Array.isArray(e)?0===e.length:"object"==typeof e&&0===Object.keys(e).length),isArray:e=>Array.isArray(e),isObject:e=>null!==e&&"object"==typeof e&&!Array.isArray(e),isString:e=>"string"==typeof e,isNumber:e=>"number"==typeof e&&!isNaN(e),isBoolean:e=>"boolean"==typeof e,typeOf:e=>null===e?"null":Array.isArray(e)?"array":typeof e,default:(e,t)=>e??t,coalesce:(...e)=>{for(const t of e)if(null!=t)return t;return null},ifElse:(e,t,r)=>e?t:r,first:e=>{if(Array.isArray(e))return e[0]},last:e=>{if(Array.isArray(e))return e[e.length-1]},at:(e,t)=>{if(Array.isArray(e))return e[Number(t)||0]},slice:(e,t,r)=>Array.isArray(e)?e.slice(Number(t)||0,void 0!==r?Number(r):void 0):[],includes:(e,t)=>!!Array.isArray(e)&&e.includes(t),indexOf:(e,t)=>Array.isArray(e)?e.indexOf(t):-1,reverse:e=>Array.isArray(e)?[...e].reverse():[],sort:e=>Array.isArray(e)?[...e].sort():[],unique:e=>Array.isArray(e)?[...new Set(e)]:[],flatten:e=>Array.isArray(e)?e.flat():[],count:e=>Array.isArray(e)?e.length:0,get:(e,t,r)=>{if(null==e)return r;const s=String(t).split(".");let n=e;for(const o of s){if(null==n)return r;n=n[o]}return n??r},keys:e=>"object"!=typeof e||null===e?[]:Object.keys(e),values:e=>"object"!=typeof e||null===e?[]:Object.values(e),entries:e=>"object"!=typeof e||null===e?[]:Object.entries(e),has:(e,t)=>"object"==typeof e&&null!==e&&String(t)in e,merge:(...e)=>{const t={};for(const r of e)"object"==typeof r&&null!==r&&Object.assign(t,r);return t},and:(...e)=>e.every(e=>Boolean(e)),or:(...e)=>e.some(e=>Boolean(e)),not:e=>!e,eq:(e,t)=>e===t,ne:(e,t)=>e!==t,gt:(e,t)=>Number(e)>Number(t),gte:(e,t)=>Number(e)>=Number(t),lt:(e,t)=>Number(e)<Number(t),lte:(e,t)=>Number(e)<=Number(t),between:(e,t,r)=>{const s=Number(e);return s>=Number(t)&&s<=Number(r)},formatNumber:(e,t)=>{const r=Number(e)||0,s=Number(t)??0;return r.toLocaleString(void 0,{minimumFractionDigits:s,maximumFractionDigits:s})},formatCurrency:(e,t)=>{const r=Number(e)||0,s=String(t||"CNY");return r.toLocaleString("zh-CN",{style:"currency",currency:s})},formatPercent:(e,t)=>{const r=Number(e)||0,s=Number(t)??0;return(100*r).toFixed(s)+"%"},jsonParse:e=>{try{return JSON.parse(String(e))}catch{return null}},jsonStringify:e=>JSON.stringify(e)},N=class{constructor(e={}){this.depth=0,this.startTime=0,this.options={maxDepth:100,timeout:1e3,debug:!1,...e}}evaluate(e,t){this.depth=0,this.startTime=Date.now();try{return{value:this.evaluateNode(e,t)}}catch(r){return{value:void 0,error:r instanceof Error?r:new Error(String(r))}}}evaluateNode(e,t){switch(this.checkLimits(),e.type){case"literal":return this.evaluateLiteral(e);case"identifier":return this.evaluateIdentifier(e,t);case"member":return this.evaluateMember(e,t);case"call":return this.evaluateCall(e,t);case"binary":return this.evaluateBinary(e,t);case"unary":return this.evaluateUnary(e,t);case"conditional":return this.evaluateConditional(e,t);case"array":return this.evaluateArray(e,t);default:throw new h("",`Unknown node type: ${e.type}`)}}evaluateLiteral(e){return e.value}evaluateIdentifier(e,t){const r=e.name;switch(r){case"state":return t.state;case"query":return t.query;case"context":return t.context;case"event":return t.event;case"item":return t.item;case"index":return t.index;default:throw new h("",`Unknown variable '${r}'`,void 0!==e.start&&void 0!==e.end?{start:e.start,end:e.end}:void 0)}}evaluateMember(e,t){const r=this.evaluateNode(e.object,t);if(null==r)return;let s;if(e.computed){s=this.evaluateNode(e.property,t)}else s=e.property;return"object"==typeof r&&null!==r?r[s]:void 0}evaluateCall(e,t){const r=I[e.callee];if(!r)throw new h("",`Unknown function '${e.callee}'`);return r(...e.arguments.map(e=>this.evaluateNode(e,t)))}evaluateBinary(e,t){const r=e.operator;if("&&"===r){const r=this.evaluateNode(e.left,t);return r?this.evaluateNode(e.right,t):r}if("||"===r){const r=this.evaluateNode(e.left,t);return r||this.evaluateNode(e.right,t)}if("??"===r){const r=this.evaluateNode(e.left,t);return null!=r?r:this.evaluateNode(e.right,t)}const s=this.evaluateNode(e.left,t),n=this.evaluateNode(e.right,t);switch(r){case"+":return"string"==typeof s||"string"==typeof n?String(s)+String(n):s+n;case"-":return s-n;case"*":return s*n;case"/":return s/n;case"%":return s%n;case"==":return s===n;case"!=":return s!==n;case"<":return s<n;case">":return s>n;case"<=":return s<=n;case">=":return s>=n;default:throw new h("",`Unknown operator '${r}'`)}}evaluateUnary(e,t){const r=this.evaluateNode(e.argument,t);switch(e.operator){case"!":return!r;case"-":return-r;default:throw new h("",`Unknown unary operator '${e.operator}'`)}}evaluateConditional(e,t){return this.evaluateNode(e.test,t)?this.evaluateNode(e.consequent,t):this.evaluateNode(e.alternate,t)}evaluateArray(e,t){return e.elements.map(e=>this.evaluateNode(e,t))}checkLimits(){if(this.depth++,this.depth>(this.options.maxDepth??100))throw new h("","Maximum recursion depth exceeded");if(Date.now()-this.startTime>(this.options.timeout??1e3))throw new h("","Expression evaluation timeout")}},T=class{constructor(e={}){this.astCache=new Map,this.options={cacheAST:!0,maxCacheSize:1e3,...e},this.evaluator=new N(e)}evaluate(e,t){try{const r=this.parse(e);return this.evaluator.evaluate(r,t)}catch(r){return{value:void 0,error:r instanceof Error?r:new Error(String(r))}}}evaluateWithFallback(e,t,r){const s=this.evaluate(e,t);return s.error?(this.log("warn",`Expression evaluation failed: ${s.error.message}`,e),r):s.value}evaluateTemplate(e,t){return e.replace(/\$\{([^}]+)\}/g,(e,r)=>{const s=this.evaluate(r.trim(),t);return s.error?(this.log("warn",`Template expression failed: ${s.error.message}`,r),""):String(s.value??"")})}parse(e){if(this.options.cacheAST){const t=this.astCache.get(e);if(t)return t}try{const t=new E(e).tokenize(),r=new b(t).parse();if(this.options.cacheAST){if(this.astCache.size>=(this.options.maxCacheSize??1e3)){Array.from(this.astCache.keys()).slice(0,Math.floor(this.astCache.size/2)).forEach(e=>this.astCache.delete(e))}this.astCache.set(e,r)}return r}catch(t){throw new h(e,t instanceof Error?t.message:"Parse error")}}validate(e){const t=[],r=[],s=[],n=[];try{const t=this.parse(e);return this.collectReferences(t,s,n),{valid:!0,errors:[],warnings:r,referencedPaths:s,calledFunctions:n}}catch(o){return t.push({type:"SYNTAX_ERROR",message:o instanceof Error?o.message:"Parse error"}),{valid:!1,errors:t,warnings:r,referencedPaths:s,calledFunctions:n}}}clearCache(){this.astCache.clear()}collectReferences(e,t,r){switch(e.type){case"identifier":t.push(e.name);break;case"member":{const r=this.buildMemberPath(e);r&&t.push(r);break}case"call":r.push(e.callee),e.arguments.forEach(e=>this.collectReferences(e,t,r));break;case"binary":this.collectReferences(e.left,t,r),this.collectReferences(e.right,t,r);break;case"unary":this.collectReferences(e.argument,t,r);break;case"conditional":this.collectReferences(e.test,t,r),this.collectReferences(e.consequent,t,r),this.collectReferences(e.alternate,t,r);break;case"array":e.elements.forEach(e=>this.collectReferences(e,t,r))}}buildMemberPath(e){if("identifier"===e.type)return e.name;if("member"===e.type&&!e.computed){const t=this.buildMemberPath(e.object);if(t)return`${t}.${e.property}`}return null}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},w=class{constructor(e){this.storage={get:(e,t)=>{const r=this.getStorageKey(e,null==t?void 0:t.namespace),s=localStorage.getItem(r);if(s)try{const e=JSON.parse(s);return e.expires&&Date.now()>e.expires?void localStorage.removeItem(r):e.value}catch{return}},set:(e,t,r)=>{const s=this.getStorageKey(e,null==r?void 0:r.namespace),n={value:t,expires:(null==r?void 0:r.ttl)?Date.now()+1e3*r.ttl:void 0};localStorage.setItem(s,JSON.stringify(n))},remove:(e,t)=>{const r=this.getStorageKey(e,null==t?void 0:t.namespace);localStorage.removeItem(r)}},this.options=e,this.storageNamespace=`djvlc:${e.context.pageUid}`}async requestData(e,t){this.log("debug",`Requesting data: ${e}`,t);const r=performance.now(),s=this.options.context;try{const n=await fetch(`${this.options.apiBaseUrl}/data/query`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({queryVersionId:e,params:t||{},context:{pageVersionId:s.pageVersionId,uid:s.userId}})}),o=await n.json(),a=performance.now()-r;return this.log("debug",`Data query completed in ${a.toFixed(2)}ms`),o.success&&o.data&&this.options.stateManager.setQuery(e,o.data),o}catch(n){return this.log("error",`Data query failed: ${e}`,n),{success:!1,message:n instanceof Error?n.message:"Query failed"}}}async executeAction(e,t){this.log("debug",`Executing action: ${e}`,t);const r=performance.now(),s=this.options.context;try{const n=await fetch(`${this.options.apiBaseUrl}/actions/execute`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({actionType:e,params:t||{},context:{pageVersionId:s.pageVersionId,uid:s.userId,deviceId:s.deviceId,channel:s.channel},idempotencyKey:this.generateIdempotencyKey(e,t)})}),o=await n.json(),a=performance.now()-r;return this.log("debug",`Action completed in ${a.toFixed(2)}ms`),o}catch(n){return this.log("error",`Action failed: ${e}`,n),{success:!1,message:n instanceof Error?n.message:"Action failed"}}}navigate(e){this.log("debug","Navigate:",e),this.track({eventName:"navigate",params:{url:e.url,newTab:e.newTab}});let t=e.url;if(e.params){const r=new URLSearchParams(e.params);t+=(t.includes("?")?"&":"?")+r.toString()}e.newTab?window.open(t,"_blank"):e.replace?window.location.replace(t):window.location.href=t}goBack(){this.log("debug","Navigate back"),window.history.back()}refresh(){this.log("debug","Refresh page"),window.location.reload()}async openDialog(e){switch(this.log("debug","Open dialog:",e),e.type){case"alert":return window.alert(e.content||e.title),!0;case"confirm":return window.confirm(e.content||e.title);case"prompt":return window.prompt(e.content||e.title)||"";case"custom":return this.log("warn","Custom dialog not implemented"),!1;default:return!1}}closeDialog(){this.log("debug","Close dialog")}showToast(e){this.log("debug","Show toast:",e);const t=document.createElement("div");t.className=`djvlc-toast djvlc-toast-${e.type||"info"} djvlc-toast-${e.position||"top"}`,t.textContent=e.message,Object.assign(t.style,{position:"fixed",left:"50%",transform:"translateX(-50%)",padding:"12px 24px",borderRadius:"8px",color:"#fff",fontSize:"14px",zIndex:"10000",animation:"djvlc-toast-fade-in 0.3s ease"});t.style.backgroundColor={success:"#52c41a",error:"#ff4d4f",warning:"#faad14",info:"#1890ff"}[e.type||"info"];Object.assign(t.style,{top:{top:"20px"},center:{top:"50%",transform:"translate(-50%, -50%)"},bottom:{bottom:"20px"}}[e.position||"top"]),document.body.appendChild(t),setTimeout(()=>{t.style.animation="djvlc-toast-fade-out 0.3s ease",setTimeout(()=>t.remove(),300)},e.duration||3e3)}track(e){this.log("debug","Track event:",e);const t=this.options.context;fetch(`${this.options.apiBaseUrl}/track`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({eventName:e.eventName,params:e.params,timestamp:e.timestamp||Date.now(),context:{pageVersionId:t.pageVersionId,runtimeVersion:t.runtimeVersion,userId:t.userId,deviceId:t.deviceId,channel:t.channel}}),keepalive:!0}).catch(e=>{this.log("warn","Track failed:",e)})}async copyToClipboard(e){try{return await navigator.clipboard.writeText(e),{success:!0,content:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Copy failed"}}}async readFromClipboard(){try{return{success:!0,content:await navigator.clipboard.readText()}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Read failed"}}}getState(e){return this.options.stateManager.getVariable(e)}setState(e,t){this.options.stateManager.setVariable(e,t)}getVariable(e){return this.options.stateManager.getVariable(e)}postMessage(e,t){this.log("debug",`Post message to ${e}:`,t);const r=new CustomEvent(`djvlc:message:${e}`,{detail:{message:t,from:this.options.context.pageUid}});document.dispatchEvent(r)}broadcast(e,t){this.log("debug",`Broadcast to ${e}:`,t);const r=new CustomEvent(`djvlc:broadcast:${e}`,{detail:{message:t,from:this.options.context.pageUid}});document.dispatchEvent(r)}getContext(){return{...this.options.context}}buildHeaders(){const e={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(e.Authorization=`Bearer ${this.options.authToken}`),e}getStorageKey(e,t){return`${t||this.storageNamespace}:${e}`}generateIdempotencyKey(e,t){const r=Date.now(),s=JSON.stringify(t||{});return`${e}:${r}:${this.simpleHash(s)}`}simpleHash(e){let t=0;for(let r=0;r<e.length;r++){t=(t<<5)-t+e.charCodeAt(r),t&=t}return Math.abs(t).toString(36)}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},A=class{constructor(e={}){this.blockedComponentsMap=new Map,this.blockedActionsSet=new Set,this.options={enableSRI:!0,cdnDomains:[],apiDomains:[],blockedComponents:[],blockedActions:[],...e},this.updateBlockedList(e.blockedComponents||[],e.blockedActions||[])}updateBlockedList(e,t){this.blockedComponentsMap.clear(),e.forEach(e=>{this.blockedComponentsMap.set(`${e.name}@${e.version}`,e)}),this.blockedActionsSet=new Set(t)}isComponentBlocked(e,t){return this.blockedComponentsMap.has(`${e}@${t}`)}getBlockedInfo(e,t){return this.blockedComponentsMap.get(`${e}@${t}`)}isActionBlocked(e){return this.blockedActionsSet.has(e)}async validateComponent(e,t,r,s){if(!this.options.enableSRI)return;const[n,o]=s.split("-");if(!n||!o)throw new p(e,t,s,"Invalid format");const a=await this.computeHash(r,n);if(a!==o)throw new p(e,t,o,a)}isAllowedUrl(e,t){const r="cdn"===t?this.options.cdnDomains:this.options.apiDomains;if(!r||0===r.length)return!0;try{const t=new URL(e);return r.some(e=>{if(e.startsWith("*.")){const r=e.slice(2);return t.hostname.endsWith(r)}return t.hostname===e})}catch{return!1}}generateCSPPolicy(){const e=this.options.cdnDomains||[],t=this.options.apiDomains||[],r=["'self'",...e].join(" "),s=["'self'",...t].join(" ");return["default-src 'self'",`script-src ${r}`,`style-src ${["'self'","'unsafe-inline'",...e].join(" ")}`,`img-src ${["'self'","data:","blob:",...e].join(" ")}`,`connect-src ${s}`,`font-src 'self' data: ${e.join(" ")}`,"frame-ancestors 'self'","base-uri 'self'","form-action 'self'"].join("; ")}applyCSP(){const e=document.createElement("meta");e.httpEquiv="Content-Security-Policy",e.content=this.generateCSPPolicy(),document.head.appendChild(e)}assertNotBlocked(e,t){const r=this.getBlockedInfo(e,t);if(r)throw new d(e,t,r.reason)}async computeHash(e,t){const r=(new TextEncoder).encode(e),s=await crypto.subtle.digest(t.toUpperCase(),r),n=Array.from(new Uint8Array(s));return btoa(String.fromCharCode(...n))}_log(e,t){this.options.logger&&this.options.logger[e](t)}get log(){return this._log.bind(this)}},S=class{constructor(e){this.spans=new Map,this.metrics=[],this.errors=[],this.options={enabled:!0,sampleRate:1,...e},this.traceId=this.generateId(),this.shouldSample=Math.random()<(this.options.sampleRate??1)}getTraceId(){return this.traceId}getTraceparent(){return`00-${this.traceId}-${this.generateId().slice(0,16)}-01`}startSpan(e,t,r){const s={spanId:this.generateId().slice(0,16),traceId:this.traceId,parentSpanId:t,name:e,startTime:performance.now(),attributes:r};return this.spans.set(s.spanId,s),this.log("debug",`Span started: ${e} (${s.spanId})`),s}endSpan(e,t="ok"){const r=this.spans.get(e);r&&(r.endTime=performance.now(),r.status=t,this.log("debug",`Span ended: ${r.name} (${e}) - ${r.endTime-r.startTime}ms`))}recordMetric(e,t,r,s){const n={type:e,name:t,duration:r,startTime:performance.now()-r,extra:s};this.metrics.push(n),this.log("debug",`Metric: ${e} - ${t} - ${r}ms`),this.options.onMetric&&this.options.onMetric(n)}recordError(e,t){const r={type:"LOAD_ERROR",message:e.message,stack:e instanceof Error?e.stack:void 0,timestamp:Date.now(),traceId:this.traceId,...t};this.errors.push(r),this.log("error",`Error recorded: ${e.message}`),this.shouldSample&&this.options.enabled&&this.reportError(r)}recordPageLoad(e,t){this.recordMetric("page_resolve","page_load",e,{pageVersionId:this.options.pageVersionId,...t})}recordComponentLoad(e,t,r,s){this.recordMetric("component_load",`${e}@${t}`,r,{success:s})}recordFirstRender(e){this.recordMetric("first_render","first_render",e,{pageVersionId:this.options.pageVersionId})}recordActionExecute(e,t,r){this.recordMetric("action_execute",e,t,{success:r})}recordQueryExecute(e,t,r,s){this.recordMetric("query_execute",e,t,{success:r,fromCache:s})}getMetrics(){return[...this.metrics]}getSpans(){return Array.from(this.spans.values())}clear(){this.spans.clear(),this.metrics=[],this.errors=[]}async flush(){if(!this.shouldSample||!this.options.enabled||!this.options.endpoint)return;const e={traceId:this.traceId,pageVersionId:this.options.pageVersionId,appId:this.options.appId,spans:this.getSpans(),metrics:this.metrics,errors:this.errors,timestamp:Date.now()};try{await fetch(this.options.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:!0})}catch(t){this.log("warn","Failed to flush telemetry:",t)}}reportError(e){this.options.endpoint&&fetch(`${this.options.endpoint}/errors`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:!0}).catch(()=>{})}generateId(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},O=class{constructor(e){this.container=null,this.renderedElements=new Map,this.expressionContext={state:{},query:{},context:{}},this.options=e}init(){this.log("debug","Renderer initialized")}render(e,t){this.container=t,this.log("debug","Rendering page",e.page.id),t.innerHTML="",this.applyPageStyles(e.page.canvas);const r=document.createDocumentFragment();for(const s of e.components){const e=this.renderComponent(s);e&&r.appendChild(e)}t.appendChild(r),this.log("info",`Rendered ${e.components.length} components`)}updateComponent(e,t){const r=this.renderedElements.get(e);r?this.applyProps(r,t):this.log("warn",`Component not found: ${e}`)}updateContext(e){this.expressionContext={...this.expressionContext,...e}}destroy(){this.renderedElements.forEach(e=>{e.remove()}),this.renderedElements.clear(),this.container&&(this.container.innerHTML=""),this.log("debug","Renderer destroyed")}renderComponent(e){const{id:t,type:r,props:s,style:n,children:o,visible:a}=e;if(!1===a)return null;try{const e=this.options.components.get(r);let a;e&&customElements.get(r)?a=document.createElement(r):(a=document.createElement("div"),a.className=`djvlc-component djvlc-${r}`,e||(this.log("warn",`Component not loaded: ${r}`),a.textContent=`[Component: ${r}]`)),a.setAttribute("data-component-id",t),a.setAttribute("data-component-type",r);const i=this.resolveProps(s);if(this.applyProps(a,i),n&&this.applyStyles(a,n),this.options.injectHostApi(a,t),o&&o.length>0)for(const t of o){const e=this.renderComponent(t);e&&a.appendChild(e)}return this.renderedElements.set(t,a),a}catch(i){if(this.log("error",`Failed to render component: ${t}`,i),this.options.onRenderError)return this.options.onRenderError(t,i);const e=document.createElement("div");return e.className="djvlc-error-boundary",e.textContent=`Error rendering component: ${r}`,e}}resolveProps(e){const t={};for(const[r,s]of Object.entries(e))if(n(s)){const e=this.options.expressionEngine.evaluateWithFallback(s.expression,this.expressionContext,s.fallback);t[r]=e}else"object"!=typeof s||null===s||Array.isArray(s)?t[r]=s:t[r]=this.resolveProps(s);return t}applyProps(e,t){for(const[r,s]of Object.entries(t))null!=s&&(e.tagName.includes("-")?e[r]=s:"boolean"==typeof s?s?e.setAttribute(r,""):e.removeAttribute(r):"object"==typeof s?e.setAttribute(r,JSON.stringify(s)):e.setAttribute(r,String(s)))}applyStyles(e,t){for(const[r,s]of Object.entries(t)){if(null==s)continue;let t;if("number"==typeof s){t=["zIndex","opacity","flex","fontWeight"].includes(r)?String(s):`${s}px`}else t=String(s);const n=r.replace(/([A-Z])/g,"-$1").toLowerCase();e.style.setProperty(n,t)}}applyPageStyles(e){this.container&&(this.container.style.width=`${e.width}px`,e.height&&(this.container.style.minHeight=`${e.height}px`),e.background&&(this.container.style.background=e.background),this.container.classList.add("djvlc-page",`djvlc-canvas-${e.type}`))}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}};function C(e){return new R(e)}var R=class{constructor(e){this.container=null,this.options={channel:"prod",debug:!1,enableSRI:!0,...e},this.logger=this.createLogger(),this.stateManager=new y,this.eventBus=new f({debug:e.debug,logger:this.logger}),this.expressionEngine=new T({debug:e.debug,logger:this.logger}),this.pageLoader=new u({apiBaseUrl:e.apiBaseUrl,channel:e.channel,authToken:e.authToken,previewToken:e.previewToken,headers:e.headers,logger:this.logger}),this.componentLoader=new m({cdnBaseUrl:e.cdnBaseUrl,enableSRI:e.enableSRI,logger:this.logger}),this.assetLoader=new g({cdnHosts:[new URL(e.cdnBaseUrl).host],apiHosts:[new URL(e.apiBaseUrl).host]}),this.securityManager=new A({enableSRI:e.enableSRI,cdnDomains:[new URL(e.cdnBaseUrl).host],apiDomains:[new URL(e.apiBaseUrl).host],logger:this.logger}),this.log("info","Runtime created")}async init(){this.log("info","Initializing runtime");const e=performance.now();try{this.container=this.resolveContainer(),this.assetLoader.preconnectAll(),this.pageLoader.preconnect(),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(e,t,r){if("message"===e&&this.shadowRoot){const e=this.shadowRoot.querySelector(".message");e&&(e.textContent=r)}if("component-name"===e&&this.shadowRoot){const e=this.shadowRoot.querySelector(".title");e&&(e.textContent=`组件 ${r} 加载失败`)}}}),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 "}}),this.stateManager.setPhase("resolving");const t=performance.now()-e;this.log("info",`Runtime initialized in ${t.toFixed(2)}ms`)}catch(t){throw this.handleError(t),t}}async load(){var e;this.log("info","Loading page:",this.options.pageUid);const t=performance.now();try{this.stateManager.setPhase("resolving");const r=await this.pageLoader.resolve(this.options.pageUid,{uid:this.options.userId,deviceId:this.options.deviceId});this.stateManager.setPage(r),this.telemetryManager=new S({pageVersionId:r.pageVersionId,debug:this.options.debug,logger:this.logger,onMetric:this.options.onMetric}),r.runtimeConfig&&(this.securityManager.updateBlockedList(r.runtimeConfig.blockedComponents||[],r.runtimeConfig.killSwitches||[]),this.componentLoader.updateBlockedList((null==(e=r.runtimeConfig.blockedComponents)?void 0:e.map(e=>`${e.name}@${e.version}`))||[])),this.stateManager.setPhase("loading"),this.componentLoader.preload(r.manifest.components);(await this.componentLoader.loadAll(r.manifest)).forEach((e,t)=>{this.stateManager.setComponentStatus(t,e),this.telemetryManager.recordComponentLoad(e.name,e.version,e.loadTime||0,"loaded"===e.status)}),this.initHostApi(r),this.initRenderer();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:r,loadTime:s}),r}catch(r){throw this.stateManager.setPhase("error"),this.handleError(r),r}}async render(){const e=this.stateManager.getState();if(!e.page||!this.container)throw new c("Page not loaded");this.log("info","Rendering page");const t=performance.now();try{this.stateManager.setPhase("rendering"),this.renderer.updateContext({state:e.variables,query:e.queries,context:{userId:this.options.userId,deviceId:this.options.deviceId,channel:this.options.channel,pageVersionId:e.page.pageVersionId}}),this.renderer.render(e.page.pageJson,this.container),this.stateManager.setPhase("ready");const r=performance.now()-t;this.telemetryManager.recordFirstRender(r),this.log("info",`Page rendered in ${r.toFixed(2)}ms`)}catch(r){throw this.stateManager.setPhase("error"),this.handleError(r),r}}getHostApi(){return this.hostApi}getState(){return this.stateManager.getState()}onStateChange(e){return this.stateManager.subscribe(e)}on(e,t){return this.eventBus.on(e,t)}updateComponent(e,t){this.renderer.updateComponent(e,t)}setVariable(e,t){this.stateManager.setVariable(e,t);const r=this.stateManager.getState();r.page&&this.container&&this.renderer.updateContext({state:r.variables})}async refreshData(e){const t=await this.hostApi.requestData(e);if(t.success){this.stateManager.setQuery(e,t.data);const r=this.stateManager.getState();this.renderer.updateContext({query:r.queries})}}destroy(){var e,t;this.log("info","Destroying runtime"),null==(e=this.telemetryManager)||e.flush(),null==(t=this.renderer)||t.destroy(),this.eventBus.clear(),this.stateManager.setDestroyed(),this.container&&(this.container.innerHTML=""),this.log("info","Runtime destroyed")}resolveContainer(){const{container:e}=this.options;if("string"==typeof e){const t=document.querySelector(e);if(!t)throw new Error(`Container not found: ${e}`);return t}return e}initHostApi(e){const t={pageUid:e.pageUid,pageVersionId:e.pageVersionId,runtimeVersion:"0.1.0",userId:this.options.userId,deviceId:this.options.deviceId,channel:this.options.channel,isEditMode:!1,isPreviewMode:e.isPreview||!1};this.hostApi=new w({apiBaseUrl:this.options.apiBaseUrl,authToken:this.options.authToken,headers:this.options.headers,stateManager:this.stateManager,eventBus:this.eventBus,expressionEngine:this.expressionEngine,context:t,debug:this.options.debug,logger:this.logger})}initRenderer(){const e=new Map;this.stateManager.getState().components.forEach((t,r)=>{if("loaded"===t.status&&t.component){const[s,n]=r.split("@");e.set(s,{name:s,version:n,Component:t.component,loadTime:t.loadTime||0})}}),this.renderer=new O({expressionEngine:this.expressionEngine,components:e,injectHostApi:(e,t)=>{e.hostApi=this.hostApi,e.componentId=t},debug:this.options.debug,logger:this.logger,onRenderError:(e,t)=>(this.log("error",`Render error in ${e}:`,t),this.emitEvent("component:error",{componentId:e,error:t.message}),function(e,t){const r=document.createElement("djvlc-error-boundary");return t&&r.setAttribute("message",t),r}(0,t.message))}),this.renderer.init()}handleError(e){var t;const r=e instanceof i?e:{type:"LOAD_ERROR",message:e.message,timestamp:Date.now()};this.stateManager.setError(r),null==(t=this.telemetryManager)||t.recordError(e),this.emitEvent("page:error",{error:e.message}),this.options.onError&&this.options.onError(r)}emitEvent(e,t){var r;const s=f.createEvent(e,t,null==(r=this.telemetryManager)?void 0:r.getTraceId());this.eventBus.emit(s),this.options.onEvent&&this.options.onEvent(s)}createLogger(){return{debug:(...e)=>{this.options.debug},info:(...e)=>{},warn:(...e)=>{},error:(...e)=>{}}}log(e,t,...r){this.logger[e](t,...r)}};const _="0.1.0";async function M(e,t){var r,s;const n=C({container:e,pageUid:t.pageUid,apiBaseUrl:t.apiBaseUrl,cdnBaseUrl:t.cdnBaseUrl,channel:t.channel,userId:t.userId,deviceId:t.deviceId,authToken:t.authToken,previewToken:t.previewToken,debug:t.debug,enableSRI:t.enableSRI,headers:t.headers,onError:t.onError?e=>{var r;return null==(r=t.onError)?void 0:r.call(t,new Error(e.message))}:void 0,onMetric:t.onMetric});try{await n.init(),await n.load(),await n.render(),null==(r=t.onLoad)||r.call(t,n.getState())}catch(o){const e=o instanceof Error?o:new Error(String(o));throw null==(s=t.onError)||s.call(t,e),e}return{runtime:n,destroy:()=>n.destroy()}}function D(e){e.forEach(e=>{const t=document.createElement("link");t.rel="preconnect",t.href=e.startsWith("http")?e:`https://${e}`,t.crossOrigin="anonymous",document.head.appendChild(t)})}function x(e,t=_){[`${e}/runtime/${t}/runtime.esm.js`,`${e}/runtime/${t}/runtime.css`].forEach(e=>{const t=document.createElement("link");t.rel="preload",t.href=e,t.as=e.endsWith(".js")?"script":"style",e.endsWith(".js")&&(t.crossOrigin="anonymous"),document.head.appendChild(t)})}function k(){const e="djv_device_id";let t=localStorage.getItem(e);if(!t){t=`${Date.now()}-${Math.random().toString(36).substring(2,11)}`;try{localStorage.setItem(e,t)}catch{}}return t}function L(){return e=32,Array.from({length:e},()=>Math.floor(16*Math.random()).toString(16)).join("");var e}function U(){return e=16,Array.from({length:e},()=>Math.floor(16*Math.random()).toString(16)).join("");var e}function P(){return`00-${L()}-${U()}-01`}const $={mount:M,preconnect:D,preloadAssets:x,getDeviceId:k,generateTraceId:L,generateSpanId:U,generateTraceparent:P,createRuntime:C,RUNTIME_VERSION:_};return e.RUNTIME_VERSION=_,e.createRuntime=C,e.default=$,e.generateSpanId=U,e.generateTraceId=L,e.generateTraceparent=P,e.getDeviceId=k,e.mount=M,e.preconnect=D,e.preloadAssets=x,Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),e}({});
2
- //# sourceMappingURL=runtime.iife.js.map
1
+ var DJVRuntime=function(e){"use strict";var t=(e=>(e[e.UNKNOWN=1e3]="UNKNOWN",e[e.INVALID_REQUEST=1001]="INVALID_REQUEST",e[e.UNAUTHORIZED=1002]="UNAUTHORIZED",e[e.FORBIDDEN=1003]="FORBIDDEN",e[e.NOT_FOUND=1004]="NOT_FOUND",e[e.RATE_LIMITED=1005]="RATE_LIMITED",e[e.VALIDATION_ERROR=1006]="VALIDATION_ERROR",e[e.INTERNAL_ERROR=1007]="INTERNAL_ERROR",e[e.SERVICE_UNAVAILABLE=1008]="SERVICE_UNAVAILABLE",e[e.TIMEOUT=1009]="TIMEOUT",e[e.ACTION_NOT_FOUND=2001]="ACTION_NOT_FOUND",e[e.ACTION_INVALID_PARAMS=2002]="ACTION_INVALID_PARAMS",e[e.ACTION_EXECUTION_FAILED=2003]="ACTION_EXECUTION_FAILED",e[e.ACTION_IDEMPOTENCY_CONFLICT=2004]="ACTION_IDEMPOTENCY_CONFLICT",e[e.ACTION_BLOCKED=2005]="ACTION_BLOCKED",e[e.ACTION_RISK_REJECTED=2006]="ACTION_RISK_REJECTED",e[e.ACTION_EXPIRED=2007]="ACTION_EXPIRED",e[e.ACTION_QUOTA_EXCEEDED=2008]="ACTION_QUOTA_EXCEEDED",e[e.QUERY_NOT_FOUND=3001]="QUERY_NOT_FOUND",e[e.QUERY_INVALID_PARAMS=3002]="QUERY_INVALID_PARAMS",e[e.QUERY_EXECUTION_FAILED=3003]="QUERY_EXECUTION_FAILED",e[e.QUERY_FIELD_NOT_ALLOWED=3004]="QUERY_FIELD_NOT_ALLOWED",e[e.QUERY_TIMEOUT=3005]="QUERY_TIMEOUT",e[e.QUERY_DISABLED=3006]="QUERY_DISABLED",e[e.COMPONENT_NOT_FOUND=4001]="COMPONENT_NOT_FOUND",e[e.COMPONENT_VERSION_NOT_FOUND=4002]="COMPONENT_VERSION_NOT_FOUND",e[e.COMPONENT_BLOCKED=4003]="COMPONENT_BLOCKED",e[e.COMPONENT_INTEGRITY_MISMATCH=4004]="COMPONENT_INTEGRITY_MISMATCH",e[e.COMPONENT_INCOMPATIBLE=4005]="COMPONENT_INCOMPATIBLE",e[e.COMPONENT_LOAD_FAILED=4006]="COMPONENT_LOAD_FAILED",e[e.COMPONENT_RENDER_ERROR=4007]="COMPONENT_RENDER_ERROR",e[e.PAGE_NOT_FOUND=5001]="PAGE_NOT_FOUND",e[e.PAGE_VERSION_NOT_FOUND=5002]="PAGE_VERSION_NOT_FOUND",e[e.PAGE_SCHEMA_INVALID=5003]="PAGE_SCHEMA_INVALID",e[e.PAGE_MANIFEST_INVALID=5004]="PAGE_MANIFEST_INVALID",e[e.PAGE_PUBLISH_FAILED=5005]="PAGE_PUBLISH_FAILED",e[e.PAGE_ROLLBACK_FAILED=5006]="PAGE_ROLLBACK_FAILED",e[e.ACTIVITY_NOT_FOUND=6001]="ACTIVITY_NOT_FOUND",e[e.ACTIVITY_NOT_STARTED=6002]="ACTIVITY_NOT_STARTED",e[e.ACTIVITY_ENDED=6003]="ACTIVITY_ENDED",e[e.ACTIVITY_ALREADY_CLAIMED=6004]="ACTIVITY_ALREADY_CLAIMED",e[e.ACTIVITY_ALREADY_SIGNED=6005]="ACTIVITY_ALREADY_SIGNED",e[e.ACTIVITY_LIMIT_EXCEEDED=6006]="ACTIVITY_LIMIT_EXCEEDED",e[e.ACTIVITY_DISABLED=6007]="ACTIVITY_DISABLED",e[e.EXPRESSION_SYNTAX_ERROR=7001]="EXPRESSION_SYNTAX_ERROR",e[e.EXPRESSION_UNKNOWN_FUNCTION=7002]="EXPRESSION_UNKNOWN_FUNCTION",e[e.EXPRESSION_INVALID_ARGUMENT=7003]="EXPRESSION_INVALID_ARGUMENT",e[e.EXPRESSION_UNKNOWN_VARIABLE=7004]="EXPRESSION_UNKNOWN_VARIABLE",e[e.EXPRESSION_TYPE_MISMATCH=7005]="EXPRESSION_TYPE_MISMATCH",e[e.EXPRESSION_ACCESS_DENIED=7006]="EXPRESSION_ACCESS_DENIED",e[e.SCHEMA_VERSION_MISMATCH=8001]="SCHEMA_VERSION_MISMATCH",e[e.MIGRATION_FAILED=8002]="MIGRATION_FAILED",e[e.MIGRATION_NOT_FOUND=8003]="MIGRATION_NOT_FOUND",e[e.VERSION_INCOMPATIBLE=8004]="VERSION_INCOMPATIBLE",e))(t||{}),r={1e3:"未知错误",1001:"请求参数无效",1002:"未授权访问",1003:"禁止访问",1004:"资源不存在",1005:"请求频率超限",1006:"数据校验失败",1007:"服务内部错误",1008:"服务暂不可用",1009:"请求超时",2001:"动作不存在",2002:"动作参数无效",2003:"动作执行失败",2004:"重复请求",2005:"动作已被禁用",2006:"风控拒绝",2007:"动作已过期",2008:"配额已用尽",3001:"查询不存在",3002:"查询参数无效",3003:"查询执行失败",3004:"字段访问被拒绝",3005:"查询超时",3006:"查询已禁用",4001:"组件不存在",4002:"组件版本不存在",4003:"组件已被禁用",4004:"组件完整性校验失败",4005:"组件版本不兼容",4006:"组件加载失败",4007:"组件渲染错误",5001:"页面不存在",5002:"页面版本不存在",5003:"页面 Schema 无效",5004:"页面 Manifest 无效",5005:"页面发布失败",5006:"页面回滚失败",6001:"活动不存在",6002:"活动未开始",6003:"活动已结束",6004:"已领取过",6005:"今日已签到",6006:"超出领取限制",6007:"活动已禁用",7001:"表达式语法错误",7002:"未知函数",7003:"无效参数",7004:"未知变量",7005:"类型不匹配",7006:"访问被拒绝",8001:"Schema 版本不匹配",8002:"迁移失败",8003:"迁移脚本不存在",8004:"版本不兼容"},s=new Set([{name:"len",description:"获取字符串或数组长度",params:[{name:"value",type:"any",required:!0}],returnType:"number",examples:['len("hello")',"len([1,2,3])"]},{name:"trim",description:"去除字符串首尾空格",params:[{name:"str",type:"string",required:!0}],returnType:"string",examples:['trim(" hello ")']},{name:"upper",description:"转为大写",params:[{name:"str",type:"string",required:!0}],returnType:"string",examples:['upper("hello")']},{name:"lower",description:"转为小写",params:[{name:"str",type:"string",required:!0}],returnType:"string",examples:['lower("HELLO")']},{name:"substr",description:"截取子字符串",params:[{name:"str",type:"string",required:!0},{name:"start",type:"number",required:!0},{name:"length",type:"number",required:!1}],returnType:"string",examples:['substr("hello", 0, 2)']},{name:"concat",description:"连接字符串",params:[{name:"values",type:"any",required:!0,description:"可变参数"}],returnType:"string",examples:['concat("a", "b", "c")']},{name:"replace",description:"替换字符串",params:[{name:"str",type:"string",required:!0},{name:"search",type:"string",required:!0},{name:"replacement",type:"string",required:!0}],returnType:"string",examples:['replace("hello", "l", "x")']},{name:"split",description:"分割字符串",params:[{name:"str",type:"string",required:!0},{name:"separator",type:"string",required:!0}],returnType:"array",examples:['split("a,b,c", ",")']},{name:"join",description:"连接数组为字符串",params:[{name:"arr",type:"array",required:!0},{name:"separator",type:"string",required:!1,defaultValue:","}],returnType:"string",examples:['join(["a","b","c"], "-")']},{name:"toNumber",description:"转为数字",params:[{name:"value",type:"any",required:!0}],returnType:"number",examples:['toNumber("123")']},{name:"toString",description:"转为字符串",params:[{name:"value",type:"any",required:!0}],returnType:"string",examples:["toString(123)"]},{name:"round",description:"四舍五入",params:[{name:"value",type:"number",required:!0},{name:"decimals",type:"number",required:!1,defaultValue:0}],returnType:"number",examples:["round(3.14159, 2)"]},{name:"floor",description:"向下取整",params:[{name:"value",type:"number",required:!0}],returnType:"number",examples:["floor(3.7)"]},{name:"ceil",description:"向上取整",params:[{name:"value",type:"number",required:!0}],returnType:"number",examples:["ceil(3.2)"]},{name:"abs",description:"绝对值",params:[{name:"value",type:"number",required:!0}],returnType:"number",examples:["abs(-5)"]},{name:"min",description:"最小值",params:[{name:"values",type:"number",required:!0,description:"可变参数"}],returnType:"number",examples:["min(1, 2, 3)"]},{name:"max",description:"最大值",params:[{name:"values",type:"number",required:!0,description:"可变参数"}],returnType:"number",examples:["max(1, 2, 3)"]},{name:"now",description:"当前时间戳(毫秒)",params:[],returnType:"number",examples:["now()"]},{name:"dateFormat",description:"格式化日期",params:[{name:"timestamp",type:"number",required:!0},{name:"format",type:"string",required:!1,defaultValue:"YYYY-MM-DD"}],returnType:"string",examples:['dateFormat(now(), "YYYY-MM-DD HH:mm:ss")']},{name:"dateParse",description:"解析日期字符串",params:[{name:"dateStr",type:"string",required:!0},{name:"format",type:"string",required:!1}],returnType:"number",examples:['dateParse("2024-01-01")']},{name:"first",description:"获取数组第一个元素",params:[{name:"arr",type:"array",required:!0}],returnType:"any",examples:["first([1,2,3])"]},{name:"last",description:"获取数组最后一个元素",params:[{name:"arr",type:"array",required:!0}],returnType:"any",examples:["last([1,2,3])"]},{name:"includes",description:"检查数组是否包含元素",params:[{name:"arr",type:"array",required:!0},{name:"value",type:"any",required:!0}],returnType:"boolean",examples:["includes([1,2,3], 2)"]},{name:"slice",description:"截取数组",params:[{name:"arr",type:"array",required:!0},{name:"start",type:"number",required:!0},{name:"end",type:"number",required:!1}],returnType:"array",examples:["slice([1,2,3,4], 1, 3)"]},{name:"default",description:"提供默认值",params:[{name:"value",type:"any",required:!0},{name:"defaultValue",type:"any",required:!0}],returnType:"any",examples:['default(null, "fallback")']},{name:"ifElse",description:"条件判断",params:[{name:"condition",type:"boolean",required:!0},{name:"trueValue",type:"any",required:!0},{name:"falseValue",type:"any",required:!0}],returnType:"any",examples:['ifElse(age > 18, "成年", "未成年")']},{name:"isEmpty",description:"检查是否为空",params:[{name:"value",type:"any",required:!0}],returnType:"boolean",examples:['isEmpty("")',"isEmpty([])"]},{name:"isNull",description:"检查是否为 null 或 undefined",params:[{name:"value",type:"any",required:!0}],returnType:"boolean",examples:["isNull(null)"]},{name:"jsonParse",description:"解析 JSON 字符串",params:[{name:"str",type:"string",required:!0}],returnType:"any",examples:["jsonParse('{\"a\":1}')"]},{name:"jsonStringify",description:"序列化为 JSON",params:[{name:"value",type:"any",required:!0}],returnType:"string",examples:["jsonStringify({a:1})"]}].map(e=>e.name));function n(e){return null!==e&&"object"==typeof e&&!0===e.__isExpression&&"string"==typeof e.expression}var o=[];function a(e){if(o.some(t=>t.from===e.from&&t.to===e.to))throw new Error(`Migration from ${e.from} to ${e.to} already exists`);o.push(e)}a({from:"1.0.0",to:"1.1.0",description:"添加 Definition 版本绑定字段",migrate:e=>({...e,actionDefVersionIds:e.actionDefVersionIds||[],dataQueryVersionIds:e.dataQueryVersionIds||[]})}),a({from:"1.1.0",to:"2.0.0",description:"重构组件事件结构",breaking:!0,migrate:e=>({...e,components:e.components.map(e=>{var t;return{...e,events:null==(t=e.events)?void 0:t.map(e=>({...e,enabled:e.enabled??!0}))}})})});var i=class extends Error{constructor(e,t,s,n){super(t||r[e]||"Unknown error"),this.name="DjvlcRuntimeError",this.code=e,this.details=s,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}}},c=class extends i{constructor(e,r,s){super(t.PAGE_NOT_FOUND,e,r,s),this.name="PageLoadError"}},l=class extends i{constructor(e,r,s,n=t.COMPONENT_NOT_FOUND,o){super(n,s,{...o,componentName:e,componentVersion:r}),this.name="ComponentLoadError",this.componentName=e,this.componentVersion=r}},p=class extends i{constructor(e,r,s,n){super(t.COMPONENT_INTEGRITY_MISMATCH,`Integrity check failed for ${e}@${r}`,{expectedHash:s,actualHash:n}),this.name="IntegrityError",this.componentName=e,this.componentVersion=r,this.expectedHash=s,this.actualHash=n}},d=class extends i{constructor(e,r,s){super(t.COMPONENT_BLOCKED,`Component ${e}@${r} is blocked`,{componentName:e,componentVersion:r,reason:s}),this.name="ComponentBlockedError",this.componentName=e,this.componentVersion=r,this.reason=s}},h=class extends i{constructor(e,r,s,n){super(t.UNKNOWN,r,{...n,expression:e,position:s}),this.name="ExpressionError",this.expression=e,this.position=s}},u=class{constructor(e){this.cache=new Map,this.options={channel:"prod",cache:{enabled:!0,maxAge:300},...e}}async resolve(e,t){var r,s;const n=this.getCacheKey(e,t);if(null==(r=this.options.cache)?void 0:r.enabled){const t=this.cache.get(n);if(t&&this.isCacheValid(t.timestamp))return this.log("debug",`Page ${e} loaded from cache`),t.data}const o=performance.now();try{const r=this.buildResolveUrl(e,t),a=await fetch(r,{method:"GET",headers:this.buildHeaders()});if(!a.ok)throw new c(`Failed to resolve page: ${a.status} ${a.statusText}`,{pageUid:e,status:a.status});const i=await a.json();if(!this.isValidPageResolveResult(i))throw new c("Invalid page resolve response",{pageUid:e});const l=i.data;(null==(s=this.options.cache)?void 0:s.enabled)&&this.cache.set(n,{data:l,timestamp:Date.now()});const p=performance.now()-o;return this.log("info",`Page ${e} resolved in ${p.toFixed(2)}ms`),l}catch(a){if(a instanceof c)throw a;throw new c(`Failed to resolve page: ${a instanceof Error?a.message:"Unknown error"}`,{pageUid:e})}}preconnect(){const e=document.createElement("link");e.rel="preconnect",e.href=this.options.apiBaseUrl,document.head.appendChild(e)}clearCache(e){if(e)for(const t of this.cache.keys())t.startsWith(e)&&this.cache.delete(t);else this.cache.clear()}buildResolveUrl(e,t){const r=new URL(`${this.options.apiBaseUrl}/page/resolve`);return r.searchParams.set("pageUid",e),this.options.channel&&r.searchParams.set("channel",this.options.channel),this.options.previewToken&&r.searchParams.set("previewToken",this.options.previewToken),(null==t?void 0:t.uid)&&r.searchParams.set("uid",t.uid),(null==t?void 0:t.deviceId)&&r.searchParams.set("deviceId",t.deviceId),r.toString()}buildHeaders(){const e={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(e.Authorization=`Bearer ${this.options.authToken}`),e}getCacheKey(e,t){const r=[e,this.options.channel];return(null==t?void 0:t.uid)&&r.push(t.uid),(null==t?void 0:t.deviceId)&&r.push(t.deviceId),r.join(":")}isCacheValid(e){var t;const r=1e3*((null==(t=this.options.cache)?void 0:t.maxAge)??300);return Date.now()-e<r}isValidPageResolveResult(e){if(!e||"object"!=typeof e)return!1;const t=e;if(!t.data||"object"!=typeof t.data)return!1;const r=t.data;return"string"==typeof r.pageUid&&"string"==typeof r.pageVersionId&&void 0!==r.pageJson&&void 0!==r.manifest}log(e,t){this.options.logger&&this.options.logger[e](t)}},m=class{constructor(e){this.loadedComponents=new Map,this.loadingPromises=new Map,this.options={enableSRI:!0,concurrency:4,timeout:3e4,blockedComponents:[],...e},this.blockedSet=new Set(this.options.blockedComponents)}async load(e){const t=this.getComponentKey(e.name,e.version);if(this.isBlocked(e.name,e.version))throw new d(e.name,e.version,"Component is blocked");const r=this.loadedComponents.get(t);if(r)return r;const s=this.loadingPromises.get(t);if(s)return s;const n=this.loadComponent(e);this.loadingPromises.set(t,n);try{const e=await n;return this.loadedComponents.set(t,e),e}finally{this.loadingPromises.delete(t)}}async loadAll(e){const t=new Map,{concurrency:r=4}=this.options,s=e.components;for(let n=0;n<s.length;n+=r){const e=s.slice(n,n+r).map(async e=>{const r=this.getComponentKey(e.name,e.version),s=performance.now();try{const n=await this.load(e);t.set(r,{name:e.name,version:e.version,status:"loaded",component:n.Component,loadTime:performance.now()-s})}catch(n){const o=n instanceof d?"blocked":"failed";if(t.set(r,{name:e.name,version:e.version,status:o,error:n instanceof Error?n.message:"Unknown error",loadTime:performance.now()-s}),e.critical)throw n}});await Promise.all(e)}return t}preload(e){e.forEach(e=>{const t=document.createElement("link");t.rel="preload",t.as="script",t.href=this.resolveUrl(e.entryUrl),this.options.enableSRI&&e.integrity&&(t.integrity=e.integrity,t.crossOrigin="anonymous"),document.head.appendChild(t)})}isLoaded(e,t){return this.loadedComponents.has(this.getComponentKey(e,t))}get(e,t){return this.loadedComponents.get(this.getComponentKey(e,t))}isBlocked(e,t){return this.blockedSet.has(`${e}@${t}`)||this.blockedSet.has(e)}updateBlockedList(e){this.blockedSet=new Set(e)}async loadComponent(e){const t=performance.now(),r=this.resolveUrl(e.entryUrl);this.log("debug",`Loading component ${e.name}@${e.version}`);try{const s=await this.fetchWithTimeout(r);if(!s.ok)throw new l(e.name,e.version,`Failed to fetch component: ${s.status} ${s.statusText}`);const n=await s.text();this.options.enableSRI&&e.integrity&&await this.validateIntegrity(e,n);const o=await this.executeScript(n,e),a=performance.now()-t;return this.log("info",`Component ${e.name}@${e.version} loaded in ${a.toFixed(2)}ms`),{name:e.name,version:e.version,Component:o,loadTime:a}}catch(s){if(s instanceof l||s instanceof p||s instanceof d)throw s;throw new l(e.name,e.version,`Failed to load component: ${s instanceof Error?s.message:"Unknown error"}`)}}async fetchWithTimeout(e){const t=new AbortController,r=setTimeout(()=>t.abort(),this.options.timeout);try{return await fetch(e,{signal:t.signal,credentials:"omit"})}finally{clearTimeout(r)}}async validateIntegrity(e,t){if(!e.integrity)return;const[r,s]=e.integrity.split("-");if(!r||!s)throw new p(e.name,e.version,e.integrity,"Invalid format");const n=await crypto.subtle.digest(r.toUpperCase(),(new TextEncoder).encode(t)),o=Array.from(new Uint8Array(n)),a=btoa(String.fromCharCode(...o));if(a!==s)throw new p(e.name,e.version,s,a)}async executeScript(e,t){const r=new Blob([e],{type:"application/javascript"}),s=URL.createObjectURL(r);try{const e=await import(s),r=e.default||e[t.name]||e.Component;if(!r)throw new l(t.name,t.version,"Component module does not export a valid component");return r}finally{URL.revokeObjectURL(s)}}resolveUrl(e){return e.startsWith("http://")||e.startsWith("https://")?e:`${this.options.cdnBaseUrl}/${e.replace(/^\//,"")}`}getComponentKey(e,t){return`${e}@${t}`}log(e,t){this.options.logger&&this.options.logger[e](t)}},g=class{constructor(e){this.preconnectedHosts=new Set,this.preloadedAssets=new Set,this.options=e}preconnectAll(){[...this.options.cdnHosts,...this.options.apiHosts].forEach(e=>this.preconnect(e))}preconnect(e){if(this.preconnectedHosts.has(e))return;const t=document.createElement("link");t.rel="preconnect",t.href=e.startsWith("http")?e:`https://${e}`,t.crossOrigin="anonymous",document.head.appendChild(t),this.preconnectedHosts.add(e)}dnsPrefetch(e){const t=document.createElement("link");t.rel="dns-prefetch",t.href=e.startsWith("http")?e:`https://${e}`,document.head.appendChild(t)}preloadScript(e,t){if(this.preloadedAssets.has(e))return;const r=document.createElement("link");r.rel="preload",r.as="script",r.href=e,t&&(r.integrity=t,r.crossOrigin="anonymous"),document.head.appendChild(r),this.preloadedAssets.add(e)}preloadStyle(e,t){if(this.preloadedAssets.has(e))return;const r=document.createElement("link");r.rel="preload",r.as="style",r.href=e,t&&(r.integrity=t,r.crossOrigin="anonymous"),document.head.appendChild(r),this.preloadedAssets.add(e)}preloadImage(e){if(this.preloadedAssets.has(e))return;const t=document.createElement("link");t.rel="preload",t.as="image",t.href=e,document.head.appendChild(t),this.preloadedAssets.add(e)}prefetch(e,t){const r=document.createElement("link");r.rel="prefetch",r.href=e,t&&(r.as=t),document.head.appendChild(r)}loadStylesheet(e,t){return new Promise((r,s)=>{const n=document.createElement("link");n.rel="stylesheet",n.href=e,t&&(n.integrity=t,n.crossOrigin="anonymous"),n.onload=()=>r(),n.onerror=()=>s(new Error(`Failed to load stylesheet: ${e}`)),document.head.appendChild(n)})}loadScript(e,t){return new Promise((r,s)=>{const n=document.createElement("script");n.src=e,n.async=!0,t&&(n.integrity=t,n.crossOrigin="anonymous"),n.onload=()=>r(),n.onerror=()=>s(new Error(`Failed to load script: ${e}`)),document.body.appendChild(n)})}},y=class{constructor(){this.listeners=new Set,this.state=this.createInitialState()}getState(){return this.state}getPhase(){return this.state.phase}setPhase(e){this.setState({phase:e})}setPage(e){this.setState({page:e,variables:e.pageJson.page.variables||{}})}setError(e){this.setState({phase:"error",error:e})}getVariable(e){return this.state.variables[e]}setVariable(e,t){this.setState({variables:{...this.state.variables,[e]:t}})}setVariables(e){this.setState({variables:{...this.state.variables,...e}})}getQuery(e){return this.state.queries[e]}setQuery(e,t){this.setState({queries:{...this.state.queries,[e]:t}})}setComponentStatus(e,t){const r=new Map(this.state.components);r.set(e,t),this.setState({components:r})}setDestroyed(){this.setState({destroyed:!0})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}reset(){this.state=this.createInitialState(),this.notifyListeners()}setState(e){this.state={...this.state,...e},this.notifyListeners()}notifyListeners(){this.listeners.forEach(e=>{try{e(this.state)}catch(t){}})}createInitialState(){return{phase:"idle",page:null,variables:{},queries:{},components:new Map,error:null,destroyed:!1}}},f=class{constructor(e={}){this.handlers=new Map,this.options={debug:!1,maxListeners:100,...e}}emit(e){this.options.debug&&this.log("debug",`Event emitted: ${e.type}`,e);const t=this.handlers.get(e.type);t&&t.forEach(t=>{try{t(e)}catch(r){this.log("error",`Error in event handler for ${e.type}:`,r)}})}on(e,t){let r=this.handlers.get(e);return r||(r=new Set,this.handlers.set(e,r)),r.size>=(this.options.maxListeners??100)&&this.log("warn",`Max listeners (${this.options.maxListeners}) reached for event: ${e}`),r.add(t),()=>{null==r||r.delete(t),0===(null==r?void 0:r.size)&&this.handlers.delete(e)}}off(e,t){const r=this.handlers.get(e);r&&(r.delete(t),0===r.size&&this.handlers.delete(e))}once(e,t){const r=this.on(e,e=>{r(),t(e)});return r}clear(e){e?this.handlers.delete(e):this.handlers.clear()}listenerCount(e){var t;return(null==(t=this.handlers.get(e))?void 0:t.size)??0}static createEvent(e,t,r){return{type:e,data:t,timestamp:Date.now(),traceId:r}}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},E=class{constructor(e){this.pos=0,this.tokens=[],this.input=e}tokenize(){for(this.pos=0,this.tokens=[];this.pos<this.input.length&&(this.skipWhitespace(),!(this.pos>=this.input.length));){const e=this.readToken();e&&this.tokens.push(e)}return this.tokens.push({type:"EOF",value:null,start:this.input.length,end:this.input.length}),this.tokens}readToken(){const e=this.input[this.pos],t=this.pos;if(this.isDigit(e)||"-"===e&&this.isDigit(this.peek(1)))return this.readNumber();if('"'===e||"'"===e)return this.readString(e);if(this.isIdentifierStart(e))return this.readIdentifier();const r=this.readOperator();if(r)return r;switch(e){case".":return this.pos++,{type:"DOT",value:".",start:t,end:this.pos};case"[":return this.pos++,{type:"LBRACKET",value:"[",start:t,end:this.pos};case"]":return this.pos++,{type:"RBRACKET",value:"]",start:t,end:this.pos};case"(":return this.pos++,{type:"LPAREN",value:"(",start:t,end:this.pos};case")":return this.pos++,{type:"RPAREN",value:")",start:t,end:this.pos};case",":return this.pos++,{type:"COMMA",value:",",start:t,end:this.pos};case"?":return this.pos++,{type:"QUESTION",value:"?",start:t,end:this.pos};case":":return this.pos++,{type:"COLON",value:":",start:t,end:this.pos}}throw new Error(`Unexpected character '${e}' at position ${this.pos}`)}readNumber(){const e=this.pos;let t="";for("-"===this.input[this.pos]&&(t+="-",this.pos++);this.isDigit(this.input[this.pos]);)t+=this.input[this.pos],this.pos++;if("."===this.input[this.pos]&&this.isDigit(this.peek(1)))for(t+=".",this.pos++;this.isDigit(this.input[this.pos]);)t+=this.input[this.pos],this.pos++;return{type:"NUMBER",value:parseFloat(t),start:e,end:this.pos}}readString(e){const t=this.pos;this.pos++;let r="";for(;this.pos<this.input.length&&this.input[this.pos]!==e;){if("\\"===this.input[this.pos]){this.pos++;const e=this.input[this.pos];switch(e){case"n":r+="\n";break;case"t":r+="\t";break;case"r":r+="\r";break;case"\\":r+="\\";break;case'"':r+='"';break;case"'":r+="'";break;default:r+=e}}else r+=this.input[this.pos];this.pos++}if(this.input[this.pos]!==e)throw new Error(`Unterminated string at position ${t}`);return this.pos++,{type:"STRING",value:r,start:t,end:this.pos}}readIdentifier(){const e=this.pos;let t="";for(;this.pos<this.input.length&&this.isIdentifierChar(this.input[this.pos]);)t+=this.input[this.pos],this.pos++;return"true"===t?{type:"BOOLEAN",value:!0,start:e,end:this.pos}:"false"===t?{type:"BOOLEAN",value:!1,start:e,end:this.pos}:"null"===t?{type:"NULL",value:null,start:e,end:this.pos}:{type:"IDENTIFIER",value:t,start:e,end:this.pos}}readOperator(){const e=this.pos,t=this.input.slice(this.pos,this.pos+2),r=this.input[this.pos];if(["==","!=",">=","<=","&&","||","??"].includes(t))return this.pos+=2,{type:"OPERATOR",value:t,start:e,end:this.pos};return["+","-","*","/","%",">","<","!"].includes(r)?(this.pos++,{type:"OPERATOR",value:r,start:e,end:this.pos}):null}skipWhitespace(){for(;this.pos<this.input.length&&/\s/.test(this.input[this.pos]);)this.pos++}isDigit(e){return/[0-9]/.test(e)}isIdentifierStart(e){return/[a-zA-Z_$]/.test(e)}isIdentifierChar(e){return/[a-zA-Z0-9_$]/.test(e)}peek(e=1){return this.input[this.pos+e]||""}},v={"||":1,"??":1,"&&":2,"==":3,"!=":3,"<":4,">":4,"<=":4,">=":4,"+":5,"-":5,"*":6,"/":6,"%":6},b=class{constructor(e){this.pos=0,this.tokens=e}parse(){const e=this.parseExpression();if("EOF"!==this.current().type)throw new Error(`Unexpected token '${this.current().value}' at position ${this.current().start}`);return e}parseExpression(){return this.parseTernary()}parseTernary(){const e=this.parseBinary(0);if("QUESTION"===this.current().type){this.advance();const t=this.parseExpression();this.expect("COLON");return{type:"conditional",test:e,consequent:t,alternate:this.parseExpression(),raw:void 0}}return e}parseBinary(e){let t=this.parseUnary();for(;;){const r=this.current();if("OPERATOR"!==r.type)break;const s=v[r.value];if(void 0===s||s<e)break;this.advance();const n=this.parseBinary(s+1);t={type:"binary",operator:r.value,left:t,right:n,raw:void 0}}return t}parseUnary(){const e=this.current();if("OPERATOR"===e.type&&("!"===e.value||"-"===e.value)){this.advance();const t=this.parseUnary();return{type:"unary",operator:e.value,argument:t,raw:void 0}}return this.parsePostfix()}parsePostfix(){let e=this.parsePrimary();for(;;){const t=this.current();if("DOT"===t.type){this.advance();e={type:"member",object:e,property:this.expect("IDENTIFIER").value,computed:!1,raw:void 0}}else if("LBRACKET"===t.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"!==t.type||"identifier"!==e.type)break;{const r=e.name;if(!s.has(r))throw new Error(`Unknown function '${r}' at position ${t.start}`);this.advance();const n=this.parseArguments();this.expect("RPAREN"),e={type:"call",callee:r,arguments:n,raw:void 0}}}}return e}parsePrimary(){const e=this.current();if("NUMBER"===e.type||"STRING"===e.type||"BOOLEAN"===e.type||"NULL"===e.type)return this.advance(),{type:"literal",value:e.value,start:e.start,end:e.end,raw:void 0};if("IDENTIFIER"===e.type)return this.advance(),{type:"identifier",name:e.value,start:e.start,end:e.end,raw:void 0};if("LBRACKET"===e.type)return this.parseArray();if("LPAREN"===e.type){this.advance();const e=this.parseExpression();return this.expect("RPAREN"),e}throw new Error(`Unexpected token '${e.value}' at position ${e.start}`)}parseArray(){const e=this.current().start;this.advance();const t=[];for(;"RBRACKET"!==this.current().type&&(t.push(this.parseExpression()),"COMMA"===this.current().type);)this.advance();const r=this.current().end;return this.expect("RBRACKET"),{type:"array",elements:t,start:e,end:r,raw:void 0}}parseArguments(){const e=[];if("RPAREN"!==this.current().type)for(e.push(this.parseExpression());"COMMA"===this.current().type;)this.advance(),e.push(this.parseExpression());return e}current(){return this.tokens[this.pos]}advance(){return this.tokens[this.pos++]}expect(e){const t=this.current();if(t.type!==e)throw new Error(`Expected '${e}' but got '${t.type}' at position ${t.start}`);return this.advance()}},I={len:e=>"string"==typeof e||Array.isArray(e)?e.length:0,trim:e=>String(e??"").trim(),upper:e=>String(e??"").toUpperCase(),lower:e=>String(e??"").toLowerCase(),substr:(e,t,r)=>{const s=String(e??""),n=Number(t)||0,o=void 0!==r?Number(r):void 0;return s.substring(n,void 0!==o?n+o:void 0)},concat:(...e)=>e.map(e=>String(e??"")).join(""),replace:(e,t,r)=>String(e??"").split(String(t)).join(String(r)),split:(e,t)=>String(e??"").split(String(t)),join:(e,t)=>Array.isArray(e)?e.join(void 0!==t?String(t):","):"",startsWith:(e,t)=>String(e??"").startsWith(String(t)),endsWith:(e,t)=>String(e??"").endsWith(String(t)),contains:(e,t)=>String(e??"").includes(String(t)),toNumber:e=>{const t=Number(e);return isNaN(t)?0:t},toString:e=>String(e??""),toInt:e=>Math.trunc(Number(e)||0),toFloat:e=>parseFloat(String(e))||0,round:(e,t)=>{const r=Number(e)||0,s=Number(t)||0,n=Math.pow(10,s);return Math.round(r*n)/n},floor:e=>Math.floor(Number(e)||0),ceil:e=>Math.ceil(Number(e)||0),abs:e=>Math.abs(Number(e)||0),min:(...e)=>{const t=e.map(e=>Number(e)).filter(e=>!isNaN(e));return t.length>0?Math.min(...t):0},max:(...e)=>{const t=e.map(e=>Number(e)).filter(e=>!isNaN(e));return t.length>0?Math.max(...t):0},sum:e=>Array.isArray(e)?e.reduce((e,t)=>e+(Number(t)||0),0):0,avg:e=>{if(!Array.isArray(e)||0===e.length)return 0;return e.reduce((e,t)=>e+(Number(t)||0),0)/e.length},random:()=>Math.random(),randomInt:(e,t)=>{const r=Math.ceil(Number(e)||0),s=Math.floor(Number(t)||100);return Math.floor(Math.random()*(s-r+1))+r},now:()=>Date.now(),today:()=>(new Date).toISOString().split("T")[0],dateFormat:(e,t)=>{const r=new Date(Number(e)||Date.now()),s=e=>e.toString().padStart(2,"0");return String(t||"YYYY-MM-DD").replace("YYYY",r.getFullYear().toString()).replace("MM",s(r.getMonth()+1)).replace("DD",s(r.getDate())).replace("HH",s(r.getHours())).replace("mm",s(r.getMinutes())).replace("ss",s(r.getSeconds()))},dateParse:e=>new Date(String(e)).getTime(),year:e=>new Date(Number(e)||Date.now()).getFullYear(),month:e=>new Date(Number(e)||Date.now()).getMonth()+1,day:e=>new Date(Number(e)||Date.now()).getDate(),addDays:(e,t)=>{const r=new Date(Number(e)||Date.now());return r.setDate(r.getDate()+(Number(t)||0)),r.getTime()},diffDays:(e,t)=>{const r=new Date(Number(e)||Date.now()),s=new Date(Number(t)||Date.now()),n=Math.abs(s.getTime()-r.getTime());return Math.floor(n/864e5)},isNull:e=>null==e,isUndefined:e=>void 0===e,isEmpty:e=>null==e||("string"==typeof e||Array.isArray(e)?0===e.length:"object"==typeof e&&0===Object.keys(e).length),isArray:e=>Array.isArray(e),isObject:e=>null!==e&&"object"==typeof e&&!Array.isArray(e),isString:e=>"string"==typeof e,isNumber:e=>"number"==typeof e&&!isNaN(e),isBoolean:e=>"boolean"==typeof e,typeOf:e=>null===e?"null":Array.isArray(e)?"array":typeof e,default:(e,t)=>e??t,coalesce:(...e)=>{for(const t of e)if(null!=t)return t;return null},ifElse:(e,t,r)=>e?t:r,first:e=>{if(Array.isArray(e))return e[0]},last:e=>{if(Array.isArray(e))return e[e.length-1]},at:(e,t)=>{if(Array.isArray(e))return e[Number(t)||0]},slice:(e,t,r)=>Array.isArray(e)?e.slice(Number(t)||0,void 0!==r?Number(r):void 0):[],includes:(e,t)=>!!Array.isArray(e)&&e.includes(t),indexOf:(e,t)=>Array.isArray(e)?e.indexOf(t):-1,reverse:e=>Array.isArray(e)?[...e].reverse():[],sort:e=>Array.isArray(e)?[...e].sort():[],unique:e=>Array.isArray(e)?[...new Set(e)]:[],flatten:e=>Array.isArray(e)?e.flat():[],count:e=>Array.isArray(e)?e.length:0,get:(e,t,r)=>{if(null==e)return r;const s=String(t).split(".");let n=e;for(const o of s){if(null==n)return r;n=n[o]}return n??r},keys:e=>"object"!=typeof e||null===e?[]:Object.keys(e),values:e=>"object"!=typeof e||null===e?[]:Object.values(e),entries:e=>"object"!=typeof e||null===e?[]:Object.entries(e),has:(e,t)=>"object"==typeof e&&null!==e&&String(t)in e,merge:(...e)=>{const t={};for(const r of e)"object"==typeof r&&null!==r&&Object.assign(t,r);return t},and:(...e)=>e.every(e=>Boolean(e)),or:(...e)=>e.some(e=>Boolean(e)),not:e=>!e,eq:(e,t)=>e===t,ne:(e,t)=>e!==t,gt:(e,t)=>Number(e)>Number(t),gte:(e,t)=>Number(e)>=Number(t),lt:(e,t)=>Number(e)<Number(t),lte:(e,t)=>Number(e)<=Number(t),between:(e,t,r)=>{const s=Number(e);return s>=Number(t)&&s<=Number(r)},formatNumber:(e,t)=>{const r=Number(e)||0,s=Number(t)??0;return r.toLocaleString(void 0,{minimumFractionDigits:s,maximumFractionDigits:s})},formatCurrency:(e,t)=>{const r=Number(e)||0,s=String(t||"CNY");return r.toLocaleString("zh-CN",{style:"currency",currency:s})},formatPercent:(e,t)=>{const r=Number(e)||0,s=Number(t)??0;return(100*r).toFixed(s)+"%"},jsonParse:e=>{try{return JSON.parse(String(e))}catch{return null}},jsonStringify:e=>JSON.stringify(e)},N=class{constructor(e={}){this.depth=0,this.startTime=0,this.options={maxDepth:100,timeout:1e3,debug:!1,...e}}evaluate(e,t){this.depth=0,this.startTime=Date.now();try{return{value:this.evaluateNode(e,t)}}catch(r){return{value:void 0,error:r instanceof Error?r:new Error(String(r))}}}evaluateNode(e,t){switch(this.checkLimits(),e.type){case"literal":return this.evaluateLiteral(e);case"identifier":return this.evaluateIdentifier(e,t);case"member":return this.evaluateMember(e,t);case"call":return this.evaluateCall(e,t);case"binary":return this.evaluateBinary(e,t);case"unary":return this.evaluateUnary(e,t);case"conditional":return this.evaluateConditional(e,t);case"array":return this.evaluateArray(e,t);default:throw new h("",`Unknown node type: ${e.type}`)}}evaluateLiteral(e){return e.value}evaluateIdentifier(e,t){const r=e.name;switch(r){case"state":return t.state;case"query":return t.query;case"context":return t.context;case"event":return t.event;case"item":return t.item;case"index":return t.index;default:throw new h("",`Unknown variable '${r}'`,void 0!==e.start&&void 0!==e.end?{start:e.start,end:e.end}:void 0)}}evaluateMember(e,t){const r=this.evaluateNode(e.object,t);if(null==r)return;let s;if(e.computed){s=this.evaluateNode(e.property,t)}else s=e.property;return"object"==typeof r&&null!==r?r[s]:void 0}evaluateCall(e,t){const r=I[e.callee];if(!r)throw new h("",`Unknown function '${e.callee}'`);return r(...e.arguments.map(e=>this.evaluateNode(e,t)))}evaluateBinary(e,t){const r=e.operator;if("&&"===r){const r=this.evaluateNode(e.left,t);return r?this.evaluateNode(e.right,t):r}if("||"===r){const r=this.evaluateNode(e.left,t);return r||this.evaluateNode(e.right,t)}if("??"===r){const r=this.evaluateNode(e.left,t);return null!=r?r:this.evaluateNode(e.right,t)}const s=this.evaluateNode(e.left,t),n=this.evaluateNode(e.right,t);switch(r){case"+":return"string"==typeof s||"string"==typeof n?String(s)+String(n):s+n;case"-":return s-n;case"*":return s*n;case"/":return s/n;case"%":return s%n;case"==":return s===n;case"!=":return s!==n;case"<":return s<n;case">":return s>n;case"<=":return s<=n;case">=":return s>=n;default:throw new h("",`Unknown operator '${r}'`)}}evaluateUnary(e,t){const r=this.evaluateNode(e.argument,t);switch(e.operator){case"!":return!r;case"-":return-r;default:throw new h("",`Unknown unary operator '${e.operator}'`)}}evaluateConditional(e,t){return this.evaluateNode(e.test,t)?this.evaluateNode(e.consequent,t):this.evaluateNode(e.alternate,t)}evaluateArray(e,t){return e.elements.map(e=>this.evaluateNode(e,t))}checkLimits(){if(this.depth++,this.depth>(this.options.maxDepth??100))throw new h("","Maximum recursion depth exceeded");if(Date.now()-this.startTime>(this.options.timeout??1e3))throw new h("","Expression evaluation timeout")}},T=class{constructor(e={}){this.astCache=new Map,this.options={cacheAST:!0,maxCacheSize:1e3,...e},this.evaluator=new N(e)}evaluate(e,t){try{const r=this.parse(e);return this.evaluator.evaluate(r,t)}catch(r){return{value:void 0,error:r instanceof Error?r:new Error(String(r))}}}evaluateWithFallback(e,t,r){const s=this.evaluate(e,t);return s.error?(this.log("warn",`Expression evaluation failed: ${s.error.message}`,e),r):s.value}evaluateTemplate(e,t){return e.replace(/\$\{([^}]+)\}/g,(e,r)=>{const s=this.evaluate(r.trim(),t);return s.error?(this.log("warn",`Template expression failed: ${s.error.message}`,r),""):String(s.value??"")})}parse(e){if(this.options.cacheAST){const t=this.astCache.get(e);if(t)return t}try{const t=new E(e).tokenize(),r=new b(t).parse();if(this.options.cacheAST){if(this.astCache.size>=(this.options.maxCacheSize??1e3)){Array.from(this.astCache.keys()).slice(0,Math.floor(this.astCache.size/2)).forEach(e=>this.astCache.delete(e))}this.astCache.set(e,r)}return r}catch(t){throw new h(e,t instanceof Error?t.message:"Parse error")}}validate(e){const t=[],r=[],s=[],n=[];try{const t=this.parse(e);return this.collectReferences(t,s,n),{valid:!0,errors:[],warnings:r,referencedPaths:s,calledFunctions:n}}catch(o){return t.push({type:"SYNTAX_ERROR",message:o instanceof Error?o.message:"Parse error"}),{valid:!1,errors:t,warnings:r,referencedPaths:s,calledFunctions:n}}}clearCache(){this.astCache.clear()}collectReferences(e,t,r){switch(e.type){case"identifier":t.push(e.name);break;case"member":{const r=this.buildMemberPath(e);r&&t.push(r);break}case"call":r.push(e.callee),e.arguments.forEach(e=>this.collectReferences(e,t,r));break;case"binary":this.collectReferences(e.left,t,r),this.collectReferences(e.right,t,r);break;case"unary":this.collectReferences(e.argument,t,r);break;case"conditional":this.collectReferences(e.test,t,r),this.collectReferences(e.consequent,t,r),this.collectReferences(e.alternate,t,r);break;case"array":e.elements.forEach(e=>this.collectReferences(e,t,r))}}buildMemberPath(e){if("identifier"===e.type)return e.name;if("member"===e.type&&!e.computed){const t=this.buildMemberPath(e.object);if(t)return`${t}.${e.property}`}return null}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},w=class{constructor(e){this.storage={get:(e,t)=>{const r=this.getStorageKey(e,null==t?void 0:t.namespace),s=localStorage.getItem(r);if(s)try{const e=JSON.parse(s);return e.expires&&Date.now()>e.expires?void localStorage.removeItem(r):e.value}catch{return}},set:(e,t,r)=>{const s=this.getStorageKey(e,null==r?void 0:r.namespace),n={value:t,expires:(null==r?void 0:r.ttl)?Date.now()+1e3*r.ttl:void 0};localStorage.setItem(s,JSON.stringify(n))},remove:(e,t)=>{const r=this.getStorageKey(e,null==t?void 0:t.namespace);localStorage.removeItem(r)}},this.options=e,this.storageNamespace=`djvlc:${e.context.pageUid}`}async requestData(e,t){this.log("debug",`Requesting data: ${e}`,t);const r=performance.now(),s=this.options.context;try{const n=await fetch(`${this.options.apiBaseUrl}/data/query`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({queryVersionId:e,params:t||{},context:{pageVersionId:s.pageVersionId,uid:s.userId}})}),o=await n.json(),a=performance.now()-r;return this.log("debug",`Data query completed in ${a.toFixed(2)}ms`),o.success&&o.data&&this.options.stateManager.setQuery(e,o.data),o}catch(n){return this.log("error",`Data query failed: ${e}`,n),{success:!1,message:n instanceof Error?n.message:"Query failed"}}}async executeAction(e,t){this.log("debug",`Executing action: ${e}`,t);const r=performance.now(),s=this.options.context;try{const n=await fetch(`${this.options.apiBaseUrl}/actions/execute`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({actionType:e,params:t||{},context:{pageVersionId:s.pageVersionId,uid:s.userId,deviceId:s.deviceId,channel:s.channel},idempotencyKey:this.generateIdempotencyKey(e,t)})}),o=await n.json(),a=performance.now()-r;return this.log("debug",`Action completed in ${a.toFixed(2)}ms`),o}catch(n){return this.log("error",`Action failed: ${e}`,n),{success:!1,message:n instanceof Error?n.message:"Action failed"}}}navigate(e){this.log("debug","Navigate:",e),this.track({eventName:"navigate",params:{url:e.url,newTab:e.newTab}});let t=e.url;if(e.params){const r=new URLSearchParams(e.params);t+=(t.includes("?")?"&":"?")+r.toString()}e.newTab?window.open(t,"_blank"):e.replace?window.location.replace(t):window.location.href=t}goBack(){this.log("debug","Navigate back"),window.history.back()}refresh(){this.log("debug","Refresh page"),window.location.reload()}async openDialog(e){switch(this.log("debug","Open dialog:",e),e.type){case"alert":return window.alert(e.content||e.title),!0;case"confirm":return window.confirm(e.content||e.title);case"prompt":return window.prompt(e.content||e.title)||"";case"custom":return this.log("warn","Custom dialog not implemented"),!1;default:return!1}}closeDialog(){this.log("debug","Close dialog")}showToast(e){this.log("debug","Show toast:",e);const t=document.createElement("div");t.className=`djvlc-toast djvlc-toast-${e.type||"info"} djvlc-toast-${e.position||"top"}`,t.textContent=e.message,Object.assign(t.style,{position:"fixed",left:"50%",transform:"translateX(-50%)",padding:"12px 24px",borderRadius:"8px",color:"#fff",fontSize:"14px",zIndex:"10000",animation:"djvlc-toast-fade-in 0.3s ease"});t.style.backgroundColor={success:"#52c41a",error:"#ff4d4f",warning:"#faad14",info:"#1890ff"}[e.type||"info"];Object.assign(t.style,{top:{top:"20px"},center:{top:"50%",transform:"translate(-50%, -50%)"},bottom:{bottom:"20px"}}[e.position||"top"]),document.body.appendChild(t),setTimeout(()=>{t.style.animation="djvlc-toast-fade-out 0.3s ease",setTimeout(()=>t.remove(),300)},e.duration||3e3)}track(e){this.log("debug","Track event:",e);const t=this.options.context;fetch(`${this.options.apiBaseUrl}/track`,{method:"POST",headers:this.buildHeaders(),body:JSON.stringify({eventName:e.eventName,params:e.params,timestamp:e.timestamp||Date.now(),context:{pageVersionId:t.pageVersionId,runtimeVersion:t.runtimeVersion,userId:t.userId,deviceId:t.deviceId,channel:t.channel}}),keepalive:!0}).catch(e=>{this.log("warn","Track failed:",e)})}async copyToClipboard(e){try{return await navigator.clipboard.writeText(e),{success:!0,content:e}}catch(t){return{success:!1,error:t instanceof Error?t.message:"Copy failed"}}}async readFromClipboard(){try{return{success:!0,content:await navigator.clipboard.readText()}}catch(e){return{success:!1,error:e instanceof Error?e.message:"Read failed"}}}getState(e){return this.options.stateManager.getVariable(e)}setState(e,t){this.options.stateManager.setVariable(e,t)}getVariable(e){return this.options.stateManager.getVariable(e)}postMessage(e,t){this.log("debug",`Post message to ${e}:`,t);const r=new CustomEvent(`djvlc:message:${e}`,{detail:{message:t,from:this.options.context.pageUid}});document.dispatchEvent(r)}broadcast(e,t){this.log("debug",`Broadcast to ${e}:`,t);const r=new CustomEvent(`djvlc:broadcast:${e}`,{detail:{message:t,from:this.options.context.pageUid}});document.dispatchEvent(r)}getContext(){return{...this.options.context}}buildHeaders(){const e={"Content-Type":"application/json",...this.options.headers};return this.options.authToken&&(e.Authorization=`Bearer ${this.options.authToken}`),e}getStorageKey(e,t){return`${t||this.storageNamespace}:${e}`}generateIdempotencyKey(e,t){const r=Date.now(),s=JSON.stringify(t||{});return`${e}:${r}:${this.simpleHash(s)}`}simpleHash(e){let t=0;for(let r=0;r<e.length;r++){t=(t<<5)-t+e.charCodeAt(r),t&=t}return Math.abs(t).toString(36)}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},A=class{constructor(e={}){this.blockedComponentsMap=new Map,this.blockedActionsSet=new Set,this.options={enableSRI:!0,cdnDomains:[],apiDomains:[],blockedComponents:[],blockedActions:[],...e},this.updateBlockedList(e.blockedComponents||[],e.blockedActions||[])}updateBlockedList(e,t){this.blockedComponentsMap.clear(),e.forEach(e=>{this.blockedComponentsMap.set(`${e.name}@${e.version}`,e)}),this.blockedActionsSet=new Set(t)}isComponentBlocked(e,t){return this.blockedComponentsMap.has(`${e}@${t}`)}getBlockedInfo(e,t){return this.blockedComponentsMap.get(`${e}@${t}`)}isActionBlocked(e){return this.blockedActionsSet.has(e)}async validateComponent(e,t,r,s){if(!this.options.enableSRI)return;const[n,o]=s.split("-");if(!n||!o)throw new p(e,t,s,"Invalid format");const a=await this.computeHash(r,n);if(a!==o)throw new p(e,t,o,a)}isAllowedUrl(e,t){const r="cdn"===t?this.options.cdnDomains:this.options.apiDomains;if(!r||0===r.length)return!0;try{const t=new URL(e);return r.some(e=>{if(e.startsWith("*.")){const r=e.slice(2);return t.hostname.endsWith(r)}return t.hostname===e})}catch{return!1}}generateCSPPolicy(){const e=this.options.cdnDomains||[],t=this.options.apiDomains||[],r=["'self'",...e].join(" "),s=["'self'",...t].join(" ");return["default-src 'self'",`script-src ${r}`,`style-src ${["'self'","'unsafe-inline'",...e].join(" ")}`,`img-src ${["'self'","data:","blob:",...e].join(" ")}`,`connect-src ${s}`,`font-src 'self' data: ${e.join(" ")}`,"frame-ancestors 'self'","base-uri 'self'","form-action 'self'"].join("; ")}applyCSP(){const e=document.createElement("meta");e.httpEquiv="Content-Security-Policy",e.content=this.generateCSPPolicy(),document.head.appendChild(e)}assertNotBlocked(e,t){const r=this.getBlockedInfo(e,t);if(r)throw new d(e,t,r.reason)}async computeHash(e,t){const r=(new TextEncoder).encode(e),s=await crypto.subtle.digest(t.toUpperCase(),r),n=Array.from(new Uint8Array(s));return btoa(String.fromCharCode(...n))}_log(e,t){this.options.logger&&this.options.logger[e](t)}get log(){return this._log.bind(this)}},S=class{constructor(e){this.spans=new Map,this.metrics=[],this.errors=[],this.options={enabled:!0,sampleRate:1,...e},this.traceId=this.generateId(),this.shouldSample=Math.random()<(this.options.sampleRate??1)}getTraceId(){return this.traceId}getTraceparent(){return`00-${this.traceId}-${this.generateId().slice(0,16)}-01`}startSpan(e,t,r){const s={spanId:this.generateId().slice(0,16),traceId:this.traceId,parentSpanId:t,name:e,startTime:performance.now(),attributes:r};return this.spans.set(s.spanId,s),this.log("debug",`Span started: ${e} (${s.spanId})`),s}endSpan(e,t="ok"){const r=this.spans.get(e);r&&(r.endTime=performance.now(),r.status=t,this.log("debug",`Span ended: ${r.name} (${e}) - ${r.endTime-r.startTime}ms`))}recordMetric(e,t,r,s){const n={type:e,name:t,duration:r,startTime:performance.now()-r,extra:s};this.metrics.push(n),this.log("debug",`Metric: ${e} - ${t} - ${r}ms`),this.options.onMetric&&this.options.onMetric(n)}recordError(e,t){const r={type:"LOAD_ERROR",message:e.message,stack:e instanceof Error?e.stack:void 0,timestamp:Date.now(),traceId:this.traceId,...t};this.errors.push(r),this.log("error",`Error recorded: ${e.message}`),this.shouldSample&&this.options.enabled&&this.reportError(r)}recordPageLoad(e,t){this.recordMetric("page_resolve","page_load",e,{pageVersionId:this.options.pageVersionId,...t})}recordComponentLoad(e,t,r,s){this.recordMetric("component_load",`${e}@${t}`,r,{success:s})}recordFirstRender(e){this.recordMetric("first_render","first_render",e,{pageVersionId:this.options.pageVersionId})}recordActionExecute(e,t,r){this.recordMetric("action_execute",e,t,{success:r})}recordQueryExecute(e,t,r,s){this.recordMetric("query_execute",e,t,{success:r,fromCache:s})}getMetrics(){return[...this.metrics]}getSpans(){return Array.from(this.spans.values())}clear(){this.spans.clear(),this.metrics=[],this.errors=[]}async flush(){if(!this.shouldSample||!this.options.enabled||!this.options.endpoint)return;const e={traceId:this.traceId,pageVersionId:this.options.pageVersionId,appId:this.options.appId,spans:this.getSpans(),metrics:this.metrics,errors:this.errors,timestamp:Date.now()};try{await fetch(this.options.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:!0})}catch(t){this.log("warn","Failed to flush telemetry:",t)}}reportError(e){this.options.endpoint&&fetch(`${this.options.endpoint}/errors`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:!0}).catch(()=>{})}generateId(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}},O=class{constructor(e){this.container=null,this.renderedElements=new Map,this.expressionContext={state:{},query:{},context:{}},this.options=e}init(){this.log("debug","Renderer initialized")}render(e,t){this.container=t,this.log("debug","Rendering page",e.page.id),t.innerHTML="",this.applyPageStyles(e.page.canvas);const r=document.createDocumentFragment();for(const s of e.components){const e=this.renderComponent(s);e&&r.appendChild(e)}t.appendChild(r),this.log("info",`Rendered ${e.components.length} components`)}updateComponent(e,t){const r=this.renderedElements.get(e);r?this.applyProps(r,t):this.log("warn",`Component not found: ${e}`)}updateContext(e){this.expressionContext={...this.expressionContext,...e}}destroy(){this.renderedElements.forEach(e=>{e.remove()}),this.renderedElements.clear(),this.container&&(this.container.innerHTML=""),this.log("debug","Renderer destroyed")}renderComponent(e){const{id:t,type:r,props:s,style:n,children:o,visible:a}=e;if(!1===a)return null;try{const e=this.options.components.get(r);let a;e&&customElements.get(r)?a=document.createElement(r):(a=document.createElement("div"),a.className=`djvlc-component djvlc-${r}`,e||(this.log("warn",`Component not loaded: ${r}`),a.textContent=`[Component: ${r}]`)),a.setAttribute("data-component-id",t),a.setAttribute("data-component-type",r);const i=this.resolveProps(s);if(this.applyProps(a,i),n&&this.applyStyles(a,n),this.options.injectHostApi(a,t),o&&o.length>0)for(const t of o){const e=this.renderComponent(t);e&&a.appendChild(e)}return this.renderedElements.set(t,a),a}catch(i){if(this.log("error",`Failed to render component: ${t}`,i),this.options.onRenderError)return this.options.onRenderError(t,i);const e=document.createElement("div");return e.className="djvlc-error-boundary",e.textContent=`Error rendering component: ${r}`,e}}resolveProps(e){const t={};for(const[r,s]of Object.entries(e))if(n(s)){const e=this.options.expressionEngine.evaluateWithFallback(s.expression,this.expressionContext,s.fallback);t[r]=e}else"object"!=typeof s||null===s||Array.isArray(s)?t[r]=s:t[r]=this.resolveProps(s);return t}applyProps(e,t){for(const[r,s]of Object.entries(t))null!=s&&(e.tagName.includes("-")?e[r]=s:"boolean"==typeof s?s?e.setAttribute(r,""):e.removeAttribute(r):"object"==typeof s?e.setAttribute(r,JSON.stringify(s)):e.setAttribute(r,String(s)))}applyStyles(e,t){for(const[r,s]of Object.entries(t)){if(null==s)continue;let t;if("number"==typeof s){t=["zIndex","opacity","flex","fontWeight"].includes(r)?String(s):`${s}px`}else t=String(s);const n=r.replace(/([A-Z])/g,"-$1").toLowerCase();e.style.setProperty(n,t)}}applyPageStyles(e){this.container&&(this.container.style.width=`${e.width}px`,e.height&&(this.container.style.minHeight=`${e.height}px`),e.background&&(this.container.style.background=e.background),this.container.classList.add("djvlc-page",`djvlc-canvas-${e.type}`))}log(e,t,...r){this.options.logger?this.options.logger[e](t,...r):this.options.debug}};function C(e){return new R(e)}var R=class{constructor(e){this.container=null,this.options={channel:"prod",debug:!1,enableSRI:!0,...e},this.logger=this.createLogger(),this.stateManager=new y,this.eventBus=new f({debug:e.debug,logger:this.logger}),this.expressionEngine=new T({debug:e.debug,logger:this.logger}),this.pageLoader=new u({apiBaseUrl:e.apiBaseUrl,channel:e.channel,authToken:e.authToken,previewToken:e.previewToken,headers:e.headers,logger:this.logger}),this.componentLoader=new m({cdnBaseUrl:e.cdnBaseUrl,enableSRI:e.enableSRI,logger:this.logger}),this.assetLoader=new g({cdnHosts:[new URL(e.cdnBaseUrl).host],apiHosts:[new URL(e.apiBaseUrl).host]}),this.securityManager=new A({enableSRI:e.enableSRI,cdnDomains:[new URL(e.cdnBaseUrl).host],apiDomains:[new URL(e.apiBaseUrl).host],logger:this.logger}),this.log("info","Runtime created")}async init(){this.log("info","Initializing runtime");const e=performance.now();try{this.container=this.resolveContainer(),this.assetLoader.preconnectAll(),this.pageLoader.preconnect(),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(e,t,r){if("message"===e&&this.shadowRoot){const e=this.shadowRoot.querySelector(".message");e&&(e.textContent=r)}if("component-name"===e&&this.shadowRoot){const e=this.shadowRoot.querySelector(".title");e&&(e.textContent=`组件 ${r} 加载失败`)}}}),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 "}}),this.stateManager.setPhase("resolving");const t=performance.now()-e;this.log("info",`Runtime initialized in ${t.toFixed(2)}ms`)}catch(t){throw this.handleError(t),t}}async load(){var e;this.log("info","Loading page:",this.options.pageUid);const t=performance.now();try{this.stateManager.setPhase("resolving");const r=await this.pageLoader.resolve(this.options.pageUid,{uid:this.options.userId,deviceId:this.options.deviceId});this.stateManager.setPage(r),this.telemetryManager=new S({pageVersionId:r.pageVersionId,debug:this.options.debug,logger:this.logger,onMetric:this.options.onMetric}),r.runtimeConfig&&(this.securityManager.updateBlockedList(r.runtimeConfig.blockedComponents||[],r.runtimeConfig.killSwitches||[]),this.componentLoader.updateBlockedList((null==(e=r.runtimeConfig.blockedComponents)?void 0:e.map(e=>`${e.name}@${e.version}`))||[])),this.stateManager.setPhase("loading"),this.componentLoader.preload(r.manifest.components);(await this.componentLoader.loadAll(r.manifest)).forEach((e,t)=>{this.stateManager.setComponentStatus(t,e),this.telemetryManager.recordComponentLoad(e.name,e.version,e.loadTime||0,"loaded"===e.status)}),this.initHostApi(r),this.initRenderer();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:r,loadTime:s}),r}catch(r){throw this.stateManager.setPhase("error"),this.handleError(r),r}}async render(){const e=this.stateManager.getState();if(!e.page||!this.container)throw new c("Page not loaded");this.log("info","Rendering page");const t=performance.now();try{this.stateManager.setPhase("rendering"),this.renderer.updateContext({state:e.variables,query:e.queries,context:{userId:this.options.userId,deviceId:this.options.deviceId,channel:this.options.channel,pageVersionId:e.page.pageVersionId}}),this.renderer.render(e.page.pageJson,this.container),this.stateManager.setPhase("ready");const r=performance.now()-t;this.telemetryManager.recordFirstRender(r),this.log("info",`Page rendered in ${r.toFixed(2)}ms`)}catch(r){throw this.stateManager.setPhase("error"),this.handleError(r),r}}getHostApi(){return this.hostApi}getState(){return this.stateManager.getState()}onStateChange(e){return this.stateManager.subscribe(e)}on(e,t){return this.eventBus.on(e,t)}updateComponent(e,t){this.renderer.updateComponent(e,t)}setVariable(e,t){this.stateManager.setVariable(e,t);const r=this.stateManager.getState();r.page&&this.container&&this.renderer.updateContext({state:r.variables})}async refreshData(e){const t=await this.hostApi.requestData(e);if(t.success){this.stateManager.setQuery(e,t.data);const r=this.stateManager.getState();this.renderer.updateContext({query:r.queries})}}destroy(){var e,t;this.log("info","Destroying runtime"),null==(e=this.telemetryManager)||e.flush(),null==(t=this.renderer)||t.destroy(),this.eventBus.clear(),this.stateManager.setDestroyed(),this.container&&(this.container.innerHTML=""),this.log("info","Runtime destroyed")}resolveContainer(){const{container:e}=this.options;if("string"==typeof e){const t=document.querySelector(e);if(!t)throw new Error(`Container not found: ${e}`);return t}return e}initHostApi(e){const t={pageUid:e.pageUid,pageVersionId:e.pageVersionId,runtimeVersion:"0.1.0",userId:this.options.userId,deviceId:this.options.deviceId,channel:this.options.channel,isEditMode:!1,isPreviewMode:e.isPreview||!1};this.hostApi=new w({apiBaseUrl:this.options.apiBaseUrl,authToken:this.options.authToken,headers:this.options.headers,stateManager:this.stateManager,eventBus:this.eventBus,expressionEngine:this.expressionEngine,context:t,debug:this.options.debug,logger:this.logger})}initRenderer(){const e=new Map;this.stateManager.getState().components.forEach((t,r)=>{if("loaded"===t.status&&t.component){const[s,n]=r.split("@");e.set(s,{name:s,version:n,Component:t.component,loadTime:t.loadTime||0})}}),this.renderer=new O({expressionEngine:this.expressionEngine,components:e,injectHostApi:(e,t)=>{e.hostApi=this.hostApi,e.componentId=t},debug:this.options.debug,logger:this.logger,onRenderError:(e,t)=>(this.log("error",`Render error in ${e}:`,t),this.emitEvent("component:error",{componentId:e,error:t.message}),function(e,t){const r=document.createElement("djvlc-error-boundary");return t&&r.setAttribute("message",t),r}(0,t.message))}),this.renderer.init()}handleError(e){var t;const r=e instanceof i?e:{type:"LOAD_ERROR",message:e.message,timestamp:Date.now()};this.stateManager.setError(r),null==(t=this.telemetryManager)||t.recordError(e),this.emitEvent("page:error",{error:e.message}),this.options.onError&&this.options.onError(r)}emitEvent(e,t){var r;const s=f.createEvent(e,t,null==(r=this.telemetryManager)?void 0:r.getTraceId());this.eventBus.emit(s),this.options.onEvent&&this.options.onEvent(s)}createLogger(){return{debug:(...e)=>{this.options.debug},info:(...e)=>{},warn:(...e)=>{},error:(...e)=>{}}}log(e,t,...r){this.logger[e](t,...r)}};const _="1.0.0";async function M(e,t){var r,s;const n=C({container:e,pageUid:t.pageUid,apiBaseUrl:t.apiBaseUrl,cdnBaseUrl:t.cdnBaseUrl,channel:t.channel,userId:t.userId,deviceId:t.deviceId,authToken:t.authToken,previewToken:t.previewToken,debug:t.debug,enableSRI:t.enableSRI,headers:t.headers,onError:t.onError?e=>{var r;return null==(r=t.onError)?void 0:r.call(t,new Error(e.message))}:void 0,onMetric:t.onMetric});try{await n.init(),await n.load(),await n.render(),null==(r=t.onLoad)||r.call(t,n.getState())}catch(o){const e=o instanceof Error?o:new Error(String(o));throw null==(s=t.onError)||s.call(t,e),e}return{runtime:n,destroy:()=>n.destroy()}}function D(e){e.forEach(e=>{const t=document.createElement("link");t.rel="preconnect",t.href=e.startsWith("http")?e:`https://${e}`,t.crossOrigin="anonymous",document.head.appendChild(t)})}function x(e,t=_){[`${e}/runtime/${t}/runtime.esm.js`,`${e}/runtime/${t}/runtime.css`].forEach(e=>{const t=document.createElement("link");t.rel="preload",t.href=e,t.as=e.endsWith(".js")?"script":"style",e.endsWith(".js")&&(t.crossOrigin="anonymous"),document.head.appendChild(t)})}function k(){const e="djv_device_id";let t=localStorage.getItem(e);if(!t){t=`${Date.now()}-${Math.random().toString(36).substring(2,11)}`;try{localStorage.setItem(e,t)}catch{}}return t}function L(){return e=32,Array.from({length:e},()=>Math.floor(16*Math.random()).toString(16)).join("");var e}function U(){return e=16,Array.from({length:e},()=>Math.floor(16*Math.random()).toString(16)).join("");var e}function P(){return`00-${L()}-${U()}-01`}const $={mount:M,preconnect:D,preloadAssets:x,getDeviceId:k,generateTraceId:L,generateSpanId:U,generateTraceparent:P,createRuntime:C,RUNTIME_VERSION:_};return e.RUNTIME_VERSION=_,e.createRuntime=C,e.default=$,e.generateSpanId=U,e.generateTraceId=L,e.generateTraceparent=P,e.getDeviceId=k,e.mount=M,e.preconnect=D,e.preloadAssets=x,Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),e}({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djvlc/runtime-web",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "DJV 低代码平台浏览器版运行时(CDN 发布用)",
5
5
  "type": "module",
6
6
  "main": "./dist/runtime.iife.js",