barehttp 1.0.0 → 2.1.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.
Files changed (83) hide show
  1. package/README.md +185 -28
  2. package/lib/context/execution.d.ts +7 -0
  3. package/lib/context/execution.js +14 -0
  4. package/lib/context/index.d.ts +10 -0
  5. package/lib/context/index.js +46 -0
  6. package/lib/env.d.ts +5 -0
  7. package/lib/env.js +5 -0
  8. package/lib/index.d.ts +5 -0
  9. package/lib/index.js +3 -0
  10. package/lib/logger/index.d.ts +16 -0
  11. package/lib/logger/index.js +26 -0
  12. package/lib/logger/serializers.d.ts +28 -0
  13. package/lib/logger/serializers.js +78 -0
  14. package/lib/middlewares/cookies/cookie-manager.d.ts +25 -0
  15. package/lib/middlewares/cookies/cookie-manager.js +68 -0
  16. package/lib/middlewares/cookies/signer.d.ts +8 -0
  17. package/lib/middlewares/cookies/signer.js +25 -0
  18. package/lib/middlewares/cors/cors.d.ts +38 -0
  19. package/lib/middlewares/cors/cors.js +164 -0
  20. package/lib/request.d.ts +84 -0
  21. package/lib/request.js +260 -0
  22. package/lib/schemas/custom-schema.d.ts +32 -0
  23. package/lib/schemas/custom-schema.js +62 -0
  24. package/lib/schemas/dirty-tsm.d.ts +1 -0
  25. package/lib/schemas/dirty-tsm.js +199 -0
  26. package/lib/schemas/generator.d.ts +7 -0
  27. package/lib/schemas/generator.js +179 -0
  28. package/lib/schemas/helpers.d.ts +27 -0
  29. package/lib/schemas/helpers.js +40 -0
  30. package/lib/schemas/json-schema.d.ts +2 -0
  31. package/lib/schemas/json-schema.js +48 -0
  32. package/lib/schemas/openami-schema.d.ts +2 -0
  33. package/lib/schemas/openami-schema.js +59 -0
  34. package/lib/schemas/project.d.ts +1 -0
  35. package/lib/schemas/project.js +1 -0
  36. package/lib/server.d.ts +154 -0
  37. package/lib/server.js +396 -0
  38. package/lib/utils/content-type.d.ts +54 -0
  39. package/lib/utils/content-type.js +54 -0
  40. package/lib/utils/http-methods.d.ts +11 -0
  41. package/lib/utils/http-methods.js +9 -0
  42. package/lib/utils/index.d.ts +4 -0
  43. package/lib/utils/index.js +4 -0
  44. package/lib/utils/safe-json.d.ts +2 -0
  45. package/lib/utils/safe-json.js +18 -0
  46. package/lib/utils/status-codes.d.ts +339 -0
  47. package/lib/utils/status-codes.js +339 -0
  48. package/lib/utils/status-phrases.d.ts +338 -0
  49. package/lib/utils/status-phrases.js +339 -0
  50. package/lib/websocket.d.ts +36 -0
  51. package/lib/websocket.js +176 -0
  52. package/package.json +65 -33
  53. package/.eslintrc.js +0 -47
  54. package/.github/workflows/release.yml +0 -27
  55. package/.jest-setup.js +0 -1
  56. package/jest.config.js +0 -8
  57. package/prettier.config.js +0 -6
  58. package/src/context/context.test.ts +0 -30
  59. package/src/context/execution.ts +0 -17
  60. package/src/context/index.ts +0 -61
  61. package/src/env.ts +0 -5
  62. package/src/examples/bare-http.ts +0 -36
  63. package/src/examples/express.ts +0 -11
  64. package/src/examples/fastify.ts +0 -18
  65. package/src/index.ts +0 -4
  66. package/src/logger/index.ts +0 -67
  67. package/src/logger/serializers.test.ts +0 -186
  68. package/src/logger/serializers.ts +0 -109
  69. package/src/middlewares/cookies/cookie-manager.ts +0 -86
  70. package/src/middlewares/cookies/signer.ts +0 -30
  71. package/src/report.ts +0 -25
  72. package/src/request.test.ts +0 -143
  73. package/src/request.ts +0 -277
  74. package/src/server.integration.test.ts +0 -296
  75. package/src/server.middlewares.test.ts +0 -93
  76. package/src/server.routes.test.ts +0 -71
  77. package/src/server.ts +0 -450
  78. package/src/utils/content-type.ts +0 -59
  79. package/src/utils/index.ts +0 -2
  80. package/src/utils/safe-json.ts +0 -17
  81. package/src/utils/status-codes.ts +0 -339
  82. package/src/utils/status-phrases.ts +0 -339
  83. package/tsconfig.json +0 -24
@@ -0,0 +1,154 @@
1
+ import { ServerOptions } from 'ws';
2
+ import { Ajv } from 'ajv';
3
+ import { BareRequest, CacheOpts } from './request.js';
4
+ import { CookiesManagerOptions } from './middlewares/cookies/cookie-manager.js';
5
+ import { HttpMethodsUnion, StatusCodesUnion } from './utils/index.js';
6
+ import { CorsOptions } from './middlewares/cors/cors.js';
7
+ import { WebSocketServer } from './websocket.js';
8
+ import { Server } from 'http';
9
+ type Middleware = (flow: BareRequest) => Promise<void> | void;
10
+ type Handler<H extends {
11
+ [key: string]: string | undefined;
12
+ }> = (flow: BareRequest<H>) => any;
13
+ type ErrorHandler = (err: any, flow: BareRequest, status?: StatusCodesUnion) => void;
14
+ type IP = `${number}.${number}.${number}.${number}`;
15
+ type RouteOpts<C> = {
16
+ disableCache?: C extends true ? C : undefined;
17
+ cache?: C extends true ? undefined : CacheOpts;
18
+ /**
19
+ * Request timeout handler in `ms`
20
+ */
21
+ timeout?: number;
22
+ builtInRuntime?: {
23
+ output?: boolean;
24
+ };
25
+ middlewares?: Array<Middleware>;
26
+ };
27
+ type BareOptions<A extends IP> = {
28
+ /**
29
+ * Declare a global middlewares array
30
+ * Default: []
31
+ */
32
+ middlewares?: Array<Middleware>;
33
+ /**
34
+ * Opt-out request body parsing (de-serialization)
35
+ * Default `false`
36
+ */
37
+ doNotParseBody?: boolean;
38
+ /**
39
+ * Opt-in to have a custom swagger per route generation
40
+ * Default `false`
41
+ */
42
+ /**
43
+ * Opt-in to have a custom runtime JSON Schema checker per routes
44
+ * Default `false`
45
+ */
46
+ enableSchemaValidation?: boolean;
47
+ serverPort?: number;
48
+ declaredRoutesPaths?: Array<string>;
49
+ /**
50
+ * Address to bind the web server to
51
+ * Default '0.0.0.0'
52
+ */
53
+ serverAddress?: A | 'localhost';
54
+ setRandomPort?: boolean;
55
+ /**
56
+ * Enable request context storage
57
+ * Default `false`
58
+ */
59
+ context?: boolean;
60
+ /**
61
+ * Enable request/response predefined logging
62
+ * Default `false`
63
+ */
64
+ logging?: boolean;
65
+ errorHandlerMiddleware?: ErrorHandler;
66
+ /**
67
+ * Request time format in `seconds` or `milliseconds`
68
+ * Default - disabled
69
+ */
70
+ requestTimeFormat?: 's' | 'ms';
71
+ /**
72
+ * Control over cookies.
73
+ * This will enable automatic cookies decoding
74
+ */
75
+ cookies?: boolean;
76
+ cookiesOptions?: CookiesManagerOptions;
77
+ /**
78
+ * Log the resolved reverse DNS first hop for remote ip of the client (first proxy)
79
+ */
80
+ reverseDns?: boolean;
81
+ /**
82
+ * WebSocket server exposure
83
+ */
84
+ ws?: boolean;
85
+ wsOptions?: Omit<ServerOptions, 'host' | 'port' | 'server' | 'noServer'> & {
86
+ closeHandler?: (server: WebSocketServer) => Promise<void>;
87
+ };
88
+ /**
89
+ * Enable Cors
90
+ */
91
+ cors?: boolean | CorsOptions;
92
+ };
93
+ type ExtractRouteParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}` ? {
94
+ [K in Param | keyof ExtractRouteParams<Rest>]: string;
95
+ } : T extends `${string}:${infer Param}` ? {
96
+ [K in Param]: string;
97
+ } : {
98
+ [k: string]: string;
99
+ };
100
+ interface HandlerExposed<K> {
101
+ <R extends `/${string}`, C>(setUp: K extends 'declare' ? {
102
+ route: R;
103
+ options?: RouteOpts<C>;
104
+ handler: Handler<ExtractRouteParams<R>>;
105
+ methods: Array<HttpMethodsUnion>;
106
+ } : {
107
+ route: R;
108
+ options?: RouteOpts<C>;
109
+ handler: Handler<ExtractRouteParams<R>>;
110
+ }): BareServer<any> & Routes;
111
+ }
112
+ export type RouteReport = {
113
+ hits: number;
114
+ success: number;
115
+ fails: number;
116
+ };
117
+ export type Routes = {
118
+ [K in HttpMethodsUnion | 'declare']: HandlerExposed<K>;
119
+ };
120
+ export type BareHttpType<A extends IP = any> = BareServer<A> & Routes;
121
+ export declare class BareServer<A extends IP> {
122
+ #private;
123
+ private bareOptions;
124
+ server: Server;
125
+ ws?: WebSocketServer;
126
+ ajv?: Ajv;
127
+ route: Readonly<Routes>;
128
+ constructor(bareOptions?: BareOptions<A>);
129
+ private applyLaunchOptions;
130
+ private applyMiddlewares;
131
+ /**
132
+ * This handler is used in async generated middlewares runtime function
133
+ */
134
+ private resolveMiddleware;
135
+ private setRoute;
136
+ private handleRoute;
137
+ private resolveResponse;
138
+ private encodeRoute;
139
+ private explodeRoute;
140
+ private basicErrorHandler;
141
+ private stopWs;
142
+ private attachGracefulHandlers;
143
+ private attachRoutesDeclarator;
144
+ get runtimeRoute(): Readonly<Routes>;
145
+ start(cb?: (address: string) => void): Promise<void>;
146
+ stop(cb?: (e?: Error) => void): Promise<void>;
147
+ loadRoutesSchemas(): void;
148
+ use(middleware: Middleware): this;
149
+ getMiddlewares(): Middleware[];
150
+ setCustomErrorHandler(eh: ErrorHandler): void;
151
+ getServerPort(): number;
152
+ getRoutes(): string[];
153
+ }
154
+ export { BareServer as BareHttp };
package/lib/server.js ADDED
@@ -0,0 +1,396 @@
1
+ import Router from 'find-my-way';
2
+ import { Ajv } from 'ajv';
3
+ import { BareRequest } from './request.js';
4
+ import { logMe } from './logger/index.js';
5
+ import { context, enableContext, newContext } from './context/index.js';
6
+ import { HttpMethods, } from './utils/index.js';
7
+ import { Cors } from './middlewares/cors/cors.js';
8
+ import { WebSocketServer } from './websocket.js';
9
+ import { generateRouteSchema } from './schemas/generator.js';
10
+ import dns from 'dns';
11
+ import { createServer } from 'http';
12
+ export class BareServer {
13
+ bareOptions;
14
+ server;
15
+ ws;
16
+ ajv;
17
+ route = {};
18
+ #middlewares = [];
19
+ #routes = new Map();
20
+ #routesLib = new Map();
21
+ #router = Router({ ignoreTrailingSlash: true });
22
+ #errorHandler = this.basicErrorHandler;
23
+ #corsInstance;
24
+ #port = 3000;
25
+ #host = '0.0.0.0';
26
+ #globalMiddlewaresRun = (_) => _;
27
+ #routeMiddlewaresStore = new Map();
28
+ #routeRuntimeSchemas = new Map();
29
+ constructor(bareOptions = {}) {
30
+ this.bareOptions = bareOptions;
31
+ // init
32
+ this.server = createServer(this.#listener.bind(this));
33
+ this.attachGracefulHandlers();
34
+ this.attachRoutesDeclarator();
35
+ this.applyLaunchOptions();
36
+ this.loadRoutesSchemas();
37
+ return this;
38
+ }
39
+ #listener = (request, response) => {
40
+ const flow = new BareRequest(request, response, this.bareOptions);
41
+ // init and attach request uuid to the context
42
+ if (this.bareOptions.context) {
43
+ newContext('request');
44
+ context.current?.store.set('id', flow.ID.code);
45
+ }
46
+ // execute global middlewares on the request
47
+ this.applyMiddlewares(flow)
48
+ .catch((e) => {
49
+ this.#errorHandler(e, flow, 400);
50
+ })
51
+ .then(() => {
52
+ // if middlewares sent the response back, stop here
53
+ if (flow.sent)
54
+ return;
55
+ this.#router.lookup(flow._originalRequest, flow._originalResponse);
56
+ });
57
+ };
58
+ /**
59
+ * This function generates previously defined middlewares for the sequential execution
60
+ */
61
+ #writeMiddlewares = () => {
62
+ const lines = [];
63
+ let order = 0;
64
+ const maxOrder = this.#middlewares.length;
65
+ const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
66
+ if (maxOrder > 0) {
67
+ while (order <= maxOrder - 1) {
68
+ lines.push(`if (flow.sent) return;`);
69
+ lines.push(`await this.resolveMiddleware(flow, ${order});`);
70
+ order++;
71
+ }
72
+ }
73
+ const text = lines.join('\n');
74
+ this.#globalMiddlewaresRun = new AsyncFunction('flow', text);
75
+ };
76
+ applyLaunchOptions = () => {
77
+ const { bareOptions: bo } = this;
78
+ if (bo.setRandomPort) {
79
+ this.#port = undefined;
80
+ }
81
+ else {
82
+ this.#port = +(bo.serverPort || process.env.PORT || 3000);
83
+ }
84
+ this.#host = typeof bo.serverAddress === 'string' ? bo.serverAddress : '0.0.0.0';
85
+ // context setting
86
+ if (bo.context)
87
+ enableContext();
88
+ // ws attachment
89
+ if (bo.ws) {
90
+ this.ws = new WebSocketServer(this.server, bo.wsOptions);
91
+ }
92
+ // middlewares settings
93
+ if (bo.errorHandlerMiddleware) {
94
+ this.#errorHandler = bo.errorHandlerMiddleware;
95
+ }
96
+ if (this.bareOptions.cors) {
97
+ const corsOpts = typeof this.bareOptions.cors === 'object' ? this.bareOptions.cors : {};
98
+ this.#corsInstance = new Cors(corsOpts);
99
+ }
100
+ this.#middlewares.push(...(bo.middlewares || []));
101
+ };
102
+ async applyMiddlewares(flow) {
103
+ if (this.bareOptions.cors) {
104
+ this.resolveMiddleware(flow, 0, this.#corsInstance?.corsMiddleware.bind(this.#corsInstance));
105
+ }
106
+ if (this.bareOptions.doNotParseBody !== true) {
107
+ // invoke body stream consumption
108
+ await flow['readBody']();
109
+ }
110
+ // attach cookies middleware
111
+ if (this.bareOptions.cookies) {
112
+ flow['attachCookieManager'](this.bareOptions.cookiesOptions);
113
+ flow['populateCookies']();
114
+ }
115
+ // to test in cloud provider
116
+ // this should resolve the name of the first hop from the dns chain
117
+ if (this.bareOptions.reverseDns) {
118
+ const remoteClient = await dns.promises.reverse(flow.remoteIp);
119
+ flow['setRemoteClient'](remoteClient[0]);
120
+ }
121
+ if (this.#middlewares.length)
122
+ await this.#globalMiddlewaresRun(flow);
123
+ }
124
+ /**
125
+ * This handler is used in async generated middlewares runtime function
126
+ */
127
+ async resolveMiddleware(flow, order, middleware) {
128
+ try {
129
+ const toExecute = middleware || this.#middlewares[order];
130
+ const response = toExecute(flow);
131
+ if (response instanceof Promise)
132
+ await response;
133
+ }
134
+ catch (e) {
135
+ this.#errorHandler(e, flow);
136
+ }
137
+ }
138
+ setRoute(method, route, isRuntime, handler, opts) {
139
+ const encode = this.encodeRoute(method, route);
140
+ const handleFn = (req, _, routeParams) => {
141
+ this.handleRoute(req, checkParams(routeParams), handler, opts);
142
+ };
143
+ this.#routesLib.set(encode, handleFn);
144
+ if (isRuntime) {
145
+ this.#router.reset();
146
+ this.#routesLib.forEach((handlerFn, route) => {
147
+ const [m, r] = this.explodeRoute(route);
148
+ this.#router.on(m, r, handlerFn);
149
+ });
150
+ }
151
+ else {
152
+ this.#router.on(method, route, handleFn);
153
+ }
154
+ }
155
+ handleRoute(req, routeParams, handle, routeOpts) {
156
+ const flow = req.flow;
157
+ if (!flow) {
158
+ throw new Error(`No flow been found to route this request, theres a sync mistake in the server.`); // should NEVER happen
159
+ }
160
+ // populate with route params
161
+ if (routeParams)
162
+ flow['setParams'](routeParams);
163
+ // apply possible route options
164
+ if (routeOpts) {
165
+ if (routeOpts.disableCache)
166
+ flow.disableCache();
167
+ if (routeOpts.cache)
168
+ flow.setCache(routeOpts.cache);
169
+ if (routeOpts.timeout)
170
+ flow['attachTimeout'](routeOpts.timeout);
171
+ }
172
+ // TODO: implement per route middlewares!
173
+ try {
174
+ const routeReturn = handle(flow);
175
+ if (flow.sent)
176
+ return;
177
+ if (routeReturn instanceof Promise) {
178
+ routeReturn
179
+ .then((result) => this.resolveResponse(flow, result, req.url, req.method?.toLowerCase(), routeOpts?.builtInRuntime?.output))
180
+ .catch((e) => {
181
+ this.#errorHandler(e, flow);
182
+ });
183
+ return;
184
+ }
185
+ this.resolveResponse(flow, routeReturn, req.url, req.method?.toLowerCase(), routeOpts?.builtInRuntime?.output);
186
+ }
187
+ catch (e) {
188
+ this.#errorHandler(e, flow);
189
+ }
190
+ }
191
+ resolveResponse(flow, response, url, method, builtInRuntime) {
192
+ if (!builtInRuntime || !method || !url) {
193
+ flow.send(response);
194
+ return;
195
+ }
196
+ const schema = this.#routeRuntimeSchemas.get(`${method}-${url}`);
197
+ const check = schema?.compiled(response);
198
+ if ((schema && check) || !schema)
199
+ flow.send(response);
200
+ else {
201
+ logMe.error('Response schema error!', {
202
+ method,
203
+ url,
204
+ errors: schema?.compiled.errors,
205
+ received: response,
206
+ });
207
+ flow
208
+ .status(500)
209
+ .send({ message: `Response schema error, please communicate to server administrator.` });
210
+ }
211
+ }
212
+ encodeRoute(method, route) {
213
+ if (route.endsWith('/'))
214
+ route = route.slice(0, -1);
215
+ return `${method}?${route}`;
216
+ }
217
+ explodeRoute(route) {
218
+ return route.split('?');
219
+ }
220
+ basicErrorHandler(e, flow, status) {
221
+ flow.status(status ?? 500).json({ ...e, message: e.message, stack: e.stack });
222
+ }
223
+ async stopWs() {
224
+ if (!this.ws)
225
+ return;
226
+ if (this.bareOptions.wsOptions?.closeHandler) {
227
+ await this.bareOptions.wsOptions.closeHandler(this.ws);
228
+ }
229
+ this.ws._internal.close();
230
+ }
231
+ attachGracefulHandlers() {
232
+ const graceful = async (code = 0) => {
233
+ await this.stop();
234
+ process.exit(code);
235
+ };
236
+ // Stop graceful
237
+ process.on('uncaughtException', (err) => {
238
+ console.error(err);
239
+ graceful(1);
240
+ });
241
+ process.on('unhandledRejection', (err) => {
242
+ console.error(err);
243
+ });
244
+ process.on('SIGTERM', () => graceful(0));
245
+ process.on('SIGINT', () => graceful(0));
246
+ }
247
+ attachRoutesDeclarator() {
248
+ for (const method of [...Object.keys(HttpMethods), 'declare']) {
249
+ this.route[method] = (routeSetUp) => {
250
+ checkRouteSetUp(routeSetUp, method);
251
+ if (method === 'declare') {
252
+ for (const m of new Set(routeSetUp.methods))
253
+ this.setRoute(HttpMethods[m], routeSetUp.route, false, routeSetUp.handler, routeSetUp.options);
254
+ }
255
+ else {
256
+ this.setRoute(HttpMethods[method], routeSetUp.route, false, routeSetUp.handler, routeSetUp.options);
257
+ }
258
+ return this;
259
+ };
260
+ }
261
+ }
262
+ // ========= PUBLIC APIS ==========
263
+ // TODO: add working options setter
264
+ // setOption<B extends BareOptions<any>, O extends keyof B>(option: O, arg: B[O]) {
265
+ // throw new Error('Not implemented')
266
+ // }
267
+ get runtimeRoute() {
268
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
269
+ const self = this;
270
+ return new Proxy({}, {
271
+ get(_, key) {
272
+ if (typeof key === 'symbol')
273
+ return this;
274
+ if (!self.server?.listening) {
275
+ console.warn('Runtime route declaration can be done only while the server is running. Follow documentation for more details');
276
+ return this;
277
+ }
278
+ if ([...Object.keys(HttpMethods), 'declare'].includes(key)) {
279
+ return (routeSetUp) => {
280
+ checkRouteSetUp(routeSetUp, key);
281
+ if (key === 'declare') {
282
+ for (const m of new Set(routeSetUp.methods))
283
+ self.setRoute(HttpMethods[m], routeSetUp.route, true, routeSetUp.handler, routeSetUp.options);
284
+ }
285
+ else {
286
+ self.setRoute(HttpMethods[key], routeSetUp.route, true, routeSetUp.handler, routeSetUp.options);
287
+ }
288
+ return this;
289
+ };
290
+ }
291
+ return this;
292
+ },
293
+ });
294
+ }
295
+ start(cb) {
296
+ this.#writeMiddlewares();
297
+ this.ws?.['_start']();
298
+ return new Promise((res) =>
299
+ // https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
300
+ this.server.listen(this.#port, this.#host, undefined, () => {
301
+ cb?.(`http://0.0.0.0:${this.#port}`);
302
+ res();
303
+ }));
304
+ }
305
+ async stop(cb) {
306
+ // TODO: to solve problem announcing to clients the disconnect
307
+ // for (const flow of this.#flows.values()) {
308
+ // if (!flow.sent) {
309
+ // flow.status(500);
310
+ // flow.send('Server terminated');
311
+ // }
312
+ // }
313
+ if (!this.ws)
314
+ await this.stopWs();
315
+ if (!this.server?.listening)
316
+ return;
317
+ await new Promise((res, rej) => {
318
+ this.server.close((e) => {
319
+ if (e) {
320
+ rej(e);
321
+ cb?.(e);
322
+ }
323
+ else {
324
+ cb?.();
325
+ res();
326
+ }
327
+ });
328
+ });
329
+ }
330
+ loadRoutesSchemas() {
331
+ if (!this.bareOptions.enableSchemaValidation) {
332
+ return;
333
+ }
334
+ if (this.bareOptions.declaredRoutesPaths?.length) {
335
+ this.ajv = new Ajv({ strict: true });
336
+ for (const path of this.bareOptions.declaredRoutesPaths) {
337
+ const schemas = generateRouteSchema(path);
338
+ for (const schema of schemas) {
339
+ this.#routeRuntimeSchemas.set(`${schema.methodName}-${schema.route}`, {
340
+ raw: schema.jsonSchema,
341
+ compiled: this.ajv.compile(schema.jsonSchema),
342
+ });
343
+ }
344
+ }
345
+ }
346
+ }
347
+ use(middleware) {
348
+ this.#middlewares.push(middleware);
349
+ return this;
350
+ }
351
+ getMiddlewares() {
352
+ return this.#middlewares;
353
+ }
354
+ setCustomErrorHandler(eh) {
355
+ this.#errorHandler = eh;
356
+ }
357
+ getServerPort() {
358
+ return this.server.address().port;
359
+ }
360
+ getRoutes() {
361
+ return [...this.#routes.keys()];
362
+ }
363
+ }
364
+ function checkRouteSetUp(routeSetUp, key) {
365
+ if (typeof routeSetUp.route !== 'string') {
366
+ throw new TypeError(`A route path for the method ${key} is not a a string`);
367
+ }
368
+ else if (routeSetUp.route[0] !== '/') {
369
+ throw new SyntaxError(`A route path should start with '/' for route ${routeSetUp.route} for method ${key}`);
370
+ }
371
+ else if (routeSetUp.route[1] === '/') {
372
+ throw new SyntaxError(`Declared route ${routeSetUp.route} for method ${key} is not correct, review the syntax`);
373
+ }
374
+ else if (typeof routeSetUp.handler !== 'function') {
375
+ throw new TypeError(`Handler for the route ${routeSetUp.route} for method ${key} is not a function`);
376
+ }
377
+ else if (routeSetUp.options?.timeout &&
378
+ typeof routeSetUp.options.timeout !== 'number' &&
379
+ !Number.isFinite(routeSetUp.options.timeout)) {
380
+ throw new TypeError(`Only numeric values are valid per-route timeout, submitted ${routeSetUp.options.timeout}`);
381
+ }
382
+ }
383
+ function checkParams(params) {
384
+ if (!params || Object.keys(params).length === 0)
385
+ return params;
386
+ for (const [param, value] of Object.entries(params)) {
387
+ if (value === undefined)
388
+ continue;
389
+ if (/(\.\/)(\.\.)(\\.)/.test(decodeURI(value))) {
390
+ logMe.warn(`Param ${param} value ${value} was redacted because contained dangerous characters`);
391
+ param[param] = 'REDACTED';
392
+ }
393
+ }
394
+ return params;
395
+ }
396
+ export { BareServer as BareHttp };
@@ -0,0 +1,54 @@
1
+ export declare const ContentType: {
2
+ readonly 'application/EDI-X12': "application/EDI-X12";
3
+ readonly 'application/EDIFACT': "application/EDIFACT";
4
+ readonly 'application/javascript': "application/javascript";
5
+ readonly 'application/octet-stream': "application/octet-stream";
6
+ readonly 'application/ogg': "application/ogg";
7
+ readonly 'application/pdf': "application/pdf";
8
+ readonly 'application/xhtml+xml': "application/xhtml+xml";
9
+ readonly 'application/x-shockwave-flash': "application/x-shockwave-flash";
10
+ readonly 'application/json': "application/json";
11
+ readonly 'application/ld+json': "application/ld+json";
12
+ readonly 'application/xml': "application/xml";
13
+ readonly 'application/zip': "application/zip";
14
+ readonly 'application/x-www-form-urlencoded': "application/x-www-form-urlencoded";
15
+ readonly 'audio/mpeg': "audio/mpeg";
16
+ readonly 'audio/x-ms-wma': "audio/x-ms-wma";
17
+ readonly 'audio/vnd.rn-realaudio': "audio/vnd.rn-realaudio";
18
+ readonly 'audio/x-wav': "audio/x-wav";
19
+ readonly 'image/gif': "image/gif";
20
+ readonly 'image/jpeg': "image/jpeg";
21
+ readonly 'image/png': "image/png";
22
+ readonly 'image/tiff': "image/tiff";
23
+ readonly 'image/vnd.microsoft.icon': "image/vnd.microsoft.icon";
24
+ readonly 'image/x-icon': "image/x-icon";
25
+ readonly 'image/vnd.djvu': "image/vnd.djvu";
26
+ readonly 'image/svg+xml': "image/svg+xml";
27
+ readonly 'multipart/mixed': "multipart/mixed";
28
+ readonly 'multipart/alternative': "multipart/alternative";
29
+ readonly 'multipart/related': "multipart/related";
30
+ readonly 'multipart/form-data': "multipart/form-data";
31
+ readonly 'text/css': "text/css";
32
+ readonly 'text/csv': "text/csv";
33
+ readonly 'text/html': "text/html";
34
+ readonly 'text/plain': "text/plain";
35
+ readonly 'text/xml': "text/xml";
36
+ readonly 'video/mpeg': "video/mpeg";
37
+ readonly 'video/mp4': "video/mp4";
38
+ readonly 'video/quicktime': "video/quicktime";
39
+ readonly 'video/x-ms-wmv': "video/x-ms-wmv";
40
+ readonly 'video/x-msvideo': "video/x-msvideo";
41
+ readonly 'video/x-flv': "video/x-flv";
42
+ readonly 'video/webm': "video/webm";
43
+ readonly 'application/vnd.oasis.opendocument.text': "application/vnd.oasis.opendocument.text";
44
+ readonly 'application/vnd.oasis.opendocument.spreadsheet': "application/vnd.oasis.opendocument.spreadsheet";
45
+ readonly 'application/vnd.oasis.opendocument.presentation': "application/vnd.oasis.opendocument.presentation";
46
+ readonly 'application/vnd.oasis.opendocument.graphics': "application/vnd.oasis.opendocument.graphics";
47
+ readonly 'application/vnd.ms-excel': "application/vnd.ms-excel";
48
+ readonly 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
49
+ readonly 'application/vnd.ms-powerpoint': "application/vnd.ms-powerpoint";
50
+ readonly 'application/vnd.openxmlformats-officedocument.presentationml.presentation': "application/vnd.openxmlformats-officedocument.presentationml.presentation";
51
+ readonly 'application/msword': "application/msword";
52
+ readonly 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
53
+ readonly 'application/vnd.mozilla.xul+xml': "application/vnd.mozilla.xul+xml";
54
+ };
@@ -0,0 +1,54 @@
1
+ export const ContentType = {
2
+ 'application/EDI-X12': 'application/EDI-X12',
3
+ 'application/EDIFACT': 'application/EDIFACT',
4
+ 'application/javascript': 'application/javascript',
5
+ 'application/octet-stream': 'application/octet-stream',
6
+ 'application/ogg': 'application/ogg',
7
+ 'application/pdf': 'application/pdf',
8
+ 'application/xhtml+xml': 'application/xhtml+xml',
9
+ 'application/x-shockwave-flash': 'application/x-shockwave-flash',
10
+ 'application/json': 'application/json',
11
+ 'application/ld+json': 'application/ld+json',
12
+ 'application/xml': 'application/xml',
13
+ 'application/zip': 'application/zip',
14
+ 'application/x-www-form-urlencoded': 'application/x-www-form-urlencoded',
15
+ 'audio/mpeg': 'audio/mpeg',
16
+ 'audio/x-ms-wma': 'audio/x-ms-wma',
17
+ 'audio/vnd.rn-realaudio': 'audio/vnd.rn-realaudio',
18
+ 'audio/x-wav': 'audio/x-wav',
19
+ 'image/gif': 'image/gif',
20
+ 'image/jpeg': 'image/jpeg',
21
+ 'image/png': 'image/png',
22
+ 'image/tiff': 'image/tiff',
23
+ 'image/vnd.microsoft.icon': 'image/vnd.microsoft.icon',
24
+ 'image/x-icon': 'image/x-icon',
25
+ 'image/vnd.djvu': 'image/vnd.djvu',
26
+ 'image/svg+xml': 'image/svg+xml',
27
+ 'multipart/mixed': 'multipart/mixed',
28
+ 'multipart/alternative': 'multipart/alternative',
29
+ 'multipart/related': 'multipart/related', // (using by MHTML (HTML mail).)
30
+ 'multipart/form-data': 'multipart/form-data',
31
+ 'text/css': 'text/css',
32
+ 'text/csv': 'text/csv',
33
+ 'text/html': 'text/html',
34
+ 'text/plain': 'text/plain',
35
+ 'text/xml': 'text/xml',
36
+ 'video/mpeg': 'video/mpeg',
37
+ 'video/mp4': 'video/mp4',
38
+ 'video/quicktime': 'video/quicktime',
39
+ 'video/x-ms-wmv': 'video/x-ms-wmv',
40
+ 'video/x-msvideo': 'video/x-msvideo',
41
+ 'video/x-flv': 'video/x-flv',
42
+ 'video/webm': 'video/webm',
43
+ 'application/vnd.oasis.opendocument.text': 'application/vnd.oasis.opendocument.text',
44
+ 'application/vnd.oasis.opendocument.spreadsheet': 'application/vnd.oasis.opendocument.spreadsheet',
45
+ 'application/vnd.oasis.opendocument.presentation': 'application/vnd.oasis.opendocument.presentation',
46
+ 'application/vnd.oasis.opendocument.graphics': 'application/vnd.oasis.opendocument.graphics',
47
+ 'application/vnd.ms-excel': 'application/vnd.ms-excel',
48
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
49
+ 'application/vnd.ms-powerpoint': 'application/vnd.ms-powerpoint',
50
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
51
+ 'application/msword': 'application/msword',
52
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
53
+ 'application/vnd.mozilla.xul+xml': 'application/vnd.mozilla.xul+xml',
54
+ };
@@ -0,0 +1,11 @@
1
+ export declare const HttpMethods: {
2
+ readonly get: "GET";
3
+ readonly post: "POST";
4
+ readonly put: "PUT";
5
+ readonly delete: "DELETE";
6
+ readonly patch: "PATCH";
7
+ readonly options: "OPTIONS";
8
+ readonly head: "HEAD";
9
+ };
10
+ export type HttpMethodsUnion = keyof typeof HttpMethods;
11
+ export type HttpMethodsUnionUppercase = typeof HttpMethods[keyof typeof HttpMethods];
@@ -0,0 +1,9 @@
1
+ export const HttpMethods = {
2
+ get: 'GET',
3
+ post: 'POST',
4
+ put: 'PUT',
5
+ delete: 'DELETE',
6
+ patch: 'PATCH',
7
+ options: 'OPTIONS',
8
+ head: 'HEAD',
9
+ };
@@ -0,0 +1,4 @@
1
+ export { StatusPhrases } from './status-phrases.js';
2
+ export { StatusCodes, StatusCodesUnion } from './status-codes.js';
3
+ export { HttpMethods, HttpMethodsUnion, HttpMethodsUnionUppercase } from './http-methods.js';
4
+ export { JSONStringify, JSONParse } from './safe-json.js';