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
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
// Core framework
|
|
9
|
+
export { bootstrap } from './core/bootstrap.js';
|
|
10
|
+
export { defineModule } from './core/module.js';
|
|
11
|
+
export { createErrorHandler, defaultErrorHandler } from './http/error-handler.js';
|
|
12
|
+
export { BadRequestException, ConflictException, DomainException, ForbiddenException, NotFoundException, TooManyRequestsException, UnauthorizedException, ValidationException, } from './http/errors.js';
|
|
13
|
+
export { createRoutes, route } from './http/route-helpers.js';
|
|
14
|
+
// Middleware
|
|
15
|
+
export { createRateLimitMiddleware } from './middleware/rate-limit.js';
|
|
16
|
+
export { defaultOpenAPIComponents } from './openapi/defaults.js';
|
|
17
|
+
export { createCorsHeadersHook, createPaginationHeadersHook, createRateLimitHeadersHook, } from './openapi/hooks.js';
|
|
18
|
+
// OpenAPI
|
|
19
|
+
export { configureOpenAPI } from './openapi/openapi.js';
|
|
20
|
+
export { deepMerge } from './utils/deep-merge.js';
|
|
21
|
+
// Utilities
|
|
22
|
+
export { isDevelopment, isLambda, isProduction, isTest } from './utils/environment.js';
|
|
23
|
+
export { getClientIp } from './utils/get-client-ip.js';
|
|
24
|
+
export { createLogger, createPlainLogger, defaultLogger } from './utils/logger.js';
|
|
25
|
+
export { omit } from './utils/omit.js';
|
|
26
|
+
export { paginate, paginationInput } from './utils/pagination.js';
|
|
27
|
+
export { pick } from './utils/pick.js';
|
|
28
|
+
export { serializeDates } from './utils/serialize-dates.js';
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAiBhD,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;AAQ1B,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAC9D,aAAa;AACb,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;AAC5B,UAAU;AACV,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,YAAY;AACZ,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger interface for framework and application logging
|
|
3
|
+
*/
|
|
4
|
+
export interface Logger {
|
|
5
|
+
debug(message: string, ...meta: unknown[]): void;
|
|
6
|
+
info(message: string, ...meta: unknown[]): void;
|
|
7
|
+
warn(message: string, ...meta: unknown[]): void;
|
|
8
|
+
error(message: string, ...meta: unknown[]): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Default console logger (used by framework internally)
|
|
12
|
+
*/
|
|
13
|
+
export declare const defaultLogger: Logger;
|
|
14
|
+
/**
|
|
15
|
+
* Create a logger with a prefix for namespacing
|
|
16
|
+
*
|
|
17
|
+
* @param prefix - Prefix to add to all log messages
|
|
18
|
+
* @param enabled - Whether logging is enabled (default: true)
|
|
19
|
+
* @returns Logger instance
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const logger = createLogger('MyService', debug);
|
|
24
|
+
* logger.info('Starting service'); // [MyService] Starting service
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function createLogger(prefix: string, enabled?: boolean): Logger;
|
|
28
|
+
/**
|
|
29
|
+
* Create a plain logger middleware for Lambda (strips ANSI color codes).
|
|
30
|
+
*
|
|
31
|
+
* CloudWatch Logs doesn't render ANSI colors well, so this middleware
|
|
32
|
+
* strips them for cleaner logs in production.
|
|
33
|
+
*
|
|
34
|
+
* @returns Hono logger middleware with ANSI codes stripped
|
|
35
|
+
*/
|
|
36
|
+
export declare function createPlainLogger(): import("hono").MiddlewareHandler;
|
|
37
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAK3B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,MAAM,CAYnE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,qCAQhC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { logger as honoLogger } from 'hono/logger';
|
|
2
|
+
/**
|
|
3
|
+
* Default console logger (used by framework internally)
|
|
4
|
+
*/
|
|
5
|
+
export const defaultLogger = {
|
|
6
|
+
debug: console.debug.bind(console),
|
|
7
|
+
info: console.log.bind(console),
|
|
8
|
+
warn: console.warn.bind(console),
|
|
9
|
+
error: console.error.bind(console),
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Create a logger with a prefix for namespacing
|
|
13
|
+
*
|
|
14
|
+
* @param prefix - Prefix to add to all log messages
|
|
15
|
+
* @param enabled - Whether logging is enabled (default: true)
|
|
16
|
+
* @returns Logger instance
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const logger = createLogger('MyService', debug);
|
|
21
|
+
* logger.info('Starting service'); // [MyService] Starting service
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function createLogger(prefix, enabled = true) {
|
|
25
|
+
if (!enabled) {
|
|
26
|
+
const noop = () => { };
|
|
27
|
+
return { debug: noop, info: noop, warn: noop, error: noop };
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
debug: (msg, ...meta) => console.debug(`[${prefix}] ${msg}`, ...meta),
|
|
31
|
+
info: (msg, ...meta) => console.log(`[${prefix}] ${msg}`, ...meta),
|
|
32
|
+
warn: (msg, ...meta) => console.warn(`[${prefix}] ${msg}`, ...meta),
|
|
33
|
+
error: (msg, ...meta) => console.error(`[${prefix}] ${msg}`, ...meta),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a plain logger middleware for Lambda (strips ANSI color codes).
|
|
38
|
+
*
|
|
39
|
+
* CloudWatch Logs doesn't render ANSI colors well, so this middleware
|
|
40
|
+
* strips them for cleaner logs in production.
|
|
41
|
+
*
|
|
42
|
+
* @returns Hono logger middleware with ANSI codes stripped
|
|
43
|
+
*/
|
|
44
|
+
export function createPlainLogger() {
|
|
45
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: we want to strip ANSI color codes
|
|
46
|
+
const stripAnsi = (input) => input.replace(/\u001B\[[0-9;]*m/g, '');
|
|
47
|
+
return honoLogger((str, ...rest) => {
|
|
48
|
+
const message = [str, ...rest].join(' ');
|
|
49
|
+
console.log(stripAnsi(message));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAYnD;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAW;IACnC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;IAClC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;CACnC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,OAAO,GAAG,IAAI;IACzD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC;QACrE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC;QAClE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,MAAM,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC;QACnE,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,KAAK,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC;KACtE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB;IAC/B,6FAA6F;IAC7F,MAAM,SAAS,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;IAEpF,OAAO,UAAU,CAAC,CAAC,GAAW,EAAE,GAAG,IAAc,EAAE,EAAE;QACnD,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { RateLimitOptions } from '../core/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create rate limiting middleware
|
|
5
|
+
*/
|
|
6
|
+
export declare function createRateLimitMiddleware(options: RateLimitOptions): MiddlewareHandler;
|
|
7
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAqKzD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,iBAAiB,CAuDtF"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { createLogger } from '../utils/logger.js';
|
|
2
|
+
const logger = createLogger('Glasswork:RateLimit', true);
|
|
3
|
+
/**
|
|
4
|
+
* In-memory rate limiter storage
|
|
5
|
+
*/
|
|
6
|
+
class MemoryStore {
|
|
7
|
+
store = new Map();
|
|
8
|
+
async get(key) {
|
|
9
|
+
const item = this.store.get(key);
|
|
10
|
+
if (!item) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
if (item.windowEnd < Date.now()) {
|
|
14
|
+
this.store.delete(key);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return item;
|
|
18
|
+
}
|
|
19
|
+
async set(key, value) {
|
|
20
|
+
this.store.set(key, value);
|
|
21
|
+
}
|
|
22
|
+
async increment(key) {
|
|
23
|
+
const item = this.store.get(key);
|
|
24
|
+
if (item) {
|
|
25
|
+
item.count += 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Cleanup expired entries periodically
|
|
29
|
+
startCleanup(intervalMs = 60000) {
|
|
30
|
+
setInterval(() => {
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
for (const [key, item] of this.store.entries()) {
|
|
33
|
+
if (item.windowEnd < now) {
|
|
34
|
+
this.store.delete(key);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, intervalMs);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* DynamoDB rate limiter storage
|
|
42
|
+
*/
|
|
43
|
+
class DynamoDBStore {
|
|
44
|
+
client;
|
|
45
|
+
tableName;
|
|
46
|
+
constructor(tableName, region) {
|
|
47
|
+
this.tableName = tableName;
|
|
48
|
+
// Lazy load AWS SDK only when needed
|
|
49
|
+
this.initClient(region);
|
|
50
|
+
}
|
|
51
|
+
async initClient(region) {
|
|
52
|
+
const { DynamoDBClient } = await import('@aws-sdk/client-dynamodb');
|
|
53
|
+
const { DynamoDBDocumentClient } = await import('@aws-sdk/lib-dynamodb');
|
|
54
|
+
const dynamoClient = new DynamoDBClient(region ? { region } : {});
|
|
55
|
+
this.client = DynamoDBDocumentClient.from(dynamoClient);
|
|
56
|
+
}
|
|
57
|
+
async get(key) {
|
|
58
|
+
const { GetCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
59
|
+
const client = this.client;
|
|
60
|
+
try {
|
|
61
|
+
// @ts-expect-error - client type is complex
|
|
62
|
+
const { Item } = await client.send(new GetCommand({
|
|
63
|
+
TableName: this.tableName,
|
|
64
|
+
Key: { bucketId: key },
|
|
65
|
+
}));
|
|
66
|
+
if (!Item || Item.windowEnd < Date.now()) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
count: Item.count,
|
|
71
|
+
windowEnd: Item.windowEnd,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async set(key, value) {
|
|
79
|
+
const { PutCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
80
|
+
const client = this.client;
|
|
81
|
+
const expiresAt = Math.floor(value.windowEnd / 1000);
|
|
82
|
+
try {
|
|
83
|
+
// @ts-expect-error - client type is complex
|
|
84
|
+
await client.send(new PutCommand({
|
|
85
|
+
TableName: this.tableName,
|
|
86
|
+
Item: {
|
|
87
|
+
bucketId: key,
|
|
88
|
+
count: value.count,
|
|
89
|
+
windowEnd: value.windowEnd,
|
|
90
|
+
expiresAt,
|
|
91
|
+
},
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
logger.error('DynamoDB rate limit set failed:', error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async increment(key) {
|
|
99
|
+
const { UpdateCommand } = await import('@aws-sdk/lib-dynamodb');
|
|
100
|
+
const client = this.client;
|
|
101
|
+
try {
|
|
102
|
+
// @ts-expect-error - client type is complex
|
|
103
|
+
await client.send(new UpdateCommand({
|
|
104
|
+
TableName: this.tableName,
|
|
105
|
+
Key: { bucketId: key },
|
|
106
|
+
UpdateExpression: 'SET #c = #c + :inc',
|
|
107
|
+
ExpressionAttributeNames: { '#c': 'count' },
|
|
108
|
+
ExpressionAttributeValues: { ':inc': 1 },
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger.error('DynamoDB rate limit increment failed:', error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Extract client IP from request context
|
|
118
|
+
*/
|
|
119
|
+
function getClientIdentifier(context) {
|
|
120
|
+
// Check various headers for client IP
|
|
121
|
+
const forwarded = context.req.header('x-forwarded-for');
|
|
122
|
+
if (forwarded) {
|
|
123
|
+
return forwarded.split(',')[0].trim();
|
|
124
|
+
}
|
|
125
|
+
const realIp = context.req.header('x-real-ip');
|
|
126
|
+
if (realIp) {
|
|
127
|
+
return realIp;
|
|
128
|
+
}
|
|
129
|
+
return 'unknown';
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create rate limiting middleware
|
|
133
|
+
*/
|
|
134
|
+
export function createRateLimitMiddleware(options) {
|
|
135
|
+
const { storage, windowMs = 60000, maxRequests = 100, dynamodb } = options;
|
|
136
|
+
// Create appropriate storage backend
|
|
137
|
+
const store = storage === 'dynamodb' && dynamodb
|
|
138
|
+
? new DynamoDBStore(dynamodb.tableName, dynamodb.region)
|
|
139
|
+
: new MemoryStore();
|
|
140
|
+
// Start cleanup for memory store
|
|
141
|
+
if (store instanceof MemoryStore) {
|
|
142
|
+
store.startCleanup();
|
|
143
|
+
}
|
|
144
|
+
return async (context, next) => {
|
|
145
|
+
const clientId = getClientIdentifier(context);
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
const windowEnd = now + windowMs;
|
|
148
|
+
const setHeaders = (remaining, resetMs) => {
|
|
149
|
+
context.header('RateLimit-Limit', String(maxRequests));
|
|
150
|
+
context.header('RateLimit-Remaining', String(Math.max(0, remaining)));
|
|
151
|
+
context.header('RateLimit-Reset', String(Math.ceil(resetMs / 1000)));
|
|
152
|
+
};
|
|
153
|
+
try {
|
|
154
|
+
const item = await store.get(clientId);
|
|
155
|
+
// New window or expired
|
|
156
|
+
if (!item) {
|
|
157
|
+
await store.set(clientId, { count: 1, windowEnd });
|
|
158
|
+
setHeaders(maxRequests - 1, windowMs);
|
|
159
|
+
await next();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Rate limit exceeded
|
|
163
|
+
if (item.count >= maxRequests) {
|
|
164
|
+
const retryMs = item.windowEnd - now;
|
|
165
|
+
setHeaders(0, retryMs);
|
|
166
|
+
context.header('Retry-After', String(Math.ceil(retryMs / 1000)));
|
|
167
|
+
return context.json({ error: 'Too Many Requests' }, 429);
|
|
168
|
+
}
|
|
169
|
+
// Increment counter
|
|
170
|
+
await store.increment(clientId);
|
|
171
|
+
setHeaders(maxRequests - (item.count + 1), item.windowEnd - now);
|
|
172
|
+
await next();
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
logger.error('Rate limiter error:', error);
|
|
176
|
+
// Fail open - allow request
|
|
177
|
+
setHeaders(maxRequests, windowMs);
|
|
178
|
+
await next();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"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"}
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ModuleConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Define a module with providers, imports, and routes.
|
|
4
|
+
*
|
|
5
|
+
* This is a pure metadata function - it just returns the configuration.
|
|
6
|
+
* The actual registration happens in the bootstrap function.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* export const AuthModule = defineModule({
|
|
11
|
+
* name: 'auth',
|
|
12
|
+
* basePath: 'auth',
|
|
13
|
+
* providers: [AuthService, UserService],
|
|
14
|
+
* imports: [CommonModule],
|
|
15
|
+
* exports: [AuthService],
|
|
16
|
+
* routes: AuthRoutes,
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function defineModule(config: ModuleConfig): ModuleConfig;
|
|
21
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,YAAY,EAAkB,MAAM,YAAY,CAAC;AAE5E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAG/D"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define a module with providers, imports, and routes.
|
|
3
|
+
*
|
|
4
|
+
* This is a pure metadata function - it just returns the configuration.
|
|
5
|
+
* The actual registration happens in the bootstrap function.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* export const AuthModule = defineModule({
|
|
10
|
+
* name: 'auth',
|
|
11
|
+
* basePath: 'auth',
|
|
12
|
+
* providers: [AuthService, UserService],
|
|
13
|
+
* imports: [CommonModule],
|
|
14
|
+
* exports: [AuthService],
|
|
15
|
+
* routes: AuthRoutes,
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function defineModule(config) {
|
|
20
|
+
validateModuleConfig(config);
|
|
21
|
+
return config;
|
|
22
|
+
}
|
|
23
|
+
function validateModuleConfig(config) {
|
|
24
|
+
validateModuleName(config.name);
|
|
25
|
+
validateProviders(config);
|
|
26
|
+
validateExports(config);
|
|
27
|
+
}
|
|
28
|
+
function validateModuleName(name) {
|
|
29
|
+
if (!name) {
|
|
30
|
+
throw new Error('Module name is required');
|
|
31
|
+
}
|
|
32
|
+
if (name.includes('/') || name.includes(' ')) {
|
|
33
|
+
throw new Error('Module name must not contain "/" or spaces');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function validateProviders(config) {
|
|
37
|
+
if (!config.providers) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const provider of config.providers) {
|
|
41
|
+
if (typeof provider !== 'function' && typeof provider !== 'object') {
|
|
42
|
+
throw new Error(`Invalid provider in module "${config.name}"`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function validateExports(config) {
|
|
47
|
+
if (!config.exports || !config.providers) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const providerNames = collectProviderNames(config.providers);
|
|
51
|
+
for (const exp of config.exports) {
|
|
52
|
+
const exportName = getProviderName(exp);
|
|
53
|
+
if (!providerNames.has(exportName)) {
|
|
54
|
+
throw new Error(`Module "${config.name}" exports "${exportName}" but it's not in providers`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function collectProviderNames(providers) {
|
|
59
|
+
const names = new Set();
|
|
60
|
+
for (const provider of providers) {
|
|
61
|
+
names.add(getProviderName(provider));
|
|
62
|
+
}
|
|
63
|
+
return names;
|
|
64
|
+
}
|
|
65
|
+
function getProviderName(provider) {
|
|
66
|
+
if (typeof provider === 'string') {
|
|
67
|
+
return provider;
|
|
68
|
+
}
|
|
69
|
+
if (typeof provider === 'function') {
|
|
70
|
+
return camelCase(provider.name);
|
|
71
|
+
}
|
|
72
|
+
if ('provide' in provider) {
|
|
73
|
+
return typeof provider.provide === 'string'
|
|
74
|
+
? provider.provide
|
|
75
|
+
: camelCase(provider.provide.name);
|
|
76
|
+
}
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert PascalCase to camelCase
|
|
81
|
+
*/
|
|
82
|
+
function camelCase(str) {
|
|
83
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAoB;IAChD,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,eAAe,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAoB;IAC7C,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,OAAO,QAAQ,KAAK,UAAU,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,MAAoB;IAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACzC,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAE7D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,IAAI,cAAc,UAAU,6BAA6B,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,SAA2B;IACvD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,QAA+C;IACtE,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,OAAO,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC1B,OAAO,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ;YACzC,CAAC,CAAC,QAAQ,CAAC,OAAO;YAClB,CAAC,CAAC,SAAS,CAAE,QAAQ,CAAC,OAAuB,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC"}
|
package/dist/omit.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a new object by omitting specified keys from the source object.
|
|
3
|
+
*
|
|
4
|
+
* This implementation preserves the object's prototype, making it suitable
|
|
5
|
+
* for use with class instances and objects with custom prototypes.
|
|
6
|
+
*
|
|
7
|
+
* @template T - The type of the source object
|
|
8
|
+
* @template K - The type of keys to omit (must be keys of T)
|
|
9
|
+
* @param object - The source object to omit keys from
|
|
10
|
+
* @param paths - Array of keys to omit from the object
|
|
11
|
+
* @returns A new object with the specified keys omitted
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const user = { id: 1, name: 'John', email: 'john@example.com', password: 'secret' };
|
|
16
|
+
* const publicUser = omit(user, ['password']); // { id: 1, name: 'John', email: 'john@example.com' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function omit<T extends object, K extends keyof T>(object: T, paths: K[]): Omit<T, K>;
|
|
20
|
+
//# sourceMappingURL=omit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omit.d.ts","sourceRoot":"","sources":["../src/omit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAU3F"}
|
package/dist/omit.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a new object by omitting specified keys from the source object.
|
|
3
|
+
*
|
|
4
|
+
* This implementation preserves the object's prototype, making it suitable
|
|
5
|
+
* for use with class instances and objects with custom prototypes.
|
|
6
|
+
*
|
|
7
|
+
* @template T - The type of the source object
|
|
8
|
+
* @template K - The type of keys to omit (must be keys of T)
|
|
9
|
+
* @param object - The source object to omit keys from
|
|
10
|
+
* @param paths - Array of keys to omit from the object
|
|
11
|
+
* @returns A new object with the specified keys omitted
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const user = { id: 1, name: 'John', email: 'john@example.com', password: 'secret' };
|
|
16
|
+
* const publicUser = omit(user, ['password']); // { id: 1, name: 'John', email: 'john@example.com' }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function omit(object, paths) {
|
|
20
|
+
const result = Object.create(Object.getPrototypeOf(object));
|
|
21
|
+
for (const key in object) {
|
|
22
|
+
if (Object.hasOwn(object, key) && !paths.includes(key)) {
|
|
23
|
+
result[key] = object[key];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=omit.js.map
|
package/dist/omit.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omit.js","sourceRoot":"","sources":["../src/omit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAsC,MAAS,EAAE,KAAU;IAC7E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAE5D,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAmB,CAAC,EAAE,CAAC;YACvE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
/**
|
|
3
|
+
* Default OpenAPI components provided by Glasswork.
|
|
4
|
+
* These include headers for features implemented by the framework:
|
|
5
|
+
* - Rate limiting headers
|
|
6
|
+
* - Pagination headers
|
|
7
|
+
* - CORS headers
|
|
8
|
+
* - Error response schemas
|
|
9
|
+
*/
|
|
10
|
+
export declare const defaultOpenAPIComponents: OpenAPIV3.ComponentsObject;
|
|
11
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/openapi/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,CAAC,gBAuHhD,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default OpenAPI components provided by Glasswork.
|
|
3
|
+
* These include headers for features implemented by the framework:
|
|
4
|
+
* - Rate limiting headers
|
|
5
|
+
* - Pagination headers
|
|
6
|
+
* - CORS headers
|
|
7
|
+
* - Error response schemas
|
|
8
|
+
*/
|
|
9
|
+
export const defaultOpenAPIComponents = {
|
|
10
|
+
schemas: {
|
|
11
|
+
// Error response schemas
|
|
12
|
+
ErrorResponse: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
required: ['error'],
|
|
15
|
+
properties: {
|
|
16
|
+
error: {
|
|
17
|
+
type: 'string',
|
|
18
|
+
maxLength: 1000,
|
|
19
|
+
pattern: '^[\\s\\S]*$', // Any characters including whitespace
|
|
20
|
+
description: 'Error message',
|
|
21
|
+
},
|
|
22
|
+
issues: {
|
|
23
|
+
type: 'array',
|
|
24
|
+
maxItems: 100,
|
|
25
|
+
items: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
required: ['message'],
|
|
28
|
+
properties: {
|
|
29
|
+
message: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
maxLength: 500,
|
|
32
|
+
},
|
|
33
|
+
path: {
|
|
34
|
+
type: 'array',
|
|
35
|
+
maxItems: 20,
|
|
36
|
+
items: {
|
|
37
|
+
oneOf: [
|
|
38
|
+
{ type: 'string', maxLength: 200 },
|
|
39
|
+
{ type: 'number', format: 'int32' },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
description: 'Validation error details',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
headers: {
|
|
51
|
+
// CORS headers
|
|
52
|
+
'Access-Control-Allow-Origin': {
|
|
53
|
+
description: 'Allowed origin for CORS requests',
|
|
54
|
+
schema: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
maxLength: 2048,
|
|
57
|
+
pattern: '^https?://[a-zA-Z0-9.-]+(:[0-9]+)?$',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
// Rate limiting headers (from rate-limit.ts)
|
|
61
|
+
'RateLimit-Limit': {
|
|
62
|
+
description: 'Total requests allowed in the current time window',
|
|
63
|
+
schema: {
|
|
64
|
+
type: 'integer',
|
|
65
|
+
format: 'int32',
|
|
66
|
+
minimum: 0,
|
|
67
|
+
maximum: 10000,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
'RateLimit-Remaining': {
|
|
71
|
+
description: 'Remaining requests in the current window',
|
|
72
|
+
schema: {
|
|
73
|
+
type: 'integer',
|
|
74
|
+
format: 'int32',
|
|
75
|
+
minimum: 0,
|
|
76
|
+
maximum: 10000,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
'RateLimit-Reset': {
|
|
80
|
+
description: 'Seconds until the rate limit window resets',
|
|
81
|
+
schema: {
|
|
82
|
+
type: 'integer',
|
|
83
|
+
format: 'int32',
|
|
84
|
+
minimum: 0,
|
|
85
|
+
maximum: 3600,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
'Retry-After': {
|
|
89
|
+
description: 'Seconds to wait before retrying the request (429 response)',
|
|
90
|
+
schema: {
|
|
91
|
+
type: 'integer',
|
|
92
|
+
format: 'int32',
|
|
93
|
+
minimum: 1,
|
|
94
|
+
maximum: 3600,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
// Pagination headers (from pagination.ts)
|
|
98
|
+
'X-Total-Count': {
|
|
99
|
+
description: 'Total number of items available',
|
|
100
|
+
schema: {
|
|
101
|
+
type: 'integer',
|
|
102
|
+
format: 'int32',
|
|
103
|
+
minimum: 0,
|
|
104
|
+
maximum: 2147483647, // Max int32
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
'X-Page': {
|
|
108
|
+
description: 'Current page number',
|
|
109
|
+
schema: {
|
|
110
|
+
type: 'integer',
|
|
111
|
+
format: 'int32',
|
|
112
|
+
minimum: 1,
|
|
113
|
+
maximum: 2147483647, // Max int32
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
'X-Limit': {
|
|
117
|
+
description: 'Number of items per page',
|
|
118
|
+
schema: {
|
|
119
|
+
type: 'integer',
|
|
120
|
+
format: 'int32',
|
|
121
|
+
minimum: 1,
|
|
122
|
+
maximum: 100,
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
//# sourceMappingURL=defaults.js.map
|