elit 2.0.1 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +275 -128
- package/dist/build.d.mts +10 -1
- package/dist/build.d.ts +10 -1
- package/dist/build.js +670 -1
- package/dist/build.mjs +641 -1
- package/dist/chokidar.d.mts +134 -0
- package/dist/chokidar.d.ts +134 -0
- package/dist/chokidar.js +240 -0
- package/dist/chokidar.mjs +221 -0
- package/dist/cli.js +2792 -495
- package/dist/dom.d.mts +10 -3
- package/dist/dom.d.ts +10 -3
- package/dist/dom.js +676 -1
- package/dist/dom.mjs +647 -1
- package/dist/el.d.mts +16 -36
- package/dist/el.d.ts +16 -36
- package/dist/el.js +789 -1
- package/dist/el.mjs +583 -1
- package/dist/fs.d.mts +255 -0
- package/dist/fs.d.ts +255 -0
- package/dist/fs.js +513 -0
- package/dist/fs.mjs +469 -0
- package/dist/hmr.js +112 -1
- package/dist/hmr.mjs +91 -1
- package/dist/http.d.mts +163 -0
- package/dist/http.d.ts +163 -0
- package/dist/http.js +632 -0
- package/dist/http.mjs +605 -0
- package/dist/https.d.mts +108 -0
- package/dist/https.d.ts +108 -0
- package/dist/https.js +907 -0
- package/dist/https.mjs +901 -0
- package/dist/index.d.mts +613 -33
- package/dist/index.d.ts +613 -33
- package/dist/index.js +2589 -1
- package/dist/index.mjs +2312 -1
- package/dist/mime-types.d.mts +48 -0
- package/dist/mime-types.d.ts +48 -0
- package/dist/mime-types.js +197 -0
- package/dist/mime-types.mjs +166 -0
- package/dist/path.d.mts +163 -0
- package/dist/path.d.ts +163 -0
- package/dist/path.js +350 -0
- package/dist/path.mjs +310 -0
- package/dist/router.d.mts +3 -1
- package/dist/router.d.ts +3 -1
- package/dist/router.js +830 -1
- package/dist/router.mjs +801 -1
- package/dist/runtime.d.mts +97 -0
- package/dist/runtime.d.ts +97 -0
- package/dist/runtime.js +43 -0
- package/dist/runtime.mjs +15 -0
- package/dist/server.d.mts +5 -1
- package/dist/server.d.ts +5 -1
- package/dist/server.js +3267 -1
- package/dist/server.mjs +3241 -1
- package/dist/state.d.mts +3 -1
- package/dist/state.d.ts +3 -1
- package/dist/state.js +1036 -1
- package/dist/state.mjs +992 -1
- package/dist/style.d.mts +47 -1
- package/dist/style.d.ts +47 -1
- package/dist/style.js +551 -1
- package/dist/style.mjs +483 -1
- package/dist/{types-DOAdFFJB.d.ts → types-C0nGi6MX.d.mts} +29 -13
- package/dist/{types-DOAdFFJB.d.mts → types-Du6kfwTm.d.ts} +29 -13
- package/dist/types.d.mts +452 -3
- package/dist/types.d.ts +452 -3
- package/dist/types.js +18 -1
- package/dist/ws.d.mts +195 -0
- package/dist/ws.d.ts +195 -0
- package/dist/ws.js +380 -0
- package/dist/ws.mjs +358 -0
- package/dist/wss.d.mts +108 -0
- package/dist/wss.d.ts +108 -0
- package/dist/wss.js +1306 -0
- package/dist/wss.mjs +1300 -0
- package/package.json +53 -6
- package/dist/client.d.mts +0 -9
- package/dist/client.d.ts +0 -9
- package/dist/client.js +0 -1
- package/dist/client.mjs +0 -1
package/dist/server.js
CHANGED
|
@@ -1 +1,3267 @@
|
|
|
1
|
-
"use strict";var e,t=require("http"),r=require("https"),n=require("ws"),o=require("chokidar"),i=require("fs/promises"),s=require("path"),a=require("mime-types"),l=require("esbuild"),d=(e=function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')},typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):e),c=new class{constructor(){this.elementCache=new WeakMap,this.reactiveNodes=new Map}createElement(e,t={},r=[]){return{tagName:e,props:t,children:r}}renderToDOM(e,t){if(null==e||!1===e)return;if("object"!=typeof e)return void t.appendChild(document.createTextNode(String(e)));let{tagName:r,props:n,children:o}=e,i="svg"===r||"s"===r[0]&&"v"===r[1]&&"g"===r[2]||"http://www.w3.org/2000/svg"===t.namespaceURI,s=i?document.createElementNS("http://www.w3.org/2000/svg",r.replace("svg","").toLowerCase()||r):document.createElement(r);for(let e in n){let t=n[e];if(null==t||!1===t)continue;let r=e.charCodeAt(0);if(99===r&&(e.length<6||"N"===e[5])){let e=Array.isArray(t)?t.join(" "):t;i?s.setAttribute("class",e):s.className=e}else if(115===r&&5===e.length)if("string"==typeof t)s.style.cssText=t;else{let e=s.style;for(let r in t)e[r]=t[r]}else 111===r&&110===e.charCodeAt(1)?s[e.toLowerCase()]=t:100===r&&e.length>20?s.innerHTML=t.__html:114===r&&3===e.length?setTimeout(()=>{"function"==typeof t?t(s):t.current=s},0):s.setAttribute(e,!0===t?"":String(t))}let a=o.length;if(!a)return void t.appendChild(s);let l=e=>{for(let t=0;t<a;t++){let r=o[t];if(null!=r&&!1!==r)if(Array.isArray(r))for(let t=0,n=r.length;t<n;t++){let n=r[t];null!=n&&!1!==n&&this.renderToDOM(n,e)}else this.renderToDOM(r,e)}};if(a>30){let e=document.createDocumentFragment();l(e),s.appendChild(e)}else l(s);t.appendChild(s)}render(e,t){let r="string"==typeof e?document.getElementById(e.replace("#","")):e;if(!r)throw new Error(`Element not found: ${e}`);if(t.children&&t.children.length>500){let e=document.createDocumentFragment();this.renderToDOM(t,e),r.appendChild(e)}else this.renderToDOM(t,r);return r}batchRender(e,t){let r="string"==typeof e?document.getElementById(e.replace("#","")):e;if(!r)throw new Error(`Element not found: ${e}`);let n=t.length;if(n>3e3){let e=document.createDocumentFragment(),o=0,i=1500,s=()=>{let a=Math.min(o+i,n);for(let r=o;r<a;r++)this.renderToDOM(t[r],e);o=a,o>=n?r.appendChild(e):requestAnimationFrame(s)};s()}else{let e=document.createDocumentFragment();for(let r=0;r<n;r++)this.renderToDOM(t[r],e);r.appendChild(e)}return r}renderChunked(e,t,r=5e3,n){let o="string"==typeof e?document.getElementById(e.replace("#","")):e;if(!o)throw new Error(`Element not found: ${e}`);let i=t.length,s=0,a=()=>{let e=Math.min(s+r,i),l=document.createDocumentFragment();for(let r=s;r<e;r++)this.renderToDOM(t[r],l);o.appendChild(l),s=e,n&&n(s,i),s<i&&requestAnimationFrame(a)};return requestAnimationFrame(a),o}renderToHead(...e){let t=document.head;if(t)for(let r of e.flat())r&&this.renderToDOM(r,t);return t}addStyle(e){let t=document.createElement("style");return t.textContent=e,document.head.appendChild(t)}addMeta(e){let t=document.createElement("meta");for(let r in e)t.setAttribute(r,e[r]);return document.head.appendChild(t)}addLink(e){let t=document.createElement("link");for(let r in e)t.setAttribute(r,e[r]);return document.head.appendChild(t)}setTitle(e){return document.title=e}createState(e,t={}){let r=e,n=new Set,o=null,{throttle:i=0,deep:s=!1}=t,a=()=>n.forEach(e=>e(r));return{get value(){return r},set value(e){(s?JSON.stringify(r)!==JSON.stringify(e):r!==e)&&(r=e,i>0?o||(o=setTimeout(()=>{o=null,a()},i)):a())},subscribe:e=>(n.add(e),()=>n.delete(e)),destroy(){n.clear(),o&&clearTimeout(o)}}}computed(e,t){let r=e.map(e=>e.value),n=this.createState(t(...r));return e.forEach((e,o)=>{e.subscribe(e=>{r[o]=e,n.value=t(...r)})}),n}effect(e){e()}createVirtualList(e,t,r,n=50,o=5){let i=e.clientHeight,s=t.length*n,a=0,l=()=>{let{start:l,end:d}={start:Math.max(0,Math.floor(a/n)-o),end:Math.min(t.length,Math.ceil((a+i)/n)+o)},c=document.createElement("div");c.style.cssText=`height:${s}px;position:relative`;for(let e=l;e<d;e++){let o=document.createElement("div");o.style.cssText=`position:absolute;top:${e*n}px;height:${n}px;width:100%`,this.renderToDOM(r(t[e],e),o),c.appendChild(o)}e.innerHTML="",e.appendChild(c)},d=()=>{a=e.scrollTop,requestAnimationFrame(l)};return e.addEventListener("scroll",d),l(),{render:l,destroy:()=>{e.removeEventListener("scroll",d),e.innerHTML=""}}}lazy(e){let t=null,r=!1;return async(...n)=>(!t&&!r&&(r=!0,t=await e(),r=!1),t?t(...n):{tagName:"div",props:{class:"loading"},children:["Loading..."]})}cleanupUnusedElements(e){let t=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),r=[];for(;t.nextNode();){let e=t.currentNode;e.id&&e.id.startsWith("r")&&!this.elementCache.has(e)&&r.push(e)}return r.forEach(e=>e.remove()),r.length}renderToString(e,t={}){let{pretty:r=!1,indent:n=0}=t,o=r?" ".repeat(n):"",i=r?"\n":"",s=this.resolveStateValue(e);if(s=this.unwrapReactive(s),Array.isArray(s))return s.map(e=>this.renderToString(e,t)).join("");if("object"!=typeof s||null===s)return null==s||!1===s?"":this.escapeHtml(String(s));let{tagName:a,props:l,children:d}=s,c=this.isSelfClosingTag(a),h=`${o}<${a}`,p=this.propsToAttributes(l);if(p&&(h+=` ${p}`),c)return h+=` />${i}`,h;if(h+=">",l.dangerouslySetInnerHTML)return h+=l.dangerouslySetInnerHTML.__html,h+=`</${a}>${i}`,h;if(d&&d.length>0){let e=d.map(e=>{let t=this.resolveStateValue(e);return this.unwrapReactive(t)}),t=e.some(e=>"object"==typeof e&&null!==e&&!Array.isArray(e)&&"tagName"in e);if(r&&t){h+=i;for(let t of e)if(null!=t&&!1!==t)if(Array.isArray(t))for(let e of t)null!=e&&!1!==e&&(h+=this.renderToString(e,{pretty:r,indent:n+1}));else h+=this.renderToString(t,{pretty:r,indent:n+1});h+=o}else for(let t of e)if(null!=t&&!1!==t)if(Array.isArray(t))for(let e of t)null!=e&&!1!==e&&(h+=this.renderToString(e,{pretty:!1,indent:0}));else h+=this.renderToString(t,{pretty:!1,indent:0})}return h+=`</${a}>${i}`,h}resolveStateValue(e){return e&&"object"==typeof e&&"value"in e&&"subscribe"in e?e.value:e}isReactiveWrapper(e){return!(!e||"object"!=typeof e||!e.tagName)&&("span"===e.tagName&&e.props?.id&&"string"==typeof e.props.id&&e.props.id.match(/^r[a-z0-9]{9}$/))}unwrapReactive(e){if(!this.isReactiveWrapper(e))return e;let t=e.children;if(!t||0===t.length)return"";if(1===t.length){let e=t[0];if(e&&"object"==typeof e&&"span"===e.tagName){let t=e.props,r=!t||0===Object.keys(t).length,n=e.children&&1===e.children.length&&"string"==typeof e.children[0];if(r&&n)return e.children[0]}return this.unwrapReactive(e)}return t.map(e=>this.unwrapReactive(e))}escapeHtml(e){let t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,e=>t[e])}isSelfClosingTag(e){return new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(e.toLowerCase())}propsToAttributes(e){let t=[];for(let r in e){if("children"===r||"dangerouslySetInnerHTML"===r||"ref"===r)continue;let n=e[r];if(n=this.resolveStateValue(n),null!=n&&!1!==n&&(!r.startsWith("on")||"function"!=typeof n)){if("className"===r||"class"===r){let e=Array.isArray(n)?n.join(" "):n;e&&t.push(`class="${this.escapeHtml(String(e))}"`);continue}if("style"===r){let e=this.styleToString(n);e&&t.push(`style="${this.escapeHtml(e)}"`);continue}if(!0===n){t.push(r);continue}t.push(`${r}="${this.escapeHtml(String(n))}"`)}}return t.join(" ")}styleToString(e){if("string"==typeof e)return e;if("object"==typeof e&&null!==e){let t=[];for(let r in e){let n=r.replace(/([A-Z])/g,"-$1").toLowerCase();t.push(`${n}:${e[r]}`)}return t.join(";")}return""}isState(e){return e&&"object"==typeof e&&"value"in e&&"subscribe"in e&&"function"==typeof e.subscribe}createReactiveChild(e,t){let r=t(e.value);if(typeof window<"u"&&typeof document<"u"){let r={node:null,renderFn:t};this.reactiveNodes.set(e,r),e.subscribe(()=>{if(r.node&&r.node.parentNode){let n=t(e.value);r.node.textContent=String(n??"")}})}return r}jsonToVNode(e){if(this.isState(e))return this.createReactiveChild(e,e=>e);if(null==e||"boolean"==typeof e||"string"==typeof e||"number"==typeof e)return e;let{tag:t,attributes:r={},children:n}=e,o={};for(let e in r){let t=r[e];"class"===e?o.className=this.isState(t)?t.value:t:o[e]=this.isState(t)?t.value:t}let i=[];if(null!=n)if(Array.isArray(n))for(let e of n)if(this.isState(e))i.push(this.createReactiveChild(e,e=>e));else{let t=this.jsonToVNode(e);null!=t&&!1!==t&&i.push(t)}else if(this.isState(n))i.push(this.createReactiveChild(n,e=>e));else if("object"==typeof n&&"tag"in n){let e=this.jsonToVNode(n);null!=e&&!1!==e&&i.push(e)}else i.push(n);return{tagName:t,props:o,children:i}}vNodeJsonToVNode(e){if(this.isState(e))return this.createReactiveChild(e,e=>e);if(null==e||"boolean"==typeof e||"string"==typeof e||"number"==typeof e)return e;let{tagName:t,props:r={},children:n=[]}=e,o={};for(let e in r){let t=r[e];o[e]=this.isState(t)?t.value:t}let i=[];for(let e of n)if(this.isState(e))i.push(this.createReactiveChild(e,e=>e));else{let t=this.vNodeJsonToVNode(e);null!=t&&!1!==t&&i.push(t)}return{tagName:t,props:o,children:i}}renderJson(e,t){let r=this.jsonToVNode(t);if(!r||"object"!=typeof r||!("tagName"in r))throw new Error("Invalid JSON structure");return this.render(e,r)}renderVNode(e,t){let r=this.vNodeJsonToVNode(t);if(!r||"object"!=typeof r||!("tagName"in r))throw new Error("Invalid VNode JSON structure");return this.render(e,r)}renderJsonToString(e,t={}){let r=this.jsonToVNode(e);return this.renderToString(r,t)}renderVNodeToString(e,t={}){let r=this.vNodeJsonToVNode(e);return this.renderToString(r,t)}renderServer(e){if("object"!=typeof e||null===e||!("tagName"in e))throw new Error("renderServer requires a VNode with html tag");if("html"!==e.tagName)throw new Error("renderServer requires a VNode with html tag as root");let t=e,r=null,n=null;for(let e of t.children||[])"object"==typeof e&&null!==e&&"tagName"in e&&("head"===e.tagName&&(r=e),"body"===e.tagName&&(n=e));if(t.props)for(let e in t.props){let r=t.props[e];null!=r&&!1!==r&&document.documentElement.setAttribute(e,String(r))}if(r){document.head.innerHTML="";for(let e of r.children||[])this.renderToDOM(e,document.head)}if(n){if(document.body.innerHTML="",n.props)for(let e in n.props){let t=n.props[e];null!=t&&!1!==t&&document.body.setAttribute(e,String(t))}for(let e of n.children||[])this.renderToDOM(e,document.body)}}renderToHTMLDocument(e,t={}){let{title:r="",meta:n=[],links:o=[],scripts:i=[],styles:s=[],lang:a="en",head:l="",bodyAttrs:d={},pretty:c=!1}=t,h=c?"\n":"",p=c?" ":"",u=c?" ":"",g=`<!DOCTYPE html>${h}<html lang="${a}">${h}${p}<head>${h}${u}<meta charset="UTF-8">${h}${u}<meta name="viewport" content="width=device-width, initial-scale=1.0">${h}`;r&&(g+=`${u}<title>${this.escapeHtml(r)}</title>${h}`);for(let e of n){g+=`${u}<meta`;for(let t in e)g+=` ${t}="${this.escapeHtml(e[t])}"`;g+=`>${h}`}for(let e of o){g+=`${u}<link`;for(let t in e)g+=` ${t}="${this.escapeHtml(e[t])}"`;g+=`>${h}`}for(let e of s)e.href?g+=`${u}<link rel="stylesheet" href="${this.escapeHtml(e.href)}">${h}`:e.content&&(g+=`${u}<style>${e.content}</style>${h}`);l&&(g+=l+h),g+=`${p}</head>${h}${p}<body`;for(let e in d)g+=` ${e}="${this.escapeHtml(d[e])}"`;g+=`>${h}`,g+=this.renderToString(e,{pretty:c,indent:2});for(let e of i)g+=`${u}<script`,e.type&&(g+=` type="${this.escapeHtml(e.type)}"`),e.async&&(g+=" async"),e.defer&&(g+=" defer"),e.src?g+=` src="${this.escapeHtml(e.src)}"><\/script>${h}`:e.content?g+=`>${e.content}<\/script>${h}`:g+=`><\/script>${h}`;return g+=`${p}</body>${h}</html>`,g}getElementCache(){return this.elementCache}};function h(e){return async(n,o)=>{let i=n.url||"/",s=i.split("?")[0],a=e.find(e=>s.startsWith(e.context));if(!a)return!1;let{target:l,changeOrigin:d,pathRewrite:c,headers:h}=a;try{let e=new URL(l),s="https:"===e.protocol,a=s?r.request:t.request,p=function(e,t){if(!t)return e;for(let[r,n]of Object.entries(t)){let t=new RegExp(r);if(t.test(e))return e.replace(t,n)}return e}(i,c),u={hostname:e.hostname,port:e.port||(s?443:80),path:p,method:n.method,headers:{...n.headers,...h||{}}};d&&(u.headers.host=e.host),delete u.headers.host;let g=a(u,e=>{o.writeHead(e.statusCode||200,e.headers),e.pipe(o)});return g.on("error",e=>{console.error("[Proxy] Error proxying %s to %s:",i,l,e.message),o.headersSent||(o.writeHead(502,{"Content-Type":"application/json"}),o.end(JSON.stringify({error:"Bad Gateway",message:"Proxy error"})))}),n.pipe(g),!0}catch(e){return console.error("[Proxy] Invalid proxy configuration for %s:",s,e),!1}}}var p=class{constructor(e,t){this.key=e,this.listeners=new Set,this.changeHandlers=new Set,this.options=t,this._value=t.initial}get value(){return this._value}set value(e){if(this.options.validate&&!this.options.validate(e))throw new Error(`Invalid state value for "${this.key}"`);let t=this._value;this._value=e,this.changeHandlers.forEach(r=>{r(e,t)}),this.broadcast()}update(e){this.value=e(this._value)}subscribe(e){this.listeners.add(e),this.sendTo(e)}unsubscribe(e){this.listeners.delete(e)}onChange(e){return this.changeHandlers.add(e),()=>this.changeHandlers.delete(e)}broadcast(){let e=JSON.stringify({type:"state:update",key:this.key,value:this._value,timestamp:Date.now()});this.listeners.forEach(t=>t.readyState===n.WebSocket.OPEN&&t.send(e))}sendTo(e){e.readyState===n.WebSocket.OPEN&&e.send(JSON.stringify({type:"state:init",key:this.key,value:this._value,timestamp:Date.now()}))}get subscriberCount(){return this.listeners.size}clear(){this.listeners.clear(),this.changeHandlers.clear()}},u=class{constructor(){this.states=new Map}create(e,t){if(this.states.has(e))return this.states.get(e);let r=new p(e,t);return this.states.set(e,r),r}get(e){return this.states.get(e)}has(e){return this.states.has(e)}delete(e){let t=this.states.get(e);return!!t&&(t.clear(),this.states.delete(e))}subscribe(e,t){this.states.get(e)?.subscribe(t)}unsubscribe(e,t){this.states.get(e)?.unsubscribe(t)}unsubscribeAll(e){this.states.forEach(t=>t.unsubscribe(e))}handleStateChange(e,t){let r=this.states.get(e);r&&(r.value=t)}keys(){return Array.from(this.states.keys())}clear(){this.states.forEach(e=>e.clear()),this.states.clear()}},g={port:3e3,host:"localhost",https:!1,open:!0,watch:["**/*.ts","**/*.js","**/*.html","**/*.css"],ignore:["node_modules/**","dist/**",".git/**","**/*.d.ts"],logging:!0,middleware:[],worker:[]};exports.ServerRouter=class{constructor(){this.routes=[],this.middlewares=[]}use(e){return this.middlewares.push(e),this}get(e,t){return this.addRoute("GET",e,t)}post(e,t){return this.addRoute("POST",e,t)}put(e,t){return this.addRoute("PUT",e,t)}delete(e,t){return this.addRoute("DELETE",e,t)}patch(e,t){return this.addRoute("PATCH",e,t)}options(e,t){return this.addRoute("OPTIONS",e,t)}addRoute(e,t,r){let{pattern:n,paramNames:o}=this.pathToRegex(t);return this.routes.push({method:e,pattern:n,paramNames:o,handler:r}),this}pathToRegex(e){let t=[],r=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\//g,"\\/").replace(/:(\w+)/g,(e,r)=>(t.push(r),"([^\\/]+)"));return{pattern:new RegExp(`^${r}$`),paramNames:t}}parseQuery(e){let t={},r=e.split("?")[1];return r&&new URLSearchParams(r).forEach((e,r)=>t[r]=e),t}async parseBody(e){return new Promise((t,r)=>{let n="";e.on("data",e=>n+=e.toString()),e.on("end",()=>{try{let r=e.headers["content-type"]||"";if(r.includes("application/json"))t(n?JSON.parse(n):{});else if(r.includes("application/x-www-form-urlencoded")){let e={};new URLSearchParams(n).forEach((t,r)=>e[r]=t),t(e)}else t(n)}catch(e){r(e)}}),e.on("error",r)})}async handle(e,t){let r=e.method,n=e.url||"/",o=n.split("?")[0];for(let i of this.routes){if(i.method!==r)continue;let s=o.match(i.pattern);if(!s)continue;let a={};i.paramNames.forEach((e,t)=>{a[e]=s[t+1]});let l=this.parseQuery(n),d={};if(["POST","PUT","PATCH"].includes(r))try{d=await this.parseBody(e)}catch{return t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid request body"})),!0}let c={req:e,res:t,params:a,query:l,body:d,headers:e.headers},h=0,p=async()=>{if(h<this.middlewares.length){let e=this.middlewares[h++];await e(c,p)}};try{await p(),await i.handler(c)}catch(e){console.error("Route handler error:",e),t.headersSent||(t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Internal Server Error",message:e instanceof Error?e.message:"Unknown error"})))}return!0}return!1}},exports.SharedState=p,exports.StateManager=u,exports.bodyLimit=function(e={}){let{limit:t=1048576}=e;return async(e,r)=>{if(parseInt(e.req.headers["content-length"]||"0",10)>t)return e.res.writeHead(413,{"Content-Type":"application/json"}),void e.res.end(JSON.stringify({error:"Request body too large"}));await r()}},exports.cacheControl=function(e={}){let{maxAge:t=3600,public:r=!0}=e;return async(e,n)=>{e.res.setHeader("Cache-Control",`${r?"public":"private"}, max-age=${t}`),await n()}},exports.compress=function(){return async(e,t)=>{if(!(e.req.headers["accept-encoding"]||"").includes("gzip"))return void await t();let r=e.res.end.bind(e.res),n=[];e.res.write=e=>(n.push(Buffer.from(e)),!0),e.res.end=t=>{t&&n.push(Buffer.from(t));let o=Buffer.concat(n),{gzipSync:i}=d("zlib"),s=i(o);return e.res.setHeader("Content-Encoding","gzip"),e.res.setHeader("Content-Length",s.length),r(s),e.res},await t()}},exports.cors=function(e={}){let{origin:t="*",methods:r=["GET","POST","PUT","DELETE","PATCH","OPTIONS"],credentials:n=!0,maxAge:o=86400}=e;return async(e,i)=>{let s=e.req.headers.origin||"",a=Array.isArray(t)&&t.includes(s)?s:Array.isArray(t)?"":t;if(a&&e.res.setHeader("Access-Control-Allow-Origin",a),e.res.setHeader("Access-Control-Allow-Methods",r.join(", ")),e.res.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),n&&e.res.setHeader("Access-Control-Allow-Credentials","true"),e.res.setHeader("Access-Control-Max-Age",String(o)),"OPTIONS"===e.req.method)return e.res.writeHead(204),void e.res.end();await i()}},exports.createDevServer=function(e){let r={...g,...e},p=new Set,f=new u,y=r.clients?.length?r.clients:r.root?[{root:r.root,basePath:r.basePath||"",ssr:r.ssr,proxy:r.proxy}]:null;if(!y)throw new Error('DevServerOptions must include either "clients" array or "root" directory');let m=y.map(e=>{let t=e.basePath||"";if(t){for(;t.startsWith("/");)t=t.slice(1);for(;t.endsWith("/");)t=t.slice(0,-1);t=t?"/"+t:""}return{root:e.root,basePath:t,ssr:e.ssr,proxyHandler:e.proxy?h(e.proxy):void 0}}),w=r.proxy?h(r.proxy):null,b=t.createServer(async(e,t)=>{let n=e.url||"/",o=m.find(e=>e.basePath&&n.startsWith(e.basePath))||m.find(e=>!e.basePath);if(!o)return t.writeHead(404,{"Content-Type":"text/plain"}),void t.end("404 Not Found");if(o.proxyHandler)try{if(await o.proxyHandler(e,t))return void(r.logging&&console.log(`[Proxy] ${e.method} ${n} -> proxied (client-specific)`))}catch(e){console.error("[Proxy] Error (client-specific):",e)}if(w)try{if(await w(e,t))return void(r.logging&&console.log(`[Proxy] ${e.method} ${n} -> proxied (global)`))}catch(e){console.error("[Proxy] Error (global):",e)}let a=o.basePath?n.slice(o.basePath.length)||"/":n;if(r.api&&a.startsWith("/api")&&await r.api.handle(e,t))return;let l="/"===a?"/index.html":a;if(l=l.split("?")[0],r.logging&&"/src/pages"===l&&console.log("[DEBUG] Request for /src/pages received"),l.includes("\0"))return r.logging&&console.log(`[403] Rejected path with null byte: ${l}`),t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden");let d,c=l.startsWith("/dist/"),h=s.normalize(l).replace(/\\/g,"/").replace(/^\/+/,"");if(h.includes(".."))return r.logging&&console.log(`[403] Path traversal attempt: ${l}`),t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden");d=h;let p,u=await i.realpath(s.resolve(o.root)),g=c?await i.realpath(s.resolve(o.root,"..")):u;try{if(p=await i.realpath(s.resolve(s.join(g,d))),!p.startsWith(g.endsWith(s.sep)?g:g+s.sep))return r.logging&&console.log(`[403] File access outside of root: ${p}`),t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden");r.logging&&"/src/pages"===l&&console.log(`[DEBUG] Initial resolve succeeded: ${p}`)}catch{let e;if(r.logging&&!d.includes(".")&&console.log(`[DEBUG] File not found: ${d}, trying extensions...`),d.endsWith(".js")){let n=d.replace(/\.js$/,".ts");try{let o=await i.realpath(s.resolve(s.join(g,n)));if(!o.startsWith(g.endsWith(s.sep)?g:g+s.sep))return r.logging&&console.log(`[403] Fallback TS path outside of root: ${o}`),t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden");e=o}catch{}}if(!e&&!d.includes("."))try{e=await i.realpath(s.resolve(s.join(g,d+".ts"))),r.logging&&console.log(`[DEBUG] Found: ${d}.ts`)}catch{try{e=await i.realpath(s.resolve(s.join(g,d+".js"))),r.logging&&console.log(`[DEBUG] Found: ${d}.js`)}catch{try{e=await i.realpath(s.resolve(s.join(g,d,"index.ts"))),r.logging&&console.log(`[DEBUG] Found: ${d}/index.ts`)}catch{try{e=await i.realpath(s.resolve(s.join(g,d,"index.js"))),r.logging&&console.log(`[DEBUG] Found: ${d}/index.js`)}catch{r.logging&&console.log(`[DEBUG] Not found: all attempts failed for ${d}`)}}}}if(!e)return t.writeHead(404,{"Content-Type":"text/plain"}),void t.end("404 Not Found");p=e}try{if((await i.stat(p)).isDirectory()){let e;r.logging&&console.log(`[DEBUG] Path is directory: ${p}, trying index files...`);try{e=await i.realpath(s.resolve(s.join(p,"index.ts"))),r.logging&&console.log("[DEBUG] Found index.ts in directory")}catch{try{e=await i.realpath(s.resolve(s.join(p,"index.js"))),r.logging&&console.log("[DEBUG] Found index.js in directory")}catch{return r.logging&&console.log("[DEBUG] No index file found in directory"),t.writeHead(404,{"Content-Type":"text/plain"}),void t.end("404 Not Found")}}p=e}}catch{return t.writeHead(404,{"Content-Type":"text/plain"}),void t.end("404 Not Found")}let f=await i.realpath(s.resolve(o.root,"..")),y=p.startsWith(u+s.sep)||p===u,b=c&&(p.startsWith(f+s.sep)||p===f);if(!y&&!b)return r.logging&&console.log(`[403] Path outside allowed directories: ${l}`),t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden");try{if((await i.stat(p)).isDirectory())try{let e=await i.realpath(s.resolve(s.join(p,"index.html")));return e.startsWith(u+s.sep)||e===u?(await i.stat(e),v(e,t,o)):(t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden"))}catch{return t.writeHead(404,{"Content-Type":"text/plain"}),void t.end("404 Not Found")}await v(p,t,o)}catch{r.logging&&console.log(`[404] ${l}`),t.writeHead(404,{"Content-Type":"text/plain"}),t.end("404 Not Found")}});async function v(e,t,n){try{let o,h=await i.realpath(s.resolve(n.root)),p=await i.realpath(s.resolve(n.root,".."));try{o=await i.realpath(s.resolve(e))}catch{return e.endsWith("index.html")&&n.ssr?function(e,t){try{if(!t.ssr)return e.writeHead(500,{"Content-Type":"text/plain"}),void e.end("SSR function not configured");let n,o=t.ssr();if("string"==typeof o)n=o;else if("object"==typeof o&&null!==o&&"tagName"in o){let e=o;n="html"===e.tagName?c.renderToString(e):`<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><body>${c.renderToString(e)}</body></html>`}else n=String(o);let i=`<script>(function(){const ws=new WebSocket('ws://${r.host}:${r.port}${t.basePath}');ws.onopen=()=>console.log('[Elit HMR] Connected');ws.onmessage=(e)=>{const d=JSON.parse(e.data);if(d.type==='update'){console.log('[Elit HMR] File updated:',d.path);window.location.reload()}else if(d.type==='reload'){console.log('[Elit HMR] Reloading...');window.location.reload()}else if(d.type==='error')console.error('[Elit HMR] Error:',d.error)};ws.onclose=()=>{console.log('[Elit HMR] Disconnected - Retrying...');setTimeout(()=>window.location.reload(),1000)};ws.onerror=(e)=>console.error('[Elit HMR] WebSocket error:',e)})();<\/script>`;n=n.includes("</body>")?n.replace("</body>",`${i}</body>`):n+i,e.writeHead(200,{"Content-Type":"text/html","Cache-Control":"no-cache, no-store, must-revalidate"}),e.end(n),r.logging&&console.log("[200] SSR rendered")}catch(t){e.writeHead(500,{"Content-Type":"text/plain"}),e.end("500 SSR Error"),r.logging&&console.error("[500] SSR Error:",t)}}(t,n):(t.writeHead(404,{"Content-Type":"text/plain"}),void t.end("404 Not Found"))}let u=o.startsWith(h+s.sep)||o===h,g=o.startsWith(p+s.sep+"dist"+s.sep);if(!u&&!g)return r.logging&&console.log(`[403] Attempted to serve file outside allowed directories: ${e}`),t.writeHead(403,{"Content-Type":"text/plain"}),void t.end("403 Forbidden");let f=await i.readFile(o),y=s.extname(o),m=a.lookup(o)||"application/octet-stream";if(".ts"===y||".tsx"===y)try{let e=await l.build({stdin:{contents:f.toString(),loader:".tsx"===y?"tsx":"ts",resolveDir:s.resolve(o,".."),sourcefile:o},format:"esm",target:"es2020",write:!1,bundle:!1,sourcemap:"inline"});f=Buffer.from(e.outputFiles[0].text),m="application/javascript"}catch(e){return t.writeHead(500,{"Content-Type":"text/plain"}),t.end(`TypeScript compilation error:\n${e}`),void(r.logging&&console.error("[500] TypeScript compilation error:",e))}if(".html"===y){let e=`<script type="importmap">\n{\n "imports": {\n "elit": "${n.basePath?`${n.basePath}/dist/client.mjs`:"/dist/client.mjs"}"\n }\n}\n<\/script>`,t=`<script>(function(){const ws=new WebSocket('ws://${r.host}:${r.port}${n.basePath}');ws.onopen=()=>console.log('[Elit HMR] Connected');ws.onmessage=(e)=>{const d=JSON.parse(e.data);if(d.type==='update'){console.log('[Elit HMR] File updated:',d.path);window.location.reload()}else if(d.type==='reload'){console.log('[Elit HMR] Reloading...');window.location.reload()}else if(d.type==='error')console.error('[Elit HMR] Error:',d.error)};ws.onclose=()=>{console.log('[Elit HMR] Disconnected - Retrying...');setTimeout(()=>window.location.reload(),1000)};ws.onerror=(e)=>console.error('[Elit HMR] WebSocket error:',e)})();<\/script>`,o=f.toString();if(n.basePath&&"/"!==n.basePath){let e=`<base href="${n.basePath}/">`;o.includes("<base")||(o.includes('<meta name="viewport"')?o=o.replace(/<meta name="viewport"[^>]*>/,t=>`${t}\n ${e}`):o.includes("<head>")&&(o=o.replace("<head>",`<head>\n ${e}`)))}o=o.includes("</head>")?o.replace("</head>",`${e}</head>`):o,o=o.includes("</body>")?o.replace("</body>",`${t}</body>`):o+t,f=Buffer.from(o)}let w={"Content-Type":m,"Cache-Control":".html"===y||".ts"===y||".tsx"===y?"no-cache, no-store, must-revalidate":"public, max-age=31536000, immutable"};if(/^(text\/|application\/(javascript|json|xml))/.test(m)&&f.length>1024){let{gzipSync:e}=d("zlib"),r=e(f);w["Content-Encoding"]="gzip",w["Content-Length"]=r.length,t.writeHead(200,w),t.end(r)}else t.writeHead(200,w),t.end(f);r.logging&&console.log(`[200] ${s.relative(n.root,e)}`)}catch(e){t.writeHead(500,{"Content-Type":"text/plain"}),t.end("500 Internal Server Error"),r.logging&&console.error("[500] Error reading file:",e)}}let S=new n.WebSocketServer({server:b});S.on("connection",e=>{p.add(e);let t={type:"connected",timestamp:Date.now()};e.send(JSON.stringify(t)),r.logging&&console.log("[HMR] Client connected"),e.on("message",t=>{try{let n=JSON.parse(t.toString());"state:subscribe"===n.type?(f.subscribe(n.key,e),r.logging&&console.log(`[State] Client subscribed to "${n.key}"`)):"state:unsubscribe"===n.type?(f.unsubscribe(n.key,e),r.logging&&console.log(`[State] Client unsubscribed from "${n.key}"`)):"state:change"===n.type&&(f.handleStateChange(n.key,n.value),r.logging&&console.log(`[State] Client updated "${n.key}"`))}catch(e){r.logging&&console.error("[WebSocket] Message parse error:",e)}}),e.on("close",()=>{p.delete(e),f.unsubscribeAll(e),r.logging&&console.log("[HMR] Client disconnected")})});let $=m.flatMap(e=>r.watch.map(t=>s.join(e.root,t))),T=o.watch($,{ignored:r.ignore,ignoreInitial:!0,persistent:!0});T.on("change",e=>{r.logging&&console.log(`[HMR] File changed: ${e}`);let t=JSON.stringify({type:"update",path:e,timestamp:Date.now()});p.forEach(e=>e.readyState===n.WebSocket.OPEN&&e.send(t))}),T.on("add",e=>r.logging&&console.log(`[HMR] File added: ${e}`)),T.on("unlink",e=>r.logging&&console.log(`[HMR] File removed: ${e}`)),b.setMaxListeners(20),b.listen(r.port,r.host,()=>{if(r.logging){if(console.log("\n🚀 Elit Dev Server"),console.log(`\n ➜ Local: http://${r.host}:${r.port}`),m.length>1)console.log(" ➜ Clients:"),m.forEach(e=>{let t=`http://${r.host}:${r.port}${e.basePath}`;console.log(` - ${t} → ${e.root}`)});else{let e=m[0];console.log(` ➜ Root: ${e.root}`),e.basePath&&console.log(` ➜ Base: ${e.basePath}`)}console.log("\n[HMR] Watching for file changes...\n")}if(r.open&&m.length>0){let e=m[0],t=`http://${r.host}:${r.port}${e.basePath}`;(async()=>{let{default:e}=await import("open");await e(t)})().catch(()=>{})}});let x=!1,C=m[0],E=`http://${r.host}:${r.port}${C.basePath}`;return{server:b,wss:S,url:E,state:f,close:async()=>{if(!x)return x=!0,r.logging&&console.log("\n[Server] Shutting down..."),await T.close(),S.close(),p.forEach(e=>e.close()),p.clear(),new Promise(e=>{b.close(()=>{r.logging&&console.log("[Server] Closed"),e()})})}}},exports.createProxyHandler=h,exports.errorHandler=function(){return async(e,t)=>{try{await t()}catch(t){console.error("Error:",t),e.res.headersSent||(e.res.writeHead(500,{"Content-Type":"application/json"}),e.res.end(JSON.stringify({error:"Internal Server Error",message:t instanceof Error?t.message:"Unknown error"})))}}},exports.html=(e,t,r=200)=>{e.writeHead(r,{"Content-Type":"text/html"}),e.end(t)},exports.json=(e,t,r=200)=>{e.writeHead(r,{"Content-Type":"application/json"}),e.end(JSON.stringify(t))},exports.logger=function(e={}){let{format:t="simple"}=e;return async(e,r)=>{let n=Date.now(),{method:o,url:i}=e.req;await r();let s=Date.now()-n,a=e.res.statusCode;console.log("detailed"===t?`[${(new Date).toISOString()}] ${o} ${i} ${a} - ${s}ms`:`${o} ${i} - ${a} (${s}ms)`)}},exports.rateLimit=function(e={}){let{windowMs:t=6e4,max:r=100,message:n="Too many requests"}=e,o=new Map;return async(e,i)=>{let s=e.req.socket.remoteAddress||"unknown",a=Date.now(),l=o.get(s);if((!l||a>l.resetTime)&&(l={count:0,resetTime:a+t},o.set(s,l)),++l.count>r)return e.res.writeHead(429,{"Content-Type":"application/json"}),void e.res.end(JSON.stringify({error:n}));await i()}},exports.security=function(){return async(e,t)=>{e.res.setHeader("X-Content-Type-Options","nosniff"),e.res.setHeader("X-Frame-Options","DENY"),e.res.setHeader("X-XSS-Protection","1; mode=block"),e.res.setHeader("Strict-Transport-Security","max-age=31536000; includeSubDomains"),await t()}},exports.status=(e,t,r)=>{e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify({status:t,message:r||""}))},exports.text=(e,t,r=200)=>{e.writeHead(r,{"Content-Type":"text/plain"}),e.end(t)};
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/runtime.ts
|
|
34
|
+
var runtime, isNode, isBun, isDeno;
|
|
35
|
+
var init_runtime = __esm({
|
|
36
|
+
"src/runtime.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
runtime = (() => {
|
|
39
|
+
if (typeof Deno !== "undefined") return "deno";
|
|
40
|
+
if (typeof Bun !== "undefined") return "bun";
|
|
41
|
+
return "node";
|
|
42
|
+
})();
|
|
43
|
+
isNode = runtime === "node";
|
|
44
|
+
isBun = runtime === "bun";
|
|
45
|
+
isDeno = runtime === "deno";
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// src/http.ts
|
|
50
|
+
var http_exports = {};
|
|
51
|
+
__export(http_exports, {
|
|
52
|
+
Agent: () => Agent,
|
|
53
|
+
ClientRequest: () => ClientRequest,
|
|
54
|
+
IncomingMessage: () => IncomingMessage,
|
|
55
|
+
METHODS: () => METHODS,
|
|
56
|
+
STATUS_CODES: () => STATUS_CODES,
|
|
57
|
+
Server: () => Server,
|
|
58
|
+
ServerResponse: () => ServerResponse,
|
|
59
|
+
createServer: () => createServer,
|
|
60
|
+
default: () => http_default,
|
|
61
|
+
get: () => get,
|
|
62
|
+
getRuntime: () => getRuntime,
|
|
63
|
+
request: () => request
|
|
64
|
+
});
|
|
65
|
+
function queueCallback(callback) {
|
|
66
|
+
if (callback) queueMicrotask(callback);
|
|
67
|
+
}
|
|
68
|
+
function headersToInit(headers) {
|
|
69
|
+
const result = {};
|
|
70
|
+
for (const key in headers) {
|
|
71
|
+
const value = headers[key];
|
|
72
|
+
result[key] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function createAddress(port, address, family = "IPv4") {
|
|
77
|
+
return { port, family, address };
|
|
78
|
+
}
|
|
79
|
+
function createErrorResponse() {
|
|
80
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
81
|
+
}
|
|
82
|
+
function emitListeningWithCallback(server, callback) {
|
|
83
|
+
server._listening = true;
|
|
84
|
+
server.emit("listening");
|
|
85
|
+
queueCallback(callback);
|
|
86
|
+
}
|
|
87
|
+
function closeAndEmit(server, callback) {
|
|
88
|
+
server._listening = false;
|
|
89
|
+
server.emit("close");
|
|
90
|
+
if (callback) queueMicrotask(() => callback());
|
|
91
|
+
}
|
|
92
|
+
function createServer(optionsOrListener, requestListener) {
|
|
93
|
+
return new Server(typeof optionsOrListener === "function" ? optionsOrListener : requestListener);
|
|
94
|
+
}
|
|
95
|
+
function request(url, options, callback) {
|
|
96
|
+
const urlString = typeof url === "string" ? url : url.toString();
|
|
97
|
+
const req = new ClientRequest(urlString, options);
|
|
98
|
+
if (isNode) {
|
|
99
|
+
const urlObj = new URL(urlString);
|
|
100
|
+
const client = urlObj.protocol === "https:" ? https : http;
|
|
101
|
+
const nodeReq = client.request(urlString, {
|
|
102
|
+
method: options?.method || "GET",
|
|
103
|
+
headers: options?.headers,
|
|
104
|
+
timeout: options?.timeout,
|
|
105
|
+
signal: options?.signal
|
|
106
|
+
}, (res) => {
|
|
107
|
+
const incomingMessage = new IncomingMessage(res);
|
|
108
|
+
if (callback) callback(incomingMessage);
|
|
109
|
+
req.emit("response", incomingMessage);
|
|
110
|
+
});
|
|
111
|
+
nodeReq.on("error", (error) => req.emit("error", error));
|
|
112
|
+
nodeReq.end();
|
|
113
|
+
} else {
|
|
114
|
+
queueMicrotask(async () => {
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetch(urlString, {
|
|
117
|
+
method: options?.method || "GET",
|
|
118
|
+
headers: options?.headers,
|
|
119
|
+
signal: options?.signal
|
|
120
|
+
});
|
|
121
|
+
const fetchRequest = new Request(urlString);
|
|
122
|
+
const incomingMessage = new IncomingMessage(fetchRequest);
|
|
123
|
+
incomingMessage.statusCode = response.status;
|
|
124
|
+
incomingMessage.statusMessage = response.statusText;
|
|
125
|
+
if (callback) callback(incomingMessage);
|
|
126
|
+
req.emit("response", incomingMessage);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
req.emit("error", error);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return req;
|
|
133
|
+
}
|
|
134
|
+
function get(url, options, callback) {
|
|
135
|
+
return request(url, { ...options, method: "GET" }, callback);
|
|
136
|
+
}
|
|
137
|
+
function getRuntime() {
|
|
138
|
+
return runtime;
|
|
139
|
+
}
|
|
140
|
+
var import_node_events, http, https, METHODS, STATUS_CODES, IncomingMessage, ServerResponse, Server, ClientRequest, Agent, http_default;
|
|
141
|
+
var init_http = __esm({
|
|
142
|
+
"src/http.ts"() {
|
|
143
|
+
"use strict";
|
|
144
|
+
import_node_events = require("events");
|
|
145
|
+
init_runtime();
|
|
146
|
+
if (isNode && typeof process !== "undefined") {
|
|
147
|
+
try {
|
|
148
|
+
http = require("http");
|
|
149
|
+
https = require("https");
|
|
150
|
+
} catch (e) {
|
|
151
|
+
http = require("http");
|
|
152
|
+
https = require("https");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
METHODS = [
|
|
156
|
+
"GET",
|
|
157
|
+
"POST",
|
|
158
|
+
"PUT",
|
|
159
|
+
"DELETE",
|
|
160
|
+
"PATCH",
|
|
161
|
+
"HEAD",
|
|
162
|
+
"OPTIONS",
|
|
163
|
+
"CONNECT",
|
|
164
|
+
"TRACE"
|
|
165
|
+
];
|
|
166
|
+
STATUS_CODES = {
|
|
167
|
+
100: "Continue",
|
|
168
|
+
101: "Switching Protocols",
|
|
169
|
+
102: "Processing",
|
|
170
|
+
200: "OK",
|
|
171
|
+
201: "Created",
|
|
172
|
+
202: "Accepted",
|
|
173
|
+
203: "Non-Authoritative Information",
|
|
174
|
+
204: "No Content",
|
|
175
|
+
205: "Reset Content",
|
|
176
|
+
206: "Partial Content",
|
|
177
|
+
300: "Multiple Choices",
|
|
178
|
+
301: "Moved Permanently",
|
|
179
|
+
302: "Found",
|
|
180
|
+
303: "See Other",
|
|
181
|
+
304: "Not Modified",
|
|
182
|
+
307: "Temporary Redirect",
|
|
183
|
+
308: "Permanent Redirect",
|
|
184
|
+
400: "Bad Request",
|
|
185
|
+
401: "Unauthorized",
|
|
186
|
+
402: "Payment Required",
|
|
187
|
+
403: "Forbidden",
|
|
188
|
+
404: "Not Found",
|
|
189
|
+
405: "Method Not Allowed",
|
|
190
|
+
406: "Not Acceptable",
|
|
191
|
+
407: "Proxy Authentication Required",
|
|
192
|
+
408: "Request Timeout",
|
|
193
|
+
409: "Conflict",
|
|
194
|
+
410: "Gone",
|
|
195
|
+
411: "Length Required",
|
|
196
|
+
412: "Precondition Failed",
|
|
197
|
+
413: "Payload Too Large",
|
|
198
|
+
414: "URI Too Long",
|
|
199
|
+
415: "Unsupported Media Type",
|
|
200
|
+
416: "Range Not Satisfiable",
|
|
201
|
+
417: "Expectation Failed",
|
|
202
|
+
418: "I'm a teapot",
|
|
203
|
+
422: "Unprocessable Entity",
|
|
204
|
+
425: "Too Early",
|
|
205
|
+
426: "Upgrade Required",
|
|
206
|
+
428: "Precondition Required",
|
|
207
|
+
429: "Too Many Requests",
|
|
208
|
+
431: "Request Header Fields Too Large",
|
|
209
|
+
451: "Unavailable For Legal Reasons",
|
|
210
|
+
500: "Internal Server Error",
|
|
211
|
+
501: "Not Implemented",
|
|
212
|
+
502: "Bad Gateway",
|
|
213
|
+
503: "Service Unavailable",
|
|
214
|
+
504: "Gateway Timeout",
|
|
215
|
+
505: "HTTP Version Not Supported",
|
|
216
|
+
506: "Variant Also Negotiates",
|
|
217
|
+
507: "Insufficient Storage",
|
|
218
|
+
508: "Loop Detected",
|
|
219
|
+
510: "Not Extended",
|
|
220
|
+
511: "Network Authentication Required"
|
|
221
|
+
};
|
|
222
|
+
IncomingMessage = class extends import_node_events.EventEmitter {
|
|
223
|
+
constructor(req) {
|
|
224
|
+
super();
|
|
225
|
+
this.httpVersion = "1.1";
|
|
226
|
+
this.rawHeaders = [];
|
|
227
|
+
this._req = req;
|
|
228
|
+
if (isNode) {
|
|
229
|
+
this.method = req.method;
|
|
230
|
+
this.url = req.url;
|
|
231
|
+
this.headers = req.headers;
|
|
232
|
+
this.statusCode = req.statusCode;
|
|
233
|
+
this.statusMessage = req.statusMessage;
|
|
234
|
+
this.httpVersion = req.httpVersion;
|
|
235
|
+
this.rawHeaders = req.rawHeaders;
|
|
236
|
+
this.socket = req.socket;
|
|
237
|
+
} else {
|
|
238
|
+
this.method = req.method;
|
|
239
|
+
const urlObj = new URL(req.url);
|
|
240
|
+
this.url = urlObj.pathname + urlObj.search;
|
|
241
|
+
this.headers = req.headers;
|
|
242
|
+
this.rawHeaders = [];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async text() {
|
|
246
|
+
if (isNode) {
|
|
247
|
+
return new Promise((resolve2, reject) => {
|
|
248
|
+
const chunks = [];
|
|
249
|
+
this._req.on("data", (chunk) => chunks.push(chunk));
|
|
250
|
+
this._req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
|
|
251
|
+
this._req.on("error", reject);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
return this._req.text();
|
|
255
|
+
}
|
|
256
|
+
async json() {
|
|
257
|
+
if (isNode) {
|
|
258
|
+
const text2 = await this.text();
|
|
259
|
+
return JSON.parse(text2);
|
|
260
|
+
}
|
|
261
|
+
return this._req.json();
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
ServerResponse = class extends import_node_events.EventEmitter {
|
|
265
|
+
constructor(_req, nodeRes) {
|
|
266
|
+
super();
|
|
267
|
+
this.statusCode = 200;
|
|
268
|
+
this.statusMessage = "OK";
|
|
269
|
+
this.headersSent = false;
|
|
270
|
+
this._body = "";
|
|
271
|
+
this._finished = false;
|
|
272
|
+
this._nodeRes = nodeRes;
|
|
273
|
+
this._headers = /* @__PURE__ */ Object.create(null);
|
|
274
|
+
}
|
|
275
|
+
setHeader(name, value) {
|
|
276
|
+
if (this.headersSent) {
|
|
277
|
+
throw new Error("Cannot set headers after they are sent");
|
|
278
|
+
}
|
|
279
|
+
if (isNode && this._nodeRes) {
|
|
280
|
+
this._nodeRes.setHeader(name, value);
|
|
281
|
+
}
|
|
282
|
+
this._headers[name.toLowerCase()] = value;
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
getHeader(name) {
|
|
286
|
+
if (isNode && this._nodeRes) {
|
|
287
|
+
return this._nodeRes.getHeader(name);
|
|
288
|
+
}
|
|
289
|
+
return this._headers[name.toLowerCase()];
|
|
290
|
+
}
|
|
291
|
+
getHeaders() {
|
|
292
|
+
if (isNode && this._nodeRes) {
|
|
293
|
+
return this._nodeRes.getHeaders();
|
|
294
|
+
}
|
|
295
|
+
return { ...this._headers };
|
|
296
|
+
}
|
|
297
|
+
getHeaderNames() {
|
|
298
|
+
if (isNode && this._nodeRes) {
|
|
299
|
+
return this._nodeRes.getHeaderNames();
|
|
300
|
+
}
|
|
301
|
+
return Object.keys(this._headers);
|
|
302
|
+
}
|
|
303
|
+
hasHeader(name) {
|
|
304
|
+
if (isNode && this._nodeRes) {
|
|
305
|
+
return this._nodeRes.hasHeader(name);
|
|
306
|
+
}
|
|
307
|
+
return name.toLowerCase() in this._headers;
|
|
308
|
+
}
|
|
309
|
+
removeHeader(name) {
|
|
310
|
+
if (this.headersSent) {
|
|
311
|
+
throw new Error("Cannot remove headers after they are sent");
|
|
312
|
+
}
|
|
313
|
+
if (isNode && this._nodeRes) {
|
|
314
|
+
this._nodeRes.removeHeader(name);
|
|
315
|
+
}
|
|
316
|
+
delete this._headers[name.toLowerCase()];
|
|
317
|
+
}
|
|
318
|
+
writeHead(statusCode, statusMessage, headers) {
|
|
319
|
+
if (this.headersSent) {
|
|
320
|
+
throw new Error("Cannot write headers after they are sent");
|
|
321
|
+
}
|
|
322
|
+
this.statusCode = statusCode;
|
|
323
|
+
if (typeof statusMessage === "string") {
|
|
324
|
+
this.statusMessage = statusMessage;
|
|
325
|
+
if (headers) {
|
|
326
|
+
for (const key in headers) {
|
|
327
|
+
this.setHeader(key, headers[key]);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
} else if (statusMessage) {
|
|
331
|
+
for (const key in statusMessage) {
|
|
332
|
+
this.setHeader(key, statusMessage[key]);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (isNode && this._nodeRes) {
|
|
336
|
+
if (typeof statusMessage === "string") {
|
|
337
|
+
this._nodeRes.writeHead(statusCode, statusMessage, headers);
|
|
338
|
+
} else {
|
|
339
|
+
this._nodeRes.writeHead(statusCode, statusMessage);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
this.headersSent = true;
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
write(chunk, encoding, callback) {
|
|
346
|
+
if (typeof encoding === "function") {
|
|
347
|
+
callback = encoding;
|
|
348
|
+
encoding = "utf8";
|
|
349
|
+
}
|
|
350
|
+
if (!this.headersSent) {
|
|
351
|
+
this.writeHead(this.statusCode);
|
|
352
|
+
}
|
|
353
|
+
if (isNode && this._nodeRes) {
|
|
354
|
+
return this._nodeRes.write(chunk, encoding, callback);
|
|
355
|
+
}
|
|
356
|
+
this._body += chunk;
|
|
357
|
+
queueCallback(callback);
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
end(chunk, encoding, callback) {
|
|
361
|
+
if (this._finished) {
|
|
362
|
+
return this;
|
|
363
|
+
}
|
|
364
|
+
if (typeof chunk === "function") {
|
|
365
|
+
callback = chunk;
|
|
366
|
+
chunk = void 0;
|
|
367
|
+
} else if (typeof encoding === "function") {
|
|
368
|
+
callback = encoding;
|
|
369
|
+
encoding = "utf8";
|
|
370
|
+
}
|
|
371
|
+
if (chunk !== void 0) {
|
|
372
|
+
this.write(chunk, encoding);
|
|
373
|
+
}
|
|
374
|
+
if (!this.headersSent) {
|
|
375
|
+
this.writeHead(this.statusCode);
|
|
376
|
+
}
|
|
377
|
+
this._finished = true;
|
|
378
|
+
if (isNode && this._nodeRes) {
|
|
379
|
+
this._nodeRes.end(callback);
|
|
380
|
+
this.emit("finish");
|
|
381
|
+
} else {
|
|
382
|
+
const response = new Response(this._body, {
|
|
383
|
+
status: this.statusCode,
|
|
384
|
+
statusText: this.statusMessage,
|
|
385
|
+
headers: headersToInit(this._headers)
|
|
386
|
+
});
|
|
387
|
+
if (this._resolve) {
|
|
388
|
+
this._resolve(response);
|
|
389
|
+
}
|
|
390
|
+
queueCallback(callback);
|
|
391
|
+
}
|
|
392
|
+
return this;
|
|
393
|
+
}
|
|
394
|
+
_setResolver(resolve2) {
|
|
395
|
+
this._resolve = resolve2;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
Server = class extends import_node_events.EventEmitter {
|
|
399
|
+
constructor(requestListener) {
|
|
400
|
+
super();
|
|
401
|
+
this._listening = false;
|
|
402
|
+
this.requestListener = requestListener;
|
|
403
|
+
}
|
|
404
|
+
listen(...args) {
|
|
405
|
+
let port = 3e3;
|
|
406
|
+
let hostname = "0.0.0.0";
|
|
407
|
+
let callback;
|
|
408
|
+
const firstArg = args[0];
|
|
409
|
+
if (typeof firstArg === "number") {
|
|
410
|
+
port = firstArg;
|
|
411
|
+
const secondArg = args[1];
|
|
412
|
+
if (typeof secondArg === "string") {
|
|
413
|
+
hostname = secondArg;
|
|
414
|
+
callback = args[2] || args[3];
|
|
415
|
+
} else if (typeof secondArg === "function") {
|
|
416
|
+
callback = secondArg;
|
|
417
|
+
}
|
|
418
|
+
} else if (firstArg && typeof firstArg === "object") {
|
|
419
|
+
port = firstArg.port || 3e3;
|
|
420
|
+
hostname = firstArg.hostname || "0.0.0.0";
|
|
421
|
+
callback = args[1];
|
|
422
|
+
}
|
|
423
|
+
const self = this;
|
|
424
|
+
if (isNode) {
|
|
425
|
+
this.nativeServer = http.createServer((req, res) => {
|
|
426
|
+
const incomingMessage = new IncomingMessage(req);
|
|
427
|
+
const serverResponse = new ServerResponse(incomingMessage, res);
|
|
428
|
+
if (self.requestListener) {
|
|
429
|
+
self.requestListener(incomingMessage, serverResponse);
|
|
430
|
+
} else {
|
|
431
|
+
self.emit("request", incomingMessage, serverResponse);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
this.nativeServer.on("upgrade", (req, socket, head) => {
|
|
435
|
+
self.emit("upgrade", req, socket, head);
|
|
436
|
+
});
|
|
437
|
+
this.nativeServer.listen(port, hostname, () => {
|
|
438
|
+
this._listening = true;
|
|
439
|
+
this.emit("listening");
|
|
440
|
+
if (callback) callback();
|
|
441
|
+
});
|
|
442
|
+
this.nativeServer.on("error", (err) => this.emit("error", err));
|
|
443
|
+
this.nativeServer.on("close", () => {
|
|
444
|
+
this._listening = false;
|
|
445
|
+
this.emit("close");
|
|
446
|
+
});
|
|
447
|
+
} else if (isBun) {
|
|
448
|
+
this.nativeServer = Bun.serve({
|
|
449
|
+
port,
|
|
450
|
+
hostname,
|
|
451
|
+
fetch: (req) => {
|
|
452
|
+
const urlObj = new URL(req.url);
|
|
453
|
+
const pathname = urlObj.pathname + urlObj.search;
|
|
454
|
+
let statusCode = 200;
|
|
455
|
+
let statusMessage = "OK";
|
|
456
|
+
let body = "";
|
|
457
|
+
const headers = /* @__PURE__ */ Object.create(null);
|
|
458
|
+
let responseReady = false;
|
|
459
|
+
const incomingMessage = {
|
|
460
|
+
method: req.method,
|
|
461
|
+
url: pathname,
|
|
462
|
+
headers: req.headers,
|
|
463
|
+
httpVersion: "1.1",
|
|
464
|
+
rawHeaders: [],
|
|
465
|
+
_req: req,
|
|
466
|
+
text: () => req.text(),
|
|
467
|
+
json: () => req.json()
|
|
468
|
+
};
|
|
469
|
+
const serverResponse = {
|
|
470
|
+
statusCode: 200,
|
|
471
|
+
statusMessage: "OK",
|
|
472
|
+
headersSent: false,
|
|
473
|
+
_headers: headers,
|
|
474
|
+
setHeader(name, value) {
|
|
475
|
+
headers[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
476
|
+
return this;
|
|
477
|
+
},
|
|
478
|
+
getHeader(name) {
|
|
479
|
+
return headers[name.toLowerCase()];
|
|
480
|
+
},
|
|
481
|
+
getHeaders() {
|
|
482
|
+
return { ...headers };
|
|
483
|
+
},
|
|
484
|
+
writeHead(status2, arg2, arg3) {
|
|
485
|
+
statusCode = status2;
|
|
486
|
+
this.statusCode = status2;
|
|
487
|
+
this.headersSent = true;
|
|
488
|
+
if (typeof arg2 === "string") {
|
|
489
|
+
statusMessage = arg2;
|
|
490
|
+
this.statusMessage = arg2;
|
|
491
|
+
if (arg3) {
|
|
492
|
+
for (const key in arg3) {
|
|
493
|
+
headers[key.toLowerCase()] = arg3[key];
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
} else if (arg2) {
|
|
497
|
+
for (const key in arg2) {
|
|
498
|
+
headers[key.toLowerCase()] = arg2[key];
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return this;
|
|
502
|
+
},
|
|
503
|
+
write(chunk) {
|
|
504
|
+
if (!this.headersSent) {
|
|
505
|
+
this.writeHead(statusCode);
|
|
506
|
+
}
|
|
507
|
+
body += chunk;
|
|
508
|
+
return true;
|
|
509
|
+
},
|
|
510
|
+
end(chunk) {
|
|
511
|
+
if (chunk !== void 0) {
|
|
512
|
+
this.write(chunk);
|
|
513
|
+
}
|
|
514
|
+
if (!this.headersSent) {
|
|
515
|
+
this.writeHead(statusCode);
|
|
516
|
+
}
|
|
517
|
+
responseReady = true;
|
|
518
|
+
return this;
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
if (self.requestListener) {
|
|
522
|
+
self.requestListener(incomingMessage, serverResponse);
|
|
523
|
+
}
|
|
524
|
+
if (responseReady) {
|
|
525
|
+
return new Response(body, {
|
|
526
|
+
status: statusCode,
|
|
527
|
+
statusText: statusMessage,
|
|
528
|
+
headers
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
return new Promise((resolve2) => {
|
|
532
|
+
serverResponse.end = (chunk) => {
|
|
533
|
+
if (chunk !== void 0) {
|
|
534
|
+
body += chunk;
|
|
535
|
+
}
|
|
536
|
+
resolve2(new Response(body, {
|
|
537
|
+
status: statusCode,
|
|
538
|
+
statusText: statusMessage,
|
|
539
|
+
headers
|
|
540
|
+
}));
|
|
541
|
+
};
|
|
542
|
+
});
|
|
543
|
+
},
|
|
544
|
+
error: createErrorResponse
|
|
545
|
+
});
|
|
546
|
+
emitListeningWithCallback(this, callback);
|
|
547
|
+
} else if (isDeno) {
|
|
548
|
+
this.nativeServer = Deno.serve({
|
|
549
|
+
port,
|
|
550
|
+
hostname,
|
|
551
|
+
handler: (req) => {
|
|
552
|
+
return new Promise((resolve2) => {
|
|
553
|
+
const incomingMessage = new IncomingMessage(req);
|
|
554
|
+
const serverResponse = new ServerResponse();
|
|
555
|
+
serverResponse._setResolver(resolve2);
|
|
556
|
+
if (self.requestListener) {
|
|
557
|
+
self.requestListener(incomingMessage, serverResponse);
|
|
558
|
+
} else {
|
|
559
|
+
self.emit("request", incomingMessage, serverResponse);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
},
|
|
563
|
+
onError: (error) => {
|
|
564
|
+
this.emit("error", error);
|
|
565
|
+
return createErrorResponse();
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
emitListeningWithCallback(this, callback);
|
|
569
|
+
}
|
|
570
|
+
return this;
|
|
571
|
+
}
|
|
572
|
+
close(callback) {
|
|
573
|
+
if (!this.nativeServer) {
|
|
574
|
+
if (callback) queueMicrotask(() => callback());
|
|
575
|
+
return this;
|
|
576
|
+
}
|
|
577
|
+
if (isNode) {
|
|
578
|
+
this.nativeServer.close(callback);
|
|
579
|
+
} else if (isBun) {
|
|
580
|
+
this.nativeServer.stop();
|
|
581
|
+
closeAndEmit(this, callback);
|
|
582
|
+
} else if (isDeno) {
|
|
583
|
+
this.nativeServer.shutdown();
|
|
584
|
+
closeAndEmit(this, callback);
|
|
585
|
+
}
|
|
586
|
+
return this;
|
|
587
|
+
}
|
|
588
|
+
address() {
|
|
589
|
+
if (!this.nativeServer) return null;
|
|
590
|
+
if (isNode) {
|
|
591
|
+
const addr = this.nativeServer.address();
|
|
592
|
+
if (!addr) return null;
|
|
593
|
+
if (typeof addr === "string") {
|
|
594
|
+
return createAddress(0, addr, "unix");
|
|
595
|
+
}
|
|
596
|
+
return addr;
|
|
597
|
+
} else if (isBun) {
|
|
598
|
+
return createAddress(this.nativeServer.port, this.nativeServer.hostname);
|
|
599
|
+
} else if (isDeno) {
|
|
600
|
+
const addr = this.nativeServer.addr;
|
|
601
|
+
return createAddress(addr.port, addr.hostname);
|
|
602
|
+
}
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
get listening() {
|
|
606
|
+
return this._listening;
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
ClientRequest = class extends import_node_events.EventEmitter {
|
|
610
|
+
constructor(_url, _options = {}) {
|
|
611
|
+
super();
|
|
612
|
+
}
|
|
613
|
+
write(_chunk) {
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
end(callback) {
|
|
617
|
+
queueCallback(callback);
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
Agent = class {
|
|
621
|
+
constructor(options) {
|
|
622
|
+
this.options = options;
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
http_default = {
|
|
626
|
+
createServer,
|
|
627
|
+
request,
|
|
628
|
+
get,
|
|
629
|
+
Server,
|
|
630
|
+
IncomingMessage,
|
|
631
|
+
ServerResponse,
|
|
632
|
+
Agent,
|
|
633
|
+
ClientRequest,
|
|
634
|
+
METHODS,
|
|
635
|
+
STATUS_CODES,
|
|
636
|
+
getRuntime
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
// src/server.ts
|
|
642
|
+
var server_exports = {};
|
|
643
|
+
__export(server_exports, {
|
|
644
|
+
ServerRouter: () => ServerRouter,
|
|
645
|
+
SharedState: () => SharedState,
|
|
646
|
+
StateManager: () => StateManager,
|
|
647
|
+
bodyLimit: () => bodyLimit,
|
|
648
|
+
cacheControl: () => cacheControl,
|
|
649
|
+
compress: () => compress,
|
|
650
|
+
cors: () => cors,
|
|
651
|
+
createDevServer: () => createDevServer,
|
|
652
|
+
createProxyHandler: () => createProxyHandler,
|
|
653
|
+
errorHandler: () => errorHandler,
|
|
654
|
+
html: () => html,
|
|
655
|
+
json: () => json,
|
|
656
|
+
logger: () => logger,
|
|
657
|
+
rateLimit: () => rateLimit,
|
|
658
|
+
security: () => security,
|
|
659
|
+
status: () => status,
|
|
660
|
+
text: () => text
|
|
661
|
+
});
|
|
662
|
+
module.exports = __toCommonJS(server_exports);
|
|
663
|
+
init_http();
|
|
664
|
+
|
|
665
|
+
// src/https.ts
|
|
666
|
+
var import_events = require("events");
|
|
667
|
+
init_runtime();
|
|
668
|
+
function queueCallback2(callback) {
|
|
669
|
+
if (callback) queueMicrotask(callback);
|
|
670
|
+
}
|
|
671
|
+
function loadHttpClasses() {
|
|
672
|
+
const httpModule = (init_http(), __toCommonJS(http_exports));
|
|
673
|
+
return {
|
|
674
|
+
IncomingMessage: httpModule.IncomingMessage,
|
|
675
|
+
ServerResponse: httpModule.ServerResponse
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
var https2;
|
|
679
|
+
var ClientRequest2 = class extends import_events.EventEmitter {
|
|
680
|
+
constructor(_url, _options = {}) {
|
|
681
|
+
super();
|
|
682
|
+
}
|
|
683
|
+
write(_chunk) {
|
|
684
|
+
return true;
|
|
685
|
+
}
|
|
686
|
+
end(callback) {
|
|
687
|
+
queueCallback2(callback);
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
function request2(url, options, callback) {
|
|
691
|
+
const urlString = typeof url === "string" ? url : url.toString();
|
|
692
|
+
const req = new ClientRequest2(urlString, options);
|
|
693
|
+
if (isNode) {
|
|
694
|
+
const { IncomingMessage: IncomingMessage3 } = loadHttpClasses();
|
|
695
|
+
if (!https2) https2 = require("https");
|
|
696
|
+
const nodeReq = https2.request(urlString, {
|
|
697
|
+
method: options?.method || "GET",
|
|
698
|
+
headers: options?.headers,
|
|
699
|
+
timeout: options?.timeout,
|
|
700
|
+
signal: options?.signal
|
|
701
|
+
}, (res) => {
|
|
702
|
+
const incomingMessage = new IncomingMessage3(res);
|
|
703
|
+
if (callback) callback(incomingMessage);
|
|
704
|
+
req.emit("response", incomingMessage);
|
|
705
|
+
});
|
|
706
|
+
nodeReq.on("error", (error) => req.emit("error", error));
|
|
707
|
+
nodeReq.end();
|
|
708
|
+
} else {
|
|
709
|
+
const { IncomingMessage: IncomingMessage3 } = loadHttpClasses();
|
|
710
|
+
queueMicrotask(async () => {
|
|
711
|
+
try {
|
|
712
|
+
const response = await fetch(urlString, {
|
|
713
|
+
method: options?.method || "GET",
|
|
714
|
+
headers: options?.headers,
|
|
715
|
+
signal: options?.signal
|
|
716
|
+
});
|
|
717
|
+
const fetchRequest = new Request(urlString);
|
|
718
|
+
const incomingMessage = new IncomingMessage3(fetchRequest);
|
|
719
|
+
incomingMessage.statusCode = response.status;
|
|
720
|
+
incomingMessage.statusMessage = response.statusText;
|
|
721
|
+
if (callback) callback(incomingMessage);
|
|
722
|
+
req.emit("response", incomingMessage);
|
|
723
|
+
} catch (error) {
|
|
724
|
+
req.emit("error", error);
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
return req;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/ws.ts
|
|
732
|
+
var import_events2 = require("events");
|
|
733
|
+
init_runtime();
|
|
734
|
+
var CLOSE_CODES = {
|
|
735
|
+
NORMAL: 1e3,
|
|
736
|
+
GOING_AWAY: 1001,
|
|
737
|
+
PROTOCOL_ERROR: 1002,
|
|
738
|
+
UNSUPPORTED_DATA: 1003,
|
|
739
|
+
NO_STATUS: 1005,
|
|
740
|
+
ABNORMAL: 1006,
|
|
741
|
+
INVALID_DATA: 1007,
|
|
742
|
+
POLICY_VIOLATION: 1008,
|
|
743
|
+
MESSAGE_TOO_BIG: 1009,
|
|
744
|
+
EXTENSION_REQUIRED: 1010,
|
|
745
|
+
INTERNAL_ERROR: 1011,
|
|
746
|
+
SERVICE_RESTART: 1012,
|
|
747
|
+
TRY_AGAIN_LATER: 1013,
|
|
748
|
+
BAD_GATEWAY: 1014,
|
|
749
|
+
TLS_HANDSHAKE_FAIL: 1015
|
|
750
|
+
};
|
|
751
|
+
function queueCallback3(callback, error) {
|
|
752
|
+
if (callback) {
|
|
753
|
+
queueMicrotask(() => callback(error));
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
function createNativeWebSocket(url, protocols) {
|
|
757
|
+
if (runtime === "node" && typeof globalThis.WebSocket === "undefined") {
|
|
758
|
+
throw new Error("WebSocket is not available. Please use Node.js 18+ or install ws package.");
|
|
759
|
+
}
|
|
760
|
+
return new globalThis.WebSocket(url, protocols);
|
|
761
|
+
}
|
|
762
|
+
var WebSocket = class extends import_events2.EventEmitter {
|
|
763
|
+
constructor(address, protocols, _options) {
|
|
764
|
+
super();
|
|
765
|
+
this.readyState = 0 /* CONNECTING */;
|
|
766
|
+
this.protocol = "";
|
|
767
|
+
this.extensions = "";
|
|
768
|
+
this.binaryType = "nodebuffer";
|
|
769
|
+
this.url = typeof address === "string" ? address : address.toString();
|
|
770
|
+
const protocolsArray = Array.isArray(protocols) ? protocols : protocols ? [protocols] : void 0;
|
|
771
|
+
this._socket = createNativeWebSocket(this.url, protocolsArray);
|
|
772
|
+
this._setupNativeSocket();
|
|
773
|
+
}
|
|
774
|
+
_setupNativeSocket() {
|
|
775
|
+
this._socket.onopen = () => {
|
|
776
|
+
this.readyState = 1 /* OPEN */;
|
|
777
|
+
this.emit("open");
|
|
778
|
+
};
|
|
779
|
+
this._socket.onmessage = (event) => {
|
|
780
|
+
const isBinary = event.data instanceof ArrayBuffer || event.data instanceof Blob;
|
|
781
|
+
this.emit("message", event.data, isBinary);
|
|
782
|
+
};
|
|
783
|
+
this._socket.onclose = (event) => {
|
|
784
|
+
this.readyState = 3 /* CLOSED */;
|
|
785
|
+
this.emit("close", event.code, event.reason);
|
|
786
|
+
};
|
|
787
|
+
this._socket.onerror = () => {
|
|
788
|
+
this.emit("error", new Error("WebSocket error"));
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Send data through WebSocket
|
|
793
|
+
*/
|
|
794
|
+
send(data, options, callback) {
|
|
795
|
+
const cb = typeof options === "function" ? options : callback;
|
|
796
|
+
if (this.readyState !== 1 /* OPEN */) {
|
|
797
|
+
return queueCallback3(cb, new Error("WebSocket is not open"));
|
|
798
|
+
}
|
|
799
|
+
try {
|
|
800
|
+
this._socket.send(data);
|
|
801
|
+
queueCallback3(cb);
|
|
802
|
+
} catch (error) {
|
|
803
|
+
queueCallback3(cb, error);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Close the WebSocket connection
|
|
808
|
+
*/
|
|
809
|
+
close(code, reason) {
|
|
810
|
+
if (this.readyState === 3 /* CLOSED */ || this.readyState === 2 /* CLOSING */) {
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
this.readyState = 2 /* CLOSING */;
|
|
814
|
+
this._socket.close(code, typeof reason === "string" ? reason : reason?.toString());
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Pause the socket (no-op for native WebSocket)
|
|
818
|
+
*/
|
|
819
|
+
pause() {
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Resume the socket (no-op for native WebSocket)
|
|
823
|
+
*/
|
|
824
|
+
resume() {
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Send a ping frame (no-op for native WebSocket)
|
|
828
|
+
*/
|
|
829
|
+
ping(_data, _mask, callback) {
|
|
830
|
+
queueCallback3(callback);
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Send a pong frame (no-op for native WebSocket)
|
|
834
|
+
*/
|
|
835
|
+
pong(_data, _mask, callback) {
|
|
836
|
+
queueCallback3(callback);
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Terminate the connection
|
|
840
|
+
*/
|
|
841
|
+
terminate() {
|
|
842
|
+
this._socket.close();
|
|
843
|
+
this.readyState = 3 /* CLOSED */;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Get buffered amount
|
|
847
|
+
*/
|
|
848
|
+
get bufferedAmount() {
|
|
849
|
+
return this._socket.bufferedAmount || 0;
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
var WebSocketServer = class extends import_events2.EventEmitter {
|
|
853
|
+
constructor(options, callback) {
|
|
854
|
+
super();
|
|
855
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
856
|
+
this.options = options || {};
|
|
857
|
+
this.path = options?.path || "/";
|
|
858
|
+
if (runtime === "node") {
|
|
859
|
+
if (options?.server) {
|
|
860
|
+
this._httpServer = options.server;
|
|
861
|
+
this._setupUpgradeHandler();
|
|
862
|
+
} else if (options?.noServer) {
|
|
863
|
+
} else {
|
|
864
|
+
const http2 = require("http");
|
|
865
|
+
this._httpServer = http2.createServer();
|
|
866
|
+
this._setupUpgradeHandler();
|
|
867
|
+
if (options?.port) {
|
|
868
|
+
this._httpServer.listen(options.port, options.host, callback);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
} else {
|
|
872
|
+
queueCallback3(callback);
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
_setupUpgradeHandler() {
|
|
876
|
+
this._httpServer.on("upgrade", (request3, socket, head) => {
|
|
877
|
+
console.log("[WebSocket] Upgrade request:", request3.url, "Expected:", this.path);
|
|
878
|
+
if (this.path && this.path !== "/" && request3.url !== this.path) {
|
|
879
|
+
console.log("[WebSocket] Path mismatch, ignoring");
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
this.handleUpgrade(request3, socket, head, (client) => {
|
|
883
|
+
console.log("[WebSocket] Client connected");
|
|
884
|
+
this.emit("connection", client, request3);
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Handle HTTP upgrade for WebSocket
|
|
890
|
+
*/
|
|
891
|
+
handleUpgrade(request3, socket, _head, callback) {
|
|
892
|
+
const key = request3.headers["sec-websocket-key"];
|
|
893
|
+
if (!key) {
|
|
894
|
+
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
const crypto = require("crypto");
|
|
898
|
+
const acceptKey = crypto.createHash("sha1").update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");
|
|
899
|
+
const headers = [
|
|
900
|
+
"HTTP/1.1 101 Switching Protocols",
|
|
901
|
+
"Upgrade: websocket",
|
|
902
|
+
"Connection: Upgrade",
|
|
903
|
+
`Sec-WebSocket-Accept: ${acceptKey}`,
|
|
904
|
+
"",
|
|
905
|
+
""
|
|
906
|
+
];
|
|
907
|
+
socket.write(headers.join("\r\n"));
|
|
908
|
+
const client = this._createClientFromSocket(socket);
|
|
909
|
+
if (this.options.clientTracking !== false) {
|
|
910
|
+
this.clients.add(client);
|
|
911
|
+
client.on("close", () => {
|
|
912
|
+
this.clients.delete(client);
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
callback(client);
|
|
916
|
+
}
|
|
917
|
+
_createClientFromSocket(socket) {
|
|
918
|
+
const client = Object.create(WebSocket.prototype);
|
|
919
|
+
import_events2.EventEmitter.call(client);
|
|
920
|
+
client.readyState = 1 /* OPEN */;
|
|
921
|
+
client.url = "ws://localhost";
|
|
922
|
+
client.protocol = "";
|
|
923
|
+
client.extensions = "";
|
|
924
|
+
client.binaryType = "nodebuffer";
|
|
925
|
+
client._socket = socket;
|
|
926
|
+
socket.on("data", (data) => {
|
|
927
|
+
try {
|
|
928
|
+
const message = this._parseFrame(data);
|
|
929
|
+
if (message) {
|
|
930
|
+
client.emit("message", message, false);
|
|
931
|
+
}
|
|
932
|
+
} catch (error) {
|
|
933
|
+
client.emit("error", error);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
socket.on("end", () => {
|
|
937
|
+
client.readyState = 3 /* CLOSED */;
|
|
938
|
+
client.emit("close", CLOSE_CODES.NORMAL, "");
|
|
939
|
+
});
|
|
940
|
+
socket.on("error", (error) => {
|
|
941
|
+
client.emit("error", error);
|
|
942
|
+
});
|
|
943
|
+
client.send = (data, _options, callback) => {
|
|
944
|
+
try {
|
|
945
|
+
const frame = this._createFrame(data);
|
|
946
|
+
socket.write(frame);
|
|
947
|
+
queueCallback3(callback);
|
|
948
|
+
} catch (error) {
|
|
949
|
+
queueCallback3(callback, error);
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
client.close = (_code, _reason) => {
|
|
953
|
+
socket.end();
|
|
954
|
+
client.readyState = 3 /* CLOSED */;
|
|
955
|
+
};
|
|
956
|
+
return client;
|
|
957
|
+
}
|
|
958
|
+
_parseFrame(data) {
|
|
959
|
+
if (data.length < 2) return null;
|
|
960
|
+
const firstByte = data[0];
|
|
961
|
+
const secondByte = data[1];
|
|
962
|
+
const opcode = firstByte & 15;
|
|
963
|
+
const isMasked = (secondByte & 128) === 128;
|
|
964
|
+
let payloadLength = secondByte & 127;
|
|
965
|
+
let offset = 2;
|
|
966
|
+
if (payloadLength === 126) {
|
|
967
|
+
payloadLength = data.readUInt16BE(2);
|
|
968
|
+
offset = 4;
|
|
969
|
+
} else if (payloadLength === 127) {
|
|
970
|
+
payloadLength = Number(data.readBigUInt64BE(2));
|
|
971
|
+
offset = 10;
|
|
972
|
+
}
|
|
973
|
+
let payload = data.subarray(offset);
|
|
974
|
+
if (isMasked) {
|
|
975
|
+
const maskKey = data.subarray(offset, offset + 4);
|
|
976
|
+
payload = data.subarray(offset + 4, offset + 4 + payloadLength);
|
|
977
|
+
for (let i = 0; i < payload.length; i++) {
|
|
978
|
+
payload[i] ^= maskKey[i % 4];
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
if (opcode === 1) {
|
|
982
|
+
return payload.toString("utf8");
|
|
983
|
+
}
|
|
984
|
+
return null;
|
|
985
|
+
}
|
|
986
|
+
_createFrame(data) {
|
|
987
|
+
const payload = typeof data === "string" ? Buffer.from(data) : data;
|
|
988
|
+
const payloadLength = Buffer.isBuffer(payload) ? payload.length : 0;
|
|
989
|
+
let frame;
|
|
990
|
+
let offset = 2;
|
|
991
|
+
if (payloadLength < 126) {
|
|
992
|
+
frame = Buffer.allocUnsafe(2 + payloadLength);
|
|
993
|
+
frame[1] = payloadLength;
|
|
994
|
+
} else if (payloadLength < 65536) {
|
|
995
|
+
frame = Buffer.allocUnsafe(4 + payloadLength);
|
|
996
|
+
frame[1] = 126;
|
|
997
|
+
frame.writeUInt16BE(payloadLength, 2);
|
|
998
|
+
offset = 4;
|
|
999
|
+
} else {
|
|
1000
|
+
frame = Buffer.allocUnsafe(10 + payloadLength);
|
|
1001
|
+
frame[1] = 127;
|
|
1002
|
+
frame.writeBigUInt64BE(BigInt(payloadLength), 2);
|
|
1003
|
+
offset = 10;
|
|
1004
|
+
}
|
|
1005
|
+
frame[0] = 129;
|
|
1006
|
+
if (Buffer.isBuffer(payload)) {
|
|
1007
|
+
payload.copy(frame, offset);
|
|
1008
|
+
}
|
|
1009
|
+
return frame;
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Close the server
|
|
1013
|
+
*/
|
|
1014
|
+
close(callback) {
|
|
1015
|
+
this.clients.forEach((client) => client.close());
|
|
1016
|
+
this.clients.clear();
|
|
1017
|
+
if (this._httpServer) {
|
|
1018
|
+
this._httpServer.close(callback);
|
|
1019
|
+
} else {
|
|
1020
|
+
this.emit("close");
|
|
1021
|
+
queueCallback3(callback);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Check if server should handle request
|
|
1026
|
+
*/
|
|
1027
|
+
shouldHandle(request3) {
|
|
1028
|
+
if (this.path && request3.url !== this.path) {
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Get server address
|
|
1035
|
+
*/
|
|
1036
|
+
address() {
|
|
1037
|
+
if (this._httpServer && this._httpServer.address) {
|
|
1038
|
+
return this._httpServer.address();
|
|
1039
|
+
}
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
// src/chokidar.ts
|
|
1045
|
+
var import_events3 = require("events");
|
|
1046
|
+
init_runtime();
|
|
1047
|
+
function normalizePath(path) {
|
|
1048
|
+
return path.replace(/\\/g, "/");
|
|
1049
|
+
}
|
|
1050
|
+
function emitEvent(watcher, eventType, path) {
|
|
1051
|
+
watcher.emit(eventType, path);
|
|
1052
|
+
watcher.emit("all", eventType, path);
|
|
1053
|
+
}
|
|
1054
|
+
function matchesAnyPattern(path, patterns) {
|
|
1055
|
+
return patterns.some((pattern) => matchesPattern(path, pattern));
|
|
1056
|
+
}
|
|
1057
|
+
function handleRenameEvent(watcher, fullPath, fs2) {
|
|
1058
|
+
try {
|
|
1059
|
+
fs2.statSync(fullPath);
|
|
1060
|
+
emitEvent(watcher, "add", fullPath);
|
|
1061
|
+
} catch {
|
|
1062
|
+
emitEvent(watcher, "unlink", fullPath);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
function setupFsWatch(watcher, baseDir, patterns, fs2) {
|
|
1066
|
+
try {
|
|
1067
|
+
const nativeWatcher = fs2.watch(baseDir, { recursive: true }, (eventType, filename) => {
|
|
1068
|
+
if (!filename) return;
|
|
1069
|
+
const fullPath = normalizePath(`${baseDir}/${filename}`);
|
|
1070
|
+
if (!matchesAnyPattern(fullPath, patterns)) return;
|
|
1071
|
+
if (eventType === "rename") {
|
|
1072
|
+
handleRenameEvent(watcher, fullPath, fs2);
|
|
1073
|
+
} else if (eventType === "change") {
|
|
1074
|
+
emitEvent(watcher, "change", fullPath);
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
watcher._setWatcher(nativeWatcher);
|
|
1078
|
+
watcher["_watched"].add(baseDir);
|
|
1079
|
+
queueMicrotask(() => watcher.emit("ready"));
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
watcher.emit("error", error);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
var FSWatcher = class extends import_events3.EventEmitter {
|
|
1085
|
+
constructor(options) {
|
|
1086
|
+
super();
|
|
1087
|
+
this._closed = false;
|
|
1088
|
+
this._watched = /* @__PURE__ */ new Set();
|
|
1089
|
+
this.options = options || {};
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Add paths to be watched
|
|
1093
|
+
*/
|
|
1094
|
+
add(paths) {
|
|
1095
|
+
if (this._closed) {
|
|
1096
|
+
throw new Error("Watcher has been closed");
|
|
1097
|
+
}
|
|
1098
|
+
const pathArray = Array.isArray(paths) ? paths : [paths];
|
|
1099
|
+
if (runtime === "node") {
|
|
1100
|
+
if (this._watcher) {
|
|
1101
|
+
this._watcher.add(pathArray);
|
|
1102
|
+
}
|
|
1103
|
+
} else {
|
|
1104
|
+
pathArray.forEach((path) => this._watched.add(path));
|
|
1105
|
+
}
|
|
1106
|
+
return this;
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Stop watching paths
|
|
1110
|
+
*/
|
|
1111
|
+
unwatch(paths) {
|
|
1112
|
+
if (this._closed) {
|
|
1113
|
+
return this;
|
|
1114
|
+
}
|
|
1115
|
+
const pathArray = Array.isArray(paths) ? paths : [paths];
|
|
1116
|
+
if (runtime === "node") {
|
|
1117
|
+
if (this._watcher) {
|
|
1118
|
+
this._watcher.unwatch(pathArray);
|
|
1119
|
+
}
|
|
1120
|
+
} else {
|
|
1121
|
+
pathArray.forEach((path) => this._watched.delete(path));
|
|
1122
|
+
}
|
|
1123
|
+
return this;
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Close the watcher
|
|
1127
|
+
*/
|
|
1128
|
+
async close() {
|
|
1129
|
+
if (this._closed) {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
this._closed = true;
|
|
1133
|
+
if (runtime === "node") {
|
|
1134
|
+
if (this._watcher) {
|
|
1135
|
+
await this._watcher.close();
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
this.removeAllListeners();
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Get watched paths
|
|
1142
|
+
*/
|
|
1143
|
+
getWatched() {
|
|
1144
|
+
if (runtime === "node" && this._watcher) {
|
|
1145
|
+
return this._watcher.getWatched();
|
|
1146
|
+
}
|
|
1147
|
+
const result = {};
|
|
1148
|
+
this._watched.forEach((path) => {
|
|
1149
|
+
const dir = path.substring(0, path.lastIndexOf("/")) || ".";
|
|
1150
|
+
const file = path.substring(path.lastIndexOf("/") + 1);
|
|
1151
|
+
if (!result[dir]) {
|
|
1152
|
+
result[dir] = [];
|
|
1153
|
+
}
|
|
1154
|
+
result[dir].push(file);
|
|
1155
|
+
});
|
|
1156
|
+
return result;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Internal method to set native watcher
|
|
1160
|
+
* @internal
|
|
1161
|
+
*/
|
|
1162
|
+
_setWatcher(watcher) {
|
|
1163
|
+
this._watcher = watcher;
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
function getBaseDirectory(pattern) {
|
|
1167
|
+
const parts = pattern.split(/[\\\/]/);
|
|
1168
|
+
let baseDir = "";
|
|
1169
|
+
for (const part of parts) {
|
|
1170
|
+
if (part.includes("*") || part.includes("?")) {
|
|
1171
|
+
break;
|
|
1172
|
+
}
|
|
1173
|
+
baseDir = baseDir ? `${baseDir}/${part}` : part;
|
|
1174
|
+
}
|
|
1175
|
+
return baseDir || ".";
|
|
1176
|
+
}
|
|
1177
|
+
function matchesPattern(filePath, pattern) {
|
|
1178
|
+
const regexPattern = normalizePath(pattern).replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, ".");
|
|
1179
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
1180
|
+
const normalizedPath = normalizePath(filePath);
|
|
1181
|
+
return regex.test(normalizedPath);
|
|
1182
|
+
}
|
|
1183
|
+
function watch(paths, options) {
|
|
1184
|
+
const watcher = new FSWatcher(options);
|
|
1185
|
+
const pathArray = Array.isArray(paths) ? paths : [paths];
|
|
1186
|
+
const watchMap = /* @__PURE__ */ new Map();
|
|
1187
|
+
pathArray.forEach((path) => {
|
|
1188
|
+
const baseDir = getBaseDirectory(path);
|
|
1189
|
+
if (!watchMap.has(baseDir)) {
|
|
1190
|
+
watchMap.set(baseDir, []);
|
|
1191
|
+
}
|
|
1192
|
+
watchMap.get(baseDir).push(path);
|
|
1193
|
+
});
|
|
1194
|
+
if (runtime === "node") {
|
|
1195
|
+
const fs2 = require("fs");
|
|
1196
|
+
watchMap.forEach((patterns, baseDir) => setupFsWatch(watcher, baseDir, patterns, fs2));
|
|
1197
|
+
} else if (runtime === "bun") {
|
|
1198
|
+
const fs2 = require("fs");
|
|
1199
|
+
watchMap.forEach((patterns, baseDir) => setupFsWatch(watcher, baseDir, patterns, fs2));
|
|
1200
|
+
} else if (runtime === "deno") {
|
|
1201
|
+
const baseDirs = Array.from(watchMap.keys());
|
|
1202
|
+
const allPatterns = Array.from(watchMap.values()).flat();
|
|
1203
|
+
(async () => {
|
|
1204
|
+
try {
|
|
1205
|
+
const denoWatcher = Deno.watchFs(baseDirs);
|
|
1206
|
+
for await (const event of denoWatcher) {
|
|
1207
|
+
if (watcher["_closed"]) break;
|
|
1208
|
+
for (const path of event.paths) {
|
|
1209
|
+
const normalizedPath = normalizePath(path);
|
|
1210
|
+
if (!matchesAnyPattern(normalizedPath, allPatterns)) continue;
|
|
1211
|
+
switch (event.kind) {
|
|
1212
|
+
case "create":
|
|
1213
|
+
emitEvent(watcher, "add", path);
|
|
1214
|
+
break;
|
|
1215
|
+
case "modify":
|
|
1216
|
+
emitEvent(watcher, "change", path);
|
|
1217
|
+
break;
|
|
1218
|
+
case "remove":
|
|
1219
|
+
emitEvent(watcher, "unlink", path);
|
|
1220
|
+
break;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
if (!watcher["_closed"]) {
|
|
1226
|
+
watcher.emit("error", error);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
})();
|
|
1230
|
+
pathArray.forEach((path) => watcher.add(path));
|
|
1231
|
+
queueMicrotask(() => watcher.emit("ready"));
|
|
1232
|
+
}
|
|
1233
|
+
return watcher;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// src/fs.ts
|
|
1237
|
+
init_runtime();
|
|
1238
|
+
function parseOptions(options, defaultValue) {
|
|
1239
|
+
return typeof options === "string" ? { encoding: options } : options || defaultValue;
|
|
1240
|
+
}
|
|
1241
|
+
function decodeContent(content, encoding) {
|
|
1242
|
+
if (encoding) {
|
|
1243
|
+
return new TextDecoder(encoding).decode(content);
|
|
1244
|
+
}
|
|
1245
|
+
return Buffer.from(content instanceof ArrayBuffer ? new Uint8Array(content) : content);
|
|
1246
|
+
}
|
|
1247
|
+
var fs;
|
|
1248
|
+
var fsPromises;
|
|
1249
|
+
if (isNode) {
|
|
1250
|
+
fs = require("fs");
|
|
1251
|
+
fsPromises = require("fs/promises");
|
|
1252
|
+
}
|
|
1253
|
+
async function readFile(path, options) {
|
|
1254
|
+
const opts = parseOptions(options, {});
|
|
1255
|
+
if (isNode) {
|
|
1256
|
+
return fsPromises.readFile(path, opts);
|
|
1257
|
+
} else if (isBun) {
|
|
1258
|
+
const file = Bun.file(path);
|
|
1259
|
+
const content = await file.arrayBuffer();
|
|
1260
|
+
return decodeContent(content, opts.encoding);
|
|
1261
|
+
} else if (isDeno) {
|
|
1262
|
+
const content = await Deno.readFile(path);
|
|
1263
|
+
return decodeContent(content, opts.encoding);
|
|
1264
|
+
}
|
|
1265
|
+
throw new Error("Unsupported runtime");
|
|
1266
|
+
}
|
|
1267
|
+
async function stat(path) {
|
|
1268
|
+
if (isNode) {
|
|
1269
|
+
return fsPromises.stat(path);
|
|
1270
|
+
} else if (isBun) {
|
|
1271
|
+
const file = Bun.file(path);
|
|
1272
|
+
const size = file.size;
|
|
1273
|
+
const exists = await file.exists();
|
|
1274
|
+
if (!exists) {
|
|
1275
|
+
throw new Error(`ENOENT: no such file or directory, stat '${path}'`);
|
|
1276
|
+
}
|
|
1277
|
+
return createStatsObject(path, size, false);
|
|
1278
|
+
} else if (isDeno) {
|
|
1279
|
+
const info = await Deno.stat(path);
|
|
1280
|
+
return createStatsFromDenoFileInfo(info);
|
|
1281
|
+
}
|
|
1282
|
+
throw new Error("Unsupported runtime");
|
|
1283
|
+
}
|
|
1284
|
+
async function realpath(path, options) {
|
|
1285
|
+
if (isNode) {
|
|
1286
|
+
return fsPromises.realpath(path, options);
|
|
1287
|
+
} else if (isBun) {
|
|
1288
|
+
const fs2 = require("fs/promises");
|
|
1289
|
+
return fs2.realpath(path, options);
|
|
1290
|
+
} else if (isDeno) {
|
|
1291
|
+
return await Deno.realPath(path);
|
|
1292
|
+
}
|
|
1293
|
+
return path;
|
|
1294
|
+
}
|
|
1295
|
+
function createStatsObject(_path, size, isDir) {
|
|
1296
|
+
const now = Date.now();
|
|
1297
|
+
return {
|
|
1298
|
+
isFile: () => !isDir,
|
|
1299
|
+
isDirectory: () => isDir,
|
|
1300
|
+
isBlockDevice: () => false,
|
|
1301
|
+
isCharacterDevice: () => false,
|
|
1302
|
+
isSymbolicLink: () => false,
|
|
1303
|
+
isFIFO: () => false,
|
|
1304
|
+
isSocket: () => false,
|
|
1305
|
+
dev: 0,
|
|
1306
|
+
ino: 0,
|
|
1307
|
+
mode: isDir ? 16877 : 33188,
|
|
1308
|
+
nlink: 1,
|
|
1309
|
+
uid: 0,
|
|
1310
|
+
gid: 0,
|
|
1311
|
+
rdev: 0,
|
|
1312
|
+
size,
|
|
1313
|
+
blksize: 4096,
|
|
1314
|
+
blocks: Math.ceil(size / 512),
|
|
1315
|
+
atimeMs: now,
|
|
1316
|
+
mtimeMs: now,
|
|
1317
|
+
ctimeMs: now,
|
|
1318
|
+
birthtimeMs: now,
|
|
1319
|
+
atime: new Date(now),
|
|
1320
|
+
mtime: new Date(now),
|
|
1321
|
+
ctime: new Date(now),
|
|
1322
|
+
birthtime: new Date(now)
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function createStatsFromDenoFileInfo(info) {
|
|
1326
|
+
return {
|
|
1327
|
+
isFile: () => info.isFile,
|
|
1328
|
+
isDirectory: () => info.isDirectory,
|
|
1329
|
+
isBlockDevice: () => false,
|
|
1330
|
+
isCharacterDevice: () => false,
|
|
1331
|
+
isSymbolicLink: () => info.isSymlink || false,
|
|
1332
|
+
isFIFO: () => false,
|
|
1333
|
+
isSocket: () => false,
|
|
1334
|
+
dev: info.dev || 0,
|
|
1335
|
+
ino: info.ino || 0,
|
|
1336
|
+
mode: info.mode || 0,
|
|
1337
|
+
nlink: info.nlink || 1,
|
|
1338
|
+
uid: info.uid || 0,
|
|
1339
|
+
gid: info.gid || 0,
|
|
1340
|
+
rdev: 0,
|
|
1341
|
+
size: info.size,
|
|
1342
|
+
blksize: info.blksize || 4096,
|
|
1343
|
+
blocks: info.blocks || Math.ceil(info.size / 512),
|
|
1344
|
+
atimeMs: info.atime?.getTime() || Date.now(),
|
|
1345
|
+
mtimeMs: info.mtime?.getTime() || Date.now(),
|
|
1346
|
+
ctimeMs: info.birthtime?.getTime() || Date.now(),
|
|
1347
|
+
birthtimeMs: info.birthtime?.getTime() || Date.now(),
|
|
1348
|
+
atime: info.atime || /* @__PURE__ */ new Date(),
|
|
1349
|
+
mtime: info.mtime || /* @__PURE__ */ new Date(),
|
|
1350
|
+
ctime: info.birthtime || /* @__PURE__ */ new Date(),
|
|
1351
|
+
birthtime: info.birthtime || /* @__PURE__ */ new Date()
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// src/path.ts
|
|
1356
|
+
init_runtime();
|
|
1357
|
+
function getSeparator(isWin) {
|
|
1358
|
+
return isWin ? "\\" : "/";
|
|
1359
|
+
}
|
|
1360
|
+
function getCwd() {
|
|
1361
|
+
if (isNode || isBun) {
|
|
1362
|
+
return process.cwd();
|
|
1363
|
+
} else if (isDeno) {
|
|
1364
|
+
return Deno.cwd();
|
|
1365
|
+
}
|
|
1366
|
+
return "/";
|
|
1367
|
+
}
|
|
1368
|
+
function findLastSeparator(path) {
|
|
1369
|
+
return Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
1370
|
+
}
|
|
1371
|
+
function createPathOps(isWin) {
|
|
1372
|
+
return {
|
|
1373
|
+
sep: getSeparator(isWin),
|
|
1374
|
+
delimiter: isWin ? ";" : ":",
|
|
1375
|
+
normalize: (path) => normalizePath2(path, isWin),
|
|
1376
|
+
join: (...paths) => joinPaths(paths, isWin),
|
|
1377
|
+
resolve: (...paths) => resolvePaths(paths, isWin),
|
|
1378
|
+
isAbsolute: (path) => isWin ? isAbsoluteWin(path) : isAbsolutePosix(path),
|
|
1379
|
+
relative: (from, to) => relativePath(from, to, isWin),
|
|
1380
|
+
dirname: (path) => getDirname(path, isWin),
|
|
1381
|
+
basename: (path, ext) => getBasename(path, ext, isWin),
|
|
1382
|
+
extname: (path) => getExtname(path),
|
|
1383
|
+
parse: (path) => parsePath(path, isWin),
|
|
1384
|
+
format: (pathObject) => formatPath(pathObject, isWin)
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
function isAbsolutePosix(path) {
|
|
1388
|
+
return path.length > 0 && path[0] === "/";
|
|
1389
|
+
}
|
|
1390
|
+
function isAbsoluteWin(path) {
|
|
1391
|
+
const len = path.length;
|
|
1392
|
+
if (len === 0) return false;
|
|
1393
|
+
const code = path.charCodeAt(0);
|
|
1394
|
+
if (code === 47 || code === 92) {
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
if (code >= 65 && code <= 90 || code >= 97 && code <= 122) {
|
|
1398
|
+
if (len > 2 && path.charCodeAt(1) === 58) {
|
|
1399
|
+
const code2 = path.charCodeAt(2);
|
|
1400
|
+
if (code2 === 47 || code2 === 92) {
|
|
1401
|
+
return true;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return false;
|
|
1406
|
+
}
|
|
1407
|
+
var isWindows = (() => {
|
|
1408
|
+
if (isNode) {
|
|
1409
|
+
return process.platform === "win32";
|
|
1410
|
+
} else if (isDeno) {
|
|
1411
|
+
return Deno.build.os === "windows";
|
|
1412
|
+
}
|
|
1413
|
+
return typeof process !== "undefined" && process.platform === "win32";
|
|
1414
|
+
})();
|
|
1415
|
+
var sep = isWindows ? "\\" : "/";
|
|
1416
|
+
var posix = createPathOps(false);
|
|
1417
|
+
var win32 = createPathOps(true);
|
|
1418
|
+
function normalizePath2(path, isWin) {
|
|
1419
|
+
if (path.length === 0) return ".";
|
|
1420
|
+
const separator = getSeparator(isWin);
|
|
1421
|
+
const isAbsolute = isWin ? isAbsoluteWin(path) : isAbsolutePosix(path);
|
|
1422
|
+
const trailingSeparator = path[path.length - 1] === separator || isWin && path[path.length - 1] === "/";
|
|
1423
|
+
let normalized = path.replace(isWin ? /[\/\\]+/g : /\/+/g, separator);
|
|
1424
|
+
const parts = normalized.split(separator);
|
|
1425
|
+
const result = [];
|
|
1426
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1427
|
+
const part = parts[i];
|
|
1428
|
+
if (part === "" || part === ".") {
|
|
1429
|
+
if (i === 0 && isAbsolute) result.push("");
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
if (part === "..") {
|
|
1433
|
+
if (result.length > 0 && result[result.length - 1] !== "..") {
|
|
1434
|
+
if (!(result.length === 1 && result[0] === "")) {
|
|
1435
|
+
result.pop();
|
|
1436
|
+
}
|
|
1437
|
+
} else if (!isAbsolute) {
|
|
1438
|
+
result.push("..");
|
|
1439
|
+
}
|
|
1440
|
+
} else {
|
|
1441
|
+
result.push(part);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
let final = result.join(separator);
|
|
1445
|
+
if (final.length === 0) {
|
|
1446
|
+
return isAbsolute ? separator : ".";
|
|
1447
|
+
}
|
|
1448
|
+
if (trailingSeparator && final[final.length - 1] !== separator) {
|
|
1449
|
+
final += separator;
|
|
1450
|
+
}
|
|
1451
|
+
return final;
|
|
1452
|
+
}
|
|
1453
|
+
function joinPaths(paths, isWin) {
|
|
1454
|
+
if (paths.length === 0) return ".";
|
|
1455
|
+
const separator = getSeparator(isWin);
|
|
1456
|
+
let joined = "";
|
|
1457
|
+
for (let i = 0; i < paths.length; i++) {
|
|
1458
|
+
const path = paths[i];
|
|
1459
|
+
if (path && path.length > 0) {
|
|
1460
|
+
if (joined.length === 0) {
|
|
1461
|
+
joined = path;
|
|
1462
|
+
} else {
|
|
1463
|
+
joined += separator + path;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
if (joined.length === 0) return ".";
|
|
1468
|
+
return normalizePath2(joined, isWin);
|
|
1469
|
+
}
|
|
1470
|
+
function resolvePaths(paths, isWin) {
|
|
1471
|
+
const separator = getSeparator(isWin);
|
|
1472
|
+
let resolved = "";
|
|
1473
|
+
let isAbsolute = false;
|
|
1474
|
+
for (let i = paths.length - 1; i >= 0 && !isAbsolute; i--) {
|
|
1475
|
+
const path = paths[i];
|
|
1476
|
+
if (path && path.length > 0) {
|
|
1477
|
+
resolved = path + (resolved.length > 0 ? separator + resolved : "");
|
|
1478
|
+
isAbsolute = isWin ? isAbsoluteWin(resolved) : isAbsolutePosix(resolved);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
if (!isAbsolute) {
|
|
1482
|
+
const cwd = getCwd();
|
|
1483
|
+
resolved = cwd + (resolved.length > 0 ? separator + resolved : "");
|
|
1484
|
+
}
|
|
1485
|
+
return normalizePath2(resolved, isWin);
|
|
1486
|
+
}
|
|
1487
|
+
function relativePath(from, to, isWin) {
|
|
1488
|
+
from = resolvePaths([from], isWin);
|
|
1489
|
+
to = resolvePaths([to], isWin);
|
|
1490
|
+
if (from === to) return "";
|
|
1491
|
+
const separator = getSeparator(isWin);
|
|
1492
|
+
const fromParts = from.split(separator).filter((p) => p.length > 0);
|
|
1493
|
+
const toParts = to.split(separator).filter((p) => p.length > 0);
|
|
1494
|
+
let commonLength = 0;
|
|
1495
|
+
const minLength = Math.min(fromParts.length, toParts.length);
|
|
1496
|
+
for (let i = 0; i < minLength; i++) {
|
|
1497
|
+
if (fromParts[i] === toParts[i]) {
|
|
1498
|
+
commonLength++;
|
|
1499
|
+
} else {
|
|
1500
|
+
break;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
const upCount = fromParts.length - commonLength;
|
|
1504
|
+
const result = [];
|
|
1505
|
+
for (let i = 0; i < upCount; i++) {
|
|
1506
|
+
result.push("..");
|
|
1507
|
+
}
|
|
1508
|
+
for (let i = commonLength; i < toParts.length; i++) {
|
|
1509
|
+
result.push(toParts[i]);
|
|
1510
|
+
}
|
|
1511
|
+
return result.join(separator) || ".";
|
|
1512
|
+
}
|
|
1513
|
+
function getDirname(path, isWin) {
|
|
1514
|
+
if (path.length === 0) return ".";
|
|
1515
|
+
const separator = getSeparator(isWin);
|
|
1516
|
+
const normalized = normalizePath2(path, isWin);
|
|
1517
|
+
const lastSepIndex = normalized.lastIndexOf(separator);
|
|
1518
|
+
if (lastSepIndex === -1) return ".";
|
|
1519
|
+
if (lastSepIndex === 0) return separator;
|
|
1520
|
+
return normalized.slice(0, lastSepIndex);
|
|
1521
|
+
}
|
|
1522
|
+
function getBasename(path, ext, isWin) {
|
|
1523
|
+
if (path.length === 0) return "";
|
|
1524
|
+
const lastSepIndex = isWin ? findLastSeparator(path) : path.lastIndexOf("/");
|
|
1525
|
+
let base = lastSepIndex === -1 ? path : path.slice(lastSepIndex + 1);
|
|
1526
|
+
if (ext && base.endsWith(ext)) {
|
|
1527
|
+
base = base.slice(0, base.length - ext.length);
|
|
1528
|
+
}
|
|
1529
|
+
return base;
|
|
1530
|
+
}
|
|
1531
|
+
function getExtname(path) {
|
|
1532
|
+
const lastDotIndex = path.lastIndexOf(".");
|
|
1533
|
+
const lastSepIndex = findLastSeparator(path);
|
|
1534
|
+
if (lastDotIndex === -1 || lastDotIndex < lastSepIndex || lastDotIndex === path.length - 1) {
|
|
1535
|
+
return "";
|
|
1536
|
+
}
|
|
1537
|
+
return path.slice(lastDotIndex);
|
|
1538
|
+
}
|
|
1539
|
+
function parsePath(path, isWin) {
|
|
1540
|
+
let root = "";
|
|
1541
|
+
if (isWin) {
|
|
1542
|
+
if (path.length >= 2 && path[1] === ":") {
|
|
1543
|
+
root = path.slice(0, 2);
|
|
1544
|
+
if (path.length > 2 && (path[2] === "\\" || path[2] === "/")) {
|
|
1545
|
+
root += "\\";
|
|
1546
|
+
}
|
|
1547
|
+
} else if (path[0] === "\\" || path[0] === "/") {
|
|
1548
|
+
root = "\\";
|
|
1549
|
+
}
|
|
1550
|
+
} else {
|
|
1551
|
+
if (path[0] === "/") {
|
|
1552
|
+
root = "/";
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
const dir = getDirname(path, isWin);
|
|
1556
|
+
const base = getBasename(path, void 0, isWin);
|
|
1557
|
+
const ext = getExtname(path);
|
|
1558
|
+
const name = ext ? base.slice(0, base.length - ext.length) : base;
|
|
1559
|
+
return { root, dir, base, ext, name };
|
|
1560
|
+
}
|
|
1561
|
+
function formatPath(pathObject, isWin) {
|
|
1562
|
+
const separator = getSeparator(isWin);
|
|
1563
|
+
const dir = pathObject.dir || pathObject.root || "";
|
|
1564
|
+
const base = pathObject.base || (pathObject.name || "") + (pathObject.ext || "");
|
|
1565
|
+
if (!dir) return base;
|
|
1566
|
+
if (dir === pathObject.root) return dir + base;
|
|
1567
|
+
return dir + separator + base;
|
|
1568
|
+
}
|
|
1569
|
+
function normalize(path) {
|
|
1570
|
+
return normalizePath2(path, isWindows);
|
|
1571
|
+
}
|
|
1572
|
+
function join(...paths) {
|
|
1573
|
+
return joinPaths(paths, isWindows);
|
|
1574
|
+
}
|
|
1575
|
+
function resolve(...paths) {
|
|
1576
|
+
return resolvePaths(paths, isWindows);
|
|
1577
|
+
}
|
|
1578
|
+
function relative(from, to) {
|
|
1579
|
+
return relativePath(from, to, isWindows);
|
|
1580
|
+
}
|
|
1581
|
+
function extname(path) {
|
|
1582
|
+
return getExtname(path);
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
// src/mime-types.ts
|
|
1586
|
+
init_runtime();
|
|
1587
|
+
var MIME_TYPES = {
|
|
1588
|
+
// Text
|
|
1589
|
+
"txt": "text/plain",
|
|
1590
|
+
"html": "text/html",
|
|
1591
|
+
"htm": "text/html",
|
|
1592
|
+
"css": "text/css",
|
|
1593
|
+
"js": "text/javascript",
|
|
1594
|
+
"mjs": "text/javascript",
|
|
1595
|
+
"json": "application/json",
|
|
1596
|
+
"xml": "application/xml",
|
|
1597
|
+
"csv": "text/csv",
|
|
1598
|
+
"md": "text/markdown",
|
|
1599
|
+
"markdown": "text/x-markdown",
|
|
1600
|
+
// Images
|
|
1601
|
+
"png": "image/png",
|
|
1602
|
+
"jpg": "image/jpeg",
|
|
1603
|
+
"jpeg": "image/jpeg",
|
|
1604
|
+
"gif": "image/gif",
|
|
1605
|
+
"svg": "image/svg+xml",
|
|
1606
|
+
"webp": "image/webp",
|
|
1607
|
+
"ico": "image/x-icon",
|
|
1608
|
+
"bmp": "image/bmp",
|
|
1609
|
+
"tiff": "image/tiff",
|
|
1610
|
+
"tif": "image/tiff",
|
|
1611
|
+
// Audio
|
|
1612
|
+
"mp3": "audio/mpeg",
|
|
1613
|
+
"wav": "audio/wav",
|
|
1614
|
+
"ogg": "audio/ogg",
|
|
1615
|
+
"aac": "audio/aac",
|
|
1616
|
+
"m4a": "audio/mp4",
|
|
1617
|
+
"flac": "audio/flac",
|
|
1618
|
+
// Video
|
|
1619
|
+
"mp4": "video/mp4",
|
|
1620
|
+
"webm": "video/webm",
|
|
1621
|
+
"avi": "video/x-msvideo",
|
|
1622
|
+
"mov": "video/quicktime",
|
|
1623
|
+
"mkv": "video/x-matroska",
|
|
1624
|
+
"flv": "video/x-flv",
|
|
1625
|
+
// Application
|
|
1626
|
+
"pdf": "application/pdf",
|
|
1627
|
+
"zip": "application/zip",
|
|
1628
|
+
"gz": "application/gzip",
|
|
1629
|
+
"tar": "application/x-tar",
|
|
1630
|
+
"rar": "application/x-rar-compressed",
|
|
1631
|
+
"7z": "application/x-7z-compressed",
|
|
1632
|
+
// Documents
|
|
1633
|
+
"doc": "application/msword",
|
|
1634
|
+
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
1635
|
+
"xls": "application/vnd.ms-excel",
|
|
1636
|
+
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
1637
|
+
"ppt": "application/vnd.ms-powerpoint",
|
|
1638
|
+
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
1639
|
+
// Fonts
|
|
1640
|
+
"woff": "font/woff",
|
|
1641
|
+
"woff2": "font/woff2",
|
|
1642
|
+
"ttf": "font/ttf",
|
|
1643
|
+
"otf": "font/otf",
|
|
1644
|
+
"eot": "application/vnd.ms-fontobject",
|
|
1645
|
+
// Web
|
|
1646
|
+
"wasm": "application/wasm",
|
|
1647
|
+
"manifest": "application/manifest+json",
|
|
1648
|
+
// Binary
|
|
1649
|
+
"bin": "application/octet-stream",
|
|
1650
|
+
"exe": "application/x-msdownload",
|
|
1651
|
+
"dll": "application/x-msdownload",
|
|
1652
|
+
// TypeScript/Modern JS
|
|
1653
|
+
"ts": "text/typescript",
|
|
1654
|
+
"tsx": "text/tsx",
|
|
1655
|
+
"jsx": "text/jsx"
|
|
1656
|
+
};
|
|
1657
|
+
var TYPE_TO_EXTENSIONS = {};
|
|
1658
|
+
for (const ext in MIME_TYPES) {
|
|
1659
|
+
const type = MIME_TYPES[ext];
|
|
1660
|
+
if (!TYPE_TO_EXTENSIONS[type]) {
|
|
1661
|
+
TYPE_TO_EXTENSIONS[type] = [];
|
|
1662
|
+
}
|
|
1663
|
+
TYPE_TO_EXTENSIONS[type].push(ext);
|
|
1664
|
+
}
|
|
1665
|
+
function getExtension(path) {
|
|
1666
|
+
const match = /\.([^./\\]+)$/.exec(path);
|
|
1667
|
+
return match ? match[1].toLowerCase() : "";
|
|
1668
|
+
}
|
|
1669
|
+
function lookup(path) {
|
|
1670
|
+
const ext = getExtension(path) || path.toLowerCase();
|
|
1671
|
+
return MIME_TYPES[ext] || false;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
// src/server.ts
|
|
1675
|
+
init_runtime();
|
|
1676
|
+
|
|
1677
|
+
// src/dom.ts
|
|
1678
|
+
function resolveElement(rootElement) {
|
|
1679
|
+
return typeof rootElement === "string" ? document.getElementById(rootElement.replace("#", "")) : rootElement;
|
|
1680
|
+
}
|
|
1681
|
+
function ensureElement(el, rootElement) {
|
|
1682
|
+
if (!el) {
|
|
1683
|
+
throw new Error(`Element not found: ${rootElement}`);
|
|
1684
|
+
}
|
|
1685
|
+
return el;
|
|
1686
|
+
}
|
|
1687
|
+
function shouldSkipChild(child) {
|
|
1688
|
+
return child == null || child === false;
|
|
1689
|
+
}
|
|
1690
|
+
function isPrimitiveJson(json2) {
|
|
1691
|
+
return json2 == null || typeof json2 === "boolean" || typeof json2 === "string" || typeof json2 === "number";
|
|
1692
|
+
}
|
|
1693
|
+
var DomNode = class {
|
|
1694
|
+
constructor() {
|
|
1695
|
+
this.elementCache = /* @__PURE__ */ new WeakMap();
|
|
1696
|
+
this.reactiveNodes = /* @__PURE__ */ new Map();
|
|
1697
|
+
}
|
|
1698
|
+
createElement(tagName, props = {}, children = []) {
|
|
1699
|
+
return { tagName, props, children };
|
|
1700
|
+
}
|
|
1701
|
+
renderToDOM(vNode, parent) {
|
|
1702
|
+
if (vNode == null || vNode === false) return;
|
|
1703
|
+
if (typeof vNode !== "object") {
|
|
1704
|
+
parent.appendChild(document.createTextNode(String(vNode)));
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
const { tagName, props, children } = vNode;
|
|
1708
|
+
const isSVG = tagName === "svg" || tagName[0] === "s" && tagName[1] === "v" && tagName[2] === "g" || parent.namespaceURI === "http://www.w3.org/2000/svg";
|
|
1709
|
+
const el = isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tagName.replace("svg", "").toLowerCase() || tagName) : document.createElement(tagName);
|
|
1710
|
+
for (const key in props) {
|
|
1711
|
+
const value = props[key];
|
|
1712
|
+
if (value == null || value === false) continue;
|
|
1713
|
+
const c = key.charCodeAt(0);
|
|
1714
|
+
if (c === 99 && (key.length < 6 || key[5] === "N")) {
|
|
1715
|
+
const classValue = Array.isArray(value) ? value.join(" ") : value;
|
|
1716
|
+
isSVG ? el.setAttribute("class", classValue) : el.className = classValue;
|
|
1717
|
+
} else if (c === 115 && key.length === 5) {
|
|
1718
|
+
if (typeof value === "string") {
|
|
1719
|
+
el.style.cssText = value;
|
|
1720
|
+
} else {
|
|
1721
|
+
const s = el.style;
|
|
1722
|
+
for (const k in value) s[k] = value[k];
|
|
1723
|
+
}
|
|
1724
|
+
} else if (c === 111 && key.charCodeAt(1) === 110) {
|
|
1725
|
+
el[key.toLowerCase()] = value;
|
|
1726
|
+
} else if (c === 100 && key.length > 20) {
|
|
1727
|
+
el.innerHTML = value.__html;
|
|
1728
|
+
} else if (c === 114 && key.length === 3) {
|
|
1729
|
+
setTimeout(() => {
|
|
1730
|
+
typeof value === "function" ? value(el) : value.current = el;
|
|
1731
|
+
}, 0);
|
|
1732
|
+
} else {
|
|
1733
|
+
el.setAttribute(key, value === true ? "" : String(value));
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
const len = children.length;
|
|
1737
|
+
if (!len) {
|
|
1738
|
+
parent.appendChild(el);
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
const renderChildren = (target) => {
|
|
1742
|
+
for (let i = 0; i < len; i++) {
|
|
1743
|
+
const child = children[i];
|
|
1744
|
+
if (shouldSkipChild(child)) continue;
|
|
1745
|
+
if (Array.isArray(child)) {
|
|
1746
|
+
for (let j = 0, cLen = child.length; j < cLen; j++) {
|
|
1747
|
+
const c = child[j];
|
|
1748
|
+
!shouldSkipChild(c) && this.renderToDOM(c, target);
|
|
1749
|
+
}
|
|
1750
|
+
} else {
|
|
1751
|
+
this.renderToDOM(child, target);
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
if (len > 30) {
|
|
1756
|
+
const fragment = document.createDocumentFragment();
|
|
1757
|
+
renderChildren(fragment);
|
|
1758
|
+
el.appendChild(fragment);
|
|
1759
|
+
} else {
|
|
1760
|
+
renderChildren(el);
|
|
1761
|
+
}
|
|
1762
|
+
parent.appendChild(el);
|
|
1763
|
+
}
|
|
1764
|
+
render(rootElement, vNode) {
|
|
1765
|
+
const el = ensureElement(resolveElement(rootElement), rootElement);
|
|
1766
|
+
el.innerHTML = "";
|
|
1767
|
+
if (vNode.children && vNode.children.length > 500) {
|
|
1768
|
+
const fragment = document.createDocumentFragment();
|
|
1769
|
+
this.renderToDOM(vNode, fragment);
|
|
1770
|
+
el.appendChild(fragment);
|
|
1771
|
+
} else {
|
|
1772
|
+
this.renderToDOM(vNode, el);
|
|
1773
|
+
}
|
|
1774
|
+
return el;
|
|
1775
|
+
}
|
|
1776
|
+
batchRender(rootElement, vNodes) {
|
|
1777
|
+
const el = ensureElement(resolveElement(rootElement), rootElement);
|
|
1778
|
+
const len = vNodes.length;
|
|
1779
|
+
if (len > 3e3) {
|
|
1780
|
+
const fragment = document.createDocumentFragment();
|
|
1781
|
+
let processed = 0;
|
|
1782
|
+
const chunkSize = 1500;
|
|
1783
|
+
const processChunk = () => {
|
|
1784
|
+
const end = Math.min(processed + chunkSize, len);
|
|
1785
|
+
for (let i = processed; i < end; i++) {
|
|
1786
|
+
this.renderToDOM(vNodes[i], fragment);
|
|
1787
|
+
}
|
|
1788
|
+
processed = end;
|
|
1789
|
+
if (processed >= len) {
|
|
1790
|
+
el.appendChild(fragment);
|
|
1791
|
+
} else {
|
|
1792
|
+
requestAnimationFrame(processChunk);
|
|
1793
|
+
}
|
|
1794
|
+
};
|
|
1795
|
+
processChunk();
|
|
1796
|
+
} else {
|
|
1797
|
+
const fragment = document.createDocumentFragment();
|
|
1798
|
+
for (let i = 0; i < len; i++) {
|
|
1799
|
+
this.renderToDOM(vNodes[i], fragment);
|
|
1800
|
+
}
|
|
1801
|
+
el.appendChild(fragment);
|
|
1802
|
+
}
|
|
1803
|
+
return el;
|
|
1804
|
+
}
|
|
1805
|
+
renderChunked(rootElement, vNodes, chunkSize = 5e3, onProgress) {
|
|
1806
|
+
const el = ensureElement(resolveElement(rootElement), rootElement);
|
|
1807
|
+
const len = vNodes.length;
|
|
1808
|
+
let index = 0;
|
|
1809
|
+
const renderChunk = () => {
|
|
1810
|
+
const end = Math.min(index + chunkSize, len);
|
|
1811
|
+
const fragment = document.createDocumentFragment();
|
|
1812
|
+
for (let i = index; i < end; i++) {
|
|
1813
|
+
this.renderToDOM(vNodes[i], fragment);
|
|
1814
|
+
}
|
|
1815
|
+
el.appendChild(fragment);
|
|
1816
|
+
index = end;
|
|
1817
|
+
if (onProgress) onProgress(index, len);
|
|
1818
|
+
if (index < len) {
|
|
1819
|
+
requestAnimationFrame(renderChunk);
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
requestAnimationFrame(renderChunk);
|
|
1823
|
+
return el;
|
|
1824
|
+
}
|
|
1825
|
+
renderToHead(...vNodes) {
|
|
1826
|
+
const head = document.head;
|
|
1827
|
+
if (head) {
|
|
1828
|
+
for (const vNode of vNodes.flat()) {
|
|
1829
|
+
vNode && this.renderToDOM(vNode, head);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
return head;
|
|
1833
|
+
}
|
|
1834
|
+
addStyle(cssText) {
|
|
1835
|
+
const el = document.createElement("style");
|
|
1836
|
+
el.textContent = cssText;
|
|
1837
|
+
return document.head.appendChild(el);
|
|
1838
|
+
}
|
|
1839
|
+
addMeta(attrs) {
|
|
1840
|
+
const el = document.createElement("meta");
|
|
1841
|
+
for (const k in attrs) el.setAttribute(k, attrs[k]);
|
|
1842
|
+
return document.head.appendChild(el);
|
|
1843
|
+
}
|
|
1844
|
+
addLink(attrs) {
|
|
1845
|
+
const el = document.createElement("link");
|
|
1846
|
+
for (const k in attrs) el.setAttribute(k, attrs[k]);
|
|
1847
|
+
return document.head.appendChild(el);
|
|
1848
|
+
}
|
|
1849
|
+
setTitle(text2) {
|
|
1850
|
+
return document.title = text2;
|
|
1851
|
+
}
|
|
1852
|
+
// Reactive State Management
|
|
1853
|
+
createState(initialValue, options = {}) {
|
|
1854
|
+
let value = initialValue;
|
|
1855
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1856
|
+
let updateTimer = null;
|
|
1857
|
+
const { throttle = 0, deep = false } = options;
|
|
1858
|
+
const notify = () => listeners.forEach((fn) => fn(value));
|
|
1859
|
+
const scheduleUpdate = () => {
|
|
1860
|
+
if (throttle > 0) {
|
|
1861
|
+
if (!updateTimer) {
|
|
1862
|
+
updateTimer = setTimeout(() => {
|
|
1863
|
+
updateTimer = null;
|
|
1864
|
+
notify();
|
|
1865
|
+
}, throttle);
|
|
1866
|
+
}
|
|
1867
|
+
} else {
|
|
1868
|
+
notify();
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
return {
|
|
1872
|
+
get value() {
|
|
1873
|
+
return value;
|
|
1874
|
+
},
|
|
1875
|
+
set value(newValue) {
|
|
1876
|
+
const changed = deep ? JSON.stringify(value) !== JSON.stringify(newValue) : value !== newValue;
|
|
1877
|
+
if (changed) {
|
|
1878
|
+
value = newValue;
|
|
1879
|
+
scheduleUpdate();
|
|
1880
|
+
}
|
|
1881
|
+
},
|
|
1882
|
+
subscribe(fn) {
|
|
1883
|
+
listeners.add(fn);
|
|
1884
|
+
return () => listeners.delete(fn);
|
|
1885
|
+
},
|
|
1886
|
+
destroy() {
|
|
1887
|
+
listeners.clear();
|
|
1888
|
+
updateTimer && clearTimeout(updateTimer);
|
|
1889
|
+
}
|
|
1890
|
+
};
|
|
1891
|
+
}
|
|
1892
|
+
computed(states, computeFn) {
|
|
1893
|
+
const values = states.map((s) => s.value);
|
|
1894
|
+
const result = this.createState(computeFn(...values));
|
|
1895
|
+
states.forEach((state, index) => {
|
|
1896
|
+
state.subscribe((newValue) => {
|
|
1897
|
+
values[index] = newValue;
|
|
1898
|
+
result.value = computeFn(...values);
|
|
1899
|
+
});
|
|
1900
|
+
});
|
|
1901
|
+
return result;
|
|
1902
|
+
}
|
|
1903
|
+
effect(stateFn) {
|
|
1904
|
+
stateFn();
|
|
1905
|
+
}
|
|
1906
|
+
// Virtual scrolling helper for large lists
|
|
1907
|
+
createVirtualList(container, items, renderItem, itemHeight = 50, bufferSize = 5) {
|
|
1908
|
+
const viewportHeight = container.clientHeight;
|
|
1909
|
+
const totalHeight = items.length * itemHeight;
|
|
1910
|
+
let scrollTop = 0;
|
|
1911
|
+
const getVisibleRange = () => {
|
|
1912
|
+
const start = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferSize);
|
|
1913
|
+
const end = Math.min(items.length, Math.ceil((scrollTop + viewportHeight) / itemHeight) + bufferSize);
|
|
1914
|
+
return { start, end };
|
|
1915
|
+
};
|
|
1916
|
+
const render2 = () => {
|
|
1917
|
+
const { start, end } = getVisibleRange();
|
|
1918
|
+
const wrapper = document.createElement("div");
|
|
1919
|
+
wrapper.style.cssText = `height:${totalHeight}px;position:relative`;
|
|
1920
|
+
for (let i = start; i < end; i++) {
|
|
1921
|
+
const itemEl = document.createElement("div");
|
|
1922
|
+
itemEl.style.cssText = `position:absolute;top:${i * itemHeight}px;height:${itemHeight}px;width:100%`;
|
|
1923
|
+
this.renderToDOM(renderItem(items[i], i), itemEl);
|
|
1924
|
+
wrapper.appendChild(itemEl);
|
|
1925
|
+
}
|
|
1926
|
+
container.innerHTML = "";
|
|
1927
|
+
container.appendChild(wrapper);
|
|
1928
|
+
};
|
|
1929
|
+
const scrollHandler = () => {
|
|
1930
|
+
scrollTop = container.scrollTop;
|
|
1931
|
+
requestAnimationFrame(render2);
|
|
1932
|
+
};
|
|
1933
|
+
container.addEventListener("scroll", scrollHandler);
|
|
1934
|
+
render2();
|
|
1935
|
+
return {
|
|
1936
|
+
render: render2,
|
|
1937
|
+
destroy: () => {
|
|
1938
|
+
container.removeEventListener("scroll", scrollHandler);
|
|
1939
|
+
container.innerHTML = "";
|
|
1940
|
+
}
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
// Lazy load components
|
|
1944
|
+
lazy(loadFn) {
|
|
1945
|
+
let component = null;
|
|
1946
|
+
let loading = false;
|
|
1947
|
+
return async (...args) => {
|
|
1948
|
+
if (!component && !loading) {
|
|
1949
|
+
loading = true;
|
|
1950
|
+
component = await loadFn();
|
|
1951
|
+
loading = false;
|
|
1952
|
+
}
|
|
1953
|
+
return component ? component(...args) : { tagName: "div", props: { class: "loading" }, children: ["Loading..."] };
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
// Memory management - cleanup unused elements
|
|
1957
|
+
cleanupUnusedElements(root) {
|
|
1958
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
1959
|
+
const toRemove = [];
|
|
1960
|
+
while (walker.nextNode()) {
|
|
1961
|
+
const node = walker.currentNode;
|
|
1962
|
+
if (node.id && node.id.startsWith("r") && !this.elementCache.has(node)) {
|
|
1963
|
+
toRemove.push(node);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
toRemove.forEach((el) => el.remove());
|
|
1967
|
+
return toRemove.length;
|
|
1968
|
+
}
|
|
1969
|
+
// Server-Side Rendering - convert VNode to HTML string
|
|
1970
|
+
renderToString(vNode, options = {}) {
|
|
1971
|
+
const { pretty = false, indent = 0 } = options;
|
|
1972
|
+
const indentStr = pretty ? " ".repeat(indent) : "";
|
|
1973
|
+
const newLine = pretty ? "\n" : "";
|
|
1974
|
+
let resolvedVNode = this.resolveStateValue(vNode);
|
|
1975
|
+
resolvedVNode = this.unwrapReactive(resolvedVNode);
|
|
1976
|
+
if (Array.isArray(resolvedVNode)) {
|
|
1977
|
+
return resolvedVNode.map((child) => this.renderToString(child, options)).join("");
|
|
1978
|
+
}
|
|
1979
|
+
if (typeof resolvedVNode !== "object" || resolvedVNode === null) {
|
|
1980
|
+
if (resolvedVNode === null || resolvedVNode === void 0 || resolvedVNode === false) {
|
|
1981
|
+
return "";
|
|
1982
|
+
}
|
|
1983
|
+
return this.escapeHtml(String(resolvedVNode));
|
|
1984
|
+
}
|
|
1985
|
+
const { tagName, props, children } = resolvedVNode;
|
|
1986
|
+
const isSelfClosing = this.isSelfClosingTag(tagName);
|
|
1987
|
+
let html2 = `${indentStr}<${tagName}`;
|
|
1988
|
+
const attrs = this.propsToAttributes(props);
|
|
1989
|
+
if (attrs) {
|
|
1990
|
+
html2 += ` ${attrs}`;
|
|
1991
|
+
}
|
|
1992
|
+
if (isSelfClosing) {
|
|
1993
|
+
html2 += ` />${newLine}`;
|
|
1994
|
+
return html2;
|
|
1995
|
+
}
|
|
1996
|
+
html2 += ">";
|
|
1997
|
+
if (props.dangerouslySetInnerHTML) {
|
|
1998
|
+
html2 += props.dangerouslySetInnerHTML.__html;
|
|
1999
|
+
html2 += `</${tagName}>${newLine}`;
|
|
2000
|
+
return html2;
|
|
2001
|
+
}
|
|
2002
|
+
if (children && children.length > 0) {
|
|
2003
|
+
const resolvedChildren = children.map((c) => {
|
|
2004
|
+
const resolved = this.resolveStateValue(c);
|
|
2005
|
+
return this.unwrapReactive(resolved);
|
|
2006
|
+
});
|
|
2007
|
+
const hasComplexChildren = resolvedChildren.some(
|
|
2008
|
+
(c) => typeof c === "object" && c !== null && !Array.isArray(c) && "tagName" in c
|
|
2009
|
+
);
|
|
2010
|
+
if (pretty && hasComplexChildren) {
|
|
2011
|
+
html2 += newLine;
|
|
2012
|
+
for (const child of resolvedChildren) {
|
|
2013
|
+
if (shouldSkipChild(child)) continue;
|
|
2014
|
+
if (Array.isArray(child)) {
|
|
2015
|
+
for (const c of child) {
|
|
2016
|
+
if (!shouldSkipChild(c)) {
|
|
2017
|
+
html2 += this.renderToString(c, { pretty, indent: indent + 1 });
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
} else {
|
|
2021
|
+
html2 += this.renderToString(child, { pretty, indent: indent + 1 });
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
html2 += indentStr;
|
|
2025
|
+
} else {
|
|
2026
|
+
for (const child of resolvedChildren) {
|
|
2027
|
+
if (shouldSkipChild(child)) continue;
|
|
2028
|
+
if (Array.isArray(child)) {
|
|
2029
|
+
for (const c of child) {
|
|
2030
|
+
if (!shouldSkipChild(c)) {
|
|
2031
|
+
html2 += this.renderToString(c, { pretty: false, indent: 0 });
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
} else {
|
|
2035
|
+
html2 += this.renderToString(child, { pretty: false, indent: 0 });
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
html2 += `</${tagName}>${newLine}`;
|
|
2041
|
+
return html2;
|
|
2042
|
+
}
|
|
2043
|
+
resolveStateValue(value) {
|
|
2044
|
+
if (value && typeof value === "object" && "value" in value && "subscribe" in value) {
|
|
2045
|
+
return value.value;
|
|
2046
|
+
}
|
|
2047
|
+
return value;
|
|
2048
|
+
}
|
|
2049
|
+
isReactiveWrapper(vNode) {
|
|
2050
|
+
if (!vNode || typeof vNode !== "object" || !vNode.tagName) {
|
|
2051
|
+
return false;
|
|
2052
|
+
}
|
|
2053
|
+
return vNode.tagName === "span" && vNode.props?.id && typeof vNode.props.id === "string" && vNode.props.id.match(/^r[a-z0-9]{9}$/);
|
|
2054
|
+
}
|
|
2055
|
+
unwrapReactive(vNode) {
|
|
2056
|
+
if (!this.isReactiveWrapper(vNode)) {
|
|
2057
|
+
return vNode;
|
|
2058
|
+
}
|
|
2059
|
+
const children = vNode.children;
|
|
2060
|
+
if (!children || children.length === 0) {
|
|
2061
|
+
return "";
|
|
2062
|
+
}
|
|
2063
|
+
if (children.length === 1) {
|
|
2064
|
+
const child = children[0];
|
|
2065
|
+
if (child && typeof child === "object" && child.tagName === "span") {
|
|
2066
|
+
const props = child.props;
|
|
2067
|
+
const hasNoProps = !props || Object.keys(props).length === 0;
|
|
2068
|
+
const hasSingleStringChild = child.children && child.children.length === 1 && typeof child.children[0] === "string";
|
|
2069
|
+
if (hasNoProps && hasSingleStringChild) {
|
|
2070
|
+
return child.children[0];
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
return this.unwrapReactive(child);
|
|
2074
|
+
}
|
|
2075
|
+
return children.map((c) => this.unwrapReactive(c));
|
|
2076
|
+
}
|
|
2077
|
+
escapeHtml(text2) {
|
|
2078
|
+
const htmlEscapes = {
|
|
2079
|
+
"&": "&",
|
|
2080
|
+
"<": "<",
|
|
2081
|
+
">": ">",
|
|
2082
|
+
'"': """,
|
|
2083
|
+
"'": "'"
|
|
2084
|
+
};
|
|
2085
|
+
return text2.replace(/[&<>"']/g, (char) => htmlEscapes[char]);
|
|
2086
|
+
}
|
|
2087
|
+
isSelfClosingTag(tagName) {
|
|
2088
|
+
const selfClosingTags = /* @__PURE__ */ new Set([
|
|
2089
|
+
"area",
|
|
2090
|
+
"base",
|
|
2091
|
+
"br",
|
|
2092
|
+
"col",
|
|
2093
|
+
"embed",
|
|
2094
|
+
"hr",
|
|
2095
|
+
"img",
|
|
2096
|
+
"input",
|
|
2097
|
+
"link",
|
|
2098
|
+
"meta",
|
|
2099
|
+
"param",
|
|
2100
|
+
"source",
|
|
2101
|
+
"track",
|
|
2102
|
+
"wbr"
|
|
2103
|
+
]);
|
|
2104
|
+
return selfClosingTags.has(tagName.toLowerCase());
|
|
2105
|
+
}
|
|
2106
|
+
propsToAttributes(props) {
|
|
2107
|
+
const attrs = [];
|
|
2108
|
+
for (const key in props) {
|
|
2109
|
+
if (key === "children" || key === "dangerouslySetInnerHTML" || key === "ref") {
|
|
2110
|
+
continue;
|
|
2111
|
+
}
|
|
2112
|
+
let value = props[key];
|
|
2113
|
+
value = this.resolveStateValue(value);
|
|
2114
|
+
if (value == null || value === false) continue;
|
|
2115
|
+
if (key.startsWith("on") && typeof value === "function") {
|
|
2116
|
+
continue;
|
|
2117
|
+
}
|
|
2118
|
+
if (key === "className" || key === "class") {
|
|
2119
|
+
const className = Array.isArray(value) ? value.join(" ") : value;
|
|
2120
|
+
if (className) {
|
|
2121
|
+
attrs.push(`class="${this.escapeHtml(String(className))}"`);
|
|
2122
|
+
}
|
|
2123
|
+
continue;
|
|
2124
|
+
}
|
|
2125
|
+
if (key === "style") {
|
|
2126
|
+
const styleStr = this.styleToString(value);
|
|
2127
|
+
if (styleStr) {
|
|
2128
|
+
attrs.push(`style="${this.escapeHtml(styleStr)}"`);
|
|
2129
|
+
}
|
|
2130
|
+
continue;
|
|
2131
|
+
}
|
|
2132
|
+
if (value === true) {
|
|
2133
|
+
attrs.push(key);
|
|
2134
|
+
continue;
|
|
2135
|
+
}
|
|
2136
|
+
attrs.push(`${key}="${this.escapeHtml(String(value))}"`);
|
|
2137
|
+
}
|
|
2138
|
+
return attrs.join(" ");
|
|
2139
|
+
}
|
|
2140
|
+
styleToString(style) {
|
|
2141
|
+
if (typeof style === "string") {
|
|
2142
|
+
return style;
|
|
2143
|
+
}
|
|
2144
|
+
if (typeof style === "object" && style !== null) {
|
|
2145
|
+
const styles = [];
|
|
2146
|
+
for (const key in style) {
|
|
2147
|
+
const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
2148
|
+
styles.push(`${cssKey}:${style[key]}`);
|
|
2149
|
+
}
|
|
2150
|
+
return styles.join(";");
|
|
2151
|
+
}
|
|
2152
|
+
return "";
|
|
2153
|
+
}
|
|
2154
|
+
isState(value) {
|
|
2155
|
+
return value && typeof value === "object" && "value" in value && "subscribe" in value && typeof value.subscribe === "function";
|
|
2156
|
+
}
|
|
2157
|
+
createReactiveChild(state, renderFn) {
|
|
2158
|
+
const currentValue = renderFn(state.value);
|
|
2159
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
2160
|
+
const entry = { node: null, renderFn };
|
|
2161
|
+
this.reactiveNodes.set(state, entry);
|
|
2162
|
+
state.subscribe(() => {
|
|
2163
|
+
if (entry.node && entry.node.parentNode) {
|
|
2164
|
+
const newValue = renderFn(state.value);
|
|
2165
|
+
entry.node.textContent = String(newValue ?? "");
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
return currentValue;
|
|
2170
|
+
}
|
|
2171
|
+
jsonToVNode(json2) {
|
|
2172
|
+
if (this.isState(json2)) {
|
|
2173
|
+
return this.createReactiveChild(json2, (v) => v);
|
|
2174
|
+
}
|
|
2175
|
+
if (isPrimitiveJson(json2)) {
|
|
2176
|
+
return json2;
|
|
2177
|
+
}
|
|
2178
|
+
const { tag, attributes = {}, children } = json2;
|
|
2179
|
+
const props = {};
|
|
2180
|
+
for (const key in attributes) {
|
|
2181
|
+
const value = attributes[key];
|
|
2182
|
+
if (key === "class") {
|
|
2183
|
+
props.className = this.isState(value) ? value.value : value;
|
|
2184
|
+
} else {
|
|
2185
|
+
props[key] = this.isState(value) ? value.value : value;
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
const childrenArray = [];
|
|
2189
|
+
if (children != null) {
|
|
2190
|
+
if (Array.isArray(children)) {
|
|
2191
|
+
for (const child of children) {
|
|
2192
|
+
if (this.isState(child)) {
|
|
2193
|
+
childrenArray.push(this.createReactiveChild(child, (v) => v));
|
|
2194
|
+
} else {
|
|
2195
|
+
const converted = this.jsonToVNode(child);
|
|
2196
|
+
if (converted != null && converted !== false) {
|
|
2197
|
+
childrenArray.push(converted);
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
} else if (this.isState(children)) {
|
|
2202
|
+
childrenArray.push(this.createReactiveChild(children, (v) => v));
|
|
2203
|
+
} else if (typeof children === "object" && "tag" in children) {
|
|
2204
|
+
const converted = this.jsonToVNode(children);
|
|
2205
|
+
if (converted != null && converted !== false) {
|
|
2206
|
+
childrenArray.push(converted);
|
|
2207
|
+
}
|
|
2208
|
+
} else {
|
|
2209
|
+
childrenArray.push(children);
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
return { tagName: tag, props, children: childrenArray };
|
|
2213
|
+
}
|
|
2214
|
+
vNodeJsonToVNode(json2) {
|
|
2215
|
+
if (this.isState(json2)) {
|
|
2216
|
+
return this.createReactiveChild(json2, (v) => v);
|
|
2217
|
+
}
|
|
2218
|
+
if (isPrimitiveJson(json2)) {
|
|
2219
|
+
return json2;
|
|
2220
|
+
}
|
|
2221
|
+
const { tagName, props = {}, children = [] } = json2;
|
|
2222
|
+
const resolvedProps = {};
|
|
2223
|
+
for (const key in props) {
|
|
2224
|
+
const value = props[key];
|
|
2225
|
+
resolvedProps[key] = this.isState(value) ? value.value : value;
|
|
2226
|
+
}
|
|
2227
|
+
const childrenArray = [];
|
|
2228
|
+
for (const child of children) {
|
|
2229
|
+
if (this.isState(child)) {
|
|
2230
|
+
childrenArray.push(this.createReactiveChild(child, (v) => v));
|
|
2231
|
+
} else {
|
|
2232
|
+
const converted = this.vNodeJsonToVNode(child);
|
|
2233
|
+
if (converted != null && converted !== false) {
|
|
2234
|
+
childrenArray.push(converted);
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
return { tagName, props: resolvedProps, children: childrenArray };
|
|
2239
|
+
}
|
|
2240
|
+
renderJson(rootElement, json2) {
|
|
2241
|
+
const vNode = this.jsonToVNode(json2);
|
|
2242
|
+
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
2243
|
+
throw new Error("Invalid JSON structure");
|
|
2244
|
+
}
|
|
2245
|
+
return this.render(rootElement, vNode);
|
|
2246
|
+
}
|
|
2247
|
+
renderVNode(rootElement, json2) {
|
|
2248
|
+
const vNode = this.vNodeJsonToVNode(json2);
|
|
2249
|
+
if (!vNode || typeof vNode !== "object" || !("tagName" in vNode)) {
|
|
2250
|
+
throw new Error("Invalid VNode JSON structure");
|
|
2251
|
+
}
|
|
2252
|
+
return this.render(rootElement, vNode);
|
|
2253
|
+
}
|
|
2254
|
+
renderJsonToString(json2, options = {}) {
|
|
2255
|
+
const vNode = this.jsonToVNode(json2);
|
|
2256
|
+
return this.renderToString(vNode, options);
|
|
2257
|
+
}
|
|
2258
|
+
renderVNodeToString(json2, options = {}) {
|
|
2259
|
+
const vNode = this.vNodeJsonToVNode(json2);
|
|
2260
|
+
return this.renderToString(vNode, options);
|
|
2261
|
+
}
|
|
2262
|
+
// Generate complete HTML document as string (for SSR)
|
|
2263
|
+
renderToHTMLDocument(vNode, options = {}) {
|
|
2264
|
+
const { title = "", meta = [], links = [], scripts = [], styles = [], lang = "en", head = "", bodyAttrs = {}, pretty = false } = options;
|
|
2265
|
+
const nl = pretty ? "\n" : "";
|
|
2266
|
+
const indent = pretty ? " " : "";
|
|
2267
|
+
const indent2 = pretty ? " " : "";
|
|
2268
|
+
let html2 = `<!DOCTYPE html>${nl}<html lang="${lang}">${nl}${indent}<head>${nl}${indent2}<meta charset="UTF-8">${nl}${indent2}<meta name="viewport" content="width=device-width, initial-scale=1.0">${nl}`;
|
|
2269
|
+
if (title) html2 += `${indent2}<title>${this.escapeHtml(title)}</title>${nl}`;
|
|
2270
|
+
for (const m of meta) {
|
|
2271
|
+
html2 += `${indent2}<meta`;
|
|
2272
|
+
for (const k in m) html2 += ` ${k}="${this.escapeHtml(m[k])}"`;
|
|
2273
|
+
html2 += `>${nl}`;
|
|
2274
|
+
}
|
|
2275
|
+
for (const l of links) {
|
|
2276
|
+
html2 += `${indent2}<link`;
|
|
2277
|
+
for (const k in l) html2 += ` ${k}="${this.escapeHtml(l[k])}"`;
|
|
2278
|
+
html2 += `>${nl}`;
|
|
2279
|
+
}
|
|
2280
|
+
for (const s of styles) {
|
|
2281
|
+
if (s.href) {
|
|
2282
|
+
html2 += `${indent2}<link rel="stylesheet" href="${this.escapeHtml(s.href)}">${nl}`;
|
|
2283
|
+
} else if (s.content) {
|
|
2284
|
+
html2 += `${indent2}<style>${s.content}</style>${nl}`;
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
if (head) html2 += head + nl;
|
|
2288
|
+
html2 += `${indent}</head>${nl}${indent}<body`;
|
|
2289
|
+
for (const k in bodyAttrs) html2 += ` ${k}="${this.escapeHtml(bodyAttrs[k])}"`;
|
|
2290
|
+
html2 += `>${nl}`;
|
|
2291
|
+
html2 += this.renderToString(vNode, { pretty, indent: 2 });
|
|
2292
|
+
for (const script of scripts) {
|
|
2293
|
+
html2 += `${indent2}<script`;
|
|
2294
|
+
if (script.type) html2 += ` type="${this.escapeHtml(script.type)}"`;
|
|
2295
|
+
if (script.async) html2 += ` async`;
|
|
2296
|
+
if (script.defer) html2 += ` defer`;
|
|
2297
|
+
if (script.src) {
|
|
2298
|
+
html2 += ` src="${this.escapeHtml(script.src)}"></script>${nl}`;
|
|
2299
|
+
} else if (script.content) {
|
|
2300
|
+
html2 += `>${script.content}</script>${nl}`;
|
|
2301
|
+
} else {
|
|
2302
|
+
html2 += `></script>${nl}`;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
html2 += `${indent}</body>${nl}</html>`;
|
|
2306
|
+
return html2;
|
|
2307
|
+
}
|
|
2308
|
+
// Expose elementCache for reactive updates
|
|
2309
|
+
getElementCache() {
|
|
2310
|
+
return this.elementCache;
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
var dom = new DomNode();
|
|
2314
|
+
var render = dom.render.bind(dom);
|
|
2315
|
+
var renderToString = dom.renderToString.bind(dom);
|
|
2316
|
+
|
|
2317
|
+
// src/server.ts
|
|
2318
|
+
var ServerRouter = class {
|
|
2319
|
+
constructor() {
|
|
2320
|
+
this.routes = [];
|
|
2321
|
+
this.middlewares = [];
|
|
2322
|
+
this.get = (path, handler) => this.addRoute("GET", path, handler);
|
|
2323
|
+
this.post = (path, handler) => this.addRoute("POST", path, handler);
|
|
2324
|
+
this.put = (path, handler) => this.addRoute("PUT", path, handler);
|
|
2325
|
+
this.delete = (path, handler) => this.addRoute("DELETE", path, handler);
|
|
2326
|
+
this.patch = (path, handler) => this.addRoute("PATCH", path, handler);
|
|
2327
|
+
this.options = (path, handler) => this.addRoute("OPTIONS", path, handler);
|
|
2328
|
+
}
|
|
2329
|
+
use(middleware) {
|
|
2330
|
+
this.middlewares.push(middleware);
|
|
2331
|
+
return this;
|
|
2332
|
+
}
|
|
2333
|
+
addRoute(method, path, handler) {
|
|
2334
|
+
const { pattern, paramNames } = this.pathToRegex(path);
|
|
2335
|
+
this.routes.push({ method, pattern, paramNames, handler });
|
|
2336
|
+
return this;
|
|
2337
|
+
}
|
|
2338
|
+
pathToRegex(path) {
|
|
2339
|
+
const paramNames = [];
|
|
2340
|
+
const pattern = path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\//g, "\\/").replace(/:(\w+)/g, (_, name) => (paramNames.push(name), "([^\\/]+)"));
|
|
2341
|
+
return { pattern: new RegExp(`^${pattern}$`), paramNames };
|
|
2342
|
+
}
|
|
2343
|
+
parseQuery(url) {
|
|
2344
|
+
const query = {};
|
|
2345
|
+
url.split("?")[1]?.split("&").forEach((p) => {
|
|
2346
|
+
const [k, v] = p.split("=");
|
|
2347
|
+
if (k) query[k] = v || "";
|
|
2348
|
+
});
|
|
2349
|
+
return query;
|
|
2350
|
+
}
|
|
2351
|
+
parseBody(req) {
|
|
2352
|
+
return new Promise((resolve2, reject) => {
|
|
2353
|
+
let body = "";
|
|
2354
|
+
req.on("data", (chunk) => body += chunk);
|
|
2355
|
+
req.on("end", () => {
|
|
2356
|
+
try {
|
|
2357
|
+
const ct = req.headers["content-type"] || "";
|
|
2358
|
+
resolve2(ct.includes("json") ? body ? JSON.parse(body) : {} : ct.includes("urlencoded") ? Object.fromEntries(new URLSearchParams(body)) : body);
|
|
2359
|
+
} catch (e) {
|
|
2360
|
+
reject(e);
|
|
2361
|
+
}
|
|
2362
|
+
});
|
|
2363
|
+
req.on("error", reject);
|
|
2364
|
+
});
|
|
2365
|
+
}
|
|
2366
|
+
async handle(req, res) {
|
|
2367
|
+
const method = req.method, url = req.url || "/", path = url.split("?")[0];
|
|
2368
|
+
for (const route of this.routes) {
|
|
2369
|
+
if (route.method !== method || !route.pattern.test(path)) continue;
|
|
2370
|
+
const match = path.match(route.pattern);
|
|
2371
|
+
const params = Object.fromEntries(route.paramNames.map((name, i2) => [name, match[i2 + 1]]));
|
|
2372
|
+
let body = {};
|
|
2373
|
+
if (["POST", "PUT", "PATCH"].includes(method)) {
|
|
2374
|
+
try {
|
|
2375
|
+
body = await this.parseBody(req);
|
|
2376
|
+
} catch {
|
|
2377
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2378
|
+
res.end('{"error":"Invalid request body"}');
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
const ctx = { req, res, params, query: this.parseQuery(url), body, headers: req.headers };
|
|
2383
|
+
let i = 0;
|
|
2384
|
+
const next = async () => i < this.middlewares.length && await this.middlewares[i++](ctx, next);
|
|
2385
|
+
try {
|
|
2386
|
+
await next();
|
|
2387
|
+
await route.handler(ctx);
|
|
2388
|
+
} catch (e) {
|
|
2389
|
+
console.error("Route error:", e);
|
|
2390
|
+
!res.headersSent && (res.writeHead(500, { "Content-Type": "application/json" }), res.end(JSON.stringify({ error: "Internal Server Error", message: e instanceof Error ? e.message : "Unknown" })));
|
|
2391
|
+
}
|
|
2392
|
+
return true;
|
|
2393
|
+
}
|
|
2394
|
+
return false;
|
|
2395
|
+
}
|
|
2396
|
+
};
|
|
2397
|
+
var json = (res, data, status2 = 200) => (res.writeHead(status2, { "Content-Type": "application/json" }), res.end(JSON.stringify(data)));
|
|
2398
|
+
var text = (res, data, status2 = 200) => (res.writeHead(status2, { "Content-Type": "text/plain" }), res.end(data));
|
|
2399
|
+
var html = (res, data, status2 = 200) => (res.writeHead(status2, { "Content-Type": "text/html" }), res.end(data));
|
|
2400
|
+
var status = (res, code, message = "") => (res.writeHead(code, { "Content-Type": "application/json" }), res.end(JSON.stringify({ status: code, message })));
|
|
2401
|
+
var sendError = (res, code, msg) => {
|
|
2402
|
+
res.writeHead(code, { "Content-Type": "text/plain" });
|
|
2403
|
+
res.end(msg);
|
|
2404
|
+
};
|
|
2405
|
+
var send404 = (res, msg = "Not Found") => sendError(res, 404, msg);
|
|
2406
|
+
var send403 = (res, msg = "Forbidden") => sendError(res, 403, msg);
|
|
2407
|
+
var send500 = (res, msg = "Internal Server Error") => sendError(res, 500, msg);
|
|
2408
|
+
var createElitImportMap = (basePath = "", mode = "dev") => {
|
|
2409
|
+
const srcPath = mode === "dev" ? basePath ? `${basePath}/node_modules/elit/src` : "/node_modules/elit/src" : basePath ? `${basePath}/dist` : "/dist";
|
|
2410
|
+
const fileExt = mode === "dev" ? ".ts" : ".mjs";
|
|
2411
|
+
return `<script type="importmap">{"imports":{"elit":"${srcPath}/index${fileExt}","elit/":"${srcPath}/","elit/dom":"${srcPath}/dom${fileExt}","elit/state":"${srcPath}/state${fileExt}","elit/style":"${srcPath}/style${fileExt}","elit/el":"${srcPath}/el${fileExt}","elit/router":"${srcPath}/router${fileExt}","elit/hmr":"${srcPath}/hmr${fileExt}","elit/types":"${srcPath}/types${fileExt}"}}</script>`;
|
|
2412
|
+
};
|
|
2413
|
+
var createHMRScript = (port, wsPath) => `<script>(function(){let ws;let retries=0;let maxRetries=5;function connect(){ws=new WebSocket('ws://'+window.location.hostname+':${port}${wsPath}');ws.onopen=()=>{console.log('[Elit HMR] Connected');retries=0};ws.onmessage=(e)=>{const d=JSON.parse(e.data);if(d.type==='update'){console.log('[Elit HMR] File updated:',d.path);window.location.reload()}else if(d.type==='reload'){console.log('[Elit HMR] Reloading...');window.location.reload()}else if(d.type==='error')console.error('[Elit HMR] Error:',d.error)};ws.onclose=()=>{if(retries<maxRetries){retries++;setTimeout(connect,1000*retries)}else if(retries===maxRetries){console.log('[Elit HMR] Connection closed. Start dev server to reconnect.')}};ws.onerror=()=>{ws.close()}}connect()})();</script>`;
|
|
2414
|
+
var rewriteRelativePaths = (html2, basePath) => {
|
|
2415
|
+
if (!basePath) return html2;
|
|
2416
|
+
html2 = html2.replace(/(<script[^>]+src=["'])(?!https?:\/\/|\/)(\.\/)?([^"']+)(["'])/g, `$1${basePath}/$3$4`);
|
|
2417
|
+
html2 = html2.replace(/(<link[^>]+href=["'])(?!https?:\/\/|\/)(\.\/)?([^"']+)(["'])/g, `$1${basePath}/$3$4`);
|
|
2418
|
+
return html2;
|
|
2419
|
+
};
|
|
2420
|
+
var normalizeBasePath = (basePath) => basePath && basePath !== "/" ? basePath : "";
|
|
2421
|
+
async function findSpecialDir(startDir, targetDir) {
|
|
2422
|
+
let currentDir = startDir;
|
|
2423
|
+
const maxLevels = 5;
|
|
2424
|
+
for (let i = 0; i < maxLevels; i++) {
|
|
2425
|
+
const targetPath = resolve(currentDir, targetDir);
|
|
2426
|
+
try {
|
|
2427
|
+
const stats = await stat(targetPath);
|
|
2428
|
+
if (stats.isDirectory()) {
|
|
2429
|
+
return currentDir;
|
|
2430
|
+
}
|
|
2431
|
+
} catch {
|
|
2432
|
+
}
|
|
2433
|
+
const parentDir = resolve(currentDir, "..");
|
|
2434
|
+
if (parentDir === currentDir) break;
|
|
2435
|
+
currentDir = parentDir;
|
|
2436
|
+
}
|
|
2437
|
+
return null;
|
|
2438
|
+
}
|
|
2439
|
+
function cors(options = {}) {
|
|
2440
|
+
const { origin = "*", methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], credentials = true, maxAge = 86400 } = options;
|
|
2441
|
+
return async (ctx, next) => {
|
|
2442
|
+
const requestOriginHeader = ctx.req.headers.origin;
|
|
2443
|
+
const requestOrigin = Array.isArray(requestOriginHeader) ? requestOriginHeader[0] : requestOriginHeader || "";
|
|
2444
|
+
const allowOrigin = Array.isArray(origin) && origin.includes(requestOrigin) ? requestOrigin : Array.isArray(origin) ? "" : origin;
|
|
2445
|
+
if (allowOrigin) ctx.res.setHeader("Access-Control-Allow-Origin", allowOrigin);
|
|
2446
|
+
ctx.res.setHeader("Access-Control-Allow-Methods", methods.join(", "));
|
|
2447
|
+
ctx.res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
2448
|
+
if (credentials) ctx.res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
2449
|
+
ctx.res.setHeader("Access-Control-Max-Age", String(maxAge));
|
|
2450
|
+
if (ctx.req.method === "OPTIONS") {
|
|
2451
|
+
ctx.res.writeHead(204);
|
|
2452
|
+
ctx.res.end();
|
|
2453
|
+
return;
|
|
2454
|
+
}
|
|
2455
|
+
await next();
|
|
2456
|
+
};
|
|
2457
|
+
}
|
|
2458
|
+
function logger(options = {}) {
|
|
2459
|
+
const { format = "simple" } = options;
|
|
2460
|
+
return async (ctx, next) => {
|
|
2461
|
+
const start = Date.now();
|
|
2462
|
+
const { method, url } = ctx.req;
|
|
2463
|
+
await next();
|
|
2464
|
+
const duration = Date.now() - start;
|
|
2465
|
+
const status2 = ctx.res.statusCode;
|
|
2466
|
+
console.log(format === "detailed" ? `[${(/* @__PURE__ */ new Date()).toISOString()}] ${method} ${url} ${status2} - ${duration}ms` : `${method} ${url} - ${status2} (${duration}ms)`);
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
function errorHandler() {
|
|
2470
|
+
return async (ctx, next) => {
|
|
2471
|
+
try {
|
|
2472
|
+
await next();
|
|
2473
|
+
} catch (error) {
|
|
2474
|
+
console.error("Error:", error);
|
|
2475
|
+
if (!ctx.res.headersSent) {
|
|
2476
|
+
ctx.res.writeHead(500, { "Content-Type": "application/json" });
|
|
2477
|
+
ctx.res.end(JSON.stringify({ error: "Internal Server Error", message: error instanceof Error ? error.message : "Unknown error" }));
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
}
|
|
2482
|
+
function rateLimit(options = {}) {
|
|
2483
|
+
const { windowMs = 6e4, max = 100, message = "Too many requests" } = options;
|
|
2484
|
+
const clients = /* @__PURE__ */ new Map();
|
|
2485
|
+
return async (ctx, next) => {
|
|
2486
|
+
const ip = ctx.req.socket.remoteAddress || "unknown";
|
|
2487
|
+
const now = Date.now();
|
|
2488
|
+
let clientData = clients.get(ip);
|
|
2489
|
+
if (!clientData || now > clientData.resetTime) {
|
|
2490
|
+
clientData = { count: 0, resetTime: now + windowMs };
|
|
2491
|
+
clients.set(ip, clientData);
|
|
2492
|
+
}
|
|
2493
|
+
if (++clientData.count > max) {
|
|
2494
|
+
ctx.res.writeHead(429, { "Content-Type": "application/json" });
|
|
2495
|
+
ctx.res.end(JSON.stringify({ error: message }));
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
await next();
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
function bodyLimit(options = {}) {
|
|
2502
|
+
const { limit = 1024 * 1024 } = options;
|
|
2503
|
+
return async (ctx, next) => {
|
|
2504
|
+
const contentLength = ctx.req.headers["content-length"];
|
|
2505
|
+
const contentLengthStr = Array.isArray(contentLength) ? contentLength[0] : contentLength || "0";
|
|
2506
|
+
if (parseInt(contentLengthStr, 10) > limit) {
|
|
2507
|
+
ctx.res.writeHead(413, { "Content-Type": "application/json" });
|
|
2508
|
+
ctx.res.end(JSON.stringify({ error: "Request body too large" }));
|
|
2509
|
+
return;
|
|
2510
|
+
}
|
|
2511
|
+
await next();
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
function cacheControl(options = {}) {
|
|
2515
|
+
const { maxAge = 3600, public: isPublic = true } = options;
|
|
2516
|
+
return async (ctx, next) => {
|
|
2517
|
+
ctx.res.setHeader("Cache-Control", `${isPublic ? "public" : "private"}, max-age=${maxAge}`);
|
|
2518
|
+
await next();
|
|
2519
|
+
};
|
|
2520
|
+
}
|
|
2521
|
+
function compress() {
|
|
2522
|
+
return async (ctx, next) => {
|
|
2523
|
+
const acceptEncoding = ctx.req.headers["accept-encoding"] || "";
|
|
2524
|
+
if (!acceptEncoding.includes("gzip")) {
|
|
2525
|
+
await next();
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
const originalEnd = ctx.res.end.bind(ctx.res);
|
|
2529
|
+
const chunks = [];
|
|
2530
|
+
ctx.res.write = ((chunk) => {
|
|
2531
|
+
chunks.push(Buffer.from(chunk));
|
|
2532
|
+
return true;
|
|
2533
|
+
});
|
|
2534
|
+
ctx.res.end = ((chunk) => {
|
|
2535
|
+
if (chunk) chunks.push(Buffer.from(chunk));
|
|
2536
|
+
const buffer = Buffer.concat(chunks);
|
|
2537
|
+
const { gzipSync } = require("zlib");
|
|
2538
|
+
const compressed = gzipSync(buffer);
|
|
2539
|
+
ctx.res.setHeader("Content-Encoding", "gzip");
|
|
2540
|
+
ctx.res.setHeader("Content-Length", compressed.length);
|
|
2541
|
+
originalEnd(compressed);
|
|
2542
|
+
return ctx.res;
|
|
2543
|
+
});
|
|
2544
|
+
await next();
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
function security() {
|
|
2548
|
+
return async (ctx, next) => {
|
|
2549
|
+
ctx.res.setHeader("X-Content-Type-Options", "nosniff");
|
|
2550
|
+
ctx.res.setHeader("X-Frame-Options", "DENY");
|
|
2551
|
+
ctx.res.setHeader("X-XSS-Protection", "1; mode=block");
|
|
2552
|
+
ctx.res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
|
|
2553
|
+
await next();
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
function rewritePath(path, pathRewrite) {
|
|
2557
|
+
if (!pathRewrite) return path;
|
|
2558
|
+
for (const [from, to] of Object.entries(pathRewrite)) {
|
|
2559
|
+
const regex = new RegExp(from);
|
|
2560
|
+
if (regex.test(path)) {
|
|
2561
|
+
return path.replace(regex, to);
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
return path;
|
|
2565
|
+
}
|
|
2566
|
+
function createProxyHandler(proxyConfigs) {
|
|
2567
|
+
return async (req, res) => {
|
|
2568
|
+
const url = req.url || "/";
|
|
2569
|
+
const path = url.split("?")[0];
|
|
2570
|
+
const proxy = proxyConfigs.find((p) => path.startsWith(p.context));
|
|
2571
|
+
if (!proxy) return false;
|
|
2572
|
+
const { target, changeOrigin, pathRewrite, headers } = proxy;
|
|
2573
|
+
try {
|
|
2574
|
+
const targetUrl = new URL(target);
|
|
2575
|
+
const isHttps = targetUrl.protocol === "https:";
|
|
2576
|
+
const requestLib = isHttps ? request2 : request;
|
|
2577
|
+
let proxyPath = rewritePath(url, pathRewrite);
|
|
2578
|
+
const proxyUrl = `${isHttps ? "https" : "http"}://${targetUrl.hostname}:${targetUrl.port || (isHttps ? 443 : 80)}${proxyPath}`;
|
|
2579
|
+
const proxyReqHeaders = {};
|
|
2580
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
2581
|
+
if (value !== void 0) {
|
|
2582
|
+
proxyReqHeaders[key] = value;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
if (headers) {
|
|
2586
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
2587
|
+
if (value !== void 0) {
|
|
2588
|
+
proxyReqHeaders[key] = value;
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
if (changeOrigin) {
|
|
2593
|
+
proxyReqHeaders.host = targetUrl.host;
|
|
2594
|
+
}
|
|
2595
|
+
delete proxyReqHeaders["host"];
|
|
2596
|
+
const proxyReqOptions = {
|
|
2597
|
+
method: req.method,
|
|
2598
|
+
headers: proxyReqHeaders
|
|
2599
|
+
};
|
|
2600
|
+
const proxyReq = requestLib(proxyUrl, proxyReqOptions, (proxyRes) => {
|
|
2601
|
+
const outgoingHeaders = {};
|
|
2602
|
+
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
|
2603
|
+
if (value !== void 0) {
|
|
2604
|
+
outgoingHeaders[key] = value;
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
res.writeHead(proxyRes.statusCode || 200, outgoingHeaders);
|
|
2608
|
+
proxyRes.on("data", (chunk) => res.write(chunk));
|
|
2609
|
+
proxyRes.on("end", () => res.end());
|
|
2610
|
+
});
|
|
2611
|
+
proxyReq.on("error", (error) => {
|
|
2612
|
+
console.error("[Proxy] Error proxying %s to %s:", url, target, error.message);
|
|
2613
|
+
if (!res.headersSent) {
|
|
2614
|
+
json(res, { error: "Bad Gateway", message: "Proxy error" }, 502);
|
|
2615
|
+
}
|
|
2616
|
+
});
|
|
2617
|
+
req.on("data", (chunk) => proxyReq.write(chunk));
|
|
2618
|
+
req.on("end", () => proxyReq.end());
|
|
2619
|
+
return true;
|
|
2620
|
+
} catch (error) {
|
|
2621
|
+
console.error("[Proxy] Invalid proxy configuration for %s:", path, error);
|
|
2622
|
+
return false;
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
var SharedState = class {
|
|
2627
|
+
constructor(key, options) {
|
|
2628
|
+
this.key = key;
|
|
2629
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2630
|
+
this.changeHandlers = /* @__PURE__ */ new Set();
|
|
2631
|
+
this.options = options;
|
|
2632
|
+
this._value = options.initial;
|
|
2633
|
+
}
|
|
2634
|
+
get value() {
|
|
2635
|
+
return this._value;
|
|
2636
|
+
}
|
|
2637
|
+
set value(newValue) {
|
|
2638
|
+
if (this.options.validate && !this.options.validate(newValue)) {
|
|
2639
|
+
throw new Error(`Invalid state value for "${this.key}"`);
|
|
2640
|
+
}
|
|
2641
|
+
const oldValue = this._value;
|
|
2642
|
+
this._value = newValue;
|
|
2643
|
+
this.changeHandlers.forEach((handler) => {
|
|
2644
|
+
handler(newValue, oldValue);
|
|
2645
|
+
});
|
|
2646
|
+
this.broadcast();
|
|
2647
|
+
}
|
|
2648
|
+
update(updater) {
|
|
2649
|
+
this.value = updater(this._value);
|
|
2650
|
+
}
|
|
2651
|
+
subscribe(ws) {
|
|
2652
|
+
this.listeners.add(ws);
|
|
2653
|
+
this.sendTo(ws);
|
|
2654
|
+
}
|
|
2655
|
+
unsubscribe(ws) {
|
|
2656
|
+
this.listeners.delete(ws);
|
|
2657
|
+
}
|
|
2658
|
+
onChange(handler) {
|
|
2659
|
+
this.changeHandlers.add(handler);
|
|
2660
|
+
return () => this.changeHandlers.delete(handler);
|
|
2661
|
+
}
|
|
2662
|
+
broadcast() {
|
|
2663
|
+
const message = JSON.stringify({ type: "state:update", key: this.key, value: this._value, timestamp: Date.now() });
|
|
2664
|
+
this.listeners.forEach((ws) => ws.readyState === 1 /* OPEN */ && ws.send(message));
|
|
2665
|
+
}
|
|
2666
|
+
sendTo(ws) {
|
|
2667
|
+
if (ws.readyState === 1 /* OPEN */) {
|
|
2668
|
+
ws.send(JSON.stringify({ type: "state:init", key: this.key, value: this._value, timestamp: Date.now() }));
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
get subscriberCount() {
|
|
2672
|
+
return this.listeners.size;
|
|
2673
|
+
}
|
|
2674
|
+
clear() {
|
|
2675
|
+
this.listeners.clear();
|
|
2676
|
+
this.changeHandlers.clear();
|
|
2677
|
+
}
|
|
2678
|
+
};
|
|
2679
|
+
var StateManager = class {
|
|
2680
|
+
constructor() {
|
|
2681
|
+
this.states = /* @__PURE__ */ new Map();
|
|
2682
|
+
}
|
|
2683
|
+
create(key, options) {
|
|
2684
|
+
if (this.states.has(key)) return this.states.get(key);
|
|
2685
|
+
const state = new SharedState(key, options);
|
|
2686
|
+
this.states.set(key, state);
|
|
2687
|
+
return state;
|
|
2688
|
+
}
|
|
2689
|
+
get(key) {
|
|
2690
|
+
return this.states.get(key);
|
|
2691
|
+
}
|
|
2692
|
+
has(key) {
|
|
2693
|
+
return this.states.has(key);
|
|
2694
|
+
}
|
|
2695
|
+
delete(key) {
|
|
2696
|
+
const state = this.states.get(key);
|
|
2697
|
+
if (state) {
|
|
2698
|
+
state.clear();
|
|
2699
|
+
return this.states.delete(key);
|
|
2700
|
+
}
|
|
2701
|
+
return false;
|
|
2702
|
+
}
|
|
2703
|
+
subscribe(key, ws) {
|
|
2704
|
+
this.states.get(key)?.subscribe(ws);
|
|
2705
|
+
}
|
|
2706
|
+
unsubscribe(key, ws) {
|
|
2707
|
+
this.states.get(key)?.unsubscribe(ws);
|
|
2708
|
+
}
|
|
2709
|
+
unsubscribeAll(ws) {
|
|
2710
|
+
this.states.forEach((state) => state.unsubscribe(ws));
|
|
2711
|
+
}
|
|
2712
|
+
handleStateChange(key, value) {
|
|
2713
|
+
const state = this.states.get(key);
|
|
2714
|
+
if (state) state.value = value;
|
|
2715
|
+
}
|
|
2716
|
+
keys() {
|
|
2717
|
+
return Array.from(this.states.keys());
|
|
2718
|
+
}
|
|
2719
|
+
clear() {
|
|
2720
|
+
this.states.forEach((state) => state.clear());
|
|
2721
|
+
this.states.clear();
|
|
2722
|
+
}
|
|
2723
|
+
};
|
|
2724
|
+
var defaultOptions = {
|
|
2725
|
+
port: 3e3,
|
|
2726
|
+
host: "localhost",
|
|
2727
|
+
https: false,
|
|
2728
|
+
open: true,
|
|
2729
|
+
watch: ["**/*.ts", "**/*.js", "**/*.html", "**/*.css"],
|
|
2730
|
+
ignore: ["node_modules/**", "dist/**", ".git/**", "**/*.d.ts"],
|
|
2731
|
+
logging: true,
|
|
2732
|
+
middleware: [],
|
|
2733
|
+
worker: [],
|
|
2734
|
+
mode: "dev"
|
|
2735
|
+
};
|
|
2736
|
+
function createDevServer(options) {
|
|
2737
|
+
const config = { ...defaultOptions, ...options };
|
|
2738
|
+
const wsClients = /* @__PURE__ */ new Set();
|
|
2739
|
+
const stateManager = new StateManager();
|
|
2740
|
+
const clientsToNormalize = config.clients?.length ? config.clients : config.root ? [{ root: config.root, basePath: config.basePath || "", index: config.index, ssr: config.ssr, api: config.api, proxy: config.proxy, mode: config.mode }] : null;
|
|
2741
|
+
if (!clientsToNormalize) throw new Error('DevServerOptions must include either "clients" array or "root" directory');
|
|
2742
|
+
const normalizedClients = clientsToNormalize.map((client) => {
|
|
2743
|
+
let basePath = client.basePath || "";
|
|
2744
|
+
if (basePath) {
|
|
2745
|
+
while (basePath.startsWith("/")) basePath = basePath.slice(1);
|
|
2746
|
+
while (basePath.endsWith("/")) basePath = basePath.slice(0, -1);
|
|
2747
|
+
basePath = basePath ? "/" + basePath : "";
|
|
2748
|
+
}
|
|
2749
|
+
let indexPath = client.index;
|
|
2750
|
+
if (indexPath) {
|
|
2751
|
+
indexPath = indexPath.replace(/^\.\//, "/");
|
|
2752
|
+
if (!indexPath.startsWith("/")) {
|
|
2753
|
+
indexPath = "/" + indexPath;
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
return {
|
|
2757
|
+
root: client.root,
|
|
2758
|
+
basePath,
|
|
2759
|
+
index: indexPath,
|
|
2760
|
+
ssr: client.ssr,
|
|
2761
|
+
api: client.api,
|
|
2762
|
+
proxyHandler: client.proxy ? createProxyHandler(client.proxy) : void 0,
|
|
2763
|
+
mode: client.mode || "dev"
|
|
2764
|
+
};
|
|
2765
|
+
});
|
|
2766
|
+
const globalProxyHandler = config.proxy ? createProxyHandler(config.proxy) : null;
|
|
2767
|
+
const server = createServer(async (req, res) => {
|
|
2768
|
+
const originalUrl = req.url || "/";
|
|
2769
|
+
const matchedClient = normalizedClients.find((c) => c.basePath && originalUrl.startsWith(c.basePath)) || normalizedClients.find((c) => !c.basePath);
|
|
2770
|
+
if (!matchedClient) return send404(res, "404 Not Found");
|
|
2771
|
+
if (matchedClient.proxyHandler) {
|
|
2772
|
+
try {
|
|
2773
|
+
const proxied = await matchedClient.proxyHandler(req, res);
|
|
2774
|
+
if (proxied) {
|
|
2775
|
+
if (config.logging) console.log(`[Proxy] ${req.method} ${originalUrl} -> proxied (client-specific)`);
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2778
|
+
} catch (error) {
|
|
2779
|
+
console.error("[Proxy] Error (client-specific):", error);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
if (globalProxyHandler) {
|
|
2783
|
+
try {
|
|
2784
|
+
const proxied = await globalProxyHandler(req, res);
|
|
2785
|
+
if (proxied) {
|
|
2786
|
+
if (config.logging) console.log(`[Proxy] ${req.method} ${originalUrl} -> proxied (global)`);
|
|
2787
|
+
return;
|
|
2788
|
+
}
|
|
2789
|
+
} catch (error) {
|
|
2790
|
+
console.error("[Proxy] Error (global):", error);
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
const url = matchedClient.basePath ? originalUrl.slice(matchedClient.basePath.length) || "/" : originalUrl;
|
|
2794
|
+
if (matchedClient.api && url.startsWith("/api")) {
|
|
2795
|
+
const handled = await matchedClient.api.handle(req, res);
|
|
2796
|
+
if (handled) return;
|
|
2797
|
+
}
|
|
2798
|
+
if (config.api && url.startsWith("/api")) {
|
|
2799
|
+
const handled = await config.api.handle(req, res);
|
|
2800
|
+
if (handled) return;
|
|
2801
|
+
}
|
|
2802
|
+
let filePath;
|
|
2803
|
+
if (url === "/" && matchedClient.ssr && !matchedClient.index) {
|
|
2804
|
+
return serveSSR(res, matchedClient);
|
|
2805
|
+
} else {
|
|
2806
|
+
filePath = url === "/" ? matchedClient.index || "/index.html" : url;
|
|
2807
|
+
}
|
|
2808
|
+
filePath = filePath.split("?")[0];
|
|
2809
|
+
if (config.logging && filePath === "/src/pages") {
|
|
2810
|
+
console.log(`[DEBUG] Request for /src/pages received`);
|
|
2811
|
+
}
|
|
2812
|
+
if (filePath.includes("\0")) {
|
|
2813
|
+
if (config.logging) console.log(`[403] Rejected path with null byte: ${filePath}`);
|
|
2814
|
+
return send403(res, "403 Forbidden");
|
|
2815
|
+
}
|
|
2816
|
+
const isDistRequest = filePath.startsWith("/dist/");
|
|
2817
|
+
const isNodeModulesRequest = filePath.startsWith("/node_modules/");
|
|
2818
|
+
let normalizedPath;
|
|
2819
|
+
const tempPath = normalize(filePath).replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2820
|
+
if (tempPath.includes("..")) {
|
|
2821
|
+
if (config.logging) console.log(`[403] Path traversal attempt: ${filePath}`);
|
|
2822
|
+
return send403(res, "403 Forbidden");
|
|
2823
|
+
}
|
|
2824
|
+
normalizedPath = tempPath;
|
|
2825
|
+
const rootDir = await realpath(resolve(matchedClient.root));
|
|
2826
|
+
let baseDir = rootDir;
|
|
2827
|
+
if (isDistRequest || isNodeModulesRequest) {
|
|
2828
|
+
const targetDir = isDistRequest ? "dist" : "node_modules";
|
|
2829
|
+
const foundDir = await findSpecialDir(matchedClient.root, targetDir);
|
|
2830
|
+
baseDir = foundDir ? await realpath(foundDir) : rootDir;
|
|
2831
|
+
}
|
|
2832
|
+
let fullPath;
|
|
2833
|
+
try {
|
|
2834
|
+
const unresolvedPath = resolve(join(baseDir, normalizedPath));
|
|
2835
|
+
if (!unresolvedPath.startsWith(baseDir.endsWith(sep) ? baseDir : baseDir + sep)) {
|
|
2836
|
+
if (config.logging) console.log(`[403] File access outside of root (before symlink): ${unresolvedPath}`);
|
|
2837
|
+
return send403(res, "403 Forbidden");
|
|
2838
|
+
}
|
|
2839
|
+
fullPath = await realpath(unresolvedPath);
|
|
2840
|
+
if (config.logging && filePath === "/src/pages") {
|
|
2841
|
+
console.log(`[DEBUG] Initial resolve succeeded: ${fullPath}`);
|
|
2842
|
+
}
|
|
2843
|
+
} catch (firstError) {
|
|
2844
|
+
let resolvedPath;
|
|
2845
|
+
if (config.logging && !normalizedPath.includes(".")) {
|
|
2846
|
+
console.log(`[DEBUG] File not found: ${normalizedPath}, trying extensions...`);
|
|
2847
|
+
}
|
|
2848
|
+
if (normalizedPath.endsWith(".js")) {
|
|
2849
|
+
const tsPath = normalizedPath.replace(/\.js$/, ".ts");
|
|
2850
|
+
try {
|
|
2851
|
+
const tsFullPath = await realpath(resolve(join(baseDir, tsPath)));
|
|
2852
|
+
if (!tsFullPath.startsWith(baseDir.endsWith(sep) ? baseDir : baseDir + sep)) {
|
|
2853
|
+
if (config.logging) console.log(`[403] Fallback TS path outside of root: ${tsFullPath}`);
|
|
2854
|
+
return send403(res, "403 Forbidden");
|
|
2855
|
+
}
|
|
2856
|
+
resolvedPath = tsFullPath;
|
|
2857
|
+
} catch {
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
if (!resolvedPath && !normalizedPath.includes(".")) {
|
|
2861
|
+
try {
|
|
2862
|
+
resolvedPath = await realpath(resolve(join(baseDir, normalizedPath + ".ts")));
|
|
2863
|
+
if (config.logging) console.log(`[DEBUG] Found: ${normalizedPath}.ts`);
|
|
2864
|
+
} catch {
|
|
2865
|
+
try {
|
|
2866
|
+
resolvedPath = await realpath(resolve(join(baseDir, normalizedPath + ".js")));
|
|
2867
|
+
if (config.logging) console.log(`[DEBUG] Found: ${normalizedPath}.js`);
|
|
2868
|
+
} catch {
|
|
2869
|
+
try {
|
|
2870
|
+
resolvedPath = await realpath(resolve(join(baseDir, normalizedPath, "index.ts")));
|
|
2871
|
+
if (config.logging) console.log(`[DEBUG] Found: ${normalizedPath}/index.ts`);
|
|
2872
|
+
} catch {
|
|
2873
|
+
try {
|
|
2874
|
+
resolvedPath = await realpath(resolve(join(baseDir, normalizedPath, "index.js")));
|
|
2875
|
+
if (config.logging) console.log(`[DEBUG] Found: ${normalizedPath}/index.js`);
|
|
2876
|
+
} catch {
|
|
2877
|
+
if (config.logging) console.log(`[DEBUG] Not found: all attempts failed for ${normalizedPath}`);
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
if (!resolvedPath) {
|
|
2884
|
+
if (!res.headersSent) {
|
|
2885
|
+
if (filePath === "/index.html" && matchedClient.ssr) {
|
|
2886
|
+
return serveSSR(res, matchedClient);
|
|
2887
|
+
}
|
|
2888
|
+
if (config.logging) console.log(`[404] ${filePath}`);
|
|
2889
|
+
return send404(res, "404 Not Found");
|
|
2890
|
+
}
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
fullPath = resolvedPath;
|
|
2894
|
+
}
|
|
2895
|
+
try {
|
|
2896
|
+
const stats = await stat(fullPath);
|
|
2897
|
+
if (stats.isDirectory()) {
|
|
2898
|
+
if (config.logging) console.log(`[DEBUG] Path is directory: ${fullPath}, trying index files...`);
|
|
2899
|
+
let indexPath;
|
|
2900
|
+
try {
|
|
2901
|
+
indexPath = await realpath(resolve(join(fullPath, "index.ts")));
|
|
2902
|
+
if (config.logging) console.log(`[DEBUG] Found index.ts in directory`);
|
|
2903
|
+
} catch {
|
|
2904
|
+
try {
|
|
2905
|
+
indexPath = await realpath(resolve(join(fullPath, "index.js")));
|
|
2906
|
+
if (config.logging) console.log(`[DEBUG] Found index.js in directory`);
|
|
2907
|
+
} catch {
|
|
2908
|
+
if (config.logging) console.log(`[DEBUG] No index file found in directory`);
|
|
2909
|
+
if (matchedClient.ssr) {
|
|
2910
|
+
return serveSSR(res, matchedClient);
|
|
2911
|
+
}
|
|
2912
|
+
return send404(res, "404 Not Found");
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
fullPath = indexPath;
|
|
2916
|
+
}
|
|
2917
|
+
} catch (statError) {
|
|
2918
|
+
if (config.logging) console.log(`[404] ${filePath}`);
|
|
2919
|
+
return send404(res, "404 Not Found");
|
|
2920
|
+
}
|
|
2921
|
+
try {
|
|
2922
|
+
const stats = await stat(fullPath);
|
|
2923
|
+
if (stats.isDirectory()) {
|
|
2924
|
+
try {
|
|
2925
|
+
const indexPath = await realpath(resolve(join(fullPath, "index.html")));
|
|
2926
|
+
if (!indexPath.startsWith(rootDir + sep) && indexPath !== rootDir) {
|
|
2927
|
+
return send403(res, "403 Forbidden");
|
|
2928
|
+
}
|
|
2929
|
+
await stat(indexPath);
|
|
2930
|
+
return serveFile(indexPath, res, matchedClient);
|
|
2931
|
+
} catch {
|
|
2932
|
+
return send404(res, "404 Not Found");
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
await serveFile(fullPath, res, matchedClient);
|
|
2936
|
+
} catch (error) {
|
|
2937
|
+
if (!res.headersSent) {
|
|
2938
|
+
if (config.logging) console.log(`[404] ${filePath}`);
|
|
2939
|
+
send404(res, "404 Not Found");
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
});
|
|
2943
|
+
async function serveFile(filePath, res, client) {
|
|
2944
|
+
try {
|
|
2945
|
+
const rootDir = await realpath(resolve(client.root));
|
|
2946
|
+
const unresolvedPath = resolve(filePath);
|
|
2947
|
+
const isNodeModules = filePath.includes("/node_modules/") || filePath.includes("\\node_modules\\");
|
|
2948
|
+
const isDist = filePath.includes("/dist/") || filePath.includes("\\dist\\");
|
|
2949
|
+
const projectRoot = await realpath(resolve(client.root, ".."));
|
|
2950
|
+
const isInProjectRoot = unresolvedPath.startsWith(projectRoot + sep) || unresolvedPath === projectRoot;
|
|
2951
|
+
if (!unresolvedPath.startsWith(rootDir + sep) && unresolvedPath !== rootDir && !isInProjectRoot) {
|
|
2952
|
+
if (!isNodeModules && !isDist) {
|
|
2953
|
+
if (config.logging) console.log(`[403] Attempted to serve file outside allowed directories: ${filePath}`);
|
|
2954
|
+
return send403(res, "403 Forbidden");
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
let resolvedPath;
|
|
2958
|
+
try {
|
|
2959
|
+
resolvedPath = await realpath(unresolvedPath);
|
|
2960
|
+
} catch {
|
|
2961
|
+
if (filePath.endsWith("index.html") && client.ssr) {
|
|
2962
|
+
return serveSSR(res, client);
|
|
2963
|
+
}
|
|
2964
|
+
return send404(res, "404 Not Found");
|
|
2965
|
+
}
|
|
2966
|
+
let content = await readFile(resolvedPath);
|
|
2967
|
+
const ext = extname(resolvedPath);
|
|
2968
|
+
let mimeType = lookup(resolvedPath) || "application/octet-stream";
|
|
2969
|
+
if (ext === ".ts" || ext === ".tsx") {
|
|
2970
|
+
try {
|
|
2971
|
+
let transpiled;
|
|
2972
|
+
if (isDeno) {
|
|
2973
|
+
const result = await Deno.emit(resolvedPath, {
|
|
2974
|
+
check: false,
|
|
2975
|
+
compilerOptions: {
|
|
2976
|
+
sourceMap: true,
|
|
2977
|
+
inlineSourceMap: true,
|
|
2978
|
+
target: "ES2020",
|
|
2979
|
+
module: "esnext"
|
|
2980
|
+
},
|
|
2981
|
+
sources: {
|
|
2982
|
+
[resolvedPath]: content.toString()
|
|
2983
|
+
}
|
|
2984
|
+
});
|
|
2985
|
+
transpiled = result.files[resolvedPath.replace(/\.tsx?$/, ".js")] || "";
|
|
2986
|
+
} else if (isBun) {
|
|
2987
|
+
const transpiler = new Bun.Transpiler({
|
|
2988
|
+
loader: ext === ".tsx" ? "tsx" : "ts",
|
|
2989
|
+
target: "browser"
|
|
2990
|
+
});
|
|
2991
|
+
transpiled = transpiler.transformSync(content.toString());
|
|
2992
|
+
} else {
|
|
2993
|
+
const { build } = await import("esbuild");
|
|
2994
|
+
const result = await build({
|
|
2995
|
+
stdin: {
|
|
2996
|
+
contents: content.toString(),
|
|
2997
|
+
loader: ext === ".tsx" ? "tsx" : "ts",
|
|
2998
|
+
resolveDir: resolve(resolvedPath, ".."),
|
|
2999
|
+
sourcefile: resolvedPath
|
|
3000
|
+
},
|
|
3001
|
+
format: "esm",
|
|
3002
|
+
target: "es2020",
|
|
3003
|
+
write: false,
|
|
3004
|
+
bundle: false,
|
|
3005
|
+
sourcemap: "inline"
|
|
3006
|
+
});
|
|
3007
|
+
transpiled = result.outputFiles[0].text;
|
|
3008
|
+
}
|
|
3009
|
+
transpiled = transpiled.replace(
|
|
3010
|
+
/from\s+["']([^"']+)\.ts(x?)["']/g,
|
|
3011
|
+
(_, path, tsx) => `from "${path}.js${tsx}"`
|
|
3012
|
+
);
|
|
3013
|
+
transpiled = transpiled.replace(
|
|
3014
|
+
/import\s+["']([^"']+)\.ts(x?)["']/g,
|
|
3015
|
+
(_, path, tsx) => `import "${path}.js${tsx}"`
|
|
3016
|
+
);
|
|
3017
|
+
content = Buffer.from(transpiled);
|
|
3018
|
+
mimeType = "application/javascript";
|
|
3019
|
+
} catch (error) {
|
|
3020
|
+
if (config.logging) console.error("[500] TypeScript compilation error:", error);
|
|
3021
|
+
return send500(res, `TypeScript compilation error:
|
|
3022
|
+
${error}`);
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
if (ext === ".html") {
|
|
3026
|
+
const wsPath = normalizeBasePath(client.basePath);
|
|
3027
|
+
const hmrScript = createHMRScript(config.port, wsPath);
|
|
3028
|
+
let html2 = content.toString();
|
|
3029
|
+
let ssrStyles = "";
|
|
3030
|
+
if (client.ssr) {
|
|
3031
|
+
try {
|
|
3032
|
+
const result = client.ssr();
|
|
3033
|
+
let ssrHtml;
|
|
3034
|
+
if (typeof result === "string") {
|
|
3035
|
+
ssrHtml = result;
|
|
3036
|
+
} else if (typeof result === "object" && result !== null && "tagName" in result) {
|
|
3037
|
+
ssrHtml = dom.renderToString(result);
|
|
3038
|
+
} else {
|
|
3039
|
+
ssrHtml = String(result);
|
|
3040
|
+
}
|
|
3041
|
+
const styleMatches = ssrHtml.match(/<style[^>]*>[\s\S]*?<\/style>/g);
|
|
3042
|
+
if (styleMatches) {
|
|
3043
|
+
ssrStyles = styleMatches.join("\n");
|
|
3044
|
+
}
|
|
3045
|
+
} catch (error) {
|
|
3046
|
+
if (config.logging) console.error("[Warning] Failed to extract styles from SSR:", error);
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
const basePath = normalizeBasePath(client.basePath);
|
|
3050
|
+
html2 = rewriteRelativePaths(html2, basePath);
|
|
3051
|
+
if (client.basePath && client.basePath !== "/") {
|
|
3052
|
+
const baseTag = `<base href="${client.basePath}/">`;
|
|
3053
|
+
if (!html2.includes("<base")) {
|
|
3054
|
+
if (html2.includes('<meta name="viewport"')) {
|
|
3055
|
+
html2 = html2.replace(
|
|
3056
|
+
/<meta name="viewport"[^>]*>/,
|
|
3057
|
+
(match) => `${match}
|
|
3058
|
+
${baseTag}`
|
|
3059
|
+
);
|
|
3060
|
+
} else if (html2.includes("<head>")) {
|
|
3061
|
+
html2 = html2.replace("<head>", `<head>
|
|
3062
|
+
${baseTag}`);
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
const elitImportMap = createElitImportMap(basePath, client.mode);
|
|
3067
|
+
const headInjection = ssrStyles ? `${ssrStyles}
|
|
3068
|
+
${elitImportMap}` : elitImportMap;
|
|
3069
|
+
html2 = html2.includes("</head>") ? html2.replace("</head>", `${headInjection}</head>`) : html2;
|
|
3070
|
+
html2 = html2.includes("</body>") ? html2.replace("</body>", `${hmrScript}</body>`) : html2 + hmrScript;
|
|
3071
|
+
content = Buffer.from(html2);
|
|
3072
|
+
}
|
|
3073
|
+
const cacheControl2 = ext === ".html" || ext === ".ts" || ext === ".tsx" ? "no-cache, no-store, must-revalidate" : "public, max-age=31536000, immutable";
|
|
3074
|
+
const headers = {
|
|
3075
|
+
"Content-Type": mimeType,
|
|
3076
|
+
"Cache-Control": cacheControl2
|
|
3077
|
+
};
|
|
3078
|
+
const compressible = /^(text\/|application\/(javascript|json|xml))/.test(mimeType);
|
|
3079
|
+
if (compressible && content.length > 1024) {
|
|
3080
|
+
const { gzipSync } = require("zlib");
|
|
3081
|
+
const compressed = gzipSync(content);
|
|
3082
|
+
headers["Content-Encoding"] = "gzip";
|
|
3083
|
+
headers["Content-Length"] = compressed.length;
|
|
3084
|
+
res.writeHead(200, headers);
|
|
3085
|
+
res.end(compressed);
|
|
3086
|
+
} else {
|
|
3087
|
+
res.writeHead(200, headers);
|
|
3088
|
+
res.end(content);
|
|
3089
|
+
}
|
|
3090
|
+
if (config.logging) console.log(`[200] ${relative(client.root, filePath)}`);
|
|
3091
|
+
} catch (error) {
|
|
3092
|
+
if (config.logging) console.error("[500] Error reading file:", error);
|
|
3093
|
+
send500(res, "500 Internal Server Error");
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
function serveSSR(res, client) {
|
|
3097
|
+
try {
|
|
3098
|
+
if (!client.ssr) {
|
|
3099
|
+
return send500(res, "SSR function not configured");
|
|
3100
|
+
}
|
|
3101
|
+
const result = client.ssr();
|
|
3102
|
+
let html2;
|
|
3103
|
+
if (typeof result === "string") {
|
|
3104
|
+
html2 = result;
|
|
3105
|
+
} else if (typeof result === "object" && result !== null && "tagName" in result) {
|
|
3106
|
+
const vnode = result;
|
|
3107
|
+
if (vnode.tagName === "html") {
|
|
3108
|
+
html2 = dom.renderToString(vnode);
|
|
3109
|
+
} else {
|
|
3110
|
+
html2 = `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><body>${dom.renderToString(vnode)}</body></html>`;
|
|
3111
|
+
}
|
|
3112
|
+
} else {
|
|
3113
|
+
html2 = String(result);
|
|
3114
|
+
}
|
|
3115
|
+
const basePath = normalizeBasePath(client.basePath);
|
|
3116
|
+
html2 = rewriteRelativePaths(html2, basePath);
|
|
3117
|
+
const hmrScript = createHMRScript(config.port, basePath);
|
|
3118
|
+
const elitImportMap = createElitImportMap(basePath, client.mode);
|
|
3119
|
+
html2 = html2.includes("</head>") ? html2.replace("</head>", `${elitImportMap}</head>`) : html2;
|
|
3120
|
+
html2 = html2.includes("</body>") ? html2.replace("</body>", `${hmrScript}</body>`) : html2 + hmrScript;
|
|
3121
|
+
res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-cache, no-store, must-revalidate" });
|
|
3122
|
+
res.end(html2);
|
|
3123
|
+
if (config.logging) console.log(`[200] SSR rendered`);
|
|
3124
|
+
} catch (error) {
|
|
3125
|
+
if (config.logging) console.error("[500] SSR Error:", error);
|
|
3126
|
+
send500(res, "500 SSR Error");
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
const wss = new WebSocketServer({ server });
|
|
3130
|
+
if (config.logging) {
|
|
3131
|
+
console.log("[HMR] WebSocket server initialized");
|
|
3132
|
+
}
|
|
3133
|
+
wss.on("connection", (ws, req) => {
|
|
3134
|
+
wsClients.add(ws);
|
|
3135
|
+
const message = { type: "connected", timestamp: Date.now() };
|
|
3136
|
+
ws.send(JSON.stringify(message));
|
|
3137
|
+
if (config.logging) {
|
|
3138
|
+
console.log("[HMR] Client connected from", req.socket.remoteAddress);
|
|
3139
|
+
}
|
|
3140
|
+
ws.on("message", (data) => {
|
|
3141
|
+
try {
|
|
3142
|
+
const msg = JSON.parse(data.toString());
|
|
3143
|
+
if (msg.type === "state:subscribe") {
|
|
3144
|
+
stateManager.subscribe(msg.key, ws);
|
|
3145
|
+
if (config.logging) {
|
|
3146
|
+
console.log(`[State] Client subscribed to "${msg.key}"`);
|
|
3147
|
+
}
|
|
3148
|
+
} else if (msg.type === "state:unsubscribe") {
|
|
3149
|
+
stateManager.unsubscribe(msg.key, ws);
|
|
3150
|
+
if (config.logging) {
|
|
3151
|
+
console.log(`[State] Client unsubscribed from "${msg.key}"`);
|
|
3152
|
+
}
|
|
3153
|
+
} else if (msg.type === "state:change") {
|
|
3154
|
+
stateManager.handleStateChange(msg.key, msg.value);
|
|
3155
|
+
if (config.logging) {
|
|
3156
|
+
console.log(`[State] Client updated "${msg.key}"`);
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
} catch (error) {
|
|
3160
|
+
if (config.logging) {
|
|
3161
|
+
console.error("[WebSocket] Message parse error:", error);
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
});
|
|
3165
|
+
ws.on("close", () => {
|
|
3166
|
+
wsClients.delete(ws);
|
|
3167
|
+
stateManager.unsubscribeAll(ws);
|
|
3168
|
+
if (config.logging) {
|
|
3169
|
+
console.log("[HMR] Client disconnected");
|
|
3170
|
+
}
|
|
3171
|
+
});
|
|
3172
|
+
});
|
|
3173
|
+
const watchPaths = normalizedClients.flatMap(
|
|
3174
|
+
(client) => config.watch.map((pattern) => join(client.root, pattern))
|
|
3175
|
+
);
|
|
3176
|
+
const watcher = watch(watchPaths, {
|
|
3177
|
+
ignored: (path) => config.ignore.some((pattern) => path.includes(pattern.replace("/**", "").replace("**/", ""))),
|
|
3178
|
+
ignoreInitial: true,
|
|
3179
|
+
persistent: true
|
|
3180
|
+
});
|
|
3181
|
+
watcher.on("change", (path) => {
|
|
3182
|
+
if (config.logging) console.log(`[HMR] File changed: ${path}`);
|
|
3183
|
+
const message = JSON.stringify({ type: "update", path, timestamp: Date.now() });
|
|
3184
|
+
wsClients.forEach((client) => client.readyState === 1 /* OPEN */ && client.send(message));
|
|
3185
|
+
});
|
|
3186
|
+
watcher.on("add", (path) => config.logging && console.log(`[HMR] File added: ${path}`));
|
|
3187
|
+
watcher.on("unlink", (path) => config.logging && console.log(`[HMR] File removed: ${path}`));
|
|
3188
|
+
server.setMaxListeners(20);
|
|
3189
|
+
server.listen(config.port, config.host, () => {
|
|
3190
|
+
if (config.logging) {
|
|
3191
|
+
console.log("\n\u{1F680} Elit Dev Server");
|
|
3192
|
+
console.log(`
|
|
3193
|
+
\u279C Local: http://${config.host}:${config.port}`);
|
|
3194
|
+
if (normalizedClients.length > 1) {
|
|
3195
|
+
console.log(` \u279C Clients:`);
|
|
3196
|
+
normalizedClients.forEach((client) => {
|
|
3197
|
+
const clientUrl = `http://${config.host}:${config.port}${client.basePath}`;
|
|
3198
|
+
console.log(` - ${clientUrl} \u2192 ${client.root}`);
|
|
3199
|
+
});
|
|
3200
|
+
} else {
|
|
3201
|
+
const client = normalizedClients[0];
|
|
3202
|
+
console.log(` \u279C Root: ${client.root}`);
|
|
3203
|
+
if (client.basePath) {
|
|
3204
|
+
console.log(` \u279C Base: ${client.basePath}`);
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
console.log(`
|
|
3208
|
+
[HMR] Watching for file changes...
|
|
3209
|
+
`);
|
|
3210
|
+
}
|
|
3211
|
+
if (config.open && normalizedClients.length > 0) {
|
|
3212
|
+
const firstClient = normalizedClients[0];
|
|
3213
|
+
const url = `http://${config.host}:${config.port}${firstClient.basePath}`;
|
|
3214
|
+
const open = async () => {
|
|
3215
|
+
const { default: openBrowser } = await import("open");
|
|
3216
|
+
await openBrowser(url);
|
|
3217
|
+
};
|
|
3218
|
+
open().catch(() => {
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
});
|
|
3222
|
+
let isClosing = false;
|
|
3223
|
+
const close = async () => {
|
|
3224
|
+
if (isClosing) return;
|
|
3225
|
+
isClosing = true;
|
|
3226
|
+
if (config.logging) console.log("\n[Server] Shutting down...");
|
|
3227
|
+
await watcher.close();
|
|
3228
|
+
wss.close();
|
|
3229
|
+
wsClients.forEach((client) => client.close());
|
|
3230
|
+
wsClients.clear();
|
|
3231
|
+
return new Promise((resolve2) => {
|
|
3232
|
+
server.close(() => {
|
|
3233
|
+
if (config.logging) console.log("[Server] Closed");
|
|
3234
|
+
resolve2();
|
|
3235
|
+
});
|
|
3236
|
+
});
|
|
3237
|
+
};
|
|
3238
|
+
const primaryClient = normalizedClients[0];
|
|
3239
|
+
const primaryUrl = `http://${config.host}:${config.port}${primaryClient.basePath}`;
|
|
3240
|
+
return {
|
|
3241
|
+
server,
|
|
3242
|
+
wss,
|
|
3243
|
+
url: primaryUrl,
|
|
3244
|
+
state: stateManager,
|
|
3245
|
+
close
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3249
|
+
0 && (module.exports = {
|
|
3250
|
+
ServerRouter,
|
|
3251
|
+
SharedState,
|
|
3252
|
+
StateManager,
|
|
3253
|
+
bodyLimit,
|
|
3254
|
+
cacheControl,
|
|
3255
|
+
compress,
|
|
3256
|
+
cors,
|
|
3257
|
+
createDevServer,
|
|
3258
|
+
createProxyHandler,
|
|
3259
|
+
errorHandler,
|
|
3260
|
+
html,
|
|
3261
|
+
json,
|
|
3262
|
+
logger,
|
|
3263
|
+
rateLimit,
|
|
3264
|
+
security,
|
|
3265
|
+
status,
|
|
3266
|
+
text
|
|
3267
|
+
});
|