lacis 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -190,7 +190,8 @@ The spec is built from all `defineHandler` routes. Routes without `defineHandler
190
190
 
191
191
  | Library | Package to install |
192
192
  |---|---|
193
- | Zod | `zod-to-json-schema` |
193
+ | Zod 4.4+ | none (native) |
194
+ | Zod < 4.4 | `zod-to-json-schema` |
194
195
  | Valibot | `@valibot/to-json-schema` |
195
196
  | ArkType | none (native `.toJsonSchema()`) |
196
197
 
@@ -1,4 +1,4 @@
1
- import { i as Adapter } from '../index-rE4kFMlu.js';
1
+ import { i as Adapter } from '../index-DMyND6f7.js';
2
2
  import 'http';
3
3
 
4
4
  declare const nodeAdapter: Adapter;
@@ -1 +1 @@
1
- export{I as bunAdapter,J as getAdapter,H as netlifyAdapter,F as nodeAdapter,G as vercelAdapter}from'../chunk-QZ3VOPKR.js';
1
+ export{I as bunAdapter,J as getAdapter,H as netlifyAdapter,F as nodeAdapter,G as vercelAdapter}from'../chunk-VQ3XR2HC.js';
@@ -0,0 +1,26 @@
1
+ import z from'path';import De from'fs/promises';import U from'cluster';import he,{IncomingMessage,ServerResponse}from'http';import Qe from'https';import*as q from'os';import q__default from'os';import {EventEmitter}from'events';import {Socket}from'net';var $={beforeRequest:[],afterRequest:[],onError:[]},T=new Map;function ae(t,e){return $[t].push(e),{remove:()=>{let r=$[t].indexOf(e);r!==-1&&$[t].splice(r,1);}}}function ft(t,e,r){let n=t==="/"?"/":t.replace(/\/+$/,"");return T.has(n)||T.set(n,{beforeRequest:[],afterRequest:[],onError:[]}),T.get(n)[e].push(r),{remove:()=>{if(T.has(n)){let s=T.get(n),i=s[e].indexOf(r);i!==-1&&s[e].splice(i,1);}}}}function Be(t){let r=(t==="/"?"/":t.replace(/\/+$/,"")).split("/").filter(Boolean),n={beforeRequest:[...$.beforeRequest],afterRequest:[...$.afterRequest],onError:[...$.onError]},o="";if(T.has("/")){let s=T.get("/");n.beforeRequest.push(...s.beforeRequest),n.afterRequest.push(...s.afterRequest),n.onError.push(...s.onError);}for(let s of r)if(o+="/"+s,T.has(o)){let i=T.get(o);n.beforeRequest.push(...i.beforeRequest),n.afterRequest.push(...i.afterRequest),n.onError.push(...i.onError);}return n}function k(){return $.beforeRequest.length>0||$.afterRequest.length>0||$.onError.length>0?true:T.size>0}async function H(t,e,r,n){let o=e.url?.split("?")[0]||"/",s=Be(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(d){if(t!=="onError")try{for(let a of s.onError)await a(e,r,{error:d,phase:t});}catch(a){console.error("Error in error handler:",a);}return false}return true}async function Ce(t){T.clear();async function e(r,n=""){try{let o=await De.readdir(r,{withFileTypes:!0}),s=o.find(i=>i.name==="+middleware.ts"||i.name==="+middleware.js");if(s){let i=z.join(r,s.name);try{let a=await import(`${z.resolve(i)}?update=${Date.now()}`);if(T.has(n)||T.set(n,{beforeRequest:[],afterRequest:[],onError:[]}),a.beforeRequest){let l=Array.isArray(a.beforeRequest)?a.beforeRequest:[a.beforeRequest];T.get(n).beforeRequest.push(...l);}if(a.afterRequest){let l=Array.isArray(a.afterRequest)?a.afterRequest:[a.afterRequest];T.get(n).afterRequest.push(...l);}if(a.onError){let l=Array.isArray(a.onError)?a.onError:[a.onError];T.get(n).onError.push(...l);}}catch(d){console.error(`Error loading middleware for ${n}:`,d);}}for(let i of o)i.isDirectory()&&await e(z.join(r,i.name),`${n==="/"?"":n}/${i.name}`);}catch(o){console.error(`Error scanning directory ${r}:`,o);}}await e(t,"/");}function pt(){return T}function ht(){$.beforeRequest=[],$.afterRequest=[],$.onError=[],T.clear();}function I(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)ae(e,o);}}}function Ne(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 We(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,d)=>{let a=i.getHeader("origin");if(!a||!Ne(a,t.origin))return;let l=s&&!t.credentials;if(d.setHeader("Access-Control-Allow-Origin",l?"*":a),l||d.setHeader("Vary","Origin"),t.credentials&&d.setHeader("Access-Control-Allow-Credentials","true"),n&&d.setHeader("Access-Control-Expose-Headers",n),i.method==="OPTIONS")return d.setHeader("Access-Control-Allow-Methods",e),d.setHeader("Access-Control-Allow-Headers",r),o&&d.setHeader("Access-Control-Max-Age",o),d.status(204),d.end(),false}}function L(t){t&&ae("beforeRequest",We(t));}function y(...t){U.isPrimary&&console.log(...t);}function Je(t){let e=t.match(/^\[(\w+)(\??)]/);return e?{name:e[1],isParam:true,isOptional:e[2]==="?"}:{name:t,isParam:false,isOptional:false}}var Ve=1e3,Ge=100,ie=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 d=Je(i);if(d.isParam){if(!s.paramChild)s.paramChild={name:d.name,node:this.createNode(),isOptional:d.isOptional};else if(s.paramChild.name!==d.name)throw new Error(`Route conflict: param name "[${d.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 s;let i=n==="/"?[]:n.split("/").filter(Boolean),d=Object.create(null),a=this.traverse(this.rootNode,i,e,d,0)??{handler:null,params:Object.create(null)};if(this.cachedRoutes.size>=Ve){let l=0;for(let u of this.cachedRoutes.keys())if(this.cachedRoutes.delete(u),++l>=Ge)break}return this.cachedRoutes.set(o,a),a}traverse(e,r,n,o,s){if(s===r.length){if(e.isEndpoint){let l=e.handlers[n]??(n==="HEAD"?e.handlers.GET:void 0)??e.handlers[""];if(l)return {handler:l,params:{...o}};let u=Object.keys(e.handlers).filter(h=>h!=="");return {handler:null,params:{},allowedMethods:u}}let a=e.paramChild;if(a?.isOptional&&a.node.isEndpoint){let l=a.node.handlers[n]??(n==="HEAD"?a.node.handlers.GET:void 0)??a.node.handlers[""];if(l)return {handler:l,params:{...o}}}return null}let i=r[s],d=e.staticChildren.get(i);if(d){let a=this.traverse(d,r,n,o,s+1);if(a)return a}if(e.paramChild){let{name:a,node:l}=e.paramChild;o[a]=i;let u=this.traverse(l,r,n,o,s+1);if(u)return u;delete o[a];}if(e.wildcardHandler){let a=e.wildcardHandler[n]??e.wildcardHandler[""],l=r.slice(s).join("/");if(a)return {handler:a,params:{...o,"*":l}};let u=Object.keys(e.wildcardHandler).filter(h=>h!=="");if(u.length>0)return {handler:null,params:{...o,"*":l},allowedMethods:u}}return null}async loadRoutes(e){this.rootNode=this.createNode(),this.cachedRoutes.clear(),this.routeCount=0,await Ce(e);let r=this;async function n(o,s=[]){try{let i=await De.readdir(o,{withFileTypes:!0}),d=i.find(a=>!a.isDirectory()&&(a.name==="index.ts"||a.name==="index.js"));if(d)try{let l=await import(`${z.resolve(z.join(o,d.name))}?update=${Date.now()}`),u=["GET","POST","PUT","DELETE","PATCH"],h="/"+s.join("/"),g=!1;for(let R of u)typeof l[R]=="function"&&(r.addRoute(R,h,l[R]),g=!0);!g&&typeof l.default=="function"&&r.addRoute("GET",h,l.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 l=a.name.match(/^\[(\w+)(\??)]/),u=l?`[${l[1]}${l[2]}]`:a.name;await n(z.join(o,a.name),[...s,u]);}}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;}},B=new ie;function J(t){return t&&typeof t=="object"&&"error"in t}function V(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"&&B.addRoute(o,n,s);}}async function G(t){return B.loadRoutes(t)}function j(t,e="GET"){let r=B.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 bt(t){return z.resolve(process.cwd(),t||process.env.ROUTES_DIR||"routes")}function Mt(){return B.getStats()}function xt(t){B.setVerbose(t);}function Tt(){B.reset();}function Se(t,e={},r={},n){let o=false,s=0,i={},d=[],a=[],l=[],u=null;r.onMessage&&d.push(r.onMessage),r.onClose&&a.push(r.onClose),r.onError&&l.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,R=e.disableReconnect||false,w=e.body,p=e.contentType||(w?"application/json":void 0),c=e.method||(w?"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);}),E()}if(typeof t=="string")return new Promise((f,m)=>{O().then(()=>f(E())).catch(m);});function v(f){let m=f,S=m.split(`
2
+
3
+ `);m=S.pop()||"";for(let M of S){let A=M.split(`
4
+ `),C="",b="";for(let _ of A)_.startsWith("event:")?b=_.slice(6).trim():_.startsWith("data:")&&(C=_.slice(5).trim());if(C)try{let _=JSON.parse(C);b&&i[b]?i[b].forEach(N=>N(_)):d.forEach(N=>N(_));}catch{b&&i[b]?i[b].forEach(_=>_(C)):d.forEach(_=>_(C));}}}function E(){return {onMessage(f){return d.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),o=false,a.forEach(f=>f());}}}async function O(){if(!o){o=true;try{await x();}catch(f){!R&&s<g?(s++,setTimeout(()=>{O();},h)):l.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,b])=>{S.searchParams.append(C,String(b));}):typeof e.params=="string"&&new URLSearchParams(e.params).forEach((b,_)=>{S.searchParams.append(_,b);}));let M={hostname:S.hostname,port:S.port||(S.protocol==="https:"?443:80),path:S.pathname+S.search,method:c,headers:{Accept:"text/event-stream",...n?.headers||{},"Cache-Control":"no-cache",Connection:"keep-alive",...p&&{"Content-Type":p},...w&&typeof w=="string"&&{"Content-Length":Buffer.byteLength(w).toString()},...w&&typeof w!="string"&&{"Content-Length":Buffer.byteLength(JSON.stringify(w)).toString()}}};u=(S.protocol==="https:"?Qe:he).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,u?.destroy(),u=null,a.forEach(b=>b()),f(null);}),C.on("close",()=>{o=false,u?.destroy(),u=null,a.forEach(b=>b()),f(null);}),C.on("error",b=>{o=false,u?.destroy(),u=null,a.forEach(_=>_()),m(b);});}),u.on("error",C=>{o=false,u?.destroy(),u=null,m(C);}),w&&(typeof w=="string"?u.write(w):u.write(JSON.stringify(w))),u.end();})}return E()}function ve(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 Ee(t,e){return t.writableEnded?false:t.write(`data: ${e}
5
+
6
+ `)}function be(t,e){return t.writableEnded?false:t.write(`data: ${JSON.stringify(e)}
7
+
8
+ `)}function Me(t,e,r){return t.writableEnded?false:(t.write(`event: ${e}
9
+ `),t.write(`data: ${JSON.stringify(r)}
10
+
11
+ `))}function xe(t,e){return t.writableEnded?false:t.write(`: ${e}
12
+
13
+ `)}function Te(t,e){return t.writableEnded?false:t.write(`id: ${e}
14
+
15
+ `)}function _e(t,e){return t.writableEnded?false:t.write(`retry: ${e}
16
+
17
+ `)}function ke(t,e="Connection closed"){t.write(`: ${e}
18
+
19
+ `),t.end();}function He(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 Xe=10485760,Q=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()}}},X=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 qe(t){if(typeof t.get=="function")return t.get("cookie")??void 0;let e=t.cookie;return Array.isArray(e)?e.join("; "):e}function W(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 Q(qe(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(d=>{let a={},l=Buffer.from(`--${i}`),u=[],h=0,g;for(;(g=d.indexOf(l,h))!==-1;)u.push(d.subarray(h,g)),h=g+l.length;u.push(d.subarray(h));for(let R=1;R<u.length-1;R++){let w=u[R].subarray(2),p=w.indexOf(`\r
23
+ \r
24
+ `);if(p===-1)continue;let c=w.subarray(0,p).toString(),v=w.subarray(p+4,w.length-2),E=c.match(/Content-Disposition: form-data; name="([^"]+)"(?:; filename="([^"]+)")?/i);if(E)if(E[2]){let O=c.match(/Content-Type:\s*([^\r\n]+)/i);a[E[1]]={filename:E[2],mimetype:O?O[1].trim():"application/octet-stream",data:v,size:v.length};}else a[E[1]]=v.toString("utf-8");}e(a);}).catch(r);})}createSSEClient(e,r){return Se(this,e,r)}}}function Y(){let t=[],e=0,r=false;return new Promise((n,o)=>{this.on("data",s=>{if(e+=s.length,e>Xe){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 Ae(t,e){let r=t.serialize();r.length>0&&!e.headersSent&&e.setHeader("Set-Cookie",r);}function F(t){return class extends t{_zresCookies;get cookies(){return this._zresCookies||(this._zresCookies=new X),this._zresCookies}end(e){return this._zresCookies&&Ae(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}initSSE(e){return ve(this,e)}sseSend(e){Ee(this,e);}sseJson(e){be(this,e);}sseEvent(e,r){Me(this,e,r);}sseComment(e){xe(this,e);}sseId(e){Te(this,e);}sseRetry(e){_e(this,e);}sseClose(e){ke(this,e);}sseError(e,r,n=500,o){He(this,e,r,n,o);}}}var le=class{params={};headers={};body(){return Y.call(this)}},K=W(le).prototype,de=class{statusCode=200;headersSent=false;setHeader(e,r){}end(e){}write(e){}},Ye=F(de).prototype;function Z(t){t.body=Y,t.json=K.json,t.form=K.form,t.getHeader=K.getHeader,t.createSSEClient=K.createSSEClient,t.cookies=new Q(qe(t.headers));}function ee(t){let e=t.indexOf("?");return e===-1?t:t.slice(0,e)}function te(t){let e=t.indexOf("?");return e===-1?{}:Object.fromEntries(new URLSearchParams(t.slice(e+1)).entries())}async function P(t,e,r){console.error("[lacis] Unhandled error:",r),k()&&await H("onError",t,e,{error:r});}function re(t){let e=Ye;t.status=e.status,t.send=e.send,t.json=e.json,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 X;t.cookies=r;let n=t.end.bind(t);t.end=function(...o){return Ae(r,this),n(...o)};}var se=null;function et(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=l(),i=[],d=process.cpuUsage(),a={cpu:false,memory:false,responseTime:false,errorRate:false};function l(){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:q.loadavg(),systemMemory:{total:q.totalmem(),free:q.freemem(),used:q.totalmem()-q.freemem()}}}function u(){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 b of f)m=Math.min(m,b),S=Math.max(S,b),M+=b;let A=M/f.length,C={min:m,max:S,avg:A,count:f.length,sum:M};if(r.enableHistogram){let b=[...f].sort((_,N)=>_-N);C.p50=b[Math.floor(b.length*.5)],C.p90=b[Math.floor(b.length*.9)],C.p99=b[Math.floor(b.length*.99)];}return C}function h(){let f=Date.now(),m=process.uptime(),S=process.memoryUsage(),M=process.cpuUsage(d);d=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:u(),statusCodes:{...o.statusCodes},memory:S,cpu:{usage:C,system:M.system,user:M.user},systemLoad:q.loadavg(),systemMemory:{total:q.totalmem(),free:q.freemem(),used:q.totalmem()-q.freemem()}},i.push({...s}),i.length>100&&i.shift(),w(),U.isWorker&&process.send&&process.send({type:"metrics",metrics:s});}function g(){if(!r.logToConsole||U.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(([A],[C])=>parseInt(A)-parseInt(C)).forEach(([A,C])=>{y(` ${A}: ${C}`);})),y(""),o.lastReport=Date.now();}function R(){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 w(){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),A=Math.floor(f%60),C=[];return m>0&&C.push(`${m}d`),S>0&&C.push(`${S}h`),M>0&&C.push(`${M}m`),(A>0||C.length===0)&&C.push(`${A}s`),C.join(" ")}function c(){let f=setInterval(h,r.sampleInterval),m=setInterval(g,r.reportInterval),S=setInterval(R,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 E(){return !Object.values(a).some(f=>f)}function O(){let f=s.memory.heapUsed/s.memory.heapTotal*100,m=s.requestCount?s.errorCount/s.requestCount*100:0;return {status:E()?"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=c();return {trackRequest:v,getMetrics:()=>({...s}),getMetricsHistory:()=>[...i],getHealthMetrics:O,isHealthy:E,stop:x.stop,on:e.on.bind(e),once:e.once.bind(e),off:e.off.bind(e)}}function Oe(t){if(!se){let e=et(t),r=e.stop;e.stop=()=>{r(),se=null;},se=e;}return se}function ue(t={}){let e=t.reportInterval??5e3,r={workers:new Map,workerIds:[]};function n(){if(!U.isWorker)return;let l=process.cpuUsage(),u=()=>{if(!process.send)return;let h=process.memoryUsage(),g=process.cpuUsage(l);l=process.cpuUsage();let R=(g.user+g.system)/(e*1e3),w={type:"stats",stats:{pid:process.pid,load:R,lastUsed:Date.now(),memoryUsage:h}};process.send(w);};u(),setInterval(u,e).unref();}function o(){let l=U.fork();r.workers.set(l.id,{pid:l.process.pid,load:0,lastUsed:Date.now(),memoryUsage:{rss:0,heapTotal:0,heapUsed:0,external:0,arrayBuffers:0}}),r.workerIds.push(l.id),y(`Worker ${l.process.pid} started`);}let s=false,i=[];function d(l=q.cpus().length){if(!U.isPrimary)return n();y(`\u{1F9F5} Launching ${l} workers...`);for(let u=0;u<l;u++)o();U.on("message",(u,h)=>{if(h.type==="stats"&&"stats"in h){let g=r.workers.get(u.id);g&&Object.assign(g,h.stats);}}),U.on("exit",(u,h,g)=>{if(r.workers.delete(u.id),r.workerIds=r.workerIds.filter(R=>R!==u.id),s){i.forEach(R=>R());return}y(`Worker ${u.process.pid} died (${g||h}). Restarting...`),setTimeout(()=>o(),1e3);});}function a(l){s=true;let u=Object.keys(U.workers??{});if(u.length===0){l?.();return}let h=u.length;i.push(()=>{h--,h===0&&l?.();});for(let g of u)U.workers?.[g]?.kill();}return {start:d,shutdown:a,getWorkerStats:()=>Array.from(r.workers.entries()),getActiveWorkerCount:()=>r.workerIds.length}}var ce=class extends he.IncomingMessage{params={};body=Y},fe=class extends W(ce){},pe=class extends F(he.ServerResponse){},Ie={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:d={enabled:false}}=r,a=null;s&&d.enabled&&(a=Oe({sampleInterval:d.sampleInterval||5e3,reportInterval:d.reportInterval||6e4,thresholds:d.thresholds,logToConsole:true}),U.isPrimary&&(y("\u{1F4CA} Development performance monitoring enabled"),a.on("alarm",(u,h)=>{y(`\u26A0\uFE0F ALERT: ${h}`);}),a.on("alarm-clear",(u,h)=>{y(`\u2705 RESOLVED: ${h}`);})));let l=o?Object.entries(o):[];if(i?.enabled&&U.isPrimary){let u=i.workers??q__default.cpus().length,h=r.httpsOptions?"https":"http";if(y(`\u{1F9F5} Starting server with ${u} workers`),U.schedulingPolicy!==void 0)try{U.schedulingPolicy=U.SCHED_RR;}catch{}let g=ue();return g.start(u),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:R=>{a&&a.stop(),g.shutdown(R);}}}if(U.isWorker||!i?.enabled){r.routes||await G(e),L(r.cors),I(r.middleware);let u=async(p,c,v)=>{try{if(s&&a&&p.url==="/health"){c.setHeader("Content-Type","application/json"),c.end(JSON.stringify(a.getHealthMetrics())),v?.end(200);return}let E=p.url||"/",O=ee(E);if(p.query=te(E),k()&&(await H("beforeRequest",p,c)===!1||c.headersSent)){v?.end(c.statusCode||204);return}let x=j(O,p.method||"GET");if(!x){k()&&await H("onError",p,c),c.status(404).json({error:"Route not found"}),v?.end(404);return}if("error"in x){let f=x.status||500;c.status(f).json({error:x.error}),v?.end(f,!0);return}p.params=x.params,await x.handler(p,c),k()&&await H("afterRequest",p,c),c.headersSent||c.end(),v?.end(c.statusCode||200);}catch(E){await P(p,c,E),c.headersSent||c.status(500).json({error:"Internal Server Error"}),v?.end(c.statusCode||500,true);}},h=(p,c)=>{let v=s&&a?a.trackRequest():null;if(l.length>0)for(let E=0;E<l.length;E++)c.setHeader(l[E][0],l[E][1]);u(p,c,v).catch(E=>{s&&console.error("Fatal error:",E),c.headersSent||(c.statusCode=500,c.end("Server Error")),v?.end(500,true);});},g={IncomingMessage:fe,ServerResponse:pe},R=r.httpsOptions?Qe.createServer({...g,...r.httpsOptions},h):he.createServer(g,h);R.on("clientError",(p,c)=>{c.destroyed||c.destroy();});let w=r.httpsOptions?"https":"http";return U.isWorker&&ue().start(),R.listen(n,()=>{i?.enabled?s&&y(`Worker ${process.pid} is listening on port ${n}`):(y(`\u{1F680} Server running at ${w}://localhost:${n}/`+(s?" (dev)":"")),s&&a&&y(`\u{1F4CA} Performance monitoring available at http://localhost:${n}/health`));}),R}return null}}};var Le={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()=>{V(t.routes),L(t.cors),I(t.middleware);})(),e);return async(n,o)=>{await r(),Z(n),re(o);let s=n,i=o;try{if(k()&&(await H("beforeRequest",s,i)===!1||i.headersSent))return;let d=j(ee(s.url??"/"),s.method??"GET");if(!d){i.status(404).json({error:"Route not found"});return}if(J(d)){i.status(d.status??500).json({error:d.error});return}s.params=d.params,await d.handler(s,i),k()&&await H("afterRequest",s,i);}catch(d){await P(s,i,d),i.headersSent||i.status(500).json({error:"Internal server error"});}}}};function me(t,e,r,n){let o=Object.keys(r).length>0;return {statusCode:t,headers:e,...o?{multiValueHeaders:r}:{},body:n}}var je={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()=>{V(t.routes),L(t.cors),I(t.middleware);})(),e);return async(n,o)=>{await r();let s=n.queryStringParameters?"?"+new URLSearchParams(n.queryStringParameters).toString():"",i=n.path+s,d=new IncomingMessage(new Socket);if(d.url=i,d.method=n.httpMethod,d.headers=n.headers,n.body){let p=n.isBase64Encoded?"base64":"utf-8";d.push(Buffer.from(n.body,p));}d.push(null);let a="",l={},u={},h=false,g=new ServerResponse(d);g.writeHead=function(p,c){return g.statusCode=p,c&&(l={...l,...c}),this},g.setHeader=function(p,c){let v=p.toLowerCase();return Array.isArray(c)?(u[v]=c.map(String),l[v]=String(c[0])):l[v]=String(c),this},g.getHeader=function(p){return l[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}),Z(d),re(g);let R=d,w=g;R.query=n.queryStringParameters??{};try{if(k()&&(await H("beforeRequest",R,w)===!1||h))return me(w.statusCode,l,u,a);let p=j(n.path,n.httpMethod);return p?J(p)?{statusCode:p.status??500,body:JSON.stringify({error:p.error})}:(R.params=p.params,await p.handler(R,w),k()&&await H("afterRequest",R,w),me(w.statusCode,l,u,a)):{statusCode:404,body:JSON.stringify({error:"Route not found"})}}catch(p){return await P(R,w,p),h?me(w.statusCode,l,u,a):{statusCode:500,body:JSON.stringify({error:"Internal server error"})}}}}};var it=10485760,lt=new TextEncoder,ge=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>it)throw Object.assign(new Error("Payload Too Large"),{code:413});return Buffer.from(e)})}},ye=class extends W(ge){json(){return this._req.json()}},Re=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(lt.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;}},we=class extends F(Re){initSSE(e){return this._initSseStream(),super.initSSE(e)}},Ue={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,d=parseInt(process.env.LACIS_BUN_WORKER??"0"),a=d>0;if(i?.enabled&&!a){let h=i.workers??q__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:R=>{for(let w of g)w.kill();R?.();}}}if(a){let h=setInterval(()=>{try{process.kill(d,0);}catch{clearInterval(h),process.exit(0);}},2e3);h.unref();}y("\u{1F680} Bun high-performance mode enabled"),r.routes||await G(e),L(r.cors),I(r.middleware);let l=s?Object.entries(s):[],u=Bun.serve({port:o,reusePort:a,async fetch(h,g){let R=new URL(h.url),w=R.pathname,p=new ye(h,w,R.search,g?.requestIP(h)?.address??"");p.query=te(R.search);let c=new we;try{for(let x=0;x<l.length;x++)c.setHeader(l[x][0],l[x][1]);if(k()&&(!await H("beforeRequest",p,c)||c.headersSent))return ne(c);let v=j(w,h.method);if(!v)return k()&&await H("onError",p,c),new Response(JSON.stringify({error:"Route not found"}),{status:404,headers:{"Content-Type":"application/json"}});if("error"in v)return k()&&await H("onError",p,c),new Response(JSON.stringify({error:v.error}),{status:v.status||500,headers:{"Content-Type":"application/json"}});p.params=v.params;let E=null,O=(async()=>{await v.handler(p,c),k()&&await H("afterRequest",p,c),c.headersSent||c.end();})().catch(x=>{E=x,n&&console.error("Server error:",x),c._sseReadable&&!c.headersSent&&c.end();});return c._closeSseWindow(),c._sseReadable?ne(c,c._sseReadable):(await O,E&&(await P(p,c,E),!c.headersSent)?new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}}):ne(c))}catch(v){return await P(p,c,v),c.headersSent?ne(c):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:()=>{u.stop();}}}}};function ne(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 dt={node:Ie,vercel:Le,netlify:je,bun:Ue};function Tr(t="node"){let e=dt[t];if(!e)throw new Error(`Platform "${t}" not supported`);return e}
26
+ export{xe as A,Te as B,_e as C,ke as D,He as E,Ie as F,Le as G,je as H,Ue as I,Tr as J,ae as a,ft as b,Be as c,k as d,H as e,Ce as f,pt as g,ht as h,I as i,y as j,B as k,J as l,V as m,G as n,j as o,bt as p,Mt as q,xt as r,Tt as s,We as t,L as u,Se as v,ve as w,Ee as x,be as y,Me as z};
@@ -64,32 +64,6 @@ type PathMiddlewares = Map<string, {
64
64
  onError: MiddlewareCallback[];
65
65
  }>;
66
66
 
67
- interface SSEOptions {
68
- headers?: Record<string, string>;
69
- timeout?: number;
70
- }
71
- interface SSEClientOptions {
72
- reconnectInterval?: number;
73
- maxRetries?: number;
74
- body?: string | Record<string, any>;
75
- contentType?: string;
76
- method?: "GET" | "POST" | "PUT";
77
- params?: string | Record<string, string>;
78
- disableReconnect?: boolean;
79
- }
80
- interface SSEEventHandlers {
81
- onMessage?: (data: any) => void;
82
- onEvent?: Record<string, (data: any) => void>;
83
- onClose?: () => void;
84
- onError?: (error: Error) => void;
85
- }
86
- interface SSEClient {
87
- onMessage: (callback: (data: any) => void) => SSEClient;
88
- onEvent: (eventName: string, callback: (data: any) => void) => SSEClient;
89
- onClose: (callback: () => void) => SSEClient;
90
- close: () => void;
91
- }
92
-
93
67
  interface AdapterRequest extends IncomingMessage {
94
68
  params?: Record<string, string>;
95
69
  query?: Record<string, string>;
@@ -122,6 +96,32 @@ interface Adapter {
122
96
  createHandler: (config: string | ServerlessConfig) => unknown;
123
97
  }
124
98
 
99
+ interface SSEOptions {
100
+ headers?: Record<string, string>;
101
+ timeout?: number;
102
+ }
103
+ interface SSEClientOptions {
104
+ reconnectInterval?: number;
105
+ maxRetries?: number;
106
+ body?: string | Record<string, any>;
107
+ contentType?: string;
108
+ method?: "GET" | "POST" | "PUT";
109
+ params?: string | Record<string, string>;
110
+ disableReconnect?: boolean;
111
+ }
112
+ interface SSEEventHandlers {
113
+ onMessage?: (data: any) => void;
114
+ onEvent?: Record<string, (data: any) => void>;
115
+ onClose?: () => void;
116
+ onError?: (error: Error) => void;
117
+ }
118
+ interface SSEClient {
119
+ onMessage: (callback: (data: any) => void) => SSEClient;
120
+ onEvent: (eventName: string, callback: (data: any) => void) => SSEClient;
121
+ onClose: (callback: () => void) => SSEClient;
122
+ close: () => void;
123
+ }
124
+
125
125
  interface CorsConfig {
126
126
  origin?: string | string[] | RegExp | ((origin: string) => boolean);
127
127
  methods?: string[];
@@ -164,6 +164,7 @@ interface ServerConfig {
164
164
  afterRequest?: MiddlewareCallback | MiddlewareCallback[];
165
165
  onError?: MiddlewareCallback | MiddlewareCallback[];
166
166
  };
167
+ routes?: ServerlessRoute[];
167
168
  openapi?: {
168
169
  path?: string;
169
170
  info: {
package/dist/index.d.ts CHANGED
@@ -1,41 +1,61 @@
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-rE4kFMlu.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-rE4kFMlu.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, C as CorsConfig, e as SSEOptions, f as SSEClientOptions, g as SSEEventHandlers, h as SSEClient } from './index-DMyND6f7.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-DMyND6f7.js';
3
3
  import { Server, ServerResponse, IncomingMessage } from 'http';
4
4
 
5
5
  interface VercelRequest {
6
6
  url?: string;
7
7
  method?: string;
8
8
  headers: Record<string, string | string[] | undefined>;
9
+ cookies: Record<string, string>;
9
10
  body?: any;
10
11
  query?: Record<string, string | string[]>;
11
12
  }
12
13
  interface VercelResponse {
13
14
  statusCode?: number;
15
+ headersSent: boolean;
14
16
  status: (statusCode: number) => VercelResponse;
15
- json: (body: any) => void;
16
- send: (body: any) => void;
17
- setHeader: (name: string, value: string) => void;
17
+ json: (body: any) => VercelResponse;
18
+ send: (body: any) => VercelResponse;
19
+ redirect: (statusOrUrl: string | number, url?: string) => VercelResponse;
20
+ setHeader: (name: string, value: string | string[]) => VercelResponse;
21
+ getHeader: (name: string) => string | string[] | undefined;
22
+ end: (data?: any) => void;
18
23
  }
19
24
  interface NetlifyEvent {
25
+ rawUrl: string;
26
+ rawQuery: string;
20
27
  path: string;
21
28
  httpMethod: string;
22
29
  headers: Record<string, string | undefined>;
23
- body?: string;
24
- queryStringParameters?: Record<string, string>;
30
+ multiValueHeaders: Record<string, string[] | undefined>;
31
+ queryStringParameters: Record<string, string | undefined> | null;
32
+ multiValueQueryStringParameters: Record<string, string[] | undefined> | null;
33
+ body: string | null;
34
+ isBase64Encoded: boolean;
35
+ route?: string;
25
36
  }
26
37
  interface NetlifyContext {
38
+ callbackWaitsForEmptyEventLoop: boolean;
39
+ functionName: string;
40
+ functionVersion: string;
41
+ invokedFunctionArn: string;
42
+ memoryLimitInMB: string;
43
+ awsRequestId: string;
44
+ logGroupName: string;
45
+ logStreamName: string;
46
+ identity?: Record<string, any>;
47
+ clientContext?: Record<string, any>;
48
+ getRemainingTimeInMillis(): number;
27
49
  }
28
50
  interface NetlifyResponse {
29
51
  statusCode: number;
30
- headers?: Record<string, string>;
31
- body: string;
52
+ headers?: Record<string, boolean | number | string>;
53
+ multiValueHeaders?: Record<string, readonly (boolean | number | string)[]>;
54
+ body?: string;
55
+ isBase64Encoded?: boolean;
32
56
  }
33
57
  type NetlifyHandler = (event: NetlifyEvent, context: NetlifyContext) => Promise<NetlifyResponse>;
34
- type PlatformHandler = ((config?: ServerConfig) => Server) | ((req: AdapterRequest, res: AdapterResponse) => Promise<void>) | ((event: NetlifyEvent, context: NetlifyContext) => Promise<{
35
- statusCode: number;
36
- body: string;
37
- headers?: Record<string, string>;
38
- }>);
58
+ type PlatformHandler = ((config?: ServerConfig) => Server) | ((req: AdapterRequest, res: AdapterResponse) => Promise<void>) | ((event: NetlifyEvent, context: NetlifyContext) => Promise<NetlifyResponse>);
39
59
 
40
60
  interface MetricValue {
41
61
  min: number;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {k as k$1,n,j,J}from'./chunk-QZ3VOPKR.js';export{a as addMiddleware,b as addPathMiddleware,c as collectMiddleware,t as createCorsMiddleware,v as createSSEClient,o as findRoute,g as getPathMiddlewares,q as getRouterStats,p as getRoutesDir,d as hasMiddlewares,w as initSSE,l as isRouteError,f as loadMiddlewares,n as loadRoutes,u as registerCorsConfig,i as registerMiddlewareConfig,m as registerRoutes,h as resetMiddlewares,s as resetRouter,k as router,e as runMiddlewares,x as send,z as sendEvent,y as sendJson,r as setVerboseLogging,D as sseClose,A as sseComment,E as sseEventError,B as sseId,C as sseRetry}from'./chunk-QZ3VOPKR.js';import O from'cluster';var g={port:3e3,isDev:process.env.NODE_ENV==="development",timeout:3e4,cluster:{enabled:true,workers:void 0},platform:"node"};function le(e={}){return {...g,...e}}async function S(e,r){let t=await e["~standard"].validate(r);return t.issues?{success:false,issues:t.issues}:{success:true,data:t.value}}function E(e){return Array.from(e).map(r=>({message:r.message,path:r.path?Array.from(r.path).map(t=>typeof t=="object"&&"key"in t?t.key:t):void 0}))}function ye(e){let r=async(t,n)=>{if(e.params){let a=await S(e.params,t.params??{});if(!a.success){n.status(400).json({error:"Validation failed",issues:E(a.issues)});return}t.params=a.data;}if(e.query){let a=await S(e.query,t.query??{});if(!a.success){n.status(400).json({error:"Validation failed",issues:E(a.issues)});return}t.query=a.data;}if(e.body){let a;try{a=await t.json();}catch{n.status(400).json({error:"Invalid JSON body"});return}let s=await S(e.body,a);if(!s.success){n.status(400).json({error:"Validation failed",issues:E(s.issues)});return}t.body=s.data;}await e.handler(t,n);};return r._defineHandler=e,r}async function R(e){let r=e?.["~standard"]?.vendor;if(!r)return null;try{if(r==="zod"){let t=await import('zod');if(typeof t.toJSONSchema=="function")return t.toJSONSchema(e);let n=await import('zod-to-json-schema');return (n.zodToJsonSchema??n.default)(e,{target:"openApi3"})}if(r==="valibot"){let t=await import('@valibot/to-json-schema');return (t.toJsonSchema??t.default)(e)}if(r==="arktype")return e.toJsonSchema()}catch{j(`[openapi] no converter found for "${r}" \u2014 install the matching json-schema package`);}return null}function k(e){return e.replace(/:(\w+)\??/g,"{$1}")}async function N(e,r){let t={responses:{200:{description:"Success"}}};r.meta?.summary&&(t.summary=r.meta.summary),r.meta?.description&&(t.description=r.meta.description),r.meta?.tags&&(t.tags=r.meta.tags),r.meta?.deprecated&&(t.deprecated=r.meta.deprecated);let n=[];if(r.params){let a=await R(r.params);if(a?.properties)for(let[s,o]of Object.entries(a.properties))n.push({name:s,in:"path",required:true,schema:o});}if(r.query){let a=await R(r.query);if(a?.properties){let s=a.required??[];for(let[o,i]of Object.entries(a.properties))n.push({name:o,in:"query",required:s.includes(o),schema:i});}}if(n.length>0&&(t.parameters=n),r.body){let a=await R(r.body);a&&(t.requestBody={required:true,content:{"application/json":{schema:a}}});}return t}async function h(e){let r=k$1.getRoutes(),t={};for(let{method:n,path:a,handler:s}of r){let o=s._defineHandler,i=k(a);t[i]||(t[i]={}),t[i][n.toLowerCase()]=o?await N(n,o):{responses:{200:{description:"Success"}}};}return {openapi:"3.1.0",info:e.info,paths:t}}var y=null,v=false,C=false;async function we(e,r=g){let{platform:t="node"}=r,n$1=r.isDev&&O.isPrimary&&!process.env.LACIS_BUN_WORKER;try{if(await n(e),r.openapi){let i=await h(r.openapi),m=r.openapi.path??"/openapi.json";k$1.addRoute("GET",m,(l,c)=>c.json(i)),n$1&&j(`OpenAPI doc available at ${m}`);}n$1&&(j("\u{1F680} Serveur d\xE9marr\xE9"),j(`\u{1F4C2} Routes charg\xE9es depuis: ${e}`)),r.isDev&&n$1&&j("\u{1F525} Mode de d\xE9veloppement activ\xE9");let s=J(t).createHandler(e),o;switch(t){case "node":o=await s(r),y=o;break;case "bun":o=s(r);break;case "vercel":case "netlify":o=s;break;default:throw new Error(`Plateforme "${t}" non support\xE9e`)}return I(),o}catch(a){throw n$1&&j("\u274C Erreur lors de la cr\xE9ation du serveur:",a),a}}function I(){if(!O.isPrimary||C)return;C=true;let e=async r=>{v||(v=true,j(`
2
- Signal ${r} re\xE7u, arr\xEAt en cours...`),y&&typeof y.close=="function"&&await new Promise(t=>{y.close(()=>t()),setTimeout(()=>{j("Fermeture forc\xE9e apr\xE8s d\xE9lai"),t();},3e3);}),process.exit(0));};process.on("SIGINT",()=>e("SIGINT")),process.on("SIGTERM",()=>e("SIGTERM")),process.on("SIGHUP",()=>e("SIGHUP"));}var p={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},P={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 u(e){let r=e.code||p.INTERNAL_SERVER_ERROR,t=e.message||P[r]||"Unknown Error",n=e.name||`HttpError${r}`,a=new Error(t);return Error.captureStackTrace?.(a,u),{name:n,code:r,message:t,details:e.details,expose:e.expose!==void 0?e.expose:r<500,log:e.log!==void 0?e.log:r>=500,stack:a.stack}}function q(e){let r={error:e.message,code:e.code};return e.expose&&e.details?{...r,details:e.details}:r}function w(e,r){r.headersSent||(r.statusCode=e.code,r.setHeader("Content-Type","application/json"),r.end(JSON.stringify(q(e)))),e.log&&D(e);}function D(e){let r={name:e.name,message:e.message,code:e.code,details:e.details,stack:e.stack};e.code>=500?j("\u274C ERROR:",JSON.stringify(r,null,2)):j("\u26A0\uFE0F WARNING:",JSON.stringify(r,null,2));}function Ae(e,r){return u({name:"BadRequestError",code:p.BAD_REQUEST,message:e,details:r})}function ke(e,r){return u({name:"UnauthorizedError",code:p.UNAUTHORIZED,message:e,details:r})}function Ne(e,r){return u({name:"ForbiddenError",code:p.FORBIDDEN,message:e,details:r})}function Ie(e,r){return u({name:"NotFoundError",code:p.NOT_FOUND,message:e,details:r})}function Pe(e,r){return u({name:"MethodNotAllowedError",code:p.METHOD_NOT_ALLOWED,message:e,details:r})}function qe(e,r){return u({name:"ConflictError",code:p.CONFLICT,message:e,details:r})}function De(e,r){return u({name:"ValidationError",code:p.UNPROCESSABLE_ENTITY,message:e,details:r,expose:true})}function x(e,r){return u({name:"RateLimitError",code:p.TOO_MANY_REQUESTS,message:e,details:r})}function L(e,r){return u({name:"InternalServerError",code:p.INTERNAL_SERVER_ERROR,message:e,details:r})}function M(e,r){return u({name:"ServiceUnavailableError",code:p.SERVICE_UNAVAILABLE,message:e,details:r})}function U(e,r){return u({name:"GatewayTimeoutError",code:p.GATEWAY_TIMEOUT,message:e,details:r})}function Le(e){if(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e)return e;let r=e?.message||"Unknown error occurred",t=e?.stack?{stack:e.stack}:void 0,n=e?.code||e?.statusCode;return n==="ECONNREFUSED"||n==="ENOTFOUND"?M(`Service connection failed: ${r}`,t):n==="ETIMEDOUT"?U(`Request timed out: ${r}`,t):typeof n=="number"&&n>=400&&n<600?u({code:n,message:r,details:t}):L(r,t)}function Me(e){return !!(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e&&"name"in e)}function Be(e={}){let r=e.windowMs??6e4,t=e.max??100,n=e.message??"Too Many Requests",a=e.keyGenerator??(o=>{let i=o.headers["x-forwarded-for"];return (typeof i=="string"?i.split(",")[0].trim():o.socket?.remoteAddress)??"unknown"}),s=new Map;return (o,i)=>{let m=a(o),l=Date.now(),c=s.get(m);(!c||l>=c.resetAt)&&(c={count:0,resetAt:l+r},s.set(m,c)),c.count++;let H=Math.max(0,t-c.count),A=Math.ceil(c.resetAt/1e3);if(i.setHeader("X-RateLimit-Limit",String(t)),i.setHeader("X-RateLimit-Remaining",String(H)),i.setHeader("X-RateLimit-Reset",String(A)),c.count>t)return i.setHeader("Retry-After",String(Math.ceil((c.resetAt-l)/1e3))),w(x(n),i),false}}export{p as HTTP_STATUS,h as buildOpenApiDoc,Ae as createBadRequestError,qe as createConflictError,Ne as createForbiddenError,U as createGatewayTimeoutError,u as createHttpError,L as createInternalServerError,Pe as createMethodNotAllowedError,Ie as createNotFoundError,Be as createRateLimit,x as createRateLimitError,we as createServer,M as createServiceUnavailableError,ke as createUnauthorizedError,De as createValidationError,g as defaultConfig,ye as defineHandler,le as getConfig,Me as isHttpError,D as logError,Le as normalizeError,w as sendError};
1
+ import {k as k$1,s,h,m,n,j as j$1,J}from'./chunk-VQ3XR2HC.js';export{a as addMiddleware,b as addPathMiddleware,c as collectMiddleware,t as createCorsMiddleware,v as createSSEClient,o as findRoute,g as getPathMiddlewares,q as getRouterStats,p as getRoutesDir,d as hasMiddlewares,w as initSSE,l as isRouteError,f as loadMiddlewares,n as loadRoutes,u as registerCorsConfig,i as registerMiddlewareConfig,m as registerRoutes,h as resetMiddlewares,s as resetRouter,k as router,e as runMiddlewares,x as send,z as sendEvent,y as sendJson,r as setVerboseLogging,D as sseClose,A as sseComment,E as sseEventError,B as sseId,C as sseRetry}from'./chunk-VQ3XR2HC.js';import H from'cluster';var g={port:3e3,isDev:process.env.NODE_ENV==="development",timeout:3e4,cluster:{enabled:false,workers:void 0},platform:"node"};function le(e={}){return {...g,...e}}async function S(e,r){let t=await e["~standard"].validate(r);return t.issues?{success:false,issues:t.issues}:{success:true,data:t.value}}function R(e){return Array.from(e).map(r=>({message:r.message,path:r.path?Array.from(r.path).map(t=>typeof t=="object"&&"key"in t?t.key:t):void 0}))}function ye(e){let r=async(t,a)=>{if(e.params){let n=await S(e.params,t.params??{});if(!n.success){a.status(400).json({error:"Validation failed",issues:R(n.issues)});return}t.params=n.data;}if(e.query){let n=await S(e.query,t.query??{});if(!n.success){a.status(400).json({error:"Validation failed",issues:R(n.issues)});return}t.query=n.data;}if(e.body){let n;try{n=await t.json();}catch{a.status(400).json({error:"Invalid JSON body"});return}let s=await S(e.body,n);if(!s.success){a.status(400).json({error:"Validation failed",issues:R(s.issues)});return}t.body=s.data;}await e.handler(t,a);};return r._defineHandler=e,r}async function E(e){let r=e?.["~standard"]?.vendor;if(!r)return null;try{if(r==="zod"){let t=await import('zod');if(typeof t.toJSONSchema=="function")return t.toJSONSchema(e);let a=await import('zod-to-json-schema');return (a.zodToJsonSchema??a.default)(e,{target:"openApi3"})}if(r==="valibot"){let t=await import('@valibot/to-json-schema');return (t.toJsonSchema??t.default)(e)}if(r==="arktype")return e.toJsonSchema()}catch{j$1(`[openapi] no converter found for "${r}" \u2014 install the matching json-schema package`);}return null}function q(e){return e.replace(/:(\w+)\??/g,"{$1}")}async function P(e,r){let t={responses:{200:{description:"Success"}}};r.meta?.summary&&(t.summary=r.meta.summary),r.meta?.description&&(t.description=r.meta.description),r.meta?.tags&&(t.tags=r.meta.tags),r.meta?.deprecated&&(t.deprecated=r.meta.deprecated);let a=[];if(r.params){let n=await E(r.params);if(n?.properties)for(let[s,i]of Object.entries(n.properties))a.push({name:s,in:"path",required:true,schema:i});}if(r.query){let n=await E(r.query);if(n?.properties){let s=n.required??[];for(let[i,o]of Object.entries(n.properties))a.push({name:i,in:"query",required:s.includes(i),schema:o});}}if(a.length>0&&(t.parameters=a),r.body){let n=await E(r.body);n&&(t.requestBody={required:true,content:{"application/json":{schema:n}}});}return t}async function O(e){let r=k$1.getRoutes(),t={};for(let{method:a,path:n,handler:s}of r){let i=s._defineHandler,o=q(n);t[o]||(t[o]={}),t[o][a.toLowerCase()]=i?await P(a,i):{responses:{200:{description:"Success"}}};}return {openapi:"3.1.0",info:e.info,paths:t}}var y=null,w=false,x=false;async function xe(e,r=g){let{platform:t="node"}=r,a=r.isDev&&H.isPrimary&&!process.env.LACIS_BUN_WORKER;try{r.routes?(s(),h(),m(r.routes)):await n(e);let n$1=null,s$1=null;r.openapi&&(n$1=await O(r.openapi),s$1=r.openapi.path??"/openapi.json"),a&&(j$1("\u{1F680} Serveur d\xE9marr\xE9"),j$1(`\u{1F4C2} Routes charg\xE9es depuis: ${e}`)),r.isDev&&a&&j$1("\u{1F525} Mode de d\xE9veloppement activ\xE9");let o=J(t).createHandler(e),m$1;switch(t){case "node":m$1=await o(r),y=m$1;break;case "bun":m$1=o(r);break;case "vercel":case "netlify":m$1=o;break;default:throw new Error(`Plateforme "${t}" non support\xE9e`)}return n$1&&s$1&&(k$1.addRoute("GET",s$1,(l,c)=>c.json(n$1)),a&&j$1(`OpenAPI doc available at ${s$1}`)),D(),m$1}catch(n){throw a&&j$1("\u274C Erreur lors de la cr\xE9ation du serveur:",n),n}}function D(){if(!H.isPrimary||x)return;x=true;let e=async r=>{w||(w=true,j$1(`
2
+ Signal ${r} re\xE7u, arr\xEAt en cours...`),y&&typeof y.close=="function"&&await new Promise(t=>{y.close(()=>t()),setTimeout(()=>{j$1("Fermeture forc\xE9e apr\xE8s d\xE9lai"),t();},3e3);}),process.exit(0));};process.on("SIGINT",()=>e("SIGINT")),process.on("SIGTERM",()=>e("SIGTERM")),process.on("SIGHUP",()=>e("SIGHUP"));}var p={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},L={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 u(e){let r=e.code||p.INTERNAL_SERVER_ERROR,t=e.message||L[r]||"Unknown Error",a=e.name||`HttpError${r}`,n=new Error(t);return Error.captureStackTrace?.(n,u),{name:a,code:r,message:t,details:e.details,expose:e.expose!==void 0?e.expose:r<500,log:e.log!==void 0?e.log:r>=500,stack:n.stack}}function M(e){let r={error:e.message,code:e.code};return e.expose&&e.details?{...r,details:e.details}:r}function A(e,r){r.headersSent||(r.statusCode=e.code,r.setHeader("Content-Type","application/json"),r.end(JSON.stringify(M(e)))),e.log&&U(e);}function U(e){let r={name:e.name,message:e.message,code:e.code,details:e.details,stack:e.stack};e.code>=500?j$1("\u274C ERROR:",JSON.stringify(r,null,2)):j$1("\u26A0\uFE0F WARNING:",JSON.stringify(r,null,2));}function ke(e,r){return u({name:"BadRequestError",code:p.BAD_REQUEST,message:e,details:r})}function Ne(e,r){return u({name:"UnauthorizedError",code:p.UNAUTHORIZED,message:e,details:r})}function Ie(e,r){return u({name:"ForbiddenError",code:p.FORBIDDEN,message:e,details:r})}function qe(e,r){return u({name:"NotFoundError",code:p.NOT_FOUND,message:e,details:r})}function Pe(e,r){return u({name:"MethodNotAllowedError",code:p.METHOD_NOT_ALLOWED,message:e,details:r})}function De(e,r){return u({name:"ConflictError",code:p.CONFLICT,message:e,details:r})}function Le(e,r){return u({name:"ValidationError",code:p.UNPROCESSABLE_ENTITY,message:e,details:r,expose:true})}function k(e,r){return u({name:"RateLimitError",code:p.TOO_MANY_REQUESTS,message:e,details:r})}function _(e,r){return u({name:"InternalServerError",code:p.INTERNAL_SERVER_ERROR,message:e,details:r})}function B(e,r){return u({name:"ServiceUnavailableError",code:p.SERVICE_UNAVAILABLE,message:e,details:r})}function j(e,r){return u({name:"GatewayTimeoutError",code:p.GATEWAY_TIMEOUT,message:e,details:r})}function Me(e){if(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e)return e;let r=e?.message||"Unknown error occurred",t=e?.stack?{stack:e.stack}:void 0,a=e?.code||e?.statusCode;return a==="ECONNREFUSED"||a==="ENOTFOUND"?B(`Service connection failed: ${r}`,t):a==="ETIMEDOUT"?j(`Request timed out: ${r}`,t):typeof a=="number"&&a>=400&&a<600?u({code:a,message:r,details:t}):_(r,t)}function Ue(e){return !!(e&&typeof e=="object"&&typeof e.code=="number"&&"message"in e&&"name"in e)}function je(e={}){let r=e.windowMs??6e4,t=e.max??100,a=e.message??"Too Many Requests",n=e.keyGenerator??(i=>{let o=i.headers["x-forwarded-for"];return (typeof o=="string"?o.split(",")[0].trim():i.socket?.remoteAddress)??"unknown"}),s=new Map;return (i,o)=>{let m=n(i),l=Date.now(),c=s.get(m);(!c||l>=c.resetAt)&&(c={count:0,resetAt:l+r},s.set(m,c)),c.count++;let N=Math.max(0,t-c.count),I=Math.ceil(c.resetAt/1e3);if(o.setHeader("X-RateLimit-Limit",String(t)),o.setHeader("X-RateLimit-Remaining",String(N)),o.setHeader("X-RateLimit-Reset",String(I)),c.count>t)return o.setHeader("Retry-After",String(Math.ceil((c.resetAt-l)/1e3))),A(k(a),o),false}}export{p as HTTP_STATUS,O as buildOpenApiDoc,ke as createBadRequestError,De as createConflictError,Ie as createForbiddenError,j as createGatewayTimeoutError,u as createHttpError,_ as createInternalServerError,Pe as createMethodNotAllowedError,qe as createNotFoundError,je as createRateLimit,k as createRateLimitError,xe as createServer,B as createServiceUnavailableError,Ne as createUnauthorizedError,Le as createValidationError,g as defaultConfig,ye as defineHandler,le as getConfig,Ue as isHttpError,U as logError,Me as normalizeError,A as sendError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lacis",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Zero-dependency TypeScript web framework",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,18 +42,6 @@
42
42
  "zod": "^4.4.3",
43
43
  "zod-to-json-schema": "^3.25.2"
44
44
  },
45
- "peerDependencies": {
46
- "@types/node": ">=18",
47
- "typescript": "^5.0.0"
48
- },
49
- "peerDependenciesMeta": {
50
- "typescript": {
51
- "optional": true
52
- },
53
- "@types/node": {
54
- "optional": true
55
- }
56
- },
57
45
  "bin": {
58
46
  "lacis": "dist/cli/index.js"
59
47
  },
@@ -1,26 +0,0 @@
1
- import F from'path';import Le from'fs/promises';import j from'cluster';import ue,{IncomingMessage,ServerResponse}from'http';import Ve from'https';import*as q from'os';import q__default from'os';import {EventEmitter}from'events';import {Socket}from'net';var O={beforeRequest:[],afterRequest:[],onError:[]},T=new Map;function re(t,e){return O[t].push(e),{remove:()=>{let r=O[t].indexOf(e);r!==-1&&O[t].splice(r,1);}}}function dt(t,e,r){let n=t==="/"?"/":t.replace(/\/+$/,"");return T.has(n)||T.set(n,{beforeRequest:[],afterRequest:[],onError:[]}),T.get(n)[e].push(r),{remove:()=>{if(T.has(n)){let s=T.get(n),a=s[e].indexOf(r);a!==-1&&s[e].splice(a,1);}}}}function je(t){let r=(t==="/"?"/":t.replace(/\/+$/,"")).split("/").filter(Boolean),n={beforeRequest:[...O.beforeRequest],afterRequest:[...O.afterRequest],onError:[...O.onError]},o="";if(T.has("/")){let s=T.get("/");n.beforeRequest.push(...s.beforeRequest),n.afterRequest.push(...s.afterRequest),n.onError.push(...s.onError);}for(let s of r)if(o+="/"+s,T.has(o)){let a=T.get(o);n.beforeRequest.push(...a.beforeRequest),n.afterRequest.push(...a.afterRequest),n.onError.push(...a.onError);}return n}function x(){return O.beforeRequest.length>0||O.afterRequest.length>0||O.onError.length>0?true:T.size>0}async function _(t,e,r,n){let o=e.url?.split("?")[0]||"/",s=je(o);if(s[t].length===0)return true;for(let a of s[t])try{if(await a(e,r,n)===!1)return !1}catch(l){if(t!=="onError")try{for(let i of s.onError)await i(e,r,{error:l,phase:t});}catch(i){console.error("Error in error handler:",i);}return false}return true}async function ye(t){T.clear();async function e(r,n=""){try{let o=await Le.readdir(r,{withFileTypes:!0}),s=o.find(a=>a.name==="+middleware.ts"||a.name==="+middleware.js");if(s){let a=F.join(r,s.name);try{let i=await import(`${F.resolve(a)}?update=${Date.now()}`);if(T.has(n)||T.set(n,{beforeRequest:[],afterRequest:[],onError:[]}),i.beforeRequest){let d=Array.isArray(i.beforeRequest)?i.beforeRequest:[i.beforeRequest];T.get(n).beforeRequest.push(...d);}if(i.afterRequest){let d=Array.isArray(i.afterRequest)?i.afterRequest:[i.afterRequest];T.get(n).afterRequest.push(...d);}if(i.onError){let d=Array.isArray(i.onError)?i.onError:[i.onError];T.get(n).onError.push(...d);}}catch(l){console.error(`Error loading middleware for ${n}:`,l);}}for(let a of o)a.isDirectory()&&await e(F.join(r,a.name),`${n==="/"?"":n}/${a.name}`);}catch(o){console.error(`Error scanning directory ${r}:`,o);}}await e(t,"/");}function ut(){return T}function ct(){O.beforeRequest=[],O.afterRequest=[],O.onError=[],T.clear();}function P(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)re(e,o);}}}function Ue(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 De(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(a,l)=>{let i=a.getHeader("origin");if(!i||!Ue(i,t.origin))return;let d=s&&!t.credentials;if(l.setHeader("Access-Control-Allow-Origin",d?"*":i),d||l.setHeader("Vary","Origin"),t.credentials&&l.setHeader("Access-Control-Allow-Credentials","true"),n&&l.setHeader("Access-Control-Expose-Headers",n),a.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 I(t){t&&re("beforeRequest",De(t));}function g(...t){j.isPrimary&&console.log(...t);}function We(t){let e=t.match(/^\[(\w+)(\??)]/);return e?{name:e[1],isParam:true,isOptional:e[2]==="?"}:{name:t,isParam:false,isOptional:false}}var Fe=1e3,ze=100,se=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 a of o){let l=We(a);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(a==="*")return s.wildcardHandler||(s.wildcardHandler=Object.create(null)),s.wildcardHandler[e]=n,this.cachedRoutes.clear(),this;s.staticChildren.has(a)||s.staticChildren.set(a,this.createNode()),s=s.staticChildren.get(a);}}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 s;let a=n==="/"?[]:n.split("/").filter(Boolean),l=Object.create(null),i=this.traverse(this.rootNode,a,e,l,0)??{handler:null,params:Object.create(null)};if(this.cachedRoutes.size>=Fe){let d=0;for(let c of this.cachedRoutes.keys())if(this.cachedRoutes.delete(c),++d>=ze)break}return this.cachedRoutes.set(o,i),i}traverse(e,r,n,o,s){if(s===r.length){if(e.isEndpoint){let d=e.handlers[n]??(n==="HEAD"?e.handlers.GET:void 0)??e.handlers[""];if(d)return {handler:d,params:{...o}};let c=Object.keys(e.handlers).filter(p=>p!=="");return {handler:null,params:{},allowedMethods:c}}let i=e.paramChild;if(i?.isOptional&&i.node.isEndpoint){let d=i.node.handlers[n]??(n==="HEAD"?i.node.handlers.GET:void 0)??i.node.handlers[""];if(d)return {handler:d,params:{...o}}}return null}let a=r[s],l=e.staticChildren.get(a);if(l){let i=this.traverse(l,r,n,o,s+1);if(i)return i}if(e.paramChild){let{name:i,node:d}=e.paramChild;o[i]=a;let c=this.traverse(d,r,n,o,s+1);if(c)return c;delete o[i];}if(e.wildcardHandler){let i=e.wildcardHandler[n]??e.wildcardHandler[""],d=r.slice(s).join("/");if(i)return {handler:i,params:{...o,"*":d}};let c=Object.keys(e.wildcardHandler).filter(p=>p!=="");if(c.length>0)return {handler:null,params:{...o,"*":d},allowedMethods:c}}return null}async loadRoutes(e){this.rootNode=this.createNode(),this.cachedRoutes.clear(),this.routeCount=0,await ye(e);let r=this;async function n(o,s=[]){try{let a=await Le.readdir(o,{withFileTypes:!0}),l=a.find(i=>!i.isDirectory()&&(i.name==="index.ts"||i.name==="index.js"));if(l)try{let d=await import(`${F.resolve(F.join(o,l.name))}?update=${Date.now()}`),c=["GET","POST","PUT","DELETE","PATCH"],p="/"+s.join("/"),m=!1;for(let S of c)typeof d[S]=="function"&&(r.addRoute(S,p,d[S]),m=!0);!m&&typeof d.default=="function"&&r.addRoute("GET",p,d.default),r.verbose&&g(`Route loaded: ${p}`);}catch(i){console.error(`Error loading index in ${o}:`,i);}for(let i of a)if(i.isDirectory()){let d=i.name.match(/^\[(\w+)(\??)]/),c=d?`[${d[1]}${d[2]}]`:i.name;await n(F.join(o,i.name),[...s,c]);}}catch(a){console.error(`Error scanning directory ${o}:`,a);}}return await n(e),this.lastLoaded=Date.now(),this.verbose&&g(`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,a]of Object.entries(e.handlers))s!==""&&n.push({method:s,path:o,handler:a});}for(let[o,s]of e.staticChildren)this.collectRoutes(s,[...r,o],n);if(e.paramChild){let{name:o,isOptional:s,node:a}=e.paramChild;this.collectRoutes(a,[...r,s?`:${o}?`:`:${o}`],n);}if(e.wildcardHandler){let o="/"+[...r,"*"].join("/");for(let[s,a]of Object.entries(e.wildcardHandler))s!==""&&n.push({method:s,path:o,handler:a});}}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 se;function z(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 V(t){return D.loadRoutes(t)}function L(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 St(t){return F.resolve(process.cwd(),t||process.env.ROUTES_DIR||"routes")}function vt(){return D.getStats()}function bt(t){D.setVerbose(t);}function Et(){D.reset();}function Re(t,e={},r={},n){let o=false,s=0,a={},l=[],i=[],d=[],c=null;r.onMessage&&l.push(r.onMessage),r.onClose&&i.push(r.onClose),r.onError&&d.push(r.onError),r.onEvent&&Object.entries(r.onEvent).forEach(([f,h])=>{a[f]||(a[f]=[]),a[f].push(h);});let p=e.reconnectInterval||3e3,m=e.maxRetries||3,S=e.disableReconnect||false,y=e.body,w=e.contentType||(y?"application/json":void 0),u=e.method||(y?"POST":"GET");if(typeof t!="string"){let f=t;return o=true,f.on("data",h=>{C(h.toString());}),f.on("end",()=>{o=false;}),f.on("error",h=>{o=false,console.error("SSE Error:",h);}),b()}if(typeof t=="string")return new Promise((f,h)=>{A().then(()=>f(b())).catch(h);});function C(f){let h=f,v=h.split(`
2
-
3
- `);h=v.pop()||"";for(let M of v){let $=M.split(`
4
- `),R="",E="";for(let k of $)k.startsWith("event:")?E=k.slice(6).trim():k.startsWith("data:")&&(R=k.slice(5).trim());if(R)try{let k=JSON.parse(R);E&&a[E]?a[E].forEach(B=>B(k)):l.forEach(B=>B(k));}catch{E&&a[E]?a[E].forEach(k=>k(R)):l.forEach(k=>k(R));}}}function b(){return {onMessage(f){return l.push(f),this},onEvent(f,h){return a[f]||(a[f]=[]),a[f].push(h),this},onClose(f){return i.push(f),this},close(){c&&(c.destroy(),c=null),o=false,i.forEach(f=>f());}}}async function A(){if(!o){o=true;try{await H();}catch(f){!S&&s<m?(s++,setTimeout(()=>{A();},p)):d.forEach(h=>h(f));}}}async function H(){return new Promise((f,h)=>{let v=new URL(t);e.params&&(typeof e.params=="object"?Object.entries(e.params).forEach(([R,E])=>{v.searchParams.append(R,String(E));}):typeof e.params=="string"&&new URLSearchParams(e.params).forEach((E,k)=>{v.searchParams.append(k,E);}));let M={hostname:v.hostname,port:v.port||(v.protocol==="https:"?443:80),path:v.pathname+v.search,method:u,headers:{Accept:"text/event-stream",...n?.headers||{},"Cache-Control":"no-cache",Connection:"keep-alive",...w&&{"Content-Type":w},...y&&typeof y=="string"&&{"Content-Length":Buffer.byteLength(y).toString()},...y&&typeof y!="string"&&{"Content-Length":Buffer.byteLength(JSON.stringify(y)).toString()}}};c=(v.protocol==="https:"?Ve:ue).request(M,R=>{if(R.statusCode!==200){o=false,h(new Error(`Server responded with status: ${R.statusCode}`));return}R.setEncoding("utf8"),R.on("data",C),R.on("end",()=>{o=false,c?.destroy(),c=null,i.forEach(E=>E()),f(null);}),R.on("close",()=>{o=false,c?.destroy(),c=null,i.forEach(E=>E()),f(null);}),R.on("error",E=>{o=false,c?.destroy(),c=null,i.forEach(k=>k()),h(E);});}),c.on("error",R=>{o=false,c?.destroy(),c=null,h(R);}),y&&(typeof y=="string"?c.write(y):c.write(JSON.stringify(y))),c.end();})}return b()}function we(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 Ce(t,e){return t.writableEnded?false:t.write(`data: ${e}
5
-
6
- `)}function Se(t,e){return t.writableEnded?false:t.write(`data: ${JSON.stringify(e)}
7
-
8
- `)}function ve(t,e,r){return t.writableEnded?false:(t.write(`event: ${e}
9
- `),t.write(`data: ${JSON.stringify(r)}
10
-
11
- `))}function be(t,e){return t.writableEnded?false:t.write(`: ${e}
12
-
13
- `)}function Ee(t,e){return t.writableEnded?false:t.write(`id: ${e}
14
-
15
- `)}function Me(t,e){return t.writableEnded?false:t.write(`retry: ${e}
16
-
17
- `)}function Te(t,e="Connection closed"){t.write(`: ${e}
18
-
19
- `),t.end();}function xe(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 Ge=10485760,K=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()}}},X=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 _e(t){if(typeof t.get=="function")return t.get("cookie")??void 0;let e=t.cookie;return Array.isArray(e)?e.join("; "):e}function N(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 K(_e(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 a=s[1].trim();this.body().then(l=>{let i={},d=Buffer.from(`--${a}`),c=[],p=0,m;for(;(m=l.indexOf(d,p))!==-1;)c.push(l.subarray(p,m)),p=m+d.length;c.push(l.subarray(p));for(let S=1;S<c.length-1;S++){let y=c[S].subarray(2),w=y.indexOf(`\r
23
- \r
24
- `);if(w===-1)continue;let u=y.subarray(0,w).toString(),C=y.subarray(w+4,y.length-2),b=u.match(/Content-Disposition: form-data; name="([^"]+)"(?:; filename="([^"]+)")?/i);if(b)if(b[2]){let A=u.match(/Content-Type:\s*([^\r\n]+)/i);i[b[1]]={filename:b[2],mimetype:A?A[1].trim():"application/octet-stream",data:C,size:C.length};}else i[b[1]]=C.toString("utf-8");}e(i);}).catch(r);})}createSSEClient(e,r){return Re(this,e,r)}}}function Y(){let t=[],e=0,r=false;return new Promise((n,o)=>{this.on("data",s=>{if(e+=s.length,e>Ge){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 ke(t,e){let r=t.serialize();r.length>0&&!e.headersSent&&e.setHeader("Set-Cookie",r);}function W(t){return class extends t{_zresCookies;get cookies(){return this._zresCookies||(this._zresCookies=new X),this._zresCookies}end(e){return this._zresCookies&&ke(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}initSSE(e){return we(this,e)}sseSend(e){Ce(this,e);}sseJson(e){Se(this,e);}sseEvent(e,r){ve(this,e,r);}sseComment(e){be(this,e);}sseId(e){Ee(this,e);}sseRetry(e){Me(this,e);}sseClose(e){Te(this,e);}sseError(e,r,n=500,o){xe(this,e,r,n,o);}}}var ne=class{params={};headers={};body(){return Y.call(this)}},G=N(ne).prototype,oe=class{statusCode=200;headersSent=false;setHeader(e,r){}end(e){}write(e){}},Ke=W(oe).prototype;function Z(t){t.body=Y,t.json=G.json,t.form=G.form,t.getHeader=G.getHeader,t.createSSEClient=G.createSSEClient,t.cookies=new K(_e(t.headers));}function Q(t){let e=Ke;t.status=e.status,t.send=e.send,t.json=e.json,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 X;t.cookies=r;let n=t.end.bind(t);t.end=function(...o){return ke(r,this),n(...o)};}var ee=null;function Ye(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=d(),a=[],l=process.cpuUsage(),i={cpu:false,memory:false,responseTime:false,errorRate:false};function d(){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:q.loadavg(),systemMemory:{total:q.totalmem(),free:q.freemem(),used:q.totalmem()-q.freemem()}}}function c(){let f=o.responseTimes;if(f.length===0)return {min:0,max:0,avg:0,count:0,sum:0};let h=1/0,v=-1/0,M=0;for(let E of f)h=Math.min(h,E),v=Math.max(v,E),M+=E;let $=M/f.length,R={min:h,max:v,avg:$,count:f.length,sum:M};if(r.enableHistogram){let E=[...f].sort((k,B)=>k-B);R.p50=E[Math.floor(E.length*.5)],R.p90=E[Math.floor(E.length*.9)],R.p99=E[Math.floor(E.length*.99)];}return R}function p(){let f=Date.now(),h=process.uptime(),v=process.memoryUsage(),M=process.cpuUsage(l);l=process.cpuUsage();let R=(M.user+M.system)/1e3/r.sampleInterval*100;s={timestamp:f,uptime:h,requestCount:o.requestCount,activeRequests:o.activeRequests,errorCount:o.errorCount,responseTimes:c(),statusCodes:{...o.statusCodes},memory:v,cpu:{usage:R,system:M.system,user:M.user},systemLoad:q.loadavg(),systemMemory:{total:q.totalmem(),free:q.freemem(),used:q.totalmem()-q.freemem()}},a.push({...s}),a.length>100&&a.shift(),y(),j.isWorker&&process.send&&process.send({type:"metrics",metrics:s});}function m(){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)},h=Date.now()-o.lastReport,v=(s.requestCount/(h/1e3)).toFixed(2),M=s.requestCount?(s.errorCount/s.requestCount*100).toFixed(2):"0.00";g(`
25
- \u{1F4CA} Server Performance Metrics \u{1F4CA}`),g(`Uptime: ${w(s.uptime)}`),g(`Load: ${s.systemLoad[0].toFixed(2)}, ${s.systemLoad[1].toFixed(2)}, ${s.systemLoad[2].toFixed(2)}`),g(`Requests: ${s.requestCount} total, ${v} req/sec`),g(`Active Requests: ${s.activeRequests}`),g(`Errors: ${s.errorCount} (${M}%)`),s.responseTimes.count>0&&(g(`Response Times: avg ${s.responseTimes.avg.toFixed(2)}ms, min ${s.responseTimes.min}ms, max ${s.responseTimes.max}ms`),s.responseTimes.p50&&g(`Response Time Percentiles: p50 ${s.responseTimes.p50}ms, p90 ${s.responseTimes.p90}ms, p99 ${s.responseTimes.p99}ms`)),g(`Memory: ${f.rss}MB (RSS), ${f.heapUsed}MB / ${f.heapTotal}MB (Heap)`),g(`CPU Usage: ${s.cpu.usage.toFixed(2)}%`),Object.keys(s.statusCodes).length>0&&(g("Status Codes:"),Object.entries(s.statusCodes).sort(([$],[R])=>parseInt($)-parseInt(R)).forEach(([$,R])=>{g(` ${$}: ${R}`);})),g(""),o.lastReport=Date.now();}function S(){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,g("\u{1F504} Performance metrics have been reset");}function y(){let f=s.memory.heapUsed/s.memory.heapTotal*100,h=s.requestCount?s.errorCount/s.requestCount*100:0,v=s.responseTimes.avg;s.cpu.usage>r.thresholds.cpu&&!i.cpu?(i.cpu=true,e.emit("alarm","cpu",`High CPU usage: ${s.cpu.usage.toFixed(2)}%`)):s.cpu.usage<=r.thresholds.cpu&&i.cpu&&(i.cpu=false,e.emit("alarm-clear","cpu",`CPU usage returned to normal: ${s.cpu.usage.toFixed(2)}%`)),f>r.thresholds.memory&&!i.memory?(i.memory=true,e.emit("alarm","memory",`High memory usage: ${f.toFixed(2)}%`)):f<=r.thresholds.memory&&i.memory&&(i.memory=false,e.emit("alarm-clear","memory",`Memory usage returned to normal: ${f.toFixed(2)}%`)),v>r.thresholds.responseTime&&!i.responseTime?(i.responseTime=true,e.emit("alarm","responseTime",`High response time: ${v.toFixed(2)}ms`)):v<=r.thresholds.responseTime&&i.responseTime&&(i.responseTime=false,e.emit("alarm-clear","responseTime",`Response time returned to normal: ${v.toFixed(2)}ms`)),h>r.thresholds.errorRate&&!i.errorRate?(i.errorRate=true,e.emit("alarm","errorRate",`High error rate: ${h.toFixed(2)}%`)):h<=r.thresholds.errorRate&&i.errorRate&&(i.errorRate=false,e.emit("alarm-clear","errorRate",`Error rate returned to normal: ${h.toFixed(2)}%`));}function w(f){let h=Math.floor(f/86400),v=Math.floor(f%86400/3600),M=Math.floor(f%3600/60),$=Math.floor(f%60),R=[];return h>0&&R.push(`${h}d`),v>0&&R.push(`${v}h`),M>0&&R.push(`${M}m`),($>0||R.length===0)&&R.push(`${$}s`),R.join(" ")}function u(){let f=setInterval(p,r.sampleInterval),h=setInterval(m,r.reportInterval),v=setInterval(S,r.resetInterval);return {stop:()=>{clearInterval(f),clearInterval(h),clearInterval(v);}}}function C(){let f=Date.now();return o.activeRequests++,{end:(h,v=false)=>{let M=Date.now()-f;return o.activeRequests--,o.requestCount++,o.responseTimes.push(M),o.responseTimes.length>1e3&&o.responseTimes.shift(),o.statusCodes[h]=(o.statusCodes[h]||0)+1,(v||h>=500)&&o.errorCount++,M}}}function b(){return !Object.values(i).some(f=>f)}function A(){let f=s.memory.heapUsed/s.memory.heapTotal*100,h=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:h.toFixed(2)},alerts:Object.entries(i).filter(([v,M])=>M).map(([v])=>v)}}let H=u();return {trackRequest:C,getMetrics:()=>({...s}),getMetricsHistory:()=>[...a],getHealthMetrics:A,isHealthy:b,stop:H.stop,on:e.on.bind(e),once:e.once.bind(e),off:e.off.bind(e)}}function qe(t){if(!ee){let e=Ye(t),r=e.stop;e.stop=()=>{r(),ee=null;},ee=e;}return ee}function ie(t={}){let e=t.reportInterval??5e3,r={workers:new Map,workerIds:[]};function n(){if(!j.isWorker)return;let d=process.cpuUsage(),c=()=>{if(!process.send)return;let p=process.memoryUsage(),m=process.cpuUsage(d);d=process.cpuUsage();let S=(m.user+m.system)/(e*1e3),y={type:"stats",stats:{pid:process.pid,load:S,lastUsed:Date.now(),memoryUsage:p}};process.send(y);};c(),setInterval(c,e).unref();}function o(){let d=j.fork();r.workers.set(d.id,{pid:d.process.pid,load:0,lastUsed:Date.now(),memoryUsage:{rss:0,heapTotal:0,heapUsed:0,external:0,arrayBuffers:0}}),r.workerIds.push(d.id),g(`Worker ${d.process.pid} started`);}let s=false,a=[];function l(d=q.cpus().length){if(!j.isPrimary)return n();g(`\u{1F9F5} Launching ${d} workers...`);for(let c=0;c<d;c++)o();j.on("message",(c,p)=>{if(p.type==="stats"&&"stats"in p){let m=r.workers.get(c.id);m&&Object.assign(m,p.stats);}}),j.on("exit",(c,p,m)=>{if(r.workers.delete(c.id),r.workerIds=r.workerIds.filter(S=>S!==c.id),s){a.forEach(S=>S());return}g(`Worker ${c.process.pid} died (${m||p}). Restarting...`),setTimeout(()=>o(),1e3);});}function i(d){s=true;let c=Object.keys(j.workers??{});if(c.length===0){d?.();return}let p=c.length;a.push(()=>{p--,p===0&&d?.();});for(let m of c)j.workers?.[m]?.kill();}return {start:l,shutdown:i,getWorkerStats:()=>Array.from(r.workers.entries()),getActiveWorkerCount:()=>r.workerIds.length}}var ae=class extends ue.IncomingMessage{params={};body=Y},le=class extends N(ae){},de=class extends W(ue.ServerResponse){},$e={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:a,monitoring:l={enabled:false}}=r,i=null;s&&l.enabled&&(i=qe({sampleInterval:l.sampleInterval||5e3,reportInterval:l.reportInterval||6e4,thresholds:l.thresholds,logToConsole:true}),j.isPrimary&&(g("\u{1F4CA} Development performance monitoring enabled"),i.on("alarm",(c,p)=>{g(`\u26A0\uFE0F ALERT: ${p}`);}),i.on("alarm-clear",(c,p)=>{g(`\u2705 RESOLVED: ${p}`);})));let d=o?Object.entries(o):[];if(a?.enabled&&j.isPrimary){let c=a.workers??q__default.cpus().length,p=r.httpsOptions?"https":"http";if(g(`\u{1F9F5} Starting server with ${c} workers`),j.schedulingPolicy!==void 0)try{j.schedulingPolicy=j.SCHED_RR;}catch{}let m=ie();return m.start(c),g(`\u{1F680} Server running at ${p}://localhost:${n}/`+(s?" (dev)":"")),s&&i&&g(`\u{1F4CA} Performance monitoring available at http://localhost:${n}/health`),{close:S=>{i&&i.stop(),m.shutdown(S);}}}if(j.isWorker||!a?.enabled){await V(e),I(r.cors),P(r.middleware);let c=async(w,u,C)=>{try{if(s&&i&&w.url==="/health"){u.setHeader("Content-Type","application/json"),u.end(JSON.stringify(i.getHealthMetrics())),C?.end(200);return}let b=w.url||"/",A=b.indexOf("?"),H=A===-1?b:b.slice(0,A);if(x()&&(await _("beforeRequest",w,u)===!1||u.headersSent)){C?.end(u.statusCode||204);return}let f=L(H,w.method||"GET");if(!f){x()&&await _("onError",w,u),u.status(404).json({error:"Route not found"}),C?.end(404);return}if("error"in f){let h=f.status||500;u.status(h).json({error:f.error}),C?.end(h,!0);return}w.params=f.params,await f.handler(w,u),x()&&await _("afterRequest",w,u),u.headersSent||u.end(),C?.end(u.statusCode||200);}catch(b){s&&console.error("Error:",b),u.headersSent||u.status(500).json({error:"Internal Server Error"}),x()&&await _("onError",w,u),C?.end(u.statusCode||500,true);}},p=(w,u)=>{let C=s&&i?i.trackRequest():null;if(d.length>0)for(let b=0;b<d.length;b++)u.setHeader(d[b][0],d[b][1]);c(w,u,C).catch(b=>{s&&console.error("Fatal error:",b),u.headersSent||(u.statusCode=500,u.end("Server Error")),C?.end(500,true);});},m={IncomingMessage:le,ServerResponse:de},S=r.httpsOptions?Ve.createServer({...m,...r.httpsOptions},p):ue.createServer(m,p);S.on("clientError",(w,u)=>{u.destroyed||u.destroy();});let y=r.httpsOptions?"https":"http";return j.isWorker&&ie().start(),S.listen(n,()=>{a?.enabled?s&&g(`Worker ${process.pid} is listening on port ${n}`):(g(`\u{1F680} Server running at ${y}://localhost:${n}/`+(s?" (dev)":"")),s&&i&&g(`\u{1F4CA} Performance monitoring available at http://localhost:${n}/health`));}),S}return null}}};var Oe={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),I(t.cors),P(t.middleware);})(),e);return async(n,o)=>{await r(),Z(n),Q(o);let s=n,a=o;try{if(x()&&(await _("beforeRequest",s,a)===!1||a.headersSent))return;let l=L(s.url??"/",s.method??"GET");if(!l){a.status(404).json({error:"Route not found"});return}if(z(l)){a.status(l.status??500).json({error:l.error});return}s.params=l.params,await l.handler(s,a),x()&&await _("afterRequest",s,a);}catch(l){console.error("[lacis/vercel] Handler error:",l),x()&&await _("onError",s,a,{error:l}),a.headersSent||a.status(500).json({error:"Internal server error"});}}}};function ce(t,e,r,n){let o=Object.keys(r).length>0;return {statusCode:t,headers:e,...o?{multiValueHeaders:r}:{},body:n}}var Pe={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),I(t.cors),P(t.middleware);})(),e);return async(n,o)=>{await r();let s=n.queryStringParameters?"?"+new URLSearchParams(n.queryStringParameters).toString():"",a=n.path+s,l=new IncomingMessage(new Socket);l.url=a,l.method=n.httpMethod,l.headers=n.headers,n.body&&l.push(Buffer.from(n.body,"utf-8")),l.push(null);let i="",d={},c={},p=false,m=new ServerResponse(l);m.writeHead=function(u,C){return m.statusCode=u,C&&(d={...d,...C}),this},m.setHeader=function(u,C){let b=u.toLowerCase();return Array.isArray(C)?(c[b]=C.map(String),d[b]=String(C[0])):d[b]=String(C),this},m.getHeader=function(u){return d[u.toLowerCase()]},m.end=function(u){return p=true,u!==void 0&&(i=typeof u=="string"?u:u.toString()),this},Object.defineProperty(m,"headersSent",{get:()=>p}),Z(l),Q(m);let S=l,y=m,w=L(n.path,n.httpMethod);if(!w)return {statusCode:404,body:JSON.stringify({error:"Route not found"})};if(z(w))return {statusCode:w.status??500,body:JSON.stringify({error:w.error})};try{return x()&&(await _("beforeRequest",S,y)===!1||p)||(S.params=w.params,await w.handler(S,y),x()&&await _("afterRequest",S,y)),ce(y.statusCode,d,c,i)}catch(u){return console.error("[lacis/netlify] Handler error:",u),x()&&await _("onError",S,y,{error:u}),p?ce(y.statusCode,d,c,i):{statusCode:500,body:JSON.stringify({error:"Internal server error"})}}}}};var nt=10485760,ot=new TextEncoder,pe=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>nt)throw Object.assign(new Error("Payload Too Large"),{code:413});return Buffer.from(e)})}},he=class extends N(pe){json(){return this._req.json()}},me=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(ot.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;}},ge=class extends W(me){initSSE(e){return this._initSseStream(),super.initSSE(e)}},Ie={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:a}=r,l=parseInt(process.env.LACIS_BUN_WORKER??"0"),i=l>0;if(a?.enabled&&!i){let p=a.workers??q__default.cpus().length;g(`\u{1F9F5} Starting Bun server with ${p} workers (reusePort)`);let m=Array.from({length:p},()=>Bun.spawn(process.argv,{env:{...process.env,LACIS_BUN_WORKER:String(process.pid)},stdout:"ignore",stderr:"inherit"}));return g(`\u{1F680} Server running at http://localhost:${o}/`),{close:S=>{for(let y of m)y.kill();S?.();}}}if(i){let p=setInterval(()=>{try{process.kill(l,0);}catch{clearInterval(p),process.exit(0);}},2e3);p.unref();}g("\u{1F680} Bun high-performance mode enabled"),await V(e),I(r.cors),P(r.middleware);let d=s?Object.entries(s):[],c=Bun.serve({port:o,reusePort:i,async fetch(p,m){let S=new URL(p.url),y=S.pathname,w=new he(p,y,S.search,m?.requestIP(p)?.address??""),u=new ge;try{for(let H=0;H<d.length;H++)u.setHeader(d[H][0],d[H][1]);if(x()&&(!await _("beforeRequest",w,u)||u.headersSent))return fe(u);let C=L(y,p.method);if(!C)return x()&&await _("onError",w,u),new Response(JSON.stringify({error:"Route not found"}),{status:404,headers:{"Content-Type":"application/json"}});if("error"in C)return x()&&await _("onError",w,u),new Response(JSON.stringify({error:C.error}),{status:C.status||500,headers:{"Content-Type":"application/json"}});w.params=C.params;let b=null,A=(async()=>{await C.handler(w,u),x()&&await _("afterRequest",w,u),u.headersSent||u.end();})().catch(H=>{b=H,n&&console.error("Server error:",H),u._sseReadable&&!u.headersSent&&u.end();});return u._closeSseWindow(),u._sseReadable?fe(u,u._sseReadable):(await A,b&&!u.headersSent?new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}}):fe(u))}catch(C){return n&&console.error("Server error:",C),new Response(JSON.stringify({error:"Internal Server Error"}),{status:500,headers:{"Content-Type":"application/json"}})}}});return g(`\u{1F680} Server started on http://localhost:${o}${n?" (dev)":""}`),{close:()=>{c.stop();}}}}};function fe(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],a=t._headers[o+1];s.toLowerCase()==="set-cookie"?n.append(s,a):n.set(s,a);}return new Response(r,{status:t.statusCode,headers:n})}var it={node:$e,vercel:Oe,netlify:Pe,bun:Ie};function br(t="node"){let e=it[t];if(!e)throw new Error(`Platform "${t}" not supported`);return e}
26
- export{be as A,Ee as B,Me as C,Te as D,xe as E,$e as F,Oe as G,Pe as H,Ie as I,br as J,re as a,dt as b,je as c,x as d,_ as e,ye as f,ut as g,ct as h,P as i,g as j,D as k,z as l,J as m,V as n,L as o,St as p,vt as q,bt as r,Et as s,De as t,I as u,Re as v,we as w,Ce as x,Se as y,ve as z};