@hazeljs/core 0.2.0-beta.8 → 0.2.0-beta.81
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 +192 -21
- package/README.md +48 -10
- package/dist/__tests__/decorators.test.d.ts.map +1 -1
- package/dist/__tests__/decorators.test.js +544 -0
- package/dist/__tests__/hazel-app.test.js +128 -0
- package/dist/__tests__/router.test.js +503 -0
- package/dist/container.js +4 -4
- package/dist/decorators.d.ts +75 -1
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +196 -1
- package/dist/errors/http.error.d.ts +3 -0
- package/dist/errors/http.error.d.ts.map +1 -1
- package/dist/errors/http.error.js +8 -1
- package/dist/hazel-app.d.ts +17 -1
- package/dist/hazel-app.d.ts.map +1 -1
- package/dist/hazel-app.js +88 -25
- package/dist/hazel-module.d.ts +11 -2
- package/dist/hazel-module.d.ts.map +1 -1
- package/dist/hazel-module.js +47 -19
- package/dist/hazel-response.d.ts +5 -0
- package/dist/hazel-response.d.ts.map +1 -1
- package/dist/hazel-response.js +21 -0
- package/dist/health.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -2
- package/dist/interceptors/interceptor.d.ts +8 -0
- package/dist/interceptors/interceptor.d.ts.map +1 -1
- package/dist/interceptors/interceptor.js +26 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +51 -28
- package/dist/request-context.d.ts +5 -0
- package/dist/request-context.d.ts.map +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +56 -6
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -4
package/dist/hazel-module.js
CHANGED
|
@@ -19,45 +19,80 @@ function HazelModule(options) {
|
|
|
19
19
|
// Alias for backward compatibility
|
|
20
20
|
exports.Module = HazelModule;
|
|
21
21
|
function getModuleMetadata(target) {
|
|
22
|
-
|
|
22
|
+
const fromDecorator = Reflect.getMetadata(MODULE_METADATA_KEY, target);
|
|
23
|
+
if (fromDecorator)
|
|
24
|
+
return fromDecorator;
|
|
25
|
+
// Support dynamic modules: { module, providers?, controllers?, imports? }
|
|
26
|
+
if (target && typeof target === 'object' && 'module' in target) {
|
|
27
|
+
const dyn = target;
|
|
28
|
+
return {
|
|
29
|
+
providers: dyn.providers,
|
|
30
|
+
controllers: dyn.controllers,
|
|
31
|
+
imports: dyn.imports,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
23
35
|
}
|
|
24
36
|
class HazelModuleInstance {
|
|
25
37
|
constructor(moduleType) {
|
|
26
38
|
this.moduleType = moduleType;
|
|
27
|
-
|
|
39
|
+
const name = moduleType?.name ?? moduleType?.module?.name ?? 'DynamicModule';
|
|
40
|
+
logger_1.default.debug(`Initializing HazelModule: ${name}`);
|
|
28
41
|
this.container = container_1.Container.getInstance();
|
|
29
42
|
this.initialize();
|
|
30
43
|
}
|
|
31
44
|
initialize() {
|
|
32
45
|
const metadata = getModuleMetadata(this.moduleType) || {};
|
|
33
46
|
logger_1.default.debug('Module metadata:', metadata);
|
|
47
|
+
// Initialize imported modules first (so their providers are available)
|
|
48
|
+
if (metadata.imports) {
|
|
49
|
+
logger_1.default.debug('Initializing imported modules:', metadata.imports.map((m) => (m && typeof m === 'object' && 'module' in m ? m.module?.name : m?.name)));
|
|
50
|
+
metadata.imports.forEach((moduleType) => {
|
|
51
|
+
new HazelModuleInstance(moduleType);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
34
54
|
// Register providers
|
|
35
55
|
if (metadata.providers) {
|
|
36
|
-
logger_1.default.debug('Registering providers:', metadata.providers.map((p) =>
|
|
56
|
+
logger_1.default.debug('Registering providers:', metadata.providers.map((p) => {
|
|
57
|
+
const val = p && typeof p === 'object' && 'provide' in p ? p.provide : p?.name;
|
|
58
|
+
return typeof val === 'symbol' ? val.toString() : val;
|
|
59
|
+
}));
|
|
37
60
|
metadata.providers.forEach((provider) => {
|
|
38
|
-
|
|
61
|
+
// Dynamic module provider: { provide, useFactory?, useClass?, useValue? } (NestJS-style)
|
|
62
|
+
if (provider && typeof provider === 'object' && ('provide' in provider || 'token' in provider)) {
|
|
63
|
+
const p = provider;
|
|
64
|
+
const token = p.token ?? p.provide;
|
|
65
|
+
logger_1.default.debug(`Registering provider config for: ${typeof token === 'symbol' ? token.toString() : token}`);
|
|
66
|
+
this.container.registerProvider({
|
|
67
|
+
token,
|
|
68
|
+
useFactory: p.useFactory,
|
|
69
|
+
useClass: p.useClass,
|
|
70
|
+
useValue: p.useValue,
|
|
71
|
+
inject: p.inject,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const cls = provider;
|
|
76
|
+
logger_1.default.debug(`Registering provider: ${cls?.name}`);
|
|
39
77
|
// Check if provider is request-scoped
|
|
40
|
-
const scope = Reflect.getMetadata('hazel:scope',
|
|
78
|
+
const scope = Reflect.getMetadata('hazel:scope', cls);
|
|
41
79
|
if (scope === 'request') {
|
|
42
80
|
// Don't eagerly resolve request-scoped providers
|
|
43
|
-
// They will be resolved per-request by the container
|
|
44
|
-
logger_1.default.debug(`Skipping eager resolution for request-scoped provider: ${provider.name}`);
|
|
45
|
-
// Just register the class itself, not an instance
|
|
46
81
|
this.container.registerProvider({
|
|
47
|
-
token:
|
|
48
|
-
useClass:
|
|
82
|
+
token: cls,
|
|
83
|
+
useClass: cls,
|
|
49
84
|
scope: container_1.Scope.REQUEST,
|
|
50
85
|
});
|
|
51
86
|
}
|
|
52
87
|
else {
|
|
53
88
|
// Eagerly resolve singleton and transient providers
|
|
54
|
-
this.container.register(
|
|
89
|
+
this.container.register(cls, this.container.resolve(cls));
|
|
55
90
|
}
|
|
56
91
|
});
|
|
57
92
|
}
|
|
58
93
|
// Register controllers
|
|
59
94
|
if (metadata.controllers) {
|
|
60
|
-
logger_1.default.debug('Registering controllers:', metadata.controllers.map((c) => c
|
|
95
|
+
logger_1.default.debug('Registering controllers:', metadata.controllers.map((c) => c?.name));
|
|
61
96
|
metadata.controllers.forEach((controller) => {
|
|
62
97
|
logger_1.default.debug(`Registering controller: ${controller.name}`);
|
|
63
98
|
// Check if controller has request-scoped dependencies
|
|
@@ -94,13 +129,6 @@ class HazelModuleInstance {
|
|
|
94
129
|
});
|
|
95
130
|
});
|
|
96
131
|
}
|
|
97
|
-
// Initialize imported modules
|
|
98
|
-
if (metadata.imports) {
|
|
99
|
-
logger_1.default.debug('Initializing imported modules:', metadata.imports.map((m) => m.name));
|
|
100
|
-
metadata.imports.forEach((moduleType) => {
|
|
101
|
-
new HazelModuleInstance(moduleType);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
132
|
}
|
|
105
133
|
getContainer() {
|
|
106
134
|
return this.container;
|
package/dist/hazel-response.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ export interface HazelResponse {
|
|
|
5
5
|
end(): void;
|
|
6
6
|
status(code: number): HazelResponse;
|
|
7
7
|
json(data: unknown): void;
|
|
8
|
+
redirect(url: string, statusCode?: number): void;
|
|
9
|
+
/** Send a Buffer as binary (e.g. audio, PDF). Sets Content-Type if provided. */
|
|
10
|
+
sendBuffer?(buffer: Buffer, contentType?: string): void;
|
|
8
11
|
}
|
|
9
12
|
export declare class HazelExpressResponse implements HazelResponse {
|
|
10
13
|
private res;
|
|
@@ -15,6 +18,8 @@ export declare class HazelExpressResponse implements HazelResponse {
|
|
|
15
18
|
write(chunk: string): void;
|
|
16
19
|
end(): void;
|
|
17
20
|
status(code: number): HazelResponse;
|
|
21
|
+
redirect(url: string, statusCode?: number): void;
|
|
22
|
+
sendBuffer(buffer: Buffer, contentType?: string): void;
|
|
18
23
|
json(data: unknown): void;
|
|
19
24
|
}
|
|
20
25
|
//# sourceMappingURL=hazel-response.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazel-response.d.ts","sourceRoot":"","sources":["../src/hazel-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,IAAI,IAAI,CAAC;IACZ,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"hazel-response.d.ts","sourceRoot":"","sources":["../src/hazel-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,IAAI,IAAI,CAAC;IACZ,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,gFAAgF;IAChF,UAAU,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzD;AAED,qBAAa,oBAAqB,YAAW,aAAa;IAI5C,OAAO,CAAC,GAAG;IAHvB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAAkB;gBAEjB,GAAG,EAAE,QAAQ;IAEjC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAY1B,GAAG,IAAI,IAAI;IAMX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAOnC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,GAAE,MAAY,GAAG,IAAI;IAWrD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAWtD,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;CA+B1B"}
|
package/dist/hazel-response.js
CHANGED
|
@@ -35,6 +35,27 @@ class HazelExpressResponse {
|
|
|
35
35
|
}
|
|
36
36
|
return this;
|
|
37
37
|
}
|
|
38
|
+
redirect(url, statusCode = 302) {
|
|
39
|
+
if (this.headersSent)
|
|
40
|
+
return;
|
|
41
|
+
if (typeof this.res.redirect === 'function') {
|
|
42
|
+
this.res.redirect(url, statusCode);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.headersSent = true;
|
|
46
|
+
this.res.writeHead(statusCode, { Location: url });
|
|
47
|
+
this.res.end();
|
|
48
|
+
}
|
|
49
|
+
sendBuffer(buffer, contentType) {
|
|
50
|
+
if (this.isStreaming || this.headersSent) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (contentType) {
|
|
54
|
+
this.res.setHeader('Content-Type', contentType);
|
|
55
|
+
}
|
|
56
|
+
this.res.send(buffer);
|
|
57
|
+
this.headersSent = true;
|
|
58
|
+
}
|
|
38
59
|
json(data) {
|
|
39
60
|
if (this.isStreaming || this.headersSent) {
|
|
40
61
|
return; // Don't try to send JSON if we're already streaming or headers are sent
|
package/dist/health.js
CHANGED
|
@@ -19,7 +19,7 @@ class HealthCheckManager {
|
|
|
19
19
|
*/
|
|
20
20
|
registerCheck(check) {
|
|
21
21
|
this.checks.set(check.name, check);
|
|
22
|
-
logger_1.default.
|
|
22
|
+
logger_1.default.debug(`Registered health check: ${check.name}`);
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Run all health checks
|
package/dist/index.d.ts
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
* A modern, modular Node.js framework with TypeScript support
|
|
4
4
|
*/
|
|
5
5
|
import 'reflect-metadata';
|
|
6
|
-
export { HazelApp } from './hazel-app';
|
|
6
|
+
export { HazelApp, type EarlyHttpHandler, type ProxyHandler } from './hazel-app';
|
|
7
7
|
export { HazelModule, Module, HazelModuleInstance, getModuleMetadata } from './hazel-module';
|
|
8
|
-
export type { ModuleOptions } from './hazel-module';
|
|
8
|
+
export type { ModuleOptions, DynamicModule } from './hazel-module';
|
|
9
9
|
export { ShutdownManager } from './shutdown';
|
|
10
10
|
export type { ShutdownHandler } from './shutdown';
|
|
11
11
|
export { HealthCheckManager, BuiltInHealthChecks } from './health';
|
|
12
12
|
export type { HealthCheck, HealthCheckResult, HealthStatus } from './health';
|
|
13
13
|
export { TimeoutMiddleware } from './middleware/timeout.middleware';
|
|
14
14
|
export type { TimeoutOptions } from './middleware/timeout.middleware';
|
|
15
|
-
export { Controller, Injectable, Service, Get, Post, Put, Delete, Patch, Body, Param, Query, Req, Res, Headers, HttpCode, Header, Redirect, Inject, UsePipes, UseInterceptors, UseGuards, type ControllerMetadata, type RouteMetadata, type ControllerOptions, type RouteOptions, type ServiceOptions, type InjectableOptions, type RepositoryOptions, type OnModuleInit, type OnModuleDestroy, type ExecutionContext, type CanActivate, } from './decorators';
|
|
15
|
+
export { Controller, Injectable, Service, Get, Post, Put, Delete, Patch, Body, Param, Query, Req, Res, Ip, Host, Headers, HttpCode, Header, Redirect, Inject, UsePipes, UseInterceptors, UseGuards, Public, SkipAuth, AITask, Timeout, Optional, Session, Retry, ApiTags, ApiOperation, SetMetadata, getMetadata, createParamDecorator, CUSTOM_METADATA_PREFIX, type ControllerMetadata, type RouteMetadata, type ControllerOptions, type RouteOptions, type ServiceOptions, type InjectableOptions, type RepositoryOptions, type OnModuleInit, type OnModuleDestroy, type ExecutionContext, type CanActivate, type RetryDecoratorOptions, type ApiOperationOptions, type ParamDecoratorContext, } from './decorators';
|
|
16
16
|
export { Container, Scope, type InjectionToken, type Provider } from './container';
|
|
17
17
|
export type { Type, Request, Response, RequestContext, ValidationSchema } from './types';
|
|
18
|
-
export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, InternalServerError, HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException, InternalServerErrorException, } from './errors/http.error';
|
|
18
|
+
export { HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, InternalServerError, HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException, ConflictException, InternalServerErrorException, RequestTimeoutError, } from './errors/http.error';
|
|
19
19
|
export { PipeTransform, ValidationError, ParseIntPipe, type PipeMetadata } from './pipes/pipe';
|
|
20
20
|
export { ValidationPipe } from './pipes/validation.pipe';
|
|
21
|
-
export { Interceptor, type InterceptorMetadata } from './interceptors/interceptor';
|
|
21
|
+
export { Interceptor, RetryInterceptor, type InterceptorMetadata, type RetryOptions, } from './interceptors/interceptor';
|
|
22
22
|
export { type ExceptionFilter, type ArgumentsHost, ArgumentsHostImpl, Catch, getFilterExceptions, } from './filters/exception-filter';
|
|
23
23
|
export { HttpExceptionFilter } from './filters/http-exception.filter';
|
|
24
24
|
export { Test, TestingModule, TestingModuleBuilder, type TestingModuleMetadata, } from './testing/testing.module';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.
|
|
11
|
-
exports.escapeHtml = exports.sanitizeObject = exports.sanitizeSql = exports.sanitizeEmail = exports.sanitizeUrl = exports.sanitizeString = exports.sanitizeHtml = exports.RequestParser = exports.Router = exports.Validator = exports.default = exports.logger = exports.UploadedFiles = exports.UploadedFile = exports.FileUploadInterceptor = exports.CsrfMiddleware = exports.RateLimitMiddleware = exports.SecurityHeadersMiddleware = exports.LoggerMiddleware = exports.CorsMiddleware = exports.GlobalMiddlewareManager = exports.extractVersion = exports.matchVersion = exports.getVersionMetadata = exports.VersioningType = exports.Version = exports.RouteMatcher = exports.TestingModuleBuilder = exports.TestingModule = exports.Test = exports.HttpExceptionFilter = exports.getFilterExceptions = exports.Catch = void 0;
|
|
10
|
+
exports.UnauthorizedError = exports.BadRequestError = exports.HttpError = exports.Scope = exports.Container = exports.CUSTOM_METADATA_PREFIX = exports.createParamDecorator = exports.getMetadata = exports.SetMetadata = exports.ApiOperation = exports.ApiTags = exports.Retry = exports.Session = exports.Optional = exports.Timeout = exports.AITask = exports.SkipAuth = exports.Public = exports.UseGuards = exports.UseInterceptors = exports.UsePipes = exports.Inject = exports.Redirect = exports.Header = exports.HttpCode = exports.Headers = exports.Host = exports.Ip = exports.Res = exports.Req = exports.Query = exports.Param = exports.Body = exports.Patch = exports.Delete = exports.Put = exports.Post = exports.Get = exports.Service = exports.Injectable = exports.Controller = exports.TimeoutMiddleware = exports.BuiltInHealthChecks = exports.HealthCheckManager = exports.ShutdownManager = exports.getModuleMetadata = exports.HazelModuleInstance = exports.Module = exports.HazelModule = exports.HazelApp = void 0;
|
|
11
|
+
exports.escapeHtml = exports.sanitizeObject = exports.sanitizeSql = exports.sanitizeEmail = exports.sanitizeUrl = exports.sanitizeString = exports.sanitizeHtml = exports.RequestParser = exports.Router = exports.Validator = exports.default = exports.logger = exports.UploadedFiles = exports.UploadedFile = exports.FileUploadInterceptor = exports.CsrfMiddleware = exports.RateLimitMiddleware = exports.SecurityHeadersMiddleware = exports.LoggerMiddleware = exports.CorsMiddleware = exports.GlobalMiddlewareManager = exports.extractVersion = exports.matchVersion = exports.getVersionMetadata = exports.VersioningType = exports.Version = exports.RouteMatcher = exports.TestingModuleBuilder = exports.TestingModule = exports.Test = exports.HttpExceptionFilter = exports.getFilterExceptions = exports.Catch = exports.ArgumentsHostImpl = exports.RetryInterceptor = exports.ValidationPipe = exports.ParseIntPipe = exports.ValidationError = exports.RequestTimeoutError = exports.InternalServerErrorException = exports.ConflictException = exports.NotFoundException = exports.ForbiddenException = exports.UnauthorizedException = exports.BadRequestException = exports.HttpException = exports.InternalServerError = exports.ConflictError = exports.NotFoundError = exports.ForbiddenError = void 0;
|
|
12
12
|
// Import reflect-metadata to enable decorator metadata
|
|
13
13
|
// Users don't need to import this manually
|
|
14
14
|
require("reflect-metadata");
|
|
@@ -44,6 +44,8 @@ Object.defineProperty(exports, "Param", { enumerable: true, get: function () { r
|
|
|
44
44
|
Object.defineProperty(exports, "Query", { enumerable: true, get: function () { return decorators_1.Query; } });
|
|
45
45
|
Object.defineProperty(exports, "Req", { enumerable: true, get: function () { return decorators_1.Req; } });
|
|
46
46
|
Object.defineProperty(exports, "Res", { enumerable: true, get: function () { return decorators_1.Res; } });
|
|
47
|
+
Object.defineProperty(exports, "Ip", { enumerable: true, get: function () { return decorators_1.Ip; } });
|
|
48
|
+
Object.defineProperty(exports, "Host", { enumerable: true, get: function () { return decorators_1.Host; } });
|
|
47
49
|
Object.defineProperty(exports, "Headers", { enumerable: true, get: function () { return decorators_1.Headers; } });
|
|
48
50
|
Object.defineProperty(exports, "HttpCode", { enumerable: true, get: function () { return decorators_1.HttpCode; } });
|
|
49
51
|
Object.defineProperty(exports, "Header", { enumerable: true, get: function () { return decorators_1.Header; } });
|
|
@@ -52,6 +54,19 @@ Object.defineProperty(exports, "Inject", { enumerable: true, get: function () {
|
|
|
52
54
|
Object.defineProperty(exports, "UsePipes", { enumerable: true, get: function () { return decorators_1.UsePipes; } });
|
|
53
55
|
Object.defineProperty(exports, "UseInterceptors", { enumerable: true, get: function () { return decorators_1.UseInterceptors; } });
|
|
54
56
|
Object.defineProperty(exports, "UseGuards", { enumerable: true, get: function () { return decorators_1.UseGuards; } });
|
|
57
|
+
Object.defineProperty(exports, "Public", { enumerable: true, get: function () { return decorators_1.Public; } });
|
|
58
|
+
Object.defineProperty(exports, "SkipAuth", { enumerable: true, get: function () { return decorators_1.SkipAuth; } });
|
|
59
|
+
Object.defineProperty(exports, "AITask", { enumerable: true, get: function () { return decorators_1.AITask; } });
|
|
60
|
+
Object.defineProperty(exports, "Timeout", { enumerable: true, get: function () { return decorators_1.Timeout; } });
|
|
61
|
+
Object.defineProperty(exports, "Optional", { enumerable: true, get: function () { return decorators_1.Optional; } });
|
|
62
|
+
Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return decorators_1.Session; } });
|
|
63
|
+
Object.defineProperty(exports, "Retry", { enumerable: true, get: function () { return decorators_1.Retry; } });
|
|
64
|
+
Object.defineProperty(exports, "ApiTags", { enumerable: true, get: function () { return decorators_1.ApiTags; } });
|
|
65
|
+
Object.defineProperty(exports, "ApiOperation", { enumerable: true, get: function () { return decorators_1.ApiOperation; } });
|
|
66
|
+
Object.defineProperty(exports, "SetMetadata", { enumerable: true, get: function () { return decorators_1.SetMetadata; } });
|
|
67
|
+
Object.defineProperty(exports, "getMetadata", { enumerable: true, get: function () { return decorators_1.getMetadata; } });
|
|
68
|
+
Object.defineProperty(exports, "createParamDecorator", { enumerable: true, get: function () { return decorators_1.createParamDecorator; } });
|
|
69
|
+
Object.defineProperty(exports, "CUSTOM_METADATA_PREFIX", { enumerable: true, get: function () { return decorators_1.CUSTOM_METADATA_PREFIX; } });
|
|
55
70
|
// Container & DI
|
|
56
71
|
var container_1 = require("./container");
|
|
57
72
|
Object.defineProperty(exports, "Container", { enumerable: true, get: function () { return container_1.Container; } });
|
|
@@ -72,12 +87,16 @@ Object.defineProperty(exports, "ForbiddenException", { enumerable: true, get: fu
|
|
|
72
87
|
Object.defineProperty(exports, "NotFoundException", { enumerable: true, get: function () { return http_error_1.NotFoundException; } });
|
|
73
88
|
Object.defineProperty(exports, "ConflictException", { enumerable: true, get: function () { return http_error_1.ConflictException; } });
|
|
74
89
|
Object.defineProperty(exports, "InternalServerErrorException", { enumerable: true, get: function () { return http_error_1.InternalServerErrorException; } });
|
|
90
|
+
Object.defineProperty(exports, "RequestTimeoutError", { enumerable: true, get: function () { return http_error_1.RequestTimeoutError; } });
|
|
75
91
|
// Pipes
|
|
76
92
|
var pipe_1 = require("./pipes/pipe");
|
|
77
93
|
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return pipe_1.ValidationError; } });
|
|
78
94
|
Object.defineProperty(exports, "ParseIntPipe", { enumerable: true, get: function () { return pipe_1.ParseIntPipe; } });
|
|
79
95
|
var validation_pipe_1 = require("./pipes/validation.pipe");
|
|
80
96
|
Object.defineProperty(exports, "ValidationPipe", { enumerable: true, get: function () { return validation_pipe_1.ValidationPipe; } });
|
|
97
|
+
// Interceptors
|
|
98
|
+
var interceptor_1 = require("./interceptors/interceptor");
|
|
99
|
+
Object.defineProperty(exports, "RetryInterceptor", { enumerable: true, get: function () { return interceptor_1.RetryInterceptor; } });
|
|
81
100
|
// Filters
|
|
82
101
|
var exception_filter_1 = require("./filters/exception-filter");
|
|
83
102
|
Object.defineProperty(exports, "ArgumentsHostImpl", { enumerable: true, get: function () { return exception_filter_1.ArgumentsHostImpl; } });
|
|
@@ -18,5 +18,13 @@ export declare class CacheInterceptor implements Interceptor {
|
|
|
18
18
|
constructor(options?: CacheOptions);
|
|
19
19
|
intercept(context: RequestContext, next: () => Promise<unknown>): Promise<unknown>;
|
|
20
20
|
}
|
|
21
|
+
export interface RetryOptions {
|
|
22
|
+
count: number;
|
|
23
|
+
delay?: number;
|
|
24
|
+
retryIf?: (err: Error) => boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class RetryInterceptor implements Interceptor {
|
|
27
|
+
intercept(context: RequestContext, next: () => Promise<unknown>): Promise<unknown>;
|
|
28
|
+
}
|
|
21
29
|
export type Type<T = unknown> = new (...args: unknown[]) => T;
|
|
22
30
|
//# sourceMappingURL=interceptor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../../src/interceptors/interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,kBAAmB,YAAW,WAAW;IAC9C,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;CAgBzF;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAA2D;IAC/E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,OAAO,CAAC,EAAE,YAAY;IAI5B,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;CAgBzF;AAED,MAAM,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../../src/interceptors/interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,kBAAmB,YAAW,WAAW;IAC9C,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;CAgBzF;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAA2D;IAC/E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,OAAO,CAAC,EAAE,YAAY;IAI5B,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;CAgBzF;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,CAAC;CACnC;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAC5C,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;CAqBzF;AAED,MAAM,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC"}
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.CacheInterceptor = exports.LoggingInterceptor = void 0;
|
|
6
|
+
exports.RetryInterceptor = exports.CacheInterceptor = exports.LoggingInterceptor = void 0;
|
|
7
7
|
const logger_1 = __importDefault(require("../logger"));
|
|
8
8
|
class LoggingInterceptor {
|
|
9
9
|
async intercept(context, next) {
|
|
@@ -44,3 +44,28 @@ class CacheInterceptor {
|
|
|
44
44
|
}
|
|
45
45
|
exports.CacheInterceptor = CacheInterceptor;
|
|
46
46
|
CacheInterceptor.cache = new Map();
|
|
47
|
+
class RetryInterceptor {
|
|
48
|
+
async intercept(context, next) {
|
|
49
|
+
const opts = context.retryOptions;
|
|
50
|
+
if (!opts || opts.count < 1) {
|
|
51
|
+
return next();
|
|
52
|
+
}
|
|
53
|
+
const delayMs = opts.delay ?? 100;
|
|
54
|
+
const shouldRetry = opts.retryIf ?? (() => true);
|
|
55
|
+
let lastError;
|
|
56
|
+
for (let attempt = 0; attempt <= opts.count; attempt++) {
|
|
57
|
+
try {
|
|
58
|
+
return await next();
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
62
|
+
if (attempt === opts.count || !shouldRetry(lastError)) {
|
|
63
|
+
throw lastError;
|
|
64
|
+
}
|
|
65
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw lastError;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.RetryInterceptor = RetryInterceptor;
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAK9B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAK9B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAwQvD,eAAO,MAAM,aAAa,GACxB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,MAAM,MAAM,IAAI,KACf,IAyBF,CAAC;AAQF,QAAA,MAAM,cAAc;0BALO,OAAO;CAOhC,CAAC;AAGH,eAAe,cAAc,CAAC"}
|
package/dist/logger.js
CHANGED
|
@@ -13,8 +13,10 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
13
13
|
dotenv_1.default.config();
|
|
14
14
|
const logLevel = process.env.LOG_LEVEL || 'info';
|
|
15
15
|
const logDir = process.env.LOG_DIR || 'logs';
|
|
16
|
+
const logEnabled = process.env.LOG_ENABLED !== 'false'; // default: true
|
|
17
|
+
const logPackage = process.env.LOG_PACKAGE || ''; // e.g. "http" = only HTTP request logs
|
|
16
18
|
// Ensure log directory exists
|
|
17
|
-
if (!fs_1.default.existsSync(logDir)) {
|
|
19
|
+
if (logDir && !fs_1.default.existsSync(logDir)) {
|
|
18
20
|
fs_1.default.mkdirSync(logDir, { recursive: true });
|
|
19
21
|
}
|
|
20
22
|
// Professional color scheme for different log levels
|
|
@@ -67,15 +69,16 @@ const getCategoryColor = (message) => {
|
|
|
67
69
|
return chalk_1.default.white;
|
|
68
70
|
};
|
|
69
71
|
// Custom format for better readability with enhanced colors
|
|
70
|
-
const customFormat = winston_1.default.format.printf((
|
|
72
|
+
const customFormat = winston_1.default.format.printf((info) => {
|
|
73
|
+
const { level, message, timestamp, ...metadata } = info;
|
|
71
74
|
// Get the appropriate color for the log level
|
|
72
75
|
const levelColor = colors[level] || chalk_1.default.white;
|
|
73
76
|
// Format the timestamp with subtle color
|
|
74
|
-
const time = chalk_1.default.gray.dim(timestamp);
|
|
77
|
+
const time = chalk_1.default.gray.dim(String(timestamp ?? ''));
|
|
75
78
|
// Format the level with color and padding (no icons for professional look)
|
|
76
|
-
const levelStr = levelColor.bold(`[${level.toUpperCase()}]`.padEnd(9));
|
|
79
|
+
const levelStr = levelColor.bold(`[${String(level).toUpperCase()}]`.padEnd(9));
|
|
77
80
|
// Convert message to string
|
|
78
|
-
const messageStr = String(message);
|
|
81
|
+
const messageStr = String(message ?? '');
|
|
79
82
|
// Detect category and apply appropriate color to message
|
|
80
83
|
const categoryColor = getCategoryColor(messageStr);
|
|
81
84
|
let msg = categoryColor(messageStr);
|
|
@@ -151,20 +154,29 @@ const customFormat = winston_1.default.format.printf(({ level, message, timestam
|
|
|
151
154
|
}
|
|
152
155
|
return `${time} ${levelStr} ${msg}${metaStr}`;
|
|
153
156
|
});
|
|
154
|
-
//
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
// When LOG_PACKAGE=http, only allow logs that look like HTTP requests
|
|
158
|
+
const isHttpLog = (info) => {
|
|
159
|
+
const msg = String(info.message ?? '');
|
|
160
|
+
return /^(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\s+/i.test(msg) || msg.includes(' → ') || msg.includes(' ← ');
|
|
161
|
+
};
|
|
162
|
+
const transports = [];
|
|
163
|
+
if (logEnabled) {
|
|
164
|
+
if (logPackage === 'http') {
|
|
165
|
+
transports.push(new winston_1.default.transports.Console({
|
|
166
|
+
format: winston_1.default.format.combine(winston_1.default.format((info) => (isHttpLog(info) ? info : false))(), customFormat),
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
transports.push(new winston_1.default.transports.Console({
|
|
161
171
|
format: winston_1.default.format.combine(customFormat),
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
if (logDir) {
|
|
175
|
+
transports.push(new winston_1.default.transports.File({
|
|
165
176
|
filename: path_1.default.join(logDir, 'combined.log'),
|
|
166
|
-
format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.printf((
|
|
167
|
-
|
|
177
|
+
format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.printf((info) => {
|
|
178
|
+
const { level, message, timestamp, ...metadata } = info;
|
|
179
|
+
let msg = `${timestamp} [${String(level).toUpperCase()}] ${message}`;
|
|
168
180
|
if (Object.keys(metadata).length > 0) {
|
|
169
181
|
msg += ` | ${JSON.stringify(metadata, (key, val) => {
|
|
170
182
|
if (key === 'socket' || key === 'parser' || key === 'res' || key === 'req') {
|
|
@@ -175,13 +187,12 @@ const logger = winston_1.default.createLogger({
|
|
|
175
187
|
}
|
|
176
188
|
return msg;
|
|
177
189
|
})),
|
|
178
|
-
}),
|
|
179
|
-
// File transport for errors only (without colors)
|
|
180
|
-
new winston_1.default.transports.File({
|
|
190
|
+
}), new winston_1.default.transports.File({
|
|
181
191
|
filename: path_1.default.join(logDir, 'error.log'),
|
|
182
192
|
level: 'error',
|
|
183
|
-
format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.printf((
|
|
184
|
-
|
|
193
|
+
format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.printf((info) => {
|
|
194
|
+
const { level, message, timestamp, ...metadata } = info;
|
|
195
|
+
let msg = `${timestamp} [${String(level).toUpperCase()}] ${message}`;
|
|
185
196
|
if (Object.keys(metadata).length > 0) {
|
|
186
197
|
msg += ` | ${JSON.stringify(metadata, (key, val) => {
|
|
187
198
|
if (key === 'socket' || key === 'parser' || key === 'res' || key === 'req') {
|
|
@@ -192,8 +203,17 @@ const logger = winston_1.default.createLogger({
|
|
|
192
203
|
}
|
|
193
204
|
return msg;
|
|
194
205
|
})),
|
|
195
|
-
})
|
|
196
|
-
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
transports.push(new winston_1.default.transports.Console({ silent: true }));
|
|
211
|
+
}
|
|
212
|
+
// Create logger instance
|
|
213
|
+
const logger = winston_1.default.createLogger({
|
|
214
|
+
level: logLevel,
|
|
215
|
+
format: winston_1.default.format.combine(winston_1.default.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), customFormat),
|
|
216
|
+
transports,
|
|
197
217
|
});
|
|
198
218
|
// Log application info when starting
|
|
199
219
|
const appInfo = {
|
|
@@ -206,6 +226,9 @@ logger.info(chalk_1.default.cyan.bold('Application started'), appInfo);
|
|
|
206
226
|
const requestLogger = (req, res, next) => {
|
|
207
227
|
const start = Date.now();
|
|
208
228
|
res.on('finish', () => {
|
|
229
|
+
const pathname = (req.url ?? '').split('?')[0];
|
|
230
|
+
if (pathname === '/favicon.ico')
|
|
231
|
+
return;
|
|
209
232
|
const duration = Date.now() - start;
|
|
210
233
|
const statusColor = res.statusCode >= 500
|
|
211
234
|
? chalk_1.default.red
|
|
@@ -216,11 +239,11 @@ const requestLogger = (req, res, next) => {
|
|
|
216
239
|
: res.statusCode >= 200
|
|
217
240
|
? chalk_1.default.green
|
|
218
241
|
: chalk_1.default.white;
|
|
219
|
-
logger.info(`${chalk_1.default.bold(req.method)} ${req.url}`, {
|
|
220
|
-
status: statusColor(res.statusCode),
|
|
242
|
+
logger.info(`${chalk_1.default.bold(req.method ?? '')} ${req.url ?? ''}`, {
|
|
243
|
+
status: statusColor(String(res.statusCode)),
|
|
221
244
|
duration: chalk_1.default.yellow(`${duration}ms`),
|
|
222
|
-
userAgent: chalk_1.default.gray(req.headers['user-agent']),
|
|
223
|
-
ip: chalk_1.default.gray(req.socket.remoteAddress),
|
|
245
|
+
userAgent: chalk_1.default.gray(String(req.headers['user-agent'] ?? '')),
|
|
246
|
+
ip: chalk_1.default.gray(String(req.socket.remoteAddress ?? '')),
|
|
224
247
|
});
|
|
225
248
|
});
|
|
226
249
|
next();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,IAAI,CAAC,EAAE;QACL,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../src/request-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,IAAI,CAAC,EAAE;QACL,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAC;CACrF"}
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMxC,OAAO,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMxC,OAAO,kBAAkB,CAAC;AAc1B,UAAU,UAAU;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,KAAK,YAAY,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;AAEpF,qBAAa,MAAM;IAKL,OAAO,CAAC,SAAS;IAJ7B,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,cAAc,CAAuD;IAC7E,OAAO,CAAC,iBAAiB,CAAoB;gBAEzB,SAAS,EAAE,SAAS;IAUxC,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI;YA4DrC,UAAU;YAsBV,iBAAiB;IAe/B,OAAO,CAAC,kBAAkB;IAgT1B,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,SAAS;IAiBjB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,aAAa;IAOf,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA0C7F,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIjD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIlD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIjD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIpD,OAAO,CAAC,QAAQ;IAKV,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAkChE"}
|