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 +2 -2
- package/dist/handler.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/compose.ts +4 -3
- package/src/handler.ts +18 -17
- package/src/index.ts +9 -7
package/dist/compose.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{parse as e}from"fast-querystring";import{
|
|
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:
|
|
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)=>{
|
|
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
|
|
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
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
|
|
12
|
-
|
|
13
|
-
headers.delete('Set-Cookie')
|
|
10
|
+
const parseSetCookies = (headers: Headers, setCookie: string[]) => {
|
|
11
|
+
headers.delete('Set-Cookie')
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
for (let i = 0; i < setCookie.length; i++) {
|
|
14
|
+
const index = setCookie[i].indexOf('=')
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
-
|
|
2175
|
-
|
|
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
|
|
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])
|