@drunkcod/express-kit 0.0.10 → 0.0.12
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/lib/cjs/index.d.ts +19 -0
- package/lib/cjs/index.js +80 -0
- package/lib/cjs/loggable.d.ts +5 -0
- package/lib/cjs/loggable.js +46 -0
- package/lib/cjs/package.json +1 -0
- package/lib/loggable.d.ts +3 -0
- package/lib/loggable.js +5 -0
- package/package.json +19 -5
- package/lib/express-async/index.d.ts +0 -39
- package/lib/express-async/index.js +0 -37
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type express from 'express';
|
|
2
|
+
export * from '@drunkcod/express-async';
|
|
3
|
+
export * from './loggable.js';
|
|
4
|
+
type AsyncFn<T> = () => Promise<T>;
|
|
5
|
+
type ExpressServer = ReturnType<express.Application['listen']>;
|
|
6
|
+
export type ErrorHandler = (error: Error, request: express.Request, response: express.Response, next: express.NextFunction) => void;
|
|
7
|
+
export declare function onceAsync<T>(fn: AsyncFn<T>): AsyncFn<T>;
|
|
8
|
+
export declare function mergeCallsAsync<T>(fn: AsyncFn<T>): AsyncFn<T>;
|
|
9
|
+
interface Listener<T> {
|
|
10
|
+
listen(cb: () => void): T;
|
|
11
|
+
listen(port: number, cb: () => void): T;
|
|
12
|
+
}
|
|
13
|
+
export declare function listenAsync<T>(server: Listener<T>, options?: {
|
|
14
|
+
port?: number;
|
|
15
|
+
}): Promise<T>;
|
|
16
|
+
export declare function closeAsync(server: {
|
|
17
|
+
close: (cb: (error?: Error) => void) => void;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export declare function registerShutdown<Server extends ExpressServer = ExpressServer>(server: Server, shutdown?: () => Promise<void>): void;
|
package/lib/cjs/index.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.onceAsync = onceAsync;
|
|
18
|
+
exports.mergeCallsAsync = mergeCallsAsync;
|
|
19
|
+
exports.listenAsync = listenAsync;
|
|
20
|
+
exports.closeAsync = closeAsync;
|
|
21
|
+
exports.registerShutdown = registerShutdown;
|
|
22
|
+
__exportStar(require("@drunkcod/express-async"), exports);
|
|
23
|
+
__exportStar(require("./loggable.js"), exports);
|
|
24
|
+
function onceAsync(fn) {
|
|
25
|
+
let p;
|
|
26
|
+
return () => {
|
|
27
|
+
if (p)
|
|
28
|
+
return p;
|
|
29
|
+
p = fn();
|
|
30
|
+
fn = () => p;
|
|
31
|
+
return p;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function mergeCallsAsync(fn) {
|
|
35
|
+
let p;
|
|
36
|
+
return async () => {
|
|
37
|
+
if (!p)
|
|
38
|
+
p = fn();
|
|
39
|
+
try {
|
|
40
|
+
return await p;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
p = null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function listenAsync(server, options) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
try {
|
|
50
|
+
if (options?.port) {
|
|
51
|
+
const r = server.listen(options.port, () => resolve(r));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const r = server.listen(() => resolve(r));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
reject(err);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function closeAsync(server) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
server.close((err) => {
|
|
65
|
+
if (err)
|
|
66
|
+
reject(err);
|
|
67
|
+
else
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function registerShutdown(server, shutdown) {
|
|
73
|
+
const onShutdown = onceAsync(async () => {
|
|
74
|
+
await closeAsync(server);
|
|
75
|
+
if (shutdown)
|
|
76
|
+
await shutdown();
|
|
77
|
+
});
|
|
78
|
+
process.on('SIGINT', onShutdown);
|
|
79
|
+
process.on('SIGTERM', onShutdown);
|
|
80
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.at = at;
|
|
4
|
+
exports.asLoggableError = asLoggableError;
|
|
5
|
+
exports.hasOwnJSON = hasOwnJSON;
|
|
6
|
+
const argis_1 = require("@drunkcod/argis");
|
|
7
|
+
function at(message) {
|
|
8
|
+
const old = Error.stackTraceLimit;
|
|
9
|
+
try {
|
|
10
|
+
const r = { stack: '' };
|
|
11
|
+
Error.stackTraceLimit = 1;
|
|
12
|
+
Error.captureStackTrace(r, at);
|
|
13
|
+
message = message ? `${message} ` : '';
|
|
14
|
+
return message + r.stack.substring(10);
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
Error.stackTraceLimit = old;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function asLoggableCause(cause) {
|
|
21
|
+
if (cause == null || typeof cause !== 'object')
|
|
22
|
+
return cause;
|
|
23
|
+
if (hasOwnJSON(cause))
|
|
24
|
+
return asLoggableCause(cause.toJSON());
|
|
25
|
+
if (cause instanceof Error) {
|
|
26
|
+
const { message, stack, cause: innerCause, ...rest } = cause;
|
|
27
|
+
return innerCause
|
|
28
|
+
? { message, stack, cause: asLoggableCause(innerCause), ...rest }
|
|
29
|
+
: { message, stack, ...rest };
|
|
30
|
+
}
|
|
31
|
+
if ((0, argis_1.hasOwn)(cause, 'cause')) {
|
|
32
|
+
const { cause: innerCause, ...rest } = cause;
|
|
33
|
+
return { ...rest, cause: asLoggableCause(innerCause) };
|
|
34
|
+
}
|
|
35
|
+
return { ...cause };
|
|
36
|
+
}
|
|
37
|
+
function asLoggableError(error) {
|
|
38
|
+
if (error instanceof Error)
|
|
39
|
+
return asLoggableCause(error);
|
|
40
|
+
const r = (error && typeof error === 'object') ? asLoggableCause(error) : { message: error };
|
|
41
|
+
Error.captureStackTrace(r, asLoggableError);
|
|
42
|
+
return Object.defineProperty(r, 'stack', { enumerable: true });
|
|
43
|
+
}
|
|
44
|
+
function hasOwnJSON(x) {
|
|
45
|
+
return 'toJSON' in x && typeof x.toJSON === 'function';
|
|
46
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "commonjs"}
|
package/lib/loggable.d.ts
CHANGED
package/lib/loggable.js
CHANGED
|
@@ -15,6 +15,8 @@ export function at(message) {
|
|
|
15
15
|
function asLoggableCause(cause) {
|
|
16
16
|
if (cause == null || typeof cause !== 'object')
|
|
17
17
|
return cause;
|
|
18
|
+
if (hasOwnJSON(cause))
|
|
19
|
+
return asLoggableCause(cause.toJSON());
|
|
18
20
|
if (cause instanceof Error) {
|
|
19
21
|
const { message, stack, cause: innerCause, ...rest } = cause;
|
|
20
22
|
return innerCause
|
|
@@ -34,3 +36,6 @@ export function asLoggableError(error) {
|
|
|
34
36
|
Error.captureStackTrace(r, asLoggableError);
|
|
35
37
|
return Object.defineProperty(r, 'stack', { enumerable: true });
|
|
36
38
|
}
|
|
39
|
+
export function hasOwnJSON(x) {
|
|
40
|
+
return 'toJSON' in x && typeof x.toJSON === 'function';
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drunkcod/express-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.12",
|
|
5
5
|
"description": "Express4 utility things",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -9,12 +9,26 @@
|
|
|
9
9
|
"lib/**/*",
|
|
10
10
|
"!lib/**/*.spec.*"
|
|
11
11
|
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": {
|
|
15
|
+
"default": "./lib/index.js",
|
|
16
|
+
"types": "./lib/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"default": "./lib/cjs/index.js",
|
|
20
|
+
"types": "./lib/cjs/index.d.ts"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
12
24
|
"scripts": {
|
|
13
25
|
"clean": "rimraf lib",
|
|
14
26
|
"compile": "tsc",
|
|
27
|
+
"cjs:compile": "tsc --module commonjs --outdir lib/cjs",
|
|
28
|
+
"cjs:fixup": "echo '{\"type\": \"commonjs\"}' > lib/cjs/package.json",
|
|
15
29
|
"test": "NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" jest",
|
|
16
30
|
"test:all": "npm-run-all \"test --workspaces --include-workspace-root\" --silent",
|
|
17
|
-
"build": "npm-run-all clean compile --silent"
|
|
31
|
+
"build": "npm-run-all clean -p compile cjs:compile -s cjs:fixup --silent"
|
|
18
32
|
},
|
|
19
33
|
"keywords": [
|
|
20
34
|
"express"
|
|
@@ -25,8 +39,8 @@
|
|
|
25
39
|
"express-async"
|
|
26
40
|
],
|
|
27
41
|
"dependencies": {
|
|
28
|
-
"@drunkcod/argis": "^0.0.
|
|
29
|
-
"@drunkcod/express-async": "^0.0.
|
|
42
|
+
"@drunkcod/argis": "^0.0.7",
|
|
43
|
+
"@drunkcod/express-async": "^0.0.11"
|
|
30
44
|
},
|
|
31
45
|
"devDependencies": {
|
|
32
46
|
"@drunkcod/ts-jest-esm": "^0.0.1",
|
|
@@ -36,6 +50,6 @@
|
|
|
36
50
|
"npm-run-all": "^4.1.5",
|
|
37
51
|
"rimraf": "^6.0.1",
|
|
38
52
|
"ts-jest": "^29.2.5",
|
|
39
|
-
"typescript": "^5.
|
|
53
|
+
"typescript": "^5.7.2"
|
|
40
54
|
}
|
|
41
55
|
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type express from 'express';
|
|
2
|
-
type WithReturn<Type extends (...args: any) => any, R> = Type extends (...args: infer Args) => any ? (...args: Args) => R : never;
|
|
3
|
-
type IsEmptyObject<T extends Record<PropertyKey, unknown>> = [keyof T] extends [never] ? true : false;
|
|
4
|
-
type RequestHandler<T, Req extends express.Request<any> = express.Request<any>> = ((req: Req, res: express.Response<any>) => Promise<T>) | ((req: Req, res: express.Response<any>, next: express.NextFunction) => Promise<T>);
|
|
5
|
-
type RequestParams = [
|
|
6
|
-
express.Request<any>,
|
|
7
|
-
express.Response
|
|
8
|
-
] | [express.Request<any>, express.Response, express.NextFunction];
|
|
9
|
-
type ErrorParams = [Error, express.Request<any>, express.Response, express.NextFunction];
|
|
10
|
-
type IsRequestHandler<T, P extends keyof T> = T[P] extends (...args: any) => any ? Parameters<T[P]> extends RequestParams ? P : never : never;
|
|
11
|
-
type IsErrorHandler<T, P extends keyof T> = T[P] extends (...args: any) => any ? Parameters<T[P]> extends ErrorParams ? P : never : never;
|
|
12
|
-
type ErrorHandler<T> = WithReturn<express.ErrorRequestHandler, Promise<T>>;
|
|
13
|
-
type HandlerFns<C> = {
|
|
14
|
-
[P in keyof C as IsRequestHandler<C, P>]: C[P];
|
|
15
|
-
};
|
|
16
|
-
type HandlerErrorFns<C> = {
|
|
17
|
-
[P in keyof C as IsErrorHandler<C, P>]: C[P];
|
|
18
|
-
};
|
|
19
|
-
type ControllerHandlerFns<C> = IsEmptyObject<HandlerFns<C>> extends true ? never : HandlerFns<C>;
|
|
20
|
-
type ControllerErrorFns<C> = IsEmptyObject<HandlerErrorFns<C>> extends true ? never : HandlerErrorFns<C>;
|
|
21
|
-
type ControllerFns<C> = ControllerHandlerFns<C> | ControllerErrorFns<C>;
|
|
22
|
-
type HandlerFn<Req, T> = Req extends [never] ? never : ((...args: [request: Req, response: express.Response]) => Promise<T>) | ((...args: [request: Req, response: express.Response, next: express.NextFunction]) => Promise<T>);
|
|
23
|
-
type ErrorHandlerFn<Req, T> = Req extends [never] ? never : ((...args: [errpr: Error, request: Req, response: express.Response, next: express.NextFunction]) => Promise<T>);
|
|
24
|
-
export declare const as: <T>(x: T) => T;
|
|
25
|
-
export declare function asyncHandler<T, Req extends express.Request = express.Request<any>>(fn: HandlerFn<Req, T>): RequestHandler<T>;
|
|
26
|
-
export declare function asyncHandler<T, Req extends express.Request = express.Request<any>>(fn: ErrorHandlerFn<Req, T>): ErrorHandler<T>;
|
|
27
|
-
export declare function boundAsyncHandler<C extends ControllerHandlerFns<C>, T>(x: C, m: keyof ControllerHandlerFns<C>): RequestHandler<unknown>;
|
|
28
|
-
export declare function boundAsyncHandler<C extends ControllerErrorFns<C>, T>(x: C, m: keyof ControllerErrorFns<C>): ErrorHandler<unknown>;
|
|
29
|
-
export declare class AsyncBinder<Controller extends ControllerFns<Controller>> {
|
|
30
|
-
private controller;
|
|
31
|
-
static for<Controller extends ControllerFns<Controller>>(controller: Controller): {
|
|
32
|
-
(m: keyof ControllerHandlerFns<Controller>): RequestHandler<unknown>;
|
|
33
|
-
(m: keyof ControllerErrorFns<Controller>): ErrorHandler<unknown>;
|
|
34
|
-
};
|
|
35
|
-
constructor(controller: Controller);
|
|
36
|
-
bind(m: keyof ControllerHandlerFns<Controller>): RequestHandler<unknown>;
|
|
37
|
-
bind(m: keyof ControllerErrorFns<Controller>): ErrorHandler<unknown>;
|
|
38
|
-
}
|
|
39
|
-
export {};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
const safeResolve = (fn, ...args) => {
|
|
2
|
-
try {
|
|
3
|
-
return Promise.resolve(fn(...args));
|
|
4
|
-
}
|
|
5
|
-
catch (reason) {
|
|
6
|
-
return Promise.reject(reason);
|
|
7
|
-
}
|
|
8
|
-
};
|
|
9
|
-
export const as = (x) => x;
|
|
10
|
-
export function asyncHandler(fn) {
|
|
11
|
-
switch (fn.length) {
|
|
12
|
-
case 2:
|
|
13
|
-
case 3: return (req, res, next) => safeResolve(fn, req, res, next).catch(next);
|
|
14
|
-
case 4: return (error, req, res, next) => safeResolve(fn, error, req, res, next).catch(next);
|
|
15
|
-
default: return (...args) => {
|
|
16
|
-
const next = args.pop();
|
|
17
|
-
return safeResolve(fn, ...args, next).catch(next);
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export function boundAsyncHandler(x, m) {
|
|
22
|
-
return asyncHandler(as(x[m]).bind(x));
|
|
23
|
-
}
|
|
24
|
-
export class AsyncBinder {
|
|
25
|
-
controller;
|
|
26
|
-
static for(controller) {
|
|
27
|
-
const self = new AsyncBinder(controller);
|
|
28
|
-
return self.bind.bind(self);
|
|
29
|
-
}
|
|
30
|
-
constructor(controller) {
|
|
31
|
-
this.controller = controller;
|
|
32
|
-
}
|
|
33
|
-
bind(m) {
|
|
34
|
-
const x = this.controller;
|
|
35
|
-
return asyncHandler(as(x[m]).bind(x));
|
|
36
|
-
}
|
|
37
|
-
}
|