elysia 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/compose.js CHANGED
@@ -1,4 +1,4 @@
1
- import{parse as e}from"fast-querystring";import{createValidationError as r}from"./utils";import{mapEarlyResponse as t,mapResponse as a}from"./handler";import{mapErrorCode as s}from"./error";let n="AsyncFunction",o=e=>e.constructor.name===n;export const composeHandler=({method:c,hooks:l,validator:d,handler:i,handleError:f})=>{let p="try {\n",u="GET"!==c||i.constructor.name===n||l.parse.length||l.afterHandle.find(o)||l.beforeHandle.find(o)||l.transform.find(o);if(u){if(p+=`
1
+ import{parse as e}from"fast-querystring";import{mapEarlyResponse as r,mapResponse as t}from"./handler";import{createValidationError as a}from"./utils";import{mapErrorCode as s}from"./error";let n="AsyncFunction",o=e=>e.constructor.name===n;export const composeHandler=({method:c,hooks:l,validator:d,handler:i,handleError:f})=>{let p="try {\n",u="GET"!==c||i.constructor.name===n||l.parse.length||l.afterHandle.find(o)||l.beforeHandle.find(o)||l.transform.find(o);if(u){if(p+=`
2
2
  let contentType = c.request.headers.get('content-type');
3
3
 
4
4
  if (contentType) {
@@ -126,4 +126,4 @@ if(${r}) return ${r};
126
126
  }
127
127
  } = hooks
128
128
 
129
- return ${u?"async":""} function(c) {${p}}`.replace(/\t/g,"");let h=Function("hooks",p);return h({handler:i,hooks:l,validator:d,handleError:f,utils:{createValidationError:r,mapResponse:a,mapEarlyResponse:t,mapErrorCode:s,parseQuery:e}})};
129
+ return ${u?"async":""} function(c) {${p}}`.replace(/\t/g,"");let h=Function("hooks",p);return h({handler:i,hooks:l,validator:d,handleError:f,utils:{createValidationError:a,mapResponse:t,mapEarlyResponse:r,mapErrorCode:s,parseQuery:e}})};
package/dist/handler.js CHANGED
@@ -1 +1 @@
1
- export const isNotEmpty=e=>{for(let s in e)return!0;return!1};let e=(e,s)=>{if(Array.isArray(s)){e.delete("Set-Cookie");for(let r=0;r<s.length;r++){let t=s[r].indexOf("=");e.append("Set-Cookie",`${s[r].slice(0,t)}=${s[r].slice(t+1)}`)}}return e};export const mapEarlyResponse=(s,r)=>{if(isNotEmpty(r.headers)||200!==r.status||r.redirect)switch(r.redirect&&(r.headers.Location=r.redirect,r.status=302),r.headers["Set-Cookie"]&&(r.headers=e(new Headers(r.headers),r.headers["Set-Cookie"])),typeof s){case"string":return new Response(s,{status:r.status,headers:r.headers});case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:for(let e in r.headers)s.headers.append(e,r.headers[e]);return s;case Blob:return new Response(s,{status:r.status,headers:r.headers});case Promise:return s.then(e=>{let s=mapEarlyResponse(e,r);if(void 0!==s)return s});default:return r.headers["Content-Type"]||(r.headers["Content-Type"]="application/json"),new Response(JSON.stringify(s),{status:r.status,headers:r.headers})}case"function":if(s instanceof Blob)return new Response(s,{status:r.status,headers:r.headers});for(let e in r.headers)s.headers.append(e,r.headers[e]);return s;case"number":case"boolean":return new Response(s.toString(),{status:r.status,headers:r.headers})}else switch(typeof s){case"string":return new Response(s);case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:return s;case Blob:return new Response(s);case Promise:return s.then(e=>{let s=mapEarlyResponse(e,r);if(void 0!==s)return s});default:return new Response(JSON.stringify(s),{headers:{"content-type":"application/json"}})}case"function":if(s instanceof Blob)return new Response(s);return s;case"number":case"boolean":return new Response(s.toString())}};export const mapResponse=(s,r)=>{if(Object.keys(r.headers).length||200!==r.status||r.redirect)switch(r.redirect&&(r.headers.Location=r.redirect,r.status=302),r.headers?.["Set-Cookie"]&&(r.headers=e(new Headers(r.headers),r.headers["Set-Cookie"])),typeof s){case"string":return new Response(s,{status:r.status,headers:r.headers});case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:for(let e in r.headers)s.headers.append(e,r.headers[e]);return s;case Blob:return new Response(s,{status:r.status,headers:r.headers});case Promise:return s.then(e=>mapResponse(e,r));default:return r.headers["Content-Type"]||(r.headers["Content-Type"]="application/json"),new Response(JSON.stringify(s),{status:r.status,headers:r.headers})}case"function":if(s instanceof Blob)return new Response(s,{status:r.status,headers:r.headers});return s();case"number":case"boolean":return new Response(s.toString(),{status:r.status,headers:r.headers});case"undefined":return new Response("",{status:r.status,headers:r.headers});default:return new Response(s,{status:r.status,headers:r.headers})}else switch(typeof s){case"string":return new Response(s);case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:return s;case Blob:return new Response(s);case Promise:return s.then(e=>mapResponse(e,r));default:return new Response(JSON.stringify(s),{headers:{"content-type":"application/json"}})}case"function":if(s instanceof Blob)return new Response(s);return s();case"number":case"boolean":return new Response(s.toString());case"undefined":return new Response("");default:return new Response(s)}};export const errorToResponse=(e,s)=>new Response(JSON.stringify({name:e?.name,message:e?.message,cause:e?.cause}),{status:500,headers:s});
1
+ export const isNotEmpty=e=>{for(let s in e)return!0;return!1};let e=(e,s)=>{e.delete("Set-Cookie");for(let r=0;r<s.length;r++){let t=s[r].indexOf("=");e.append("Set-Cookie",`${s[r].slice(0,t)}=${s[r].slice(t+1)}`)}return e};export const mapEarlyResponse=(s,r)=>{if(isNotEmpty(r.headers)||r.status||r.redirect)switch(r.redirect&&(r.headers.Location=r.redirect,r.status=302),r.headers["Set-Cookie"]&&Array.isArray(r.headers["Set-Cookie"])&&(r.headers=e(new Headers(r.headers),r.headers["Set-Cookie"])),typeof s){case"string":return new Response(s,{status:r.status,headers:r.headers});case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:for(let e in r.headers)s.headers.append(e,r.headers[e]);return s;case Blob:return new Response(s,{status:r.status,headers:r.headers});case Promise:return s.then(e=>{let s=mapEarlyResponse(e,r);if(void 0!==s)return s});default:return r.headers["Content-Type"]||(r.headers["Content-Type"]="application/json"),new Response(JSON.stringify(s),{status:r.status,headers:r.headers})}case"function":if(s instanceof Blob)return new Response(s,{status:r.status,headers:r.headers});for(let e in r.headers)s.headers.append(e,r.headers[e]);return s;case"number":case"boolean":return new Response(s.toString(),{status:r.status,headers:r.headers})}else switch(typeof s){case"string":return new Response(s);case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:return s;case Blob:return new Response(s);case Promise:return s.then(e=>{let s=mapEarlyResponse(e,r);if(void 0!==s)return s});default:return new Response(JSON.stringify(s),{headers:{"content-type":"application/json"}})}case"function":if(s instanceof Blob)return new Response(s);return s;case"number":case"boolean":return new Response(s.toString())}};export const mapResponse=(s,r)=>{if(isNotEmpty(r.headers)||r.status||r.redirect)switch(r.redirect&&(r.headers.Location=r.redirect,r.status=302),r.headers["Set-Cookie"]&&Array.isArray(r.headers["Set-Cookie"])&&(r.headers=e(new Headers(r.headers),r.headers["Set-Cookie"])),typeof s){case"string":return new Response(s,{status:r.status,headers:r.headers});case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:for(let e in r.headers)s.headers.append(e,r.headers[e]);return s;case Blob:return new Response(s,{status:r.status,headers:r.headers});case Promise:return s.then(e=>mapResponse(e,r));default:return r.headers["Content-Type"]||(r.headers["Content-Type"]="application/json"),new Response(JSON.stringify(s),{status:r.status,headers:r.headers})}case"function":if(s instanceof Blob)return new Response(s,{status:r.status,headers:r.headers});return s();case"number":case"boolean":return new Response(s.toString(),{status:r.status,headers:r.headers});case"undefined":return new Response("",{status:r.status,headers:r.headers});default:return new Response(s,{status:r.status,headers:r.headers})}else switch(typeof s){case"string":return new Response(s);case"object":switch(s?.constructor){case Error:return errorToResponse(s,r.headers);case Response:return s;case Blob:return new Response(s);case Promise:return s.then(e=>mapResponse(e,r));default:return new Response(JSON.stringify(s),{headers:{"content-type":"application/json"}})}case"function":if(s instanceof Blob)return new Response(s);return s();case"number":case"boolean":return new Response(s.toString());case"undefined":return new Response("");default:return new Response(s)}};export const errorToResponse=(e,s)=>new Response(JSON.stringify({name:e?.name,message:e?.message,cause:e?.cause}),{status:500,headers:s});
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{nanoid as e}from"nanoid";import{Raikiri as t}from"raikiri";import{parse as r}from"fast-querystring";import{mapResponse as s,mapEarlyResponse as a}from"./handler";import{SCHEMA as i,EXPOSED as n,DEFS as h,clone as o,mergeHook as u,getSchemaValidator as l,getResponseSchemaValidator as d,mapPathnameAndQueryRegEx as c}from"./utils";import{registerSchemaPath as m}from"./schema";import{mapErrorCode as p,mapErrorStatus as f}from"./error";import{composeHandler as v}from"./compose";import{ws as y}from"./ws";export default class g{config;store={};meta={[i]:Object.create(null),[h]:Object.create(null),[n]:Object.create(null)};decorators={[i]:this.meta[i],[h]:this.meta[h],store:this.store};event={start:[],request:[],parse:[],transform:[],beforeHandle:[],afterHandle:[],error:[],stop:[]};server=null;$schema=null;router=new t;routes=[];wsRouter;lazyLoadModules=[];constructor(e){this.config={fn:"/~fn",...e}}_addHandler(e,t,r,s){t=t.startsWith("/")?t:`/${t}`,this.routes.push({method:e,path:t,handler:r,hooks:u({...this.event},s)});let a=this.meta[h],n=l(s?.schema?.body??this.$schema?.body,a),c=l(s?.schema?.headers??this.$schema?.headers,a,!0),p=l(s?.schema?.params??this.$schema?.params,a),f=l(s?.schema?.query??this.$schema?.query,a),y=d(s?.schema?.response??this.$schema?.response,a);m({schema:this.meta[i],contentType:s?.schema?.contentType,hook:s,method:e,path:t,models:this.meta[h]});let g=u(o(this.event),s),b={handle:v({method:e,hooks:g,validator:{body:n,headers:c,params:p,query:f,response:y},handler:r,handleError:this.handleError}),onError:g.error};this.router.add(e,t,b)}onStart(e){return this.event.start.push(e),this}onRequest(e){return this.event.request.push(e),this}onParse(e){return this.event.parse.splice(this.event.parse.length-1,0,e),this}onTransform(e){return this.event.transform.push(e),this}onBeforeHandle(e){return this.event.beforeHandle.push(e),this}onAfterHandle(e){return this.event.afterHandle.push(e),this}onError(e){return this.event.error.push(e),this}onStop(e){return this.event.stop.push(e),this}on(e,t){switch(e){case"start":this.event.start.push(t);break;case"request":this.event.request.push(t);break;case"parse":this.event.parse.push(t);break;case"transform":this.event.transform.push(t);break;case"beforeHandle":this.event.beforeHandle.push(t);break;case"afterHandle":this.event.afterHandle.push(t);break;case"error":this.event.error.push(t);break;case"stop":this.event.stop.push(t)}return this}group(e,t){let r=new g;r.store=this.store,this.wsRouter&&r.use(y());let s=t(r);return s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),this.setModel(s.meta[h]),Object.values(r.routes).forEach(({method:t,path:a,handler:i,hooks:n})=>{let h="/"===a?e:`${e}${a}`,o=r.wsRouter?.match("subscribe",h);if(o){let e=r.wsRouter.history.find(([e,t])=>a===t);if(!e)return;return this.ws(h,e[2])}this._addHandler(t,h,i,u(n,{error:s.event.error}))}),r.wsRouter&&this.wsRouter&&r.wsRouter.history.forEach(([t,r,s])=>{"/"===r?this.wsRouter?.add(t,e,s):this.wsRouter?.add(t,`${e}${r}`,s)}),this}guard(e,t){let r=new g;r.store=this.store,this.wsRouter&&r.use(y());let s=t(r);return s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),this.setModel(s.meta[h]),Object.values(r.routes).forEach(({method:t,path:s,handler:a,hooks:i})=>{let n=r.wsRouter?.match("subscribe",s);if(n){let e=r.wsRouter.history.find(([e,t])=>s===t);if(!e)return;return this.ws(s,e[2])}this._addHandler(t,s,a,u(e,i))}),r.wsRouter&&this.wsRouter&&r.wsRouter.history.forEach(([e,t,r])=>{this.wsRouter?.add(e,t,r)}),this}use(e){if(e instanceof Promise)return this.lazyLoadModules.push(e.then(e=>"function"==typeof e?e(this):e.default(this))),this;let t=e(this);return t instanceof Promise?(this.lazyLoadModules.push(t),this):t}if(e,t){return e?this.use(t):this}get(e,t,r){return this._addHandler("GET",e,t,r),this}post(e,t,r){return this._addHandler("POST",e,t,r),this}put(e,t,r){return this._addHandler("PUT",e,t,r),this}patch(e,t,r){return this._addHandler("PATCH",e,t,r),this}delete(e,t,r){return this._addHandler("DELETE",e,t,r),this}options(e,t,r){return this._addHandler("OPTIONS",e,t,r),this}all(e,t,r){return this._addHandler("ALL",e,t,r),this}head(e,t,r){return this._addHandler("HEAD",e,t,r),this}trace(e,t,r){return this._addHandler("TRACE",e,t,r),this}connect(e,t,r){return this._addHandler("CONNECT",e,t,r),this}ws(t,r){if(!this.wsRouter)throw Error("Can't find WebSocket. Please register WebSocket plugin first by importing 'elysia/ws'");return this.wsRouter.add("subscribe",t,r),this.get(t,t=>{if(console.log("Got",t.request.url),!this.server?.upgrade(t.request,{headers:"function"==typeof r.headers?r.headers(t):r.headers,data:{...t,id:e(),message:l(r.schema?.body,this.meta[h]),transformMessage:r.transform?Array.isArray(r.transformMessage)?r.transformMessage:[r.transformMessage]:[]}}))return t.set.status=400,"Expected a websocket connection"},{beforeHandle:r.beforeHandle,transform:r.transform,schema:{headers:r.schema?.headers,params:r.schema?.params,query:r.schema?.query}}),this}route(e,t,r,s){return this._addHandler(e,t,r,s),this}state(e,t){return e in this.store||(this.store[e]=t),this}decorate(e,t){return e in this.decorators||(this.decorators[e]=t),this}derive(e){return"AsyncFunction"===e.constructor.name?this.onTransform(async t=>{Object.assign(t,await e(t))}):this.onTransform(t=>{Object.assign(t,e(t))})}fn(e){return this.use(async()=>{let{fn:t}=await import("@elysiajs/fn");return t({app:this,value:e,path:this.config.fn})})}schema(e){let t=this.meta[h];return this.$schema={body:l(e.body,t),headers:l(e?.headers,t,!0),params:l(e?.params,t),query:l(e?.query,t),response:l(e?.response,t)},this}handle=async e=>this.innerHandle(e);innerHandle=e=>{let t=this.decorators;if(t.request=e,t.set={status:200,headers:{}},this.event.request.length)try{for(let e=0;e<this.event.request.length;e++){let r=a(this.event.request[e](t),t.set);if(r)return r}}catch(r){return this.handleError(e,r,t.set)}let s=e.url.match(c),i=this.router.match(e.method,s[1])??this.router.match("ALL",s[1]);return i?(t.params=i.params,s[2]?t.query=r(s[2]):t.query={},i.store.handle(t)):this.handleError(e,Error("NOT_FOUND"),t.set)};handleError=async(e,t,r={headers:{}})=>{for(let a=0;a<this.event.error.length;a++){let i=this.event.error[a]({request:e,code:p(t.message),error:t,set:r});if(i instanceof Promise&&(i=await i),null!=i)return s(i,r)}return new Response("string"==typeof t.cause?t.cause:t.message,{headers:r.headers,status:f(p(t.message))})};listen=(e,t)=>{if(!Bun)throw Error("Bun to run");if("string"==typeof e&&Number.isNaN(e=+e))throw Error("Port must be a numeric value");let r=this.innerHandle,s="object"==typeof e?{...this.config.serve,...e,fetch:r}:{...this.config.serve,port:e,fetch:r},a=`$$Elysia:${s.port}`;globalThis[a]?(this.server=globalThis[a],this.server.reload(s)):globalThis[a]=this.server=Bun.serve(s);for(let e=0;e<this.event.start.length;e++)this.event.start[e](this);return t&&t(this.server),Promise.all(this.lazyLoadModules).then(()=>{this.server.pendingRequests||Bun.gc(!0)}),this};stop=async()=>{if(!this.server)throw Error("Elysia isn't running. Call `app.listen` to start the server.");this.server.stop();for(let e=0;e<this.event.stop.length;e++)await this.event.stop[e](this)};get modules(){return Promise.all(this.lazyLoadModules)}setModel(e){return Object.entries(e).forEach(([e,t])=>{e in this.meta[h]||(this.meta[h][e]=t)}),this}}export{t}from"./custom-types";export{ws}from"./ws";export{SCHEMA,DEFS,EXPOSED,createValidationError,getSchemaValidator,mergeDeep,mergeHook,mergeObjectArray,mapPathnameAndQueryRegEx}from"./utils";export{ElysiaError,ValidationError}from"./validation";export{g as Elysia};
1
+ import{nanoid as e}from"nanoid";import{Raikiri as t}from"raikiri";import{parse as r}from"fast-querystring";import{mapResponse as s,mapEarlyResponse as a}from"./handler";import{SCHEMA as i,EXPOSED as o,DEFS as h,clone as n,mergeHook as u,getSchemaValidator as d,getResponseSchemaValidator as l,mapPathnameAndQueryRegEx as c,mergeDeep as m}from"./utils";import{registerSchemaPath as p}from"./schema";import{mapErrorCode as f,mapErrorStatus as v}from"./error";import{composeHandler as y}from"./compose";import{ws as g}from"./ws";export default class b{config;store={};meta={[i]:Object.create(null),[h]:Object.create(null),[o]:Object.create(null)};decorators={[i]:this.meta[i],[h]:this.meta[h],store:this.store};event={start:[],request:[],parse:[],transform:[],beforeHandle:[],afterHandle:[],error:[],stop:[]};server=null;$schema=null;router=new t;routes=[];wsRouter;lazyLoadModules=[];constructor(e){this.config={fn:"/~fn",...e}}_addHandler(e,t,r,s){t=t.startsWith("/")?t:`/${t}`,this.routes.push({method:e,path:t,handler:r,hooks:u({...this.event},s)});let a=this.meta[h],o=d(s?.schema?.body??this.$schema?.body,a),c=d(s?.schema?.headers??this.$schema?.headers,a,!0),m=d(s?.schema?.params??this.$schema?.params,a),f=d(s?.schema?.query??this.$schema?.query,a),v=l(s?.schema?.response??this.$schema?.response,a);p({schema:this.meta[i],contentType:s?.schema?.contentType,hook:s,method:e,path:t,models:this.meta[h]});let g=u(n(this.event),s),b={handle:y({method:e,hooks:g,validator:{body:o,headers:c,params:m,query:f,response:v},handler:r,handleError:this.handleError}),onError:g.error};this.router.add(e,t,b)}onStart(e){return this.event.start.push(e),this}onRequest(e){return this.event.request.push(e),this}onParse(e){return this.event.parse.splice(this.event.parse.length-1,0,e),this}onTransform(e){return this.event.transform.push(e),this}onBeforeHandle(e){return this.event.beforeHandle.push(e),this}onAfterHandle(e){return this.event.afterHandle.push(e),this}onError(e){return this.event.error.push(e),this}onStop(e){return this.event.stop.push(e),this}on(e,t){switch(e){case"start":this.event.start.push(t);break;case"request":this.event.request.push(t);break;case"parse":this.event.parse.push(t);break;case"transform":this.event.transform.push(t);break;case"beforeHandle":this.event.beforeHandle.push(t);break;case"afterHandle":this.event.afterHandle.push(t);break;case"error":this.event.error.push(t);break;case"stop":this.event.stop.push(t)}return this}group(e,t){let r=new b;r.store=this.store,this.wsRouter&&r.use(g());let s=t(r);return this.decorators=m(this.decorators,r.decorators),s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),this.setModel(s.meta[h]),Object.values(r.routes).forEach(({method:t,path:a,handler:i,hooks:o})=>{let h="/"===a?e:`${e}${a}`,n=r.wsRouter?.match("subscribe",h);if(n){let e=r.wsRouter.history.find(([e,t])=>a===t);if(!e)return;return this.ws(h,e[2])}this._addHandler(t,h,i,u(o,{error:s.event.error}))}),r.wsRouter&&this.wsRouter&&r.wsRouter.history.forEach(([t,r,s])=>{"/"===r?this.wsRouter?.add(t,e,s):this.wsRouter?.add(t,`${e}${r}`,s)}),this}guard(e,t){let r=new b;r.store=this.store,this.wsRouter&&r.use(g());let s=t(r);return this.decorators=m(this.decorators,r.decorators),s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),this.setModel(s.meta[h]),Object.values(r.routes).forEach(({method:t,path:s,handler:a,hooks:i})=>{let o=r.wsRouter?.match("subscribe",s);if(o){let e=r.wsRouter.history.find(([e,t])=>s===t);if(!e)return;return this.ws(s,e[2])}this._addHandler(t,s,a,u(e,i))}),r.wsRouter&&this.wsRouter&&r.wsRouter.history.forEach(([e,t,r])=>{this.wsRouter?.add(e,t,r)}),this}use(e){if(e instanceof Promise)return this.lazyLoadModules.push(e.then(e=>"function"==typeof e?e(this):e.default(this))),this;let t=e(this);return t instanceof Promise?(this.lazyLoadModules.push(t),this):t}if(e,t){return e?this.use(t):this}get(e,t,r){return this._addHandler("GET",e,t,r),this}post(e,t,r){return this._addHandler("POST",e,t,r),this}put(e,t,r){return this._addHandler("PUT",e,t,r),this}patch(e,t,r){return this._addHandler("PATCH",e,t,r),this}delete(e,t,r){return this._addHandler("DELETE",e,t,r),this}options(e,t,r){return this._addHandler("OPTIONS",e,t,r),this}all(e,t,r){return this._addHandler("ALL",e,t,r),this}head(e,t,r){return this._addHandler("HEAD",e,t,r),this}trace(e,t,r){return this._addHandler("TRACE",e,t,r),this}connect(e,t,r){return this._addHandler("CONNECT",e,t,r),this}ws(t,r){if(!this.wsRouter)throw Error("Can't find WebSocket. Please register WebSocket plugin first by importing 'elysia/ws'");return this.wsRouter.add("subscribe",t,r),this.get(t,t=>{if(!this.server?.upgrade(t.request,{headers:"function"==typeof r.headers?r.headers(t):r.headers,data:{...t,id:e(),message:d(r.schema?.body,this.meta[h]),transformMessage:r.transform?Array.isArray(r.transformMessage)?r.transformMessage:[r.transformMessage]:[]}}))return t.set.status=400,"Expected a websocket connection"},{beforeHandle:r.beforeHandle,transform:r.transform,schema:{headers:r.schema?.headers,params:r.schema?.params,query:r.schema?.query}}),this}route(e,t,r,s){return this._addHandler(e,t,r,s),this}state(e,t){return e in this.store||(this.store[e]=t),this}decorate(e,t){return e in this.decorators||(this.decorators[e]=t),this}derive(e){return"AsyncFunction"===e.constructor.name?this.onTransform(async t=>{Object.assign(t,await e(t))}):this.onTransform(t=>{Object.assign(t,e(t))})}fn(e){return this.use(async()=>{let{fn:t}=await import("@elysiajs/fn");return t({app:this,value:e,path:this.config.fn})})}schema(e){let t=this.meta[h];return this.$schema={body:d(e.body,t),headers:d(e?.headers,t,!0),params:d(e?.params,t),query:d(e?.query,t),response:d(e?.response,t)},this}handle=async e=>this.innerHandle(e);innerHandle=e=>{let t=this.decorators;if(t.request=e,t.set={headers:{},status:200},this.event.request.length)try{for(let e=0;e<this.event.request.length;e++){let r=a(this.event.request[e](t),t.set);if(r)return r}}catch(r){return this.handleError(e,r,t.set)}let s=c.exec(e.url),i=this.router.match(e.method,s[1])??this.router.match("ALL",s[1]);return i?(t.params=i.params,s[2]?t.query=r(s[2]):t.query={},i.store.handle(t)):this.handleError(e,Error("NOT_FOUND"),t.set)};handleError=async(e,t,r={headers:{}})=>{for(let a=0;a<this.event.error.length;a++){let i=this.event.error[a]({request:e,code:f(t.message),error:t,set:r});if(i instanceof Promise&&(i=await i),null!=i)return s(i,r)}return new Response("string"==typeof t.cause?t.cause:t.message,{headers:r.headers,status:v(f(t.message))})};listen=(e,t)=>{if(!Bun)throw Error("Bun to run");if("string"==typeof e&&Number.isNaN(e=+e))throw Error("Port must be a numeric value");let r=this.innerHandle,s="object"==typeof e?{...this.config.serve,...e,fetch:r}:{...this.config.serve,port:e,fetch:r},a=`$$Elysia:${s.port}`;globalThis[a]?(this.server=globalThis[a],this.server.reload(s)):globalThis[a]=this.server=Bun.serve(s);for(let e=0;e<this.event.start.length;e++)this.event.start[e](this);return t&&t(this.server),Promise.all(this.lazyLoadModules).then(()=>{this.server.pendingRequests||Bun.gc(!0)}),this};stop=async()=>{if(!this.server)throw Error("Elysia isn't running. Call `app.listen` to start the server.");this.server.stop();for(let e=0;e<this.event.stop.length;e++)await this.event.stop[e](this)};get modules(){return Promise.all(this.lazyLoadModules)}setModel(e){return Object.entries(e).forEach(([e,t])=>{e in this.meta[h]||(this.meta[h][e]=t)}),this}}export{t}from"./custom-types";export{ws}from"./ws";export{SCHEMA,DEFS,EXPOSED,createValidationError,getSchemaValidator,mergeDeep,mergeHook,mergeObjectArray,mapPathnameAndQueryRegEx}from"./utils";export{ElysiaError,ValidationError}from"./validation";export{b as Elysia};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elysia",
3
3
  "description": "Fast, and friendly Bun web framework",
4
- "version": "0.4.2",
4
+ "version": "0.4.4",
5
5
  "author": {
6
6
  "name": "saltyAom",
7
7
  "url": "https://github.com/SaltyAom",
package/src/compose.ts CHANGED
@@ -1,16 +1,17 @@
1
+ import { Elysia } from '.'
2
+
1
3
  import { parse as parseQuery } from 'fast-querystring'
2
4
 
3
- import { createValidationError } from './utils'
4
5
  import { mapEarlyResponse, mapResponse } from './handler'
6
+ import { createValidationError } from './utils'
7
+ import { mapErrorCode } from './error'
5
8
 
6
- import { Elysia } from '.'
7
9
  import type {
8
10
  HTTPMethod,
9
11
  LocalHandler,
10
12
  RegisteredHook,
11
13
  SchemaValidator
12
14
  } from './types'
13
- import { mapErrorCode } from './error'
14
15
 
15
16
  const ASYNC_FN = 'AsyncFunction'
16
17
  const isAsync = (x: Function) => x.constructor.name === ASYNC_FN
package/src/handler.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable no-case-declarations */
2
- import type { MaybePromise } from './types'
3
2
  import type { Context } from './context'
4
3
 
5
4
  export const isNotEmpty = (obj: Object) => {
@@ -8,20 +7,16 @@ export const isNotEmpty = (obj: Object) => {
8
7
  return false
9
8
  }
10
9
 
11
- const parseSetCookies = (headers: Headers, setCookie: string | string[]) => {
12
- if (Array.isArray(setCookie)) {
13
- headers.delete('Set-Cookie')
10
+ const parseSetCookies = (headers: Headers, setCookie: string[]) => {
11
+ headers.delete('Set-Cookie')
14
12
 
15
- for (let i = 0; i < setCookie.length; i++) {
16
- const index = setCookie[i].indexOf('=')
13
+ for (let i = 0; i < setCookie.length; i++) {
14
+ const index = setCookie[i].indexOf('=')
17
15
 
18
- headers.append(
19
- 'Set-Cookie',
20
- `${setCookie[i].slice(0, index)}=${setCookie[i].slice(
21
- index + 1
22
- )}`
23
- )
24
- }
16
+ headers.append(
17
+ 'Set-Cookie',
18
+ `${setCookie[i].slice(0, index)}=${setCookie[i].slice(index + 1)}`
19
+ )
25
20
  }
26
21
 
27
22
  return headers
@@ -32,13 +27,16 @@ export const mapEarlyResponse = (
32
27
  response: unknown,
33
28
  set: Context['set']
34
29
  ): Response | undefined => {
35
- if (isNotEmpty(set.headers) || set.status !== 200 || set.redirect) {
30
+ if (isNotEmpty(set.headers) || set.status || set.redirect) {
36
31
  if (set.redirect) {
37
32
  set.headers.Location = set.redirect
38
33
  set.status = 302
39
34
  }
40
35
 
41
- if (set.headers['Set-Cookie'])
36
+ if (
37
+ set.headers['Set-Cookie'] &&
38
+ Array.isArray(set.headers['Set-Cookie'])
39
+ )
42
40
  // @ts-ignore
43
41
  set.headers = parseSetCookies(
44
42
  new Headers(set.headers),
@@ -171,13 +169,16 @@ export const mapResponse = (
171
169
  response: unknown,
172
170
  set: Context['set']
173
171
  ): Response => {
174
- if (Object.keys(set.headers).length || set.status !== 200 || set.redirect) {
172
+ if (isNotEmpty(set.headers) || set.status || set.redirect) {
175
173
  if (set.redirect) {
176
174
  set.headers.Location = set.redirect
177
175
  set.status = 302
178
176
  }
179
177
 
180
- if (set.headers?.['Set-Cookie'])
178
+ if (
179
+ set.headers['Set-Cookie'] &&
180
+ Array.isArray(set.headers['Set-Cookie'])
181
+ )
181
182
  // @ts-ignore
182
183
  set.headers = parseSetCookies(
183
184
  new Headers(set.headers),
package/src/index.ts CHANGED
@@ -13,7 +13,8 @@ import {
13
13
  mergeHook,
14
14
  getSchemaValidator,
15
15
  getResponseSchemaValidator,
16
- mapPathnameAndQueryRegEx
16
+ mapPathnameAndQueryRegEx,
17
+ mergeDeep
17
18
  } from './utils'
18
19
  import { registerSchemaPath } from './schema'
19
20
  import { mapErrorCode, mapErrorStatus } from './error'
@@ -484,6 +485,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
484
485
  if (this.wsRouter) instance.use(ws())
485
486
 
486
487
  const sandbox = run(instance)
488
+ this.decorators = mergeDeep(this.decorators, instance.decorators)
487
489
 
488
490
  if (sandbox.event.request.length)
489
491
  this.event.request = [
@@ -575,6 +577,8 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
575
577
 
576
578
  const sandbox = run(instance)
577
579
 
580
+ this.decorators = mergeDeep(this.decorators, instance.decorators)
581
+
578
582
  if (sandbox.event.request.length)
579
583
  this.event.request = [
580
584
  ...this.event.request,
@@ -1813,8 +1817,6 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
1813
1817
  path,
1814
1818
  // @ts-ignore
1815
1819
  (context) => {
1816
- console.log('Got', context.request.url)
1817
-
1818
1820
  if (
1819
1821
  // @ts-ignore
1820
1822
  this.server?.upgrade(context.request, {
@@ -2165,14 +2167,14 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
2165
2167
  /**
2166
2168
  * Handle can be either sync or async to save performance.
2167
2169
  *
2168
- * Beside for benchmark purpose, please use 'handle' instead.
2170
+ * Beside benchmark purpose, please use 'handle' instead.
2169
2171
  */
2170
2172
  innerHandle = (request: Request): MaybePromise<Response> => {
2171
2173
  const context: Context = this.decorators as any as Context
2172
2174
  context.request = request
2173
2175
  context.set = {
2174
- status: 200,
2175
- headers: {}
2176
+ headers: {},
2177
+ status: 200
2176
2178
  }
2177
2179
 
2178
2180
  if (this.event.request.length)
@@ -2188,7 +2190,7 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
2188
2190
  return this.handleError(request, error as Error, context.set)
2189
2191
  }
2190
2192
 
2191
- const fracture = request.url.match(mapPathnameAndQueryRegEx)!
2193
+ const fracture = mapPathnameAndQueryRegEx.exec(request.url)!
2192
2194
  const route =
2193
2195
  this.router.match(request.method, fracture[1]) ??
2194
2196
  this.router.match('ALL', fracture[1])