@serve.zone/dcrouter 11.14.0 → 11.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_serve/bundle.js +4 -4
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/cache/classes.cache.cleaner.d.ts +47 -0
- package/dist_ts/cache/classes.cache.cleaner.js +130 -0
- package/dist_ts/cache/classes.cached.document.d.ts +76 -0
- package/dist_ts/cache/classes.cached.document.js +100 -0
- package/dist_ts/cache/classes.cachedb.d.ts +60 -0
- package/dist_ts/cache/classes.cachedb.js +126 -0
- package/dist_ts/cache/documents/classes.cached.email.d.ts +125 -0
- package/dist_ts/cache/documents/classes.cached.email.js +337 -0
- package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +119 -0
- package/dist_ts/cache/documents/classes.cached.ip.reputation.js +323 -0
- package/dist_ts/cache/documents/index.d.ts +2 -0
- package/dist_ts/cache/documents/index.js +3 -0
- package/dist_ts/cache/index.d.ts +4 -0
- package/dist_ts/cache/index.js +7 -0
- package/dist_ts/classes.cert-provision-scheduler.d.ts +54 -0
- package/dist_ts/classes.cert-provision-scheduler.js +118 -0
- package/dist_ts/classes.dcrouter.d.ts +392 -0
- package/dist_ts/classes.dcrouter.js +1703 -0
- package/dist_ts/classes.storage-cert-manager.d.ts +18 -0
- package/dist_ts/classes.storage-cert-manager.js +43 -0
- package/dist_ts/config/classes.api-token-manager.d.ts +46 -0
- package/dist_ts/config/classes.api-token-manager.js +150 -0
- package/dist_ts/config/classes.route-config-manager.d.ts +38 -0
- package/dist_ts/config/classes.route-config-manager.js +257 -0
- package/dist_ts/config/index.d.ts +3 -0
- package/dist_ts/config/index.js +5 -0
- package/dist_ts/config/validator.d.ts +104 -0
- package/dist_ts/config/validator.js +152 -0
- package/dist_ts/errors/base.errors.d.ts +224 -0
- package/dist_ts/errors/base.errors.js +320 -0
- package/dist_ts/errors/error-handler.d.ts +98 -0
- package/dist_ts/errors/error-handler.js +282 -0
- package/dist_ts/errors/error.codes.d.ts +115 -0
- package/dist_ts/errors/error.codes.js +136 -0
- package/dist_ts/errors/index.d.ts +54 -0
- package/dist_ts/errors/index.js +136 -0
- package/dist_ts/errors/reputation.errors.d.ts +183 -0
- package/dist_ts/errors/reputation.errors.js +292 -0
- package/dist_ts/http3/http3-route-augmentation.d.ts +50 -0
- package/dist_ts/http3/http3-route-augmentation.js +98 -0
- package/dist_ts/http3/index.d.ts +1 -0
- package/dist_ts/http3/index.js +2 -0
- package/dist_ts/index.d.ts +8 -0
- package/dist_ts/index.js +29 -0
- package/dist_ts/logger.d.ts +21 -0
- package/dist_ts/logger.js +81 -0
- package/dist_ts/monitoring/classes.metricscache.d.ts +32 -0
- package/dist_ts/monitoring/classes.metricscache.js +63 -0
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +184 -0
- package/dist_ts/monitoring/classes.metricsmanager.js +744 -0
- package/dist_ts/monitoring/index.d.ts +1 -0
- package/dist_ts/monitoring/index.js +2 -0
- package/dist_ts/opsserver/classes.opsserver.d.ts +38 -0
- package/dist_ts/opsserver/classes.opsserver.js +87 -0
- package/dist_ts/opsserver/handlers/admin.handler.d.ts +31 -0
- package/dist_ts/opsserver/handlers/admin.handler.js +180 -0
- package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
- package/dist_ts/opsserver/handlers/certificate.handler.d.ts +32 -0
- package/dist_ts/opsserver/handlers/certificate.handler.js +421 -0
- package/dist_ts/opsserver/handlers/config.handler.d.ts +7 -0
- package/dist_ts/opsserver/handlers/config.handler.js +192 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
- package/dist_ts/opsserver/handlers/index.d.ts +12 -0
- package/dist_ts/opsserver/handlers/index.js +13 -0
- package/dist_ts/opsserver/handlers/logs.handler.d.ts +25 -0
- package/dist_ts/opsserver/handlers/logs.handler.js +256 -0
- package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
- package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
- package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
- package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
- package/dist_ts/opsserver/handlers/security.handler.js +233 -0
- package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
- package/dist_ts/opsserver/handlers/stats.handler.js +403 -0
- package/dist_ts/opsserver/handlers/vpn.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/vpn.handler.js +199 -0
- package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
- package/dist_ts/opsserver/helpers/guards.js +43 -0
- package/dist_ts/opsserver/index.d.ts +1 -0
- package/dist_ts/opsserver/index.js +2 -0
- package/dist_ts/paths.d.ts +26 -0
- package/dist_ts/paths.js +45 -0
- package/dist_ts/plugins.d.ts +81 -0
- package/dist_ts/plugins.js +115 -0
- package/dist_ts/radius/classes.accounting.manager.d.ts +231 -0
- package/dist_ts/radius/classes.accounting.manager.js +462 -0
- package/dist_ts/radius/classes.radius.server.d.ts +171 -0
- package/dist_ts/radius/classes.radius.server.js +386 -0
- package/dist_ts/radius/classes.vlan.manager.d.ts +128 -0
- package/dist_ts/radius/classes.vlan.manager.js +279 -0
- package/dist_ts/radius/index.d.ts +13 -0
- package/dist_ts/radius/index.js +14 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +94 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.js +271 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
- package/dist_ts/remoteingress/index.d.ts +2 -0
- package/dist_ts/remoteingress/index.js +3 -0
- package/dist_ts/security/classes.contentscanner.d.ts +164 -0
- package/dist_ts/security/classes.contentscanner.js +642 -0
- package/dist_ts/security/classes.ipreputationchecker.d.ts +160 -0
- package/dist_ts/security/classes.ipreputationchecker.js +537 -0
- package/dist_ts/security/classes.securitylogger.d.ts +144 -0
- package/dist_ts/security/classes.securitylogger.js +235 -0
- package/dist_ts/security/index.d.ts +3 -0
- package/dist_ts/security/index.js +4 -0
- package/dist_ts/sms/classes.smsservice.d.ts +15 -0
- package/dist_ts/sms/classes.smsservice.js +72 -0
- package/dist_ts/sms/config/sms.config.d.ts +93 -0
- package/dist_ts/sms/config/sms.config.js +2 -0
- package/dist_ts/sms/config/sms.schema.d.ts +5 -0
- package/dist_ts/sms/config/sms.schema.js +121 -0
- package/dist_ts/sms/index.d.ts +1 -0
- package/dist_ts/sms/index.js +2 -0
- package/dist_ts/storage/classes.storagemanager.d.ts +83 -0
- package/dist_ts/storage/classes.storagemanager.js +348 -0
- package/dist_ts/storage/index.d.ts +1 -0
- package/dist_ts/storage/index.js +3 -0
- package/dist_ts/vpn/classes.vpn-manager.d.ts +127 -0
- package/dist_ts/vpn/classes.vpn-manager.js +335 -0
- package/dist_ts/vpn/index.d.ts +1 -0
- package/dist_ts/vpn/index.js +2 -0
- package/dist_ts_apiclient/classes.apitoken.d.ts +41 -0
- package/dist_ts_apiclient/classes.apitoken.js +115 -0
- package/dist_ts_apiclient/classes.certificate.d.ts +57 -0
- package/dist_ts_apiclient/classes.certificate.js +69 -0
- package/dist_ts_apiclient/classes.config.d.ts +7 -0
- package/dist_ts_apiclient/classes.config.js +11 -0
- package/dist_ts_apiclient/classes.dcrouterapiclient.d.ts +41 -0
- package/dist_ts_apiclient/classes.dcrouterapiclient.js +81 -0
- package/dist_ts_apiclient/classes.email.d.ts +30 -0
- package/dist_ts_apiclient/classes.email.js +52 -0
- package/dist_ts_apiclient/classes.logs.d.ts +21 -0
- package/dist_ts_apiclient/classes.logs.js +14 -0
- package/dist_ts_apiclient/classes.radius.d.ts +59 -0
- package/dist_ts_apiclient/classes.radius.js +95 -0
- package/dist_ts_apiclient/classes.remoteingress.d.ts +54 -0
- package/dist_ts_apiclient/classes.remoteingress.js +136 -0
- package/dist_ts_apiclient/classes.route.d.ts +42 -0
- package/dist_ts_apiclient/classes.route.js +154 -0
- package/dist_ts_apiclient/classes.stats.d.ts +47 -0
- package/dist_ts_apiclient/classes.stats.js +38 -0
- package/dist_ts_apiclient/index.d.ts +10 -0
- package/dist_ts_apiclient/index.js +14 -0
- package/dist_ts_apiclient/plugins.d.ts +3 -0
- package/dist_ts_apiclient/plugins.js +5 -0
- package/dist_ts_interfaces/data/remoteingress.d.ts +2 -0
- package/dist_ts_interfaces/data/vpn.d.ts +1 -1
- package/dist_ts_interfaces/requests/vpn.d.ts +1 -1
- package/dist_ts_web/00_commitinfo_data.d.ts +8 -0
- package/dist_ts_web/00_commitinfo_data.js +9 -0
- package/dist_ts_web/appstate.d.ts +238 -0
- package/dist_ts_web/appstate.js +1174 -0
- package/dist_ts_web/elements/index.d.ts +13 -0
- package/dist_ts_web/elements/index.js +14 -0
- package/dist_ts_web/elements/ops-dashboard.d.ts +23 -0
- package/dist_ts_web/elements/ops-dashboard.js +323 -0
- package/dist_ts_web/elements/ops-view-apitokens.d.ts +13 -0
- package/dist_ts_web/elements/ops-view-apitokens.js +371 -0
- package/dist_ts_web/elements/ops-view-certificates.d.ts +22 -0
- package/dist_ts_web/elements/ops-view-certificates.js +528 -0
- package/dist_ts_web/elements/ops-view-config.d.ts +19 -0
- package/dist_ts_web/elements/ops-view-config.js +339 -0
- package/dist_ts_web/elements/ops-view-emails.d.ts +21 -0
- package/dist_ts_web/elements/ops-view-emails.js +165 -0
- package/dist_ts_web/elements/ops-view-logs.d.ts +13 -0
- package/dist_ts_web/elements/ops-view-logs.js +159 -0
- package/dist_ts_web/elements/ops-view-network.d.ts +71 -0
- package/dist_ts_web/elements/ops-view-network.js +764 -0
- package/dist_ts_web/elements/ops-view-overview.d.ts +22 -0
- package/dist_ts_web/elements/ops-view-overview.js +456 -0
- package/dist_ts_web/elements/ops-view-remoteingress.d.ts +20 -0
- package/dist_ts_web/elements/ops-view-remoteingress.js +494 -0
- package/dist_ts_web/elements/ops-view-routes.d.ts +12 -0
- package/dist_ts_web/elements/ops-view-routes.js +404 -0
- package/dist_ts_web/elements/ops-view-security.d.ts +21 -0
- package/dist_ts_web/elements/ops-view-security.js +574 -0
- package/dist_ts_web/elements/ops-view-vpn.d.ts +14 -0
- package/dist_ts_web/elements/ops-view-vpn.js +369 -0
- package/dist_ts_web/elements/shared/css.d.ts +1 -0
- package/dist_ts_web/elements/shared/css.js +10 -0
- package/dist_ts_web/elements/shared/index.d.ts +2 -0
- package/dist_ts_web/elements/shared/index.js +3 -0
- package/dist_ts_web/elements/shared/ops-sectionheading.d.ts +5 -0
- package/dist_ts_web/elements/shared/ops-sectionheading.js +82 -0
- package/dist_ts_web/index.d.ts +1 -0
- package/dist_ts_web/index.js +10 -0
- package/dist_ts_web/plugins.d.ts +6 -0
- package/dist_ts_web/plugins.js +11 -0
- package/dist_ts_web/router.d.ts +19 -0
- package/dist_ts_web/router.js +91 -0
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +33 -3
- package/ts/config/classes.route-config-manager.ts +7 -6
- package/ts/opsserver/handlers/vpn.handler.ts +3 -3
- package/ts/vpn/classes.vpn-manager.ts +56 -5
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +2 -2
- package/ts_web/elements/ops-view-vpn.ts +4 -4
package/dist_serve/bundle.js
CHANGED
|
@@ -40174,7 +40174,7 @@ Customer Support Team`}};async onActivate(b){this.appui=b.appui,this.appui.setCo
|
|
|
40174
40174
|
}
|
|
40175
40175
|
`];render(){return w`
|
|
40176
40176
|
<dees-appui></dees-appui>
|
|
40177
|
-
`}async firstUpdated(){let o=this.shadowRoot?.querySelector("dees-appui");o&&(o.configure({branding:{logoIcon:"lucide:Box",logoText:"serve.zone"},appBar:{showSearch:!0,breadcrumbs:"serve.zone",menuItems:[{name:"File",action:i(async()=>{},"action"),submenu:[{name:"New Service",shortcut:"Cmd+N",action:i(async()=>{console.log("New Service")},"action")},{name:"Import Configuration",action:i(async()=>{console.log("Import")},"action")},{name:"Export Configuration",action:i(async()=>{console.log("Export")},"action")},{divider:!0},{name:"Preferences",shortcut:"Cmd+,",action:i(async()=>{o.navigateToView("settings")},"action")}]},{name:"View",action:i(async()=>{},"action"),submenu:[{name:"Dashboard",shortcut:"Cmd+1",action:i(async()=>{o.navigateToView("dashboard")},"action")},{name:"Services",shortcut:"Cmd+2",action:i(async()=>{o.navigateToView("services")},"action")},{name:"Network",shortcut:"Cmd+3",action:i(async()=>{o.navigateToView("network")},"action")},{divider:!0},{name:"Activity Log",shortcut:"Cmd+Shift+A",action:i(async()=>{o.toggleActivityLog()},"action")},{name:"Toggle Sidebar",shortcut:"Cmd+B",action:i(async()=>{o.setMainMenuCollapsed(!o.mainmenuCollapsed)},"action")}]},{name:"Services",action:i(async()=>{},"action"),submenu:[{name:"Deploy New Service",action:i(async()=>{console.log("Deploy")},"action")},{name:"Start All",action:i(async()=>{console.log("Start all")},"action")},{name:"Stop All",action:i(async()=>{console.log("Stop all")},"action")},{divider:!0},{name:"Garbage Collect",action:i(async()=>{console.log("GC")},"action")}]},{name:"Help",action:i(async()=>{},"action"),submenu:[{name:"Documentation",action:i(async()=>{window.open("https://docs.serve.zone","_blank")},"action")},{name:"Release Notes",action:i(async()=>{console.log("Release notes")},"action")},{divider:!0},{name:"About serve.zone",action:i(async()=>{console.log("About")},"action")}]}]},views:[{id:"dashboard",name:"Dashboard",iconName:"lucide:LayoutDashboard",content:"sz-demo-view-dashboard"},{id:"services",name:"Services",iconName:"lucide:Server",content:"sz-demo-view-services"},{id:"network",name:"Network",iconName:"lucide:Network",content:"sz-demo-view-network"},{id:"registries",name:"Registries",iconName:"lucide:Archive",content:"sz-demo-view-registries"},{id:"tokens",name:"Tokens",iconName:"lucide:Key",content:"sz-demo-view-tokens"},{id:"mta",name:"Email / MTA",iconName:"lucide:Mail",content:"sz-demo-view-mta"},{id:"routes",name:"Routes",iconName:"lucide:Route",content:"sz-demo-view-routes"},{id:"settings",name:"Settings",iconName:"lucide:Settings",content:"sz-demo-view-settings"}],mainMenu:{sections:[{name:"Overview",views:["dashboard"]},{name:"Infrastructure",views:["services","network","registries","mta","routes"]},{name:"Administration",views:["tokens","settings"]}]},defaultView:"dashboard",onViewChange:i((l,h)=>{console.log("View changed to:",l,h)},"onViewChange")}),o.setUser({name:"Admin User",email:"admin@serve.zone",status:"online"}),o.setProfileMenuItems([{name:"Profile",iconName:"lucide:User",action:i(async()=>{console.log("Profile")},"action")},{name:"Preferences",iconName:"lucide:SlidersHorizontal",action:i(async()=>{console.log("Preferences")},"action")},{divider:!0},{name:"Sign Out",iconName:"lucide:LogOut",action:i(async()=>{console.log("Sign Out")},"action")}]))}static{Mva(r,a)}};return n=r})();var xu={};it(xu,{TypedSocket:()=>nqe});var sqe={};it(sqe,{sha256FromString:()=>Cva});var uH={};it(uH,{Smartenv:()=>iqe});var rqe=K1(Qaa(),1);var iqe=class{static{i(this,"Smartenv")}constructor(){this.loadedScripts=[]}async getEnvAwareModule(e){if(this.isNode)return await this.getSafeNodeModule(e.nodeModuleName);if(this.isBrowser)return await this.getSafeWebModule(e.webUrlArg,e.getFunction);console.error("platform for loading not supported by smartenv")}async getSafeNodeModule(e){if(!this.isNode){console.error(`You tried to load a node module in a wrong context: ${e}`);return}return new Function(`return import('${e}')`)()}async getSafeWebModule(e,a){if(!this.isBrowser){console.error("You tried to load a web module in a wrong context");return}if(this.loadedScripts.includes(e))return a();this.loadedScripts.push(e);let r=rqe.defer();if(globalThis.importScripts)globalThis.importScripts(e),r.resolve();else{let s=document.createElement("script");s.onload=()=>{r.resolve()},s.src=e,document.head.appendChild(s)}return await r.promise,a()}get runtimeEnv(){return typeof process<"u"?"node":"browser"}get isBrowser(){return!this.isNode}get userAgent(){return this.isBrowser?navigator.userAgent:"undefined"}get isNode(){return this.runtimeEnv==="node"}get nodeVersion(){return process.version}get isCI(){return this.isNode?!!process.env.CI:!1}async isMacAsync(){return this.isNode?(await this.getSafeNodeModule("os")).platform()==="darwin":!1}async isWindowsAsync(){return this.isNode?(await this.getSafeNodeModule("os")).platform()==="win32":!1}async isLinuxAsync(){return this.isNode?(await this.getSafeNodeModule("os")).platform()==="linux":!1}async printEnv(){this.isNode?(console.log("running on NODE"),console.log("node version is "+this.nodeVersion)):(console.log("running on BROWSER"),console.log("browser is "+this.userAgent))}};var Sva=i(t=>{let e=[],a=new DataView(t);for(let r=0;r<a.byteLength;r+=4){let n=a.getUint32(r).toString(16),o="00000000",l=(o+n).slice(-o.length);e.push(l)}return e.join("")},"hex"),Cva=i(async t=>{let e=new uH.Smartenv;if(e.isBrowser){let a=new TextEncoder().encode(t),r=await crypto.subtle.digest("SHA-256",a);return Sva(r)}else if(e.isNode)return await(await e.getSafeNodeModule("@pushrocks/smarthash")).sha256FromString(t)},"sha256FromString");J5();u5();O2();vse();cr();ns();a0();UW();var oqe="__typedsocket_tag__";function Tva(t){return{peer:t,async getTagById(e){if(!t.tags.has(e))return;let a=t.data.get(`${oqe}${e}`);return{id:e,payload:a}}}}i(Tva,"wrapSmartServePeer");var nqe=class t{static{i(this,"TypedSocket")}static async createClient(e,a,r={}){let n={...{autoReconnect:!0,maxRetries:100,initialBackoffMs:1e3,maxBackoffMs:6e4},...r},o=new t("client",e);return o.clientOptions=n,o.serverUrl=a,o.currentBackoff=n.initialBackoffMs,await o.connect(),o}static{this.useWindowLocationOriginUrl=()=>Hi.Smarturl.createFromUrl(globalThis.location.origin).toString()}static fromSmartServe(e,a){let r=new Map;t.registerTagHandlers(a);let s=new t("server",a);return s.smartServeRef=e,s.smartServeConnectionWrappers=r,s}static registerTagHandlers(e){e.addTypedHandler(new a1.TypedHandler("__typedsocket_setTag",async(a,r)=>{let s=r?.localData?.peer;return s?(s.tags.add(a.name),s.data.set(`${oqe}${a.name}`,a.payload),{success:!0}):(console.warn("setTag: No peer found in request context"),{success:!1})})),e.addTypedHandler(new a1.TypedHandler("__typedsocket_removeTag",async(a,r)=>{let s=r?.localData?.peer;return s?(s.tags.delete(a.name),s.data.delete(`${oqe}${a.name}`),{success:!0}):(console.warn("removeTag: No peer found in request context"),{success:!1})}))}constructor(e,a){this.statusSubject=new Wt.rxjs.Subject,this.connectionStatus="new",this.websocket=null,this.clientOptions=null,this.serverUrl="",this.retryCount=0,this.currentBackoff=1e3,this.pendingRequests=new Map,this.smartServeRef=null,this.smartServeConnectionWrappers=new Map,this.side=e,this.typedrouter=a}async connect(){let e=Je.defer();this.updateStatus("connecting");let a=this.toWebSocketUrl(this.serverUrl);console.log(`TypedSocket connecting to ${a}...`),this.websocket=new WebSocket(a);let r=setTimeout(()=>{this.connectionStatus!=="connected"&&(console.warn("TypedSocket connection timeout"),this.websocket?.close(),e.reject(new Error("Connection timeout")))},1e4);this.websocket.onopen=()=>{clearTimeout(r),console.log("TypedSocket connected!"),this.updateStatus("connected"),this.retryCount=0,this.currentBackoff=this.clientOptions?.initialBackoffMs??1e3,e.resolve()},this.websocket.onmessage=async s=>{await this.handleMessage(s.data)},this.websocket.onclose=()=>{clearTimeout(r),this.handleDisconnect()},this.websocket.onerror=s=>{console.error("TypedSocket WebSocket error:",s)};try{await e.promise}catch(s){if(clearTimeout(r),this.clientOptions?.autoReconnect)await this.scheduleReconnect();else throw s}}toWebSocketUrl(e){let a=new URL(e);return`${a.protocol==="https:"?"wss:":"ws:"}//${a.host}${a.pathname}`}async handleMessage(e){try{let a=typeof e=="string"?e:new TextDecoder().decode(e),r=ri.parse(a);if(r.correlation?.id&&this.pendingRequests.has(r.correlation.id)){let n=this.pendingRequests.get(r.correlation.id);this.pendingRequests.delete(r.correlation.id),n.resolve(r);return}let s=await this.typedrouter.routeAndAddResponse(r);s&&this.websocket?.readyState===WebSocket.OPEN&&this.websocket.send(ri.stringify(s))}catch(a){console.error("TypedSocket failed to process message:",a)}}handleDisconnect(){if(this.connectionStatus!=="disconnected"){this.updateStatus("disconnected");for(let[e,a]of this.pendingRequests)a.reject(new Error("TypedSocket disconnected"));this.pendingRequests.clear(),this.clientOptions?.autoReconnect&&this.retryCount<this.clientOptions.maxRetries&&this.scheduleReconnect()}}async scheduleReconnect(){if(!this.clientOptions)return;this.updateStatus("reconnecting"),this.retryCount++;let e=this.currentBackoff*.2*(Math.random()*2-1),a=Math.min(this.currentBackoff+e,this.clientOptions.maxBackoffMs);console.log(`TypedSocket reconnecting in ${Math.round(a)}ms (attempt ${this.retryCount}/${this.clientOptions.maxRetries})`),await St.delayFor(a),this.currentBackoff=Math.min(this.currentBackoff*2,this.clientOptions.maxBackoffMs);try{await this.connect()}catch(r){console.error("TypedSocket reconnection failed:",r)}}updateStatus(e){this.connectionStatus!==e&&(this.connectionStatus=e,this.statusSubject.next(e))}async sendRequest(e){if(!this.websocket||this.websocket.readyState!==WebSocket.OPEN)throw new Error("WebSocket not connected");return new Promise((a,r)=>{let s=setTimeout(()=>{this.pendingRequests.delete(e.correlation.id),r(new Error("Request timeout"))},3e4);this.pendingRequests.set(e.correlation.id,{resolve:i(n=>{clearTimeout(s),a(n)},"resolve"),reject:i(n=>{clearTimeout(s),r(n)},"reject")}),this.websocket.send(ri.stringify(e))})}createTypedRequest(e,a){let r=i(async s=>{if(this.side==="client")return this.sendRequest(s);if(!this.smartServeRef)throw new Error("Server not initialized");let n=a;if(!n){let l=this.smartServeRef.getWebSocketConnections();if(l.length===1){let h=l[0];n=this.getOrCreateWrapper(h)}else throw l.length===0?new Error("No WebSocket connections available"):new Error("Multiple connections available - specify targetConnection")}let o=await this.typedrouter.fireEventInterestMap.addInterest(s.correlation.id,s);return n.peer.send(ri.stringify(s)),await o.interestFullfilled},"postMethod");return new a1.TypedRequest(new a1.TypedTarget({postMethod:r}),e)}getStatus(){return this.connectionStatus}async stop(){this.side==="client"?(this.clientOptions&&(this.clientOptions.autoReconnect=!1),this.websocket&&(this.websocket.close(),this.websocket=null),this.pendingRequests.clear()):this.smartServeConnectionWrappers.clear()}async setTag(e,a){if(this.side!=="client")throw new Error("setTag is only available on clients");if(!(await this.createTypedRequest("__typedsocket_setTag").fire({name:e,payload:a})).success)throw new Error("Failed to set tag on server")}async removeTag(e){if(this.side!=="client")throw new Error("removeTag is only available on clients");if(!(await this.createTypedRequest("__typedsocket_removeTag").fire({name:e})).success)throw new Error("Failed to remove tag on server")}getOrCreateWrapper(e){let a=this.smartServeConnectionWrappers.get(e.id);return a||(a=Tva(e),this.smartServeConnectionWrappers.set(e.id,a)),a}async findAllTargetConnections(e){if(this.side!=="server"||!this.smartServeRef)throw new Error("findAllTargetConnections is only available on servers");let a=[];for(let r of this.smartServeRef.getWebSocketConnections()){let s=this.getOrCreateWrapper(r);await e(s)&&a.push(s)}return a}async findTargetConnection(e){return(await this.findAllTargetConnections(e))[0]}async findAllTargetConnectionsByTag(e,a){if(this.side!=="server"||!this.smartServeRef)throw new Error("findAllTargetConnectionsByTag is only available on servers");let r=this.smartServeRef.getWebSocketConnectionsByTag(e),s=[];for(let n of r){let o=this.getOrCreateWrapper(n);if(a!==void 0){let l=await o.getTagById(e);if(ri.stringify(l?.payload)!==ri.stringify(a))continue}s.push(o)}return s}async findTargetConnectionByTag(e,a){return(await this.findAllTargetConnectionsByTag(e,a))[0]}};de();Xa();var vt=gt;u5();var Jaa={};var e1a={};var Hs=new vt.plugins.smartstate.Smartstate,Ka=await Hs.getStatePart("login",{identity:null,isLoggedIn:!1},"persistent"),lr=await Hs.getStatePart("stats",{serverStats:null,emailStats:null,dnsStats:null,securityMetrics:null,lastUpdated:0,isLoading:!1,error:null},"soft"),H6=await Hs.getStatePart("config",{config:null,isLoading:!1,error:null}),Lva=i(()=>{let t=typeof window<"u"?window.location.pathname:"/",e=["overview","network","emails","logs","routes","apitokens","configuration","security","certificates","remoteingress"],r=t.split("/").filter(Boolean)[0];return e.includes(r)?r:"overview"},"getInitialView"),ci=await Hs.getStatePart("ui",{activeView:Lva(),sidebarCollapsed:!1,autoRefresh:!0,refreshInterval:1e3,theme:"light"}),jo=await Hs.getStatePart("logs",{recentLogs:[],isStreaming:!1,filters:{}},"soft"),$2=await Hs.getStatePart("network",{connections:[],connectionsByIP:{},throughputRate:{bytesInPerSecond:0,bytesOutPerSecond:0},totalBytes:{in:0,out:0},topIPs:[],throughputByIP:[],throughputHistory:[],requestsPerSecond:0,requestsTotal:0,backends:[],lastUpdated:0,isLoading:!1,error:null},"soft"),NX=await Hs.getStatePart("emailOps",{emails:[],isLoading:!1,error:null,lastUpdated:0},"soft"),di=await Hs.getStatePart("certificates",{certificates:[],summary:{total:0,valid:0,expiring:0,expired:0,failed:0,unknown:0},isLoading:!1,error:null,lastUpdated:0},"soft"),S1=await Hs.getStatePart("remoteIngress",{edges:[],statuses:[],selectedEdgeId:null,newEdgeId:null,isLoading:!1,error:null,lastUpdated:0},"soft"),pa=await Hs.getStatePart("routeManagement",{mergedRoutes:[],warnings:[],apiTokens:[],isLoading:!1,error:null,lastUpdated:0},"soft"),Jt=i(()=>{let t=Ka.getState().identity;return t&&t.expiresAt&&t.expiresAt<Date.now()?{identity:null}:{identity:t}},"getActionContext"),o1a=Ka.createAction(async(t,e)=>{let a=new vt.plugins.typedrequest.TypedRequest("/typedrequest","adminLoginWithUsernameAndPassword");try{let r=await a.fire({username:e.username,password:e.password});return r.identity?{identity:r.identity,isLoggedIn:!0}:t.getState()}catch(r){return console.error("Login failed:",r),t.getState()}}),wu=Ka.createAction(async t=>{let e=Jt();if(e.identity){let a=new vt.plugins.typedrequest.TypedRequest("/typedrequest","adminLogout");try{await a.fire({identity:e.identity})}catch(r){console.error("Logout error:",r)}}return{identity:null,isLoggedIn:!1}}),Mu=lr.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getCombinedMetrics").fire({identity:e.identity,sections:{server:!0,email:!0,dns:!0,security:!0,network:!1}});return{serverStats:s.metrics.server||a.serverStats,emailStats:s.metrics.email||a.emailStats,dnsStats:s.metrics.dns||a.dnsStats,securityMetrics:s.metrics.security||a.securityMetrics,lastUpdated:Date.now(),isLoading:!1,error:null}}catch(r){return{...a,isLoading:!1,error:r.message||"Failed to fetch statistics"}}}),IX=H6.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{return{config:(await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getConfiguration").fire({identity:e.identity})).config,isLoading:!1,error:null}}catch(r){return{...a,isLoading:!1,error:r.message||"Failed to fetch configuration"}}}),FX=jo.createAction(async(t,e)=>{let a=Jt();if(!a.identity)return t.getState();let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRecentLogs").fire({identity:a.identity,limit:e.limit||100,level:e.level,category:e.category});return{...t.getState(),recentLogs:s.logs}}),Bji=ci.createAction(async t=>{let e=t.getState();return{...e,autoRefresh:!e.autoRefresh}}),Hji=ci.createAction(async(t,e)=>{let a=t.getState();return e==="network"&&a.activeView!=="network"&&setTimeout(()=>{$2.dispatchAction(pqe,null)},100),e==="certificates"&&a.activeView!=="certificates"&&setTimeout(()=>{di.dispatchAction(xl,null)},100),e==="routes"&&a.activeView!=="routes"&&setTimeout(()=>{pa.dispatchAction(D2,null)},100),e==="apitokens"&&a.activeView!=="apitokens"&&setTimeout(()=>{pa.dispatchAction(yl,null)},100),e==="remoteingress"&&a.activeView!=="remoteingress"&&setTimeout(()=>{S1.dispatchAction(vl,null)},100),{...a,activeView:e}}),pqe=$2.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getActiveConnections").fire({identity:e.identity}),o=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getNetworkStats").fire({identity:e.identity}),l={};return o.connectionsByIP&&Array.isArray(o.connectionsByIP)?o.connectionsByIP.forEach(h=>{l[h.ip]=h.count}):s.connections.forEach(h=>{let p=h.remoteAddress;l[p]=(l[p]||0)+1}),{connections:s.connections,connectionsByIP:l,throughputRate:o.throughputRate||{bytesInPerSecond:0,bytesOutPerSecond:0},totalBytes:o.totalDataTransferred?{in:o.totalDataTransferred.bytesIn,out:o.totalDataTransferred.bytesOut}:{in:0,out:0},topIPs:o.topIPs||[],throughputByIP:o.throughputByIP||[],throughputHistory:o.throughputHistory||[],requestsPerSecond:o.requestsPerSecond||0,requestsTotal:o.requestsTotal||0,backends:o.backends||[],lastUpdated:Date.now(),isLoading:!1,error:null}}catch(r){return console.error("Failed to fetch network stats:",r),{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch network stats"}}}),n1a=NX.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{return{emails:(await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getAllEmails").fire({identity:e.identity})).emails,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch emails"}}}),xl=di.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getCertificateOverview").fire({identity:e.identity});return{certificates:s.certificates,summary:s.summary,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch certificate overview"}}}),l1a=di.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","reprovisionCertificateDomain").fire({identity:r.identity,domain:e}),await a.dispatch(xl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to reprovision certificate"}}}),c1a=di.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteCertificate").fire({identity:r.identity,domain:e}),await a.dispatch(xl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete certificate"}}}),d1a=di.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","importCertificate").fire({identity:r.identity,cert:e}),await a.dispatch(xl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to import certificate"}}});async function u1a(t){let e=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","exportCertificate").fire({identity:e.identity,domain:t})}i(u1a,"fetchCertificateExport");async function fqe(t){let e=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRemoteIngressConnectionToken").fire({identity:e.identity,edgeId:t})}i(fqe,"fetchConnectionToken");var vl=S1.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let r=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRemoteIngresses"),s=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRemoteIngressStatus"),[n,o]=await Promise.all([r.fire({identity:e.identity}),s.fire({identity:e.identity})]);return{...a,edges:n.edges,statuses:o.statuses,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch remote ingress data"}}}),p1a=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{let o=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","createRemoteIngress").fire({identity:r.identity,name:e.name,listenPorts:e.listenPorts,autoDerivePorts:e.autoDerivePorts,tags:e.tags});return o.success?(await a.dispatch(vl,null),{...t.getState(),newEdgeId:o.edge.id}):s}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to create edge"}}}),f1a=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteRemoteIngress").fire({identity:r.identity,id:e}),await a.dispatch(vl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete edge"}}}),h1a=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","updateRemoteIngress").fire({identity:r.identity,id:e.id,name:e.name,listenPorts:e.listenPorts,autoDerivePorts:e.autoDerivePorts,tags:e.tags}),await a.dispatch(vl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to update edge"}}}),m1a=S1.createAction(async(t,e)=>{let a=Jt(),r=t.getState();try{return(await new vt.plugins.typedrequest.TypedRequest("/typedrequest","regenerateRemoteIngressSecret").fire({identity:a.identity,id:e})).success?{...r,newEdgeId:e}:r}catch(s){return{...r,error:s instanceof Error?s.message:"Failed to regenerate secret"}}}),g1a=S1.createAction(async t=>({...t.getState(),newEdgeId:null})),hqe=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","updateRemoteIngress").fire({identity:r.identity,id:e.id,enabled:e.enabled}),await a.dispatch(vl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle edge"}}}),ui=await Hs.getStatePart("vpn",{clients:[],status:null,isLoading:!1,error:null,lastUpdated:0,newClientConfig:null},"soft"),yu=ui.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let r=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getVpnClients"),s=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getVpnStatus"),[n,o]=await Promise.all([r.fire({identity:e.identity}),s.fire({identity:e.identity})]);return{...a,clients:n.clients,status:o.status,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch VPN data"}}}),b1a=ui.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{let o=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","createVpnClient").fire({identity:r.identity,clientId:e.clientId,tags:e.tags,description:e.description});return o.success?{...await a.dispatch(yu,null),newClientConfig:o.wireguardConfig||null}:{...s,error:o.message||"Failed to create client"}}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to create VPN client"}}}),v1a=ui.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteVpnClient").fire({identity:r.identity,clientId:e}),await a.dispatch(yu,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete VPN client"}}}),x1a=ui.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{let n=e.enabled?"enableVpnClient":"disableVpnClient";return await new vt.plugins.typedrequest.TypedRequest("/typedrequest",n).fire({identity:r.identity,clientId:e.clientId}),await a.dispatch(yu,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle VPN client"}}}),y1a=ui.createAction(async t=>({...t.getState(),newClientConfig:null})),D2=pa.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getMergedRoutes").fire({identity:e.identity});return{...a,mergedRoutes:s.routes,warnings:s.warnings,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch routes"}}}),w1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","createRoute").fire({identity:r.identity,route:e.route,enabled:e.enabled}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to create route"}}}),M1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteRoute").fire({identity:r.identity,id:e}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete route"}}}),k1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","toggleRoute").fire({identity:r.identity,id:e.id,enabled:e.enabled}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle route"}}}),mqe=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","setRouteOverride").fire({identity:r.identity,routeName:e.routeName,enabled:e.enabled}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to set override"}}}),z1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","removeRouteOverride").fire({identity:r.identity,routeName:e}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to remove override"}}}),yl=pa.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","listApiTokens").fire({identity:e.identity});return{...a,apiTokens:s.tokens}}catch(r){return{...a,error:r instanceof Error?r.message:"Failed to fetch tokens"}}});async function S1a(t,e,a){let r=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","createApiToken").fire({identity:r.identity,name:t,scopes:e,expiresInDays:a})}i(S1a,"createApiToken");async function C1a(t){let e=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","rollApiToken").fire({identity:e.identity,id:t})}i(C1a,"rollApiToken");var _1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","revokeApiToken").fire({identity:r.identity,id:e}),await a.dispatch(yl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to revoke token"}}}),gqe=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","toggleApiToken").fire({identity:r.identity,id:e.id,enabled:e.enabled}),await a.dispatch(yl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle token"}}}),O6=null,t1a=new vt.plugins.typedrequest.TypedRouter,EX=[],lqe=!1;function $va(){if(lqe=!1,EX.length===0)return;let t=jo.getState(),e=[...t.recentLogs,...EX];EX=[],e.length>2e3&&e.splice(0,e.length-2e3),jo.setState({...t,recentLogs:e})}i($va,"flushLogEntries"),t1a.addTypedHandler(new vt.plugins.typedrequest.TypedHandler("pushLogEntry",async t=>(EX.push(t.entry),lqe||(lqe=!0,requestAnimationFrame($va)),{})));async function cqe(){if(!O6)try{O6=await xu.TypedSocket.createClient(t1a,xu.TypedSocket.useWindowLocationOriginUrl()),await O6.setTag("role","ops_dashboard")}catch(t){console.error("TypedSocket connection failed:",t),O6=null}}i(cqe,"connectSocket");async function a1a(){if(O6){try{await O6.stop()}catch{}O6=null}}i(a1a,"disconnectSocket");var dqe=!1;async function Dva(){if(!dqe){dqe=!0;try{await Ava()}finally{dqe=!1}}}i(Dva,"dispatchCombinedRefreshAction");async function Ava(){let t=Jt();if(!t.identity)return;let e=ci.getState().activeView;try{let r=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getCombinedMetrics").fire({identity:t.identity,sections:{server:!0,email:!0,dns:!0,security:!0,network:e==="network"}}),s=lr.getState();if(lr.setState({...s,serverStats:r.metrics.server||s.serverStats,emailStats:r.metrics.email||s.emailStats,dnsStats:r.metrics.dns||s.dnsStats,securityMetrics:r.metrics.security||s.securityMetrics,lastUpdated:Date.now(),isLoading:!1,error:null}),r.metrics.network&&e==="network"){let n=r.metrics.network,o={};n.connectionDetails.forEach(l=>{o[l.remoteAddress]=(o[l.remoteAddress]||0)+1});try{let h=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getActiveConnections").fire({identity:t.identity});$2.setState({...$2.getState(),connections:h.connections,connectionsByIP:o,throughputRate:{bytesInPerSecond:n.totalBandwidth.in,bytesOutPerSecond:n.totalBandwidth.out},totalBytes:n.totalBytes||{in:0,out:0},topIPs:n.topEndpoints.map(p=>({ip:p.endpoint,count:p.requests})),throughputByIP:n.topEndpoints.map(p=>({ip:p.endpoint,in:p.bandwidth?.in||0,out:p.bandwidth?.out||0})),throughputHistory:n.throughputHistory||[],requestsPerSecond:n.requestsPerSecond||0,requestsTotal:n.requestsTotal||0,backends:n.backends||[],lastUpdated:Date.now(),isLoading:!1,error:null})}catch(l){console.error("Failed to fetch connections:",l),$2.setState({...$2.getState(),connections:[],connectionsByIP:o,throughputRate:{bytesInPerSecond:n.totalBandwidth.in,bytesOutPerSecond:n.totalBandwidth.out},totalBytes:n.totalBytes||{in:0,out:0},topIPs:n.topEndpoints.map(h=>({ip:h.endpoint,count:h.requests})),throughputByIP:n.topEndpoints.map(h=>({ip:h.endpoint,in:h.bandwidth?.in||0,out:h.bandwidth?.out||0})),throughputHistory:n.throughputHistory||[],requestsPerSecond:n.requestsPerSecond||0,requestsTotal:n.requestsTotal||0,backends:n.backends||[],lastUpdated:Date.now(),isLoading:!1,error:null})}}if(e==="certificates")try{await di.dispatchAction(xl,null)}catch(n){console.error("Certificate refresh failed:",n)}if(e==="remoteingress")try{await S1.dispatchAction(vl,null)}catch(n){console.error("Remote ingress refresh failed:",n)}if(e==="vpn")try{await ui.dispatchAction(yu,null)}catch(n){console.error("VPN refresh failed:",n)}}catch(a){console.error("Combined refresh failed:",a);let r=String(a);(r.includes("invalid")||r.includes("unauthorized")||r.includes("401"))&&(await Ka.dispatchAction(wu,null),window.location.reload())}}i(Ava,"dispatchCombinedRefreshActionInner");var Pva=lr.createAction(async t=>(await Dva(),t.getState())),B6=null,uqe=i(()=>{let t=ci.getState(),e=Ka.getState();t.autoRefresh&&e.isLoggedIn?(B6&&(B6.dispose(),B6=null),B6=lr.createScheduledAction({action:Pva,payload:void 0,intervalMs:t.refreshInterval,autoPause:"visibility"})):B6&&(B6.dispose(),B6=null)},"startAutoRefresh"),r1a=ci.getState().autoRefresh,i1a=ci.getState().refreshInterval,s1a=Ka.getState().isLoggedIn;ci.select(t=>({autoRefresh:t.autoRefresh,refreshInterval:t.refreshInterval})).subscribe(t=>{(t.autoRefresh!==r1a||t.refreshInterval!==i1a)&&(r1a=t.autoRefresh,i1a=t.refreshInterval,uqe())}),Ka.select(t=>t.isLoggedIn).subscribe(t=>{t!==s1a&&(s1a=t,uqe(),t?cqe():a1a())}),document.addEventListener("visibilitychange",()=>{document.hidden?a1a():Ka.getState().isLoggedIn&&cqe()}),uqe(),Ka.getState().isLoggedIn&&cqe();var Eva=vt.plugins.smartrouter.SmartRouter,bqe=["overview","network","emails","logs","routes","apitokens","configuration","security","certificates","remoteingress","vpn"],vqe=class{static{i(this,"AppRouter")}router;initialized=!1;suppressStateUpdate=!1;constructor(){this.router=new Eva({debug:!1})}init(){this.initialized||(this.setupRoutes(),this.setupStateSync(),this.handleInitialRoute(),this.initialized=!0)}setupRoutes(){for(let e of bqe)this.router.on(`/${e}`,async()=>{this.updateViewState(e)});this.router.on("/",async()=>{this.navigateTo("/overview")})}setupStateSync(){ci.select().subscribe(e=>{if(this.suppressStateUpdate)return;let a=window.location.pathname,r=`/${e.activeView}`;a!==r&&(this.suppressStateUpdate=!0,this.router.pushUrl(r),this.suppressStateUpdate=!1)})}handleInitialRoute(){let e=window.location.pathname;if(!e||e==="/")this.router.pushUrl("/overview");else{let r=e.split("/").filter(Boolean)[0];bqe.includes(r)?this.updateViewState(r):this.router.pushUrl("/overview")}}updateViewState(e){this.suppressStateUpdate=!0;let a=ci.getState();a.activeView!==e&&ci.setState({...a,activeView:e}),this.suppressStateUpdate=!1}navigateTo(e){this.router.pushUrl(e)}navigateToView(e){bqe.includes(e)?this.navigateTo(`/${e}`):this.navigateTo("/overview")}getCurrentView(){return ci.getState().activeView}destroy(){this.router.destroy(),this.initialized=!1}},ku=new vqe;de();var n1=Z`
|
|
40177
|
+
`}async firstUpdated(){let o=this.shadowRoot?.querySelector("dees-appui");o&&(o.configure({branding:{logoIcon:"lucide:Box",logoText:"serve.zone"},appBar:{showSearch:!0,breadcrumbs:"serve.zone",menuItems:[{name:"File",action:i(async()=>{},"action"),submenu:[{name:"New Service",shortcut:"Cmd+N",action:i(async()=>{console.log("New Service")},"action")},{name:"Import Configuration",action:i(async()=>{console.log("Import")},"action")},{name:"Export Configuration",action:i(async()=>{console.log("Export")},"action")},{divider:!0},{name:"Preferences",shortcut:"Cmd+,",action:i(async()=>{o.navigateToView("settings")},"action")}]},{name:"View",action:i(async()=>{},"action"),submenu:[{name:"Dashboard",shortcut:"Cmd+1",action:i(async()=>{o.navigateToView("dashboard")},"action")},{name:"Services",shortcut:"Cmd+2",action:i(async()=>{o.navigateToView("services")},"action")},{name:"Network",shortcut:"Cmd+3",action:i(async()=>{o.navigateToView("network")},"action")},{divider:!0},{name:"Activity Log",shortcut:"Cmd+Shift+A",action:i(async()=>{o.toggleActivityLog()},"action")},{name:"Toggle Sidebar",shortcut:"Cmd+B",action:i(async()=>{o.setMainMenuCollapsed(!o.mainmenuCollapsed)},"action")}]},{name:"Services",action:i(async()=>{},"action"),submenu:[{name:"Deploy New Service",action:i(async()=>{console.log("Deploy")},"action")},{name:"Start All",action:i(async()=>{console.log("Start all")},"action")},{name:"Stop All",action:i(async()=>{console.log("Stop all")},"action")},{divider:!0},{name:"Garbage Collect",action:i(async()=>{console.log("GC")},"action")}]},{name:"Help",action:i(async()=>{},"action"),submenu:[{name:"Documentation",action:i(async()=>{window.open("https://docs.serve.zone","_blank")},"action")},{name:"Release Notes",action:i(async()=>{console.log("Release notes")},"action")},{divider:!0},{name:"About serve.zone",action:i(async()=>{console.log("About")},"action")}]}]},views:[{id:"dashboard",name:"Dashboard",iconName:"lucide:LayoutDashboard",content:"sz-demo-view-dashboard"},{id:"services",name:"Services",iconName:"lucide:Server",content:"sz-demo-view-services"},{id:"network",name:"Network",iconName:"lucide:Network",content:"sz-demo-view-network"},{id:"registries",name:"Registries",iconName:"lucide:Archive",content:"sz-demo-view-registries"},{id:"tokens",name:"Tokens",iconName:"lucide:Key",content:"sz-demo-view-tokens"},{id:"mta",name:"Email / MTA",iconName:"lucide:Mail",content:"sz-demo-view-mta"},{id:"routes",name:"Routes",iconName:"lucide:Route",content:"sz-demo-view-routes"},{id:"settings",name:"Settings",iconName:"lucide:Settings",content:"sz-demo-view-settings"}],mainMenu:{sections:[{name:"Overview",views:["dashboard"]},{name:"Infrastructure",views:["services","network","registries","mta","routes"]},{name:"Administration",views:["tokens","settings"]}]},defaultView:"dashboard",onViewChange:i((l,h)=>{console.log("View changed to:",l,h)},"onViewChange")}),o.setUser({name:"Admin User",email:"admin@serve.zone",status:"online"}),o.setProfileMenuItems([{name:"Profile",iconName:"lucide:User",action:i(async()=>{console.log("Profile")},"action")},{name:"Preferences",iconName:"lucide:SlidersHorizontal",action:i(async()=>{console.log("Preferences")},"action")},{divider:!0},{name:"Sign Out",iconName:"lucide:LogOut",action:i(async()=>{console.log("Sign Out")},"action")}]))}static{Mva(r,a)}};return n=r})();var xu={};it(xu,{TypedSocket:()=>nqe});var sqe={};it(sqe,{sha256FromString:()=>Cva});var uH={};it(uH,{Smartenv:()=>iqe});var rqe=K1(Qaa(),1);var iqe=class{static{i(this,"Smartenv")}constructor(){this.loadedScripts=[]}async getEnvAwareModule(e){if(this.isNode)return await this.getSafeNodeModule(e.nodeModuleName);if(this.isBrowser)return await this.getSafeWebModule(e.webUrlArg,e.getFunction);console.error("platform for loading not supported by smartenv")}async getSafeNodeModule(e){if(!this.isNode){console.error(`You tried to load a node module in a wrong context: ${e}`);return}return new Function(`return import('${e}')`)()}async getSafeWebModule(e,a){if(!this.isBrowser){console.error("You tried to load a web module in a wrong context");return}if(this.loadedScripts.includes(e))return a();this.loadedScripts.push(e);let r=rqe.defer();if(globalThis.importScripts)globalThis.importScripts(e),r.resolve();else{let s=document.createElement("script");s.onload=()=>{r.resolve()},s.src=e,document.head.appendChild(s)}return await r.promise,a()}get runtimeEnv(){return typeof process<"u"?"node":"browser"}get isBrowser(){return!this.isNode}get userAgent(){return this.isBrowser?navigator.userAgent:"undefined"}get isNode(){return this.runtimeEnv==="node"}get nodeVersion(){return process.version}get isCI(){return this.isNode?!!process.env.CI:!1}async isMacAsync(){return this.isNode?(await this.getSafeNodeModule("os")).platform()==="darwin":!1}async isWindowsAsync(){return this.isNode?(await this.getSafeNodeModule("os")).platform()==="win32":!1}async isLinuxAsync(){return this.isNode?(await this.getSafeNodeModule("os")).platform()==="linux":!1}async printEnv(){this.isNode?(console.log("running on NODE"),console.log("node version is "+this.nodeVersion)):(console.log("running on BROWSER"),console.log("browser is "+this.userAgent))}};var Sva=i(t=>{let e=[],a=new DataView(t);for(let r=0;r<a.byteLength;r+=4){let n=a.getUint32(r).toString(16),o="00000000",l=(o+n).slice(-o.length);e.push(l)}return e.join("")},"hex"),Cva=i(async t=>{let e=new uH.Smartenv;if(e.isBrowser){let a=new TextEncoder().encode(t),r=await crypto.subtle.digest("SHA-256",a);return Sva(r)}else if(e.isNode)return await(await e.getSafeNodeModule("@pushrocks/smarthash")).sha256FromString(t)},"sha256FromString");J5();u5();O2();vse();cr();ns();a0();UW();var oqe="__typedsocket_tag__";function Tva(t){return{peer:t,async getTagById(e){if(!t.tags.has(e))return;let a=t.data.get(`${oqe}${e}`);return{id:e,payload:a}}}}i(Tva,"wrapSmartServePeer");var nqe=class t{static{i(this,"TypedSocket")}static async createClient(e,a,r={}){let n={...{autoReconnect:!0,maxRetries:100,initialBackoffMs:1e3,maxBackoffMs:6e4},...r},o=new t("client",e);return o.clientOptions=n,o.serverUrl=a,o.currentBackoff=n.initialBackoffMs,await o.connect(),o}static{this.useWindowLocationOriginUrl=()=>Hi.Smarturl.createFromUrl(globalThis.location.origin).toString()}static fromSmartServe(e,a){let r=new Map;t.registerTagHandlers(a);let s=new t("server",a);return s.smartServeRef=e,s.smartServeConnectionWrappers=r,s}static registerTagHandlers(e){e.addTypedHandler(new a1.TypedHandler("__typedsocket_setTag",async(a,r)=>{let s=r?.localData?.peer;return s?(s.tags.add(a.name),s.data.set(`${oqe}${a.name}`,a.payload),{success:!0}):(console.warn("setTag: No peer found in request context"),{success:!1})})),e.addTypedHandler(new a1.TypedHandler("__typedsocket_removeTag",async(a,r)=>{let s=r?.localData?.peer;return s?(s.tags.delete(a.name),s.data.delete(`${oqe}${a.name}`),{success:!0}):(console.warn("removeTag: No peer found in request context"),{success:!1})}))}constructor(e,a){this.statusSubject=new Wt.rxjs.Subject,this.connectionStatus="new",this.websocket=null,this.clientOptions=null,this.serverUrl="",this.retryCount=0,this.currentBackoff=1e3,this.pendingRequests=new Map,this.smartServeRef=null,this.smartServeConnectionWrappers=new Map,this.side=e,this.typedrouter=a}async connect(){let e=Je.defer();this.updateStatus("connecting");let a=this.toWebSocketUrl(this.serverUrl);console.log(`TypedSocket connecting to ${a}...`),this.websocket=new WebSocket(a);let r=setTimeout(()=>{this.connectionStatus!=="connected"&&(console.warn("TypedSocket connection timeout"),this.websocket?.close(),e.reject(new Error("Connection timeout")))},1e4);this.websocket.onopen=()=>{clearTimeout(r),console.log("TypedSocket connected!"),this.updateStatus("connected"),this.retryCount=0,this.currentBackoff=this.clientOptions?.initialBackoffMs??1e3,e.resolve()},this.websocket.onmessage=async s=>{await this.handleMessage(s.data)},this.websocket.onclose=()=>{clearTimeout(r),this.handleDisconnect()},this.websocket.onerror=s=>{console.error("TypedSocket WebSocket error:",s)};try{await e.promise}catch(s){if(clearTimeout(r),this.clientOptions?.autoReconnect)await this.scheduleReconnect();else throw s}}toWebSocketUrl(e){let a=new URL(e);return`${a.protocol==="https:"?"wss:":"ws:"}//${a.host}${a.pathname}`}async handleMessage(e){try{let a=typeof e=="string"?e:new TextDecoder().decode(e),r=ri.parse(a);if(r.correlation?.id&&this.pendingRequests.has(r.correlation.id)){let n=this.pendingRequests.get(r.correlation.id);this.pendingRequests.delete(r.correlation.id),n.resolve(r);return}let s=await this.typedrouter.routeAndAddResponse(r);s&&this.websocket?.readyState===WebSocket.OPEN&&this.websocket.send(ri.stringify(s))}catch(a){console.error("TypedSocket failed to process message:",a)}}handleDisconnect(){if(this.connectionStatus!=="disconnected"){this.updateStatus("disconnected");for(let[e,a]of this.pendingRequests)a.reject(new Error("TypedSocket disconnected"));this.pendingRequests.clear(),this.clientOptions?.autoReconnect&&this.retryCount<this.clientOptions.maxRetries&&this.scheduleReconnect()}}async scheduleReconnect(){if(!this.clientOptions)return;this.updateStatus("reconnecting"),this.retryCount++;let e=this.currentBackoff*.2*(Math.random()*2-1),a=Math.min(this.currentBackoff+e,this.clientOptions.maxBackoffMs);console.log(`TypedSocket reconnecting in ${Math.round(a)}ms (attempt ${this.retryCount}/${this.clientOptions.maxRetries})`),await St.delayFor(a),this.currentBackoff=Math.min(this.currentBackoff*2,this.clientOptions.maxBackoffMs);try{await this.connect()}catch(r){console.error("TypedSocket reconnection failed:",r)}}updateStatus(e){this.connectionStatus!==e&&(this.connectionStatus=e,this.statusSubject.next(e))}async sendRequest(e){if(!this.websocket||this.websocket.readyState!==WebSocket.OPEN)throw new Error("WebSocket not connected");return new Promise((a,r)=>{let s=setTimeout(()=>{this.pendingRequests.delete(e.correlation.id),r(new Error("Request timeout"))},3e4);this.pendingRequests.set(e.correlation.id,{resolve:i(n=>{clearTimeout(s),a(n)},"resolve"),reject:i(n=>{clearTimeout(s),r(n)},"reject")}),this.websocket.send(ri.stringify(e))})}createTypedRequest(e,a){let r=i(async s=>{if(this.side==="client")return this.sendRequest(s);if(!this.smartServeRef)throw new Error("Server not initialized");let n=a;if(!n){let l=this.smartServeRef.getWebSocketConnections();if(l.length===1){let h=l[0];n=this.getOrCreateWrapper(h)}else throw l.length===0?new Error("No WebSocket connections available"):new Error("Multiple connections available - specify targetConnection")}let o=await this.typedrouter.fireEventInterestMap.addInterest(s.correlation.id,s);return n.peer.send(ri.stringify(s)),await o.interestFullfilled},"postMethod");return new a1.TypedRequest(new a1.TypedTarget({postMethod:r}),e)}getStatus(){return this.connectionStatus}async stop(){this.side==="client"?(this.clientOptions&&(this.clientOptions.autoReconnect=!1),this.websocket&&(this.websocket.close(),this.websocket=null),this.pendingRequests.clear()):this.smartServeConnectionWrappers.clear()}async setTag(e,a){if(this.side!=="client")throw new Error("setTag is only available on clients");if(!(await this.createTypedRequest("__typedsocket_setTag").fire({name:e,payload:a})).success)throw new Error("Failed to set tag on server")}async removeTag(e){if(this.side!=="client")throw new Error("removeTag is only available on clients");if(!(await this.createTypedRequest("__typedsocket_removeTag").fire({name:e})).success)throw new Error("Failed to remove tag on server")}getOrCreateWrapper(e){let a=this.smartServeConnectionWrappers.get(e.id);return a||(a=Tva(e),this.smartServeConnectionWrappers.set(e.id,a)),a}async findAllTargetConnections(e){if(this.side!=="server"||!this.smartServeRef)throw new Error("findAllTargetConnections is only available on servers");let a=[];for(let r of this.smartServeRef.getWebSocketConnections()){let s=this.getOrCreateWrapper(r);await e(s)&&a.push(s)}return a}async findTargetConnection(e){return(await this.findAllTargetConnections(e))[0]}async findAllTargetConnectionsByTag(e,a){if(this.side!=="server"||!this.smartServeRef)throw new Error("findAllTargetConnectionsByTag is only available on servers");let r=this.smartServeRef.getWebSocketConnectionsByTag(e),s=[];for(let n of r){let o=this.getOrCreateWrapper(n);if(a!==void 0){let l=await o.getTagById(e);if(ri.stringify(l?.payload)!==ri.stringify(a))continue}s.push(o)}return s}async findTargetConnectionByTag(e,a){return(await this.findAllTargetConnectionsByTag(e,a))[0]}};de();Xa();var vt=gt;u5();var Jaa={};var e1a={};var Hs=new vt.plugins.smartstate.Smartstate,Ka=await Hs.getStatePart("login",{identity:null,isLoggedIn:!1},"persistent"),lr=await Hs.getStatePart("stats",{serverStats:null,emailStats:null,dnsStats:null,securityMetrics:null,lastUpdated:0,isLoading:!1,error:null},"soft"),H6=await Hs.getStatePart("config",{config:null,isLoading:!1,error:null}),Lva=i(()=>{let t=typeof window<"u"?window.location.pathname:"/",e=["overview","network","emails","logs","routes","apitokens","configuration","security","certificates","remoteingress"],r=t.split("/").filter(Boolean)[0];return e.includes(r)?r:"overview"},"getInitialView"),ci=await Hs.getStatePart("ui",{activeView:Lva(),sidebarCollapsed:!1,autoRefresh:!0,refreshInterval:1e3,theme:"light"}),jo=await Hs.getStatePart("logs",{recentLogs:[],isStreaming:!1,filters:{}},"soft"),$2=await Hs.getStatePart("network",{connections:[],connectionsByIP:{},throughputRate:{bytesInPerSecond:0,bytesOutPerSecond:0},totalBytes:{in:0,out:0},topIPs:[],throughputByIP:[],throughputHistory:[],requestsPerSecond:0,requestsTotal:0,backends:[],lastUpdated:0,isLoading:!1,error:null},"soft"),NX=await Hs.getStatePart("emailOps",{emails:[],isLoading:!1,error:null,lastUpdated:0},"soft"),di=await Hs.getStatePart("certificates",{certificates:[],summary:{total:0,valid:0,expiring:0,expired:0,failed:0,unknown:0},isLoading:!1,error:null,lastUpdated:0},"soft"),S1=await Hs.getStatePart("remoteIngress",{edges:[],statuses:[],selectedEdgeId:null,newEdgeId:null,isLoading:!1,error:null,lastUpdated:0},"soft"),pa=await Hs.getStatePart("routeManagement",{mergedRoutes:[],warnings:[],apiTokens:[],isLoading:!1,error:null,lastUpdated:0},"soft"),Jt=i(()=>{let t=Ka.getState().identity;return t&&t.expiresAt&&t.expiresAt<Date.now()?{identity:null}:{identity:t}},"getActionContext"),o1a=Ka.createAction(async(t,e)=>{let a=new vt.plugins.typedrequest.TypedRequest("/typedrequest","adminLoginWithUsernameAndPassword");try{let r=await a.fire({username:e.username,password:e.password});return r.identity?{identity:r.identity,isLoggedIn:!0}:t.getState()}catch(r){return console.error("Login failed:",r),t.getState()}}),wu=Ka.createAction(async t=>{let e=Jt();if(e.identity){let a=new vt.plugins.typedrequest.TypedRequest("/typedrequest","adminLogout");try{await a.fire({identity:e.identity})}catch(r){console.error("Logout error:",r)}}return{identity:null,isLoggedIn:!1}}),Mu=lr.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getCombinedMetrics").fire({identity:e.identity,sections:{server:!0,email:!0,dns:!0,security:!0,network:!1}});return{serverStats:s.metrics.server||a.serverStats,emailStats:s.metrics.email||a.emailStats,dnsStats:s.metrics.dns||a.dnsStats,securityMetrics:s.metrics.security||a.securityMetrics,lastUpdated:Date.now(),isLoading:!1,error:null}}catch(r){return{...a,isLoading:!1,error:r.message||"Failed to fetch statistics"}}}),IX=H6.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{return{config:(await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getConfiguration").fire({identity:e.identity})).config,isLoading:!1,error:null}}catch(r){return{...a,isLoading:!1,error:r.message||"Failed to fetch configuration"}}}),FX=jo.createAction(async(t,e)=>{let a=Jt();if(!a.identity)return t.getState();let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRecentLogs").fire({identity:a.identity,limit:e.limit||100,level:e.level,category:e.category});return{...t.getState(),recentLogs:s.logs}}),Bji=ci.createAction(async t=>{let e=t.getState();return{...e,autoRefresh:!e.autoRefresh}}),Hji=ci.createAction(async(t,e)=>{let a=t.getState();return e==="network"&&a.activeView!=="network"&&setTimeout(()=>{$2.dispatchAction(pqe,null)},100),e==="certificates"&&a.activeView!=="certificates"&&setTimeout(()=>{di.dispatchAction(xl,null)},100),e==="routes"&&a.activeView!=="routes"&&setTimeout(()=>{pa.dispatchAction(D2,null)},100),e==="apitokens"&&a.activeView!=="apitokens"&&setTimeout(()=>{pa.dispatchAction(yl,null)},100),e==="remoteingress"&&a.activeView!=="remoteingress"&&setTimeout(()=>{S1.dispatchAction(vl,null)},100),{...a,activeView:e}}),pqe=$2.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getActiveConnections").fire({identity:e.identity}),o=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getNetworkStats").fire({identity:e.identity}),l={};return o.connectionsByIP&&Array.isArray(o.connectionsByIP)?o.connectionsByIP.forEach(h=>{l[h.ip]=h.count}):s.connections.forEach(h=>{let p=h.remoteAddress;l[p]=(l[p]||0)+1}),{connections:s.connections,connectionsByIP:l,throughputRate:o.throughputRate||{bytesInPerSecond:0,bytesOutPerSecond:0},totalBytes:o.totalDataTransferred?{in:o.totalDataTransferred.bytesIn,out:o.totalDataTransferred.bytesOut}:{in:0,out:0},topIPs:o.topIPs||[],throughputByIP:o.throughputByIP||[],throughputHistory:o.throughputHistory||[],requestsPerSecond:o.requestsPerSecond||0,requestsTotal:o.requestsTotal||0,backends:o.backends||[],lastUpdated:Date.now(),isLoading:!1,error:null}}catch(r){return console.error("Failed to fetch network stats:",r),{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch network stats"}}}),n1a=NX.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{return{emails:(await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getAllEmails").fire({identity:e.identity})).emails,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch emails"}}}),xl=di.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getCertificateOverview").fire({identity:e.identity});return{certificates:s.certificates,summary:s.summary,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch certificate overview"}}}),l1a=di.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","reprovisionCertificateDomain").fire({identity:r.identity,domain:e}),await a.dispatch(xl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to reprovision certificate"}}}),c1a=di.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteCertificate").fire({identity:r.identity,domain:e}),await a.dispatch(xl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete certificate"}}}),d1a=di.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","importCertificate").fire({identity:r.identity,cert:e}),await a.dispatch(xl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to import certificate"}}});async function u1a(t){let e=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","exportCertificate").fire({identity:e.identity,domain:t})}i(u1a,"fetchCertificateExport");async function fqe(t){let e=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRemoteIngressConnectionToken").fire({identity:e.identity,edgeId:t})}i(fqe,"fetchConnectionToken");var vl=S1.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let r=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRemoteIngresses"),s=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getRemoteIngressStatus"),[n,o]=await Promise.all([r.fire({identity:e.identity}),s.fire({identity:e.identity})]);return{...a,edges:n.edges,statuses:o.statuses,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch remote ingress data"}}}),p1a=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{let o=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","createRemoteIngress").fire({identity:r.identity,name:e.name,listenPorts:e.listenPorts,autoDerivePorts:e.autoDerivePorts,tags:e.tags});return o.success?(await a.dispatch(vl,null),{...t.getState(),newEdgeId:o.edge.id}):s}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to create edge"}}}),f1a=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteRemoteIngress").fire({identity:r.identity,id:e}),await a.dispatch(vl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete edge"}}}),h1a=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","updateRemoteIngress").fire({identity:r.identity,id:e.id,name:e.name,listenPorts:e.listenPorts,autoDerivePorts:e.autoDerivePorts,tags:e.tags}),await a.dispatch(vl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to update edge"}}}),m1a=S1.createAction(async(t,e)=>{let a=Jt(),r=t.getState();try{return(await new vt.plugins.typedrequest.TypedRequest("/typedrequest","regenerateRemoteIngressSecret").fire({identity:a.identity,id:e})).success?{...r,newEdgeId:e}:r}catch(s){return{...r,error:s instanceof Error?s.message:"Failed to regenerate secret"}}}),g1a=S1.createAction(async t=>({...t.getState(),newEdgeId:null})),hqe=S1.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","updateRemoteIngress").fire({identity:r.identity,id:e.id,enabled:e.enabled}),await a.dispatch(vl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle edge"}}}),ui=await Hs.getStatePart("vpn",{clients:[],status:null,isLoading:!1,error:null,lastUpdated:0,newClientConfig:null},"soft"),yu=ui.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let r=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getVpnClients"),s=new vt.plugins.typedrequest.TypedRequest("/typedrequest","getVpnStatus"),[n,o]=await Promise.all([r.fire({identity:e.identity}),s.fire({identity:e.identity})]);return{...a,clients:n.clients,status:o.status,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch VPN data"}}}),b1a=ui.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{let o=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","createVpnClient").fire({identity:r.identity,clientId:e.clientId,serverDefinedClientTags:e.serverDefinedClientTags,description:e.description});return o.success?{...await a.dispatch(yu,null),newClientConfig:o.wireguardConfig||null}:{...s,error:o.message||"Failed to create client"}}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to create VPN client"}}}),v1a=ui.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteVpnClient").fire({identity:r.identity,clientId:e}),await a.dispatch(yu,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete VPN client"}}}),x1a=ui.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{let n=e.enabled?"enableVpnClient":"disableVpnClient";return await new vt.plugins.typedrequest.TypedRequest("/typedrequest",n).fire({identity:r.identity,clientId:e.clientId}),await a.dispatch(yu,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle VPN client"}}}),y1a=ui.createAction(async t=>({...t.getState(),newClientConfig:null})),D2=pa.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getMergedRoutes").fire({identity:e.identity});return{...a,mergedRoutes:s.routes,warnings:s.warnings,isLoading:!1,error:null,lastUpdated:Date.now()}}catch(r){return{...a,isLoading:!1,error:r instanceof Error?r.message:"Failed to fetch routes"}}}),w1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","createRoute").fire({identity:r.identity,route:e.route,enabled:e.enabled}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to create route"}}}),M1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","deleteRoute").fire({identity:r.identity,id:e}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to delete route"}}}),k1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","toggleRoute").fire({identity:r.identity,id:e.id,enabled:e.enabled}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle route"}}}),mqe=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","setRouteOverride").fire({identity:r.identity,routeName:e.routeName,enabled:e.enabled}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to set override"}}}),z1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","removeRouteOverride").fire({identity:r.identity,routeName:e}),await a.dispatch(D2,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to remove override"}}}),yl=pa.createAction(async t=>{let e=Jt(),a=t.getState();if(!e.identity)return a;try{let s=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","listApiTokens").fire({identity:e.identity});return{...a,apiTokens:s.tokens}}catch(r){return{...a,error:r instanceof Error?r.message:"Failed to fetch tokens"}}});async function S1a(t,e,a){let r=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","createApiToken").fire({identity:r.identity,name:t,scopes:e,expiresInDays:a})}i(S1a,"createApiToken");async function C1a(t){let e=Jt();return new vt.plugins.typedrequest.TypedRequest("/typedrequest","rollApiToken").fire({identity:e.identity,id:t})}i(C1a,"rollApiToken");var _1a=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","revokeApiToken").fire({identity:r.identity,id:e}),await a.dispatch(yl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to revoke token"}}}),gqe=pa.createAction(async(t,e,a)=>{let r=Jt(),s=t.getState();try{return await new vt.plugins.typedrequest.TypedRequest("/typedrequest","toggleApiToken").fire({identity:r.identity,id:e.id,enabled:e.enabled}),await a.dispatch(yl,null)}catch(n){return{...s,error:n instanceof Error?n.message:"Failed to toggle token"}}}),O6=null,t1a=new vt.plugins.typedrequest.TypedRouter,EX=[],lqe=!1;function $va(){if(lqe=!1,EX.length===0)return;let t=jo.getState(),e=[...t.recentLogs,...EX];EX=[],e.length>2e3&&e.splice(0,e.length-2e3),jo.setState({...t,recentLogs:e})}i($va,"flushLogEntries"),t1a.addTypedHandler(new vt.plugins.typedrequest.TypedHandler("pushLogEntry",async t=>(EX.push(t.entry),lqe||(lqe=!0,requestAnimationFrame($va)),{})));async function cqe(){if(!O6)try{O6=await xu.TypedSocket.createClient(t1a,xu.TypedSocket.useWindowLocationOriginUrl()),await O6.setTag("role","ops_dashboard")}catch(t){console.error("TypedSocket connection failed:",t),O6=null}}i(cqe,"connectSocket");async function a1a(){if(O6){try{await O6.stop()}catch{}O6=null}}i(a1a,"disconnectSocket");var dqe=!1;async function Dva(){if(!dqe){dqe=!0;try{await Ava()}finally{dqe=!1}}}i(Dva,"dispatchCombinedRefreshAction");async function Ava(){let t=Jt();if(!t.identity)return;let e=ci.getState().activeView;try{let r=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getCombinedMetrics").fire({identity:t.identity,sections:{server:!0,email:!0,dns:!0,security:!0,network:e==="network"}}),s=lr.getState();if(lr.setState({...s,serverStats:r.metrics.server||s.serverStats,emailStats:r.metrics.email||s.emailStats,dnsStats:r.metrics.dns||s.dnsStats,securityMetrics:r.metrics.security||s.securityMetrics,lastUpdated:Date.now(),isLoading:!1,error:null}),r.metrics.network&&e==="network"){let n=r.metrics.network,o={};n.connectionDetails.forEach(l=>{o[l.remoteAddress]=(o[l.remoteAddress]||0)+1});try{let h=await new vt.plugins.typedrequest.TypedRequest("/typedrequest","getActiveConnections").fire({identity:t.identity});$2.setState({...$2.getState(),connections:h.connections,connectionsByIP:o,throughputRate:{bytesInPerSecond:n.totalBandwidth.in,bytesOutPerSecond:n.totalBandwidth.out},totalBytes:n.totalBytes||{in:0,out:0},topIPs:n.topEndpoints.map(p=>({ip:p.endpoint,count:p.requests})),throughputByIP:n.topEndpoints.map(p=>({ip:p.endpoint,in:p.bandwidth?.in||0,out:p.bandwidth?.out||0})),throughputHistory:n.throughputHistory||[],requestsPerSecond:n.requestsPerSecond||0,requestsTotal:n.requestsTotal||0,backends:n.backends||[],lastUpdated:Date.now(),isLoading:!1,error:null})}catch(l){console.error("Failed to fetch connections:",l),$2.setState({...$2.getState(),connections:[],connectionsByIP:o,throughputRate:{bytesInPerSecond:n.totalBandwidth.in,bytesOutPerSecond:n.totalBandwidth.out},totalBytes:n.totalBytes||{in:0,out:0},topIPs:n.topEndpoints.map(h=>({ip:h.endpoint,count:h.requests})),throughputByIP:n.topEndpoints.map(h=>({ip:h.endpoint,in:h.bandwidth?.in||0,out:h.bandwidth?.out||0})),throughputHistory:n.throughputHistory||[],requestsPerSecond:n.requestsPerSecond||0,requestsTotal:n.requestsTotal||0,backends:n.backends||[],lastUpdated:Date.now(),isLoading:!1,error:null})}}if(e==="certificates")try{await di.dispatchAction(xl,null)}catch(n){console.error("Certificate refresh failed:",n)}if(e==="remoteingress")try{await S1.dispatchAction(vl,null)}catch(n){console.error("Remote ingress refresh failed:",n)}if(e==="vpn")try{await ui.dispatchAction(yu,null)}catch(n){console.error("VPN refresh failed:",n)}}catch(a){console.error("Combined refresh failed:",a);let r=String(a);(r.includes("invalid")||r.includes("unauthorized")||r.includes("401"))&&(await Ka.dispatchAction(wu,null),window.location.reload())}}i(Ava,"dispatchCombinedRefreshActionInner");var Pva=lr.createAction(async t=>(await Dva(),t.getState())),B6=null,uqe=i(()=>{let t=ci.getState(),e=Ka.getState();t.autoRefresh&&e.isLoggedIn?(B6&&(B6.dispose(),B6=null),B6=lr.createScheduledAction({action:Pva,payload:void 0,intervalMs:t.refreshInterval,autoPause:"visibility"})):B6&&(B6.dispose(),B6=null)},"startAutoRefresh"),r1a=ci.getState().autoRefresh,i1a=ci.getState().refreshInterval,s1a=Ka.getState().isLoggedIn;ci.select(t=>({autoRefresh:t.autoRefresh,refreshInterval:t.refreshInterval})).subscribe(t=>{(t.autoRefresh!==r1a||t.refreshInterval!==i1a)&&(r1a=t.autoRefresh,i1a=t.refreshInterval,uqe())}),Ka.select(t=>t.isLoggedIn).subscribe(t=>{t!==s1a&&(s1a=t,uqe(),t?cqe():a1a())}),document.addEventListener("visibilitychange",()=>{document.hidden?a1a():Ka.getState().isLoggedIn&&cqe()}),uqe(),Ka.getState().isLoggedIn&&cqe();var Eva=vt.plugins.smartrouter.SmartRouter,bqe=["overview","network","emails","logs","routes","apitokens","configuration","security","certificates","remoteingress","vpn"],vqe=class{static{i(this,"AppRouter")}router;initialized=!1;suppressStateUpdate=!1;constructor(){this.router=new Eva({debug:!1})}init(){this.initialized||(this.setupRoutes(),this.setupStateSync(),this.handleInitialRoute(),this.initialized=!0)}setupRoutes(){for(let e of bqe)this.router.on(`/${e}`,async()=>{this.updateViewState(e)});this.router.on("/",async()=>{this.navigateTo("/overview")})}setupStateSync(){ci.select().subscribe(e=>{if(this.suppressStateUpdate)return;let a=window.location.pathname,r=`/${e.activeView}`;a!==r&&(this.suppressStateUpdate=!0,this.router.pushUrl(r),this.suppressStateUpdate=!1)})}handleInitialRoute(){let e=window.location.pathname;if(!e||e==="/")this.router.pushUrl("/overview");else{let r=e.split("/").filter(Boolean)[0];bqe.includes(r)?this.updateViewState(r):this.router.pushUrl("/overview")}}updateViewState(e){this.suppressStateUpdate=!0;let a=ci.getState();a.activeView!==e&&ci.setState({...a,activeView:e}),this.suppressStateUpdate=!1}navigateTo(e){this.router.pushUrl(e)}navigateToView(e){bqe.includes(e)?this.navigateTo(`/${e}`):this.navigateTo("/overview")}getCurrentView(){return ci.getState().activeView}destroy(){this.router.destroy(),this.initialized=!1}},ku=new vqe;de();var n1=Z`
|
|
40178
40178
|
:host {
|
|
40179
40179
|
display: block;
|
|
40180
40180
|
margin: auto;
|
|
@@ -41403,7 +41403,7 @@ Customer Support Team`}};async onActivate(b){this.appui=b.appui,this.appui.setCo
|
|
|
41403
41403
|
.heading1=${"VPN Clients"}
|
|
41404
41404
|
.heading2=${"Manage WireGuard and SmartVPN client registrations"}
|
|
41405
41405
|
.data=${r}
|
|
41406
|
-
.displayFunction=${h=>({"Client ID":h.clientId,Status:h.enabled?w`<span class="statusBadge enabled">enabled</span>`:w`<span class="statusBadge disabled">disabled</span>`,"VPN IP":h.assignedIp||"-",Tags:h.
|
|
41406
|
+
.displayFunction=${h=>({"Client ID":h.clientId,Status:h.enabled?w`<span class="statusBadge enabled">enabled</span>`:w`<span class="statusBadge disabled">disabled</span>`,"VPN IP":h.assignedIp||"-",Tags:h.serverDefinedClientTags?.length?w`${h.serverDefinedClientTags.map(p=>w`<span class="tagBadge">${p}</span>`)}`:"-",Description:h.description||"-",Created:new Date(h.createdAt).toLocaleDateString()})}
|
|
41407
41407
|
.dataActions=${[{name:"Toggle",iconName:"lucide:power",action:i(async h=>{await ui.dispatchAction(x1a,{clientId:h.clientId,enabled:!h.enabled})},"action")},{name:"Delete",iconName:"lucide:trash2",action:i(async h=>{let{DeesModal:p}=await Promise.resolve().then(()=>(Xa(),Za));p.createAndShow({heading:"Delete VPN Client",content:w`<p>Are you sure you want to delete client "${h.clientId}"?</p>`,menuOptions:[{name:"Cancel",action:i(async f=>f.destroy(),"action")},{name:"Delete",action:i(async f=>{await ui.dispatchAction(v1a,h.clientId),f.destroy()},"action")}]})},"action")}]}
|
|
41408
41408
|
.createNewItem=${async()=>{let{DeesModal:h,DeesForm:p,DeesInputText:f}=await Promise.resolve().then(()=>(Xa(),Za));h.createAndShow({heading:"Create VPN Client",content:w`
|
|
41409
41409
|
<dees-form>
|
|
@@ -41411,7 +41411,7 @@ Customer Support Team`}};async onActivate(b){this.appui=b.appui,this.appui.setCo
|
|
|
41411
41411
|
<dees-input-text id="description" .label=${"Description"} .key=${"description"}></dees-input-text>
|
|
41412
41412
|
<dees-input-text id="tags" .label=${"Tags (comma-separated)"} .key=${"tags"}></dees-input-text>
|
|
41413
41413
|
</dees-form>
|
|
41414
|
-
`,menuOptions:[{name:"Cancel",action:i(async u=>u.destroy(),"action")},{name:"Create",action:i(async u=>{let v=await u.shadowRoot.querySelector("dees-form").collectFormData(),x=v.tags?v.tags.split(",").map(b=>b.trim()).filter(Boolean):void 0;await ui.dispatchAction(b1a,{clientId:v.clientId,description:v.description||void 0,
|
|
41414
|
+
`,menuOptions:[{name:"Cancel",action:i(async u=>u.destroy(),"action")},{name:"Create",action:i(async u=>{let v=await u.shadowRoot.querySelector("dees-form").collectFormData(),x=v.tags?v.tags.split(",").map(b=>b.trim()).filter(Boolean):void 0;await ui.dispatchAction(b1a,{clientId:v.clientId,description:v.description||void 0,serverDefinedClientTags:x}),u.destroy()},"action")}]})}}
|
|
41415
41415
|
></dees-table>
|
|
41416
41416
|
`}};$u=$a(mra),Oqe=new WeakMap,xt($u,4,"vpnState",hra,_l,Oqe),_l=xt($u,0,"OpsViewVpn",gra,_l),i(_l,"OpsViewVpn"),ta(_l,"styles",[d.defaultStyles,n1,Z`
|
|
41417
41417
|
.vpnContainer {
|
|
@@ -43364,4 +43364,4 @@ ibantools/jsnext/ibantools.js:
|
|
|
43364
43364
|
* @preferred
|
|
43365
43365
|
*)
|
|
43366
43366
|
*/
|
|
43367
|
-
//# sourceMappingURL=bundle-
|
|
43367
|
+
//# sourceMappingURL=bundle-1774872518117.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
|
+
*/
|
|
4
|
+
export const commitinfo = {
|
|
5
|
+
name: '@serve.zone/dcrouter',
|
|
6
|
+
version: '11.15.0',
|
|
7
|
+
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLDBFQUEwRTtDQUN4RixDQUFBIn0=
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CacheDb } from './classes.cachedb.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the cache cleaner
|
|
4
|
+
*/
|
|
5
|
+
export interface ICacheCleanerOptions {
|
|
6
|
+
/** Cleanup interval in milliseconds (default: 1 hour) */
|
|
7
|
+
intervalMs?: number;
|
|
8
|
+
/** Enable verbose logging */
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* CacheCleaner - Periodically removes expired documents from the cache
|
|
13
|
+
*
|
|
14
|
+
* Runs on a configurable interval (default: hourly) and queries each
|
|
15
|
+
* collection for documents where expiresAt < now(), then deletes them.
|
|
16
|
+
*/
|
|
17
|
+
export declare class CacheCleaner {
|
|
18
|
+
private cleanupInterval;
|
|
19
|
+
private isRunning;
|
|
20
|
+
private options;
|
|
21
|
+
private cacheDb;
|
|
22
|
+
constructor(cacheDb: CacheDb, options?: ICacheCleanerOptions);
|
|
23
|
+
/**
|
|
24
|
+
* Start the periodic cleanup process
|
|
25
|
+
*/
|
|
26
|
+
start(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Stop the periodic cleanup process
|
|
29
|
+
*/
|
|
30
|
+
stop(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Run a single cleanup cycle
|
|
33
|
+
*/
|
|
34
|
+
runCleanup(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Clean expired documents from a specific collection using smartdata API
|
|
37
|
+
*/
|
|
38
|
+
private cleanExpiredDocuments;
|
|
39
|
+
/**
|
|
40
|
+
* Check if the cleaner is running
|
|
41
|
+
*/
|
|
42
|
+
isActive(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get the cleanup interval in milliseconds
|
|
45
|
+
*/
|
|
46
|
+
getIntervalMs(): number;
|
|
47
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
import { CacheDb } from './classes.cachedb.js';
|
|
4
|
+
// Import document classes for cleanup
|
|
5
|
+
import { CachedEmail } from './documents/classes.cached.email.js';
|
|
6
|
+
import { CachedIPReputation } from './documents/classes.cached.ip.reputation.js';
|
|
7
|
+
/**
|
|
8
|
+
* CacheCleaner - Periodically removes expired documents from the cache
|
|
9
|
+
*
|
|
10
|
+
* Runs on a configurable interval (default: hourly) and queries each
|
|
11
|
+
* collection for documents where expiresAt < now(), then deletes them.
|
|
12
|
+
*/
|
|
13
|
+
export class CacheCleaner {
|
|
14
|
+
cleanupInterval = null;
|
|
15
|
+
isRunning = false;
|
|
16
|
+
options;
|
|
17
|
+
cacheDb;
|
|
18
|
+
constructor(cacheDb, options = {}) {
|
|
19
|
+
this.cacheDb = cacheDb;
|
|
20
|
+
this.options = {
|
|
21
|
+
intervalMs: options.intervalMs || 60 * 60 * 1000, // 1 hour default
|
|
22
|
+
verbose: options.verbose || false,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Start the periodic cleanup process
|
|
27
|
+
*/
|
|
28
|
+
start() {
|
|
29
|
+
if (this.isRunning) {
|
|
30
|
+
logger.log('warn', 'CacheCleaner already running');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.isRunning = true;
|
|
34
|
+
// Run cleanup immediately on start
|
|
35
|
+
this.runCleanup().catch((error) => {
|
|
36
|
+
logger.log('error', `Initial cache cleanup failed: ${error.message}`);
|
|
37
|
+
});
|
|
38
|
+
// Schedule periodic cleanup
|
|
39
|
+
this.cleanupInterval = setInterval(() => {
|
|
40
|
+
this.runCleanup().catch((error) => {
|
|
41
|
+
logger.log('error', `Cache cleanup failed: ${error.message}`);
|
|
42
|
+
});
|
|
43
|
+
}, this.options.intervalMs);
|
|
44
|
+
logger.log('info', `CacheCleaner started with interval: ${this.options.intervalMs / 1000 / 60} minutes`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Stop the periodic cleanup process
|
|
48
|
+
*/
|
|
49
|
+
stop() {
|
|
50
|
+
if (!this.isRunning) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (this.cleanupInterval) {
|
|
54
|
+
clearInterval(this.cleanupInterval);
|
|
55
|
+
this.cleanupInterval = null;
|
|
56
|
+
}
|
|
57
|
+
this.isRunning = false;
|
|
58
|
+
logger.log('info', 'CacheCleaner stopped');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Run a single cleanup cycle
|
|
62
|
+
*/
|
|
63
|
+
async runCleanup() {
|
|
64
|
+
if (!this.cacheDb.isReady()) {
|
|
65
|
+
logger.log('warn', 'CacheDb not ready, skipping cleanup');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const now = new Date();
|
|
69
|
+
const results = [];
|
|
70
|
+
try {
|
|
71
|
+
const emailsDeleted = await this.cleanExpiredDocuments(CachedEmail, now);
|
|
72
|
+
results.push({ collection: 'CachedEmail', deleted: emailsDeleted });
|
|
73
|
+
const ipReputationDeleted = await this.cleanExpiredDocuments(CachedIPReputation, now);
|
|
74
|
+
results.push({ collection: 'CachedIPReputation', deleted: ipReputationDeleted });
|
|
75
|
+
// Log results
|
|
76
|
+
const totalDeleted = results.reduce((sum, r) => sum + r.deleted, 0);
|
|
77
|
+
if (totalDeleted > 0 || this.options.verbose) {
|
|
78
|
+
const summary = results
|
|
79
|
+
.filter((r) => r.deleted > 0)
|
|
80
|
+
.map((r) => `${r.collection}: ${r.deleted}`)
|
|
81
|
+
.join(', ');
|
|
82
|
+
logger.log('info', `Cache cleanup completed. Deleted ${totalDeleted} expired documents. ${summary || 'No deletions.'}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger.log('error', `Cache cleanup error: ${error.message}`);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Clean expired documents from a specific collection using smartdata API
|
|
92
|
+
*/
|
|
93
|
+
async cleanExpiredDocuments(documentClass, now) {
|
|
94
|
+
try {
|
|
95
|
+
// Find all expired documents
|
|
96
|
+
const expiredDocs = await documentClass.getInstances({
|
|
97
|
+
expiresAt: { $lt: now },
|
|
98
|
+
});
|
|
99
|
+
// Delete each expired document
|
|
100
|
+
let deletedCount = 0;
|
|
101
|
+
for (const doc of expiredDocs) {
|
|
102
|
+
try {
|
|
103
|
+
await doc.delete();
|
|
104
|
+
deletedCount++;
|
|
105
|
+
}
|
|
106
|
+
catch (deleteError) {
|
|
107
|
+
logger.log('warn', `Failed to delete expired document: ${deleteError.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return deletedCount;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
logger.log('error', `Error cleaning collection: ${error.message}`);
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check if the cleaner is running
|
|
119
|
+
*/
|
|
120
|
+
isActive() {
|
|
121
|
+
return this.isRunning;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get the cleanup interval in milliseconds
|
|
125
|
+
*/
|
|
126
|
+
getIntervalMs() {
|
|
127
|
+
return this.options.intervalMs;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jYWNoZS5jbGVhbmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvY2FjaGUvY2xhc3Nlcy5jYWNoZS5jbGVhbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRS9DLHNDQUFzQztBQUN0QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDbEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFZakY7Ozs7O0dBS0c7QUFDSCxNQUFNLE9BQU8sWUFBWTtJQUNmLGVBQWUsR0FBMEMsSUFBSSxDQUFDO0lBQzlELFNBQVMsR0FBWSxLQUFLLENBQUM7SUFDM0IsT0FBTyxDQUFpQztJQUN4QyxPQUFPLENBQVU7SUFFekIsWUFBWSxPQUFnQixFQUFFLFVBQWdDLEVBQUU7UUFDOUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLE9BQU8sR0FBRztZQUNiLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxJQUFJLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxFQUFFLGlCQUFpQjtZQUNuRSxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU8sSUFBSSxLQUFLO1NBQ2xDLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLO1FBQ1YsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDbkIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsOEJBQThCLENBQUMsQ0FBQztZQUNuRCxPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO1FBRXRCLG1DQUFtQztRQUNuQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBYyxFQUFFLEVBQUU7WUFDekMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsaUNBQWtDLEtBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLENBQUMsQ0FBQyxDQUFDO1FBRUgsNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxlQUFlLEdBQUcsV0FBVyxDQUFDLEdBQUcsRUFBRTtZQUN0QyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBYyxFQUFFLEVBQUU7Z0JBQ3pDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLHlCQUEwQixLQUFlLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUMzRSxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRTVCLE1BQU0sQ0FBQyxHQUFHLENBQ1IsTUFBTSxFQUNOLHVDQUF1QyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsR0FBRyxJQUFJLEdBQUcsRUFBRSxVQUFVLENBQ3JGLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSSxJQUFJO1FBQ1QsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNwQixPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3pCLGFBQWEsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFDcEMsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7UUFDOUIsQ0FBQztRQUVELElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLHNCQUFzQixDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFVBQVU7UUFDckIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUM1QixNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxxQ0FBcUMsQ0FBQyxDQUFDO1lBQzFELE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN2QixNQUFNLE9BQU8sR0FBOEMsRUFBRSxDQUFDO1FBRTlELElBQUksQ0FBQztZQUNILE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUN6RSxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztZQUVwRSxNQUFNLG1CQUFtQixHQUFHLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLGtCQUFrQixFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ3RGLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxVQUFVLEVBQUUsb0JBQW9CLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLENBQUMsQ0FBQztZQUVqRixjQUFjO1lBQ2QsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3BFLElBQUksWUFBWSxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUM3QyxNQUFNLE9BQU8sR0FBRyxPQUFPO3FCQUNwQixNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO3FCQUM1QixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsS0FBSyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7cUJBQzNDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDZCxNQUFNLENBQUMsR0FBRyxDQUNSLE1BQU0sRUFDTixvQ0FBb0MsWUFBWSx1QkFBdUIsT0FBTyxJQUFJLGVBQWUsRUFBRSxDQUNwRyxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQWMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLHdCQUF5QixLQUFlLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUN4RSxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMscUJBQXFCLENBQ2pDLGFBQThELEVBQzlELEdBQVM7UUFFVCxJQUFJLENBQUM7WUFDSCw2QkFBNkI7WUFDN0IsTUFBTSxXQUFXLEdBQUcsTUFBTSxhQUFhLENBQUMsWUFBWSxDQUFDO2dCQUNuRCxTQUFTLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFO2FBQ3hCLENBQUMsQ0FBQztZQUVILCtCQUErQjtZQUMvQixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7WUFDckIsS0FBSyxNQUFNLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDOUIsSUFBSSxDQUFDO29CQUNILE1BQU0sR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNuQixZQUFZLEVBQUUsQ0FBQztnQkFDakIsQ0FBQztnQkFBQyxPQUFPLFdBQW9CLEVBQUUsQ0FBQztvQkFDOUIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsc0NBQXVDLFdBQXFCLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztnQkFDN0YsQ0FBQztZQUNILENBQUM7WUFFRCxPQUFPLFlBQVksQ0FBQztRQUN0QixDQUFDO1FBQUMsT0FBTyxLQUFjLEVBQUUsQ0FBQztZQUN4QixNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSw4QkFBK0IsS0FBZSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDOUUsT0FBTyxDQUFDLENBQUM7UUFDWCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ksUUFBUTtRQUNiLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUN4QixDQUFDO0lBRUQ7O09BRUc7SUFDSSxhQUFhO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUM7SUFDakMsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for all cached documents with TTL support
|
|
4
|
+
*
|
|
5
|
+
* Extends smartdata's SmartDataDbDoc to add:
|
|
6
|
+
* - Automatic timestamps (createdAt, lastAccessedAt)
|
|
7
|
+
* - TTL/expiration support (expiresAt)
|
|
8
|
+
* - Helper methods for TTL management
|
|
9
|
+
*
|
|
10
|
+
* NOTE: Subclasses MUST add @svDb() decorators to createdAt, expiresAt, and lastAccessedAt
|
|
11
|
+
* since decorators on abstract classes don't propagate correctly.
|
|
12
|
+
*/
|
|
13
|
+
export declare abstract class CachedDocument<T extends CachedDocument<T>> extends plugins.smartdata.SmartDataDbDoc<T, T> {
|
|
14
|
+
/**
|
|
15
|
+
* Timestamp when the document was created
|
|
16
|
+
* NOTE: Subclasses must add @svDb() decorator
|
|
17
|
+
*/
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
/**
|
|
20
|
+
* Timestamp when the document expires and should be cleaned up
|
|
21
|
+
* NOTE: Subclasses must add @svDb() decorator
|
|
22
|
+
*/
|
|
23
|
+
expiresAt: Date;
|
|
24
|
+
/**
|
|
25
|
+
* Timestamp of last access (for LRU-style eviction if needed)
|
|
26
|
+
* NOTE: Subclasses must add @svDb() decorator
|
|
27
|
+
*/
|
|
28
|
+
lastAccessedAt: Date;
|
|
29
|
+
/**
|
|
30
|
+
* Set the TTL (time to live) for this document
|
|
31
|
+
* @param ttlMs Time to live in milliseconds
|
|
32
|
+
*/
|
|
33
|
+
setTTL(ttlMs: number): void;
|
|
34
|
+
/**
|
|
35
|
+
* Set TTL using days
|
|
36
|
+
* @param days Number of days until expiration
|
|
37
|
+
*/
|
|
38
|
+
setTTLDays(days: number): void;
|
|
39
|
+
/**
|
|
40
|
+
* Set TTL using hours
|
|
41
|
+
* @param hours Number of hours until expiration
|
|
42
|
+
*/
|
|
43
|
+
setTTLHours(hours: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* Check if this document has expired
|
|
46
|
+
*/
|
|
47
|
+
isExpired(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Update the lastAccessedAt timestamp
|
|
50
|
+
*/
|
|
51
|
+
touch(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Get remaining TTL in milliseconds
|
|
54
|
+
* Returns 0 if expired, -1 if no expiration set
|
|
55
|
+
*/
|
|
56
|
+
getRemainingTTL(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Extend the TTL by the specified milliseconds from now
|
|
59
|
+
* @param ttlMs Additional time to live in milliseconds
|
|
60
|
+
*/
|
|
61
|
+
extendTTL(ttlMs: number): void;
|
|
62
|
+
/**
|
|
63
|
+
* Set the document to never expire (100 years in the future)
|
|
64
|
+
*/
|
|
65
|
+
setNeverExpires(): void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* TTL constants in milliseconds
|
|
69
|
+
*/
|
|
70
|
+
export declare const TTL: {
|
|
71
|
+
readonly HOURS_1: number;
|
|
72
|
+
readonly HOURS_24: number;
|
|
73
|
+
readonly DAYS_7: number;
|
|
74
|
+
readonly DAYS_30: number;
|
|
75
|
+
readonly DAYS_90: number;
|
|
76
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for all cached documents with TTL support
|
|
4
|
+
*
|
|
5
|
+
* Extends smartdata's SmartDataDbDoc to add:
|
|
6
|
+
* - Automatic timestamps (createdAt, lastAccessedAt)
|
|
7
|
+
* - TTL/expiration support (expiresAt)
|
|
8
|
+
* - Helper methods for TTL management
|
|
9
|
+
*
|
|
10
|
+
* NOTE: Subclasses MUST add @svDb() decorators to createdAt, expiresAt, and lastAccessedAt
|
|
11
|
+
* since decorators on abstract classes don't propagate correctly.
|
|
12
|
+
*/
|
|
13
|
+
export class CachedDocument extends plugins.smartdata.SmartDataDbDoc {
|
|
14
|
+
/**
|
|
15
|
+
* Timestamp when the document was created
|
|
16
|
+
* NOTE: Subclasses must add @svDb() decorator
|
|
17
|
+
*/
|
|
18
|
+
createdAt = new Date();
|
|
19
|
+
/**
|
|
20
|
+
* Timestamp when the document expires and should be cleaned up
|
|
21
|
+
* NOTE: Subclasses must add @svDb() decorator
|
|
22
|
+
*/
|
|
23
|
+
expiresAt;
|
|
24
|
+
/**
|
|
25
|
+
* Timestamp of last access (for LRU-style eviction if needed)
|
|
26
|
+
* NOTE: Subclasses must add @svDb() decorator
|
|
27
|
+
*/
|
|
28
|
+
lastAccessedAt = new Date();
|
|
29
|
+
/**
|
|
30
|
+
* Set the TTL (time to live) for this document
|
|
31
|
+
* @param ttlMs Time to live in milliseconds
|
|
32
|
+
*/
|
|
33
|
+
setTTL(ttlMs) {
|
|
34
|
+
this.expiresAt = new Date(Date.now() + ttlMs);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Set TTL using days
|
|
38
|
+
* @param days Number of days until expiration
|
|
39
|
+
*/
|
|
40
|
+
setTTLDays(days) {
|
|
41
|
+
this.setTTL(days * 24 * 60 * 60 * 1000);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Set TTL using hours
|
|
45
|
+
* @param hours Number of hours until expiration
|
|
46
|
+
*/
|
|
47
|
+
setTTLHours(hours) {
|
|
48
|
+
this.setTTL(hours * 60 * 60 * 1000);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if this document has expired
|
|
52
|
+
*/
|
|
53
|
+
isExpired() {
|
|
54
|
+
if (!this.expiresAt) {
|
|
55
|
+
return false; // No expiration set
|
|
56
|
+
}
|
|
57
|
+
return new Date() > this.expiresAt;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Update the lastAccessedAt timestamp
|
|
61
|
+
*/
|
|
62
|
+
touch() {
|
|
63
|
+
this.lastAccessedAt = new Date();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get remaining TTL in milliseconds
|
|
67
|
+
* Returns 0 if expired, -1 if no expiration set
|
|
68
|
+
*/
|
|
69
|
+
getRemainingTTL() {
|
|
70
|
+
if (!this.expiresAt) {
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
73
|
+
const remaining = this.expiresAt.getTime() - Date.now();
|
|
74
|
+
return remaining > 0 ? remaining : 0;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Extend the TTL by the specified milliseconds from now
|
|
78
|
+
* @param ttlMs Additional time to live in milliseconds
|
|
79
|
+
*/
|
|
80
|
+
extendTTL(ttlMs) {
|
|
81
|
+
this.expiresAt = new Date(Date.now() + ttlMs);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Set the document to never expire (100 years in the future)
|
|
85
|
+
*/
|
|
86
|
+
setNeverExpires() {
|
|
87
|
+
this.expiresAt = new Date(Date.now() + 100 * 365 * 24 * 60 * 60 * 1000);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* TTL constants in milliseconds
|
|
92
|
+
*/
|
|
93
|
+
export const TTL = {
|
|
94
|
+
HOURS_1: 1 * 60 * 60 * 1000,
|
|
95
|
+
HOURS_24: 24 * 60 * 60 * 1000,
|
|
96
|
+
DAYS_7: 7 * 24 * 60 * 60 * 1000,
|
|
97
|
+
DAYS_30: 30 * 24 * 60 * 60 * 1000,
|
|
98
|
+
DAYS_90: 90 * 24 * 60 * 60 * 1000,
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jYWNoZWQuZG9jdW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jYWNoZS9jbGFzc2VzLmNhY2hlZC5kb2N1bWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUV6Qzs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxPQUFnQixjQUE0QyxTQUFRLE9BQU8sQ0FBQyxTQUFTLENBQUMsY0FBb0I7SUFDOUc7OztPQUdHO0lBQ0ksU0FBUyxHQUFTLElBQUksSUFBSSxFQUFFLENBQUM7SUFFcEM7OztPQUdHO0lBQ0ksU0FBUyxDQUFRO0lBRXhCOzs7T0FHRztJQUNJLGNBQWMsR0FBUyxJQUFJLElBQUksRUFBRSxDQUFDO0lBRXpDOzs7T0FHRztJQUNJLE1BQU0sQ0FBQyxLQUFhO1FBQ3pCLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRDs7O09BR0c7SUFDSSxVQUFVLENBQUMsSUFBWTtRQUM1QixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksV0FBVyxDQUFDLEtBQWE7UUFDOUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxTQUFTO1FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNwQixPQUFPLEtBQUssQ0FBQyxDQUFDLG9CQUFvQjtRQUNwQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDckMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSztRQUNWLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksZUFBZTtRQUNwQixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3BCLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDWixDQUFDO1FBQ0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDeEQsT0FBTyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksU0FBUyxDQUFDLEtBQWE7UUFDNUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOztPQUVHO0lBQ0ksZUFBZTtRQUNwQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxHQUFHLEdBQUcsR0FBRyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQzFFLENBQUM7Q0FDRjtBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHO0lBQ2pCLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJO0lBQzNCLFFBQVEsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJO0lBQzdCLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSTtJQUMvQixPQUFPLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUk7SUFDakMsT0FBTyxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJO0NBQ3pCLENBQUMifQ==
|