neoctl-web 0.1.17 → 0.1.18
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/README.md +21 -0
- package/dist/assets/App-BBTgdI-j.js +105 -0
- package/dist/assets/{index-B3c8NCtO.js → index-B0Wkp2VZ.js} +2 -2
- package/dist/index.html +1 -1
- package/isolation.mjs +7 -8
- package/local-resources.mjs +15 -0
- package/package.json +4 -2
- package/plugin-manager.mjs +120 -0
- package/plugin-settings.mjs +13 -7
- package/plugins/downloads/downloads.mjs +2 -1
- package/plugins/downloads/index.mjs +2 -2
- package/plugins.mjs +162 -69
- package/server.mjs +12 -9
- package/dist/assets/App-DAtURpfb.js +0 -105
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/App-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/App-BBTgdI-j.js","assets/App-ha0ZLeCJ.css"])))=>i.map(i=>d[i]);
|
|
2
2
|
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const i of r)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&s(o)}).observe(document,{childList:!0,subtree:!0});function n(r){const i={};return r.integrity&&(i.integrity=r.integrity),r.referrerPolicy&&(i.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?i.credentials="include":r.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(r){if(r.ep)return;r.ep=!0;const i=n(r);fetch(r.href,i)}})();/**
|
|
3
3
|
* @vue/shared v3.5.34
|
|
4
4
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
@@ -15,4 +15,4 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/App-DAtURpfb.js
|
|
|
15
15
|
* @vue/runtime-dom v3.5.34
|
|
16
16
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
17
17
|
* @license MIT
|
|
18
|
-
**/let as;const cr=typeof window<"u"&&window.trustedTypes;if(cr)try{as=cr.createPolicy("vue",{createHTML:e=>e})}catch{}const Hi=as?e=>as.createHTML(e):e=>e,Zl="http://www.w3.org/2000/svg",Ql="http://www.w3.org/1998/Math/MathML",We=typeof document<"u"?document:null,fr=We&&We.createElement("template"),ec={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const r=t==="svg"?We.createElementNS(Zl,e):t==="mathml"?We.createElementNS(Ql,e):n?We.createElement(e,{is:n}):We.createElement(e);return e==="select"&&s&&s.multiple!=null&&r.setAttribute("multiple",s.multiple),r},createText:e=>We.createTextNode(e),createComment:e=>We.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>We.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,r,i){const o=n?n.previousSibling:t.lastChild;if(r&&(r===i||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===i||!(r=r.nextSibling)););else{fr.innerHTML=Hi(s==="svg"?`<svg>${e}</svg>`:s==="mathml"?`<math>${e}</math>`:e);const l=fr.content;if(s==="svg"||s==="mathml"){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},tt="transition",Ht="animation",Pt=Symbol("_vtc"),ji={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},tc=ie({},Go,ji),pt=(e,t=[])=>{I(e)?e.forEach(n=>n(...t)):e&&e(...t)},ar=e=>e?I(e)?e.some(t=>t.length>1):e.length>1:!1;function nc(e){const t={};for(const A in e)A in ji||(t[A]=e[A]);if(e.css===!1)return t;const{name:n="v",type:s,duration:r,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:u=o,appearToClass:a=l,leaveFromClass:h=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:v=`${n}-leave-to`}=e,C=sc(r),x=C&&C[0],N=C&&C[1],{onBeforeEnter:D,onEnter:M,onEnterCancelled:F,onLeave:O,onLeaveCancelled:V,onBeforeAppear:se=D,onAppear:j=M,onAppearCancelled:G=F}=t,P=(A,X,oe,Ke)=>{A._enterCancelled=Ke,rt(A,X?a:l),rt(A,X?u:o),oe&&oe()},K=(A,X)=>{A._isLeaving=!1,rt(A,h),rt(A,v),rt(A,p),X&&X()},J=A=>(X,oe)=>{const Ke=A?j:M,ce=()=>P(X,A,oe);pt(Ke,[X,ce]),ur(()=>{rt(X,A?c:i),Ne(X,A?a:l),ar(Ke)||dr(X,s,x,ce)})};return ie(t,{onBeforeEnter(A){pt(D,[A]),Ne(A,i),Ne(A,o)},onBeforeAppear(A){pt(se,[A]),Ne(A,c),Ne(A,u)},onEnter:J(!1),onAppear:J(!0),onLeave(A,X){A._isLeaving=!0;const oe=()=>K(A,X);Ne(A,h),A._enterCancelled?(Ne(A,p),us(A)):(us(A),Ne(A,p)),ur(()=>{A._isLeaving&&(rt(A,h),Ne(A,v),ar(O)||dr(A,s,N,oe))}),pt(O,[A,oe])},onEnterCancelled(A){P(A,!1,void 0,!0),pt(F,[A])},onAppearCancelled(A){P(A,!0,void 0,!0),pt(G,[A])},onLeaveCancelled(A){K(A),pt(V,[A])}})}function sc(e){if(e==null)return null;if(q(e))return[Gn(e.enter),Gn(e.leave)];{const t=Gn(e);return[t,t]}}function Gn(e){return Xi(e)}function Ne(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Pt]||(e[Pt]=new Set)).add(t)}function rt(e,t){t.split(/\s+/).forEach(s=>s&&e.classList.remove(s));const n=e[Pt];n&&(n.delete(t),n.size||(e[Pt]=void 0))}function ur(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let rc=0;function dr(e,t,n,s){const r=e._endId=++rc,i=()=>{r===e._endId&&s()};if(n!=null)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=Vi(e,t);if(!o)return s();const u=o+"end";let a=0;const h=()=>{e.removeEventListener(u,p),i()},p=v=>{v.target===e&&++a>=c&&h()};setTimeout(()=>{a<c&&h()},l+1),e.addEventListener(u,p)}function Vi(e,t){const n=window.getComputedStyle(e),s=C=>(n[C]||"").split(", "),r=s(`${tt}Delay`),i=s(`${tt}Duration`),o=hr(r,i),l=s(`${Ht}Delay`),c=s(`${Ht}Duration`),u=hr(l,c);let a=null,h=0,p=0;t===tt?o>0&&(a=tt,h=o,p=i.length):t===Ht?u>0&&(a=Ht,h=u,p=c.length):(h=Math.max(o,u),a=h>0?o>u?tt:Ht:null,p=a?a===tt?i.length:c.length:0);const v=a===tt&&/\b(?:transform|all)(?:,|$)/.test(s(`${tt}Property`).toString());return{type:a,timeout:h,propCount:p,hasTransform:v}}function hr(e,t){for(;e.length<t.length;)e=e.concat(e);return Math.max(...t.map((n,s)=>pr(n)+pr(e[s])))}function pr(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function us(e){return(e?e.ownerDocument:document).body.offsetHeight}function ic(e,t,n){const s=e[Pt];s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const gr=Symbol("_vod"),oc=Symbol("_vsh"),lc=Symbol(""),cc=/(?:^|;)\s*display\s*:/;function fc(e,t,n){const s=e.style,r=te(n);let i=!1;if(n&&!r){if(t)if(te(t))for(const o of t.split(";")){const l=o.slice(0,o.indexOf(":")).trim();n[l]==null&&Ut(s,l,"")}else for(const o in t)n[o]==null&&Ut(s,o,"");for(const o in n){o==="display"&&(i=!0);const l=n[o];l!=null?uc(e,o,!te(t)&&t?t[o]:void 0,l)||Ut(s,o,l):Ut(s,o,"")}}else if(r){if(t!==n){const o=s[lc];o&&(n+=";"+o),s.cssText=n,i=cc.test(n)}}else t&&e.removeAttribute("style");gr in e&&(e[gr]=i?s.display:"",e[oc]&&(s.display="none"))}const mr=/\s*!important$/;function Ut(e,t,n){if(I(n))n.forEach(s=>Ut(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=ac(e,t);mr.test(n)?e.setProperty(ft(s),n.replace(mr,""),"important"):e[s]=n}}const _r=["Webkit","Moz","ms"],Jn={};function ac(e,t){const n=Jn[t];if(n)return n;let s=_e(t);if(s!=="filter"&&s in e)return Jn[t]=s;s=An(s);for(let r=0;r<_r.length;r++){const i=_r[r]+s;if(i in e)return Jn[t]=i}return t}function uc(e,t,n,s){return e.tagName==="TEXTAREA"&&(t==="width"||t==="height")&&te(s)&&n===s}const yr="http://www.w3.org/1999/xlink";function br(e,t,n,s,r,i=so(t)){s&&t.startsWith("xlink:")?n==null?e.removeAttributeNS(yr,t.slice(6,t.length)):e.setAttributeNS(yr,t,n):n==null||i&&!$r(n)?e.removeAttribute(t):e.setAttribute(t,i?"":Be(n)?String(n):n)}function vr(e,t,n,s,r){if(t==="innerHTML"||t==="textContent"){n!=null&&(e[t]=t==="innerHTML"?Hi(n):n);return}const i=e.tagName;if(t==="value"&&i!=="PROGRESS"&&!i.includes("-")){const l=i==="OPTION"?e.getAttribute("value")||"":e.value,c=n==null?e.type==="checkbox"?"on":"":String(n);(l!==c||!("_value"in e))&&(e.value=c),n==null&&e.removeAttribute(t),e._value=n;return}let o=!1;if(n===""||n==null){const l=typeof e[t];l==="boolean"?n=$r(n):n==null&&l==="string"?(n="",o=!0):l==="number"&&(n=0,o=!0)}try{e[t]=n}catch{}o&&e.removeAttribute(r||t)}function Ye(e,t,n,s){e.addEventListener(t,n,s)}function dc(e,t,n,s){e.removeEventListener(t,n,s)}const xr=Symbol("_vei");function hc(e,t,n,s,r=null){const i=e[xr]||(e[xr]={}),o=i[t];if(s&&o)o.value=s;else{const[l,c]=pc(t);if(s){const u=i[t]=_c(s,r);Ye(e,l,u,c)}else o&&(dc(e,l,o,c),i[t]=void 0)}}const wr=/(?:Once|Passive|Capture)$/;function pc(e){let t;if(wr.test(e)){t={};let s;for(;s=e.match(wr);)e=e.slice(0,e.length-s[0].length),t[s[0].toLowerCase()]=!0}return[e[2]===":"?e.slice(3):ft(e.slice(2)),t]}let Yn=0;const gc=Promise.resolve(),mc=()=>Yn||(gc.then(()=>Yn=0),Yn=Date.now());function _c(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;Pe(yc(s,n.value),t,5,[s])};return n.value=e,n.attached=mc(),n}function yc(e,t){if(I(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>r=>!r._stopped&&s&&s(r))}else return t}const Sr=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,bc=(e,t,n,s,r,i)=>{const o=r==="svg";t==="class"?ic(e,s,o):t==="style"?fc(e,n,s):Cn(t)?Tn(t)||hc(e,t,n,s,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):vc(e,t,s,o))?(vr(e,t,s),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&br(e,t,s,o,i,t!=="value")):e._isVueCE&&(xc(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!te(s)))?vr(e,_e(t),s,i,t):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),br(e,t,s,o))};function vc(e,t,n,s){if(s)return!!(t==="innerHTML"||t==="textContent"||t in e&&Sr(t)&&H(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const r=e.tagName;if(r==="IMG"||r==="VIDEO"||r==="CANVAS"||r==="SOURCE")return!1}return Sr(t)&&te(n)?!1:t in e}function xc(e,t){const n=e._def.props;if(!n)return!1;const s=_e(t);return Array.isArray(n)?n.some(r=>_e(r)===s):Object.keys(n).some(r=>_e(r)===s)}const Ui=new WeakMap,Bi=new WeakMap,Sn=Symbol("_moveCb"),Cr=Symbol("_enterCb"),wc=e=>(delete e.props.mode,e),Sc=wc({name:"TransitionGroup",props:ie({},tc,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=Di(),s=qo();let r,i;return hi(()=>{if(!r.length)return;const o=e.moveClass||`${e.name||"v"}-move`;if(!Ac(r[0].el,n.vnode.el,o)){r=[];return}r.forEach(Cc),r.forEach(Tc);const l=r.filter(Ec);us(n.vnode.el),l.forEach(c=>{const u=c.el,a=u.style;Ne(u,o),a.transform=a.webkitTransform=a.transitionDuration="";const h=u[Sn]=p=>{p&&p.target!==u||(!p||p.propertyName.endsWith("transform"))&&(u.removeEventListener("transitionend",h),u[Sn]=null,rt(u,o))};u.addEventListener("transitionend",h)}),r=[]}),()=>{const o=k(e),l=nc(o);let c=o.tag||Ce;if(r=[],i)for(let u=0;u<i.length;u++){const a=i[u];a.el&&a.el instanceof Element&&(r.push(a),Zt(a,rs(a,l,s,n)),Ui.set(a,Ki(a.el)))}i=t.default?ui(t.default()):[];for(let u=0;u<i.length;u++){const a=i[u];a.key!=null&&Zt(a,rs(a,l,s,n))}return ye(c,null,i)}}}),Mf=Sc;function Cc(e){const t=e.el;t[Sn]&&t[Sn](),t[Cr]&&t[Cr]()}function Tc(e){Bi.set(e,Ki(e.el))}function Ec(e){const t=Ui.get(e),n=Bi.get(e),s=t.left-n.left,r=t.top-n.top;if(s||r){const i=e.el,o=i.style,l=i.getBoundingClientRect();let c=1,u=1;return i.offsetWidth&&(c=l.width/i.offsetWidth),i.offsetHeight&&(u=l.height/i.offsetHeight),(!Number.isFinite(c)||c===0)&&(c=1),(!Number.isFinite(u)||u===0)&&(u=1),Math.abs(c-1)<.01&&(c=1),Math.abs(u-1)<.01&&(u=1),o.transform=o.webkitTransform=`translate(${s/c}px,${r/u}px)`,o.transitionDuration="0s",e}}function Ki(e){const t=e.getBoundingClientRect();return{left:t.left,top:t.top}}function Ac(e,t,n){const s=e.cloneNode(),r=e[Pt];r&&r.forEach(l=>{l.split(/\s+/).forEach(c=>c&&s.classList.remove(c))}),n.split(/\s+/).forEach(l=>l&&s.classList.add(l)),s.style.display="none";const i=t.nodeType===1?t:t.parentNode;i.appendChild(s);const{hasTransform:o}=Vi(s);return i.removeChild(s),o}const ct=e=>{const t=e.props["onUpdate:modelValue"]||!1;return I(t)?n=>hn(t,n):t};function Mc(e){e.target.composing=!0}function Tr(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Ee=Symbol("_assign");function Er(e,t,n){return t&&(e=e.trim()),n&&(e=Mn(e)),e}const ds={created(e,{modifiers:{lazy:t,trim:n,number:s}},r){e[Ee]=ct(r);const i=s||r.props&&r.props.type==="number";Ye(e,t?"change":"input",o=>{o.target.composing||e[Ee](Er(e.value,n,i))}),(n||i)&&Ye(e,"change",()=>{e.value=Er(e.value,n,i)}),t||(Ye(e,"compositionstart",Mc),Ye(e,"compositionend",Tr),Ye(e,"change",Tr))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:s,trim:r,number:i}},o){if(e[Ee]=ct(o),e.composing)return;const l=(i||e.type==="number")&&!/^0\d/.test(e.value)?Mn(e.value):e.value,c=t??"";if(l===c)return;const u=e.getRootNode();(u instanceof Document||u instanceof ShadowRoot)&&u.activeElement===e&&e.type!=="range"&&(s&&t===n||r&&e.value.trim()===c)||(e.value=c)}},Oc={deep:!0,created(e,t,n){e[Ee]=ct(n),Ye(e,"change",()=>{const s=e._modelValue,r=Rt(e),i=e.checked,o=e[Ee];if(I(s)){const l=_s(s,r),c=l!==-1;if(i&&!c)o(s.concat(r));else if(!i&&c){const u=[...s];u.splice(l,1),o(u)}}else if(It(s)){const l=new Set(s);i?l.add(r):l.delete(r),o(l)}else o(ki(e,i))})},mounted:Ar,beforeUpdate(e,t,n){e[Ee]=ct(n),Ar(e,t,n)}};function Ar(e,{value:t,oldValue:n},s){e._modelValue=t;let r;if(I(t))r=_s(t,s.props.value)>-1;else if(It(t))r=t.has(s.props.value);else{if(t===n)return;r=lt(t,ki(e,!0))}e.checked!==r&&(e.checked=r)}const Pc={created(e,{value:t},n){e.checked=lt(t,n.props.value),e[Ee]=ct(n),Ye(e,"change",()=>{e[Ee](Rt(e))})},beforeUpdate(e,{value:t,oldValue:n},s){e[Ee]=ct(s),t!==n&&(e.checked=lt(t,s.props.value))}},Rc={deep:!0,created(e,{value:t,modifiers:{number:n}},s){const r=It(t);Ye(e,"change",()=>{const i=Array.prototype.filter.call(e.options,o=>o.selected).map(o=>n?Mn(Rt(o)):Rt(o));e[Ee](e.multiple?r?new Set(i):i:i[0]),e._assigning=!0,si(()=>{e._assigning=!1})}),e[Ee]=ct(s)},mounted(e,{value:t}){Mr(e,t)},beforeUpdate(e,t,n){e[Ee]=ct(n)},updated(e,{value:t}){e._assigning||Mr(e,t)}};function Mr(e,t){const n=e.multiple,s=I(t);if(!(n&&!s&&!It(t))){for(let r=0,i=e.options.length;r<i;r++){const o=e.options[r],l=Rt(o);if(n)if(s){const c=typeof l;c==="string"||c==="number"?o.selected=t.some(u=>String(u)===String(l)):o.selected=_s(t,l)>-1}else o.selected=t.has(l);else if(lt(Rt(o),t)){e.selectedIndex!==r&&(e.selectedIndex=r);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function Rt(e){return"_value"in e?e._value:e.value}function ki(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const Ic={created(e,t,n){dn(e,t,n,null,"created")},mounted(e,t,n){dn(e,t,n,null,"mounted")},beforeUpdate(e,t,n,s){dn(e,t,n,s,"beforeUpdate")},updated(e,t,n,s){dn(e,t,n,s,"updated")}};function Fc(e,t){switch(e){case"SELECT":return Rc;case"TEXTAREA":return ds;default:switch(t){case"checkbox":return Oc;case"radio":return Pc;default:return ds}}}function dn(e,t,n,s,r){const o=Fc(e.tagName,n.props&&n.props.type)[r];o&&o(e,t,n,s)}const Lc=["ctrl","shift","alt","meta"],Dc={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Lc.some(n=>e[`${n}Key`]&&!t.includes(n))},Nc=(e,t)=>{if(!e)return e;const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(r,...i)=>{for(let o=0;o<t.length;o++){const l=Dc[t[o]];if(l&&l(r,t))return}return e(r,...i)})},$c={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Of=(e,t)=>{const n=e._withKeys||(e._withKeys={}),s=t.join(".");return n[s]||(n[s]=r=>{if(!("key"in r))return;const i=ft(r.key);if(t.some(o=>o===i||$c[o]===i))return e(r)})},Hc=ie({patchProp:bc},ec);let Or;function jc(){return Or||(Or=Rl(Hc))}const Vc=(...e)=>{const t=jc().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=Bc(s);if(!r)return;const i=t._component;!H(i)&&!i.render&&!i.template&&(i.template=r.innerHTML),r.nodeType===1&&(r.textContent="");const o=n(r,!1,Uc(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),o},t};function Uc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Bc(e){return te(e)?document.querySelector(e):e}const Kc="modulepreload",kc=function(e){return"/"+e},Pr={},Wc=function(t,n,s){let r=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),l=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));r=Promise.allSettled(n.map(c=>{if(c=kc(c),c in Pr)return;Pr[c]=!0;const u=c.endsWith(".css"),a=u?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${a}`))return;const h=document.createElement("link");if(h.rel=u?"stylesheet":Kc,u||(h.as="script"),h.crossOrigin="",h.href=c,l&&h.setAttribute("nonce",l),document.head.appendChild(h),u)return new Promise((p,v)=>{h.addEventListener("load",p),h.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function i(o){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=o,window.dispatchEvent(l),!l.defaultPrevented)throw o}return r.then(o=>{for(const l of o||[])l.status==="rejected"&&i(l.reason);return t().catch(i)})},ge=In({ready:!1,isolation:!1,user:null,adminOwnerUsername:""}),qc=()=>{var e;return ge.isolation&&((e=ge.user)==null?void 0:e.role)==="admin"},Pf=()=>{var e;return ge.isolation?`.user.${((e=ge.user)==null?void 0:e.username)||"anonymous"}`:""};function Gc(e,t="/",n=(s=>(s=globalThis.location)==null?void 0:s.origin)()||"http://localhost"){if(typeof e!="string"&&!(e instanceof URL))return e;const r=String(e);if(!r.startsWith("/")&&!/^https?:\/\//i.test(r))return e;const i=new URL(r,n);if(i.origin!==n||!/^\/(api(?:\/|$)|events(?:\/|$)|vendor(?:\/|$))/.test(i.pathname))return e;const o=`/${t.split("/").filter(Boolean).join("/")}`;return o==="/"?e:(i.pathname=o+i.pathname,`${i.pathname}${i.search}${i.hash}`)}const Jc=e=>Gc(Yc(e));function Yc(e){var s;if(!qc()||!ge.adminOwnerUsername||typeof e!="string"&&!(e instanceof URL))return e;const t=((s=globalThis.location)==null?void 0:s.origin)||"http://localhost",n=new URL(String(e),t);return n.origin!==t||!/^\/(api(?:\/|$)|events(?:\/|$))/.test(n.pathname)||/^\/api\/(auth|admin|login|memory|cpa-quota|cpa-config|prompt-config|plugins|tools)(?:\/|$)/.test(n.pathname)?e:(n.searchParams.set("ownerUsername",ge.adminOwnerUsername),`${n.pathname}${n.search}${n.hash}`)}const Rr=async(e,t)=>{var s;const n=await globalThis.fetch(Jc(e),t);return n.status===401&&!String(e).includes("/api/auth/")&&((s=globalThis.dispatchEvent)==null||s.call(globalThis,new Event("neo-auth-required"))),n},zc=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Xc={key:1,class:"auth-screen","aria-label":"用户登录"},Zc=["aria-busy"],Qc={class:"auth-fields"},ef={class:"icon-field"},tf=["aria-invalid","aria-describedby"],nf={class:"icon-field"},sf=["type","aria-invalid","aria-describedby"],rf=["aria-label","aria-pressed"],of={viewBox:"0 0 24 24","aria-hidden":"true"},lf={key:0,d:"m3 3 18 18"},cf={class:"auth-actions"},ff={class:"status-slot"},af={key:0,id:"auth-error",class:"auth-error",role:"alert"},uf={class:"sr-only"},df=["aria-label","disabled"],hf={key:0,class:"spinner","aria-hidden":"true"},pf={key:1,viewBox:"0 0 24 24","aria-hidden":"true"},gf={key:1,class:"connecting",role:"status","aria-label":"正在连接服务"},mf={key:1,class:"spinner","aria-hidden":"true"},_f={key:2,class:"sr-only",role:"alert"},yf={__name:"AuthGate",setup(e){const t=Xo(()=>Wc(()=>import("./App-DAtURpfb.js"),__vite__mapDeps([0,1]))),n=ot(""),s=ot(""),r=ot(""),i=ot(!1),o=ot(!1);async function l(){r.value="";try{const h=await Rr("/api/auth/status",{cache:"no-store"});if(!h.ok)throw new Error("无法读取登录状态");const p=await h.json();if(typeof p.isolation!="boolean")throw new Error("登录状态无效");Object.assign(ge,p,{ready:!0})}catch(h){r.value=h.message}}async function c(){var h;if(!i.value){if(!n.value||!s.value){r.value="请输入用户名和密码",(h=document.getElementById(n.value?"auth-password":"auth-username"))==null||h.focus();return}i.value=!0,r.value="";try{const p=await Rr("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:n.value,password:s.value})}),v=await p.json();if(!p.ok)throw new Error(v.error||"登录失败");s.value="",location.reload()}catch(p){r.value=p.message}finally{i.value=!1}}}const u=()=>{ge.user=null,s.value=""};let a;return Ms(async()=>{window.addEventListener("neo-auth-required",u),await l(),a=setInterval(()=>{ge.isolation&&ge.user&&l()},3e4)}),Os(()=>{clearInterval(a),window.removeEventListener("neo-auth-required",u)}),(h,p)=>{var v;return gt(ge).ready&&(!gt(ge).isolation||gt(ge).user)?(ve(),Ii(gt(t),{key:((v=gt(ge).user)==null?void 0:v.username)||"local"})):(ve(),Ae("main",Xc,[p[12]||(p[12]=B("div",{class:"motion-field","aria-hidden":"true"},[B("i",{class:"flow flow-a"}),B("i",{class:"flow flow-b"})],-1)),B("form",{class:Pn(["auth-card",{shaking:r.value}]),"aria-label":"用户登录","aria-busy":i.value,novalidate:"",onSubmit:Nc(c,["prevent"])},[gt(ge).ready?(ve(),Ae(Ce,{key:0},[B("div",Qc,[B("div",ef,[ks(B("input",{id:"auth-username","onUpdate:modelValue":p[0]||(p[0]=C=>n.value=C),"aria-label":"用户名",name:"username",autocomplete:"username",autocapitalize:"none",spellcheck:!1,maxlength:"100",enterkeyhint:"next",required:"","aria-invalid":!!r.value,"aria-describedby":r.value?"auth-error":void 0},null,8,tf),[[ds,n.value]]),p[3]||(p[3]=B("svg",{class:"field-icon",viewBox:"0 0 24 24","aria-hidden":"true"},[B("circle",{cx:"12",cy:"8",r:"3.5"}),B("path",{d:"M5 20c0-4 2.5-6 7-6s7 2 7 6"})],-1)),p[4]||(p[4]=B("i",{class:"field-line","aria-hidden":"true"},null,-1))]),B("div",nf,[ks(B("input",{id:"auth-password","onUpdate:modelValue":p[1]||(p[1]=C=>s.value=C),"aria-label":"密码",name:"password",type:o.value?"text":"password",autocomplete:"current-password",enterkeyhint:"go",required:"","aria-invalid":!!r.value,"aria-describedby":r.value?"auth-error":void 0},null,8,sf),[[Ic,s.value]]),p[7]||(p[7]=B("svg",{class:"field-icon",viewBox:"0 0 24 24","aria-hidden":"true"},[B("rect",{x:"5",y:"10",width:"14",height:"11",rx:"3"}),B("path",{d:"M8 10V7a4 4 0 0 1 8 0v3M12 14v3"})],-1)),p[8]||(p[8]=B("i",{class:"field-line","aria-hidden":"true"},null,-1)),B("button",{class:"password-toggle",type:"button","aria-label":o.value?"隐藏密码":"显示密码","aria-pressed":o.value,onClick:p[2]||(p[2]=C=>o.value=!o.value)},[(ve(),Ae("svg",of,[p[5]||(p[5]=B("path",{d:"M2 12s4-6 10-6 10 6 10 6-4 6-10 6-10-6-10-6Z"},null,-1)),p[6]||(p[6]=B("circle",{cx:"12",cy:"12",r:"3"},null,-1)),o.value?(ve(),Ae("path",lf)):qn("",!0)]))],8,rf)])]),B("div",cf,[B("div",ff,[r.value?(ve(),Ae("div",af,[p[9]||(p[9]=B("svg",{viewBox:"0 0 24 24","aria-hidden":"true"},[B("circle",{cx:"12",cy:"12",r:"9"}),B("path",{d:"M12 7v6m0 3h.01"})],-1)),B("span",uf,zn(r.value),1)])):qn("",!0)]),B("button",{class:"submit-button",type:"submit","aria-label":i.value?"正在验证":"登录",disabled:i.value},[i.value?(ve(),Ae("i",hf)):(ve(),Ae("svg",pf,[...p[10]||(p[10]=[B("path",{d:"M5 12h14m-6-6 6 6-6 6"},null,-1)])]))],8,df)])],64)):(ve(),Ae("div",gf,[r.value?(ve(),Ae("button",{key:0,class:"retry-button",type:"button","aria-label":"重试",onClick:l},[...p[11]||(p[11]=[B("svg",{viewBox:"0 0 24 24","aria-hidden":"true"},[B("path",{d:"M20 7v5h-5M20 12a8 8 0 1 0-2 6"})],-1)])])):(ve(),Ae("i",mf)),r.value?(ve(),Ae("span",_f,zn(r.value),1)):qn("",!0)]))],42,Zc)]))}}},bf=zc(yf,[["__scopeId","data-v-67ef8410"]]);Vc(bf).mount("#app");export{Tf as A,Ii as B,qc as C,ge as D,Pf as E,Ce as F,Af as G,ye as H,Jc as I,$o as J,Mf as K,Ic as L,Oc as M,Pc as N,Cf as T,zc as _,ve as a,qn as b,Ae as c,Rr as d,Ef as e,B as f,ot as g,Sf as h,xf as i,zl as j,Ms as k,si as l,jl as m,Pn as n,Os as o,ks as p,ds as q,In as r,wf as s,zn as t,gt as u,Rc as v,Kn as w,Of as x,Nc as y,ms as z};
|
|
18
|
+
**/let as;const cr=typeof window<"u"&&window.trustedTypes;if(cr)try{as=cr.createPolicy("vue",{createHTML:e=>e})}catch{}const Hi=as?e=>as.createHTML(e):e=>e,Zl="http://www.w3.org/2000/svg",Ql="http://www.w3.org/1998/Math/MathML",We=typeof document<"u"?document:null,fr=We&&We.createElement("template"),ec={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,s)=>{const r=t==="svg"?We.createElementNS(Zl,e):t==="mathml"?We.createElementNS(Ql,e):n?We.createElement(e,{is:n}):We.createElement(e);return e==="select"&&s&&s.multiple!=null&&r.setAttribute("multiple",s.multiple),r},createText:e=>We.createTextNode(e),createComment:e=>We.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>We.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,s,r,i){const o=n?n.previousSibling:t.lastChild;if(r&&(r===i||r.nextSibling))for(;t.insertBefore(r.cloneNode(!0),n),!(r===i||!(r=r.nextSibling)););else{fr.innerHTML=Hi(s==="svg"?`<svg>${e}</svg>`:s==="mathml"?`<math>${e}</math>`:e);const l=fr.content;if(s==="svg"||s==="mathml"){const c=l.firstChild;for(;c.firstChild;)l.appendChild(c.firstChild);l.removeChild(c)}t.insertBefore(l,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},tt="transition",Ht="animation",Pt=Symbol("_vtc"),ji={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},tc=ie({},Go,ji),pt=(e,t=[])=>{I(e)?e.forEach(n=>n(...t)):e&&e(...t)},ar=e=>e?I(e)?e.some(t=>t.length>1):e.length>1:!1;function nc(e){const t={};for(const A in e)A in ji||(t[A]=e[A]);if(e.css===!1)return t;const{name:n="v",type:s,duration:r,enterFromClass:i=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:l=`${n}-enter-to`,appearFromClass:c=i,appearActiveClass:u=o,appearToClass:a=l,leaveFromClass:h=`${n}-leave-from`,leaveActiveClass:p=`${n}-leave-active`,leaveToClass:v=`${n}-leave-to`}=e,C=sc(r),x=C&&C[0],N=C&&C[1],{onBeforeEnter:D,onEnter:M,onEnterCancelled:F,onLeave:O,onLeaveCancelled:V,onBeforeAppear:se=D,onAppear:j=M,onAppearCancelled:G=F}=t,P=(A,X,oe,Ke)=>{A._enterCancelled=Ke,rt(A,X?a:l),rt(A,X?u:o),oe&&oe()},K=(A,X)=>{A._isLeaving=!1,rt(A,h),rt(A,v),rt(A,p),X&&X()},J=A=>(X,oe)=>{const Ke=A?j:M,ce=()=>P(X,A,oe);pt(Ke,[X,ce]),ur(()=>{rt(X,A?c:i),Ne(X,A?a:l),ar(Ke)||dr(X,s,x,ce)})};return ie(t,{onBeforeEnter(A){pt(D,[A]),Ne(A,i),Ne(A,o)},onBeforeAppear(A){pt(se,[A]),Ne(A,c),Ne(A,u)},onEnter:J(!1),onAppear:J(!0),onLeave(A,X){A._isLeaving=!0;const oe=()=>K(A,X);Ne(A,h),A._enterCancelled?(Ne(A,p),us(A)):(us(A),Ne(A,p)),ur(()=>{A._isLeaving&&(rt(A,h),Ne(A,v),ar(O)||dr(A,s,N,oe))}),pt(O,[A,oe])},onEnterCancelled(A){P(A,!1,void 0,!0),pt(F,[A])},onAppearCancelled(A){P(A,!0,void 0,!0),pt(G,[A])},onLeaveCancelled(A){K(A),pt(V,[A])}})}function sc(e){if(e==null)return null;if(q(e))return[Gn(e.enter),Gn(e.leave)];{const t=Gn(e);return[t,t]}}function Gn(e){return Xi(e)}function Ne(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Pt]||(e[Pt]=new Set)).add(t)}function rt(e,t){t.split(/\s+/).forEach(s=>s&&e.classList.remove(s));const n=e[Pt];n&&(n.delete(t),n.size||(e[Pt]=void 0))}function ur(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let rc=0;function dr(e,t,n,s){const r=e._endId=++rc,i=()=>{r===e._endId&&s()};if(n!=null)return setTimeout(i,n);const{type:o,timeout:l,propCount:c}=Vi(e,t);if(!o)return s();const u=o+"end";let a=0;const h=()=>{e.removeEventListener(u,p),i()},p=v=>{v.target===e&&++a>=c&&h()};setTimeout(()=>{a<c&&h()},l+1),e.addEventListener(u,p)}function Vi(e,t){const n=window.getComputedStyle(e),s=C=>(n[C]||"").split(", "),r=s(`${tt}Delay`),i=s(`${tt}Duration`),o=hr(r,i),l=s(`${Ht}Delay`),c=s(`${Ht}Duration`),u=hr(l,c);let a=null,h=0,p=0;t===tt?o>0&&(a=tt,h=o,p=i.length):t===Ht?u>0&&(a=Ht,h=u,p=c.length):(h=Math.max(o,u),a=h>0?o>u?tt:Ht:null,p=a?a===tt?i.length:c.length:0);const v=a===tt&&/\b(?:transform|all)(?:,|$)/.test(s(`${tt}Property`).toString());return{type:a,timeout:h,propCount:p,hasTransform:v}}function hr(e,t){for(;e.length<t.length;)e=e.concat(e);return Math.max(...t.map((n,s)=>pr(n)+pr(e[s])))}function pr(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function us(e){return(e?e.ownerDocument:document).body.offsetHeight}function ic(e,t,n){const s=e[Pt];s&&(t=(t?[t,...s]:[...s]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const gr=Symbol("_vod"),oc=Symbol("_vsh"),lc=Symbol(""),cc=/(?:^|;)\s*display\s*:/;function fc(e,t,n){const s=e.style,r=te(n);let i=!1;if(n&&!r){if(t)if(te(t))for(const o of t.split(";")){const l=o.slice(0,o.indexOf(":")).trim();n[l]==null&&Ut(s,l,"")}else for(const o in t)n[o]==null&&Ut(s,o,"");for(const o in n){o==="display"&&(i=!0);const l=n[o];l!=null?uc(e,o,!te(t)&&t?t[o]:void 0,l)||Ut(s,o,l):Ut(s,o,"")}}else if(r){if(t!==n){const o=s[lc];o&&(n+=";"+o),s.cssText=n,i=cc.test(n)}}else t&&e.removeAttribute("style");gr in e&&(e[gr]=i?s.display:"",e[oc]&&(s.display="none"))}const mr=/\s*!important$/;function Ut(e,t,n){if(I(n))n.forEach(s=>Ut(e,t,s));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const s=ac(e,t);mr.test(n)?e.setProperty(ft(s),n.replace(mr,""),"important"):e[s]=n}}const _r=["Webkit","Moz","ms"],Jn={};function ac(e,t){const n=Jn[t];if(n)return n;let s=_e(t);if(s!=="filter"&&s in e)return Jn[t]=s;s=An(s);for(let r=0;r<_r.length;r++){const i=_r[r]+s;if(i in e)return Jn[t]=i}return t}function uc(e,t,n,s){return e.tagName==="TEXTAREA"&&(t==="width"||t==="height")&&te(s)&&n===s}const yr="http://www.w3.org/1999/xlink";function br(e,t,n,s,r,i=so(t)){s&&t.startsWith("xlink:")?n==null?e.removeAttributeNS(yr,t.slice(6,t.length)):e.setAttributeNS(yr,t,n):n==null||i&&!$r(n)?e.removeAttribute(t):e.setAttribute(t,i?"":Be(n)?String(n):n)}function vr(e,t,n,s,r){if(t==="innerHTML"||t==="textContent"){n!=null&&(e[t]=t==="innerHTML"?Hi(n):n);return}const i=e.tagName;if(t==="value"&&i!=="PROGRESS"&&!i.includes("-")){const l=i==="OPTION"?e.getAttribute("value")||"":e.value,c=n==null?e.type==="checkbox"?"on":"":String(n);(l!==c||!("_value"in e))&&(e.value=c),n==null&&e.removeAttribute(t),e._value=n;return}let o=!1;if(n===""||n==null){const l=typeof e[t];l==="boolean"?n=$r(n):n==null&&l==="string"?(n="",o=!0):l==="number"&&(n=0,o=!0)}try{e[t]=n}catch{}o&&e.removeAttribute(r||t)}function Ye(e,t,n,s){e.addEventListener(t,n,s)}function dc(e,t,n,s){e.removeEventListener(t,n,s)}const xr=Symbol("_vei");function hc(e,t,n,s,r=null){const i=e[xr]||(e[xr]={}),o=i[t];if(s&&o)o.value=s;else{const[l,c]=pc(t);if(s){const u=i[t]=_c(s,r);Ye(e,l,u,c)}else o&&(dc(e,l,o,c),i[t]=void 0)}}const wr=/(?:Once|Passive|Capture)$/;function pc(e){let t;if(wr.test(e)){t={};let s;for(;s=e.match(wr);)e=e.slice(0,e.length-s[0].length),t[s[0].toLowerCase()]=!0}return[e[2]===":"?e.slice(3):ft(e.slice(2)),t]}let Yn=0;const gc=Promise.resolve(),mc=()=>Yn||(gc.then(()=>Yn=0),Yn=Date.now());function _c(e,t){const n=s=>{if(!s._vts)s._vts=Date.now();else if(s._vts<=n.attached)return;Pe(yc(s,n.value),t,5,[s])};return n.value=e,n.attached=mc(),n}function yc(e,t){if(I(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(s=>r=>!r._stopped&&s&&s(r))}else return t}const Sr=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,bc=(e,t,n,s,r,i)=>{const o=r==="svg";t==="class"?ic(e,s,o):t==="style"?fc(e,n,s):Cn(t)?Tn(t)||hc(e,t,n,s,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):vc(e,t,s,o))?(vr(e,t,s),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&br(e,t,s,o,i,t!=="value")):e._isVueCE&&(xc(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!te(s)))?vr(e,_e(t),s,i,t):(t==="true-value"?e._trueValue=s:t==="false-value"&&(e._falseValue=s),br(e,t,s,o))};function vc(e,t,n,s){if(s)return!!(t==="innerHTML"||t==="textContent"||t in e&&Sr(t)&&H(n));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const r=e.tagName;if(r==="IMG"||r==="VIDEO"||r==="CANVAS"||r==="SOURCE")return!1}return Sr(t)&&te(n)?!1:t in e}function xc(e,t){const n=e._def.props;if(!n)return!1;const s=_e(t);return Array.isArray(n)?n.some(r=>_e(r)===s):Object.keys(n).some(r=>_e(r)===s)}const Ui=new WeakMap,Bi=new WeakMap,Sn=Symbol("_moveCb"),Cr=Symbol("_enterCb"),wc=e=>(delete e.props.mode,e),Sc=wc({name:"TransitionGroup",props:ie({},tc,{tag:String,moveClass:String}),setup(e,{slots:t}){const n=Di(),s=qo();let r,i;return hi(()=>{if(!r.length)return;const o=e.moveClass||`${e.name||"v"}-move`;if(!Ac(r[0].el,n.vnode.el,o)){r=[];return}r.forEach(Cc),r.forEach(Tc);const l=r.filter(Ec);us(n.vnode.el),l.forEach(c=>{const u=c.el,a=u.style;Ne(u,o),a.transform=a.webkitTransform=a.transitionDuration="";const h=u[Sn]=p=>{p&&p.target!==u||(!p||p.propertyName.endsWith("transform"))&&(u.removeEventListener("transitionend",h),u[Sn]=null,rt(u,o))};u.addEventListener("transitionend",h)}),r=[]}),()=>{const o=k(e),l=nc(o);let c=o.tag||Ce;if(r=[],i)for(let u=0;u<i.length;u++){const a=i[u];a.el&&a.el instanceof Element&&(r.push(a),Zt(a,rs(a,l,s,n)),Ui.set(a,Ki(a.el)))}i=t.default?ui(t.default()):[];for(let u=0;u<i.length;u++){const a=i[u];a.key!=null&&Zt(a,rs(a,l,s,n))}return ye(c,null,i)}}}),Mf=Sc;function Cc(e){const t=e.el;t[Sn]&&t[Sn](),t[Cr]&&t[Cr]()}function Tc(e){Bi.set(e,Ki(e.el))}function Ec(e){const t=Ui.get(e),n=Bi.get(e),s=t.left-n.left,r=t.top-n.top;if(s||r){const i=e.el,o=i.style,l=i.getBoundingClientRect();let c=1,u=1;return i.offsetWidth&&(c=l.width/i.offsetWidth),i.offsetHeight&&(u=l.height/i.offsetHeight),(!Number.isFinite(c)||c===0)&&(c=1),(!Number.isFinite(u)||u===0)&&(u=1),Math.abs(c-1)<.01&&(c=1),Math.abs(u-1)<.01&&(u=1),o.transform=o.webkitTransform=`translate(${s/c}px,${r/u}px)`,o.transitionDuration="0s",e}}function Ki(e){const t=e.getBoundingClientRect();return{left:t.left,top:t.top}}function Ac(e,t,n){const s=e.cloneNode(),r=e[Pt];r&&r.forEach(l=>{l.split(/\s+/).forEach(c=>c&&s.classList.remove(c))}),n.split(/\s+/).forEach(l=>l&&s.classList.add(l)),s.style.display="none";const i=t.nodeType===1?t:t.parentNode;i.appendChild(s);const{hasTransform:o}=Vi(s);return i.removeChild(s),o}const ct=e=>{const t=e.props["onUpdate:modelValue"]||!1;return I(t)?n=>hn(t,n):t};function Mc(e){e.target.composing=!0}function Tr(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const Ee=Symbol("_assign");function Er(e,t,n){return t&&(e=e.trim()),n&&(e=Mn(e)),e}const ds={created(e,{modifiers:{lazy:t,trim:n,number:s}},r){e[Ee]=ct(r);const i=s||r.props&&r.props.type==="number";Ye(e,t?"change":"input",o=>{o.target.composing||e[Ee](Er(e.value,n,i))}),(n||i)&&Ye(e,"change",()=>{e.value=Er(e.value,n,i)}),t||(Ye(e,"compositionstart",Mc),Ye(e,"compositionend",Tr),Ye(e,"change",Tr))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:s,trim:r,number:i}},o){if(e[Ee]=ct(o),e.composing)return;const l=(i||e.type==="number")&&!/^0\d/.test(e.value)?Mn(e.value):e.value,c=t??"";if(l===c)return;const u=e.getRootNode();(u instanceof Document||u instanceof ShadowRoot)&&u.activeElement===e&&e.type!=="range"&&(s&&t===n||r&&e.value.trim()===c)||(e.value=c)}},Oc={deep:!0,created(e,t,n){e[Ee]=ct(n),Ye(e,"change",()=>{const s=e._modelValue,r=Rt(e),i=e.checked,o=e[Ee];if(I(s)){const l=_s(s,r),c=l!==-1;if(i&&!c)o(s.concat(r));else if(!i&&c){const u=[...s];u.splice(l,1),o(u)}}else if(It(s)){const l=new Set(s);i?l.add(r):l.delete(r),o(l)}else o(ki(e,i))})},mounted:Ar,beforeUpdate(e,t,n){e[Ee]=ct(n),Ar(e,t,n)}};function Ar(e,{value:t,oldValue:n},s){e._modelValue=t;let r;if(I(t))r=_s(t,s.props.value)>-1;else if(It(t))r=t.has(s.props.value);else{if(t===n)return;r=lt(t,ki(e,!0))}e.checked!==r&&(e.checked=r)}const Pc={created(e,{value:t},n){e.checked=lt(t,n.props.value),e[Ee]=ct(n),Ye(e,"change",()=>{e[Ee](Rt(e))})},beforeUpdate(e,{value:t,oldValue:n},s){e[Ee]=ct(s),t!==n&&(e.checked=lt(t,s.props.value))}},Rc={deep:!0,created(e,{value:t,modifiers:{number:n}},s){const r=It(t);Ye(e,"change",()=>{const i=Array.prototype.filter.call(e.options,o=>o.selected).map(o=>n?Mn(Rt(o)):Rt(o));e[Ee](e.multiple?r?new Set(i):i:i[0]),e._assigning=!0,si(()=>{e._assigning=!1})}),e[Ee]=ct(s)},mounted(e,{value:t}){Mr(e,t)},beforeUpdate(e,t,n){e[Ee]=ct(n)},updated(e,{value:t}){e._assigning||Mr(e,t)}};function Mr(e,t){const n=e.multiple,s=I(t);if(!(n&&!s&&!It(t))){for(let r=0,i=e.options.length;r<i;r++){const o=e.options[r],l=Rt(o);if(n)if(s){const c=typeof l;c==="string"||c==="number"?o.selected=t.some(u=>String(u)===String(l)):o.selected=_s(t,l)>-1}else o.selected=t.has(l);else if(lt(Rt(o),t)){e.selectedIndex!==r&&(e.selectedIndex=r);return}}!n&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function Rt(e){return"_value"in e?e._value:e.value}function ki(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const Ic={created(e,t,n){dn(e,t,n,null,"created")},mounted(e,t,n){dn(e,t,n,null,"mounted")},beforeUpdate(e,t,n,s){dn(e,t,n,s,"beforeUpdate")},updated(e,t,n,s){dn(e,t,n,s,"updated")}};function Fc(e,t){switch(e){case"SELECT":return Rc;case"TEXTAREA":return ds;default:switch(t){case"checkbox":return Oc;case"radio":return Pc;default:return ds}}}function dn(e,t,n,s,r){const o=Fc(e.tagName,n.props&&n.props.type)[r];o&&o(e,t,n,s)}const Lc=["ctrl","shift","alt","meta"],Dc={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Lc.some(n=>e[`${n}Key`]&&!t.includes(n))},Nc=(e,t)=>{if(!e)return e;const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(r,...i)=>{for(let o=0;o<t.length;o++){const l=Dc[t[o]];if(l&&l(r,t))return}return e(r,...i)})},$c={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Of=(e,t)=>{const n=e._withKeys||(e._withKeys={}),s=t.join(".");return n[s]||(n[s]=r=>{if(!("key"in r))return;const i=ft(r.key);if(t.some(o=>o===i||$c[o]===i))return e(r)})},Hc=ie({patchProp:bc},ec);let Or;function jc(){return Or||(Or=Rl(Hc))}const Vc=(...e)=>{const t=jc().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=Bc(s);if(!r)return;const i=t._component;!H(i)&&!i.render&&!i.template&&(i.template=r.innerHTML),r.nodeType===1&&(r.textContent="");const o=n(r,!1,Uc(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),o},t};function Uc(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function Bc(e){return te(e)?document.querySelector(e):e}const Kc="modulepreload",kc=function(e){return"/"+e},Pr={},Wc=function(t,n,s){let r=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),l=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));r=Promise.allSettled(n.map(c=>{if(c=kc(c),c in Pr)return;Pr[c]=!0;const u=c.endsWith(".css"),a=u?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${a}`))return;const h=document.createElement("link");if(h.rel=u?"stylesheet":Kc,u||(h.as="script"),h.crossOrigin="",h.href=c,l&&h.setAttribute("nonce",l),document.head.appendChild(h),u)return new Promise((p,v)=>{h.addEventListener("load",p),h.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${c}`)))})}))}function i(o){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=o,window.dispatchEvent(l),!l.defaultPrevented)throw o}return r.then(o=>{for(const l of o||[])l.status==="rejected"&&i(l.reason);return t().catch(i)})},ge=In({ready:!1,isolation:!1,user:null,adminOwnerUsername:""}),qc=()=>{var e;return ge.isolation&&((e=ge.user)==null?void 0:e.role)==="admin"},Pf=()=>{var e;return ge.isolation?`.user.${((e=ge.user)==null?void 0:e.username)||"anonymous"}`:""};function Gc(e,t="/",n=(s=>(s=globalThis.location)==null?void 0:s.origin)()||"http://localhost"){if(typeof e!="string"&&!(e instanceof URL))return e;const r=String(e);if(!r.startsWith("/")&&!/^https?:\/\//i.test(r))return e;const i=new URL(r,n);if(i.origin!==n||!/^\/(api(?:\/|$)|events(?:\/|$)|vendor(?:\/|$))/.test(i.pathname))return e;const o=`/${t.split("/").filter(Boolean).join("/")}`;return o==="/"?e:(i.pathname=o+i.pathname,`${i.pathname}${i.search}${i.hash}`)}const Jc=e=>Gc(Yc(e));function Yc(e){var s;if(!qc()||!ge.adminOwnerUsername||typeof e!="string"&&!(e instanceof URL))return e;const t=((s=globalThis.location)==null?void 0:s.origin)||"http://localhost",n=new URL(String(e),t);return n.origin!==t||!/^\/(api(?:\/|$)|events(?:\/|$))/.test(n.pathname)||/^\/api\/(auth|admin|login|memory|cpa-quota|cpa-config|prompt-config|plugins|tools)(?:\/|$)/.test(n.pathname)?e:(n.searchParams.set("ownerUsername",ge.adminOwnerUsername),`${n.pathname}${n.search}${n.hash}`)}const Rr=async(e,t)=>{var s;const n=await globalThis.fetch(Jc(e),t);return n.status===401&&!String(e).includes("/api/auth/")&&((s=globalThis.dispatchEvent)==null||s.call(globalThis,new Event("neo-auth-required"))),n},zc=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Xc={key:1,class:"auth-screen","aria-label":"用户登录"},Zc=["aria-busy"],Qc={class:"auth-fields"},ef={class:"icon-field"},tf=["aria-invalid","aria-describedby"],nf={class:"icon-field"},sf=["type","aria-invalid","aria-describedby"],rf=["aria-label","aria-pressed"],of={viewBox:"0 0 24 24","aria-hidden":"true"},lf={key:0,d:"m3 3 18 18"},cf={class:"auth-actions"},ff={class:"status-slot"},af={key:0,id:"auth-error",class:"auth-error",role:"alert"},uf={class:"sr-only"},df=["aria-label","disabled"],hf={key:0,class:"spinner","aria-hidden":"true"},pf={key:1,viewBox:"0 0 24 24","aria-hidden":"true"},gf={key:1,class:"connecting",role:"status","aria-label":"正在连接服务"},mf={key:1,class:"spinner","aria-hidden":"true"},_f={key:2,class:"sr-only",role:"alert"},yf={__name:"AuthGate",setup(e){const t=Xo(()=>Wc(()=>import("./App-BBTgdI-j.js"),__vite__mapDeps([0,1]))),n=ot(""),s=ot(""),r=ot(""),i=ot(!1),o=ot(!1);async function l(){r.value="";try{const h=await Rr("/api/auth/status",{cache:"no-store"});if(!h.ok)throw new Error("无法读取登录状态");const p=await h.json();if(typeof p.isolation!="boolean")throw new Error("登录状态无效");Object.assign(ge,p,{ready:!0})}catch(h){r.value=h.message}}async function c(){var h;if(!i.value){if(!n.value||!s.value){r.value="请输入用户名和密码",(h=document.getElementById(n.value?"auth-password":"auth-username"))==null||h.focus();return}i.value=!0,r.value="";try{const p=await Rr("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:n.value,password:s.value})}),v=await p.json();if(!p.ok)throw new Error(v.error||"登录失败");s.value="",location.reload()}catch(p){r.value=p.message}finally{i.value=!1}}}const u=()=>{ge.user=null,s.value=""};let a;return Ms(async()=>{window.addEventListener("neo-auth-required",u),await l(),a=setInterval(()=>{ge.isolation&&ge.user&&l()},3e4)}),Os(()=>{clearInterval(a),window.removeEventListener("neo-auth-required",u)}),(h,p)=>{var v;return gt(ge).ready&&(!gt(ge).isolation||gt(ge).user)?(ve(),Ii(gt(t),{key:((v=gt(ge).user)==null?void 0:v.username)||"local"})):(ve(),Ae("main",Xc,[p[12]||(p[12]=B("div",{class:"motion-field","aria-hidden":"true"},[B("i",{class:"flow flow-a"}),B("i",{class:"flow flow-b"})],-1)),B("form",{class:Pn(["auth-card",{shaking:r.value}]),"aria-label":"用户登录","aria-busy":i.value,novalidate:"",onSubmit:Nc(c,["prevent"])},[gt(ge).ready?(ve(),Ae(Ce,{key:0},[B("div",Qc,[B("div",ef,[ks(B("input",{id:"auth-username","onUpdate:modelValue":p[0]||(p[0]=C=>n.value=C),"aria-label":"用户名",name:"username",autocomplete:"username",autocapitalize:"none",spellcheck:!1,maxlength:"100",enterkeyhint:"next",required:"","aria-invalid":!!r.value,"aria-describedby":r.value?"auth-error":void 0},null,8,tf),[[ds,n.value]]),p[3]||(p[3]=B("svg",{class:"field-icon",viewBox:"0 0 24 24","aria-hidden":"true"},[B("circle",{cx:"12",cy:"8",r:"3.5"}),B("path",{d:"M5 20c0-4 2.5-6 7-6s7 2 7 6"})],-1)),p[4]||(p[4]=B("i",{class:"field-line","aria-hidden":"true"},null,-1))]),B("div",nf,[ks(B("input",{id:"auth-password","onUpdate:modelValue":p[1]||(p[1]=C=>s.value=C),"aria-label":"密码",name:"password",type:o.value?"text":"password",autocomplete:"current-password",enterkeyhint:"go",required:"","aria-invalid":!!r.value,"aria-describedby":r.value?"auth-error":void 0},null,8,sf),[[Ic,s.value]]),p[7]||(p[7]=B("svg",{class:"field-icon",viewBox:"0 0 24 24","aria-hidden":"true"},[B("rect",{x:"5",y:"10",width:"14",height:"11",rx:"3"}),B("path",{d:"M8 10V7a4 4 0 0 1 8 0v3M12 14v3"})],-1)),p[8]||(p[8]=B("i",{class:"field-line","aria-hidden":"true"},null,-1)),B("button",{class:"password-toggle",type:"button","aria-label":o.value?"隐藏密码":"显示密码","aria-pressed":o.value,onClick:p[2]||(p[2]=C=>o.value=!o.value)},[(ve(),Ae("svg",of,[p[5]||(p[5]=B("path",{d:"M2 12s4-6 10-6 10 6 10 6-4 6-10 6-10-6-10-6Z"},null,-1)),p[6]||(p[6]=B("circle",{cx:"12",cy:"12",r:"3"},null,-1)),o.value?(ve(),Ae("path",lf)):qn("",!0)]))],8,rf)])]),B("div",cf,[B("div",ff,[r.value?(ve(),Ae("div",af,[p[9]||(p[9]=B("svg",{viewBox:"0 0 24 24","aria-hidden":"true"},[B("circle",{cx:"12",cy:"12",r:"9"}),B("path",{d:"M12 7v6m0 3h.01"})],-1)),B("span",uf,zn(r.value),1)])):qn("",!0)]),B("button",{class:"submit-button",type:"submit","aria-label":i.value?"正在验证":"登录",disabled:i.value},[i.value?(ve(),Ae("i",hf)):(ve(),Ae("svg",pf,[...p[10]||(p[10]=[B("path",{d:"M5 12h14m-6-6 6 6-6 6"},null,-1)])]))],8,df)])],64)):(ve(),Ae("div",gf,[r.value?(ve(),Ae("button",{key:0,class:"retry-button",type:"button","aria-label":"重试",onClick:l},[...p[11]||(p[11]=[B("svg",{viewBox:"0 0 24 24","aria-hidden":"true"},[B("path",{d:"M20 7v5h-5M20 12a8 8 0 1 0-2 6"})],-1)])])):(ve(),Ae("i",mf)),r.value?(ve(),Ae("span",_f,zn(r.value),1)):qn("",!0)]))],42,Zc)]))}}},bf=zc(yf,[["__scopeId","data-v-67ef8410"]]);Vc(bf).mount("#app");export{Tf as A,Ii as B,qc as C,ge as D,Pf as E,Ce as F,Af as G,ye as H,Jc as I,$o as J,Mf as K,Ic as L,Oc as M,Pc as N,Cf as T,zc as _,ve as a,qn as b,Ae as c,Rr as d,Ef as e,B as f,ot as g,Sf as h,xf as i,zl as j,Ms as k,si as l,jl as m,Pn as n,Os as o,ks as p,ds as q,In as r,wf as s,zn as t,gt as u,Rc as v,Kn as w,Of as x,Nc as y,ms as z};
|
package/dist/index.html
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
})()
|
|
20
20
|
</script>
|
|
21
21
|
<title>neo runtime</title>
|
|
22
|
-
<script type="module" crossorigin src="/assets/index-
|
|
22
|
+
<script type="module" crossorigin src="/assets/index-B0Wkp2VZ.js"></script>
|
|
23
23
|
<link rel="stylesheet" crossorigin href="/assets/index-BXAwT7V2.css">
|
|
24
24
|
</head>
|
|
25
25
|
<body>
|
package/isolation.mjs
CHANGED
|
@@ -33,7 +33,7 @@ export function sanitizeIsolatedSnapshot(value) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/** Web-only identity boundary. The core receives neither credentials nor user identities. */
|
|
36
|
-
export async function createIsolationMode({ dataRoot, workspaceRoot, pluginDir, configFile, memoryState = () => ({ current: null, history: [] }), cpaQuotaMonitor, pluginSettings, toolSettings }) {
|
|
36
|
+
export async function createIsolationMode({ dataRoot, workspaceRoot, pluginDir, pluginManager, configFile, memoryState = () => ({ current: null, history: [] }), cpaQuotaMonitor, pluginSettings, toolSettings }) {
|
|
37
37
|
const config = await loadIsolationConfig(dataRoot, configFile);
|
|
38
38
|
if (!config.enabled) return {
|
|
39
39
|
enabled: false,
|
|
@@ -51,14 +51,14 @@ export async function createIsolationMode({ dataRoot, workspaceRoot, pluginDir,
|
|
|
51
51
|
const { installRuntimeRouterIdleCleanup } = await import('./runtime-router-cleanup.mjs');
|
|
52
52
|
installRuntimeRouterIdleCleanup();
|
|
53
53
|
const { createWorkspaceRuntimeManager } = await import('./runtime-workspaces.mjs');
|
|
54
|
-
const {
|
|
54
|
+
const { createPluginManager } = await import('./plugin-manager.mjs');
|
|
55
|
+
pluginManager ||= await createPluginManager({ directory: path.join(dataRoot, 'installed-plugins'), builtInDirectory: pluginDir, loadPlugins: core.loadNeoPlugins });
|
|
55
56
|
const { createWebPluginSettings } = await import('./plugin-settings.mjs');
|
|
56
57
|
const { createWebToolSettings } = await import('./tool-settings.mjs');
|
|
57
58
|
const { createChunkUploadHandler } = await import('./chunk-uploads.mjs');
|
|
58
59
|
const { workspaceFs, openWorkspaceRead, containerMode } = await import('./execution-backend.mjs');
|
|
59
60
|
const globalPlugins = pluginSettings || await createWebPluginSettings(path.join(dataRoot, 'plugins.json'));
|
|
60
61
|
const globalTools = toolSettings || await createWebToolSettings(path.join(dataRoot, 'tools.json'));
|
|
61
|
-
const startupPlugins = process.env.NEO_WEB_PLUGINS?.trim() || globalPlugins.globalEnabledIds();
|
|
62
62
|
const users = new Map();
|
|
63
63
|
let modelConfigQueue = Promise.resolve();
|
|
64
64
|
const withModelConfigLock = operation => {
|
|
@@ -101,11 +101,10 @@ export async function createIsolationMode({ dataRoot, workspaceRoot, pluginDir,
|
|
|
101
101
|
for (const key of ['NEO_DOWNLOADS_DIR', 'NEO_VIDEO_SHARE_DIR', 'NEO_XHS_ARTIFACTS_DIR']) delete pluginEnv[key];
|
|
102
102
|
const settings = await createWebPluginSettings(path.join(root, 'plugins.json'));
|
|
103
103
|
const tools = await createWebToolSettings(path.join(root, 'tools.json'));
|
|
104
|
-
const pluginHost =
|
|
105
|
-
|
|
106
|
-
enabled: startupPlugins, locked: Boolean(process.env.NEO_WEB_PLUGINS?.trim()),
|
|
104
|
+
const pluginHost = await pluginManager.createHost({
|
|
105
|
+
enabled: process.env.NEO_WEB_PLUGINS?.trim() || globalPlugins.globalEnabledIds(), locked: Boolean(process.env.NEO_WEB_PLUGINS?.trim()),
|
|
107
106
|
settings: { ...settings, globalEnabledIds: () => globalPlugins.globalEnabledIds(), setGlobalEnabled: ids => globalPlugins.setGlobalEnabled(ids) },
|
|
108
|
-
});
|
|
107
|
+
}, { appDataDir: root, env: pluginEnv });
|
|
109
108
|
const manager = createWorkspaceRuntimeManager({
|
|
110
109
|
projectRoot: workRoot, workspaceRoot: workRoot, registryFile: path.join(root, 'workspaces.json'),
|
|
111
110
|
createRuntime: options => core.createWebRuntime({
|
|
@@ -231,7 +230,7 @@ export async function createIsolationMode({ dataRoot, workspaceRoot, pluginDir,
|
|
|
231
230
|
const state = cpaQuotaMonitor?.getPublicState() || { config: { url: '', hasPassword: false }, quotas: [] };
|
|
232
231
|
jsonReply(res, isAdmin ? state : { quotas: state.quotas }); return true;
|
|
233
232
|
}
|
|
234
|
-
if (['/api/cpa-config', '/api/plugins/global', '/api/prompt-config', '/api/tools/global'].includes(url.pathname) || (isAdmin && ['/api/plugins', '/api/tools'].includes(url.pathname))) {
|
|
233
|
+
if (['/api/cpa-config', '/api/plugins/global', '/api/plugins/install', '/api/plugins/uninstall', '/api/prompt-config', '/api/tools/global'].includes(url.pathname) || (isAdmin && ['/api/plugins', '/api/tools'].includes(url.pathname))) {
|
|
235
234
|
if (!isAdmin) throw httpError(403, '仅超管可修改全局配置');
|
|
236
235
|
if (!['GET', 'POST'].includes(req.method)) throw httpError(405, '请求方法无效');
|
|
237
236
|
if (url.pathname === '/api/cpa-config') {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Optional host capability. Resource plugins know only this helper, not the desktop shell.
|
|
2
|
+
export function createLocalResourceHeaders({ enabled = false } = {}) {
|
|
3
|
+
return (req, absolutePath) => {
|
|
4
|
+
if (!enabled || req.method !== 'HEAD' || req.headers['x-neo-resource-action'] !== 'reveal') return {};
|
|
5
|
+
const address = req.socket?.remoteAddress;
|
|
6
|
+
if (!['127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(address)) return {};
|
|
7
|
+
if (req.headers['sec-fetch-site'] === 'cross-site') return {};
|
|
8
|
+
if (req.headers.origin) {
|
|
9
|
+
try { if (new URL(req.headers.origin).host !== req.headers.host) return {}; }
|
|
10
|
+
catch { return {}; }
|
|
11
|
+
}
|
|
12
|
+
// Percent encoding keeps Unicode and control characters out of HTTP header syntax.
|
|
13
|
+
return { 'X-Neo-Resource-Path': encodeURIComponent(absolutePath), Vary: 'X-Neo-Resource-Action' };
|
|
14
|
+
};
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neoctl-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Neo browser workspace with an embedded agent runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@tanstack/vue-virtual": "^3.13.36",
|
|
37
37
|
"highlight.js": "^11.11.1",
|
|
38
38
|
"marked": "^18.0.3",
|
|
39
|
-
"neoctl": "0.2.
|
|
39
|
+
"neoctl": "0.2.44",
|
|
40
40
|
"streaming-markdown": "^0.2.15",
|
|
41
41
|
"vue": "^3.5.13"
|
|
42
42
|
},
|
|
@@ -61,7 +61,9 @@
|
|
|
61
61
|
"chunk-uploads.mjs",
|
|
62
62
|
"plugins.mjs",
|
|
63
63
|
"plugin-settings.mjs",
|
|
64
|
+
"plugin-manager.mjs",
|
|
64
65
|
"platform-paths.mjs",
|
|
66
|
+
"local-resources.mjs",
|
|
65
67
|
"tool-settings.mjs",
|
|
66
68
|
"runtime-workspaces.mjs",
|
|
67
69
|
"runtime-router-cleanup.mjs",
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { createWebPluginHost } from './plugins.mjs';
|
|
5
|
+
|
|
6
|
+
/** Trusted local plugin packages only. Code is copied to immutable, unique module URLs. */
|
|
7
|
+
export async function createPluginManager({ directory, builtInDirectory, loadPlugins, onError = console.error }) {
|
|
8
|
+
const root = path.resolve(directory);
|
|
9
|
+
const indexFile = path.join(root, 'catalog.json');
|
|
10
|
+
await fs.mkdir(root, { recursive: true });
|
|
11
|
+
let state;
|
|
12
|
+
try { state = JSON.parse(await fs.readFile(indexFile, 'utf8')); }
|
|
13
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; state = { installed: {}, removed: [] }; }
|
|
14
|
+
if (!state || !state.installed || !Array.isArray(state.removed)) throw new Error('invalid plugin catalog');
|
|
15
|
+
const builtins = new Map();
|
|
16
|
+
const builtInEntries = await fs.readdir(builtInDirectory, { withFileTypes: true }).catch(error => {
|
|
17
|
+
if (error.code === 'ENOENT') return [];
|
|
18
|
+
throw error;
|
|
19
|
+
});
|
|
20
|
+
for (const entry of builtInEntries) {
|
|
21
|
+
if (!entry.isDirectory()) continue;
|
|
22
|
+
const dir = path.join(builtInDirectory, entry.name);
|
|
23
|
+
try { const manifest = JSON.parse(await fs.readFile(path.join(dir, 'neo-plugin.json'), 'utf8')); builtins.set(manifest.id, dir); }
|
|
24
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
25
|
+
}
|
|
26
|
+
const hosts = new Set();
|
|
27
|
+
let queue = Promise.resolve();
|
|
28
|
+
const serial = operation => { const result = queue.catch(() => {}).then(operation); queue = result; return result; };
|
|
29
|
+
function sources(value) {
|
|
30
|
+
const result = new Map([...builtins].filter(([id]) => !value.removed.includes(id)));
|
|
31
|
+
for (const [id, folder] of Object.entries(value.installed)) {
|
|
32
|
+
if (!/^[a-f0-9-]{36}$/.test(folder)) throw new Error('invalid installed plugin directory');
|
|
33
|
+
result.set(id, path.join(root, folder));
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
async function persist(next) {
|
|
38
|
+
const temp = `${indexFile}.${randomUUID()}.tmp`;
|
|
39
|
+
try { await fs.writeFile(temp, JSON.stringify(next, null, 2) + '\n'); await fs.rename(temp, indexFile); }
|
|
40
|
+
finally { await fs.rm(temp, { force: true }); }
|
|
41
|
+
}
|
|
42
|
+
async function load(source, context) {
|
|
43
|
+
const plugins = await loadPlugins({ directories: [], pluginDirectories: [source], ...context });
|
|
44
|
+
if (plugins.length !== 1) throw new Error('package must contain exactly one neo-plugin.json at its root');
|
|
45
|
+
return plugins[0];
|
|
46
|
+
}
|
|
47
|
+
async function publish(next) {
|
|
48
|
+
const nextSources = sources(next), prepared = [], created = [];
|
|
49
|
+
try {
|
|
50
|
+
for (const entry of hosts) {
|
|
51
|
+
const plugins = new Map();
|
|
52
|
+
for (const [id, source] of nextSources) {
|
|
53
|
+
let plugin = entry.plugins.get(id);
|
|
54
|
+
if (!plugin || plugin.sourceDir !== source) { plugin = await load(source, entry.context); created.push(plugin); }
|
|
55
|
+
if (plugin.id !== id) throw new Error(`plugin id mismatch: ${id}`);
|
|
56
|
+
plugins.set(id, plugin);
|
|
57
|
+
}
|
|
58
|
+
prepared.push({ entry, plugins, commit: entry.host.prepare([...plugins.values()]) });
|
|
59
|
+
}
|
|
60
|
+
await persist(next);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
await Promise.allSettled(created.map(p => Promise.resolve().then(() => p.dispose?.())));
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
const previous = state;
|
|
66
|
+
state = next;
|
|
67
|
+
const drains = prepared.map(({ entry, plugins, commit }) => { entry.plugins = plugins; return commit(); });
|
|
68
|
+
// Never wait for an active model turn in a management request. Logical removal is complete.
|
|
69
|
+
void Promise.all(drains).then(async () => {
|
|
70
|
+
const retained = new Set(Object.values(next.installed));
|
|
71
|
+
for (const folder of Object.values(previous.installed)) {
|
|
72
|
+
if (!retained.has(folder)) await fs.rm(path.join(root, folder), { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
}).catch(onError);
|
|
75
|
+
}
|
|
76
|
+
const manager = {
|
|
77
|
+
createHost(options = {}, context = {}) {
|
|
78
|
+
return serial(async () => {
|
|
79
|
+
const plugins = new Map();
|
|
80
|
+
try {
|
|
81
|
+
for (const [id, source] of sources(state)) plugins.set(id, await load(source, context));
|
|
82
|
+
const host = createWebPluginHost({ ...options, plugins: [...plugins.values()], management: manager, onError });
|
|
83
|
+
hosts.add({ host, plugins, context });
|
|
84
|
+
return host;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
await Promise.allSettled([...plugins.values()].map(p => Promise.resolve().then(() => p.dispose?.())));
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
install(directory) {
|
|
92
|
+
return serial(async () => {
|
|
93
|
+
if (typeof directory !== 'string' || !path.isAbsolute(directory)) throw new Error('install requires an absolute trusted local package directory');
|
|
94
|
+
const source = await fs.realpath(directory);
|
|
95
|
+
const relative = path.relative(source, root);
|
|
96
|
+
if (!relative || (!relative.startsWith('..' + path.sep) && relative !== '..' && !path.isAbsolute(relative))) throw new Error('package cannot contain the plugin installation store');
|
|
97
|
+
const folder = randomUUID(), target = path.join(root, folder);
|
|
98
|
+
try {
|
|
99
|
+
await fs.cp(source, target, { recursive: true, filter: async file => {
|
|
100
|
+
const stat = await fs.lstat(file);
|
|
101
|
+
if (stat.isSymbolicLink() || (!stat.isFile() && !stat.isDirectory())) throw new Error('plugin packages must contain only regular files and directories, no links');
|
|
102
|
+
return true;
|
|
103
|
+
} });
|
|
104
|
+
const manifest = JSON.parse(await fs.readFile(path.join(target, 'neo-plugin.json'), 'utf8'));
|
|
105
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/.test(manifest.id || '')) throw new Error('invalid plugin id');
|
|
106
|
+
if (!hosts.size) throw new Error('no plugin host is available to validate the package');
|
|
107
|
+
await publish({ installed: { ...state.installed, [manifest.id]: folder }, removed: state.removed.filter(id => id !== manifest.id) });
|
|
108
|
+
} catch (error) { await fs.rm(target, { recursive: true, force: true }); throw error; }
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
uninstall(id) {
|
|
112
|
+
return serial(async () => {
|
|
113
|
+
if (typeof id !== 'string' || !sources(state).has(id)) throw new Error(`unknown plugin: ${id}`);
|
|
114
|
+
const installed = { ...state.installed }; delete installed[id];
|
|
115
|
+
await publish({ installed, removed: [...new Set([...state.removed, id])] });
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
return manager;
|
|
120
|
+
}
|
package/plugin-settings.mjs
CHANGED
|
@@ -9,10 +9,14 @@ export async function createWebPluginSettings(storageFile) {
|
|
|
9
9
|
return structuredClone(state);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
function update(reduce) {
|
|
13
|
+
const operation = writeQueue.catch(() => undefined).then(async () => {
|
|
14
|
+
const next = reduce(state);
|
|
15
|
+
await writeState(storageFile, next);
|
|
16
|
+
state = next;
|
|
17
|
+
});
|
|
18
|
+
writeQueue = operation;
|
|
19
|
+
return operation;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
return {
|
|
@@ -25,16 +29,18 @@ export async function createWebPluginSettings(storageFile) {
|
|
|
25
29
|
return value && typeof value === 'object' ? { ...value } : {};
|
|
26
30
|
},
|
|
27
31
|
async setGlobalEnabled(ids) {
|
|
28
|
-
await update({ ...
|
|
32
|
+
await update(current => ({ ...current, globalEnabled: [...new Set(ids)].sort() }));
|
|
29
33
|
},
|
|
30
34
|
async setSessionOverrides(sessionId, overrides) {
|
|
31
35
|
const id = String(sessionId || '').trim();
|
|
32
36
|
if (!id) throw new Error('session id is required');
|
|
33
|
-
|
|
37
|
+
await update(current => {
|
|
38
|
+
const sessions = { ...current.sessions };
|
|
34
39
|
const normalized = Object.fromEntries(Object.entries(overrides).filter(([, value]) => typeof value === 'boolean'));
|
|
35
40
|
if (Object.keys(normalized).length) sessions[id] = normalized;
|
|
36
41
|
else delete sessions[id];
|
|
37
|
-
|
|
42
|
+
return { ...current, sessions };
|
|
43
|
+
});
|
|
38
44
|
},
|
|
39
45
|
};
|
|
40
46
|
}
|
|
@@ -86,7 +86,7 @@ export function createExposeDownloadsTool(options) {
|
|
|
86
86
|
return tool;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
export async function serveDownload(registry, req, res, id) {
|
|
89
|
+
export async function serveDownload(registry, req, res, id, helpers = {}) {
|
|
90
90
|
let handle;
|
|
91
91
|
try {
|
|
92
92
|
const entry = await registry.get(id);
|
|
@@ -95,6 +95,7 @@ export async function serveDownload(registry, req, res, id) {
|
|
|
95
95
|
const stat = await handle.stat();
|
|
96
96
|
if (!stat.isFile()) throw Object.assign(new Error('Not a file'), { code: 'ENOENT' });
|
|
97
97
|
res.writeHead(200, {
|
|
98
|
+
...helpers.localResourceHeaders?.(req, entry.absolutePath),
|
|
98
99
|
'Content-Type': 'application/octet-stream', 'Content-Length': stat.size,
|
|
99
100
|
'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(entry.filename).replace(/['()*]/g, (c) => '%' + c.charCodeAt(0).toString(16))}`,
|
|
100
101
|
'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'no-referrer',
|
|
@@ -11,11 +11,11 @@ export function createPlugin(context = {}) {
|
|
|
11
11
|
name: 'Web Downloads', requiresTools: ['expose_downloads'], cacheStable: true,
|
|
12
12
|
content: 'When you create, modify, export, package, or identify local files that the web user should receive as downloads, call expose_downloads with the relevant absolute paths before the final response. For every download link, copy downloads[].markdown verbatim (neoctl.resource-link.v1): never construct links or add/remove a sandbox: prefix. Only the link-to-original-absolute-path mapping is persisted, with no file copy and no directory restriction. Links do not automatically expire and expiresAt is null. If the original path is moved, deleted, or unreadable, the link stops working. Anyone with a link can download. Historical links from the old in-memory plugin cannot be restored; re-expose the original file if needed.',
|
|
13
13
|
}],
|
|
14
|
-
async route(req, res, url) {
|
|
14
|
+
async route(req, res, url, helpers = {}) {
|
|
15
15
|
if (!url.pathname.startsWith('/api/downloads/')) return false;
|
|
16
16
|
if (!['GET', 'HEAD'].includes(req.method)) { res.writeHead(405, { Allow: 'GET, HEAD' }); res.end(); return true; }
|
|
17
17
|
const id = url.pathname.slice('/api/downloads/'.length);
|
|
18
|
-
await serveDownload(registry, req, res, id);
|
|
18
|
+
await serveDownload(registry, req, res, id, helpers);
|
|
19
19
|
return true;
|
|
20
20
|
},
|
|
21
21
|
};
|