elysia 0.2.8 → 0.3.0-beta.0

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/context.d.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  /// <reference types="bun-types" />
2
- import { Elysia } from '.';
3
- import type { TypedRoute } from './types';
2
+ import type { Elysia, TypedRoute, DEFS, SCHEMA, TypedSchema } from '.';
4
3
  export interface Context<Route extends TypedRoute = TypedRoute, Store extends Elysia['store'] = Elysia['store']> {
5
4
  request: Request;
6
5
  query: Route['query'] extends undefined ? Record<string, unknown> : Route['query'];
7
6
  params: Route['params'];
8
7
  body: Route['body'];
9
8
  store: Store;
9
+ [SCHEMA]: TypedSchema;
10
+ [DEFS]: {
11
+ [index: string]: Record<string, unknown>;
12
+ };
10
13
  set: {
11
14
  headers: Record<string, string>;
12
15
  status?: number;
@@ -0,0 +1,26 @@
1
+ /// <reference types="bun-types" />
2
+ import { Type, type SchemaOptions } from '@sinclair/typebox';
3
+ type MaybeArray<T> = T | T[];
4
+ export declare namespace ElysiaTypeOptions {
5
+ type FileUnit = number | `${number}${'k' | 'm'}`;
6
+ interface File extends SchemaOptions {
7
+ type?: MaybeArray<(string & {}) | 'image' | 'image/jpeg' | 'image/png' | 'image/gif' | 'image/tiff' | 'image/x-icon' | 'image/svg' | 'image/webp' | 'image/avif' | 'audio' | 'audio/mpeg' | 'audio/x-ms-wma' | 'audio/vnd.rn-realaudio' | 'audio/x-wav' | 'video' | 'video/mpeg' | 'video/mp4' | 'video/quicktime' | 'video/x-ms-wmv' | 'video/x-msvideo' | 'video/x-flv' | 'video/webm' | 'text' | 'text/css' | 'text/csv' | 'text/html' | 'text/javascript' | 'text/plain' | 'text/xml' | 'application' | 'application/ogg' | 'application/pdf' | 'application/xhtml' | 'application/html' | 'application/json' | 'application/ld+json' | 'application/xml' | 'application/zip'>;
8
+ minSize?: FileUnit;
9
+ maxSize?: FileUnit;
10
+ }
11
+ interface Files extends File {
12
+ minItems?: number;
13
+ maxItems?: number;
14
+ }
15
+ }
16
+ export declare const ElysiaType: {
17
+ readonly File: (options?: Partial<ElysiaTypeOptions.File> | undefined) => import("@sinclair/typebox").TUnsafe<Blob>;
18
+ readonly Files: (options?: Partial<ElysiaTypeOptions.Files> | undefined) => import("@sinclair/typebox").TUnsafe<Blob[]>;
19
+ };
20
+ declare module '@sinclair/typebox' {
21
+ interface TypeBuilder {
22
+ File: typeof ElysiaType.File;
23
+ Files: typeof ElysiaType.Files;
24
+ }
25
+ }
26
+ export { Type as t };
@@ -0,0 +1 @@
1
+ import{Type as e}from"@sinclair/typebox";import{TypeSystem as t}from"@sinclair/typebox/system";let i=e=>{if("string"==typeof e)switch(e.slice(-1)){case"k":return 1024*+e.slice(0,e.length-1);case"m":return 1048576*+e.slice(0,e.length-1);default:return+e}return e},r=(e,t)=>{if(!(t instanceof Blob)||e.minSize&&t.size<i(e.minSize)||e.maxSize&&t.size>i(e.maxSize))return!1;if(e.extension){if("string"==typeof e.extension){if(!t.type.startsWith(e.extension))return!1}else{for(let i=0;i<e.extension.length;i++)if(t.type.startsWith(e.extension[i]))return!0;return!1}}return!0};export const ElysiaType={File:t.CreateType("File",r),Files:t.CreateType("Files",(e,t)=>{if(!Array.isArray(t)||e.minItems&&t.length<e.minItems||e.maxItems&&t.length>e.maxItems)return!1;for(let i=0;i<t.length;i++)if(!r(e,t[i]))return!1;return!0})};e.File=e=>ElysiaType.File({default:"File",...e,extension:e?.type,type:"string",format:"binary"}),e.Files=e=>ElysiaType.Files({default:"Files",...e,extension:e?.type,type:"string",format:"binary"});export{e as t};
package/dist/fn.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /// <reference types="bun-types" />
2
+ import { EXPOSED } from './utils';
3
+ import type { Context } from './context';
4
+ import type { ConnectedKeysType, ElysiaInstance, FunctionProperties, JoinKeys } from './types';
5
+ export declare const permission: <T, Key extends JoinKeys<FunctionProperties<T>, ""> = JoinKeys<FunctionProperties<T>, "">>({ value, allow, deny, check }: {
6
+ value: T;
7
+ allow?: Key[] | undefined;
8
+ deny?: Key[] | undefined;
9
+ check?: boolean | ((context: {
10
+ request: Request;
11
+ key: Key;
12
+ params: T extends (...args: infer Args) => any ? Args : Key extends string ? ConnectedKeysType<T, Key> : unknown;
13
+ match: <Case extends Key>(a: Case extends string ? Partial<{ [x in Case]: (params: ConnectedKeysType<T, Case>) => any; } | {
14
+ default?: ((params: T extends (...args: infer Args_1) => any ? Args_1 : Key extends string ? ConnectedKeysType<T, Key> : unknown) => any) | undefined;
15
+ }> : {}) => void;
16
+ }) => unknown) | undefined;
17
+ }) => {
18
+ [EXPOSED]: boolean;
19
+ value: T;
20
+ check: boolean | ((context: {
21
+ request: Request;
22
+ key: Key;
23
+ params: T extends (...args: infer Args) => any ? Args : Key extends string ? ConnectedKeysType<T, Key> : unknown;
24
+ match: <Case extends Key>(a: Case extends string ? Partial<{ [x in Case]: (params: ConnectedKeysType<T, Case>) => any; } | {
25
+ default?: ((params: T extends (...args: infer Args_1) => any ? Args_1 : Key extends string ? ConnectedKeysType<T, Key> : unknown) => any) | undefined;
26
+ }> : {}) => void;
27
+ }) => unknown);
28
+ allow: Key[] | undefined;
29
+ deny: Key[] | undefined;
30
+ };
31
+ export type Permission = typeof permission;
32
+ export declare const runFn: (context: Context, exposed: ElysiaInstance['meta'][typeof EXPOSED]) => Promise<Record<string, any>>;
package/dist/fn.js ADDED
@@ -0,0 +1 @@
1
+ import{EXPOSED as e}from"./utils";import{serialize as n}from"superjson";export const permission=({value:n,allow:r,deny:i,check:t=!0})=>({[e]:!0,value:n,check:t,allow:r,deny:i});export const runFn=(r,i)=>{let t=[],o=r.body;e:for(let n=0;n<o.length;n++){let c=o[n],l=i,u=c.n;if(!Array.isArray(c.n)){t.push(Error("Invalid procedure"));continue e}let s=u[u.length-1];if(1===u.length){if(s in l&&e in l[s]){if(!1==l[s].check){t.push(Error("Forbidden"));continue e}if(!0!==l[s].check){try{let e=l[s].check({...r,key:s,params:c.p??null,match(e){}});if(e instanceof Error){t.push(e);continue e}}catch(e){t.push(e);continue e}l=l[s],s="value"}}}else for(let n=0;n<u.length-1;n++){if(!(l=l[u[n]])){t.push(Error("Invalid procedure"));continue e}if(e in l){let e=u.slice(n+1).join("."),i="function"==typeof l.check;if(!0===l.allow?.includes(e)&&!i){l=l.value;continue}if(!1!=l.check&&!0!==l.deny?.includes(e)&&(!1!==l.allow?.includes(e)||l.deny||i)){if(!0!==l.check)try{let n;let i=l.check({...r,key:e,params:c.p??null,match(e){n=e}});if(n)try{let r=(n[e]??n.default)?.(c.p??null);if(r instanceof Error)throw r}catch(r){if(!(e in n)&&l.allow?.includes(e)){l=l.value;continue}t.push(r);continue e}if(i instanceof Error){t.push(i);continue e}}catch(e){t.push(e);continue e}}else{t.push(Error("Forbidden"));continue e}l=l.value}}"function"!=typeof l[s]?t.push(Error("Invalid procedure")):void 0===c.p?t.push(l[s]()):1===c.p.length?t.push(l[s](c.p[0])):t.push(l[s](...c.p))}return Promise.all(t).then(n)};
package/dist/handler.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference types="bun-types" />
2
2
  import type { Context } from './context';
3
+ export declare const isNotEmpty: (obj: Object) => boolean;
3
4
  export declare const mapEarlyResponse: (response: unknown, set: Context['set']) => Response | undefined;
4
5
  export declare const mapResponse: (response: unknown, set: Context['set']) => Response;
5
6
  export declare const errorToResponse: (error: Error, headers?: HeadersInit) => Response;
package/dist/handler.js CHANGED
@@ -1 +1 @@
1
- let e=e=>{for(let s in e)return!0;return!1},s=(e,s)=>{if(Array.isArray(s)){e.delete("Set-Cookie");for(let r=0;r<s.length;r++){let n=s[r].indexOf("=");e.append("Set-Cookie",`${s[r].slice(0,n)}=${s[r].slice(n+1)}`)}}return e};export const mapEarlyResponse=(r,n)=>{if(n.headers?.["Set-Cookie"]&&(n.headers=s(new Headers(n.headers),n.headers["Set-Cookie"])),n.redirect)return Response.redirect(n.redirect,{headers:n.headers});if(e(n.headers)||200!==n.status)switch(typeof r){case"string":return new Response(r,{status:n.status,headers:n.headers});case"object":if(r instanceof Error)return errorToResponse(r,n.headers);if(r instanceof Response){for(let e in n.headers)r.headers.append(e,n.headers[e]);return r}if(r instanceof Blob)return new Response(r,{status:n.status,headers:n.headers});return n.headers["Content-Type"]||(n.headers["Content-Type"]="application/json"),new Response(JSON.stringify(r),{status:n.status,headers:n.headers});case"function":if(r instanceof Blob)return new Response(r,{status:n.status,headers:n.headers});for(let e in n.headers)r.headers.append(e,n.headers[e]);return r;case"number":case"boolean":return new Response(r.toString(),{status:n.status,headers:n.headers})}else switch(typeof r){case"string":return new Response(r);case"object":if(r instanceof Response)return r;if(r instanceof Error)return errorToResponse(r,n.headers);if(r instanceof Blob)return new Response(r);return new Response(JSON.stringify(r),{headers:{"content-type":"application/json"}});case"function":if(r instanceof Blob)return new Response(r);return r;case"number":case"boolean":return new Response(r.toString())}};export const mapResponse=(r,n)=>{if(n.headers?.["Set-Cookie"]&&(n.headers=s(new Headers(n.headers),n.headers["Set-Cookie"])),n.redirect)return Response.redirect(n.redirect,{headers:n.headers});if(e(n.headers)||200!==n.status)switch(typeof r){case"string":default:return new Response(r,{status:n.status,headers:n.headers});case"object":if(r instanceof Error)return errorToResponse(r,n.headers);if(r instanceof Response){for(let e in n.headers)r.headers.append(e,n.headers[e]);return r}if(r instanceof Blob)return new Response(r,{status:n.status,headers:n.headers});return n.headers["Content-Type"]||(n.headers["Content-Type"]="application/json"),new Response(JSON.stringify(r),{status:n.status,headers:n.headers});case"function":if(r instanceof Blob)return new Response(r,{status:n.status,headers:n.headers});return r();case"number":case"boolean":return new Response(r.toString(),{status:n.status,headers:n.headers});case"undefined":return new Response("",{status:n.status,headers:n.headers})}else switch(typeof r){case"string":default:return new Response(r);case"object":if(r instanceof Response)return r;if(r instanceof Error)return errorToResponse(r,n.headers);if(r instanceof Blob)return new Response(r);return new Response(JSON.stringify(r),{headers:{"content-type":"application/json"}});case"function":if(r instanceof Blob)return new Response(r);return r();case"number":case"boolean":return new Response(r.toString());case"undefined":return new Response("")}};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)=>{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(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"])),isNotEmpty(r.headers)||200!==r.status)switch(typeof s){case"string":return new Response(s,{status:r.status,headers:r.headers});case"object":if(s instanceof Error)return errorToResponse(s,r.headers);if(s instanceof Response){for(let e in r.headers)s.headers.append(e,r.headers[e]);return s}if(s instanceof Blob)return new Response(s,{status:r.status,headers:r.headers});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":if(s instanceof Response)return s;if(s instanceof Error)return errorToResponse(s,r.headers);if(s instanceof Blob)return new Response(s);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(r.redirect&&(r.headers.Location=r.redirect,r.status=302),r.headers?.["Set-Cookie"])switch(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});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})}if(r.redirect)return Response.redirect(r.redirect,{headers:r.headers});if(Object.keys(r.headers).length||200!==r.status)switch(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});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":default:return new Response(s);case"object":if(s instanceof Response)return s;if(s instanceof Error)return errorToResponse(s,r.headers);if(s instanceof Blob)return new Response(s);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("")}};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.d.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  /// <reference types="bun-types" />
2
2
  import type { Serve, Server } from 'bun';
3
- import { SCHEMA, DEFS } from './utils';
3
+ import { permission, type Permission } from './fn';
4
+ import { SCHEMA, EXPOSED, DEFS } from './utils';
4
5
  import type { Context } from './context';
5
- import type { Handler, BeforeRequestHandler, TypedRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, InternalRoute, BodyParser, ErrorHandler, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, LifeCycleStore, VoidLifeCycle, AfterRequestHandler, MergeIfNotNull, IsAny, OverwritableTypeRoute, MergeSchema, ListenCallback, NoReturnHandler, ElysiaRoute, MaybePromise, IsNever } from './types';
6
+ import type { Handler, BeforeRequestHandler, TypedRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, InternalRoute, BodyParser, ErrorHandler, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, LifeCycleStore, VoidLifeCycle, AfterRequestHandler, IsAny, OverwritableTypeRoute, MergeSchema, ListenCallback, NoReturnHandler, ElysiaRoute, MaybePromise, IsNever } from './types';
6
7
  import { type TSchema } from '@sinclair/typebox';
7
8
  export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
8
9
  config: ElysiaConfig;
9
10
  store: Instance['store'];
10
- protected decorators: Record<string, unknown> | null;
11
+ meta: Instance['meta'];
12
+ protected decorators: ElysiaInstance['request'];
11
13
  event: LifeCycleStore<Instance>;
12
14
  server: Server | null;
13
15
  private $schema;
@@ -29,40 +31,44 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
29
31
  request: Instance['request'];
30
32
  store: Omit<Instance['store'], typeof SCHEMA> & ElysiaInstance['store'];
31
33
  schema: Instance['schema'];
34
+ meta: Omit<Instance['meta'], typeof SCHEMA> & ElysiaInstance['meta'];
32
35
  }>) => NewElysia): NewElysia extends Elysia<infer NewInstance> ? Elysia<{
33
36
  request: Instance['request'] & NewInstance['request'];
34
37
  schema: Instance['schema'] & NewInstance['schema'];
35
- store: Instance['store'] & (Omit<NewInstance['store'], typeof SCHEMA> & {
38
+ store: Instance['store'] & NewInstance['store'];
39
+ meta: Instance['meta'] & (Omit<NewInstance['meta'], typeof SCHEMA> & {
36
40
  [key in typeof SCHEMA]: {
37
- [key in keyof NewInstance['store'][typeof SCHEMA] as key extends `${infer Rest}` ? `${Prefix}${Rest}` : key]: NewInstance['store'][typeof SCHEMA][key];
41
+ [key in keyof NewInstance['meta'][typeof SCHEMA] as key extends `${infer Rest}` ? `${Prefix}${Rest}` : key]: NewInstance['meta'][typeof SCHEMA][key];
38
42
  };
39
43
  });
40
44
  }> : this;
41
- guard<Schema extends TypedSchema = {}, NewElysia extends Elysia<any> = Elysia<any>>(hook: LocalHook<Schema, Instance>, run: (group: Elysia<{
45
+ guard<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, NewElysia extends Elysia<any> = Elysia<any>>(hook: LocalHook<Schema, Instance>, run: (group: Elysia<{
42
46
  request: Instance['request'];
43
47
  store: Instance['store'];
44
- schema: Omit<MergeIfNotNull<Schema, Instance['schema']>, typeof SCHEMA>;
48
+ schema: Schema & Instance['schema'];
49
+ meta: Instance['meta'];
45
50
  }>) => NewElysia): NewElysia extends Elysia<infer NewInstance> ? Elysia<NewInstance & Instance> : this;
46
51
  use<NewElysia extends MaybePromise<Elysia<any>> = Elysia<any>, Params extends Elysia = Elysia<any>, LazyLoadElysia extends never | ElysiaInstance = never>(plugin: MaybePromise<(app: Params extends Elysia<infer ParamsInstance> ? IsAny<ParamsInstance> extends true ? this : Params : Params) => MaybePromise<NewElysia>> | Promise<{
47
52
  default: (elysia: Elysia<any>) => MaybePromise<Elysia<LazyLoadElysia>>;
48
53
  }>): IsNever<LazyLoadElysia> extends false ? Elysia<LazyLoadElysia & Instance> : NewElysia extends Elysia<infer NewInstance> ? IsNever<NewInstance> extends true ? Elysia<Instance> : Elysia<NewInstance & Instance> : NewElysia extends Promise<Elysia<infer NewInstance>> ? Elysia<NewInstance & Instance> : this;
49
- get<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'GET', Schema, Instance, Path, Response>;
50
- post<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'POST', Schema, Instance, Path, Response>;
51
- put<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'PUT', Schema, Instance, Path, Response>;
52
- patch<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'PATCH', Schema, Instance, Path, Response>;
53
- delete<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'DELETE', Schema, Instance, Path, Response>;
54
- options<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'OPTIONS', Schema, Instance, Path, Response>;
55
- all<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'ALL', Schema, Instance, Path, Response>;
56
- head<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'HEAD', Schema, Instance, Path, Response>;
57
- trace<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'TRACE', Schema, Instance, Path, Response>;
58
- connect<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'CONNECT', Schema, Instance, Path, Response>;
59
- route<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, Method extends HTTPMethod = HTTPMethod, Path extends string = string, Response = unknown>(method: Method, path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<Method, Schema, Instance, Path, Response>;
60
- state<Key extends string | number | symbol = keyof Instance['store'], Value = Instance['store'][keyof Instance['store']], ReturnValue = Value extends () => infer Returned ? Returned extends Promise<infer AsyncReturned> ? AsyncReturned : Returned : Value, NewInstance = Elysia<{
54
+ get<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'GET', Schema, Instance, Path, Response>;
55
+ post<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'POST', Schema, Instance, Path, Response>;
56
+ put<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'PUT', Schema, Instance, Path, Response>;
57
+ patch<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'PATCH', Schema, Instance, Path, Response>;
58
+ delete<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'DELETE', Schema, Instance, Path, Response>;
59
+ options<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'OPTIONS', Schema, Instance, Path, Response>;
60
+ all<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'ALL', Schema, Instance, Path, Response>;
61
+ head<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'HEAD', Schema, Instance, Path, Response>;
62
+ trace<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'TRACE', Schema, Instance, Path, Response>;
63
+ connect<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Path extends string = string, Response = unknown>(path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<'CONNECT', Schema, Instance, Path, Response>;
64
+ route<Schema extends TypedSchema<Exclude<keyof Instance['meta'][typeof DEFS], number | symbol>> = {}, Method extends HTTPMethod = HTTPMethod, Path extends string = string, Response = unknown>(method: Method, path: Path, handler: LocalHandler<Schema, Instance, Path, Response>, hook?: LocalHook<Schema, Instance, Path>): ElysiaRoute<Method, Schema, Instance, Path, Response>;
65
+ state<Key extends string | number | symbol = keyof Instance['store'], Value = Instance['store'][keyof Instance['store']], NewInstance = Elysia<{
61
66
  store: Instance['store'] & {
62
- [key in Key]: ReturnValue;
67
+ [key in Key]: Value;
63
68
  };
64
69
  request: Instance['request'];
65
70
  schema: Instance['schema'];
71
+ meta: Instance['meta'];
66
72
  }>>(name: Key, value: Value): NewInstance;
67
73
  decorate<Name extends string, Value = any, NewInstance = Elysia<{
68
74
  store: Instance['store'];
@@ -70,43 +76,48 @@ export default class Elysia<Instance extends ElysiaInstance = ElysiaInstance> {
70
76
  [key in Name]: Value;
71
77
  };
72
78
  schema: Instance['schema'];
79
+ meta: Instance['meta'];
73
80
  }>>(name: Name, value: Value): NewInstance;
74
- derive<Returned extends Record<string | number | symbol, () => any> = Record<string | number | symbol, () => any>>(transform: (store: () => Readonly<Instance['store']>) => Returned): Elysia<{
75
- store: Instance['store'] & Returned;
76
- request: Instance['request'];
77
- schema: Instance['schema'];
78
- }>;
79
81
  inject<Returned extends Object = Object>(transform: (context: Context<{}, Instance['store']> & Instance['request']) => Returned extends {
80
82
  store: any;
81
83
  } ? never : Returned): Elysia<{
82
84
  store: Instance['store'];
83
85
  request: Instance['request'] & Returned;
84
86
  schema: Instance['schema'];
87
+ meta: Instance['meta'];
88
+ }>;
89
+ fn<T extends Record<string, unknown> | ((app: Instance['request'] & {
90
+ store: Instance['store'];
91
+ permission: Permission;
92
+ }) => Record<string, unknown>) = Record<string, unknown> | ((app: Instance['request'] & {
93
+ store: Instance['store'];
94
+ permission: Permission;
95
+ }) => Record<string, unknown>)>(value: T): Elysia<{
96
+ store: Instance['store'];
97
+ request: Instance['request'];
98
+ schema: Instance['schema'];
99
+ meta: Instance['meta'] & Record<typeof EXPOSED, T extends (store: any) => infer Returned ? Returned : T>;
85
100
  }>;
86
101
  schema<Schema extends TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>> = TypedSchema<Exclude<keyof Instance['store'][typeof DEFS], number | symbol>>, NewInstance = Elysia<{
87
102
  request: Instance['request'];
88
103
  store: Instance['store'];
89
104
  schema: MergeSchema<Schema, Instance['schema']>;
105
+ meta: Instance['meta'];
90
106
  }>>(schema: Schema): NewInstance;
91
107
  handle: (request: Request) => Promise<Response>;
92
108
  handleError(request: Request, error: Error, set?: Context['set']): Promise<Response>;
93
109
  listen: (options: string | number | Partial<Serve>, callback?: ListenCallback) => this;
94
110
  stop: () => Promise<void>;
95
- get modules(): Promise<Elysia<ElysiaInstance<{
96
- store: Record<any, any> & Record<typeof SCHEMA, {}> & Record<typeof DEFS, {}>;
97
- request: {};
98
- schema: {};
99
- }>>[]>;
111
+ get modules(): Promise<Elysia<any>[]>;
100
112
  setModel<Recorder extends Record<string, TSchema>>(record: Recorder): Elysia<{
101
- store: Instance['store'] & {
102
- [Defs in typeof DEFS]: Recorder;
103
- };
113
+ store: Instance['store'];
104
114
  request: Instance['request'];
105
115
  schema: Instance['schema'];
116
+ meta: Instance['meta'] & Record<typeof DEFS, Recorder>;
106
117
  }>;
107
118
  }
108
- export { Elysia };
109
- export { Type as t } from '@sinclair/typebox';
110
- export { SCHEMA, DEFS, createValidationError, getSchemaValidator, mergeDeep, mergeHook, mergeObjectArray, mapPathnameAndQueryRegEx, mapQuery } from './utils';
119
+ export { Elysia, permission };
120
+ export { t } from './custom-types';
121
+ export { SCHEMA, DEFS, EXPOSED, createValidationError, getSchemaValidator, mergeDeep, mergeHook, mergeObjectArray, mapPathnameAndQueryRegEx, mapQuery } from './utils';
111
122
  export type { Context, PreContext } from './context';
112
123
  export type { Handler, RegisteredHook, BeforeRequestHandler, TypedRoute, OverwritableTypeRoute, ElysiaInstance, ElysiaConfig, HTTPMethod, ComposedHandler, InternalRoute, BodyParser, ErrorHandler, ErrorCode, TypedSchema, LocalHook, LocalHandler, LifeCycle, LifeCycleEvent, AfterRequestHandler, HookHandler, TypedSchemaToRoute, UnwrapSchema, LifeCycleStore, VoidLifeCycle, SchemaValidator, ElysiaRoute, ExtractPath, IsPathParameter, IsAny, IsNever, UnknownFallback, WithArray, ObjectValues, PickInOrder, MaybePromise, MergeIfNotNull } from './types';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{Raikiri as e}from"raikiri";import{mapResponse as t,mapEarlyResponse as r}from"./handler";import{mapQuery as s,clone as a,mergeHook as i,mergeDeep as n,createValidationError as h,getSchemaValidator as o,SCHEMA as l,DEFS as d,getResponseSchemaValidator as u,mapPathnameAndQueryRegEx as f}from"./utils";import{registerSchemaPath as c}from"./schema";import{mapErrorCode as p,mapErrorStatus as m}from"./error";export default class v{store={[l]:{},[d]:{}};decorators=null;event={start:[],request:[],parse:[],transform:[],beforeHandle:[],afterHandle:[],error:[],stop:[]};server=null;$schema=null;router=new e;routes=[];lazyLoadModules=[];constructor(e={}){this.config={...e}}_addHandler(e,t,r,s){t=t.startsWith("/")?t:`/${t}`,this.routes.push({method:e,path:t,handler:r,hooks:i(a(this.event),s)});let n=this.store[d],h=o(s?.schema?.body??this.$schema?.body,n),f=o(s?.schema?.headers??this.$schema?.headers,n,!0),p=o(s?.schema?.params??this.$schema?.params,n),m=o(s?.schema?.query??this.$schema?.query,n),v=u(s?.schema?.response??this.$schema?.response,n);c({schema:this.store[l],hook:s,method:e,path:t,models:this.store[d]});let g=i(a(this.event),s);g.schema||g.transform.length||g.beforeHandle.length||g.error.length||g.afterHandle.length||(g=void 0);let y={handle:r,hooks:g,validator:h||f||p||m||v?{body:h,header:f,params:p,query:m,response:v}:void 0};this.router.add(e,t,y)}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 v;r.store=this.store;let s=t(r);return s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),Object.values(r.routes).forEach(({method:t,path:r,handler:a,hooks:n})=>{"/"===r?this._addHandler(t,e,a,i(n,{error:s.event.error})):this._addHandler(t,`${e}${r}`,a,i(n,{error:s.event.error}))}),this}guard(e,t){let r=new v;r.store=this.store;let s=t(r);return s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),Object.values(r.routes).forEach(({method:t,path:r,handler:s,hooks:a})=>{this._addHandler(t,r,s,i(e,a))}),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}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}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 this.decorators||(this.decorators={}),e in this.decorators||(this.decorators[e]=t),this}derive(e){return this.store=n(this.store,e(()=>this.store)),this}inject(e){return this.onTransform(t=>{Object.assign(t,e(t))})}schema(e){let t=this.store[d];return this.$schema={body:o(e.body,t),headers:o(e?.headers,t,!0),params:o(e?.params,t),query:o(e?.query,t),response:o(e?.response,t)},this}handle=async e=>{let i;let n={status:200,headers:{}};this.decorators?((i=a(this.decorators)).request=e,i.set=n,i.store=this.store,i.query={}):i={set:n,store:this.store,request:e,query:{}};try{let a;if(this.event.request.length)for(let e=0;e<this.event.request.length;e++){let t=this.event.request[e](i);if(t instanceof Promise&&(t=await t),t=r(t,n))return t}let o=e.url.match(f);if(!o)throw Error("NOT_FOUND");let l=this.router.match(e.method,o[1])??this.router.match("ALL",o[1]),d=l?.store;if(!d)throw Error("NOT_FOUND");if("GET"!==e.method){let t=e.headers.get("content-type");if(t){let r=t.indexOf(";");if(-1!==r&&(t=t.slice(0,r)),this.event.parse.length)for(let e=0;e<this.event.parse.length;e++){let r=this.event.parse[e](i,t);if(r instanceof Promise&&(r=await r),void 0!==r){a=r;break}}if(void 0===a)switch(t){case"application/json":a=await e.json();break;case"text/plain":a=await e.text();break;case"application/x-www-form-urlencoded":a=s(await e.text())}}}i.body=a,i.params=l.params,o[2]&&(i.query=s(o[2]));let u=d.hooks;if(u?.transform.length)for(let e=0;e<u.transform.length;e++){let t=u.transform[e](i);t instanceof Promise&&await t}if(d.validator){let t=d.validator;if(t.headers){let r={};for(let t in e.headers)r[t]=e.headers.get(t);if(!1===t.headers.Check(r))throw h("header",t.headers,r)}if(!1===t.params?.Check(i.params))throw h("params",t.params,i.params);if(!1===t.query?.Check(i.query))throw h("query",t.query,i.query);if(!1===t.body?.Check(a))throw h("body",t.body,a)}if(u?.beforeHandle.length)for(let e=0;e<u.beforeHandle.length;e++){let t=u.beforeHandle[e](i);if(t instanceof Promise&&(t=await t),null!=t){for(let e=0;e<u.afterHandle.length;e++){let r=u.afterHandle[e](i,t);r instanceof Promise&&(r=await r),r&&(t=r)}let e=r(t,i.set);if(e)return e}}let c=d.handle(i);if(c instanceof Promise&&(c=await c),!1===d.validator?.response?.Check(c))throw h("response",d.validator.response,c);if(u?.afterHandle.length)for(let e=0;e<u.afterHandle.length;e++){let t=u.afterHandle[e](i,c);t instanceof Promise&&(t=await t);let s=r(t,i.set);if(s)return s}return t(c,i.set)}catch(t){return(!n.status||n.status<300)&&(n.status=500),this.handleError(e,t,n)}};async handleError(e,r,s={headers:{}}){for(let a=0;a<this.event.error.length;a++){let i=this.event.error[a]({request:e,code:p(r.message),error:r,set:s});if(i instanceof Promise&&(i=await i),null!=i)return t(i,s)}return new Response("string"==typeof r.cause?r.cause:r.message,{headers:s.headers,status:m(p(r.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.handle,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.store[d]||(this.store[d][e]=t)}),this}}export{Type as t}from"@sinclair/typebox";export{SCHEMA,DEFS,createValidationError,getSchemaValidator,mergeDeep,mergeHook,mergeObjectArray,mapPathnameAndQueryRegEx,mapQuery}from"./utils";export{v as Elysia};
1
+ import{Raikiri as e}from"raikiri";import{mapResponse as t,mapEarlyResponse as r}from"./handler";import{permission as s}from"./fn";import{SCHEMA as a,EXPOSED as n,DEFS as i,mapQuery as o,clone as h,mergeHook as l,mergeDeep as u,createValidationError as d,getSchemaValidator as f,getResponseSchemaValidator as c,mapPathnameAndQueryRegEx as m}from"./utils";import{registerSchemaPath as p}from"./schema";import{mapErrorCode as v,mapErrorStatus as g}from"./error";import{runFn as y}from"./fn";import{deserialize as b}from"superjson";export default class H{store={};meta={[a]:Object.create(null),[i]:Object.create(null),[n]:Object.create(null)};decorators={query:{},set:{status:200,headers:{}},store:this.store,[a]:this.meta[a],[i]:this.meta[i]};event={start:[],request:[],parse:[],transform:[],beforeHandle:[],afterHandle:[],error:[],stop:[]};server=null;$schema=null;router=new e;routes=[];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:l(h(this.event),s)});let n=this.meta[i],o=f(s?.schema?.body??this.$schema?.body,n),u=f(s?.schema?.headers??this.$schema?.headers,n,!0),d=f(s?.schema?.params??this.$schema?.params,n),m=f(s?.schema?.query??this.$schema?.query,n),v=c(s?.schema?.response??this.$schema?.response,n);p({schema:this.meta[a],contentType:s?.schema?.contentType,hook:s,method:e,path:t,models:this.meta[i]});let g=l(h(this.event),s);g.schema||g.transform.length||g.beforeHandle.length||g.error.length||g.afterHandle.length||(g=void 0);let y={handle:r,hooks:g,validator:o||u||d||m||v?{body:o,header:u,params:d,query:m,response:v}:void 0};this.router.add(e,t,y)}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 H;r.store=this.store;let s=t(r);return s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),Object.values(r.routes).forEach(({method:t,path:r,handler:a,hooks:n})=>{"/"===r?this._addHandler(t,e,a,l(n,{error:s.event.error})):this._addHandler(t,`${e}${r}`,a,l(n,{error:s.event.error}))}),this}guard(e,t){let r=new H;r.store=this.store;let s=t(r);return s.event.request.length&&(this.event.request=[...this.event.request,...s.event.request]),Object.values(r.routes).forEach(({method:t,path:r,handler:s,hooks:a})=>{this._addHandler(t,r,s,l(e,a))}),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}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}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}inject(e){return this.onTransform(t=>{Object.assign(t,e(t))})}fn(e){return 0===Object.keys(this.meta[n]).length&&this.post(this.config.fn??"/~fn",e=>y(e,this.meta[n])),this.meta[n]=u(this.meta[n],"function"==typeof e?e({...this.decorators,store:this.store,permission:s}):e),this}schema(e){let t=this.meta[i];return this.$schema={body:f(e.body,t),headers:f(e?.headers,t,!0),params:f(e?.params,t),query:f(e?.query,t),response:f(e?.response,t)},this}handle=async e=>{let s;let a=h(this.decorators);a.request=e;try{let n;if(this.event.request.length)for(let e=0;e<this.event.request.length;e++){let t=this.event.request[e](a);if(t instanceof Promise&&(t=await t),t=r(t,a.set))return t}let i=e.url.match(m);if(!i)throw Error("NOT_FOUND");let h=this.router.match(e.method,i[1])??this.router.match("ALL",i[1]);if(!h)throw Error("NOT_FOUND");let l=h.store,u=l.hooks;if(u?.error&&(s=u?.error),"GET"!==e.method){let t=e.headers.get("content-type");if(t){let r=t.indexOf(";");if(-1!==r&&(t=t.slice(0,r)),this.event.parse.length)for(let e=0;e<this.event.parse.length;e++){let r=this.event.parse[e](a,t);if(r instanceof Promise&&(r=await r),void 0!==r){n=r;break}}if(void 0===n)switch(t){case"application/json":n=await e.json();break;case"text/plain":n=await e.text();break;case"application/x-www-form-urlencoded":n=o(await e.text());break;case"multipart/form-data":n={},await e.formData().then(e=>{for(let t of e.keys()){if(t in n)continue;let r=e.getAll(t);1===r.length?n[t]=r[0]:n[t]=r}});break;case"elysia/fn":n=b(await e.json())}}}if(a.body=n,a.params=h.params,i[2]&&(a.query=o(i[2])),u?.transform.length)for(let e=0;e<u.transform.length;e++){let t=u.transform[e](a);t instanceof Promise&&await t}if(l.validator){let t=l.validator;if(u?.error&&(s=u?.error),t.headers){let r={};for(let t in e.headers)r[t]=e.headers.get(t);if(!1===t.headers.Check(r))throw d("header",t.headers,r)}if(!1===t.params?.Check(a.params))throw d("params",t.params,a.params);if(!1===t.query?.Check(a.query))throw d("query",t.query,a.query);if(!1===t.body?.Check(n))throw d("body",t.body,n)}if(u?.beforeHandle.length)for(let e=0;e<u.beforeHandle.length;e++){let t=u.beforeHandle[e](a);if(t instanceof Promise&&(t=await t),null!=t){for(let e=0;e<u.afterHandle.length;e++){let r=u.afterHandle[e](a,t);r instanceof Promise&&(r=await r),r&&(t=r)}let e=r(t,a.set);if(e)return e}}let f=l.handle(a);if(f instanceof Promise&&(f=await f),!1===l.validator?.response?.Check(f))throw u?.error&&(s=u?.error),d("response",l.validator.response,f);if(u?.afterHandle.length)for(let e=0;e<u.afterHandle.length;e++){let t=u.afterHandle[e](a,f);t instanceof Promise&&(t=await t);let s=r(t,a.set);if(s)return s}return t(f,a.set)}catch(n){let t=a.set;if((!t.status||t.status<300)&&(t.status=500),s){let a=v(n.message);for(let i=0;i<s.length;i++){let o=s[i]({request:e,error:n,set:t,code:a});o instanceof Promise&&(o=await o);let h=r(o,t);if(h)return h}}return this.handleError(e,n,t)}};async handleError(e,r,s={headers:{}}){for(let a=0;a<this.event.error.length;a++){let n=this.event.error[a]({request:e,code:v(r.message),error:r,set:s});if(n instanceof Promise&&(n=await n),null!=n)return t(n,s)}return new Response("string"==typeof r.cause?r.cause:r.message,{headers:s.headers,status:g(v(r.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.handle,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[i]||(this.meta[i][e]=t)}),this}}export{t}from"./custom-types";export{SCHEMA,DEFS,EXPOSED,createValidationError,getSchemaValidator,mergeDeep,mergeHook,mergeObjectArray,mapPathnameAndQueryRegEx,mapQuery}from"./utils";export{H as Elysia,s as permission};
package/dist/schema.d.ts CHANGED
@@ -1,16 +1,18 @@
1
- import { TSchema } from '@sinclair/typebox';
2
- import type { OpenAPIV2 } from 'openapi-types';
1
+ import { type TSchema } from '@sinclair/typebox';
2
+ import type { OpenAPIV3 } from 'openapi-types';
3
3
  import type { HTTPMethod, LocalHook } from './types';
4
4
  export declare const toOpenAPIPath: (path: string) => string;
5
5
  export declare const mapProperties: (name: string, schema: TSchema | string | undefined, models: Record<string, TSchema>) => any[];
6
- export declare const registerSchemaPath: ({ schema, path, method, hook, models }: {
7
- schema: OpenAPIV2.PathsObject;
6
+ export declare const registerSchemaPath: ({ schema, contentType, path, method, hook, models }: {
7
+ schema: Partial<OpenAPIV3.PathsObject>;
8
+ contentType?: string | string[] | undefined;
8
9
  path: string;
9
10
  method: HTTPMethod;
10
11
  hook?: LocalHook<import("./types").TypedSchema<string>, import("./types").ElysiaInstance<{
11
- store: Record<any, any> & Record<typeof import("./utils").SCHEMA, {}> & Record<typeof import("./utils").DEFS, {}>;
12
+ store: Record<any, any>;
12
13
  request: {};
13
14
  schema: {};
14
- }>, string, import("./types").MergeSchema<import("./types").TypedSchema<string>, {}>> | undefined;
15
+ meta: Record<typeof import("./utils").SCHEMA, {}> & Record<typeof import("./utils").DEFS, {}> & Record<typeof import("./utils").EXPOSED, {}>;
16
+ }>, string, import("./types").MergeSchema<import("./types").TypedSchema<string>, {}>, import("./types").TypedSchema<string>> | undefined;
15
17
  models: Record<string, TSchema>;
16
18
  }) => void;
package/dist/schema.js CHANGED
@@ -1 +1 @@
1
- import{Kind as e}from"@sinclair/typebox";export const toOpenAPIPath=e=>e.split("/").map(e=>e.startsWith(":")?`{${e.slice(1,e.length)}}`:e).join("/");export const mapProperties=(e,t,r)=>{if(void 0===t)return[];if("string"==typeof t){if(t in r)t=r[t];else throw Error(`Can't find model ${t}`)}return Object.entries(t?.properties??[]).map(([r,s])=>({...s,in:e,name:r,type:s?.type,required:t.required?.includes(r)??!1}))};export const registerSchemaPath=({schema:t,path:r,method:s,hook:i,models:o})=>{r=toOpenAPIPath(r);let a=i?.schema?.body,n=i?.schema?.params,p=i?.schema?.headers,m=i?.schema?.query,h=i?.schema?.response;if("object"==typeof h){if(e in h){let{type:e,properties:t,required:r,...s}=h;h={200:{...s,schema:{type:e,properties:t,required:r}}}}else Object.entries(h).forEach(([e,t])=>{if("string"==typeof t){let{type:r,properties:s,required:i,...a}=o[t];h[e]={...a,schema:{$ref:`#/definitions/${t}`}}}else{let{type:r,properties:s,required:i,...o}=t;h[e]={...o,schema:{type:r,properties:s,required:i}}}})}else if("string"==typeof h){let{type:e,properties:t,required:r,...s}=o[h];h={200:{...s,schema:{$ref:`#/definitions/${h}`}}}}let c=[...mapProperties("header",p,o),...mapProperties("path",n,o),...mapProperties("query",m,o)];a&&c.push({in:"body",name:"body",required:!0,schema:"string"==typeof a?{$ref:`#/definitions/${a}`}:a}),t[r]={...t[r]?t[r]:{},[s.toLowerCase()]:{...p||n||m||a?{parameters:c}:{},...h?{responses:h}:{},...i?.schema?.detail}}};
1
+ import{Kind as e}from"@sinclair/typebox";export const toOpenAPIPath=e=>e.split("/").map(e=>e.startsWith(":")?`{${e.slice(1,e.length)}}`:e).join("/");export const mapProperties=(e,t,r)=>{if(void 0===t)return[];if("string"==typeof t){if(t in r)t=r[t];else throw Error(`Can't find model ${t}`)}return Object.entries(t?.properties??[]).map(([r,o])=>({...o,in:e,name:r,type:o?.type,required:t.required?.includes(r)??!1}))};let t=(e,t)=>{let r={};for(let o of e)r[o]={schema:"string"==typeof t?{$ref:`#/components/schemas/${t}`}:{...t}};return r};export const registerSchemaPath=({schema:r,contentType:o=["application/json","multipart/form-data","text/plain"],path:s,method:i,hook:n,models:p})=>{s=toOpenAPIPath(s);let a="string"==typeof o?[o]:o??["application/json"],c=n?.schema?.body,l=n?.schema?.params,m=n?.schema?.headers,f=n?.schema?.query,h=n?.schema?.response;if("object"==typeof h){if(e in h){let{type:e,properties:r,required:o,...s}=h;h={200:{...s,description:s.description,content:t(a,"object"===e||"array"===e?{type:e,properties:r,required:o}:h)}}}else Object.entries(h).forEach(([e,r])=>{if("string"==typeof r){let{type:o,properties:s,required:i,...n}=p[r];h[e]={...n,description:n.description,content:t(a,r)}}else{let{type:o,properties:s,required:i,...n}=r;h[e]={...n,description:n.description,content:t(a,{type:o,properties:s,required:i})}}})}else if("string"==typeof h){let{type:e,properties:r,required:o,...s}=p[h];h={200:{...s,content:t(a,h)}}}let d=[...mapProperties("header",m,p),...mapProperties("path",l,p),...mapProperties("query",f,p)];r[s]={...r[s]?r[s]:{},[i.toLowerCase()]:{...m||l||f||c?{parameters:d}:{},...h?{responses:h}:{},...n?.schema?.detail,...c?{requestBody:{content:t(a,"string"==typeof c?{$ref:`#/components/schemas/${c}`}:c)}}:null}}};
package/dist/types.d.ts CHANGED
@@ -4,26 +4,33 @@ import type { Serve, Server } from 'bun';
4
4
  import type { Context, PreContext } from './context';
5
5
  import type { Static, TObject, TSchema } from '@sinclair/typebox';
6
6
  import type { TypeCheck } from '@sinclair/typebox/compiler';
7
- import type { SCHEMA, DEFS } from './utils';
8
- import type { OpenAPIV2 } from 'openapi-types';
7
+ import type { SCHEMA, DEFS, EXPOSED } from './utils';
8
+ import type { OpenAPIV3 } from 'openapi-types';
9
9
  export type WithArray<T> = T | T[];
10
10
  export type ObjectValues<T extends object> = T[keyof T];
11
- export interface ElysiaInstance<Instance extends {
12
- store?: Record<any, any> & Record<typeof SCHEMA, Partial<OpenAPIV2.PathsObject>> & Record<typeof DEFS, {
13
- [x in string]: TSchema;
14
- }>;
11
+ export type ElysiaInstance<Instance extends {
12
+ store?: Record<any, any>;
15
13
  request?: Record<any, any>;
16
14
  schema?: TypedSchema;
15
+ meta?: Record<typeof SCHEMA, Partial<OpenAPIV3.PathsObject>> & Record<typeof DEFS, {
16
+ [x in string]: TSchema;
17
+ }> & Record<typeof EXPOSED, Record<string, Record<string, unknown>>>;
17
18
  } = {
18
- store: Record<any, any> & Record<typeof SCHEMA, {}> & Record<typeof DEFS, {}>;
19
+ store: Record<any, any>;
19
20
  request: {};
20
21
  schema: {};
21
- }> {
22
- request: Instance['request'] extends undefined ? Record<typeof SCHEMA, {}> : Instance['request'];
22
+ meta: Record<typeof SCHEMA, {}> & Record<typeof DEFS, {}> & Record<typeof EXPOSED, {}>;
23
+ }> = {
24
+ request: Instance['request'];
23
25
  store: Instance['store'] extends undefined ? {} : Instance['store'];
24
26
  schema: Instance['schema'] extends undefined ? TypedSchema : Instance['schema'];
25
- }
26
- export type Handler<Route extends TypedRoute = TypedRoute, Instance extends ElysiaInstance = ElysiaInstance, CatchResponse = Route['response']> = (context: Context<Route, Instance['store']> & Instance['request']) => Route['response'] extends (models: Record<string, TSchema>) => TSchema ? undefined extends ReturnType<Route['response']> ? MaybePromise<CatchResponse> | Response : MaybePromise<ReturnType<Route['response']>> | Response : undefined extends Route['response'] ? MaybePromise<CatchResponse> | Response : MaybePromise<Route['response']> | Response;
27
+ meta: Instance['meta'];
28
+ };
29
+ export type Handler<Route extends TypedRoute = TypedRoute, Instance extends ElysiaInstance = ElysiaInstance, CatchResponse = Route['response']> = (context: Context<Route, Instance['store']> & Instance['request'] & {
30
+ a: Instance;
31
+ r: Route;
32
+ merged: MergeSchema<Instance['schema'], Route>;
33
+ }) => Route['response'] extends (models: Record<string, TSchema>) => TSchema ? undefined extends ReturnType<Route['response']> ? MaybePromise<CatchResponse> | Response : MaybePromise<ReturnType<Route['response']>> | Response : undefined extends Route['response'] ? MaybePromise<CatchResponse> | Response : MaybePromise<Route['response']> | Response;
27
34
  export type NoReturnHandler<Route extends TypedRoute = TypedRoute, Instance extends ElysiaInstance = ElysiaInstance> = (context: Context<Route, Instance['store']> & Instance['request']) => void | Promise<void>;
28
35
  export type LifeCycleEvent = 'start' | 'request' | 'parse' | 'transform' | 'beforeHandle' | 'afterHandle' | 'error' | 'stop';
29
36
  export type ListenCallback = ((server: Server) => void) | ((server: Server) => Promise<void>);
@@ -65,17 +72,17 @@ export interface TypedSchema<ModelName extends string = string> {
65
72
  params?: TObject | ModelName;
66
73
  response?: TSchema | Record<string | '200', TSchema> | ModelName | Record<string, ModelName | TSchema>;
67
74
  }
68
- export type UnwrapSchema<Schema extends TSchema | undefined | string, Instance extends ElysiaInstance = ElysiaInstance, Fallback = unknown> = Schema extends string ? Instance['store'][typeof DEFS] extends {
75
+ export type UnwrapSchema<Schema extends TSchema | undefined | string, Definitions extends ElysiaInstance['meta'][typeof DEFS] = {}, Fallback = unknown> = Schema extends string ? Definitions extends {
69
76
  [name in Schema]: infer NamedSchema extends TSchema;
70
77
  } ? Static<NamedSchema> : Fallback : Schema extends TSchema ? Static<NonNullable<Schema>> : Fallback;
71
- export type TypedSchemaToRoute<Schema extends TypedSchema, Instance extends ElysiaInstance> = {
72
- body: UnwrapSchema<Schema['body'], Instance>;
73
- headers: UnwrapSchema<Schema['headers'], Instance> extends infer Result extends Record<string, any> ? Result : undefined;
74
- query: UnwrapSchema<Schema['query'], Instance> extends infer Result extends Record<string, any> ? Result : undefined;
75
- params: UnwrapSchema<Schema['params'], Instance> extends infer Result extends Record<string, any> ? Result : undefined;
76
- response: Schema['response'] extends TSchema | string ? UnwrapSchema<Schema['response'], Instance> : Schema['response'] extends {
78
+ export type TypedSchemaToRoute<Schema extends TypedSchema<any>, Definitions extends ElysiaInstance['meta'][typeof DEFS]> = {
79
+ body: UnwrapSchema<Schema['body'], Definitions>;
80
+ headers: UnwrapSchema<Schema['headers'], Definitions> extends infer Result extends Record<string, any> ? Result : undefined;
81
+ query: UnwrapSchema<Schema['query'], Definitions> extends infer Result extends Record<string, any> ? Result : undefined;
82
+ params: UnwrapSchema<Schema['params'], Definitions> extends infer Result extends Record<string, any> ? Result : undefined;
83
+ response: Schema['response'] extends TSchema | string ? UnwrapSchema<Schema['response'], Definitions> : Schema['response'] extends {
77
84
  [k in string]: TSchema | string;
78
- } ? UnwrapSchema<ObjectValues<Schema['response']>, Instance> : unknown;
85
+ } ? UnwrapSchema<ObjectValues<Schema['response']>, Definitions> : unknown;
79
86
  };
80
87
  export type AnyTypedSchema = {
81
88
  body: unknown;
@@ -91,7 +98,7 @@ export type SchemaValidator = {
91
98
  params?: TypeCheck<any>;
92
99
  response?: TypeCheck<any>;
93
100
  };
94
- export type HookHandler<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance = ElysiaInstance, Path extends string = string, Typed extends AnyTypedSchema = TypedSchemaToRoute<Schema, Instance>> = Handler<Typed['params'] extends {} ? Omit<Typed, 'response'> & {
101
+ export type HookHandler<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance = ElysiaInstance, Path extends string = string, Typed extends AnyTypedSchema = TypedSchemaToRoute<Schema, Instance['meta'][typeof DEFS]>> = Handler<Typed['params'] extends {} ? Omit<Typed, 'response'> & {
95
102
  response: void | Typed['response'];
96
103
  } : Omit<Omit<Typed, 'response'> & {
97
104
  response: void | Typed['response'];
@@ -101,62 +108,65 @@ export type HookHandler<Schema extends TypedSchema = TypedSchema, Instance exten
101
108
  export type MergeIfNotNull<A, B> = B extends null ? A : A & B;
102
109
  export type UnknownFallback<A, B> = unknown extends A ? B : A;
103
110
  export type PickInOrder<A, B> = A extends NonNullable<A> ? A : B;
104
- export type MergeSchema<A extends TypedSchema, B extends TypedSchema> = {
111
+ export type MergeSchema<A extends TypedSchema<any>, B extends TypedSchema<any>> = {
105
112
  body: PickInOrder<PickInOrder<A['body'], B['body']>, undefined>;
106
113
  headers: PickInOrder<PickInOrder<A['headers'], B['headers']>, undefined>;
107
114
  query: PickInOrder<PickInOrder<A['query'], B['query']>, undefined>;
108
115
  params: PickInOrder<PickInOrder<A['params'], B['params']>, undefined>;
109
116
  response: PickInOrder<PickInOrder<A['response'], B['response']>, undefined>;
110
117
  };
111
- export interface LocalHook<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance<any> = ElysiaInstance, Path extends string = string, FinalSchema extends MergeSchema<Schema, Instance['schema']> = MergeSchema<Schema, Instance['schema']>> {
112
- schema?: Schema & {
113
- detail?: Partial<OpenAPIV2.OperationObject>;
118
+ type MaybeArray<T> = T | T[];
119
+ type ExtractModelName<Type> = Type extends TypedSchema<infer X> ? X : never;
120
+ type ContentType = MaybeArray<(string & {}) | 'text/plain' | 'application/json' | 'multipart/form-data' | 'application/x-www-form-urlencoded'>;
121
+ export interface LocalHook<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance<any> = ElysiaInstance, Path extends string = string, FinalSchema extends MergeSchema<Schema, Instance['schema']> = MergeSchema<Schema, Instance['schema']>, Models extends TypedSchema = TypedSchema<ExtractModelName<Schema>>> {
122
+ schema?: (Models extends Schema ? Models : Models) & {
123
+ contentType?: ContentType;
124
+ detail?: Partial<OpenAPIV3.OperationObject>;
114
125
  };
115
126
  transform?: WithArray<HookHandler<FinalSchema, Instance, Path>>;
116
127
  beforeHandle?: WithArray<HookHandler<FinalSchema, Instance, Path>>;
117
128
  afterHandle?: WithArray<AfterRequestHandler<any, Instance>>;
118
129
  error?: WithArray<ErrorHandler>;
119
130
  }
120
- export type RouteToSchema<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance<any> = ElysiaInstance, Path extends string = string, FinalSchema extends MergeSchema<Schema, Instance['schema']> = MergeSchema<Schema, Instance['schema']>> = FinalSchema['params'] extends NonNullable<Schema['params']> ? TypedSchemaToRoute<FinalSchema, Instance> : Omit<TypedSchemaToRoute<FinalSchema, Instance>, 'params'> & {
131
+ export type RouteToSchema<Schema extends TypedSchema, InstanceSchema extends ElysiaInstance['schema'], Definitions extends ElysiaInstance['meta'][typeof DEFS], Path extends string = string, FinalSchema extends MergeSchema<Schema, InstanceSchema> = MergeSchema<Schema, InstanceSchema>> = FinalSchema['params'] extends NonNullable<Schema['params']> ? TypedSchemaToRoute<FinalSchema, Definitions> : Omit<TypedSchemaToRoute<FinalSchema, Definitions>, 'params'> & {
121
132
  params: Record<ExtractPath<Path>, string>;
122
133
  };
123
134
  export type ElysiaRoute<Method extends string = string, Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance = ElysiaInstance, Path extends string = string, CatchResponse = unknown> = Elysia<{
124
135
  request: Instance['request'];
125
- store: Instance['store'] & {
126
- [SCHEMA]: {
127
- [path in Path]: {
128
- [method in Method]: TypedRouteToEden<Schema, Instance, Path> extends infer FinalSchema extends AnyTypedSchema ? Omit<FinalSchema, 'response'> & {
129
- response: undefined extends FinalSchema['response'] ? {
130
- '200': CatchResponse;
131
- } : FinalSchema['response'];
132
- } : never;
133
- };
134
- };
135
- };
136
+ store: Instance['store'];
136
137
  schema: Instance['schema'];
138
+ meta: Instance['meta'] & Record<typeof SCHEMA, {
139
+ [path in Path]: {
140
+ [method in Method]: TypedRouteToEden<Schema, Instance['schema'], Path> extends infer FinalSchema extends AnyTypedSchema ? Omit<FinalSchema, 'response'> & {
141
+ response: undefined extends FinalSchema['response'] ? {
142
+ '200': CatchResponse;
143
+ } : FinalSchema['response'];
144
+ } : never;
145
+ };
146
+ }>;
137
147
  }>;
138
- export type TypedRouteToEden<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance<any> = ElysiaInstance, Path extends string = string, FinalSchema extends MergeSchema<Schema, Instance['schema']> = MergeSchema<Schema, Instance['schema']>> = FinalSchema['params'] extends NonNullable<Schema['params']> ? TypedSchemaToEden<FinalSchema, Instance> : Omit<TypedSchemaToEden<FinalSchema, Instance>, 'params'> & {
148
+ export type TypedRouteToEden<Schema extends TypedSchema = TypedSchema, InstanceSchema extends TypedSchema<string> = ElysiaInstance['schema'], Path extends string = string, FinalSchema extends MergeSchema<Schema, InstanceSchema> = MergeSchema<Schema, InstanceSchema>> = FinalSchema['params'] extends NonNullable<Schema['params']> ? TypedSchemaToEden<FinalSchema, InstanceSchema> : Omit<TypedSchemaToEden<FinalSchema, InstanceSchema>, 'params'> & {
139
149
  params: Record<ExtractPath<Path>, string>;
140
150
  };
141
- export type TypedSchemaToEden<Schema extends TypedSchema, Instance extends ElysiaInstance> = {
142
- body: UnwrapSchema<Schema['body'], Instance>;
143
- headers: UnwrapSchema<Schema['headers'], Instance> extends infer Result extends Record<string, any> ? Result : undefined;
144
- query: UnwrapSchema<Schema['query'], Instance> extends infer Result extends Record<string, any> ? Result : undefined;
145
- params: UnwrapSchema<Schema['params'], Instance> extends infer Result extends Record<string, any> ? Result : undefined;
151
+ export type TypedSchemaToEden<Schema extends TypedSchema, Definitions extends ElysiaInstance['meta'][typeof DEFS]> = {
152
+ body: UnwrapSchema<Schema['body'], Definitions>;
153
+ headers: UnwrapSchema<Schema['headers'], Definitions> extends infer Result extends Record<string, any> ? Result : undefined;
154
+ query: UnwrapSchema<Schema['query'], Definitions> extends infer Result extends Record<string, any> ? Result : undefined;
155
+ params: UnwrapSchema<Schema['params'], Definitions> extends infer Result extends Record<string, any> ? Result : undefined;
146
156
  response: Schema['response'] extends TSchema | string ? {
147
- '200': UnwrapSchema<Schema['response'], Instance>;
157
+ '200': UnwrapSchema<Schema['response'], Definitions>;
148
158
  } : Schema['response'] extends {
149
159
  [x in string]: TSchema | string;
150
160
  } ? {
151
- [key in keyof Schema['response']]: UnwrapSchema<Schema['response'][key], Instance>;
161
+ [key in keyof Schema['response']]: UnwrapSchema<Schema['response'][key], Definitions>;
152
162
  } : unknown;
153
163
  };
154
- export type LocalHandler<Schema extends TypedSchema = TypedSchema, Instance extends ElysiaInstance = ElysiaInstance, Path extends string = string, CatchResponse = unknown> = Handler<RouteToSchema<Schema, Instance, Path>, Instance, CatchResponse>;
164
+ export type LocalHandler<Schema extends TypedSchema, Instance extends ElysiaInstance, Path extends string = string, CatchResponse = unknown> = Handler<RouteToSchema<Schema, Instance['schema'], Instance['meta'][typeof DEFS], Path>, Instance, CatchResponse>;
155
165
  export interface TypedRoute {
156
166
  body?: unknown;
157
- headers?: Record<string, any>;
158
- query?: Record<string, string>;
159
- params?: Record<string, string>;
167
+ headers?: Record<string, unknown>;
168
+ query?: Record<string, unknown>;
169
+ params?: Record<string, unknown>;
160
170
  response?: unknown;
161
171
  }
162
172
  export type OverwritableTypeRoute = {
@@ -172,6 +182,7 @@ export type ComposedHandler = {
172
182
  validator?: SchemaValidator;
173
183
  };
174
184
  export interface ElysiaConfig {
185
+ fn?: string;
175
186
  serve?: Partial<Serve>;
176
187
  }
177
188
  export type IsPathParameter<Part> = Part extends `:${infer Parameter}` ? Parameter : never;
@@ -219,4 +230,14 @@ export type DeepMergeTwoTypes<T, U> = [
219
230
  export type IsAny<T> = unknown extends T ? [keyof T] extends [never] ? false : true : false;
220
231
  export type MaybePromise<T> = T | Promise<T>;
221
232
  export type IsNever<T> = [T] extends [never] ? true : false;
233
+ export type FunctionProperties<T> = {
234
+ [K in keyof T as T[K] extends Record<any, any> | ((...args: any[]) => any) ? IsAny<T[K]> extends true ? never : K : never]: T[K] extends (...args: any[]) => any ? T[K] : T[K] extends Record<string, any> ? FunctionProperties<T[K]> : never;
235
+ };
236
+ export type JoinKeys<T, Prefix extends string = ''> = {
237
+ [K in keyof T]-?: T[K] extends string | Function ? '' extends Prefix ? K : K extends string ? `${Prefix}.${K}` : never : K extends string ? JoinKeys<T[K], '' extends Prefix ? K : `${Prefix}.${K}`> : never;
238
+ }[keyof T];
239
+ export type ConnectedKeysType<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? ConnectedKeysType<T[Key], Rest> : never : K extends keyof T ? T[K] extends (...args: infer A) => any ? A : never : never;
240
+ export type Prettify<T> = {
241
+ [K in keyof T]: T[K];
242
+ } & {};
222
243
  export {};
package/dist/utils.d.ts CHANGED
@@ -3,6 +3,7 @@ import { TypeCheck } from '@sinclair/typebox/compiler';
3
3
  import type { DeepMergeTwoTypes, LifeCycleStore, LocalHook, TypedSchema, RegisteredHook } from './types';
4
4
  export declare const SCHEMA: unique symbol;
5
5
  export declare const DEFS: unique symbol;
6
+ export declare const EXPOSED: unique symbol;
6
7
  export declare const mergeObjectArray: <T>(a: T | T[], b: T | T[]) => T[];
7
8
  export declare const mergeHook: (a: LocalHook<any> | LifeCycleStore<any>, b: LocalHook<any>) => RegisteredHook<any>;
8
9
  export declare const clone: <T extends Object | any[] = Object | any[]>(value: T) => T;