glasswork 0.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.
- package/LICENSE +21 -0
- package/README.md +182 -0
- package/dist/bootstrap.d.ts +55 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +359 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/core/bootstrap.d.ts +55 -0
- package/dist/core/bootstrap.d.ts.map +1 -0
- package/dist/core/bootstrap.js +329 -0
- package/dist/core/bootstrap.js.map +1 -0
- package/dist/core/module.d.ts +21 -0
- package/dist/core/module.d.ts.map +1 -0
- package/dist/core/module.js +85 -0
- package/dist/core/module.js.map +1 -0
- package/dist/core/types.d.ts +273 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/environment.d.ts +21 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +29 -0
- package/dist/environment.js.map +1 -0
- package/dist/error-handler.d.ts +33 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +53 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +65 -0
- package/dist/errors.js.map +1 -0
- package/dist/get-client-ip.d.ts +24 -0
- package/dist/get-client-ip.d.ts.map +1 -0
- package/dist/get-client-ip.js +49 -0
- package/dist/get-client-ip.js.map +1 -0
- package/dist/http/error-handler.d.ts +33 -0
- package/dist/http/error-handler.d.ts.map +1 -0
- package/dist/http/error-handler.js +55 -0
- package/dist/http/error-handler.js.map +1 -0
- package/dist/http/errors.d.ts +36 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/http/errors.js +65 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/http/route-helpers.d.ts +172 -0
- package/dist/http/route-helpers.d.ts.map +1 -0
- package/dist/http/route-helpers.js +249 -0
- package/dist/http/route-helpers.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +37 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +52 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +7 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +182 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/module.d.ts +21 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +85 -0
- package/dist/module.js.map +1 -0
- package/dist/omit.d.ts +20 -0
- package/dist/omit.d.ts.map +1 -0
- package/dist/omit.js +28 -0
- package/dist/omit.js.map +1 -0
- package/dist/openapi/defaults.d.ts +11 -0
- package/dist/openapi/defaults.d.ts.map +1 -0
- package/dist/openapi/defaults.js +127 -0
- package/dist/openapi/defaults.js.map +1 -0
- package/dist/openapi/hooks.d.ts +14 -0
- package/dist/openapi/hooks.d.ts.map +1 -0
- package/dist/openapi/hooks.js +80 -0
- package/dist/openapi/hooks.js.map +1 -0
- package/dist/openapi/openapi.d.ts +24 -0
- package/dist/openapi/openapi.d.ts.map +1 -0
- package/dist/openapi/openapi.js +108 -0
- package/dist/openapi/openapi.js.map +1 -0
- package/dist/openapi-defaults.d.ts +11 -0
- package/dist/openapi-defaults.d.ts.map +1 -0
- package/dist/openapi-defaults.js +127 -0
- package/dist/openapi-defaults.js.map +1 -0
- package/dist/openapi-hooks.d.ts +14 -0
- package/dist/openapi-hooks.d.ts.map +1 -0
- package/dist/openapi-hooks.js +80 -0
- package/dist/openapi-hooks.js.map +1 -0
- package/dist/openapi.d.ts +24 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +106 -0
- package/dist/openapi.js.map +1 -0
- package/dist/pagination.d.ts +48 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +43 -0
- package/dist/pagination.js.map +1 -0
- package/dist/pick.d.ts +20 -0
- package/dist/pick.d.ts.map +1 -0
- package/dist/pick.js +28 -0
- package/dist/pick.js.map +1 -0
- package/dist/rate-limit.d.ts +7 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +180 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/route-helpers.d.ts +172 -0
- package/dist/route-helpers.d.ts.map +1 -0
- package/dist/route-helpers.js +249 -0
- package/dist/route-helpers.js.map +1 -0
- package/dist/serialize-dates.d.ts +27 -0
- package/dist/serialize-dates.d.ts.map +1 -0
- package/dist/serialize-dates.js +39 -0
- package/dist/serialize-dates.js.map +1 -0
- package/dist/testing.d.ts +87 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +94 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +273 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/deep-merge.d.ts +5 -0
- package/dist/utils/deep-merge.d.ts.map +1 -0
- package/dist/utils/deep-merge.js +21 -0
- package/dist/utils/deep-merge.js.map +1 -0
- package/dist/utils/environment.d.ts +21 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +29 -0
- package/dist/utils/environment.js.map +1 -0
- package/dist/utils/get-client-ip.d.ts +24 -0
- package/dist/utils/get-client-ip.d.ts.map +1 -0
- package/dist/utils/get-client-ip.js +49 -0
- package/dist/utils/get-client-ip.js.map +1 -0
- package/dist/utils/logger.d.ts +37 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/omit.d.ts +20 -0
- package/dist/utils/omit.d.ts.map +1 -0
- package/dist/utils/omit.js +28 -0
- package/dist/utils/omit.js.map +1 -0
- package/dist/utils/pagination.d.ts +48 -0
- package/dist/utils/pagination.d.ts.map +1 -0
- package/dist/utils/pagination.js +42 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/pick.d.ts +20 -0
- package/dist/utils/pick.d.ts.map +1 -0
- package/dist/utils/pick.js +28 -0
- package/dist/utils/pick.js.map +1 -0
- package/dist/utils/serialize-dates.d.ts +27 -0
- package/dist/utils/serialize-dates.d.ts.map +1 -0
- package/dist/utils/serialize-dates.js +39 -0
- package/dist/utils/serialize-dates.js.map +1 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +31 -0
- package/dist/utils.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { HTTPException } from 'hono/http-exception';
|
|
2
|
+
import { createLogger } from '../utils/logger.js';
|
|
3
|
+
import { DomainException, getStatusCodeFromErrorCode } from './errors.js';
|
|
4
|
+
const logger = createLogger('Glasswork:ErrorHandler', true);
|
|
5
|
+
/**
|
|
6
|
+
* Default response handler - returns JSON error
|
|
7
|
+
*/
|
|
8
|
+
function defaultResponseHandler(error, context) {
|
|
9
|
+
return context.json({
|
|
10
|
+
error: error.message,
|
|
11
|
+
}, error.statusCode);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create an error handler middleware for Hono
|
|
15
|
+
*
|
|
16
|
+
* Handles:
|
|
17
|
+
* - DomainException (custom business logic exceptions)
|
|
18
|
+
* - HTTPException (Hono's built-in HTTP exceptions)
|
|
19
|
+
* - Validation errors (returns 422)
|
|
20
|
+
* - Generic errors (returns 500)
|
|
21
|
+
*/
|
|
22
|
+
export function createErrorHandler(options = {}) {
|
|
23
|
+
const { logErrors = process.env.NODE_ENV !== 'test', responseHandler = defaultResponseHandler } = options;
|
|
24
|
+
return (err, context) => {
|
|
25
|
+
let error;
|
|
26
|
+
if (err instanceof DomainException) {
|
|
27
|
+
const statusCode = getStatusCodeFromErrorCode(err.code);
|
|
28
|
+
error = { message: err.message, statusCode: statusCode };
|
|
29
|
+
if (logErrors && statusCode === 500) {
|
|
30
|
+
logger.error('DomainException with unknown code:', err);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else if (err instanceof HTTPException) {
|
|
34
|
+
error = {
|
|
35
|
+
message: err.message,
|
|
36
|
+
statusCode: err.status,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
if (logErrors) {
|
|
41
|
+
logger.error('Unhandled error:', err);
|
|
42
|
+
}
|
|
43
|
+
error = {
|
|
44
|
+
message: 'Internal server error',
|
|
45
|
+
statusCode: 500,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return responseHandler(error, context);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Default error handler instance
|
|
53
|
+
*/
|
|
54
|
+
export const defaultErrorHandler = createErrorHandler();
|
|
55
|
+
//# sourceMappingURL=error-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/http/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAE1E,MAAM,MAAM,GAAG,YAAY,CAAC,wBAAwB,EAAE,IAAI,CAAC,CAAC;AAmB5D;;GAEG;AACH,SAAS,sBAAsB,CAAC,KAAqB,EAAE,OAAgB;IACrE,OAAO,OAAO,CAAC,IAAI,CACjB;QACE,KAAK,EAAE,KAAK,CAAC,OAAO;KACrB,EACD,KAAK,CAAC,UAAU,CACjB,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAA+B,EAAE;IAClE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,eAAe,GAAG,sBAAsB,EAAE,GAC7F,OAAO,CAAC;IAEV,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;QACtB,IAAI,KAAqB,CAAC;QAE1B,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,0BAA0B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACxD,KAAK,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,UAAkC,EAAE,CAAC;YAEjF,IAAI,SAAS,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;gBACpC,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACxC,KAAK,GAAG;gBACN,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,UAAU,EAAE,GAAG,CAAC,MAAM;aACvB,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;YACxC,CAAC;YACD,KAAK,GAAG;gBACN,OAAO,EAAE,uBAAuB;gBAChC,UAAU,EAAE,GAAG;aAChB,CAAC;QACJ,CAAC;QAED,OAAO,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base domain exception class for business logic errors
|
|
3
|
+
*/
|
|
4
|
+
export declare class DomainException extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
constructor(message: string, code: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Standard HTTP exception classes
|
|
10
|
+
*/
|
|
11
|
+
export declare class ValidationException extends DomainException {
|
|
12
|
+
constructor(message?: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class UnauthorizedException extends DomainException {
|
|
15
|
+
constructor(message?: string);
|
|
16
|
+
}
|
|
17
|
+
export declare class NotFoundException extends DomainException {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
export declare class ConflictException extends DomainException {
|
|
21
|
+
constructor(message?: string);
|
|
22
|
+
}
|
|
23
|
+
export declare class ForbiddenException extends DomainException {
|
|
24
|
+
constructor(message?: string);
|
|
25
|
+
}
|
|
26
|
+
export declare class BadRequestException extends DomainException {
|
|
27
|
+
constructor(message?: string);
|
|
28
|
+
}
|
|
29
|
+
export declare class TooManyRequestsException extends DomainException {
|
|
30
|
+
constructor(message?: string);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Map error codes to HTTP status codes
|
|
34
|
+
*/
|
|
35
|
+
export declare function getStatusCodeFromErrorCode(code: string): number;
|
|
36
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/http/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aAGtB,IAAI,EAAE,MAAM;gBAD5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM;CAK/B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,eAAe;gBAC1C,OAAO,SAAqB;CAGzC;AAED,qBAAa,qBAAsB,SAAQ,eAAe;gBAC5C,OAAO,SAAiB;CAGrC;AAED,qBAAa,iBAAkB,SAAQ,eAAe;gBACxC,OAAO,SAAc;CAGlC;AAED,qBAAa,iBAAkB,SAAQ,eAAe;gBACxC,OAAO,SAAa;CAGjC;AAED,qBAAa,kBAAmB,SAAQ,eAAe;gBACzC,OAAO,SAAc;CAGlC;AAED,qBAAa,mBAAoB,SAAQ,eAAe;gBAC1C,OAAO,SAAgB;CAGpC;AAED,qBAAa,wBAAyB,SAAQ,eAAe;gBAC/C,OAAO,SAAsB;CAG1C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY/D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base domain exception class for business logic errors
|
|
3
|
+
*/
|
|
4
|
+
export class DomainException extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(message, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = this.constructor.name;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Standard HTTP exception classes
|
|
14
|
+
*/
|
|
15
|
+
export class ValidationException extends DomainException {
|
|
16
|
+
constructor(message = 'Validation error') {
|
|
17
|
+
super(message, 'VALIDATION_ERROR');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class UnauthorizedException extends DomainException {
|
|
21
|
+
constructor(message = 'Unauthorized') {
|
|
22
|
+
super(message, 'UNAUTHORIZED');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class NotFoundException extends DomainException {
|
|
26
|
+
constructor(message = 'Not found') {
|
|
27
|
+
super(message, 'NOT_FOUND');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class ConflictException extends DomainException {
|
|
31
|
+
constructor(message = 'Conflict') {
|
|
32
|
+
super(message, 'CONFLICT');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class ForbiddenException extends DomainException {
|
|
36
|
+
constructor(message = 'Forbidden') {
|
|
37
|
+
super(message, 'FORBIDDEN');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class BadRequestException extends DomainException {
|
|
41
|
+
constructor(message = 'Bad request') {
|
|
42
|
+
super(message, 'BAD_REQUEST');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export class TooManyRequestsException extends DomainException {
|
|
46
|
+
constructor(message = 'Too many requests') {
|
|
47
|
+
super(message, 'TOO_MANY_REQUESTS');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Map error codes to HTTP status codes
|
|
52
|
+
*/
|
|
53
|
+
export function getStatusCodeFromErrorCode(code) {
|
|
54
|
+
const codeMap = {
|
|
55
|
+
BAD_REQUEST: 400,
|
|
56
|
+
UNAUTHORIZED: 401,
|
|
57
|
+
FORBIDDEN: 403,
|
|
58
|
+
NOT_FOUND: 404,
|
|
59
|
+
CONFLICT: 409,
|
|
60
|
+
VALIDATION_ERROR: 422,
|
|
61
|
+
TOO_MANY_REQUESTS: 429,
|
|
62
|
+
};
|
|
63
|
+
return codeMap[code] || 500;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/http/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAGtB;IAFlB,YACE,OAAe,EACC,IAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IACpC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,eAAe;IACtD,YAAY,OAAO,GAAG,kBAAkB;QACtC,KAAK,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,eAAe;IACxD,YAAY,OAAO,GAAG,cAAc;QAClC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACjC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,eAAe;IACpD,YAAY,OAAO,GAAG,WAAW;QAC/B,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,eAAe;IACpD,YAAY,OAAO,GAAG,UAAU;QAC9B,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,eAAe;IACrD,YAAY,OAAO,GAAG,WAAW;QAC/B,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,eAAe;IACtD,YAAY,OAAO,GAAG,aAAa;QACjC,KAAK,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,eAAe;IAC3D,YAAY,OAAO,GAAG,mBAAmB;QACvC,KAAK,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACtC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,MAAM,OAAO,GAA2B;QACtC,WAAW,EAAE,GAAG;QAChB,YAAY,EAAE,GAAG;QACjB,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;QACd,QAAQ,EAAE,GAAG;QACb,gBAAgB,EAAE,GAAG;QACrB,iBAAiB,EAAE,GAAG;KACvB,CAAC;IAEF,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Context, Hono, MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { DescribeRouteOptions } from 'hono-openapi';
|
|
3
|
+
import type { BaseIssue, BaseSchema, BaseSchemaAsync, InferOutput } from 'valibot';
|
|
4
|
+
import type { OpenAPIResponseHook } from '../core/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Set the global OpenAPI response hooks.
|
|
7
|
+
* This is called during bootstrap and makes hooks available to route definitions.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function setGlobalResponseHooks(hooks: OpenAPIResponseHook[]): void;
|
|
12
|
+
/**
|
|
13
|
+
* Get the current global OpenAPI response hooks.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare function getGlobalResponseHooks(): OpenAPIResponseHook[];
|
|
18
|
+
/**
|
|
19
|
+
* Valibot schema type (compatible with both sync and async schemas)
|
|
20
|
+
*/
|
|
21
|
+
export type ValibotSchema = BaseSchema<unknown, unknown, BaseIssue<unknown>> | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>;
|
|
22
|
+
/**
|
|
23
|
+
* Helper type to infer the output type from a Valibot schema
|
|
24
|
+
*/
|
|
25
|
+
type InferSchemaType<T> = T extends ValibotSchema ? InferOutput<T> : never;
|
|
26
|
+
/**
|
|
27
|
+
* Helper type to infer the response type from the 200/201 status code schema
|
|
28
|
+
*
|
|
29
|
+
* Prisma client extension converts Date → string at the database layer,
|
|
30
|
+
* so handlers return string-based entities that match the response schema output type.
|
|
31
|
+
*/
|
|
32
|
+
type InferResponseType<T> = T extends {
|
|
33
|
+
200: infer TSchema;
|
|
34
|
+
} ? TSchema extends ValibotSchema ? InferOutput<TSchema> : unknown : T extends {
|
|
35
|
+
201: infer TSchema;
|
|
36
|
+
} ? TSchema extends ValibotSchema ? InferOutput<TSchema> : unknown : unknown;
|
|
37
|
+
/**
|
|
38
|
+
* HTTP status codes with descriptions
|
|
39
|
+
*/
|
|
40
|
+
declare const STATUS_DESCRIPTIONS: {
|
|
41
|
+
readonly 200: "Success";
|
|
42
|
+
readonly 201: "Created";
|
|
43
|
+
readonly 204: "No Content";
|
|
44
|
+
readonly 400: "Bad Request";
|
|
45
|
+
readonly 401: "Unauthorized";
|
|
46
|
+
readonly 403: "Forbidden";
|
|
47
|
+
readonly 404: "Not Found";
|
|
48
|
+
readonly 409: "Conflict";
|
|
49
|
+
readonly 422: "Unprocessable Entity";
|
|
50
|
+
readonly 429: "Too Many Requests";
|
|
51
|
+
readonly 500: "Internal Server Error";
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Route factory function type.
|
|
55
|
+
* Receives a real Hono instance and services from DI container.
|
|
56
|
+
*/
|
|
57
|
+
export type RouteFactory = (router: Hono, services: Record<string, unknown>) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Create routes with typed service injection.
|
|
60
|
+
*
|
|
61
|
+
* @template TServices - The shape of services required by these routes
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* interface AuthRoutesServices {
|
|
66
|
+
* authService: AuthService;
|
|
67
|
+
* userService: UserService;
|
|
68
|
+
* }
|
|
69
|
+
*
|
|
70
|
+
* export const authRoutes = createRoutes<AuthRoutesServices>((router, services) => {
|
|
71
|
+
* // services.authService is typed as AuthService!
|
|
72
|
+
* // services.userService is typed as UserService!
|
|
73
|
+
* router.post('/login', ...);
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function createRoutes<TServices = Record<string, unknown>>(factory: (router: Hono, services: TServices) => void): RouteFactory;
|
|
78
|
+
/**
|
|
79
|
+
* Route configuration with automatic type inference from Valibot schemas
|
|
80
|
+
*
|
|
81
|
+
* @template TBody - The body schema (automatically inferred)
|
|
82
|
+
* @template TResponses - The responses object (automatically inferred)
|
|
83
|
+
*/
|
|
84
|
+
export interface RouteConfig<TBody extends ValibotSchema | undefined = undefined, TResponses extends Partial<Record<keyof typeof STATUS_DESCRIPTIONS, ValibotSchema | undefined>> = Record<never, never>, TPublic extends boolean = false> {
|
|
85
|
+
tags?: string[];
|
|
86
|
+
summary?: string;
|
|
87
|
+
description?: string;
|
|
88
|
+
operationId?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Whether this is a public route (no authentication required)
|
|
91
|
+
* - false (default): Session is required and typed as non-nullable
|
|
92
|
+
* - true: Session is optional and typed as nullable
|
|
93
|
+
*/
|
|
94
|
+
public?: TPublic;
|
|
95
|
+
body?: TBody;
|
|
96
|
+
query?: ValibotSchema;
|
|
97
|
+
params?: ValibotSchema;
|
|
98
|
+
responses?: TResponses;
|
|
99
|
+
openapi?: Partial<Omit<DescribeRouteOptions, 'responses' | 'operationId' | 'tags' | 'summary' | 'description'>>;
|
|
100
|
+
/**
|
|
101
|
+
* Custom middleware to apply before validation and handler
|
|
102
|
+
*/
|
|
103
|
+
middleware?: MiddlewareHandler[];
|
|
104
|
+
/**
|
|
105
|
+
* Enable pagination - adds pagination query params and response headers to OpenAPI spec
|
|
106
|
+
*/
|
|
107
|
+
paginate?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Route handler - body and return types are automatically inferred from schemas
|
|
110
|
+
* Session is required by default (unless public: true)
|
|
111
|
+
*
|
|
112
|
+
* Prisma client extension converts Date → string at the database layer,
|
|
113
|
+
* so handler return types match the response schema output type.
|
|
114
|
+
*/
|
|
115
|
+
handler: (context: RouteContext<TBody extends ValibotSchema ? InferSchemaType<TBody> : never, TPublic extends true ? false : true>) => Promise<InferResponseType<TResponses>> | InferResponseType<TResponses>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Route handler context with typed body
|
|
119
|
+
*
|
|
120
|
+
* Leverages Hono's ContextVariableMap for session typing.
|
|
121
|
+
* If your middleware extends ContextVariableMap (e.g., auth middleware),
|
|
122
|
+
* the session will be automatically typed in route handlers.
|
|
123
|
+
*
|
|
124
|
+
* @template TBody - The typed body (inferred from schema)
|
|
125
|
+
* @template TSessionRequired - Whether session is guaranteed to exist (true by default, false for public routes)
|
|
126
|
+
*/
|
|
127
|
+
export interface RouteContext<TBody = never, TSessionRequired extends boolean = true> {
|
|
128
|
+
body: TBody;
|
|
129
|
+
query: Record<string, string>;
|
|
130
|
+
params: Record<string, string>;
|
|
131
|
+
services: Record<string, unknown>;
|
|
132
|
+
/**
|
|
133
|
+
* Session from context variables (typed via Hono's ContextVariableMap)
|
|
134
|
+
* - Required by default (for authenticated routes)
|
|
135
|
+
* - Optional only for public routes (public: true)
|
|
136
|
+
*/
|
|
137
|
+
session: TSessionRequired extends true ? NonNullable<Context['var']['session']> : Context['var']['session'];
|
|
138
|
+
/**
|
|
139
|
+
* Client IP address (extracted from headers and connection info)
|
|
140
|
+
*/
|
|
141
|
+
ip: string;
|
|
142
|
+
/**
|
|
143
|
+
* User agent string from request headers
|
|
144
|
+
*/
|
|
145
|
+
userAgent: string | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* Original Hono context (for advanced use cases)
|
|
148
|
+
*/
|
|
149
|
+
context: Context;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a route handler with validation and OpenAPI metadata.
|
|
153
|
+
*
|
|
154
|
+
* Type inference works automatically:
|
|
155
|
+
* - Body type is inferred from the `body` schema
|
|
156
|
+
* - Return type is inferred from the `responses[200]` schema
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* route({
|
|
161
|
+
* body: StartSessionDto,
|
|
162
|
+
* responses: { 200: StartSessionResponseDto },
|
|
163
|
+
* handler: async ({ body }) => {
|
|
164
|
+
* // body is typed as InferOutput<typeof StartSessionDto>
|
|
165
|
+
* return { email: body.email }; // Must match StartSessionResponseDto
|
|
166
|
+
* }
|
|
167
|
+
* })
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export declare function route<TBody extends ValibotSchema | undefined = undefined, TResponses extends Partial<Record<keyof typeof STATUS_DESCRIPTIONS, ValibotSchema | undefined>> = Record<never, never>, TPublic extends boolean = false>(config: RouteConfig<TBody, TResponses, TPublic>): MiddlewareHandler[];
|
|
171
|
+
export {};
|
|
172
|
+
//# sourceMappingURL=route-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../src/http/route-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { describeRoute as honoDescribeRoute } from 'hono-openapi';
|
|
2
|
+
import { resolver, validator } from 'hono-openapi/valibot';
|
|
3
|
+
import { getClientIp } from '../utils/get-client-ip.js';
|
|
4
|
+
/**
|
|
5
|
+
* Global storage for OpenAPI response hooks.
|
|
6
|
+
* Set during bootstrap and used when defining routes.
|
|
7
|
+
*/
|
|
8
|
+
let globalResponseHooks = [];
|
|
9
|
+
/**
|
|
10
|
+
* Set the global OpenAPI response hooks.
|
|
11
|
+
* This is called during bootstrap and makes hooks available to route definitions.
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export function setGlobalResponseHooks(hooks) {
|
|
16
|
+
globalResponseHooks = hooks;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the current global OpenAPI response hooks.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export function getGlobalResponseHooks() {
|
|
24
|
+
return globalResponseHooks;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* HTTP status codes with descriptions
|
|
28
|
+
*/
|
|
29
|
+
const STATUS_DESCRIPTIONS = {
|
|
30
|
+
200: 'Success',
|
|
31
|
+
201: 'Created',
|
|
32
|
+
204: 'No Content',
|
|
33
|
+
400: 'Bad Request',
|
|
34
|
+
401: 'Unauthorized',
|
|
35
|
+
403: 'Forbidden',
|
|
36
|
+
404: 'Not Found',
|
|
37
|
+
409: 'Conflict',
|
|
38
|
+
422: 'Unprocessable Entity',
|
|
39
|
+
429: 'Too Many Requests',
|
|
40
|
+
500: 'Internal Server Error',
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Create routes with typed service injection.
|
|
44
|
+
*
|
|
45
|
+
* @template TServices - The shape of services required by these routes
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* interface AuthRoutesServices {
|
|
50
|
+
* authService: AuthService;
|
|
51
|
+
* userService: UserService;
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* export const authRoutes = createRoutes<AuthRoutesServices>((router, services) => {
|
|
55
|
+
* // services.authService is typed as AuthService!
|
|
56
|
+
* // services.userService is typed as UserService!
|
|
57
|
+
* router.post('/login', ...);
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function createRoutes(factory) {
|
|
62
|
+
return factory;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a route handler with validation and OpenAPI metadata.
|
|
66
|
+
*
|
|
67
|
+
* Type inference works automatically:
|
|
68
|
+
* - Body type is inferred from the `body` schema
|
|
69
|
+
* - Return type is inferred from the `responses[200]` schema
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* route({
|
|
74
|
+
* body: StartSessionDto,
|
|
75
|
+
* responses: { 200: StartSessionResponseDto },
|
|
76
|
+
* handler: async ({ body }) => {
|
|
77
|
+
* // body is typed as InferOutput<typeof StartSessionDto>
|
|
78
|
+
* return { email: body.email }; // Must match StartSessionResponseDto
|
|
79
|
+
* }
|
|
80
|
+
* })
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function route(config) {
|
|
84
|
+
const middlewares = [];
|
|
85
|
+
// Add OpenAPI metadata
|
|
86
|
+
middlewares.push(buildOpenAPIMiddleware(config));
|
|
87
|
+
// Add custom middleware (e.g., auth) before validation
|
|
88
|
+
if (config.middleware) {
|
|
89
|
+
middlewares.push(...config.middleware);
|
|
90
|
+
}
|
|
91
|
+
// Add validation middleware with custom error handler (returns 422 instead of 400)
|
|
92
|
+
if (config.body) {
|
|
93
|
+
middlewares.push(validator('json', config.body, (result, c) => {
|
|
94
|
+
if (!result.success) {
|
|
95
|
+
return c.json({ error: 'Validation failed', issues: result.issues }, 422);
|
|
96
|
+
}
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
if (config.query) {
|
|
100
|
+
middlewares.push(validator('query', config.query, (result, c) => {
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
return c.json({ error: 'Validation failed', issues: result.issues }, 422);
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
if (config.params) {
|
|
107
|
+
middlewares.push(validator('param', config.params, (result, c) => {
|
|
108
|
+
if (!result.success) {
|
|
109
|
+
return c.json({ error: 'Validation failed', issues: result.issues }, 422);
|
|
110
|
+
}
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
// Add handler wrapper
|
|
114
|
+
middlewares.push(async (c) => {
|
|
115
|
+
const routeContext = buildRouteContext(c);
|
|
116
|
+
const result = await config.handler(
|
|
117
|
+
// @ts-expect-error - Session typing issue to be resolved separately
|
|
118
|
+
routeContext);
|
|
119
|
+
// If handler returned a Response, return it directly (for custom responses like text)
|
|
120
|
+
if (result instanceof Response) {
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
// Return appropriate response
|
|
124
|
+
if (result === null || result === undefined) {
|
|
125
|
+
c.status(204);
|
|
126
|
+
return c.body(null);
|
|
127
|
+
}
|
|
128
|
+
return c.json(result);
|
|
129
|
+
});
|
|
130
|
+
return middlewares;
|
|
131
|
+
}
|
|
132
|
+
function buildOpenAPIMiddleware(config) {
|
|
133
|
+
const responses = buildOpenAPIResponses(config);
|
|
134
|
+
const openApiConfig = {
|
|
135
|
+
operationId: config.operationId || config.summary,
|
|
136
|
+
tags: config.tags,
|
|
137
|
+
summary: config.summary,
|
|
138
|
+
description: config.description,
|
|
139
|
+
responses: responses,
|
|
140
|
+
security: config.public ? [] : [{ bearerAuth: [] }],
|
|
141
|
+
...(config.paginate && { parameters: buildPaginationParameters() }),
|
|
142
|
+
...config.openapi,
|
|
143
|
+
};
|
|
144
|
+
return honoDescribeRoute(openApiConfig);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build pagination parameters for OpenAPI spec
|
|
148
|
+
*/
|
|
149
|
+
function buildPaginationParameters() {
|
|
150
|
+
return [
|
|
151
|
+
{
|
|
152
|
+
name: 'page',
|
|
153
|
+
in: 'query',
|
|
154
|
+
required: false,
|
|
155
|
+
schema: {
|
|
156
|
+
type: 'integer',
|
|
157
|
+
format: 'int32',
|
|
158
|
+
minimum: 1,
|
|
159
|
+
maximum: 2147483647, // Max int32
|
|
160
|
+
default: 1,
|
|
161
|
+
},
|
|
162
|
+
description: 'Page number',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'limit',
|
|
166
|
+
in: 'query',
|
|
167
|
+
required: false,
|
|
168
|
+
schema: {
|
|
169
|
+
type: 'integer',
|
|
170
|
+
format: 'int32',
|
|
171
|
+
minimum: 1,
|
|
172
|
+
maximum: 100,
|
|
173
|
+
default: 50,
|
|
174
|
+
},
|
|
175
|
+
description: 'Number of items per page',
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
}
|
|
179
|
+
function buildOpenAPIResponses(config) {
|
|
180
|
+
const responses = {};
|
|
181
|
+
// Add default error responses
|
|
182
|
+
const defaultResponses = config.public
|
|
183
|
+
? { 400: undefined, 429: undefined, 500: undefined }
|
|
184
|
+
: { 400: undefined, 401: undefined, 429: undefined, 500: undefined };
|
|
185
|
+
const allResponses = { ...defaultResponses, ...(config.responses || {}) };
|
|
186
|
+
// Get global hooks
|
|
187
|
+
const hooks = getGlobalResponseHooks();
|
|
188
|
+
for (const [statusCode, schema] of Object.entries(allResponses)) {
|
|
189
|
+
const code = Number(statusCode);
|
|
190
|
+
const description = STATUS_DESCRIPTIONS[code] || 'Response';
|
|
191
|
+
// Determine if this is an error response that should use default error schema
|
|
192
|
+
const isErrorResponse = code >= 400;
|
|
193
|
+
const shouldUseDefaultErrorSchema = isErrorResponse && !schema;
|
|
194
|
+
// Start with base response (no headers)
|
|
195
|
+
let response = {
|
|
196
|
+
description,
|
|
197
|
+
...(schema
|
|
198
|
+
? {
|
|
199
|
+
content: {
|
|
200
|
+
'application/json': {
|
|
201
|
+
// resolver type only supports BaseSchema, but works with BaseSchemaAsync at runtime
|
|
202
|
+
// @ts-expect-error - resolver accepts both BaseSchema and BaseSchemaAsync
|
|
203
|
+
schema: resolver(schema, { errorMode: 'ignore' }),
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
}
|
|
207
|
+
: shouldUseDefaultErrorSchema
|
|
208
|
+
? {
|
|
209
|
+
content: {
|
|
210
|
+
'application/json': {
|
|
211
|
+
schema: {
|
|
212
|
+
$ref: '#/components/schemas/ErrorResponse',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
}
|
|
217
|
+
: {}),
|
|
218
|
+
};
|
|
219
|
+
// Apply hooks to build up headers
|
|
220
|
+
for (const hook of hooks) {
|
|
221
|
+
response = hook(response, {
|
|
222
|
+
statusCode,
|
|
223
|
+
routeConfig: {
|
|
224
|
+
public: config.public,
|
|
225
|
+
paginate: config.paginate,
|
|
226
|
+
tags: config.tags,
|
|
227
|
+
summary: config.summary,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
responses[statusCode] = response;
|
|
232
|
+
}
|
|
233
|
+
return responses;
|
|
234
|
+
}
|
|
235
|
+
function buildRouteContext(c) {
|
|
236
|
+
const req = c.req;
|
|
237
|
+
return {
|
|
238
|
+
body: req.valid('json'),
|
|
239
|
+
query: req.valid('query'),
|
|
240
|
+
params: req.valid('param'),
|
|
241
|
+
services: c.get('services') || {},
|
|
242
|
+
// @ts-expect-error - Session typing issue to be resolved separately
|
|
243
|
+
session: c.get('session'),
|
|
244
|
+
ip: getClientIp(c),
|
|
245
|
+
userAgent: c.req.header('user-agent'),
|
|
246
|
+
context: c,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=route-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-helpers.js","sourceRoot":"","sources":["../../src/http/route-helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glasswork - A transparent, Lambda-optimized web framework
|
|
3
|
+
*
|
|
4
|
+
* Built on Hono, Awilix, and Prisma with the principle of "Enhance, Don't Replace"
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
export type { AwilixContainer } from 'awilix';
|
|
9
|
+
export type { ErrorHandler, Hono } from 'hono';
|
|
10
|
+
export type { OpenAPIV3 } from 'openapi-types';
|
|
11
|
+
export { bootstrap } from './core/bootstrap.js';
|
|
12
|
+
export { defineModule } from './core/module.js';
|
|
13
|
+
export type { BootstrapOptions, BootstrapResult, Constructor, Environment, LoggerOptions, MiddlewareOptions, ModuleConfig, OpenAPIDocumentation, OpenAPIOptions, OpenAPIResponseHook, ProviderConfig, RateLimitOptions, RateLimitStorage, ServiceScope, } from './core/types.js';
|
|
14
|
+
export { createErrorHandler, defaultErrorHandler } from './http/error-handler.js';
|
|
15
|
+
export { BadRequestException, ConflictException, DomainException, ForbiddenException, NotFoundException, TooManyRequestsException, UnauthorizedException, ValidationException, } from './http/errors.js';
|
|
16
|
+
export type { RouteConfig, RouteContext, RouteFactory, ValibotSchema, } from './http/route-helpers.js';
|
|
17
|
+
export { createRoutes, route } from './http/route-helpers.js';
|
|
18
|
+
export { createRateLimitMiddleware } from './middleware/rate-limit.js';
|
|
19
|
+
export { defaultOpenAPIComponents } from './openapi/defaults.js';
|
|
20
|
+
export { createCorsHeadersHook, createPaginationHeadersHook, createRateLimitHeadersHook, } from './openapi/hooks.js';
|
|
21
|
+
export { configureOpenAPI } from './openapi/openapi.js';
|
|
22
|
+
export { deepMerge } from './utils/deep-merge.js';
|
|
23
|
+
export { isDevelopment, isLambda, isProduction, isTest } from './utils/environment.js';
|
|
24
|
+
export { getClientIp } from './utils/get-client-ip.js';
|
|
25
|
+
export type { Logger } from './utils/logger.js';
|
|
26
|
+
export { createLogger, createPlainLogger, defaultLogger } from './utils/logger.js';
|
|
27
|
+
export { omit } from './utils/omit.js';
|
|
28
|
+
export type { PaginatedOutput, PaginationInput } from './utils/pagination.js';
|
|
29
|
+
export { paginate, paginationInput } from './utils/pagination.js';
|
|
30
|
+
export { pick } from './utils/pick.js';
|
|
31
|
+
export type { SerializedDates } from './utils/serialize-dates.js';
|
|
32
|
+
export { serializeDates } from './utils/serialize-dates.js';
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC/C,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,WAAW,EACX,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|