@kaito-http/core 2.1.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  export declare class WrappedError<T> extends Error {
2
2
  readonly data: T;
3
- static from<T>(maybeError: T): (T & Error) | WrappedError<T>;
4
- constructor(data: T);
3
+ static maybe<T>(maybeError: T): (T & Error) | WrappedError<T>;
4
+ static from<T>(data: T): WrappedError<T>;
5
+ private constructor();
5
6
  }
@@ -3,7 +3,7 @@ import http from 'http';
3
3
  import { z, ZodTypeAny } from 'zod';
4
4
  import { KaitoRequest } from './req';
5
5
  import { KaitoResponse } from './res';
6
- import { Method } from './util';
6
+ import { Method, NormalizePath } from './util';
7
7
  export declare type GetContext<T> = (req: KaitoRequest, res: KaitoResponse) => Promise<T>;
8
8
  declare type Never = [never];
9
9
  export declare function createGetContext<T>(getContext: GetContext<T>): GetContext<T>;
@@ -13,135 +13,41 @@ export declare type ContextWithInput<Ctx, Input> = {
13
13
  input: Input;
14
14
  };
15
15
  declare type Values<T> = T[keyof T];
16
- declare type Proc<Ctx, Result, Input extends z.ZodTypeAny | Never = Never> = Readonly<{
16
+ export declare type Proc<Ctx, Result, Input extends z.ZodTypeAny | Never = Never> = {
17
17
  input?: Input;
18
18
  run(arg: ContextWithInput<Ctx, Input extends ZodTypeAny ? z.infer<Input> : undefined>): Promise<Result>;
19
- }>;
20
- declare type ProcsInit<Ctx> = {
21
- [Key in string]: Proc<Ctx, unknown, z.ZodTypeAny> & {
22
- method: Method;
23
- name: Key;
24
- };
25
19
  };
26
- declare type AnyRouter<Ctx> = Router<Ctx, ProcsInit<Ctx>>;
27
- export declare class Router<Ctx, Procs extends ProcsInit<Ctx>> {
20
+ export interface RouterProc<Path extends string, M extends Method> {
21
+ method: M;
22
+ path: Path;
23
+ pattern: RegExp;
24
+ }
25
+ export declare type AnyProcs<Ctx> = {
26
+ [Path in string]: Proc<Ctx, unknown, z.ZodTypeAny> & RouterProc<Path, Method>;
27
+ };
28
+ export declare type AnyRouter<Ctx> = Router<Ctx, AnyProcs<Ctx>>;
29
+ export declare class Router<Ctx, Procs extends AnyProcs<Ctx>> {
28
30
  private readonly procs;
31
+ private readonly _procsArray;
32
+ private static patternize;
29
33
  constructor(procs: Procs);
30
34
  getProcs(): Procs;
35
+ find(method: Method, url: string): (Proc<Ctx, unknown, z.ZodTypeAny> & RouterProc<string, Method>) | null;
31
36
  private readonly create;
32
- readonly merge: <Prefix extends string, NewCtx, NewProcs extends ProcsInit<NewCtx>>(prefix: Prefix, router: Router<NewCtx, NewProcs>) => Router<NewCtx & Ctx, Procs & { [Key in `${Prefix}${Extract<keyof NewProcs, string>}`]: Omit<NewProcs[Key extends `${Prefix}${infer Rest}` ? Rest : never], "name"> & {
33
- name: Key;
37
+ readonly merge: <Prefix extends string, NewCtx, NewProcs extends AnyProcs<NewCtx>>(_prefix: (Prefix extends `${infer U}/` ? U : Prefix) extends `/${infer U_1}` ? `/${U_1}` : `/${Prefix extends `${infer U}/` ? U : Prefix}`, router: Router<NewCtx, NewProcs>) => Router<NewCtx & Ctx, Procs & { [P in (`${Prefix}${Extract<keyof NewProcs, string>}` extends `${infer U}/` ? U : `${Prefix}${Extract<keyof NewProcs, string>}`) extends `/${infer U_1}` ? `/${U_1}` : `/${`${Prefix}${Extract<keyof NewProcs, string>}` extends `${infer U}/` ? U : `${Prefix}${Extract<keyof NewProcs, string>}`}`]: Omit<NewProcs[P extends ((`${Prefix}${infer Rest}` extends `${infer U}/` ? U : `${Prefix}${infer Rest}`) extends `/${infer U_1}` ? `/${U_1}` : `/${`${Prefix}${infer Rest}` extends `${infer U}/` ? U : `${Prefix}${infer Rest}`}`) ? Rest : never], "path"> & {
38
+ path: P;
34
39
  }; }>;
35
- readonly get: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
36
- input?: Input | undefined;
37
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
38
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
39
- input?: Input | undefined;
40
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
41
- }> & {
42
- method: "GET";
43
- name: Name;
44
- }>>;
45
- readonly post: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
46
- input?: Input | undefined;
47
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
48
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
49
- input?: Input | undefined;
50
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
51
- }> & {
52
- method: "POST";
53
- name: Name;
54
- }>>;
55
- readonly put: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
56
- input?: Input | undefined;
57
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
58
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
59
- input?: Input | undefined;
60
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
61
- }> & {
62
- method: "PUT";
63
- name: Name;
64
- }>>;
65
- readonly patch: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
66
- input?: Input | undefined;
67
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
68
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
69
- input?: Input | undefined;
70
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
71
- }> & {
72
- method: "PATCH";
73
- name: Name;
74
- }>>;
75
- readonly delete: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
76
- input?: Input | undefined;
77
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
78
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
79
- input?: Input | undefined;
80
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
81
- }> & {
82
- method: "DELETE";
83
- name: Name;
84
- }>>;
85
- readonly head: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
86
- input?: Input | undefined;
87
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
88
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
89
- input?: Input | undefined;
90
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
91
- }> & {
92
- method: "HEAD";
93
- name: Name;
94
- }>>;
95
- readonly options: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
96
- input?: Input | undefined;
97
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
98
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
99
- input?: Input | undefined;
100
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
101
- }> & {
102
- method: "OPTIONS";
103
- name: Name;
104
- }>>;
105
- readonly connect: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
106
- input?: Input | undefined;
107
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
108
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
109
- input?: Input | undefined;
110
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
111
- }> & {
112
- method: "CONNECT";
113
- name: Name;
114
- }>>;
115
- readonly trace: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
116
- input?: Input | undefined;
117
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
118
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
119
- input?: Input | undefined;
120
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
121
- }> & {
122
- method: "TRACE";
123
- name: Name;
124
- }>>;
125
- readonly acl: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
126
- input?: Input | undefined;
127
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
128
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
129
- input?: Input | undefined;
130
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
131
- }> & {
132
- method: "ACL";
133
- name: Name;
134
- }>>;
135
- readonly bind: <Name extends string, Result, Input extends z.ZodTypeAny>(name: Name, proc: Readonly<{
136
- input?: Input | undefined;
137
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
138
- }>) => Router<Ctx, Procs & Record<Name, Readonly<{
139
- input?: Input | undefined;
140
- run(arg: ContextWithInput<Ctx, Input extends z.ZodTypeAny ? z.TypeOf<Input> : undefined>): Promise<Result>;
141
- }> & {
142
- method: "BIND";
143
- name: Name;
144
- }>>;
40
+ readonly get: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "GET">>>;
41
+ readonly post: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "POST">>>;
42
+ readonly put: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "PUT">>>;
43
+ readonly patch: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "PATCH">>>;
44
+ readonly delete: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "DELETE">>>;
45
+ readonly head: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "HEAD">>>;
46
+ readonly options: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "OPTIONS">>>;
47
+ readonly connect: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "CONNECT">>>;
48
+ readonly trace: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "TRACE">>>;
49
+ readonly acl: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "ACL">>>;
50
+ readonly bind: <Path extends string, Result, Input extends z.ZodTypeAny>(path: (Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, proc: Proc<Ctx, Result, Input>) => Router<Ctx, Procs & Record<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, Proc<Ctx, Result, Input> & RouterProc<(Path extends `${infer U}/` ? U : Path) extends `/${infer U_1}` ? `/${U_1}` : `/${Path extends `${infer U}/` ? U : Path}`, "BIND">>>;
145
51
  }
146
52
  export declare class KaitoError extends Error {
147
53
  readonly status: number;
@@ -151,8 +57,8 @@ export declare class KaitoError extends Error {
151
57
  export declare function createRouter<Ctx>(): Router<Ctx, {}>;
152
58
  export declare type InferAPIResponseType<R extends AnyRouter<unknown>, M extends Method, Path extends Extract<Values<ReturnType<R['getProcs']>>, {
153
59
  method: M;
154
- }>['name']> = ReturnType<ReturnType<R['getProcs']>[Path]['run']> extends Promise<infer V> ? V : never;
155
- export declare function createServer<Ctx, R extends Router<Ctx, ProcsInit<Ctx>>>(config: {
60
+ }>['path']> = ReturnType<ReturnType<R['getProcs']>[Path]['run']> extends Promise<infer V> ? V : never;
61
+ export declare function createServer<Ctx, R extends Router<Ctx, AnyProcs<Ctx>>>(config: {
156
62
  getContext: GetContext<Ctx>;
157
63
  router: R;
158
64
  onError(error: {
@@ -1,4 +1,9 @@
1
1
  import { KaitoRequest } from './req';
2
2
  export declare function getLastEntryInMultiHeaderValue(headerValue: string | string[]): string;
3
+ declare type RemoveEndSlashes<T extends string> = T extends `${infer U}/` ? U : T;
4
+ declare type AddStartSlashes<T extends string> = T extends `/${infer U}` ? `/${U}` : `/${T}`;
5
+ export declare type NormalizePath<T extends string> = AddStartSlashes<RemoveEndSlashes<T>>;
6
+ export declare function normalizePath<T extends string>(path: T): NormalizePath<T>;
3
7
  export declare type Method = 'ACL' | 'BIND' | 'CHECKOUT' | 'CONNECT' | 'COPY' | 'DELETE' | 'GET' | 'HEAD' | 'LINK' | 'LOCK' | 'M-SEARCH' | 'MERGE' | 'MKACTIVITY' | 'MKCALENDAR' | 'MKCOL' | 'MOVE' | 'NOTIFY' | 'OPTIONS' | 'PATCH' | 'POST' | 'PRI' | 'PROPFIND' | 'PROPPATCH' | 'PURGE' | 'PUT' | 'REBIND' | 'REPORT' | 'SEARCH' | 'SOURCE' | 'SUBSCRIBE' | 'TRACE' | 'UNBIND' | 'UNLINK' | 'UNLOCK' | 'UNSUBSCRIBE';
4
8
  export declare function getInput(req: KaitoRequest): Promise<unknown>;
9
+ export {};
@@ -101,12 +101,16 @@ function _objectSpread2(target) {
101
101
  }
102
102
 
103
103
  class WrappedError extends Error {
104
- static from(maybeError) {
104
+ static maybe(maybeError) {
105
105
  if (maybeError instanceof Error) {
106
106
  return maybeError;
107
107
  }
108
108
 
109
- return new WrappedError(maybeError);
109
+ return WrappedError.from(maybeError);
110
+ }
111
+
112
+ static from(data) {
113
+ return new WrappedError(data);
110
114
  }
111
115
 
112
116
  constructor(data) {
@@ -120,6 +124,19 @@ function getLastEntryInMultiHeaderValue(headerValue) {
120
124
  var normalized = Array.isArray(headerValue) ? headerValue.join(',') : headerValue;
121
125
  var lastIndex = normalized.lastIndexOf(',');
122
126
  return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
127
+ }
128
+ function normalizePath(path) {
129
+ var result = path;
130
+
131
+ if (!result.startsWith('/')) {
132
+ result = "/".concat(result);
133
+ }
134
+
135
+ if (result.endsWith('/')) {
136
+ result = result.slice(-1);
137
+ }
138
+
139
+ return result;
123
140
  } // Type for import('http').METHODS
124
141
 
125
142
  function getInput(_x) {
@@ -227,22 +244,35 @@ function createGetContext(getContext) {
227
244
  return getContext;
228
245
  }
229
246
  class Router {
247
+ static patternize(path) {
248
+ var normalized = normalizePath(path);
249
+ return new RegExp("^".concat(normalized, "/?$"), 'i');
250
+ }
251
+
230
252
  constructor(procs) {
231
- _defineProperty(this, "create", method => (name, proc) => {
232
- return new Router(_objectSpread2(_objectSpread2({}, this.procs), {}, {
233
- [name]: _objectSpread2(_objectSpread2({}, proc), {}, {
253
+ _defineProperty(this, "create", method => (path, proc) => {
254
+ var pattern = Router.patternize(path);
255
+
256
+ var merged = _objectSpread2(_objectSpread2({}, this.procs), {}, {
257
+ [path]: _objectSpread2(_objectSpread2({}, proc), {}, {
234
258
  method,
235
- name
259
+ path,
260
+ pattern
236
261
  })
237
- }));
262
+ });
263
+
264
+ return new Router(merged);
238
265
  });
239
266
 
240
- _defineProperty(this, "merge", (prefix, router) => {
267
+ _defineProperty(this, "merge", (_prefix, router) => {
268
+ var prefix = normalizePath(_prefix);
241
269
  var newProcs = Object.entries(router.getProcs()).reduce((all, entry) => {
242
- var [name, proc] = entry;
270
+ var [path, proc] = entry;
271
+ var newPath = "".concat(prefix).concat(normalizePath(path));
243
272
  return _objectSpread2(_objectSpread2({}, all), {}, {
244
- ["".concat(prefix).concat(name)]: _objectSpread2(_objectSpread2({}, proc), {}, {
245
- name: "".concat(prefix).concat(name)
273
+ ["".concat(prefix).concat(path)]: _objectSpread2(_objectSpread2({}, proc), {}, {
274
+ path: newPath,
275
+ pattern: Router.patternize(newPath)
246
276
  })
247
277
  });
248
278
  }, {});
@@ -275,12 +305,27 @@ class Router {
275
305
  _defineProperty(this, "bind", this.create('BIND'));
276
306
 
277
307
  this.procs = procs;
308
+ this._procsArray = Object.values(procs);
278
309
  }
279
310
 
280
311
  getProcs() {
281
312
  return this.procs;
282
313
  }
283
314
 
315
+ find(method, url) {
316
+ for (var proc of this._procsArray) {
317
+ if (proc.method !== method) {
318
+ continue;
319
+ }
320
+
321
+ if (proc.pattern.test(url)) {
322
+ return proc;
323
+ }
324
+ }
325
+
326
+ return null;
327
+ }
328
+
284
329
  }
285
330
  class KaitoError extends Error {
286
331
  constructor(status, message, cause) {
@@ -302,8 +347,7 @@ function createServer(config) {
302
347
  }
303
348
  };
304
349
 
305
- var tree = config.router.getProcs();
306
- var server = http__default["default"].createServer( /*#__PURE__*/function () {
350
+ return http__default["default"].createServer( /*#__PURE__*/function () {
307
351
  var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse) {
308
352
  var start = Date.now();
309
353
  var req = new KaitoRequest(incomingMessage);
@@ -312,7 +356,7 @@ function createServer(config) {
312
356
  try {
313
357
  var _handler$input, _yield$getInput;
314
358
 
315
- var handler = tree[req.url.pathname];
359
+ var handler = config.router.find(req.method, req.url.pathname);
316
360
 
317
361
  if (!handler) {
318
362
  throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
@@ -343,7 +387,7 @@ function createServer(config) {
343
387
  status: _status,
344
388
  message: _message
345
389
  } = yield config.onError({
346
- error: WrappedError.from(error),
390
+ error: WrappedError.maybe(error),
347
391
  req,
348
392
  res
349
393
  }).catch(() => ({
@@ -365,7 +409,6 @@ function createServer(config) {
365
409
  return _ref.apply(this, arguments);
366
410
  };
367
411
  }());
368
- return server;
369
412
  }
370
413
 
371
414
  exports.KaitoError = KaitoError;
@@ -101,12 +101,16 @@ function _objectSpread2(target) {
101
101
  }
102
102
 
103
103
  class WrappedError extends Error {
104
- static from(maybeError) {
104
+ static maybe(maybeError) {
105
105
  if (maybeError instanceof Error) {
106
106
  return maybeError;
107
107
  }
108
108
 
109
- return new WrappedError(maybeError);
109
+ return WrappedError.from(maybeError);
110
+ }
111
+
112
+ static from(data) {
113
+ return new WrappedError(data);
110
114
  }
111
115
 
112
116
  constructor(data) {
@@ -120,6 +124,19 @@ function getLastEntryInMultiHeaderValue(headerValue) {
120
124
  var normalized = Array.isArray(headerValue) ? headerValue.join(',') : headerValue;
121
125
  var lastIndex = normalized.lastIndexOf(',');
122
126
  return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
127
+ }
128
+ function normalizePath(path) {
129
+ var result = path;
130
+
131
+ if (!result.startsWith('/')) {
132
+ result = "/".concat(result);
133
+ }
134
+
135
+ if (result.endsWith('/')) {
136
+ result = result.slice(-1);
137
+ }
138
+
139
+ return result;
123
140
  } // Type for import('http').METHODS
124
141
 
125
142
  function getInput(_x) {
@@ -227,22 +244,35 @@ function createGetContext(getContext) {
227
244
  return getContext;
228
245
  }
229
246
  class Router {
247
+ static patternize(path) {
248
+ var normalized = normalizePath(path);
249
+ return new RegExp("^".concat(normalized, "/?$"), 'i');
250
+ }
251
+
230
252
  constructor(procs) {
231
- _defineProperty(this, "create", method => (name, proc) => {
232
- return new Router(_objectSpread2(_objectSpread2({}, this.procs), {}, {
233
- [name]: _objectSpread2(_objectSpread2({}, proc), {}, {
253
+ _defineProperty(this, "create", method => (path, proc) => {
254
+ var pattern = Router.patternize(path);
255
+
256
+ var merged = _objectSpread2(_objectSpread2({}, this.procs), {}, {
257
+ [path]: _objectSpread2(_objectSpread2({}, proc), {}, {
234
258
  method,
235
- name
259
+ path,
260
+ pattern
236
261
  })
237
- }));
262
+ });
263
+
264
+ return new Router(merged);
238
265
  });
239
266
 
240
- _defineProperty(this, "merge", (prefix, router) => {
267
+ _defineProperty(this, "merge", (_prefix, router) => {
268
+ var prefix = normalizePath(_prefix);
241
269
  var newProcs = Object.entries(router.getProcs()).reduce((all, entry) => {
242
- var [name, proc] = entry;
270
+ var [path, proc] = entry;
271
+ var newPath = "".concat(prefix).concat(normalizePath(path));
243
272
  return _objectSpread2(_objectSpread2({}, all), {}, {
244
- ["".concat(prefix).concat(name)]: _objectSpread2(_objectSpread2({}, proc), {}, {
245
- name: "".concat(prefix).concat(name)
273
+ ["".concat(prefix).concat(path)]: _objectSpread2(_objectSpread2({}, proc), {}, {
274
+ path: newPath,
275
+ pattern: Router.patternize(newPath)
246
276
  })
247
277
  });
248
278
  }, {});
@@ -275,12 +305,27 @@ class Router {
275
305
  _defineProperty(this, "bind", this.create('BIND'));
276
306
 
277
307
  this.procs = procs;
308
+ this._procsArray = Object.values(procs);
278
309
  }
279
310
 
280
311
  getProcs() {
281
312
  return this.procs;
282
313
  }
283
314
 
315
+ find(method, url) {
316
+ for (var proc of this._procsArray) {
317
+ if (proc.method !== method) {
318
+ continue;
319
+ }
320
+
321
+ if (proc.pattern.test(url)) {
322
+ return proc;
323
+ }
324
+ }
325
+
326
+ return null;
327
+ }
328
+
284
329
  }
285
330
  class KaitoError extends Error {
286
331
  constructor(status, message, cause) {
@@ -302,8 +347,7 @@ function createServer(config) {
302
347
  }
303
348
  };
304
349
 
305
- var tree = config.router.getProcs();
306
- var server = http__default["default"].createServer( /*#__PURE__*/function () {
350
+ return http__default["default"].createServer( /*#__PURE__*/function () {
307
351
  var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse) {
308
352
  var start = Date.now();
309
353
  var req = new KaitoRequest(incomingMessage);
@@ -312,7 +356,7 @@ function createServer(config) {
312
356
  try {
313
357
  var _handler$input, _yield$getInput;
314
358
 
315
- var handler = tree[req.url.pathname];
359
+ var handler = config.router.find(req.method, req.url.pathname);
316
360
 
317
361
  if (!handler) {
318
362
  throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
@@ -343,7 +387,7 @@ function createServer(config) {
343
387
  status: _status,
344
388
  message: _message
345
389
  } = yield config.onError({
346
- error: WrappedError.from(error),
390
+ error: WrappedError.maybe(error),
347
391
  req,
348
392
  res
349
393
  }).catch(() => ({
@@ -365,7 +409,6 @@ function createServer(config) {
365
409
  return _ref.apply(this, arguments);
366
410
  };
367
411
  }());
368
- return server;
369
412
  }
370
413
 
371
414
  exports.KaitoError = KaitoError;
@@ -92,12 +92,16 @@ function _objectSpread2(target) {
92
92
  }
93
93
 
94
94
  class WrappedError extends Error {
95
- static from(maybeError) {
95
+ static maybe(maybeError) {
96
96
  if (maybeError instanceof Error) {
97
97
  return maybeError;
98
98
  }
99
99
 
100
- return new WrappedError(maybeError);
100
+ return WrappedError.from(maybeError);
101
+ }
102
+
103
+ static from(data) {
104
+ return new WrappedError(data);
101
105
  }
102
106
 
103
107
  constructor(data) {
@@ -111,6 +115,19 @@ function getLastEntryInMultiHeaderValue(headerValue) {
111
115
  var normalized = Array.isArray(headerValue) ? headerValue.join(',') : headerValue;
112
116
  var lastIndex = normalized.lastIndexOf(',');
113
117
  return lastIndex === -1 ? normalized.trim() : normalized.slice(lastIndex + 1).trim();
118
+ }
119
+ function normalizePath(path) {
120
+ var result = path;
121
+
122
+ if (!result.startsWith('/')) {
123
+ result = "/".concat(result);
124
+ }
125
+
126
+ if (result.endsWith('/')) {
127
+ result = result.slice(-1);
128
+ }
129
+
130
+ return result;
114
131
  } // Type for import('http').METHODS
115
132
 
116
133
  function getInput(_x) {
@@ -218,22 +235,35 @@ function createGetContext(getContext) {
218
235
  return getContext;
219
236
  }
220
237
  class Router {
238
+ static patternize(path) {
239
+ var normalized = normalizePath(path);
240
+ return new RegExp("^".concat(normalized, "/?$"), 'i');
241
+ }
242
+
221
243
  constructor(procs) {
222
- _defineProperty(this, "create", method => (name, proc) => {
223
- return new Router(_objectSpread2(_objectSpread2({}, this.procs), {}, {
224
- [name]: _objectSpread2(_objectSpread2({}, proc), {}, {
244
+ _defineProperty(this, "create", method => (path, proc) => {
245
+ var pattern = Router.patternize(path);
246
+
247
+ var merged = _objectSpread2(_objectSpread2({}, this.procs), {}, {
248
+ [path]: _objectSpread2(_objectSpread2({}, proc), {}, {
225
249
  method,
226
- name
250
+ path,
251
+ pattern
227
252
  })
228
- }));
253
+ });
254
+
255
+ return new Router(merged);
229
256
  });
230
257
 
231
- _defineProperty(this, "merge", (prefix, router) => {
258
+ _defineProperty(this, "merge", (_prefix, router) => {
259
+ var prefix = normalizePath(_prefix);
232
260
  var newProcs = Object.entries(router.getProcs()).reduce((all, entry) => {
233
- var [name, proc] = entry;
261
+ var [path, proc] = entry;
262
+ var newPath = "".concat(prefix).concat(normalizePath(path));
234
263
  return _objectSpread2(_objectSpread2({}, all), {}, {
235
- ["".concat(prefix).concat(name)]: _objectSpread2(_objectSpread2({}, proc), {}, {
236
- name: "".concat(prefix).concat(name)
264
+ ["".concat(prefix).concat(path)]: _objectSpread2(_objectSpread2({}, proc), {}, {
265
+ path: newPath,
266
+ pattern: Router.patternize(newPath)
237
267
  })
238
268
  });
239
269
  }, {});
@@ -266,12 +296,27 @@ class Router {
266
296
  _defineProperty(this, "bind", this.create('BIND'));
267
297
 
268
298
  this.procs = procs;
299
+ this._procsArray = Object.values(procs);
269
300
  }
270
301
 
271
302
  getProcs() {
272
303
  return this.procs;
273
304
  }
274
305
 
306
+ find(method, url) {
307
+ for (var proc of this._procsArray) {
308
+ if (proc.method !== method) {
309
+ continue;
310
+ }
311
+
312
+ if (proc.pattern.test(url)) {
313
+ return proc;
314
+ }
315
+ }
316
+
317
+ return null;
318
+ }
319
+
275
320
  }
276
321
  class KaitoError extends Error {
277
322
  constructor(status, message, cause) {
@@ -293,8 +338,7 @@ function createServer(config) {
293
338
  }
294
339
  };
295
340
 
296
- var tree = config.router.getProcs();
297
- var server = http.createServer( /*#__PURE__*/function () {
341
+ return http.createServer( /*#__PURE__*/function () {
298
342
  var _ref = _asyncToGenerator(function* (incomingMessage, serverResponse) {
299
343
  var start = Date.now();
300
344
  var req = new KaitoRequest(incomingMessage);
@@ -303,7 +347,7 @@ function createServer(config) {
303
347
  try {
304
348
  var _handler$input, _yield$getInput;
305
349
 
306
- var handler = tree[req.url.pathname];
350
+ var handler = config.router.find(req.method, req.url.pathname);
307
351
 
308
352
  if (!handler) {
309
353
  throw new KaitoError(404, "Cannot ".concat(req.method, " this route."));
@@ -334,7 +378,7 @@ function createServer(config) {
334
378
  status: _status,
335
379
  message: _message
336
380
  } = yield config.onError({
337
- error: WrappedError.from(error),
381
+ error: WrappedError.maybe(error),
338
382
  req,
339
383
  res
340
384
  }).catch(() => ({
@@ -356,7 +400,6 @@ function createServer(config) {
356
400
  return _ref.apply(this, arguments);
357
401
  };
358
402
  }());
359
- return server;
360
403
  }
361
404
 
362
405
  export { KaitoError, Router, createGetContext, createRouter, createServer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaito-http/core",
3
- "version": "2.1.0",
3
+ "version": "2.2.2",
4
4
  "description": "Functional HTTP Framework for TypeScript",
5
5
  "repository": "https://github.com/kaito-http/kaito",
6
6
  "author": "Alistair Smith <hi@alistair.sh>",