lacis 0.3.0 → 0.3.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.
@@ -1,4 +1,4 @@
1
- import { i as Adapter } from '../index-CnWzo9eB.js';
1
+ import { k as Adapter } from '../index-BPqzMBG-.js';
2
2
  import 'http';
3
3
 
4
4
  declare const nodeAdapter: Adapter;
@@ -1 +1 @@
1
- export{J as bunAdapter,K as getAdapter,I as netlifyAdapter,G as nodeAdapter,H as vercelAdapter}from'../chunk-CZJALK6N.js';
1
+ export{O as bunAdapter,P as getAdapter,N as netlifyAdapter,L as nodeAdapter,M as vercelAdapter}from'../chunk-PV6YEQ6J.js';
@@ -0,0 +1,26 @@
1
+ import G,{join}from'path';import Ge from'fs/promises';import {existsSync}from'fs';import J from'cluster';import be,{IncomingMessage,ServerResponse}from'http';import lt from'https';import*as _ from'os';import ___default from'os';import {EventEmitter}from'events';import {Socket}from'net';var A={beforeRequest:[],afterRequest:[],onError:[]},B={onNotFound:[],onShutdown:[]},P=new Map,I=new Map;function pe(t,e){return A[t].push(e),{remove:()=>{let r=A[t].indexOf(e);r!==-1&&A[t].splice(r,1);}}}function He(t,e,r,o){return t.has(e)||t.set(e,{beforeRequest:[],afterRequest:[],onError:[]}),t.get(e)[r].push(o),{remove:()=>{let n=t.get(e);if(!n)return;let s=n[r].indexOf(o);s!==-1&&n[r].splice(s,1);}}}function Ke(t,e,r){return He(P,t==="/"?"/":t.replace(/\/+$/,""),e,r)}function Qe(t,e,r){return He(I,t==="/"?"/":t.replace(/\/+$/,""),e,r)}function ee(t,e,r){let o=t.get(e);o&&(r.beforeRequest.push(...o.beforeRequest),r.afterRequest.push(...o.afterRequest),r.onError.push(...o.onError));}function Xe(t){let e=t==="/"?"/":t.replace(/\/+$/,""),r=e.split("/").filter(Boolean),o={beforeRequest:[...A.beforeRequest],afterRequest:[...A.afterRequest],onError:[...A.onError]};ee(P,"/",o),e==="/"&&ee(I,"/",o);let n="";for(let s of r)n+="/"+s,ee(P,n,o),n===e&&ee(I,n,o);return o}function H(){return A.beforeRequest.length>0||A.afterRequest.length>0||A.onError.length>0||P.size>0||I.size>0}async function T(t,e,r,o){let n=e.url?.split("?")[0]||"/",s=Xe(n);if(s[t].length===0)return true;for(let i of s[t])try{if(await i(e,r,o)===!1)return !1}catch(l){if(t!=="onError")try{for(let a of s.onError)await a(e,r,{error:l,phase:t});}catch(a){console.error("Error in error handler:",a);}return false}return true}function Ye(t,e,r){e.has(r)||e.set(r,{beforeRequest:[],afterRequest:[],onError:[]});let o=e.get(r);for(let n of ["beforeRequest","afterRequest","onError"])if(t[n]){let s=Array.isArray(t[n])?t[n]:[t[n]];o[n].push(...s);}}async function me(t){P.clear(),I.clear();async function e(r,o=""){try{let n=await Ge.readdir(r,{withFileTypes:!0});for(let[s,i]of [["+middleware.global.ts",P],["+middleware.global.js",P],["+middleware.ts",I],["+middleware.js",I]]){let l=n.find(a=>a.name===s);if(l)try{let c=await import(`${G.resolve(G.join(r,l.name))}?update=${Date.now()}`);Ye(c,i,o);}catch(a){console.error(`Error loading middleware for ${o}:`,a);}}for(let s of n)s.isDirectory()&&await e(G.join(r,s.name),`${o==="/"?"":o}/${s.name}`);}catch(n){console.error(`Error scanning directory ${r}:`,n);}}await e(t,"/");}function Mt(){return P}function V(t){if(t?.length)for(let e of t){let r=e.type==="cascade"?Ke:Qe;for(let o of ["beforeRequest","afterRequest","onError"]){let n=e.module[o];if(!n)continue;let s=Array.isArray(n)?n:[n];for(let i of s)r(e.path,o,i);}}}function j(t){t&&(t.onNotFound&&B.onNotFound.push(t.onNotFound),t.onShutdown&&B.onShutdown.push(t.onShutdown));}function L(){return B.onNotFound.length>0}async function N(t,e){for(let r of B.onNotFound)if(await r(t,e),e.headersSent)return}async function kt(){for(let t of B.onShutdown)try{await t();}catch(e){console.error("Error in onShutdown hook:",e);}}function xt(){A.beforeRequest=[],A.afterRequest=[],A.onError=[],P.clear(),I.clear(),B.onNotFound=[],B.onShutdown=[];}function F(t){if(t)for(let e of ["beforeRequest","afterRequest","onError"]){let r=t[e];if(r){let o=Array.isArray(r)?r:[r];for(let n of o)pe(e,n);}}}function Ze(t,e){return !e||e==="*"?true:typeof e=="string"?t===e:Array.isArray(e)?e.includes(t):e instanceof RegExp?e.test(t):typeof e=="function"?e(t):false}function et(t){let e=(t.methods??["GET","POST","PUT","DELETE","PATCH","OPTIONS"]).join(", "),r=(t.allowedHeaders??["Content-Type","Authorization"]).join(", "),o=t.exposedHeaders?.join(", "),n=t.maxAge!=null?String(t.maxAge):null,s=!t.origin||t.origin==="*";return async(i,l)=>{let a=i.getHeader("origin");if(!a||!Ze(a,t.origin))return;let c=s&&!t.credentials;if(l.setHeader("Access-Control-Allow-Origin",c?"*":a),c||l.setHeader("Vary","Origin"),t.credentials&&l.setHeader("Access-Control-Allow-Credentials","true"),o&&l.setHeader("Access-Control-Expose-Headers",o),i.method==="OPTIONS")return l.setHeader("Access-Control-Allow-Methods",e),l.setHeader("Access-Control-Allow-Headers",r),n&&l.setHeader("Access-Control-Max-Age",n),l.status(204),l.end(),false}}function U(t){t&&pe("beforeRequest",et(t));}function R(...t){J.isPrimary&&console.log(...t);}function ot(t){let e=t.match(/^\[(\w+)(\??)]/);return e?{name:e[1],isParam:true,isOptional:e[2]==="?"}:{name:t,isParam:false,isOptional:false}}var at=1e3,it=100,ge=class{rootNode;cachedRoutes;routeCount;lastLoaded;verbose;constructor(){this.rootNode=this.createNode(),this.cachedRoutes=new Map,this.routeCount=0,this.lastLoaded=0,this.verbose=false;}createNode(){return {handlers:Object.create(null),staticChildren:new Map,paramChild:null,wildcardHandler:null,isEndpoint:false}}addRoute(e,r,o){let n=r.split("/").filter(Boolean),s=this.rootNode;for(let i of n){let l=ot(i);if(l.isParam){if(!s.paramChild)s.paramChild={name:l.name,node:this.createNode(),isOptional:l.isOptional};else if(s.paramChild.name!==l.name)throw new Error(`Route conflict: param name "[${l.name}]" conflicts with existing "[${s.paramChild.name}]" at the same path position. Use the same param name for all methods at this level.`);s=s.paramChild.node;}else {if(i==="*")return s.wildcardHandler||(s.wildcardHandler=Object.create(null)),s.wildcardHandler[e]=o,this.cachedRoutes.clear(),this;s.staticChildren.has(i)||s.staticChildren.set(i,this.createNode()),s=s.staticChildren.get(i);}}return s.isEndpoint=true,s.handlers[e]||this.routeCount++,s.handlers[e]=o,this.cachedRoutes.clear(),this}findRoute(e,r){let o=r==="/"?"/":r.replace(/\/+$/,""),n=e+":"+o,s=this.cachedRoutes.get(n);if(s)return this.cachedRoutes.delete(n),this.cachedRoutes.set(n,s),s;let i=o==="/"?[]:o.split("/").filter(Boolean),l=Object.create(null),a=this.traverse(this.rootNode,i,e,l,0)??{handler:null,params:Object.create(null)};if(a.handler!==null||a.allowedMethods?.length){if(this.cachedRoutes.size>=at){let c=0;for(let u of this.cachedRoutes.keys())if(this.cachedRoutes.delete(u),++c>=it)break}this.cachedRoutes.set(n,a);}return a}traverse(e,r,o,n,s){if(s===r.length){if(e.isEndpoint){let c=e.handlers[o]??(o==="HEAD"?e.handlers.GET:void 0)??e.handlers[""];if(c)return {handler:c,params:Object.assign(Object.create(null),n)};let u=Object.keys(e.handlers).filter(p=>p!=="");return {handler:null,params:Object.create(null),allowedMethods:u}}let a=e.paramChild;if(a?.isOptional&&a.node.isEndpoint){let c=a.node.handlers[o]??(o==="HEAD"?a.node.handlers.GET:void 0)??a.node.handlers[""];if(c)return {handler:c,params:Object.assign(Object.create(null),n)}}return null}let i=r[s],l=e.staticChildren.get(i);if(l){let a=this.traverse(l,r,o,n,s+1);if(a)return a}if(e.paramChild){let{name:a,node:c}=e.paramChild;n[a]=i;let u=this.traverse(c,r,o,n,s+1);if(u)return u;delete n[a];}if(e.wildcardHandler){let a=e.wildcardHandler[o]??e.wildcardHandler[""],c=r.slice(s).join("/");if(a)return {handler:a,params:Object.assign(Object.create(null),n,{"*":c})};let u=Object.keys(e.wildcardHandler).filter(p=>p!=="");if(u.length>0)return {handler:null,params:Object.assign(Object.create(null),n,{"*":c}),allowedMethods:u}}return null}async loadRoutes(e){this.rootNode=this.createNode(),this.cachedRoutes.clear(),this.routeCount=0,await me(e);let r=this;async function o(n,s=[]){try{let i=await Ge.readdir(n,{withFileTypes:!0}),l=i.find(a=>!a.isDirectory()&&(a.name==="index.ts"||a.name==="index.js"));if(l)try{let c=await import(`${G.resolve(G.join(n,l.name))}?update=${Date.now()}`),u=["GET","POST","PUT","DELETE","PATCH"],p="/"+s.join("/"),g=!1;for(let w of u)typeof c[w]=="function"&&(r.addRoute(w,p,c[w]),g=!0);!g&&typeof c.default=="function"&&r.addRoute("GET",p,c.default),r.verbose&&R(`Route loaded: ${p}`);}catch(a){console.error(`Error loading index in ${n}:`,a);}for(let a of i)if(a.isDirectory()){let c=a.name.match(/^\[(\w+)(\??)]/),u=c?`[${c[1]}${c[2]}]`:a.name;await o(G.join(n,a.name),[...s,u]);}}catch(i){console.error(`Error scanning directory ${n}:`,i);}}return await o(e),this.lastLoaded=Date.now(),this.verbose&&R(`Loading completed: ${this.routeCount} routes`),true}getRoutes(){let e=[];return this.collectRoutes(this.rootNode,[],e),e}collectRoutes(e,r,o){if(e.isEndpoint){let n=r.length===0?"/":"/"+r.join("/");for(let[s,i]of Object.entries(e.handlers))s!==""&&o.push({method:s,path:n,handler:i});}for(let[n,s]of e.staticChildren)this.collectRoutes(s,[...r,n],o);if(e.paramChild){let{name:n,isOptional:s,node:i}=e.paramChild;this.collectRoutes(i,[...r,s?`:${n}?`:`:${n}`],o);}if(e.wildcardHandler){let n="/"+[...r,"*"].join("/");for(let[s,i]of Object.entries(e.wildcardHandler))s!==""&&o.push({method:s,path:n,handler:i});}}getStats(){return {routeCount:this.routeCount,lastLoaded:this.lastLoaded,uptime:Date.now()-this.lastLoaded,cacheSize:this.cachedRoutes.size}}setVerbose(e){return this.verbose=e,this}reset(){this.rootNode=this.createNode(),this.cachedRoutes=new Map,this.routeCount=0;}},W=new ge;function te(t){return t&&typeof t=="object"&&"error"in t}function Q(t){for(let{path:e,handlers:r}of t){let o=e.replace(/:(\w+\??)/g,(n,s)=>s.endsWith("?")?`[${s.slice(0,-1)}?]`:`[${s}]`);for(let[n,s]of Object.entries(r))typeof s=="function"&&W.addRoute(n,o,s);}}async function re(t){let e=join(t,"_manifest.js");if(existsSync(e)){W.reset();let r=await import(e);Q(r.routes),r.middlewares?V(r.middlewares):await me(t);return}return W.loadRoutes(t)}function D(t,e="GET"){let r=W.findRoute(e,t);return r.handler?{handler:r.handler,params:r.params}:r.allowedMethods?.length?{error:"Method Not Allowed",status:405,allowedMethods:r.allowedMethods}:null}function Nt(t){let e=process.env.NODE_ENV==="production",r=process.env.ROUTES_DIR??t??(e?"dist/routes":"routes"),o=e&&!G.isAbsolute(r)&&!r.startsWith("dist/")?G.join("dist",r):r;return G.resolve(process.cwd(),o)}function Ft(){return W.getStats()}function Ut(t){W.setVerbose(t);}function Dt(){W.reset();}function Te(t,e={},r={},o){let n=false,s=0,i={},l=[],a=[],c=[],u=null;r.onMessage&&l.push(r.onMessage),r.onClose&&a.push(r.onClose),r.onError&&c.push(r.onError),r.onEvent&&Object.entries(r.onEvent).forEach(([f,m])=>{i[f]||(i[f]=[]),i[f].push(m);});let p=e.reconnectInterval||3e3,g=e.maxRetries||3,w=e.disableReconnect||false,y=e.body,h=e.contentType||(y?"application/json":void 0),d=e.method||(y?"POST":"GET");if(typeof t!="string"){let f=t;return n=true,f.on("data",m=>{v(m.toString());}),f.on("end",()=>{n=false;}),f.on("error",m=>{n=false,console.error("SSE Error:",m);}),b()}if(typeof t=="string")return new Promise((f,m)=>{$().then(()=>f(b())).catch(m);});function v(f){let m=f,S=m.split(`
2
+
3
+ `);m=S.pop()||"";for(let M of S){let O=M.split(`
4
+ `),C="",E="";for(let x of O)x.startsWith("event:")?E=x.slice(6).trim():x.startsWith("data:")&&(C=x.slice(5).trim());if(C)try{let x=JSON.parse(C);E&&i[E]?i[E].forEach(K=>K(x)):l.forEach(K=>K(x));}catch{E&&i[E]?i[E].forEach(x=>x(C)):l.forEach(x=>x(C));}}}function b(){return {onMessage(f){return l.push(f),this},onEvent(f,m){return i[f]||(i[f]=[]),i[f].push(m),this},onClose(f){return a.push(f),this},close(){u&&(u.destroy(),u=null),n=false,a.forEach(f=>f());}}}async function $(){if(!n){n=true;try{await k();}catch(f){!w&&s<g?(s++,setTimeout(()=>{$();},p)):c.forEach(m=>m(f));}}}async function k(){return new Promise((f,m)=>{let S=new URL(t);e.params&&(typeof e.params=="object"?Object.entries(e.params).forEach(([C,E])=>{S.searchParams.append(C,String(E));}):typeof e.params=="string"&&new URLSearchParams(e.params).forEach((E,x)=>{S.searchParams.append(x,E);}));let M={hostname:S.hostname,port:S.port||(S.protocol==="https:"?443:80),path:S.pathname+S.search,method:d,headers:{Accept:"text/event-stream",...o?.headers||{},"Cache-Control":"no-cache",Connection:"keep-alive",...h&&{"Content-Type":h},...y&&typeof y=="string"&&{"Content-Length":Buffer.byteLength(y).toString()},...y&&typeof y!="string"&&{"Content-Length":Buffer.byteLength(JSON.stringify(y)).toString()}}};u=(S.protocol==="https:"?lt:be).request(M,C=>{if(C.statusCode!==200){n=false,m(new Error(`Server responded with status: ${C.statusCode}`));return}C.setEncoding("utf8"),C.on("data",v),C.on("end",()=>{n=false,u?.destroy(),u=null,a.forEach(E=>E()),f(null);}),C.on("close",()=>{n=false,u?.destroy(),u=null,a.forEach(E=>E()),f(null);}),C.on("error",E=>{n=false,u?.destroy(),u=null,a.forEach(x=>x()),m(E);});}),u.on("error",C=>{n=false,u?.destroy(),u=null,m(C);}),y&&(typeof y=="string"?u.write(y):u.write(JSON.stringify(y))),u.end();})}return b()}function _e(t,e){let r=e?.headers?.["Cache-Control"]||"no-cache",o=e?.headers?.Connection||"keep-alive",n=e?.timeout||3e5;t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":r,Connection:o,...e?.headers||{}});let s=setTimeout(()=>{t.end();},n);return t.on("close",()=>{clearTimeout(s);}),s}function Oe(t,e){return t.writableEnded?false:t.write(`data: ${e}
5
+
6
+ `)}function Ae(t,e){return t.writableEnded?false:t.write(`data: ${JSON.stringify(e)}
7
+
8
+ `)}function $e(t,e,r){return t.writableEnded?false:(t.write(`event: ${e}
9
+ `),t.write(`data: ${JSON.stringify(r)}
10
+
11
+ `))}function Pe(t,e){return t.writableEnded?false:t.write(`: ${e}
12
+
13
+ `)}function qe(t,e){return t.writableEnded?false:t.write(`id: ${e}
14
+
15
+ `)}function Ie(t,e){return t.writableEnded?false:t.write(`retry: ${e}
16
+
17
+ `)}function je(t,e="Connection closed"){t.write(`: ${e}
18
+
19
+ `),t.end();}function Le(t,e,r,o=500,n){t.writeHead(o,{"Content-Type":"text/event-stream"}),t.write(`event: ${e}
20
+ `);let s={message:r,code:o,details:n||null};t.write(`data: ${JSON.stringify(s)}
21
+
22
+ `),t.end();}var ut=10485760,ne=class{_parsed=null;_raw;constructor(e){this._raw=e;}_parse(){if(this._parsed!==null)return this._parsed;if(this._parsed={},!this._raw)return this._parsed;for(let e of this._raw.split(";")){let r=e.indexOf("=");if(r===-1)continue;let o=e.slice(0,r).trim(),n=e.slice(r+1).trim();if(o){let s=n.startsWith('"')&&n.endsWith('"')?n.slice(1,-1):n;try{this._parsed[o]=decodeURIComponent(s);}catch{this._parsed[o]=s;}}}return this._parsed}get(e){return this._parse()[e]}all(){return {...this._parse()}}},oe=class{_pending=[];set(e,r,o={}){return this._pending.push({name:e,value:r,opts:o}),this}delete(e,r={}){return this.set(e,"",{...r,maxAge:0,expires:new Date(0)})}serialize(){return this._pending.map(({name:e,value:r,opts:o})=>{let n=`${e}=${encodeURIComponent(r)}`,s=o.path!==void 0?o.path:"/";return s&&(n+=`; Path=${s}`),o.domain&&(n+=`; Domain=${o.domain}`),o.maxAge!=null&&(n+=`; Max-Age=${o.maxAge}`),o.expires&&(n+=`; Expires=${o.expires.toUTCString()}`),o.httpOnly&&(n+="; HttpOnly"),o.secure&&(n+="; Secure"),o.sameSite&&(n+=`; SameSite=${o.sameSite}`),n})}};function Ne(t){if(typeof t.get=="function")return t.get("cookie")??void 0;let e=t.cookie;return Array.isArray(e)?e.join("; "):e}function X(t){return class extends t{_zreqCookies;getHeader(e){let r=this.headers;if(typeof r.get=="function")return r.get(e)??void 0;let o=r[e.toLowerCase()];return Array.isArray(o)?o[0]:o}get cookies(){return this._zreqCookies||(this._zreqCookies=new ne(Ne(this.headers))),this._zreqCookies}json(){return this.body().then(e=>JSON.parse(e.toString()))}form(){return new Promise((e,r)=>{let o=this.headers,n=typeof o.get=="function"?o.get("content-type")??"":o["content-type"]??"";if(!n.startsWith("multipart/form-data")){r(new Error("Content-Type is not multipart/form-data"));return}let s=n.match(/boundary=(.+)$/);if(!s){r(new Error("Boundary not found"));return}let i=s[1].trim();this.body().then(l=>{let a={},c=Buffer.from(`--${i}`),u=[],p=0,g;for(;(g=l.indexOf(c,p))!==-1;)u.push(l.subarray(p,g)),p=g+c.length;u.push(l.subarray(p));for(let w=1;w<u.length-1;w++){let y=u[w].subarray(2),h=y.indexOf(`\r
23
+ \r
24
+ `);if(h===-1)continue;let d=y.subarray(0,h).toString(),v=y.subarray(h+4,y.length-2),b=d.match(/Content-Disposition: form-data; name="([^"]+)"(?:; filename="([^"]+)")?/i);if(b)if(b[2]){let $=d.match(/Content-Type:\s*([^\r\n]+)/i);a[b[1]]={filename:b[2],mimetype:$?$[1].trim():"application/octet-stream",data:v,size:v.length};}else a[b[1]]=v.toString("utf-8");}e(a);}).catch(r);})}createSSEClient(e,r){return Te(this,e,r)}}}function ae(){let t=[],e=0,r=false;return new Promise((o,n)=>{this.on("data",s=>{if(e+=s.length,e>ut){r=true,this.destroy(),n(Object.assign(new Error("Payload Too Large"),{code:413}));return}t.push(s);}).on("end",()=>{r||(r=true,o(Buffer.concat(t)));}).on("error",s=>{r||(r=true,n(s));});})}function Fe(t,e){let r=t.serialize();r.length>0&&!e.headersSent&&e.setHeader("Set-Cookie",r);}function Y(t){return class extends t{_zresCookies;get cookies(){return this._zresCookies||(this._zresCookies=new oe),this._zresCookies}end(e){return this._zresCookies&&Fe(this._zresCookies,this),super.end(e)}status(e){return this.statusCode=e,this}send(e){return typeof e=="string"?(this.setHeader("Content-Type","text/plain"),this.end(e)):this.json(e),this}json(e){return this.setHeader("Content-Type","application/json"),this.end(JSON.stringify(e)),this}html(e){return this.setHeader("Content-Type","text/html; charset=utf-8"),this.end(e),this}redirect(e,r=302){return this.statusCode=r,this.setHeader("Location",e),this.end(),this}initSSE(e){return _e(this,e)}sseSend(e){Oe(this,e);}sseJson(e){Ae(this,e);}sseEvent(e,r){$e(this,e,r);}sseComment(e){Pe(this,e);}sseId(e){qe(this,e);}sseRetry(e){Ie(this,e);}sseClose(e){je(this,e);}sseError(e,r,o=500,n){Le(this,e,r,o,n);}}}var ye=class{params={};headers={};body(){return ae.call(this)}},se=X(ye).prototype,we=class{statusCode=200;headersSent=false;setHeader(e,r){}end(e){}write(e){}},ct=Y(we).prototype;function ie(t){t.body=ae,t.json=se.json,t.form=se.form,t.getHeader=se.getHeader,t.createSSEClient=se.createSSEClient,t.cookies=new ne(Ne(t.headers));}function de(t){let e=t.indexOf("?");return e===-1?t:t.slice(0,e)}function le(t){let e=t.indexOf("?");return e===-1?{}:Object.fromEntries(new URLSearchParams(t.slice(e+1)).entries())}async function q(t,e,r){console.error("[lacis] Unhandled error:",r),H()&&await T("onError",t,e,{error:r});}function ue(t){let e=ct;t.status=e.status,t.send=e.send,t.json=e.json,t.html=e.html,t.redirect=e.redirect,t.initSSE=e.initSSE,t.sseSend=e.sseSend,t.sseJson=e.sseJson,t.sseEvent=e.sseEvent,t.sseComment=e.sseComment,t.sseId=e.sseId,t.sseRetry=e.sseRetry,t.sseClose=e.sseClose,t.sseError=e.sseError;let r=new oe;t.cookies=r;let o=t.end.bind(t);t.end=function(...n){return Fe(r,this),o(...n)};}var ce=null;function ht(t={}){let e=new EventEmitter,r={sampleInterval:t.sampleInterval||5e3,reportInterval:t.reportInterval||6e4,resetInterval:t.resetInterval||1440*60*1e3,enableHistogram:t.enableHistogram!==void 0?t.enableHistogram:true,logToConsole:t.logToConsole!==void 0?t.logToConsole:true,thresholds:{cpu:t.thresholds?.cpu||80,memory:t.thresholds?.memory||80,responseTime:t.thresholds?.responseTime||1e3,errorRate:t.thresholds?.errorRate||5}},o=Date.now(),n={requestCount:0,activeRequests:0,errorCount:0,responseTimes:[],responseTimesBucket:Array(100).fill(0),statusCodes:{},lastReport:o,lastReset:o},s=c(),i=[],l=process.cpuUsage(),a={cpu:false,memory:false,responseTime:false,errorRate:false};function c(){return {timestamp:Date.now(),uptime:process.uptime(),requestCount:0,activeRequests:0,errorCount:0,responseTimes:{min:0,max:0,avg:0,count:0,sum:0},statusCodes:{},memory:process.memoryUsage(),cpu:{usage:0,system:0,user:0},systemLoad:_.loadavg(),systemMemory:{total:_.totalmem(),free:_.freemem(),used:_.totalmem()-_.freemem()}}}function u(){let f=n.responseTimes;if(f.length===0)return {min:0,max:0,avg:0,count:0,sum:0};let m=1/0,S=-1/0,M=0;for(let E of f)m=Math.min(m,E),S=Math.max(S,E),M+=E;let O=M/f.length,C={min:m,max:S,avg:O,count:f.length,sum:M};if(r.enableHistogram){let E=[...f].sort((x,K)=>x-K);C.p50=E[Math.floor(E.length*.5)],C.p90=E[Math.floor(E.length*.9)],C.p99=E[Math.floor(E.length*.99)];}return C}function p(){let f=Date.now(),m=process.uptime(),S=process.memoryUsage(),M=process.cpuUsage(l);l=process.cpuUsage();let C=(M.user+M.system)/1e3/r.sampleInterval*100;s={timestamp:f,uptime:m,requestCount:n.requestCount,activeRequests:n.activeRequests,errorCount:n.errorCount,responseTimes:u(),statusCodes:{...n.statusCodes},memory:S,cpu:{usage:C,system:M.system,user:M.user},systemLoad:_.loadavg(),systemMemory:{total:_.totalmem(),free:_.freemem(),used:_.totalmem()-_.freemem()}},i.push({...s}),i.length>100&&i.shift(),y(),J.isWorker&&process.send&&process.send({type:"metrics",metrics:s});}function g(){if(!r.logToConsole||J.isPrimary===false)return;let f={rss:(s.memory.rss/1024/1024).toFixed(2),heapTotal:(s.memory.heapTotal/1024/1024).toFixed(2),heapUsed:(s.memory.heapUsed/1024/1024).toFixed(2)},m=Date.now()-n.lastReport,S=(s.requestCount/(m/1e3)).toFixed(2),M=s.requestCount?(s.errorCount/s.requestCount*100).toFixed(2):"0.00";R(`
25
+ \u{1F4CA} Server Performance Metrics \u{1F4CA}`),R(`Uptime: ${h(s.uptime)}`),R(`Load: ${s.systemLoad[0].toFixed(2)}, ${s.systemLoad[1].toFixed(2)}, ${s.systemLoad[2].toFixed(2)}`),R(`Requests: ${s.requestCount} total, ${S} req/sec`),R(`Active Requests: ${s.activeRequests}`),R(`Errors: ${s.errorCount} (${M}%)`),s.responseTimes.count>0&&(R(`Response Times: avg ${s.responseTimes.avg.toFixed(2)}ms, min ${s.responseTimes.min}ms, max ${s.responseTimes.max}ms`),s.responseTimes.p50&&R(`Response Time Percentiles: p50 ${s.responseTimes.p50}ms, p90 ${s.responseTimes.p90}ms, p99 ${s.responseTimes.p99}ms`)),R(`Memory: ${f.rss}MB (RSS), ${f.heapUsed}MB / ${f.heapTotal}MB (Heap)`),R(`CPU Usage: ${s.cpu.usage.toFixed(2)}%`),Object.keys(s.statusCodes).length>0&&(R("Status Codes:"),Object.entries(s.statusCodes).sort(([O],[C])=>parseInt(O)-parseInt(C)).forEach(([O,C])=>{R(` ${O}: ${C}`);})),R(""),n.lastReport=Date.now();}function w(){let f=Date.now();n.requestCount=0,n.activeRequests=0,n.errorCount=0,n.responseTimes=[],n.responseTimesBucket=Array(100).fill(0),n.statusCodes={},n.lastReport=f,n.lastReset=f,R("\u{1F504} Performance metrics have been reset");}function y(){let f=s.memory.heapUsed/s.memory.heapTotal*100,m=s.requestCount?s.errorCount/s.requestCount*100:0,S=s.responseTimes.avg;s.cpu.usage>r.thresholds.cpu&&!a.cpu?(a.cpu=true,e.emit("alarm","cpu",`High CPU usage: ${s.cpu.usage.toFixed(2)}%`)):s.cpu.usage<=r.thresholds.cpu&&a.cpu&&(a.cpu=false,e.emit("alarm-clear","cpu",`CPU usage returned to normal: ${s.cpu.usage.toFixed(2)}%`)),f>r.thresholds.memory&&!a.memory?(a.memory=true,e.emit("alarm","memory",`High memory usage: ${f.toFixed(2)}%`)):f<=r.thresholds.memory&&a.memory&&(a.memory=false,e.emit("alarm-clear","memory",`Memory usage returned to normal: ${f.toFixed(2)}%`)),S>r.thresholds.responseTime&&!a.responseTime?(a.responseTime=true,e.emit("alarm","responseTime",`High response time: ${S.toFixed(2)}ms`)):S<=r.thresholds.responseTime&&a.responseTime&&(a.responseTime=false,e.emit("alarm-clear","responseTime",`Response time returned to normal: ${S.toFixed(2)}ms`)),m>r.thresholds.errorRate&&!a.errorRate?(a.errorRate=true,e.emit("alarm","errorRate",`High error rate: ${m.toFixed(2)}%`)):m<=r.thresholds.errorRate&&a.errorRate&&(a.errorRate=false,e.emit("alarm-clear","errorRate",`Error rate returned to normal: ${m.toFixed(2)}%`));}function h(f){let m=Math.floor(f/86400),S=Math.floor(f%86400/3600),M=Math.floor(f%3600/60),O=Math.floor(f%60),C=[];return m>0&&C.push(`${m}d`),S>0&&C.push(`${S}h`),M>0&&C.push(`${M}m`),(O>0||C.length===0)&&C.push(`${O}s`),C.join(" ")}function d(){let f=setInterval(p,r.sampleInterval),m=setInterval(g,r.reportInterval),S=setInterval(w,r.resetInterval);return {stop:()=>{clearInterval(f),clearInterval(m),clearInterval(S);}}}function v(){let f=Date.now();return n.activeRequests++,{end:(m,S=false)=>{let M=Date.now()-f;return n.activeRequests--,n.requestCount++,n.responseTimes.push(M),n.responseTimes.length>1e3&&n.responseTimes.shift(),n.statusCodes[m]=(n.statusCodes[m]||0)+1,(S||m>=500)&&n.errorCount++,M}}}function b(){return !Object.values(a).some(f=>f)}function $(){let f=s.memory.heapUsed/s.memory.heapTotal*100,m=s.requestCount?s.errorCount/s.requestCount*100:0;return {status:b()?"healthy":"unhealthy",uptime:s.uptime,responseTimes:{avg:s.responseTimes.avg,p90:s.responseTimes.p90||null,p99:s.responseTimes.p99||null},memory:{usedMB:Math.round(s.memory.heapUsed/1024/1024),totalMB:Math.round(s.memory.heapTotal/1024/1024),percent:f.toFixed(2)},cpu:s.cpu.usage.toFixed(2),requests:{total:s.requestCount,active:s.activeRequests,errors:s.errorCount,errorRate:m.toFixed(2)},alerts:Object.entries(a).filter(([S,M])=>M).map(([S])=>S)}}let k=d();return {trackRequest:v,getMetrics:()=>({...s}),getMetricsHistory:()=>[...i],getHealthMetrics:$,isHealthy:b,stop:k.stop,on:e.on.bind(e),once:e.once.bind(e),off:e.off.bind(e)}}function De(t){if(!ce){let e=ht(t),r=e.stop;e.stop=()=>{r(),ce=null;},ce=e;}return ce}function Re(t={}){let e=t.reportInterval??5e3,r={workers:new Map,workerIds:[]};function o(){if(!J.isWorker)return;let c=process.cpuUsage(),u=()=>{if(!process.send)return;let p=process.memoryUsage(),g=process.cpuUsage(c);c=process.cpuUsage();let w=(g.user+g.system)/(e*1e3),y={type:"stats",stats:{pid:process.pid,load:w,lastUsed:Date.now(),memoryUsage:p}};process.send(y);};u(),setInterval(u,e).unref();}function n(){let c=J.fork();r.workers.set(c.id,{pid:c.process.pid,load:0,lastUsed:Date.now(),memoryUsage:{rss:0,heapTotal:0,heapUsed:0,external:0,arrayBuffers:0}}),r.workerIds.push(c.id),R(`Worker ${c.process.pid} started`);}let s=false,i=[];function l(c=_.cpus().length){if(!J.isPrimary)return o();R(`\u{1F9F5} Launching ${c} workers...`);for(let u=0;u<c;u++)n();J.on("message",(u,p)=>{if(p.type==="stats"&&"stats"in p){let g=r.workers.get(u.id);g&&Object.assign(g,p.stats);}}),J.on("exit",(u,p,g)=>{if(r.workers.delete(u.id),r.workerIds=r.workerIds.filter(w=>w!==u.id),s){i.forEach(w=>w());return}R(`Worker ${u.process.pid} died (${g||p}). Restarting...`),setTimeout(()=>n(),1e3);});}function a(c){s=true;let u=Object.keys(J.workers??{});if(u.length===0){c?.();return}let p=u.length;i.push(()=>{p--,p===0&&c?.();});for(let g of u)J.workers?.[g]?.kill();}return {start:l,shutdown:a,getWorkerStats:()=>Array.from(r.workers.entries()),getActiveWorkerCount:()=>r.workerIds.length}}var Ce=class extends be.IncomingMessage{params={};body=ae},Se=class extends X(Ce){},ve=class extends Y(be.ServerResponse){},We={name:"node",createHandler:t=>{if(typeof t!="string")throw new Error("nodeAdapter requires a routesDir string, not a ServerlessConfig.");let e=t;return async(r={})=>{let{port:o=3e3,defaultHeaders:n,isDev:s,cluster:i,monitoring:l={enabled:false}}=r,a=null;s&&l.enabled&&(a=De({sampleInterval:l.sampleInterval||5e3,reportInterval:l.reportInterval||6e4,thresholds:l.thresholds,logToConsole:true}),J.isPrimary&&(R("\u{1F4CA} Development performance monitoring enabled"),a.on("alarm",(u,p)=>{R(`\u26A0\uFE0F ALERT: ${p}`);}),a.on("alarm-clear",(u,p)=>{R(`\u2705 RESOLVED: ${p}`);})));let c=n?Object.entries(n):[];if(i?.enabled&&J.isPrimary){let u=i.workers??___default.cpus().length,p=r.httpsOptions?"https":"http";if(R(`\u{1F9F5} Starting server with ${u} workers`),J.schedulingPolicy!==void 0)try{J.schedulingPolicy=J.SCHED_RR;}catch{}let g=Re();return g.start(u),R(`\u{1F680} Server running at ${p}://localhost:${o}/`+(s?" (dev)":"")),s&&a&&R(`\u{1F4CA} Performance monitoring available at http://localhost:${o}/health`),{close:w=>{a&&a.stop(),g.shutdown(w);}}}if(J.isWorker||!i?.enabled){r.routes||await re(e),U(r.cors),F(r.middleware),j(r.hooks);let u=async(h,d,v)=>{try{if(s&&a&&h.url==="/health"){d.setHeader("Content-Type","application/json"),d.end(JSON.stringify(a.getHealthMetrics())),v?.end(200);return}let b=h.url||"/",$=de(b);if(h.query=le(b),H()&&(await T("beforeRequest",h,d)===!1||d.headersSent)){v?.end(d.statusCode||204);return}let k=D($,h.method||"GET");if(!k){if(L()&&(await N(h,d),d.headersSent)){v?.end(d.statusCode);return}d.status(404).json({error:"Route not found"}),v?.end(404);return}if("error"in k){let f=k.status||500;d.status(f).json({error:k.error}),v?.end(f,!0);return}h.params=k.params,await k.handler(h,d),H()&&await T("afterRequest",h,d),d.headersSent||d.end(),v?.end(d.statusCode||200);}catch(b){await q(h,d,b),d.headersSent||d.status(500).json({error:"Internal Server Error"}),v?.end(d.statusCode||500,true);}},p=(h,d)=>{let v=s&&a?a.trackRequest():null;if(c.length>0)for(let b=0;b<c.length;b++)d.setHeader(c[b][0],c[b][1]);u(h,d,v).catch(b=>{s&&console.error("Fatal error:",b),d.headersSent||(d.statusCode=500,d.end("Server Error")),v?.end(500,true);});},g={IncomingMessage:Se,ServerResponse:ve},w=r.httpsOptions?lt.createServer({...g,...r.httpsOptions},p):be.createServer(g,p);w.on("clientError",(h,d)=>{d.destroyed||d.destroy();});let y=r.httpsOptions?"https":"http";return J.isWorker&&Re().start(),w.listen(o,()=>{i?.enabled?s&&R(`Worker ${process.pid} is listening on port ${o}`):(R(`\u{1F680} Server running at ${y}://localhost:${o}/`+(s?" (dev)":"")),s&&a&&R(`\u{1F4CA} Performance monitoring available at http://localhost:${o}/health`));}),w}return null}}};var Je={name:"vercel",createHandler:t=>{if(typeof t=="string")throw new Error("vercelAdapter.createHandler() requires a ServerlessConfig object, not a routesDir string. Import your routes manifest and pass { routes } instead.");let e=null,r=()=>e||(e=(async()=>{Q(t.routes),U(t.cors),F(t.middleware),V(t.middlewares),j(t.hooks);})(),e);return async(o,n)=>{await r(),ie(o),ue(n);let s=o,i=n;try{if(H()&&(await T("beforeRequest",s,i)===!1||i.headersSent))return;let l=D(de(s.url??"/"),s.method??"GET");if(!l){if(L()&&(await N(s,i),i.headersSent))return;i.status(404).json({error:"Route not found"});return}if(te(l)){i.status(l.status??500).json({error:l.error});return}s.params=l.params,await l.handler(s,i),H()&&await T("afterRequest",s,i);}catch(l){await q(s,i,l),i.headersSent||i.status(500).json({error:"Internal server error"});}}}};function fe(t,e,r,o){let n=Object.keys(r).length>0;return {statusCode:t,headers:e,...n?{multiValueHeaders:r}:{},body:o}}var ze={name:"netlify",createHandler:t=>{if(typeof t=="string")throw new Error("netlifyAdapter.createHandler() requires a ServerlessConfig object. Run `lacis build` to generate routes/_manifest.ts and pass { routes } instead.");let e=null,r=()=>e||(e=(async()=>{Q(t.routes),U(t.cors),F(t.middleware),V(t.middlewares),j(t.hooks);})(),e);return async(o,n)=>{await r();let s=o.queryStringParameters?"?"+new URLSearchParams(o.queryStringParameters).toString():"",i=o.path+s,l=new IncomingMessage(new Socket);if(l.url=i,l.method=o.httpMethod,l.headers=o.headers,o.body){let h=o.isBase64Encoded?"base64":"utf-8";l.push(Buffer.from(o.body,h));}l.push(null);let a="",c={},u={},p=false,g=new ServerResponse(l);g.writeHead=function(h,d){return g.statusCode=h,d&&(c={...c,...d}),this},g.setHeader=function(h,d){let v=h.toLowerCase();return Array.isArray(d)?(u[v]=d.map(String),c[v]=String(d[0])):c[v]=String(d),this},g.getHeader=function(h){return c[h.toLowerCase()]},g.end=function(h){return p=true,h!==void 0&&(a=typeof h=="string"?h:h.toString()),this},Object.defineProperty(g,"headersSent",{get:()=>p}),ie(l),ue(g);let w=l,y=g;w.query=o.queryStringParameters??{};try{if(H()&&(await T("beforeRequest",w,y)===!1||p))return fe(y.statusCode,c,u,a);let h=D(o.path,o.httpMethod);return h?te(h)?{statusCode:h.status??500,body:JSON.stringify({error:h.error})}:(w.params=h.params,await h.handler(w,y),H()&&await T("afterRequest",w,y),fe(y.statusCode,c,u,a)):L()&&(await N(w,y),p)?fe(y.statusCode,c,u,a):{statusCode:404,body:JSON.stringify({error:"Route not found"})}}catch(h){return await q(w,y,h),p?fe(y.statusCode,c,u,a):{statusCode:500,body:JSON.stringify({error:"Internal server error"})}}}}};var Ct=10485760,St=new TextEncoder,Ee=class{params={};url;method;headers;socket={setTimeout:e=>{}};connection;_req;constructor(e,r,o,n){this._req=e,this.url=r+o,this.method=e.method,this.headers=e.headers,this.connection={remoteAddress:n};}setTimeout(e){}text(){return this._req.text()}body(){return this._req.arrayBuffer().then(e=>{if(e.byteLength>Ct)throw Object.assign(new Error("Payload Too Large"),{code:413});return Buffer.from(e)})}},Me=class extends X(Ee){json(){return this._req.json()}},ke=class{statusCode=200;headersSent=false;get finished(){return this.headersSent}get writableEnded(){return this.headersSent}_body=null;_headers=null;_sseReadable=null;_sseWriter=null;_sseWindowClosed=false;_listeners=null;on(e,r){return (e==="finish"||e==="close")&&(this._listeners||(this._listeners=[]),this._listeners.push(r)),this}once(e,r){return this.on(e,r)}emit(e){if((e==="finish"||e==="close")&&this._listeners)for(let r=0;r<this._listeners.length;r++)this._listeners[r]();return true}setHeader(e,r){if(this._headers||(this._headers=[]),Array.isArray(r))for(let o of r)this._headers.push(e,o);else this._headers.push(e,r);return this}getHeader(e){if(!this._headers)return;let r=e.toLowerCase();for(let o=0;o<this._headers.length;o+=2)if(this._headers[o].toLowerCase()===r)return this._headers[o+1]}removeHeader(e){if(!this._headers)return this;let r=e.toLowerCase();for(let o=0;o<this._headers.length;o+=2)if(this._headers[o].toLowerCase()===r){this._headers.splice(o,2);break}return this}hasHeader(e){if(!this._headers)return false;let r=e.toLowerCase();for(let o=0;o<this._headers.length;o+=2)if(this._headers[o].toLowerCase()===r)return true;return false}writeHead(e,r){if(this.statusCode=e,r)for(let[o,n]of Object.entries(r))this.setHeader(o,n);return this}write(e){return this._sseWriter?(this._sseWriter.write(St.encode(String(e))),true):(this._body=(this._body??"")+e,true)}end(e){if(e!==void 0&&this.write(e),this._sseWriter&&this._sseWriter.close(),this.headersSent=true,this._listeners)for(let r=0;r<this._listeners.length;r++)this._listeners[r]();return this}_initSseStream(){if(this._sseWindowClosed)throw new Error("[lacis/bun] initSSE() must be called synchronously before any `await` in your handler.");let{readable:e,writable:r}=new TransformStream;this._sseReadable=e,this._sseWriter=r.getWriter();}_closeSseWindow(){this._sseWindowClosed=true;}},xe=class extends Y(ke){initSSE(e){return this._initSseStream(),super.initSSE(e)}},Ve={name:"bun",createHandler:t=>{if(typeof t!="string")throw new Error("bunAdapter requires a routesDir string, not a ServerlessConfig.");let e=t;return async(r={})=>{let{isDev:o,port:n=3e3,defaultHeaders:s,cluster:i}=r,l=parseInt(process.env.LACIS_BUN_WORKER??"0"),a=l>0;if(i?.enabled&&!a){let p=i.workers??___default.cpus().length;R(`\u{1F9F5} Starting Bun server with ${p} workers (reusePort)`);let g=Array.from({length:p},()=>Bun.spawn(process.argv,{env:{...process.env,LACIS_BUN_WORKER:String(process.pid)},stdout:"ignore",stderr:"inherit"}));return R(`\u{1F680} Server running at http://localhost:${n}/`),{close:w=>{for(let y of g)y.kill();w?.();}}}if(a){let p=setInterval(()=>{try{process.kill(l,0);}catch{clearInterval(p),process.exit(0);}},2e3);p.unref();}R("\u{1F680} Bun high-performance mode enabled"),r.routes||await re(e),U(r.cors),F(r.middleware),j(r.hooks);let c=s?Object.entries(s):[],u=Bun.serve({port:n,reusePort:a,async fetch(p,g){let w=new URL(p.url),y=w.pathname,h=new Me(p,y,w.search,g?.requestIP(p)?.address??"");h.query=le(w.search);let d=new xe;try{for(let k=0;k<c.length;k++)d.setHeader(c[k][0],c[k][1]);if(H()&&(!await T("beforeRequest",h,d)||d.headersSent))return Z(d);let v=D(y,p.method);if(!v)return L()&&(await N(h,d),d.headersSent)?Z(d):new Response(JSON.stringify({error:"Route not found"}),{status:404,headers:{"Content-Type":"application/json"}});if("error"in v)return H()&&await T("onError",h,d),new Response(JSON.stringify({error:v.error}),{status:v.status||500,headers:{"Content-Type":"application/json"}});h.params=v.params;let b=null,$=(async()=>{await v.handler(h,d),H()&&await T("afterRequest",h,d),d.headersSent||d.end();})().catch(k=>{b=k,o&&console.error("Server error:",k),d._sseReadable&&!d.headersSent&&d.end();});return d._closeSseWindow(),d._sseReadable?Z(d,d._sseReadable):(await $,b&&(await q(h,d,b),!d.headersSent)?new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}}):Z(d))}catch(v){return await q(h,d,v),d.headersSent?Z(d):new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}})}}});return R(`\u{1F680} Server started on http://localhost:${n}${o?" (dev)":""}`),{close:()=>{u.stop();}}}}};function Z(t,e){let r=e??t._body;if(!t._headers)return new Response(r,{status:t.statusCode});let o=new Headers;for(let n=0;n<t._headers.length;n+=2){let s=t._headers[n],i=t._headers[n+1];s.toLowerCase()==="set-cookie"?o.append(s,i):o.set(s,i);}return new Response(r,{status:t.statusCode,headers:o})}var vt={node:We,vercel:Je,netlify:ze,bun:Ve};function Dr(t="node"){let e=vt[t];if(!e)throw new Error(`Platform "${t}" not supported`);return e}
26
+ export{U as A,Te as B,_e as C,Oe as D,Ae as E,$e as F,Pe as G,qe as H,Ie as I,je as J,Le as K,We as L,Je as M,ze as N,Ve as O,Dr as P,pe as a,Ke as b,Qe as c,Xe as d,H as e,T as f,me as g,Mt as h,V as i,j,L as k,N as l,kt as m,xt as n,F as o,R as p,W as q,te as r,Q as s,re as t,D as u,Nt as v,Ft as w,Ut as x,Dt as y,et as z};
package/dist/cli/index.js CHANGED
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import {resolve,join,relative}from'path';import {unlink,writeFile,readdir}from'fs/promises';import {spawn}from'child_process';import {watch,existsSync,readFileSync}from'fs';async function N(e){let t=[];async function n(o,s=[]){let c;try{c=await readdir(o,{withFileTypes:!0});}catch{return}let r=c.find(i=>!i.isDirectory()&&(i.name==="index.ts"||i.name==="index.js"));if(r){let i="./"+relative(e,join(o,r.name)).replace(/\\/g,"/").replace(/\.ts$/,".js"),u="/"+s.map(m=>m.replace(/^\[(\w+)\??\]$/,":$1")).join("/");t.push({importPath:i,routePath:u==="//"?"/":u});}for(let i of c)i.isDirectory()&&!i.name.startsWith("+")&&await n(join(o,i.name),[...s,i.name]);}return await n(e),t}async function f(e){let t=await N(e),n=t.map((c,r)=>`import * as _route_${r} from '${c.importPath}'`).join(`
3
- `),o=t.map((c,r)=>` { path: '${c.routePath}', handlers: _route_${r} }`).join(`,
4
- `),s=["// AUTO-GENERATED by lacis build \u2014 do not edit",n,"","export const routes = [",o,"]",""].join(`
5
- `);await writeFile(join(e,"_manifest.ts"),s,"utf-8"),console.log(`[lacis] Generated manifest with ${t.length} route(s)`);}function R(e){if(existsSync(join(e,"netlify.toml")))return "netlify";if(existsSync(join(e,"vercel.json")))return "vercel";try{let t=JSON.parse(readFileSync(join(e,"package.json"),"utf-8")),n={...t.dependencies,...t.devDependencies};if(n["@netlify/functions"]||n["netlify-cli"])return "netlify";if(n.vercel||n["@vercel/node"])return "vercel"}catch{}return process.versions.bun!==void 0||existsSync(join(e,"bun.lockb"))||existsSync(join(e,"bun.lock"))?"bun":"node"}function S(e){try{let t=JSON.parse(readFileSync(join(e,"package.json"),"utf-8")),n=t.module??t.main;if(typeof n=="string"&&existsSync(join(e,n)))return n}catch{}for(let t of ["server.ts","index.ts","app.ts","main.ts"])if(existsSync(join(e,t)))return t;return null}function F(e){try{return JSON.parse(readFileSync(join(e,"tsconfig.json"),"utf-8")).compilerOptions?.outDir??null}catch{return null}}async function v(e){let t=[],n;try{n=await readdir(e,{withFileTypes:!0});}catch{return t}for(let o of n)o.isDirectory()?t.push(...await v(join(e,o.name))):o.name.endsWith(".ts")&&o.name!=="_manifest.ts"&&t.push(join(e,o.name));return t}function D(e,t,n){return new Promise((o,s)=>{let c=spawn(e,t,{stdio:"inherit",cwd:n});c.on("close",r=>{r===0?o():s(new Error(`${e} exited with code ${r}`));}),c.on("error",r=>{r.code==="ENOENT"?s(new Error(`Command not found: ${e}. Make sure it is installed.`)):s(r);});})}async function b(e,t){let n=process.cwd(),o=R(n),s=join(e,"_manifest.ts");relative(n,s).replace(/\\/g,"/");if(await f(e),o==="vercel"||o==="netlify"){console.log(`[lacis] ${o} detected \u2014 manifest generated, platform handles compilation`);return}try{if(o==="bun"){let r=t??S(n);if(!r)throw new Error("Entry point not found. Specify one with --entry <file>.");let i=await v(e),u=[join(n,r),s,...i],m=await globalThis.Bun.build({entrypoints:u,outdir:join(n,"dist"),root:n,external:["*"],target:"bun"});if(!m.success){let T=m.logs.map(y=>y.message??String(y)).join(`
2
+ import {resolve,join,relative}from'path';import {unlink,writeFile,readdir}from'fs/promises';import {spawn}from'child_process';import {watch,existsSync,readFileSync}from'fs';async function k(e){let t=[];async function n(r,s=[]){let o;try{o=await readdir(r,{withFileTypes:!0});}catch{return}let a=o.find(i=>!i.isDirectory()&&(i.name==="index.ts"||i.name==="index.js"));if(a){let i="./"+relative(e,join(r,a.name)).replace(/\\/g,"/").replace(/\.ts$/,".js"),c="/"+s.map(d=>d.replace(/^\[(\w+)\??\]$/,":$1")).join("/");t.push({importPath:i,routePath:c==="//"?"/":c});}for(let i of o)i.isDirectory()&&!i.name.startsWith("+")&&await n(join(r,i.name),[...s,i.name]);}return await n(e),t}async function F(e){let t=[];async function n(r,s){let o;try{o=await readdir(r,{withFileTypes:!0});}catch{return}let a=o.find(c=>c.name==="+middleware.global.ts")??o.find(c=>c.name==="+middleware.global.js");a&&t.push({importPath:"./"+relative(e,join(r,a.name)).replace(/\\/g,"/").replace(/\.ts$/,".js"),routePath:s,type:"cascade"});let i=o.find(c=>c.name==="+middleware.ts")??o.find(c=>c.name==="+middleware.js");i&&t.push({importPath:"./"+relative(e,join(r,i.name)).replace(/\\/g,"/").replace(/\.ts$/,".js"),routePath:s,type:"exact"});for(let c of o)if(c.isDirectory()&&!c.name.startsWith("+")){let d=s==="/"?`/${c.name}`:`${s}/${c.name}`;await n(join(r,c.name),d);}}return await n(e,"/"),t}async function m(e){let[t,n]=await Promise.all([k(e),F(e)]),r=t.map((d,f)=>`import * as _route_${f} from '${d.importPath}'`).join(`
3
+ `),s=n.map((d,f)=>`import * as _mw_${f} from '${d.importPath}'`).join(`
4
+ `),o=[r,s].filter(Boolean).join(`
5
+ `),a=t.map((d,f)=>` { path: '${d.routePath}', handlers: _route_${f} }`).join(`,
6
+ `),i=n.map((d,f)=>` { path: '${d.routePath}', type: '${d.type}', module: _mw_${f} }`).join(`,
7
+ `),c=["// AUTO-GENERATED by lacis build \u2014 do not edit",o,"","export const routes = [",a,"]","","export const middlewares = [",i,"]",""].join(`
8
+ `);await writeFile(join(e,"_manifest.ts"),c,"utf-8"),console.log(`[lacis] Generated manifest with ${t.length} route(s) and ${n.length} middleware(s)`);}function N(e){if(existsSync(join(e,"netlify.toml")))return "netlify";if(existsSync(join(e,"vercel.json")))return "vercel";try{let t=JSON.parse(readFileSync(join(e,"package.json"),"utf-8")),n={...t.dependencies,...t.devDependencies};if(n["@netlify/functions"]||n["netlify-cli"])return "netlify";if(n.vercel||n["@vercel/node"])return "vercel"}catch{}return process.versions.bun!==void 0||existsSync(join(e,"bun.lockb"))||existsSync(join(e,"bun.lock"))?"bun":"node"}function S(e){try{let t=JSON.parse(readFileSync(join(e,"package.json"),"utf-8")),n=t.module??t.main;if(typeof n=="string"&&existsSync(join(e,n)))return n}catch{}for(let t of ["server.ts","index.ts","app.ts","main.ts"])if(existsSync(join(e,t)))return t;return null}function R(e){try{return JSON.parse(readFileSync(join(e,"tsconfig.json"),"utf-8")).compilerOptions?.outDir??null}catch{return null}}async function v(e){let t=[],n;try{n=await readdir(e,{withFileTypes:!0});}catch{return t}for(let r of n)r.isDirectory()?t.push(...await v(join(e,r.name))):r.name.endsWith(".ts")&&r.name!=="_manifest.ts"&&t.push(join(e,r.name));return t}function D(e,t,n){return new Promise((r,s)=>{let o=spawn(e,t,{stdio:"inherit",cwd:n});o.on("close",a=>{a===0?r():s(new Error(`${e} exited with code ${a}`));}),o.on("error",a=>{a.code==="ENOENT"?s(new Error(`Command not found: ${e}. Make sure it is installed.`)):s(a);});})}async function $(e,t){let n=process.cwd(),r=N(n),s=join(e,"_manifest.ts");if(await m(e),r==="vercel"||r==="netlify"){console.log(`[lacis] ${r} detected \u2014 manifest generated, platform handles compilation`);return}try{if(r==="bun"){let o=t??S(n);if(!o)throw new Error("Entry point not found. Specify one with --entry <file>.");let a=await v(e),i=[join(n,o),s,...a],c=await globalThis.Bun.build({entrypoints:i,outdir:join(n,"dist"),root:n,external:["*"],target:"bun"});if(!c.success){let d=c.logs.map(f=>f.message??String(f)).join(`
6
9
  `);throw new Error(`Bun build failed:
7
- ${T}`)}}else {let r=join(n,"node_modules",".bin","tsc");if(!existsSync(r))throw new Error("TypeScript not found. Add it to your project: npm install --save-dev typescript");let i=F(n)??"dist";await D(r,["--outDir",i],n);}}finally{await unlink(s).catch(()=>{});}console.log("[lacis] Build complete \u2192 dist/");}async function d(e){await f(e);let t=null;watch(e,{recursive:true},(n,o)=>{!o||o==="_manifest.ts"||(t&&clearTimeout(t),t=setTimeout(async()=>{console.log(`[lacis] Route changed: ${o}, regenerating manifest...`);try{await f(e);}catch(s){console.error("[lacis] Failed to regenerate manifest:",s);}},100));});}function A(e){if(existsSync(join(e,"netlify.toml")))return "netlify";if(existsSync(join(e,"vercel.json")))return "vercel";try{let t=JSON.parse(readFileSync(join(e,"package.json"),"utf-8")),n={...t.dependencies,...t.devDependencies};if(n["@netlify/functions"]||n["netlify-cli"])return "netlify";if(n.vercel||n["@vercel/node"])return "vercel"}catch{}return "node"}async function P(e){let t=process.cwd();if(process.env.VERCEL==="1"){await f(e);return}if(process.env.NETLIFY==="true"){await d(e);return}let n=A(t);if(console.log(`[lacis] Detected platform: ${n}`),await d(e),n==="node"){console.log("[lacis] Node mode: watching routes for changes...");return}let[o,s]=n==="netlify"?["netlify",["dev"]]:["vercel",["dev"]],c=spawn(o,s,{stdio:"inherit",shell:true,cwd:t});c.on("error",i=>{i.code==="ENOENT"?console.error(`[lacis] ${o} CLI not found. Install it with: ${n==="netlify"?"npm i -g netlify-cli":"npm i -g vercel"}`):console.error(`[lacis] Failed to start ${o} dev:`,i.message);});let r=i=>{process.on(i,()=>c.kill(i));};r("SIGINT"),r("SIGTERM");}function B(e){let t=e.slice(2),n=t[0]??"",o=t.indexOf("--routes"),s=o!==-1?t[o+1]:void 0,c=s?resolve(process.cwd(),s):resolve(process.cwd(),"routes"),r=t.indexOf("--entry"),i=r!==-1?t[r+1]:void 0;return {command:n,routesDir:c,entry:i}}function J(){console.log(`
10
+ ${d}`)}}else {let o=join(n,"node_modules",".bin","tsc");if(!existsSync(o))throw new Error("TypeScript not found. Add it to your project: npm install --save-dev typescript");let a=R(n)??"dist";await D(o,["--outDir",a],n);}}finally{await unlink(s).catch(()=>{});}console.log("[lacis] Build complete \u2192 dist/");}async function p(e){await m(e);let t=null;watch(e,{recursive:true},(n,r)=>{!r||r==="_manifest.ts"||(t&&clearTimeout(t),t=setTimeout(async()=>{console.log(`[lacis] Route changed: ${r}, regenerating manifest...`);try{await m(e);}catch(s){console.error("[lacis] Failed to regenerate manifest:",s);}},100));});}function M(e){if(existsSync(join(e,"netlify.toml")))return "netlify";if(existsSync(join(e,"vercel.json")))return "vercel";try{let t=JSON.parse(readFileSync(join(e,"package.json"),"utf-8")),n={...t.dependencies,...t.devDependencies};if(n["@netlify/functions"]||n["netlify-cli"])return "netlify";if(n.vercel||n["@vercel/node"])return "vercel"}catch{}return "node"}async function P(e){let t=process.cwd();if(process.env.VERCEL==="1"){await m(e);return}if(process.env.NETLIFY==="true"){await p(e);return}let n=M(t);if(console.log(`[lacis] Detected platform: ${n}`),await p(e),n==="node"){console.log("[lacis] Node mode: watching routes for changes...");return}let[r,s]=n==="netlify"?["netlify",["dev"]]:["vercel",["dev"]],o=spawn(r,s,{stdio:"inherit",shell:true,cwd:t});o.on("error",i=>{i.code==="ENOENT"?console.error(`[lacis] ${r} CLI not found. Install it with: ${n==="netlify"?"npm i -g netlify-cli":"npm i -g vercel"}`):console.error(`[lacis] Failed to start ${r} dev:`,i.message);});let a=i=>{process.on(i,()=>o.kill(i));};a("SIGINT"),a("SIGTERM");}function B(e){let t=e.slice(2),n=t[0]??"",r=t.indexOf("--routes"),s=r!==-1?t[r+1]:void 0,o=s?resolve(process.cwd(),s):resolve(process.cwd(),"routes"),a=t.indexOf("--entry"),i=a!==-1?t[a+1]:void 0;return {command:n,routesDir:o,entry:i}}function A(){console.log(`
8
11
  Usage: lacis <command> [options]
9
12
 
10
13
  Commands:
@@ -17,4 +20,4 @@ To scaffold a new project: npm create lacis@latest
17
20
  Options:
18
21
  --routes <dir> Path to routes directory (default: ./routes)
19
22
  --entry <file> Entry point for bundlers (default: auto-detected from package.json)
20
- `);}async function C(){let{command:e,routesDir:t,entry:n}=B(process.argv);switch(e){case "build":await b(t,n);break;case "watch":await d(t);break;case "dev":await P(t);break;default:J(),e&&(console.error(`Unknown command: ${e}`),process.exit(1));}}C().catch(e=>{console.error("[lacis]",e),process.exit(1);});
23
+ `);}async function J(){let{command:e,routesDir:t,entry:n}=B(process.argv);switch(e){case "build":await $(t,n);break;case "watch":await p(t);break;case "dev":await P(t);break;default:A(),e&&(console.error(`Unknown command: ${e}`),process.exit(1));}}J().catch(e=>{console.error("[lacis]",e),process.exit(1);});
@@ -55,6 +55,8 @@ interface Response extends ServerResponse {
55
55
 
56
56
  type MiddlewareType = 'beforeRequest' | 'afterRequest' | 'onError';
57
57
  type MiddlewareCallback = (req: Request, res: Response, context?: any) => Promise<void | boolean> | void | boolean;
58
+ type NotFoundHook = (req: Request, res: Response) => void | Promise<void>;
59
+ type ShutdownHook = () => void | Promise<void>;
58
60
  interface MiddlewareModule {
59
61
  beforeRequest?: MiddlewareCallback[];
60
62
  afterRequest?: MiddlewareCallback[];
@@ -66,6 +68,15 @@ type PathMiddlewares = Map<string, {
66
68
  onError: MiddlewareCallback[];
67
69
  }>;
68
70
 
71
+ interface ServerlessMiddleware {
72
+ path: string;
73
+ type: 'cascade' | 'exact';
74
+ module: {
75
+ beforeRequest?: MiddlewareCallback | MiddlewareCallback[];
76
+ afterRequest?: MiddlewareCallback | MiddlewareCallback[];
77
+ onError?: MiddlewareCallback | MiddlewareCallback[];
78
+ };
79
+ }
69
80
  interface AdapterRequest extends IncomingMessage {
70
81
  params?: Record<string, string>;
71
82
  query?: Record<string, string>;
@@ -92,6 +103,11 @@ interface ServerlessConfig {
92
103
  afterRequest?: MiddlewareCallback | MiddlewareCallback[];
93
104
  onError?: MiddlewareCallback | MiddlewareCallback[];
94
105
  };
106
+ middlewares?: ServerlessMiddleware[];
107
+ hooks?: {
108
+ onNotFound?: NotFoundHook;
109
+ onShutdown?: ShutdownHook;
110
+ };
95
111
  }
96
112
  interface Adapter {
97
113
  name: string;
@@ -166,6 +182,10 @@ interface ServerConfig {
166
182
  afterRequest?: MiddlewareCallback | MiddlewareCallback[];
167
183
  onError?: MiddlewareCallback | MiddlewareCallback[];
168
184
  };
185
+ hooks?: {
186
+ onNotFound?: NotFoundHook;
187
+ onShutdown?: ShutdownHook;
188
+ };
169
189
  routes?: ServerlessRoute[];
170
190
  openapi?: {
171
191
  path?: string;
@@ -192,4 +212,4 @@ interface ClusterConfig {
192
212
  workers?: number;
193
213
  }
194
214
 
195
- export type { AdapterRequest as A, CorsConfig as C, Handler as H, MiddlewareType as M, PathMiddlewares as P, Request as R, ServerConfig as S, UploadedFile as U, AdapterResponse as a, Response as b, ServerlessRoute as c, MiddlewareCallback as d, SSEOptions as e, SSEClientOptions as f, SSEEventHandlers as g, SSEClient as h, Adapter as i, AdapterContext as j, ClusterConfig as k, CookieOptions as l, MiddlewareModule as m, RequestCookies as n, ResponseCookies as o, Route as p, RouteHandlers as q, ServerlessConfig as r };
215
+ export type { AdapterRequest as A, CorsConfig as C, Handler as H, MiddlewareType as M, NotFoundHook as N, PathMiddlewares as P, Request as R, ServerConfig as S, UploadedFile as U, AdapterResponse as a, Response as b, ServerlessRoute as c, MiddlewareCallback as d, ShutdownHook as e, ServerlessMiddleware as f, SSEOptions as g, SSEClientOptions as h, SSEEventHandlers as i, SSEClient as j, Adapter as k, AdapterContext as l, ClusterConfig as m, CookieOptions as n, MiddlewareModule as o, RequestCookies as p, ResponseCookies as q, Route as r, RouteHandlers as s, ServerlessConfig as t };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServerConfig, A as AdapterRequest, a as AdapterResponse, R as Request, b as Response, c as ServerlessRoute, M as MiddlewareType, d as MiddlewareCallback, P as PathMiddlewares, C as CorsConfig, e as SSEOptions, f as SSEClientOptions, g as SSEEventHandlers, h as SSEClient } from './index-CnWzo9eB.js';
2
- export { i as Adapter, j as AdapterContext, k as ClusterConfig, l as CookieOptions, H as Handler, m as MiddlewareModule, n as RequestCookies, o as ResponseCookies, p as Route, q as RouteHandlers, r as ServerlessConfig, U as UploadedFile } from './index-CnWzo9eB.js';
1
+ import { S as ServerConfig, A as AdapterRequest, a as AdapterResponse, R as Request, b as Response, c as ServerlessRoute, M as MiddlewareType, d as MiddlewareCallback, P as PathMiddlewares, N as NotFoundHook, e as ShutdownHook, f as ServerlessMiddleware, C as CorsConfig, g as SSEOptions, h as SSEClientOptions, i as SSEEventHandlers, j as SSEClient } from './index-BPqzMBG-.js';
2
+ export { k as Adapter, l as AdapterContext, m as ClusterConfig, n as CookieOptions, H as Handler, o as MiddlewareModule, p as RequestCookies, q as ResponseCookies, r as Route, s as RouteHandlers, t as ServerlessConfig, U as UploadedFile } from './index-BPqzMBG-.js';
3
3
  import { Server, ServerResponse, IncomingMessage } from 'http';
4
4
 
5
5
  interface VercelRequest {
@@ -282,6 +282,14 @@ declare function hasMiddlewares(): boolean;
282
282
  declare function runMiddlewares(middlewareName: MiddlewareType, req: Request, res: Response, context?: any): Promise<boolean>;
283
283
  declare function loadMiddlewares(routesDir: string): Promise<void>;
284
284
  declare function getPathMiddlewares(): PathMiddlewares;
285
+ declare function registerMiddlewares(middlewares?: ServerlessMiddleware[]): void;
286
+ declare function registerHooksConfig(config?: {
287
+ onNotFound?: NotFoundHook;
288
+ onShutdown?: ShutdownHook;
289
+ }): void;
290
+ declare function hasNotFoundHook(): boolean;
291
+ declare function runNotFoundHook(req: Request, res: Response): Promise<void>;
292
+ declare function runShutdownHook(): Promise<void>;
285
293
  declare function resetMiddlewares(): void;
286
294
  declare function registerMiddlewareConfig(config?: {
287
295
  beforeRequest?: MiddlewareCallback | MiddlewareCallback[];
@@ -400,4 +408,4 @@ declare function sseEventError(res: ServerResponse, event: string, error: string
400
408
  */
401
409
  declare function createSSEClient(urlOrReq: string | IncomingMessage, options?: SSEClientOptions, handlers?: SSEEventHandlers, req?: IncomingMessage): Promise<SSEClient> | SSEClient;
402
410
 
403
- export { AdapterRequest, AdapterResponse, type AlarmStatus, type BalancerOptions, type CacheEntry, CorsConfig, type DefineHandlerConfig, type DefinedHandler, HTTP_STATUS, type HandlerCacheOptions, type HandlerMeta, type InferOutput, type MetricValue, type Metrics, MiddlewareCallback, MiddlewareType, type MonitorOptions, type NetlifyContext, type NetlifyEvent, type NetlifyHandler, type NetlifyResponse, type OpenApiConfig, type OpenApiInfo, PathMiddlewares, type PerformanceData, type PlatformHandler, type RateLimitOptions, Request, Response, type ResponseCacheOptions, SSEClient, SSEClientOptions, SSEEventHandlers, SSEOptions, ServerConfig, ServerlessRoute, type StandardIssue, type StandardSchema, type StatsMessage, type Store, type ValidatedRequest, type VercelRequest, type VercelResponse, type WithCacheOptions, type WorkerStats, addExactPathMiddleware, addMiddleware, addPathMiddleware, buildOpenApiDoc, collectMiddleware, createBadRequestError, createConflictError, createCorsMiddleware, createForbiddenError, createGatewayTimeoutError, createHttpError, createInternalServerError, createMethodNotAllowedError, createNotFoundError, createRateLimit, createRateLimitError, createResponseCache, createSSEClient, createServer, createServiceUnavailableError, createStore, createUnauthorizedError, createValidationError, defaultCacheKey, defaultConfig, defineHandler, findRoute, getConfig, getPathMiddlewares, getRouterStats, getRoutesDir, hasMiddlewares, initSSE, interceptResponse, isHttpError, isRouteError, loadMiddlewares, loadRoutes, logError, normalizeError, registerCorsConfig, registerMiddlewareConfig, registerRoutes, replayEntry, resetMiddlewares, resetRouter, router, runMiddlewares, send, sendError, sendEvent, sendJson, setVerboseLogging, sseClose, sseComment, sseEventError, sseId, sseRetry, withCache };
411
+ export { AdapterRequest, AdapterResponse, type AlarmStatus, type BalancerOptions, type CacheEntry, CorsConfig, type DefineHandlerConfig, type DefinedHandler, HTTP_STATUS, type HandlerCacheOptions, type HandlerMeta, type InferOutput, type MetricValue, type Metrics, MiddlewareCallback, MiddlewareType, type MonitorOptions, type NetlifyContext, type NetlifyEvent, type NetlifyHandler, type NetlifyResponse, NotFoundHook, type OpenApiConfig, type OpenApiInfo, PathMiddlewares, type PerformanceData, type PlatformHandler, type RateLimitOptions, Request, Response, type ResponseCacheOptions, SSEClient, SSEClientOptions, SSEEventHandlers, SSEOptions, ServerConfig, ServerlessMiddleware, ServerlessRoute, ShutdownHook, type StandardIssue, type StandardSchema, type StatsMessage, type Store, type ValidatedRequest, type VercelRequest, type VercelResponse, type WithCacheOptions, type WorkerStats, addExactPathMiddleware, addMiddleware, addPathMiddleware, buildOpenApiDoc, collectMiddleware, createBadRequestError, createConflictError, createCorsMiddleware, createForbiddenError, createGatewayTimeoutError, createHttpError, createInternalServerError, createMethodNotAllowedError, createNotFoundError, createRateLimit, createRateLimitError, createResponseCache, createSSEClient, createServer, createServiceUnavailableError, createStore, createUnauthorizedError, createValidationError, defaultCacheKey, defaultConfig, defineHandler, findRoute, getConfig, getPathMiddlewares, getRouterStats, getRoutesDir, hasMiddlewares, hasNotFoundHook, initSSE, interceptResponse, isHttpError, isRouteError, loadMiddlewares, loadRoutes, logError, normalizeError, registerCorsConfig, registerHooksConfig, registerMiddlewareConfig, registerMiddlewares, registerRoutes, replayEntry, resetMiddlewares, resetRouter, router, runMiddlewares, runNotFoundHook, runShutdownHook, send, sendError, sendEvent, sendJson, setVerboseLogging, sseClose, sseComment, sseEventError, sseId, sseRetry, withCache };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {l,t,i,n,o,k,K as K$1}from'./chunk-CZJALK6N.js';export{c as addExactPathMiddleware,a as addMiddleware,b as addPathMiddleware,d as collectMiddleware,u as createCorsMiddleware,w as createSSEClient,p as findRoute,h as getPathMiddlewares,r as getRouterStats,q as getRoutesDir,e as hasMiddlewares,x as initSSE,m as isRouteError,g as loadMiddlewares,o as loadRoutes,v as registerCorsConfig,j as registerMiddlewareConfig,n as registerRoutes,i as resetMiddlewares,t as resetRouter,l as router,f as runMiddlewares,y as send,A as sendEvent,z as sendJson,s as setVerboseLogging,E as sseClose,B as sseComment,F as sseEventError,C as sseId,D as sseRetry}from'./chunk-CZJALK6N.js';import M from'cluster';var x={port:3e3,isDev:process.env.NODE_ENV==="development",timeout:3e4,cluster:{enabled:false,workers:void 0},platform:"node"};function be(e={}){return {...x,...e}}function S(e){let t=new Map;function r(n){let a=t.get(n);if(a){if(Date.now()>=a.expiresAt){t.delete(n);return}return t.delete(n),t.set(n,a),a}}function o(n,a){if(t.size>=e){let i=0;for(let s of t.keys())if(t.delete(s),++i>=50)break}t.set(n,a);}return {get:r,set:o}}function R(e,t){let r="",o=false,n=false,a=e.setHeader.bind(e);e.setHeader=(s,d)=>{let c=s.toLowerCase();return c==="content-type"&&(r=String(d)),c==="set-cookie"&&(o=true),a(s,d)};let i=e.end.bind(e);e.end=s=>(n||(n=true,!o&&!r.includes("text/event-stream")&&t({body:s,status:e.statusCode,contentType:r})),i(s));}function h(e,t){t.contentType&&e.setHeader("Content-Type",t.contentType),e.statusCode=t.status,e.end(t.body);}function C(e){return (e.method??"GET")+":"+(e.url??"/")}function ve(e){let{ttl:t,methods:r=["GET","HEAD"],maxSize:o=500,keyGenerator:n=C,match:a,exclude:i,shouldCache:s=(u,y)=>y.statusCode>=200&&y.statusCode<300}=e,d=new Set(r.map(u=>u.toUpperCase())),c=i?Array.isArray(i)?i:[i]:[],f=S(o);return (u,y)=>{if(!d.has((u.method??"GET").toUpperCase()))return;let g=u.url??"/",G=g.indexOf("?")===-1?g:g.slice(0,g.indexOf("?"));if(c.some(b=>G.startsWith(b))||a&&!a(u))return;let A=n(u),H=f.get(A);if(H)return h(y,H),false;R(y,b=>{s(u,y)&&f.set(A,{...b,expiresAt:Date.now()+t*1e3});});}}function Oe(e,t){let{ttl:r,maxSize:o=500,key:n}=e,a=S(o);return async(i,s)=>{let d=n?n(i):C(i),c=a.get(d);if(c){h(s,c);return}R(s,f=>{s.statusCode>=200&&s.statusCode<300&&a.set(d,{...f,expiresAt:Date.now()+r*1e3});}),await t(i,s);}}async function v(e,t){let r=await e["~standard"].validate(t);return r.issues?{success:false,issues:r.issues}:{success:true,data:r.value}}function O(e){return Array.from(e).map(t=>({message:t.message,path:t.path?Array.from(t.path).map(r=>typeof r=="object"&&"key"in r?r.key:r):void 0}))}function He(e){let t=e.cache?S(e.cache.maxSize??500):null,r=async(o,n)=>{if(t&&e.cache){let a=e.cache.key?e.cache.key(o):C(o),i=t.get(a);if(i){h(n,i);return}R(n,s=>{n.statusCode>=200&&n.statusCode<300&&t.set(a,{...s,expiresAt:Date.now()+e.cache.ttl*1e3});});}if(e.params){let a=await v(e.params,o.params??{});if(!a.success){n.status(400).json({error:"Validation failed",issues:O(a.issues)});return}o.params=a.data;}if(e.query){let a=await v(e.query,o.query??{});if(!a.success){n.status(400).json({error:"Validation failed",issues:O(a.issues)});return}o.query=a.data;}if(e.body){let a;try{a=await o.json();}catch{n.status(400).json({error:"Invalid JSON body"});return}let i=await v(e.body,a);if(!i.success){n.status(400).json({error:"Validation failed",issues:O(i.issues)});return}o.body=i.data;}await e.handler(o,n);};return r._defineHandler=e,r}async function w(e){let t=e?.["~standard"]?.vendor;if(!t)return null;try{if(t==="zod"){let r=await import('zod');if(typeof r.toJSONSchema=="function")return r.toJSONSchema(e);let o=await import('zod-to-json-schema');return (o.zodToJsonSchema??o.default)(e,{target:"openApi3"})}if(t==="valibot"){let r=await import('@valibot/to-json-schema');return (r.toJsonSchema??r.default)(e)}if(t==="arktype")return e.toJsonSchema()}catch{k(`[openapi] no converter found for "${t}" \u2014 install the matching json-schema package`);}return null}function F(e){return e.replace(/:(\w+)\??/g,"{$1}")}async function j(e,t){let r={responses:{200:{description:"Success"}}};t.meta?.summary&&(r.summary=t.meta.summary),t.meta?.description&&(r.description=t.meta.description),t.meta?.tags&&(r.tags=t.meta.tags),t.meta?.deprecated&&(r.deprecated=t.meta.deprecated);let o=[];if(t.params){let n=await w(t.params);if(n?.properties)for(let[a,i]of Object.entries(n.properties))o.push({name:a,in:"path",required:true,schema:i});}if(t.query){let n=await w(t.query);if(n?.properties){let a=n.required??[];for(let[i,s]of Object.entries(n.properties))o.push({name:i,in:"query",required:a.includes(i),schema:s});}}if(o.length>0&&(r.parameters=o),t.body){let n=await w(t.body);n&&(r.requestBody={required:true,content:{"application/json":{schema:n}}});}return r}async function _(e){let t=l.getRoutes(),r={};for(let{method:o,path:n,handler:a}of t){let i=a._defineHandler,s=F(n);r[s]||(r[s]={}),r[s][o.toLowerCase()]=i?await j(o,i):{responses:{200:{description:"Success"}}};}return {openapi:"3.1.0",info:e.info,paths:r}}var T=null,P=false,L=false;async function Ge(e,t$1=x){let{platform:r="node"}=t$1,o$1=t$1.isDev&&M.isPrimary&&!process.env.LACIS_BUN_WORKER;try{t$1.routes?(t(),i(),n(t$1.routes)):await o(e);let n$1=null,a=null;t$1.openapi&&(n$1=await _(t$1.openapi),a=t$1.openapi.path??"/openapi.json"),o$1&&k(`\u{1F4C2} Routes loaded from: ${e}`);let s=K$1(r).createHandler(e),d;switch(r){case "node":d=await s(t$1),T=d;break;case "bun":d=s(t$1);break;case "vercel":case "netlify":d=s;break;default:throw new Error(`Unsupported platform: "${r}"`)}return n$1&&a&&(l.addRoute("GET",a,(c,f)=>f.json(n$1)),o$1&&k(`OpenAPI doc available at ${a}`)),V(),d}catch(n){throw o$1&&k("\u274C Failed to create server:",n),n}}function V(){if(!M.isPrimary||L)return;L=true;let e=async t=>{P||(P=true,k(`
2
- ${t} received, shutting down...`),T&&typeof T.close=="function"&&await new Promise(r=>{T.close(()=>r()),setTimeout(()=>{k("Forced shutdown after timeout"),r();},3e3);}),process.exit(0));};process.on("SIGINT",()=>e("SIGINT")),process.on("SIGTERM",()=>e("SIGTERM")),process.on("SIGHUP",()=>e("SIGHUP"));}var m={OK:200,CREATED:201,NO_CONTENT:204,BAD_REQUEST:400,UNAUTHORIZED:401,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,CONFLICT:409,UNPROCESSABLE_ENTITY:422,TOO_MANY_REQUESTS:429,INTERNAL_SERVER_ERROR:500,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504},z={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",409:"Conflict",422:"Unprocessable Entity",429:"Too Many Requests",500:"Internal Server Error",503:"Service Unavailable",504:"Gateway Timeout"};function p(e){let t=e.code||m.INTERNAL_SERVER_ERROR,r=e.message||z[t]||"Unknown Error",o=e.name||`HttpError${t}`,n=new Error(r);return Error.captureStackTrace?.(n,p),{name:o,code:t,message:r,details:e.details,expose:e.expose!==void 0?e.expose:t<500,log:e.log!==void 0?e.log:t>=500,stack:n.stack}}function Q(e){let t={error:e.message,code:e.code};return e.expose&&e.details?{...t,details:e.details}:t}function U(e,t){t.headersSent||(t.statusCode=e.code,t.setHeader("Content-Type","application/json"),t.end(JSON.stringify(Q(e)))),e.log&&J(e);}function J(e){let t={name:e.name,message:e.message,code:e.code,details:e.details,stack:e.stack};e.code>=500?k("\u274C ERROR:",JSON.stringify(t,null,2)):k("\u26A0\uFE0F WARNING:",JSON.stringify(t,null,2));}function Ve(e,t){return p({name:"BadRequestError",code:m.BAD_REQUEST,message:e,details:t})}function ze(e,t){return p({name:"UnauthorizedError",code:m.UNAUTHORIZED,message:e,details:t})}function Qe(e,t){return p({name:"ForbiddenError",code:m.FORBIDDEN,message:e,details:t})}function Je(e,t){return p({name:"NotFoundError",code:m.NOT_FOUND,message:e,details:t})}function We(e,t){return p({name:"MethodNotAllowedError",code:m.METHOD_NOT_ALLOWED,message:e,details:t})}function $e(e,t){return p({name:"ConflictError",code:m.CONFLICT,message:e,details:t})}function Ke(e,t){return p({name:"ValidationError",code:m.UNPROCESSABLE_ENTITY,message:e,details:t,expose:true})}function B(e,t){return p({name:"RateLimitError",code:m.TOO_MANY_REQUESTS,message:e,details:t})}function W(e,t){return p({name:"InternalServerError",code:m.INTERNAL_SERVER_ERROR,message:e,details:t})}function $(e,t){return p({name:"ServiceUnavailableError",code:m.SERVICE_UNAVAILABLE,message:e,details:t})}function K(e,t){return p({name:"GatewayTimeoutError",code:m.GATEWAY_TIMEOUT,message:e,details:t})}function Xe(e){if(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e)return e;let t=e?.message||"Unknown error occurred",r=e?.stack?{stack:e.stack}:void 0,o=e?.code||e?.statusCode;return o==="ECONNREFUSED"||o==="ENOTFOUND"?$(`Service connection failed: ${t}`,r):o==="ETIMEDOUT"?K(`Request timed out: ${t}`,r):typeof o=="number"&&o>=400&&o<600?p({code:o,message:t,details:r}):W(t,r)}function Ye(e){return !!(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e&&"name"in e)}function tt(e={}){let t=e.windowMs??6e4,r=e.max??100,o=e.message??"Too Many Requests",n=e.keyGenerator??(s=>{let d=s.headers["x-forwarded-for"];return (typeof d=="string"?d.split(",")[0].trim():s.socket?.remoteAddress)??"unknown"}),a=new Map;return setInterval(()=>{let s=Date.now();for(let[d,c]of a)s>=c.resetAt&&a.delete(d);},t).unref(),(s,d)=>{let c=n(s),f=Date.now(),u=a.get(c);(!u||f>=u.resetAt)&&(u={count:0,resetAt:f+t},a.set(c,u)),u.count++;let y=Math.max(0,r-u.count),g=Math.ceil(u.resetAt/1e3);if(d.setHeader("X-RateLimit-Limit",String(r)),d.setHeader("X-RateLimit-Remaining",String(y)),d.setHeader("X-RateLimit-Reset",String(g)),u.count>r)return d.setHeader("Retry-After",String(Math.ceil((u.resetAt-f)/1e3))),U(B(o),d),false}}export{m as HTTP_STATUS,_ as buildOpenApiDoc,Ve as createBadRequestError,$e as createConflictError,Qe as createForbiddenError,K as createGatewayTimeoutError,p as createHttpError,W as createInternalServerError,We as createMethodNotAllowedError,Je as createNotFoundError,tt as createRateLimit,B as createRateLimitError,ve as createResponseCache,Ge as createServer,$ as createServiceUnavailableError,S as createStore,ze as createUnauthorizedError,Ke as createValidationError,C as defaultCacheKey,x as defaultConfig,He as defineHandler,be as getConfig,R as interceptResponse,Ye as isHttpError,J as logError,Xe as normalizeError,h as replayEntry,U as sendError,Oe as withCache};
1
+ import {q,y,n,s,t,p as p$1,P,m as m$1}from'./chunk-PV6YEQ6J.js';export{c as addExactPathMiddleware,a as addMiddleware,b as addPathMiddleware,d as collectMiddleware,z as createCorsMiddleware,B as createSSEClient,u as findRoute,h as getPathMiddlewares,w as getRouterStats,v as getRoutesDir,e as hasMiddlewares,k as hasNotFoundHook,C as initSSE,r as isRouteError,g as loadMiddlewares,t as loadRoutes,A as registerCorsConfig,j as registerHooksConfig,o as registerMiddlewareConfig,i as registerMiddlewares,s as registerRoutes,n as resetMiddlewares,y as resetRouter,q as router,f as runMiddlewares,l as runNotFoundHook,m as runShutdownHook,D as send,F as sendEvent,E as sendJson,x as setVerboseLogging,J as sseClose,G as sseComment,K as sseEventError,H as sseId,I as sseRetry}from'./chunk-PV6YEQ6J.js';import B from'cluster';var v={port:3e3,isDev:process.env.NODE_ENV==="development",timeout:3e4,cluster:{enabled:false,workers:void 0},platform:"node"};function ke(e={}){return {...v,...e}}function R(e){let t=new Map;function r(n){let a=t.get(n);if(a){if(Date.now()>=a.expiresAt){t.delete(n);return}return t.delete(n),t.set(n,a),a}}function o(n,a){if(t.size>=e){let i=0;for(let s of t.keys())if(t.delete(s),++i>=50)break}t.set(n,a);}return {get:r,set:o}}function h(e,t){let r="",o=false,n=false,a=e.setHeader.bind(e);e.setHeader=(s,d)=>{let c=s.toLowerCase();return c==="content-type"&&(r=String(d)),c==="set-cookie"&&(o=true),a(s,d)};let i=e.end.bind(e);e.end=s=>(n||(n=true,!o&&!r.includes("text/event-stream")&&t({body:s,status:e.statusCode,contentType:r})),i(s));}function C(e,t){t.contentType&&e.setHeader("Content-Type",t.contentType),e.statusCode=t.status,e.end(t.body);}function T(e){return (e.method??"GET")+":"+(e.url??"/")}function Ne(e){let{ttl:t,methods:r=["GET","HEAD"],maxSize:o=500,keyGenerator:n=T,match:a,exclude:i,shouldCache:s=(u,y)=>y.statusCode>=200&&y.statusCode<300}=e,d=new Set(r.map(u=>u.toUpperCase())),c=i?Array.isArray(i)?i:[i]:[],l=R(o);return (u,y)=>{if(!d.has((u.method??"GET").toUpperCase()))return;let g=u.url??"/",j=g.indexOf("?")===-1?g:g.slice(0,g.indexOf("?"));if(c.some(x=>j.startsWith(x))||a&&!a(u))return;let k=n(u),A=l.get(k);if(A)return C(y,A),false;h(y,x=>{s(u,y)&&l.set(k,{...x,expiresAt:Date.now()+t*1e3});});}}function Ie(e,t){let{ttl:r,maxSize:o=500,key:n}=e,a=R(o);return async(i,s)=>{let d=n?n(i):T(i),c=a.get(d);if(c){C(s,c);return}h(s,l=>{s.statusCode>=200&&s.statusCode<300&&a.set(d,{...l,expiresAt:Date.now()+r*1e3});}),await t(i,s);}}async function w(e,t){let r=await e["~standard"].validate(t);return r.issues?{success:false,issues:r.issues}:{success:true,data:r.value}}function O(e){return Array.from(e).map(t=>({message:t.message,path:t.path?Array.from(t.path).map(r=>typeof r=="object"&&"key"in r?r.key:r):void 0}))}function _e(e){let t=e.cache?R(e.cache.maxSize??500):null,r=async(o,n)=>{if(t&&e.cache){let a=e.cache.key?e.cache.key(o):T(o),i=t.get(a);if(i){C(n,i);return}h(n,s=>{n.statusCode>=200&&n.statusCode<300&&t.set(a,{...s,expiresAt:Date.now()+e.cache.ttl*1e3});});}if(e.params){let a=await w(e.params,o.params??{});if(!a.success){n.status(400).json({error:"Validation failed",issues:O(a.issues)});return}o.params=a.data;}if(e.query){let a=await w(e.query,o.query??{});if(!a.success){n.status(400).json({error:"Validation failed",issues:O(a.issues)});return}o.query=a.data;}if(e.body){let a;try{a=await o.json();}catch{n.status(400).json({error:"Invalid JSON body"});return}let i=await w(e.body,a);if(!i.success){n.status(400).json({error:"Validation failed",issues:O(i.issues)});return}o.body=i.data;}await e.handler(o,n);};return r._defineHandler=e,r}async function H(e){let t=e?.["~standard"]?.vendor;if(!t)return null;try{if(t==="zod"){let r=await import('zod');if(typeof r.toJSONSchema=="function")return r.toJSONSchema(e);let o=await import('zod-to-json-schema');return (o.zodToJsonSchema??o.default)(e,{target:"openApi3"})}if(t==="valibot"){let r=await import('@valibot/to-json-schema');return (r.toJsonSchema??r.default)(e)}if(t==="arktype")return e.toJsonSchema()}catch{p$1(`[openapi] no converter found for "${t}" \u2014 install the matching json-schema package`);}return null}function V(e){return e.replace(/:(\w+)\??/g,"{$1}")}async function z(e,t){let r={responses:{200:{description:"Success"}}};t.meta?.summary&&(r.summary=t.meta.summary),t.meta?.description&&(r.description=t.meta.description),t.meta?.tags&&(r.tags=t.meta.tags),t.meta?.deprecated&&(r.deprecated=t.meta.deprecated);let o=[];if(t.params){let n=await H(t.params);if(n?.properties)for(let[a,i]of Object.entries(n.properties))o.push({name:a,in:"path",required:true,schema:i});}if(t.query){let n=await H(t.query);if(n?.properties){let a=n.required??[];for(let[i,s]of Object.entries(n.properties))o.push({name:i,in:"query",required:a.includes(i),schema:s});}}if(o.length>0&&(r.parameters=o),t.body){let n=await H(t.body);n&&(r.requestBody={required:true,content:{"application/json":{schema:n}}});}return r}async function L(e){let t=q.getRoutes(),r={};for(let{method:o,path:n,handler:a}of t){let i=a._defineHandler,s=V(n);r[s]||(r[s]={}),r[s][o.toLowerCase()]=i?await z(o,i):{responses:{200:{description:"Success"}}};}return {openapi:"3.1.0",info:e.info,paths:r}}var S=null,M=false,U=false,b=new Set;async function Je(e,t$1=v){let{platform:r="node"}=t$1,o=t$1.isDev&&B.isPrimary&&!process.env.LACIS_BUN_WORKER;try{t$1.routes?(y(),n(),s(t$1.routes)):await t(e);let n$1=null,a=null;t$1.openapi&&(n$1=await L(t$1.openapi),a=t$1.openapi.path??"/openapi.json"),o&&p$1(`\u{1F4C2} Routes loaded from: ${e}`);let s$1=P(r).createHandler(e),d;switch(r){case "node":d=await s$1(t$1),S=d,S.on("connection",c=>{b.add(c),c.on("close",()=>b.delete(c));});break;case "bun":d=s$1(t$1);break;case "vercel":case "netlify":d=s$1;break;default:throw new Error(`Unsupported platform: "${r}"`)}return n$1&&a&&(q.addRoute("GET",a,(c,l)=>l.json(n$1)),o&&p$1(`OpenAPI doc available at ${a}`)),Q(),d}catch(n){throw o&&p$1("\u274C Failed to create server:",n),n}}function Q(){if(!B.isPrimary||U)return;U=true;let e=async t=>{if(!M){if(M=true,p$1(`
2
+ ${t} received, shutting down...`),await m$1(),S&&typeof S.close=="function"){for(let r of b)r.destroy();b.clear(),await new Promise(r=>{S.close(()=>r()),setTimeout(()=>r(),3e3);});}process.exit(0);}};process.on("SIGINT",()=>e("SIGINT")),process.on("SIGTERM",()=>e("SIGTERM")),process.on("SIGHUP",()=>e("SIGHUP"));}var m={OK:200,CREATED:201,NO_CONTENT:204,BAD_REQUEST:400,UNAUTHORIZED:401,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,CONFLICT:409,UNPROCESSABLE_ENTITY:422,TOO_MANY_REQUESTS:429,INTERNAL_SERVER_ERROR:500,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504},J={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",409:"Conflict",422:"Unprocessable Entity",429:"Too Many Requests",500:"Internal Server Error",503:"Service Unavailable",504:"Gateway Timeout"};function p(e){let t=e.code||m.INTERNAL_SERVER_ERROR,r=e.message||J[t]||"Unknown Error",o=e.name||`HttpError${t}`,n=new Error(r);return Error.captureStackTrace?.(n,p),{name:o,code:t,message:r,details:e.details,expose:e.expose!==void 0?e.expose:t<500,log:e.log!==void 0?e.log:t>=500,stack:n.stack}}function W(e){let t={error:e.message,code:e.code};return e.expose&&e.details?{...t,details:e.details}:t}function F(e,t){t.headersSent||(t.statusCode=e.code,t.setHeader("Content-Type","application/json"),t.end(JSON.stringify(W(e)))),e.log&&$(e);}function $(e){let t={name:e.name,message:e.message,code:e.code,details:e.details,stack:e.stack};e.code>=500?p$1("\u274C ERROR:",JSON.stringify(t,null,2)):p$1("\u26A0\uFE0F WARNING:",JSON.stringify(t,null,2));}function Ke(e,t){return p({name:"BadRequestError",code:m.BAD_REQUEST,message:e,details:t})}function Xe(e,t){return p({name:"UnauthorizedError",code:m.UNAUTHORIZED,message:e,details:t})}function Ye(e,t){return p({name:"ForbiddenError",code:m.FORBIDDEN,message:e,details:t})}function Ze(e,t){return p({name:"NotFoundError",code:m.NOT_FOUND,message:e,details:t})}function et(e,t){return p({name:"MethodNotAllowedError",code:m.METHOD_NOT_ALLOWED,message:e,details:t})}function tt(e,t){return p({name:"ConflictError",code:m.CONFLICT,message:e,details:t})}function rt(e,t){return p({name:"ValidationError",code:m.UNPROCESSABLE_ENTITY,message:e,details:t,expose:true})}function G(e,t){return p({name:"RateLimitError",code:m.TOO_MANY_REQUESTS,message:e,details:t})}function K(e,t){return p({name:"InternalServerError",code:m.INTERNAL_SERVER_ERROR,message:e,details:t})}function X(e,t){return p({name:"ServiceUnavailableError",code:m.SERVICE_UNAVAILABLE,message:e,details:t})}function Y(e,t){return p({name:"GatewayTimeoutError",code:m.GATEWAY_TIMEOUT,message:e,details:t})}function nt(e){if(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e)return e;let t=e?.message||"Unknown error occurred",r=e?.stack?{stack:e.stack}:void 0,o=e?.code||e?.statusCode;return o==="ECONNREFUSED"||o==="ENOTFOUND"?X(`Service connection failed: ${t}`,r):o==="ETIMEDOUT"?Y(`Request timed out: ${t}`,r):typeof o=="number"&&o>=400&&o<600?p({code:o,message:t,details:r}):K(t,r)}function ot(e){return !!(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e&&"name"in e)}function it(e={}){let t=e.windowMs??6e4,r=e.max??100,o=e.message??"Too Many Requests",n=e.keyGenerator??(s=>{let d=s.headers["x-forwarded-for"];return (typeof d=="string"?d.split(",")[0].trim():s.socket?.remoteAddress)??"unknown"}),a=new Map;return setInterval(()=>{let s=Date.now();for(let[d,c]of a)s>=c.resetAt&&a.delete(d);},t).unref(),(s,d)=>{let c=n(s),l=Date.now(),u=a.get(c);(!u||l>=u.resetAt)&&(u={count:0,resetAt:l+t},a.set(c,u)),u.count++;let y=Math.max(0,r-u.count),g=Math.ceil(u.resetAt/1e3);if(d.setHeader("X-RateLimit-Limit",String(r)),d.setHeader("X-RateLimit-Remaining",String(y)),d.setHeader("X-RateLimit-Reset",String(g)),u.count>r)return d.setHeader("Retry-After",String(Math.ceil((u.resetAt-l)/1e3))),F(G(o),d),false}}export{m as HTTP_STATUS,L as buildOpenApiDoc,Ke as createBadRequestError,tt as createConflictError,Ye as createForbiddenError,Y as createGatewayTimeoutError,p as createHttpError,K as createInternalServerError,et as createMethodNotAllowedError,Ze as createNotFoundError,it as createRateLimit,G as createRateLimitError,Ne as createResponseCache,Je as createServer,X as createServiceUnavailableError,R as createStore,Xe as createUnauthorizedError,rt as createValidationError,T as defaultCacheKey,v as defaultConfig,_e as defineHandler,ke as getConfig,h as interceptResponse,ot as isHttpError,$ as logError,nt as normalizeError,C as replayEntry,F as sendError,Ie as withCache};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lacis",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Zero-dependency TypeScript web framework",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,26 +0,0 @@
1
- import W,{join}from'path';import We from'fs/promises';import {existsSync}from'fs';import B from'cluster';import ye,{IncomingMessage,ServerResponse}from'http';import rt from'https';import*as H from'os';import H__default from'os';import {EventEmitter}from'events';import {Socket}from'net';var A={beforeRequest:[],afterRequest:[],onError:[]},P=new Map,I=new Map;function le(t,e){return A[t].push(e),{remove:()=>{let r=A[t].indexOf(e);r!==-1&&A[t].splice(r,1);}}}function be(t,e,r,n){return t.has(e)||t.set(e,{beforeRequest:[],afterRequest:[],onError:[]}),t.get(e)[r].push(n),{remove:()=>{let o=t.get(e);if(!o)return;let s=o[r].indexOf(n);s!==-1&&o[r].splice(s,1);}}}function wt(t,e,r){return be(P,t==="/"?"/":t.replace(/\/+$/,""),e,r)}function Rt(t,e,r){return be(I,t==="/"?"/":t.replace(/\/+$/,""),e,r)}function G(t,e,r){let n=t.get(e);n&&(r.beforeRequest.push(...n.beforeRequest),r.afterRequest.push(...n.afterRequest),r.onError.push(...n.onError));}function Fe(t){let e=t==="/"?"/":t.replace(/\/+$/,""),r=e.split("/").filter(Boolean),n={beforeRequest:[...A.beforeRequest],afterRequest:[...A.afterRequest],onError:[...A.onError]};G(P,"/",n),e==="/"&&G(I,"/",n);let o="";for(let s of r)o+="/"+s,G(P,o,n),o===e&&G(I,o,n);return n}function k(){return A.beforeRequest.length>0||A.afterRequest.length>0||A.onError.length>0||P.size>0||I.size>0}async function _(t,e,r,n){let o=e.url?.split("?")[0]||"/",s=Fe(o);if(s[t].length===0)return true;for(let i of s[t])try{if(await i(e,r,n)===!1)return !1}catch(l){if(t!=="onError")try{for(let a of s.onError)await a(e,r,{error:l,phase:t});}catch(a){console.error("Error in error handler:",a);}return false}return true}function Je(t,e,r){e.has(r)||e.set(r,{beforeRequest:[],afterRequest:[],onError:[]});let n=e.get(r);for(let o of ["beforeRequest","afterRequest","onError"])if(t[o]){let s=Array.isArray(t[o])?t[o]:[t[o]];n[o].push(...s);}}async function de(t){P.clear(),I.clear();async function e(r,n=""){try{let o=await We.readdir(r,{withFileTypes:!0});for(let[s,i]of [["+middleware.global.ts",P],["+middleware.global.js",P],["+middleware.ts",I],["+middleware.js",I]]){let l=o.find(a=>a.name===s);if(l)try{let c=await import(`${W.resolve(W.join(r,l.name))}?update=${Date.now()}`);Je(c,i,n);}catch(a){console.error(`Error loading middleware for ${n}:`,a);}}for(let s of o)s.isDirectory()&&await e(W.join(r,s.name),`${n==="/"?"":n}/${s.name}`);}catch(o){console.error(`Error scanning directory ${r}:`,o);}}await e(t,"/");}function Ct(){return P}function St(){A.beforeRequest=[],A.afterRequest=[],A.onError=[],P.clear(),I.clear();}function j(t){if(t)for(let e of ["beforeRequest","afterRequest","onError"]){let r=t[e];if(r){let n=Array.isArray(r)?r:[r];for(let o of n)le(e,o);}}}function ze(t,e){return !e||e==="*"?true:typeof e=="string"?t===e:Array.isArray(e)?e.includes(t):e instanceof RegExp?e.test(t):typeof e=="function"?e(t):false}function Ve(t){let e=(t.methods??["GET","POST","PUT","DELETE","PATCH","OPTIONS"]).join(", "),r=(t.allowedHeaders??["Content-Type","Authorization"]).join(", "),n=t.exposedHeaders?.join(", "),o=t.maxAge!=null?String(t.maxAge):null,s=!t.origin||t.origin==="*";return async(i,l)=>{let a=i.getHeader("origin");if(!a||!ze(a,t.origin))return;let c=s&&!t.credentials;if(l.setHeader("Access-Control-Allow-Origin",c?"*":a),c||l.setHeader("Vary","Origin"),t.credentials&&l.setHeader("Access-Control-Allow-Credentials","true"),n&&l.setHeader("Access-Control-Expose-Headers",n),i.method==="OPTIONS")return l.setHeader("Access-Control-Allow-Methods",e),l.setHeader("Access-Control-Allow-Headers",r),o&&l.setHeader("Access-Control-Max-Age",o),l.status(204),l.end(),false}}function L(t){t&&le("beforeRequest",Ve(t));}function y(...t){B.isPrimary&&console.log(...t);}function Ye(t){let e=t.match(/^\[(\w+)(\??)]/);return e?{name:e[1],isParam:true,isOptional:e[2]==="?"}:{name:t,isParam:false,isOptional:false}}var Ze=1e3,et=100,ce=class{rootNode;cachedRoutes;routeCount;lastLoaded;verbose;constructor(){this.rootNode=this.createNode(),this.cachedRoutes=new Map,this.routeCount=0,this.lastLoaded=0,this.verbose=false;}createNode(){return {handlers:Object.create(null),staticChildren:new Map,paramChild:null,wildcardHandler:null,isEndpoint:false}}addRoute(e,r,n){let o=r.split("/").filter(Boolean),s=this.rootNode;for(let i of o){let l=Ye(i);if(l.isParam){if(!s.paramChild)s.paramChild={name:l.name,node:this.createNode(),isOptional:l.isOptional};else if(s.paramChild.name!==l.name)throw new Error(`Route conflict: param name "[${l.name}]" conflicts with existing "[${s.paramChild.name}]" at the same path position. Use the same param name for all methods at this level.`);s=s.paramChild.node;}else {if(i==="*")return s.wildcardHandler||(s.wildcardHandler=Object.create(null)),s.wildcardHandler[e]=n,this.cachedRoutes.clear(),this;s.staticChildren.has(i)||s.staticChildren.set(i,this.createNode()),s=s.staticChildren.get(i);}}return s.isEndpoint=true,s.handlers[e]||this.routeCount++,s.handlers[e]=n,this.cachedRoutes.clear(),this}findRoute(e,r){let n=r==="/"?"/":r.replace(/\/+$/,""),o=e+":"+n,s=this.cachedRoutes.get(o);if(s)return this.cachedRoutes.delete(o),this.cachedRoutes.set(o,s),s;let i=n==="/"?[]:n.split("/").filter(Boolean),l=Object.create(null),a=this.traverse(this.rootNode,i,e,l,0)??{handler:null,params:Object.create(null)};if(a.handler!==null||a.allowedMethods?.length){if(this.cachedRoutes.size>=Ze){let c=0;for(let d of this.cachedRoutes.keys())if(this.cachedRoutes.delete(d),++c>=et)break}this.cachedRoutes.set(o,a);}return a}traverse(e,r,n,o,s){if(s===r.length){if(e.isEndpoint){let c=e.handlers[n]??(n==="HEAD"?e.handlers.GET:void 0)??e.handlers[""];if(c)return {handler:c,params:Object.assign(Object.create(null),o)};let d=Object.keys(e.handlers).filter(h=>h!=="");return {handler:null,params:Object.create(null),allowedMethods:d}}let a=e.paramChild;if(a?.isOptional&&a.node.isEndpoint){let c=a.node.handlers[n]??(n==="HEAD"?a.node.handlers.GET:void 0)??a.node.handlers[""];if(c)return {handler:c,params:Object.assign(Object.create(null),o)}}return null}let i=r[s],l=e.staticChildren.get(i);if(l){let a=this.traverse(l,r,n,o,s+1);if(a)return a}if(e.paramChild){let{name:a,node:c}=e.paramChild;o[a]=i;let d=this.traverse(c,r,n,o,s+1);if(d)return d;delete o[a];}if(e.wildcardHandler){let a=e.wildcardHandler[n]??e.wildcardHandler[""],c=r.slice(s).join("/");if(a)return {handler:a,params:Object.assign(Object.create(null),o,{"*":c})};let d=Object.keys(e.wildcardHandler).filter(h=>h!=="");if(d.length>0)return {handler:null,params:Object.assign(Object.create(null),o,{"*":c}),allowedMethods:d}}return null}async loadRoutes(e){this.rootNode=this.createNode(),this.cachedRoutes.clear(),this.routeCount=0,await de(e);let r=this;async function n(o,s=[]){try{let i=await We.readdir(o,{withFileTypes:!0}),l=i.find(a=>!a.isDirectory()&&(a.name==="index.ts"||a.name==="index.js"));if(l)try{let c=await import(`${W.resolve(W.join(o,l.name))}?update=${Date.now()}`),d=["GET","POST","PUT","DELETE","PATCH"],h="/"+s.join("/"),g=!1;for(let w of d)typeof c[w]=="function"&&(r.addRoute(w,h,c[w]),g=!0);!g&&typeof c.default=="function"&&r.addRoute("GET",h,c.default),r.verbose&&y(`Route loaded: ${h}`);}catch(a){console.error(`Error loading index in ${o}:`,a);}for(let a of i)if(a.isDirectory()){let c=a.name.match(/^\[(\w+)(\??)]/),d=c?`[${c[1]}${c[2]}]`:a.name;await n(W.join(o,a.name),[...s,d]);}}catch(i){console.error(`Error scanning directory ${o}:`,i);}}return await n(e),this.lastLoaded=Date.now(),this.verbose&&y(`Loading completed: ${this.routeCount} routes`),true}getRoutes(){let e=[];return this.collectRoutes(this.rootNode,[],e),e}collectRoutes(e,r,n){if(e.isEndpoint){let o=r.length===0?"/":"/"+r.join("/");for(let[s,i]of Object.entries(e.handlers))s!==""&&n.push({method:s,path:o,handler:i});}for(let[o,s]of e.staticChildren)this.collectRoutes(s,[...r,o],n);if(e.paramChild){let{name:o,isOptional:s,node:i}=e.paramChild;this.collectRoutes(i,[...r,s?`:${o}?`:`:${o}`],n);}if(e.wildcardHandler){let o="/"+[...r,"*"].join("/");for(let[s,i]of Object.entries(e.wildcardHandler))s!==""&&n.push({method:s,path:o,handler:i});}}getStats(){return {routeCount:this.routeCount,lastLoaded:this.lastLoaded,uptime:Date.now()-this.lastLoaded,cacheSize:this.cachedRoutes.size}}setVerbose(e){return this.verbose=e,this}reset(){this.rootNode=this.createNode(),this.cachedRoutes=new Map,this.routeCount=0;}},D=new ce;function K(t){return t&&typeof t=="object"&&"error"in t}function J(t){for(let{path:e,handlers:r}of t){let n=e.replace(/:(\w+\??)/g,(o,s)=>s.endsWith("?")?`[${s.slice(0,-1)}?]`:`[${s}]`);for(let[o,s]of Object.entries(r))typeof s=="function"&&D.addRoute(o,n,s);}}async function Q(t){let e=join(t,"_manifest.js");if(existsSync(e)){D.reset(),await de(t);let r=await import(e);J(r.routes);return}return D.loadRoutes(t)}function U(t,e="GET"){let r=D.findRoute(e,t);return r.handler?{handler:r.handler,params:r.params}:r.allowedMethods?.length?{error:"Method Not Allowed",status:405,allowedMethods:r.allowedMethods}:null}function $t(t){let e=process.env.NODE_ENV==="production",r=process.env.ROUTES_DIR??t??(e?"dist/routes":"routes"),n=e&&!W.isAbsolute(r)&&!r.startsWith("dist/")?W.join("dist",r):r;return W.resolve(process.cwd(),n)}function Pt(){return D.getStats()}function qt(t){D.setVerbose(t);}function It(){D.reset();}function Ee(t,e={},r={},n){let o=false,s=0,i={},l=[],a=[],c=[],d=null;r.onMessage&&l.push(r.onMessage),r.onClose&&a.push(r.onClose),r.onError&&c.push(r.onError),r.onEvent&&Object.entries(r.onEvent).forEach(([f,m])=>{i[f]||(i[f]=[]),i[f].push(m);});let h=e.reconnectInterval||3e3,g=e.maxRetries||3,w=e.disableReconnect||false,R=e.body,p=e.contentType||(R?"application/json":void 0),u=e.method||(R?"POST":"GET");if(typeof t!="string"){let f=t;return o=true,f.on("data",m=>{v(m.toString());}),f.on("end",()=>{o=false;}),f.on("error",m=>{o=false,console.error("SSE Error:",m);}),b()}if(typeof t=="string")return new Promise((f,m)=>{$().then(()=>f(b())).catch(m);});function v(f){let m=f,S=m.split(`
2
-
3
- `);m=S.pop()||"";for(let M of S){let O=M.split(`
4
- `),C="",E="";for(let T of O)T.startsWith("event:")?E=T.slice(6).trim():T.startsWith("data:")&&(C=T.slice(5).trim());if(C)try{let T=JSON.parse(C);E&&i[E]?i[E].forEach(F=>F(T)):l.forEach(F=>F(T));}catch{E&&i[E]?i[E].forEach(T=>T(C)):l.forEach(T=>T(C));}}}function b(){return {onMessage(f){return l.push(f),this},onEvent(f,m){return i[f]||(i[f]=[]),i[f].push(m),this},onClose(f){return a.push(f),this},close(){d&&(d.destroy(),d=null),o=false,a.forEach(f=>f());}}}async function $(){if(!o){o=true;try{await x();}catch(f){!w&&s<g?(s++,setTimeout(()=>{$();},h)):c.forEach(m=>m(f));}}}async function x(){return new Promise((f,m)=>{let S=new URL(t);e.params&&(typeof e.params=="object"?Object.entries(e.params).forEach(([C,E])=>{S.searchParams.append(C,String(E));}):typeof e.params=="string"&&new URLSearchParams(e.params).forEach((E,T)=>{S.searchParams.append(T,E);}));let M={hostname:S.hostname,port:S.port||(S.protocol==="https:"?443:80),path:S.pathname+S.search,method:u,headers:{Accept:"text/event-stream",...n?.headers||{},"Cache-Control":"no-cache",Connection:"keep-alive",...p&&{"Content-Type":p},...R&&typeof R=="string"&&{"Content-Length":Buffer.byteLength(R).toString()},...R&&typeof R!="string"&&{"Content-Length":Buffer.byteLength(JSON.stringify(R)).toString()}}};d=(S.protocol==="https:"?rt:ye).request(M,C=>{if(C.statusCode!==200){o=false,m(new Error(`Server responded with status: ${C.statusCode}`));return}C.setEncoding("utf8"),C.on("data",v),C.on("end",()=>{o=false,d?.destroy(),d=null,a.forEach(E=>E()),f(null);}),C.on("close",()=>{o=false,d?.destroy(),d=null,a.forEach(E=>E()),f(null);}),C.on("error",E=>{o=false,d?.destroy(),d=null,a.forEach(T=>T()),m(E);});}),d.on("error",C=>{o=false,d?.destroy(),d=null,m(C);}),R&&(typeof R=="string"?d.write(R):d.write(JSON.stringify(R))),d.end();})}return b()}function Me(t,e){let r=e?.headers?.["Cache-Control"]||"no-cache",n=e?.headers?.Connection||"keep-alive",o=e?.timeout||3e5;t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":r,Connection:n,...e?.headers||{}});let s=setTimeout(()=>{t.end();},o);return t.on("close",()=>{clearTimeout(s);}),s}function xe(t,e){return t.writableEnded?false:t.write(`data: ${e}
5
-
6
- `)}function Te(t,e){return t.writableEnded?false:t.write(`data: ${JSON.stringify(e)}
7
-
8
- `)}function ke(t,e,r){return t.writableEnded?false:(t.write(`event: ${e}
9
- `),t.write(`data: ${JSON.stringify(r)}
10
-
11
- `))}function _e(t,e){return t.writableEnded?false:t.write(`: ${e}
12
-
13
- `)}function He(t,e){return t.writableEnded?false:t.write(`id: ${e}
14
-
15
- `)}function Oe(t,e){return t.writableEnded?false:t.write(`retry: ${e}
16
-
17
- `)}function Ae(t,e="Connection closed"){t.write(`: ${e}
18
-
19
- `),t.end();}function $e(t,e,r,n=500,o){t.writeHead(n,{"Content-Type":"text/event-stream"}),t.write(`event: ${e}
20
- `);let s={message:r,code:n,details:o||null};t.write(`data: ${JSON.stringify(s)}
21
-
22
- `),t.end();}var st=10485760,Y=class{_parsed=null;_raw;constructor(e){this._raw=e;}_parse(){if(this._parsed!==null)return this._parsed;if(this._parsed={},!this._raw)return this._parsed;for(let e of this._raw.split(";")){let r=e.indexOf("=");if(r===-1)continue;let n=e.slice(0,r).trim(),o=e.slice(r+1).trim();if(n){let s=o.startsWith('"')&&o.endsWith('"')?o.slice(1,-1):o;try{this._parsed[n]=decodeURIComponent(s);}catch{this._parsed[n]=s;}}}return this._parsed}get(e){return this._parse()[e]}all(){return {...this._parse()}}},Z=class{_pending=[];set(e,r,n={}){return this._pending.push({name:e,value:r,opts:n}),this}delete(e,r={}){return this.set(e,"",{...r,maxAge:0,expires:new Date(0)})}serialize(){return this._pending.map(({name:e,value:r,opts:n})=>{let o=`${e}=${encodeURIComponent(r)}`,s=n.path!==void 0?n.path:"/";return s&&(o+=`; Path=${s}`),n.domain&&(o+=`; Domain=${n.domain}`),n.maxAge!=null&&(o+=`; Max-Age=${n.maxAge}`),n.expires&&(o+=`; Expires=${n.expires.toUTCString()}`),n.httpOnly&&(o+="; HttpOnly"),n.secure&&(o+="; Secure"),n.sameSite&&(o+=`; SameSite=${n.sameSite}`),o})}};function Pe(t){if(typeof t.get=="function")return t.get("cookie")??void 0;let e=t.cookie;return Array.isArray(e)?e.join("; "):e}function z(t){return class extends t{_zreqCookies;getHeader(e){let r=this.headers;if(typeof r.get=="function")return r.get(e)??void 0;let n=r[e.toLowerCase()];return Array.isArray(n)?n[0]:n}get cookies(){return this._zreqCookies||(this._zreqCookies=new Y(Pe(this.headers))),this._zreqCookies}json(){return this.body().then(e=>JSON.parse(e.toString()))}form(){return new Promise((e,r)=>{let n=this.headers,o=typeof n.get=="function"?n.get("content-type")??"":n["content-type"]??"";if(!o.startsWith("multipart/form-data")){r(new Error("Content-Type is not multipart/form-data"));return}let s=o.match(/boundary=(.+)$/);if(!s){r(new Error("Boundary not found"));return}let i=s[1].trim();this.body().then(l=>{let a={},c=Buffer.from(`--${i}`),d=[],h=0,g;for(;(g=l.indexOf(c,h))!==-1;)d.push(l.subarray(h,g)),h=g+c.length;d.push(l.subarray(h));for(let w=1;w<d.length-1;w++){let R=d[w].subarray(2),p=R.indexOf(`\r
23
- \r
24
- `);if(p===-1)continue;let u=R.subarray(0,p).toString(),v=R.subarray(p+4,R.length-2),b=u.match(/Content-Disposition: form-data; name="([^"]+)"(?:; filename="([^"]+)")?/i);if(b)if(b[2]){let $=u.match(/Content-Type:\s*([^\r\n]+)/i);a[b[1]]={filename:b[2],mimetype:$?$[1].trim():"application/octet-stream",data:v,size:v.length};}else a[b[1]]=v.toString("utf-8");}e(a);}).catch(r);})}createSSEClient(e,r){return Ee(this,e,r)}}}function ee(){let t=[],e=0,r=false;return new Promise((n,o)=>{this.on("data",s=>{if(e+=s.length,e>st){r=true,this.destroy(),o(Object.assign(new Error("Payload Too Large"),{code:413}));return}t.push(s);}).on("end",()=>{r||(r=true,n(Buffer.concat(t)));}).on("error",s=>{r||(r=true,o(s));});})}function qe(t,e){let r=t.serialize();r.length>0&&!e.headersSent&&e.setHeader("Set-Cookie",r);}function V(t){return class extends t{_zresCookies;get cookies(){return this._zresCookies||(this._zresCookies=new Z),this._zresCookies}end(e){return this._zresCookies&&qe(this._zresCookies,this),super.end(e)}status(e){return this.statusCode=e,this}send(e){return typeof e=="string"?(this.setHeader("Content-Type","text/plain"),this.end(e)):this.json(e),this}json(e){return this.setHeader("Content-Type","application/json"),this.end(JSON.stringify(e)),this}html(e){return this.setHeader("Content-Type","text/html; charset=utf-8"),this.end(e),this}redirect(e,r=302){return this.statusCode=r,this.setHeader("Location",e),this.end(),this}initSSE(e){return Me(this,e)}sseSend(e){xe(this,e);}sseJson(e){Te(this,e);}sseEvent(e,r){ke(this,e,r);}sseComment(e){_e(this,e);}sseId(e){He(this,e);}sseRetry(e){Oe(this,e);}sseClose(e){Ae(this,e);}sseError(e,r,n=500,o){$e(this,e,r,n,o);}}}var ue=class{params={};headers={};body(){return ee.call(this)}},X=z(ue).prototype,fe=class{statusCode=200;headersSent=false;setHeader(e,r){}end(e){}write(e){}},nt=V(fe).prototype;function te(t){t.body=ee,t.json=X.json,t.form=X.form,t.getHeader=X.getHeader,t.createSSEClient=X.createSSEClient,t.cookies=new Y(Pe(t.headers));}function re(t){let e=t.indexOf("?");return e===-1?t:t.slice(0,e)}function se(t){let e=t.indexOf("?");return e===-1?{}:Object.fromEntries(new URLSearchParams(t.slice(e+1)).entries())}async function q(t,e,r){console.error("[lacis] Unhandled error:",r),k()&&await _("onError",t,e,{error:r});}function ne(t){let e=nt;t.status=e.status,t.send=e.send,t.json=e.json,t.html=e.html,t.redirect=e.redirect,t.initSSE=e.initSSE,t.sseSend=e.sseSend,t.sseJson=e.sseJson,t.sseEvent=e.sseEvent,t.sseComment=e.sseComment,t.sseId=e.sseId,t.sseRetry=e.sseRetry,t.sseClose=e.sseClose,t.sseError=e.sseError;let r=new Z;t.cookies=r;let n=t.end.bind(t);t.end=function(...o){return qe(r,this),n(...o)};}var oe=null;function at(t={}){let e=new EventEmitter,r={sampleInterval:t.sampleInterval||5e3,reportInterval:t.reportInterval||6e4,resetInterval:t.resetInterval||1440*60*1e3,enableHistogram:t.enableHistogram!==void 0?t.enableHistogram:true,logToConsole:t.logToConsole!==void 0?t.logToConsole:true,thresholds:{cpu:t.thresholds?.cpu||80,memory:t.thresholds?.memory||80,responseTime:t.thresholds?.responseTime||1e3,errorRate:t.thresholds?.errorRate||5}},n=Date.now(),o={requestCount:0,activeRequests:0,errorCount:0,responseTimes:[],responseTimesBucket:Array(100).fill(0),statusCodes:{},lastReport:n,lastReset:n},s=c(),i=[],l=process.cpuUsage(),a={cpu:false,memory:false,responseTime:false,errorRate:false};function c(){return {timestamp:Date.now(),uptime:process.uptime(),requestCount:0,activeRequests:0,errorCount:0,responseTimes:{min:0,max:0,avg:0,count:0,sum:0},statusCodes:{},memory:process.memoryUsage(),cpu:{usage:0,system:0,user:0},systemLoad:H.loadavg(),systemMemory:{total:H.totalmem(),free:H.freemem(),used:H.totalmem()-H.freemem()}}}function d(){let f=o.responseTimes;if(f.length===0)return {min:0,max:0,avg:0,count:0,sum:0};let m=1/0,S=-1/0,M=0;for(let E of f)m=Math.min(m,E),S=Math.max(S,E),M+=E;let O=M/f.length,C={min:m,max:S,avg:O,count:f.length,sum:M};if(r.enableHistogram){let E=[...f].sort((T,F)=>T-F);C.p50=E[Math.floor(E.length*.5)],C.p90=E[Math.floor(E.length*.9)],C.p99=E[Math.floor(E.length*.99)];}return C}function h(){let f=Date.now(),m=process.uptime(),S=process.memoryUsage(),M=process.cpuUsage(l);l=process.cpuUsage();let C=(M.user+M.system)/1e3/r.sampleInterval*100;s={timestamp:f,uptime:m,requestCount:o.requestCount,activeRequests:o.activeRequests,errorCount:o.errorCount,responseTimes:d(),statusCodes:{...o.statusCodes},memory:S,cpu:{usage:C,system:M.system,user:M.user},systemLoad:H.loadavg(),systemMemory:{total:H.totalmem(),free:H.freemem(),used:H.totalmem()-H.freemem()}},i.push({...s}),i.length>100&&i.shift(),R(),B.isWorker&&process.send&&process.send({type:"metrics",metrics:s});}function g(){if(!r.logToConsole||B.isPrimary===false)return;let f={rss:(s.memory.rss/1024/1024).toFixed(2),heapTotal:(s.memory.heapTotal/1024/1024).toFixed(2),heapUsed:(s.memory.heapUsed/1024/1024).toFixed(2)},m=Date.now()-o.lastReport,S=(s.requestCount/(m/1e3)).toFixed(2),M=s.requestCount?(s.errorCount/s.requestCount*100).toFixed(2):"0.00";y(`
25
- \u{1F4CA} Server Performance Metrics \u{1F4CA}`),y(`Uptime: ${p(s.uptime)}`),y(`Load: ${s.systemLoad[0].toFixed(2)}, ${s.systemLoad[1].toFixed(2)}, ${s.systemLoad[2].toFixed(2)}`),y(`Requests: ${s.requestCount} total, ${S} req/sec`),y(`Active Requests: ${s.activeRequests}`),y(`Errors: ${s.errorCount} (${M}%)`),s.responseTimes.count>0&&(y(`Response Times: avg ${s.responseTimes.avg.toFixed(2)}ms, min ${s.responseTimes.min}ms, max ${s.responseTimes.max}ms`),s.responseTimes.p50&&y(`Response Time Percentiles: p50 ${s.responseTimes.p50}ms, p90 ${s.responseTimes.p90}ms, p99 ${s.responseTimes.p99}ms`)),y(`Memory: ${f.rss}MB (RSS), ${f.heapUsed}MB / ${f.heapTotal}MB (Heap)`),y(`CPU Usage: ${s.cpu.usage.toFixed(2)}%`),Object.keys(s.statusCodes).length>0&&(y("Status Codes:"),Object.entries(s.statusCodes).sort(([O],[C])=>parseInt(O)-parseInt(C)).forEach(([O,C])=>{y(` ${O}: ${C}`);})),y(""),o.lastReport=Date.now();}function w(){let f=Date.now();o.requestCount=0,o.activeRequests=0,o.errorCount=0,o.responseTimes=[],o.responseTimesBucket=Array(100).fill(0),o.statusCodes={},o.lastReport=f,o.lastReset=f,y("\u{1F504} Performance metrics have been reset");}function R(){let f=s.memory.heapUsed/s.memory.heapTotal*100,m=s.requestCount?s.errorCount/s.requestCount*100:0,S=s.responseTimes.avg;s.cpu.usage>r.thresholds.cpu&&!a.cpu?(a.cpu=true,e.emit("alarm","cpu",`High CPU usage: ${s.cpu.usage.toFixed(2)}%`)):s.cpu.usage<=r.thresholds.cpu&&a.cpu&&(a.cpu=false,e.emit("alarm-clear","cpu",`CPU usage returned to normal: ${s.cpu.usage.toFixed(2)}%`)),f>r.thresholds.memory&&!a.memory?(a.memory=true,e.emit("alarm","memory",`High memory usage: ${f.toFixed(2)}%`)):f<=r.thresholds.memory&&a.memory&&(a.memory=false,e.emit("alarm-clear","memory",`Memory usage returned to normal: ${f.toFixed(2)}%`)),S>r.thresholds.responseTime&&!a.responseTime?(a.responseTime=true,e.emit("alarm","responseTime",`High response time: ${S.toFixed(2)}ms`)):S<=r.thresholds.responseTime&&a.responseTime&&(a.responseTime=false,e.emit("alarm-clear","responseTime",`Response time returned to normal: ${S.toFixed(2)}ms`)),m>r.thresholds.errorRate&&!a.errorRate?(a.errorRate=true,e.emit("alarm","errorRate",`High error rate: ${m.toFixed(2)}%`)):m<=r.thresholds.errorRate&&a.errorRate&&(a.errorRate=false,e.emit("alarm-clear","errorRate",`Error rate returned to normal: ${m.toFixed(2)}%`));}function p(f){let m=Math.floor(f/86400),S=Math.floor(f%86400/3600),M=Math.floor(f%3600/60),O=Math.floor(f%60),C=[];return m>0&&C.push(`${m}d`),S>0&&C.push(`${S}h`),M>0&&C.push(`${M}m`),(O>0||C.length===0)&&C.push(`${O}s`),C.join(" ")}function u(){let f=setInterval(h,r.sampleInterval),m=setInterval(g,r.reportInterval),S=setInterval(w,r.resetInterval);return {stop:()=>{clearInterval(f),clearInterval(m),clearInterval(S);}}}function v(){let f=Date.now();return o.activeRequests++,{end:(m,S=false)=>{let M=Date.now()-f;return o.activeRequests--,o.requestCount++,o.responseTimes.push(M),o.responseTimes.length>1e3&&o.responseTimes.shift(),o.statusCodes[m]=(o.statusCodes[m]||0)+1,(S||m>=500)&&o.errorCount++,M}}}function b(){return !Object.values(a).some(f=>f)}function $(){let f=s.memory.heapUsed/s.memory.heapTotal*100,m=s.requestCount?s.errorCount/s.requestCount*100:0;return {status:b()?"healthy":"unhealthy",uptime:s.uptime,responseTimes:{avg:s.responseTimes.avg,p90:s.responseTimes.p90||null,p99:s.responseTimes.p99||null},memory:{usedMB:Math.round(s.memory.heapUsed/1024/1024),totalMB:Math.round(s.memory.heapTotal/1024/1024),percent:f.toFixed(2)},cpu:s.cpu.usage.toFixed(2),requests:{total:s.requestCount,active:s.activeRequests,errors:s.errorCount,errorRate:m.toFixed(2)},alerts:Object.entries(a).filter(([S,M])=>M).map(([S])=>S)}}let x=u();return {trackRequest:v,getMetrics:()=>({...s}),getMetricsHistory:()=>[...i],getHealthMetrics:$,isHealthy:b,stop:x.stop,on:e.on.bind(e),once:e.once.bind(e),off:e.off.bind(e)}}function je(t){if(!oe){let e=at(t),r=e.stop;e.stop=()=>{r(),oe=null;},oe=e;}return oe}function pe(t={}){let e=t.reportInterval??5e3,r={workers:new Map,workerIds:[]};function n(){if(!B.isWorker)return;let c=process.cpuUsage(),d=()=>{if(!process.send)return;let h=process.memoryUsage(),g=process.cpuUsage(c);c=process.cpuUsage();let w=(g.user+g.system)/(e*1e3),R={type:"stats",stats:{pid:process.pid,load:w,lastUsed:Date.now(),memoryUsage:h}};process.send(R);};d(),setInterval(d,e).unref();}function o(){let c=B.fork();r.workers.set(c.id,{pid:c.process.pid,load:0,lastUsed:Date.now(),memoryUsage:{rss:0,heapTotal:0,heapUsed:0,external:0,arrayBuffers:0}}),r.workerIds.push(c.id),y(`Worker ${c.process.pid} started`);}let s=false,i=[];function l(c=H.cpus().length){if(!B.isPrimary)return n();y(`\u{1F9F5} Launching ${c} workers...`);for(let d=0;d<c;d++)o();B.on("message",(d,h)=>{if(h.type==="stats"&&"stats"in h){let g=r.workers.get(d.id);g&&Object.assign(g,h.stats);}}),B.on("exit",(d,h,g)=>{if(r.workers.delete(d.id),r.workerIds=r.workerIds.filter(w=>w!==d.id),s){i.forEach(w=>w());return}y(`Worker ${d.process.pid} died (${g||h}). Restarting...`),setTimeout(()=>o(),1e3);});}function a(c){s=true;let d=Object.keys(B.workers??{});if(d.length===0){c?.();return}let h=d.length;i.push(()=>{h--,h===0&&c?.();});for(let g of d)B.workers?.[g]?.kill();}return {start:l,shutdown:a,getWorkerStats:()=>Array.from(r.workers.entries()),getActiveWorkerCount:()=>r.workerIds.length}}var he=class extends ye.IncomingMessage{params={};body=ee},me=class extends z(he){},ge=class extends V(ye.ServerResponse){},Ue={name:"node",createHandler:t=>{if(typeof t!="string")throw new Error("nodeAdapter requires a routesDir string, not a ServerlessConfig.");let e=t;return async(r={})=>{let{port:n=3e3,defaultHeaders:o,isDev:s,cluster:i,monitoring:l={enabled:false}}=r,a=null;s&&l.enabled&&(a=je({sampleInterval:l.sampleInterval||5e3,reportInterval:l.reportInterval||6e4,thresholds:l.thresholds,logToConsole:true}),B.isPrimary&&(y("\u{1F4CA} Development performance monitoring enabled"),a.on("alarm",(d,h)=>{y(`\u26A0\uFE0F ALERT: ${h}`);}),a.on("alarm-clear",(d,h)=>{y(`\u2705 RESOLVED: ${h}`);})));let c=o?Object.entries(o):[];if(i?.enabled&&B.isPrimary){let d=i.workers??H__default.cpus().length,h=r.httpsOptions?"https":"http";if(y(`\u{1F9F5} Starting server with ${d} workers`),B.schedulingPolicy!==void 0)try{B.schedulingPolicy=B.SCHED_RR;}catch{}let g=pe();return g.start(d),y(`\u{1F680} Server running at ${h}://localhost:${n}/`+(s?" (dev)":"")),s&&a&&y(`\u{1F4CA} Performance monitoring available at http://localhost:${n}/health`),{close:w=>{a&&a.stop(),g.shutdown(w);}}}if(B.isWorker||!i?.enabled){r.routes||await Q(e),L(r.cors),j(r.middleware);let d=async(p,u,v)=>{try{if(s&&a&&p.url==="/health"){u.setHeader("Content-Type","application/json"),u.end(JSON.stringify(a.getHealthMetrics())),v?.end(200);return}let b=p.url||"/",$=re(b);if(p.query=se(b),k()&&(await _("beforeRequest",p,u)===!1||u.headersSent)){v?.end(u.statusCode||204);return}let x=U($,p.method||"GET");if(!x){k()&&await _("onError",p,u),u.status(404).json({error:"Route not found"}),v?.end(404);return}if("error"in x){let f=x.status||500;u.status(f).json({error:x.error}),v?.end(f,!0);return}p.params=x.params,await x.handler(p,u),k()&&await _("afterRequest",p,u),u.headersSent||u.end(),v?.end(u.statusCode||200);}catch(b){await q(p,u,b),u.headersSent||u.status(500).json({error:"Internal Server Error"}),v?.end(u.statusCode||500,true);}},h=(p,u)=>{let v=s&&a?a.trackRequest():null;if(c.length>0)for(let b=0;b<c.length;b++)u.setHeader(c[b][0],c[b][1]);d(p,u,v).catch(b=>{s&&console.error("Fatal error:",b),u.headersSent||(u.statusCode=500,u.end("Server Error")),v?.end(500,true);});},g={IncomingMessage:me,ServerResponse:ge},w=r.httpsOptions?rt.createServer({...g,...r.httpsOptions},h):ye.createServer(g,h);w.on("clientError",(p,u)=>{u.destroyed||u.destroy();});let R=r.httpsOptions?"https":"http";return B.isWorker&&pe().start(),w.listen(n,()=>{i?.enabled?s&&y(`Worker ${process.pid} is listening on port ${n}`):(y(`\u{1F680} Server running at ${R}://localhost:${n}/`+(s?" (dev)":"")),s&&a&&y(`\u{1F4CA} Performance monitoring available at http://localhost:${n}/health`));}),w}return null}}};var De={name:"vercel",createHandler:t=>{if(typeof t=="string")throw new Error("vercelAdapter.createHandler() requires a ServerlessConfig object, not a routesDir string. Import your routes manifest and pass { routes } instead.");let e=null,r=()=>e||(e=(async()=>{J(t.routes),L(t.cors),j(t.middleware);})(),e);return async(n,o)=>{await r(),te(n),ne(o);let s=n,i=o;try{if(k()&&(await _("beforeRequest",s,i)===!1||i.headersSent))return;let l=U(re(s.url??"/"),s.method??"GET");if(!l){i.status(404).json({error:"Route not found"});return}if(K(l)){i.status(l.status??500).json({error:l.error});return}s.params=l.params,await l.handler(s,i),k()&&await _("afterRequest",s,i);}catch(l){await q(s,i,l),i.headersSent||i.status(500).json({error:"Internal server error"});}}}};function we(t,e,r,n){let o=Object.keys(r).length>0;return {statusCode:t,headers:e,...o?{multiValueHeaders:r}:{},body:n}}var Be={name:"netlify",createHandler:t=>{if(typeof t=="string")throw new Error("netlifyAdapter.createHandler() requires a ServerlessConfig object. Run `lacis build` to generate routes/_manifest.ts and pass { routes } instead.");let e=null,r=()=>e||(e=(async()=>{J(t.routes),L(t.cors),j(t.middleware);})(),e);return async(n,o)=>{await r();let s=n.queryStringParameters?"?"+new URLSearchParams(n.queryStringParameters).toString():"",i=n.path+s,l=new IncomingMessage(new Socket);if(l.url=i,l.method=n.httpMethod,l.headers=n.headers,n.body){let p=n.isBase64Encoded?"base64":"utf-8";l.push(Buffer.from(n.body,p));}l.push(null);let a="",c={},d={},h=false,g=new ServerResponse(l);g.writeHead=function(p,u){return g.statusCode=p,u&&(c={...c,...u}),this},g.setHeader=function(p,u){let v=p.toLowerCase();return Array.isArray(u)?(d[v]=u.map(String),c[v]=String(u[0])):c[v]=String(u),this},g.getHeader=function(p){return c[p.toLowerCase()]},g.end=function(p){return h=true,p!==void 0&&(a=typeof p=="string"?p:p.toString()),this},Object.defineProperty(g,"headersSent",{get:()=>h}),te(l),ne(g);let w=l,R=g;w.query=n.queryStringParameters??{};try{if(k()&&(await _("beforeRequest",w,R)===!1||h))return we(R.statusCode,c,d,a);let p=U(n.path,n.httpMethod);return p?K(p)?{statusCode:p.status??500,body:JSON.stringify({error:p.error})}:(w.params=p.params,await p.handler(w,R),k()&&await _("afterRequest",w,R),we(R.statusCode,c,d,a)):{statusCode:404,body:JSON.stringify({error:"Route not found"})}}catch(p){return await q(w,R,p),h?we(R.statusCode,c,d,a):{statusCode:500,body:JSON.stringify({error:"Internal server error"})}}}}};var pt=10485760,ht=new TextEncoder,Re=class{params={};url;method;headers;socket={setTimeout:e=>{}};connection;_req;constructor(e,r,n,o){this._req=e,this.url=r+n,this.method=e.method,this.headers=e.headers,this.connection={remoteAddress:o};}setTimeout(e){}text(){return this._req.text()}body(){return this._req.arrayBuffer().then(e=>{if(e.byteLength>pt)throw Object.assign(new Error("Payload Too Large"),{code:413});return Buffer.from(e)})}},Ce=class extends z(Re){json(){return this._req.json()}},Se=class{statusCode=200;headersSent=false;get finished(){return this.headersSent}get writableEnded(){return this.headersSent}_body=null;_headers=null;_sseReadable=null;_sseWriter=null;_sseWindowClosed=false;_listeners=null;on(e,r){return (e==="finish"||e==="close")&&(this._listeners||(this._listeners=[]),this._listeners.push(r)),this}once(e,r){return this.on(e,r)}emit(e){if((e==="finish"||e==="close")&&this._listeners)for(let r=0;r<this._listeners.length;r++)this._listeners[r]();return true}setHeader(e,r){if(this._headers||(this._headers=[]),Array.isArray(r))for(let n of r)this._headers.push(e,n);else this._headers.push(e,r);return this}getHeader(e){if(!this._headers)return;let r=e.toLowerCase();for(let n=0;n<this._headers.length;n+=2)if(this._headers[n].toLowerCase()===r)return this._headers[n+1]}removeHeader(e){if(!this._headers)return this;let r=e.toLowerCase();for(let n=0;n<this._headers.length;n+=2)if(this._headers[n].toLowerCase()===r){this._headers.splice(n,2);break}return this}hasHeader(e){if(!this._headers)return false;let r=e.toLowerCase();for(let n=0;n<this._headers.length;n+=2)if(this._headers[n].toLowerCase()===r)return true;return false}writeHead(e,r){if(this.statusCode=e,r)for(let[n,o]of Object.entries(r))this.setHeader(n,o);return this}write(e){return this._sseWriter?(this._sseWriter.write(ht.encode(String(e))),true):(this._body=(this._body??"")+e,true)}end(e){if(e!==void 0&&this.write(e),this._sseWriter&&this._sseWriter.close(),this.headersSent=true,this._listeners)for(let r=0;r<this._listeners.length;r++)this._listeners[r]();return this}_initSseStream(){if(this._sseWindowClosed)throw new Error("[lacis/bun] initSSE() must be called synchronously before any `await` in your handler.");let{readable:e,writable:r}=new TransformStream;this._sseReadable=e,this._sseWriter=r.getWriter();}_closeSseWindow(){this._sseWindowClosed=true;}},ve=class extends V(Se){initSSE(e){return this._initSseStream(),super.initSSE(e)}},Ne={name:"bun",createHandler:t=>{if(typeof t!="string")throw new Error("bunAdapter requires a routesDir string, not a ServerlessConfig.");let e=t;return async(r={})=>{let{isDev:n,port:o=3e3,defaultHeaders:s,cluster:i}=r,l=parseInt(process.env.LACIS_BUN_WORKER??"0"),a=l>0;if(i?.enabled&&!a){let h=i.workers??H__default.cpus().length;y(`\u{1F9F5} Starting Bun server with ${h} workers (reusePort)`);let g=Array.from({length:h},()=>Bun.spawn(process.argv,{env:{...process.env,LACIS_BUN_WORKER:String(process.pid)},stdout:"ignore",stderr:"inherit"}));return y(`\u{1F680} Server running at http://localhost:${o}/`),{close:w=>{for(let R of g)R.kill();w?.();}}}if(a){let h=setInterval(()=>{try{process.kill(l,0);}catch{clearInterval(h),process.exit(0);}},2e3);h.unref();}y("\u{1F680} Bun high-performance mode enabled"),r.routes||await Q(e),L(r.cors),j(r.middleware);let c=s?Object.entries(s):[],d=Bun.serve({port:o,reusePort:a,async fetch(h,g){let w=new URL(h.url),R=w.pathname,p=new Ce(h,R,w.search,g?.requestIP(h)?.address??"");p.query=se(w.search);let u=new ve;try{for(let x=0;x<c.length;x++)u.setHeader(c[x][0],c[x][1]);if(k()&&(!await _("beforeRequest",p,u)||u.headersSent))return ae(u);let v=U(R,h.method);if(!v)return k()&&await _("onError",p,u),new Response(JSON.stringify({error:"Route not found"}),{status:404,headers:{"Content-Type":"application/json"}});if("error"in v)return k()&&await _("onError",p,u),new Response(JSON.stringify({error:v.error}),{status:v.status||500,headers:{"Content-Type":"application/json"}});p.params=v.params;let b=null,$=(async()=>{await v.handler(p,u),k()&&await _("afterRequest",p,u),u.headersSent||u.end();})().catch(x=>{b=x,n&&console.error("Server error:",x),u._sseReadable&&!u.headersSent&&u.end();});return u._closeSseWindow(),u._sseReadable?ae(u,u._sseReadable):(await $,b&&(await q(p,u,b),!u.headersSent)?new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}}):ae(u))}catch(v){return await q(p,u,v),u.headersSent?ae(u):new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}})}}});return y(`\u{1F680} Server started on http://localhost:${o}${n?" (dev)":""}`),{close:()=>{d.stop();}}}}};function ae(t,e){let r=e??t._body;if(!t._headers)return new Response(r,{status:t.statusCode});let n=new Headers;for(let o=0;o<t._headers.length;o+=2){let s=t._headers[o],i=t._headers[o+1];s.toLowerCase()==="set-cookie"?n.append(s,i):n.set(s,i);}return new Response(r,{status:t.statusCode,headers:n})}var mt={node:Ue,vercel:De,netlify:Be,bun:Ne};function Ir(t="node"){let e=mt[t];if(!e)throw new Error(`Platform "${t}" not supported`);return e}
26
- export{ke as A,_e as B,He as C,Oe as D,Ae as E,$e as F,Ue as G,De as H,Be as I,Ne as J,Ir as K,le as a,wt as b,Rt as c,Fe as d,k as e,_ as f,de as g,Ct as h,St as i,j,y as k,D as l,K as m,J as n,Q as o,U as p,$t as q,Pt as r,qt as s,It as t,Ve as u,L as v,Ee as w,Me as x,xe as y,Te as z};