nitrostack 1.0.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/CHANGELOG.md +227 -0
- package/CONTRIBUTING.md +182 -0
- package/LICENSE +201 -0
- package/LICENSE_URLS_UPDATE_COMPLETE.md +388 -0
- package/NOTICE +153 -0
- package/README.md +571 -0
- package/dist/auth/api-key.d.ts +118 -0
- package/dist/auth/api-key.d.ts.map +1 -0
- package/dist/auth/api-key.js +168 -0
- package/dist/auth/api-key.js.map +1 -0
- package/dist/auth/client.d.ts +151 -0
- package/dist/auth/client.d.ts.map +1 -0
- package/dist/auth/client.js +330 -0
- package/dist/auth/client.js.map +1 -0
- package/dist/auth/index.d.ts +30 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +43 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +95 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +260 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/pkce.d.ts +53 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +105 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/auth/quick-setup.d.ts +94 -0
- package/dist/auth/quick-setup.d.ts.map +1 -0
- package/dist/auth/quick-setup.js +210 -0
- package/dist/auth/quick-setup.js.map +1 -0
- package/dist/auth/server-integration.d.ts +97 -0
- package/dist/auth/server-integration.d.ts.map +1 -0
- package/dist/auth/server-integration.js +182 -0
- package/dist/auth/server-integration.js.map +1 -0
- package/dist/auth/server-metadata.d.ts +51 -0
- package/dist/auth/server-metadata.d.ts.map +1 -0
- package/dist/auth/server-metadata.js +106 -0
- package/dist/auth/server-metadata.js.map +1 -0
- package/dist/auth/simple-jwt.d.ts +88 -0
- package/dist/auth/simple-jwt.d.ts.map +1 -0
- package/dist/auth/simple-jwt.js +152 -0
- package/dist/auth/simple-jwt.js.map +1 -0
- package/dist/auth/token-store.d.ts +104 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +205 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/auth/token-validation.d.ts +47 -0
- package/dist/auth/token-validation.d.ts.map +1 -0
- package/dist/auth/token-validation.js +237 -0
- package/dist/auth/token-validation.js.map +1 -0
- package/dist/auth/types.d.ts +215 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +6 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/cli/commands/build.d.ts +6 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +104 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +7 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +312 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/generate-types.d.ts +8 -0
- package/dist/cli/commands/generate-types.d.ts.map +1 -0
- package/dist/cli/commands/generate-types.js +220 -0
- package/dist/cli/commands/generate-types.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +5 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +365 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +365 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/start.d.ts +6 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +61 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +47 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mcp-dev-wrapper.d.ts +3 -0
- package/dist/cli/mcp-dev-wrapper.d.ts.map +1 -0
- package/dist/cli/mcp-dev-wrapper.js +116 -0
- package/dist/cli/mcp-dev-wrapper.js.map +1 -0
- package/dist/core/apikey-module.d.ts +69 -0
- package/dist/core/apikey-module.d.ts.map +1 -0
- package/dist/core/apikey-module.js +114 -0
- package/dist/core/apikey-module.js.map +1 -0
- package/dist/core/app-decorator.d.ts +58 -0
- package/dist/core/app-decorator.d.ts.map +1 -0
- package/dist/core/app-decorator.js +261 -0
- package/dist/core/app-decorator.js.map +1 -0
- package/dist/core/builders.d.ts +38 -0
- package/dist/core/builders.d.ts.map +1 -0
- package/dist/core/builders.js +129 -0
- package/dist/core/builders.js.map +1 -0
- package/dist/core/component.d.ts +105 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/component.js +182 -0
- package/dist/core/component.js.map +1 -0
- package/dist/core/config-module.d.ts +55 -0
- package/dist/core/config-module.d.ts.map +1 -0
- package/dist/core/config-module.js +94 -0
- package/dist/core/config-module.js.map +1 -0
- package/dist/core/decorators/cache.decorator.d.ts +61 -0
- package/dist/core/decorators/cache.decorator.d.ts.map +1 -0
- package/dist/core/decorators/cache.decorator.js +115 -0
- package/dist/core/decorators/cache.decorator.js.map +1 -0
- package/dist/core/decorators/health-check.decorator.d.ts +80 -0
- package/dist/core/decorators/health-check.decorator.d.ts.map +1 -0
- package/dist/core/decorators/health-check.decorator.js +153 -0
- package/dist/core/decorators/health-check.decorator.js.map +1 -0
- package/dist/core/decorators/rate-limit.decorator.d.ts +62 -0
- package/dist/core/decorators/rate-limit.decorator.d.ts.map +1 -0
- package/dist/core/decorators/rate-limit.decorator.js +129 -0
- package/dist/core/decorators/rate-limit.decorator.js.map +1 -0
- package/dist/core/decorators.d.ts +151 -0
- package/dist/core/decorators.d.ts.map +1 -0
- package/dist/core/decorators.js +142 -0
- package/dist/core/decorators.js.map +1 -0
- package/dist/core/di/container.d.ts +42 -0
- package/dist/core/di/container.d.ts.map +1 -0
- package/dist/core/di/container.js +76 -0
- package/dist/core/di/container.js.map +1 -0
- package/dist/core/di/injectable.decorator.d.ts +35 -0
- package/dist/core/di/injectable.decorator.d.ts.map +1 -0
- package/dist/core/di/injectable.decorator.js +57 -0
- package/dist/core/di/injectable.decorator.js.map +1 -0
- package/dist/core/errors.d.ts +54 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +87 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/events/event-emitter.d.ts +50 -0
- package/dist/core/events/event-emitter.d.ts.map +1 -0
- package/dist/core/events/event-emitter.js +94 -0
- package/dist/core/events/event-emitter.js.map +1 -0
- package/dist/core/events/event.decorator.d.ts +48 -0
- package/dist/core/events/event.decorator.d.ts.map +1 -0
- package/dist/core/events/event.decorator.js +68 -0
- package/dist/core/events/event.decorator.js.map +1 -0
- package/dist/core/filters/exception-filter.decorator.d.ts +40 -0
- package/dist/core/filters/exception-filter.decorator.d.ts.map +1 -0
- package/dist/core/filters/exception-filter.decorator.js +54 -0
- package/dist/core/filters/exception-filter.decorator.js.map +1 -0
- package/dist/core/filters/exception-filter.interface.d.ts +30 -0
- package/dist/core/filters/exception-filter.interface.d.ts.map +1 -0
- package/dist/core/filters/exception-filter.interface.js +2 -0
- package/dist/core/filters/exception-filter.interface.js.map +1 -0
- package/dist/core/guards/apikey.guard.d.ts +22 -0
- package/dist/core/guards/apikey.guard.d.ts.map +1 -0
- package/dist/core/guards/apikey.guard.js +11 -0
- package/dist/core/guards/apikey.guard.js.map +1 -0
- package/dist/core/guards/guard.interface.d.ts +18 -0
- package/dist/core/guards/guard.interface.d.ts.map +1 -0
- package/dist/core/guards/guard.interface.js +2 -0
- package/dist/core/guards/guard.interface.js.map +1 -0
- package/dist/core/guards/jwt.guard.d.ts +18 -0
- package/dist/core/guards/jwt.guard.d.ts.map +1 -0
- package/dist/core/guards/jwt.guard.js +2 -0
- package/dist/core/guards/jwt.guard.js.map +1 -0
- package/dist/core/guards/oauth.guard.d.ts +35 -0
- package/dist/core/guards/oauth.guard.d.ts.map +1 -0
- package/dist/core/guards/oauth.guard.js +2 -0
- package/dist/core/guards/oauth.guard.js.map +1 -0
- package/dist/core/guards/use-guards.decorator.d.ts +25 -0
- package/dist/core/guards/use-guards.decorator.d.ts.map +1 -0
- package/dist/core/guards/use-guards.decorator.js +32 -0
- package/dist/core/guards/use-guards.decorator.js.map +1 -0
- package/dist/core/health/health-checks.resource.d.ts +14 -0
- package/dist/core/health/health-checks.resource.d.ts.map +1 -0
- package/dist/core/health/health-checks.resource.js +29 -0
- package/dist/core/health/health-checks.resource.js.map +1 -0
- package/dist/core/index.d.ts +55 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +57 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/interceptors/interceptor.decorator.d.ts +37 -0
- package/dist/core/interceptors/interceptor.decorator.d.ts.map +1 -0
- package/dist/core/interceptors/interceptor.decorator.js +51 -0
- package/dist/core/interceptors/interceptor.decorator.js.map +1 -0
- package/dist/core/interceptors/interceptor.interface.d.ts +31 -0
- package/dist/core/interceptors/interceptor.interface.d.ts.map +1 -0
- package/dist/core/interceptors/interceptor.interface.js +2 -0
- package/dist/core/interceptors/interceptor.interface.js.map +1 -0
- package/dist/core/jwt-module.d.ts +51 -0
- package/dist/core/jwt-module.d.ts.map +1 -0
- package/dist/core/jwt-module.js +52 -0
- package/dist/core/jwt-module.js.map +1 -0
- package/dist/core/logger.d.ts +18 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +51 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/middleware/middleware.decorator.d.ts +39 -0
- package/dist/core/middleware/middleware.decorator.d.ts.map +1 -0
- package/dist/core/middleware/middleware.decorator.js +53 -0
- package/dist/core/middleware/middleware.decorator.js.map +1 -0
- package/dist/core/middleware/middleware.interface.d.ts +29 -0
- package/dist/core/middleware/middleware.interface.d.ts.map +1 -0
- package/dist/core/middleware/middleware.interface.js +2 -0
- package/dist/core/middleware/middleware.interface.js.map +1 -0
- package/dist/core/module.d.ts +74 -0
- package/dist/core/module.d.ts.map +1 -0
- package/dist/core/module.js +82 -0
- package/dist/core/module.js.map +1 -0
- package/dist/core/oauth-module.d.ts +144 -0
- package/dist/core/oauth-module.d.ts.map +1 -0
- package/dist/core/oauth-module.js +190 -0
- package/dist/core/oauth-module.js.map +1 -0
- package/dist/core/pipes/pipe.decorator.d.ts +55 -0
- package/dist/core/pipes/pipe.decorator.d.ts.map +1 -0
- package/dist/core/pipes/pipe.decorator.js +85 -0
- package/dist/core/pipes/pipe.decorator.js.map +1 -0
- package/dist/core/pipes/pipe.interface.d.ts +36 -0
- package/dist/core/pipes/pipe.interface.d.ts.map +1 -0
- package/dist/core/pipes/pipe.interface.js +2 -0
- package/dist/core/pipes/pipe.interface.js.map +1 -0
- package/dist/core/prompt.d.ts +37 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +76 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/resource.d.ts +42 -0
- package/dist/core/resource.d.ts.map +1 -0
- package/dist/core/resource.js +90 -0
- package/dist/core/resource.js.map +1 -0
- package/dist/core/server.d.ts +72 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +406 -0
- package/dist/core/server.js.map +1 -0
- package/dist/core/tool.d.ts +78 -0
- package/dist/core/tool.d.ts.map +1 -0
- package/dist/core/tool.js +190 -0
- package/dist/core/tool.js.map +1 -0
- package/dist/core/transports/http-server.d.ts +102 -0
- package/dist/core/transports/http-server.d.ts.map +1 -0
- package/dist/core/transports/http-server.js +265 -0
- package/dist/core/transports/http-server.js.map +1 -0
- package/dist/core/types.d.ts +123 -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/core/widgets/widget-examples.resource.d.ts +17 -0
- package/dist/core/widgets/widget-examples.resource.d.ts.map +1 -0
- package/dist/core/widgets/widget-examples.resource.js +28 -0
- package/dist/core/widgets/widget-examples.resource.js.map +1 -0
- package/dist/core/widgets/widget-registry.d.ts +56 -0
- package/dist/core/widgets/widget-registry.d.ts.map +1 -0
- package/dist/core/widgets/widget-registry.js +75 -0
- package/dist/core/widgets/widget-registry.js.map +1 -0
- package/dist/testing/index.d.ts +82 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +164 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/ui-next/index.d.ts +31 -0
- package/dist/ui-next/index.d.ts.map +1 -0
- package/dist/ui-next/index.js +687 -0
- package/dist/ui-next/index.js.map +1 -0
- package/dist/widgets/index.d.ts +9 -0
- package/dist/widgets/index.d.ts.map +1 -0
- package/dist/widgets/index.js +9 -0
- package/dist/widgets/index.js.map +1 -0
- package/dist/widgets/metadata.d.ts +53 -0
- package/dist/widgets/metadata.d.ts.map +1 -0
- package/dist/widgets/metadata.js +29 -0
- package/dist/widgets/metadata.js.map +1 -0
- package/dist/widgets/withToolData.d.ts +19 -0
- package/dist/widgets/withToolData.d.ts.map +1 -0
- package/dist/widgets/withToolData.js +240 -0
- package/dist/widgets/withToolData.js.map +1 -0
- package/jest.config.js +21 -0
- package/package.json +108 -0
- package/templates/typescript-auth/AI_AGENT_CLI_REFERENCE.md +702 -0
- package/templates/typescript-auth/AI_AGENT_SDK_REFERENCE.md +1260 -0
- package/templates/typescript-auth/README.md +400 -0
- package/templates/typescript-auth/package.json +44 -0
- package/templates/typescript-auth-api-key/AI_AGENT_CLI_REFERENCE.md +701 -0
- package/templates/typescript-auth-api-key/AI_AGENT_SDK_REFERENCE.md +1260 -0
- package/templates/typescript-auth-api-key/README.md +483 -0
- package/templates/typescript-auth-api-key/package-lock.json +124 -0
- package/templates/typescript-auth-api-key/package.json +29 -0
- package/templates/typescript-oauth/AI_AGENT_CLI_REFERENCE.md +701 -0
- package/templates/typescript-oauth/AI_AGENT_SDK_REFERENCE.md +1260 -0
- package/templates/typescript-oauth/OAUTH_SETUP.md +406 -0
- package/templates/typescript-oauth/README.md +350 -0
- package/templates/typescript-oauth/package.json +30 -0
- package/templates/typescript-starter/AI_AGENT_CLI_REFERENCE.md +701 -0
- package/templates/typescript-starter/AI_AGENT_SDK_REFERENCE.md +1260 -0
- package/templates/typescript-starter/README.md +312 -0
- package/templates/typescript-starter/package.json +32 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
const CACHE_KEY = 'nitrostack:cache';
|
|
3
|
+
/**
|
|
4
|
+
* Default in-memory cache storage
|
|
5
|
+
*/
|
|
6
|
+
export class InMemoryCacheStorage {
|
|
7
|
+
cache = new Map();
|
|
8
|
+
get(key) {
|
|
9
|
+
const item = this.cache.get(key);
|
|
10
|
+
if (!item)
|
|
11
|
+
return null;
|
|
12
|
+
if (item.expires < Date.now()) {
|
|
13
|
+
this.cache.delete(key);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return item.value;
|
|
17
|
+
}
|
|
18
|
+
set(key, value, ttl) {
|
|
19
|
+
this.cache.set(key, {
|
|
20
|
+
value,
|
|
21
|
+
expires: Date.now() + (ttl * 1000),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
delete(key) {
|
|
25
|
+
this.cache.delete(key);
|
|
26
|
+
}
|
|
27
|
+
clear() {
|
|
28
|
+
this.cache.clear();
|
|
29
|
+
}
|
|
30
|
+
// Cleanup expired entries periodically
|
|
31
|
+
cleanup() {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
for (const [key, item] of this.cache.entries()) {
|
|
34
|
+
if (item.expires < now) {
|
|
35
|
+
this.cache.delete(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Default cache storage instance
|
|
41
|
+
const defaultStorage = new InMemoryCacheStorage();
|
|
42
|
+
/**
|
|
43
|
+
* Cache decorator - caches tool results for a specified duration
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* @Tool({ name: 'get_products', ... })
|
|
48
|
+
* @Cache({ ttl: 300 }) // Cache for 5 minutes
|
|
49
|
+
* async getProducts(input: any) {
|
|
50
|
+
* return await this.database.query('SELECT * FROM products');
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* // With custom cache key
|
|
54
|
+
* @Cache({
|
|
55
|
+
* ttl: 300,
|
|
56
|
+
* key: (input) => `products:${input.category}`
|
|
57
|
+
* })
|
|
58
|
+
* async getProducts(input: any) { }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function Cache(options) {
|
|
62
|
+
return (target, propertyKey, descriptor) => {
|
|
63
|
+
const originalMethod = descriptor.value;
|
|
64
|
+
descriptor.value = async function (...args) {
|
|
65
|
+
const storage = options.storage || defaultStorage;
|
|
66
|
+
const input = args[0];
|
|
67
|
+
const context = args[1];
|
|
68
|
+
// Generate cache key
|
|
69
|
+
let cacheKey;
|
|
70
|
+
if (options.key) {
|
|
71
|
+
cacheKey = options.key(input, context);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
cacheKey = `${target.constructor.name}:${String(propertyKey)}:${JSON.stringify(input)}`;
|
|
75
|
+
}
|
|
76
|
+
// Check cache
|
|
77
|
+
const cached = await storage.get(cacheKey);
|
|
78
|
+
if (cached !== null && cached !== undefined) {
|
|
79
|
+
if (context?.logger) {
|
|
80
|
+
context.logger.info(`[Cache] Hit for key: ${cacheKey}`);
|
|
81
|
+
}
|
|
82
|
+
return cached;
|
|
83
|
+
}
|
|
84
|
+
// Execute original method
|
|
85
|
+
const result = await originalMethod.apply(this, args);
|
|
86
|
+
// Store in cache
|
|
87
|
+
await storage.set(cacheKey, result, options.ttl);
|
|
88
|
+
if (context?.logger) {
|
|
89
|
+
context.logger.info(`[Cache] Miss for key: ${cacheKey}, stored for ${options.ttl}s`);
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
};
|
|
93
|
+
// Store metadata
|
|
94
|
+
Reflect.defineMetadata(CACHE_KEY, options, target, propertyKey);
|
|
95
|
+
return descriptor;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get cache options from metadata
|
|
100
|
+
*/
|
|
101
|
+
export function getCacheMetadata(target, propertyKey) {
|
|
102
|
+
return Reflect.getMetadata(CACHE_KEY, target, propertyKey);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clear cache for a specific key or all keys
|
|
106
|
+
*/
|
|
107
|
+
export async function clearCache(key) {
|
|
108
|
+
if (key) {
|
|
109
|
+
await defaultStorage.delete(key);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
await defaultStorage.clear();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=cache.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.decorator.js","sourceRoot":"","sources":["../../../src/core/decorators/cache.decorator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* Health check result
|
|
4
|
+
*/
|
|
5
|
+
export interface HealthCheckResult {
|
|
6
|
+
status: 'up' | 'down' | 'degraded';
|
|
7
|
+
message?: string;
|
|
8
|
+
details?: any;
|
|
9
|
+
timestamp?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Health check interface
|
|
13
|
+
*/
|
|
14
|
+
export interface HealthCheckInterface {
|
|
15
|
+
check(): Promise<HealthCheckResult> | HealthCheckResult;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Health check options
|
|
19
|
+
*/
|
|
20
|
+
export interface HealthCheckOptions {
|
|
21
|
+
/** Health check name/identifier */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Description */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** Interval to run health check (in seconds) */
|
|
26
|
+
interval?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Health check decorator - marks a class as a health check
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* @HealthCheck({ name: 'database', description: 'Database connectivity' })
|
|
34
|
+
* export class DatabaseHealthCheck implements HealthCheckInterface {
|
|
35
|
+
* constructor(private database: DatabaseService) {}
|
|
36
|
+
*
|
|
37
|
+
* async check(): Promise<HealthCheckResult> {
|
|
38
|
+
* try {
|
|
39
|
+
* await this.database.ping();
|
|
40
|
+
* return { status: 'up', message: 'Database is healthy' };
|
|
41
|
+
* } catch (error) {
|
|
42
|
+
* return {
|
|
43
|
+
* status: 'down',
|
|
44
|
+
* message: 'Database connection failed',
|
|
45
|
+
* details: error.message
|
|
46
|
+
* };
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function HealthCheck(options: HealthCheckOptions): ClassDecorator;
|
|
53
|
+
/**
|
|
54
|
+
* Register a health check
|
|
55
|
+
*/
|
|
56
|
+
export declare function registerHealthCheck(checker: HealthCheckInterface, options: HealthCheckOptions): void;
|
|
57
|
+
/**
|
|
58
|
+
* Get all health check results
|
|
59
|
+
*/
|
|
60
|
+
export declare function getAllHealthChecks(): Promise<Record<string, HealthCheckResult>>;
|
|
61
|
+
/**
|
|
62
|
+
* Get a specific health check result
|
|
63
|
+
*/
|
|
64
|
+
export declare function getHealthCheck(name: string): Promise<HealthCheckResult | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Get overall health status
|
|
67
|
+
*/
|
|
68
|
+
export declare function getOverallHealth(): Promise<{
|
|
69
|
+
status: 'healthy' | 'unhealthy' | 'degraded';
|
|
70
|
+
checks: Record<string, HealthCheckResult>;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Check if a class is a health check
|
|
74
|
+
*/
|
|
75
|
+
export declare function isHealthCheck(target: any): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Get health check options from metadata
|
|
78
|
+
*/
|
|
79
|
+
export declare function getHealthCheckMetadata(target: any): HealthCheckOptions | undefined;
|
|
80
|
+
//# sourceMappingURL=health-check.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check.decorator.d.ts","sourceRoot":"","sources":["../../../src/core/decorators/health-check.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,UAAU,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,IAAI,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IAEb,kBAAkB;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AASD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,cAAc,CAIvE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CA4BpG;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAwBrF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAsBpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC;IAChD,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC3C,CAAC,CAkBD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAElD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,GAAG,GAAG,kBAAkB,GAAG,SAAS,CAElF"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
const HEALTH_CHECK_KEY = 'nitrostack:health_check';
|
|
3
|
+
// Global health check registry
|
|
4
|
+
const healthChecks = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* Health check decorator - marks a class as a health check
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* @HealthCheck({ name: 'database', description: 'Database connectivity' })
|
|
11
|
+
* export class DatabaseHealthCheck implements HealthCheckInterface {
|
|
12
|
+
* constructor(private database: DatabaseService) {}
|
|
13
|
+
*
|
|
14
|
+
* async check(): Promise<HealthCheckResult> {
|
|
15
|
+
* try {
|
|
16
|
+
* await this.database.ping();
|
|
17
|
+
* return { status: 'up', message: 'Database is healthy' };
|
|
18
|
+
* } catch (error) {
|
|
19
|
+
* return {
|
|
20
|
+
* status: 'down',
|
|
21
|
+
* message: 'Database connection failed',
|
|
22
|
+
* details: error.message
|
|
23
|
+
* };
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function HealthCheck(options) {
|
|
30
|
+
return (target) => {
|
|
31
|
+
Reflect.defineMetadata(HEALTH_CHECK_KEY, options, target);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Register a health check
|
|
36
|
+
*/
|
|
37
|
+
export function registerHealthCheck(checker, options) {
|
|
38
|
+
healthChecks.set(options.name, { checker, options });
|
|
39
|
+
// Run periodically if interval is set
|
|
40
|
+
if (options.interval) {
|
|
41
|
+
setInterval(async () => {
|
|
42
|
+
try {
|
|
43
|
+
const result = await checker.check();
|
|
44
|
+
const entry = healthChecks.get(options.name);
|
|
45
|
+
if (entry) {
|
|
46
|
+
entry.lastResult = {
|
|
47
|
+
...result,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const entry = healthChecks.get(options.name);
|
|
54
|
+
if (entry) {
|
|
55
|
+
entry.lastResult = {
|
|
56
|
+
status: 'down',
|
|
57
|
+
message: 'Health check failed',
|
|
58
|
+
details: error,
|
|
59
|
+
timestamp: Date.now(),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}, options.interval * 1000);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get all health check results
|
|
68
|
+
*/
|
|
69
|
+
export async function getAllHealthChecks() {
|
|
70
|
+
const results = {};
|
|
71
|
+
for (const [name, { checker, lastResult }] of healthChecks.entries()) {
|
|
72
|
+
if (lastResult) {
|
|
73
|
+
results[name] = lastResult;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
try {
|
|
77
|
+
results[name] = {
|
|
78
|
+
...await checker.check(),
|
|
79
|
+
timestamp: Date.now(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
results[name] = {
|
|
84
|
+
status: 'down',
|
|
85
|
+
message: 'Health check failed',
|
|
86
|
+
details: error.message,
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return results;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get a specific health check result
|
|
96
|
+
*/
|
|
97
|
+
export async function getHealthCheck(name) {
|
|
98
|
+
const entry = healthChecks.get(name);
|
|
99
|
+
if (!entry)
|
|
100
|
+
return null;
|
|
101
|
+
if (entry.lastResult) {
|
|
102
|
+
return entry.lastResult;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const result = await entry.checker.check();
|
|
106
|
+
return {
|
|
107
|
+
...result,
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return {
|
|
113
|
+
status: 'down',
|
|
114
|
+
message: 'Health check failed',
|
|
115
|
+
details: error.message,
|
|
116
|
+
timestamp: Date.now(),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get overall health status
|
|
122
|
+
*/
|
|
123
|
+
export async function getOverallHealth() {
|
|
124
|
+
const checks = await getAllHealthChecks();
|
|
125
|
+
const statuses = Object.values(checks).map(c => c.status);
|
|
126
|
+
let overallStatus;
|
|
127
|
+
if (statuses.every(s => s === 'up')) {
|
|
128
|
+
overallStatus = 'healthy';
|
|
129
|
+
}
|
|
130
|
+
else if (statuses.some(s => s === 'down')) {
|
|
131
|
+
overallStatus = 'unhealthy';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
overallStatus = 'degraded';
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
status: overallStatus,
|
|
138
|
+
checks,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if a class is a health check
|
|
143
|
+
*/
|
|
144
|
+
export function isHealthCheck(target) {
|
|
145
|
+
return Reflect.hasMetadata(HEALTH_CHECK_KEY, target);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get health check options from metadata
|
|
149
|
+
*/
|
|
150
|
+
export function getHealthCheckMetadata(target) {
|
|
151
|
+
return Reflect.getMetadata(HEALTH_CHECK_KEY, target);
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=health-check.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check.decorator.js","sourceRoot":"","sources":["../../../src/core/decorators/health-check.decorator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* Rate limit options
|
|
4
|
+
*/
|
|
5
|
+
export interface RateLimitOptions {
|
|
6
|
+
/** Maximum number of requests */
|
|
7
|
+
requests: number;
|
|
8
|
+
/** Time window (e.g., '1m', '1h', '1d') */
|
|
9
|
+
window: string;
|
|
10
|
+
/** Custom key generator (default: uses auth subject or IP) */
|
|
11
|
+
key?: (context: any) => string;
|
|
12
|
+
/** Storage for rate limit data */
|
|
13
|
+
storage?: RateLimitStorage;
|
|
14
|
+
/** Custom error message */
|
|
15
|
+
message?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Rate limit storage interface
|
|
19
|
+
*/
|
|
20
|
+
export interface RateLimitStorage {
|
|
21
|
+
increment(key: string, windowMs: number): Promise<number> | number;
|
|
22
|
+
reset(key: string): Promise<void> | void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Default in-memory rate limit storage
|
|
26
|
+
*/
|
|
27
|
+
export declare class InMemoryRateLimitStorage implements RateLimitStorage {
|
|
28
|
+
private limits;
|
|
29
|
+
increment(key: string, windowMs: number): number;
|
|
30
|
+
reset(key: string): void;
|
|
31
|
+
cleanup(): void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Rate limit decorator - limits the number of requests per time window
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* @Tool({ name: 'send_email', ... })
|
|
39
|
+
* @RateLimit({ requests: 10, window: '1m' }) // 10 requests per minute
|
|
40
|
+
* async sendEmail(input: any, context: ExecutionContext) {
|
|
41
|
+
* // Send email
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* // With custom key (per user)
|
|
45
|
+
* @RateLimit({
|
|
46
|
+
* requests: 100,
|
|
47
|
+
* window: '1h',
|
|
48
|
+
* key: (ctx) => ctx.auth?.subject || 'anonymous'
|
|
49
|
+
* })
|
|
50
|
+
* async createOrder(input: any, context: ExecutionContext) { }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function RateLimit(options: RateLimitOptions): MethodDecorator;
|
|
54
|
+
/**
|
|
55
|
+
* Get rate limit options from metadata
|
|
56
|
+
*/
|
|
57
|
+
export declare function getRateLimitMetadata(target: any, propertyKey: string | symbol): RateLimitOptions | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Reset rate limit for a specific key
|
|
60
|
+
*/
|
|
61
|
+
export declare function resetRateLimit(key: string): Promise<void>;
|
|
62
|
+
//# sourceMappingURL=rate-limit.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.decorator.d.ts","sourceRoot":"","sources":["../../../src/core/decorators/rate-limit.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IAEjB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IAEf,8DAA8D;IAC9D,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;IAE/B,kCAAkC;IAClC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACnE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED;;GAEG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,OAAO,CAAC,MAAM,CAAyD;IAEvE,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAmBhD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKxB,OAAO,IAAI,IAAI;CAQhB;AA8BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA+CpE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAE5G;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/D"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
const RATE_LIMIT_KEY = 'nitrostack:rate_limit';
|
|
3
|
+
/**
|
|
4
|
+
* Default in-memory rate limit storage
|
|
5
|
+
*/
|
|
6
|
+
export class InMemoryRateLimitStorage {
|
|
7
|
+
limits = new Map();
|
|
8
|
+
increment(key, windowMs) {
|
|
9
|
+
const now = Date.now();
|
|
10
|
+
const limit = this.limits.get(key);
|
|
11
|
+
// Reset if window expired
|
|
12
|
+
if (!limit || limit.resetAt < now) {
|
|
13
|
+
this.limits.set(key, {
|
|
14
|
+
count: 1,
|
|
15
|
+
resetAt: now + windowMs,
|
|
16
|
+
});
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
// Increment
|
|
20
|
+
limit.count++;
|
|
21
|
+
this.limits.set(key, limit);
|
|
22
|
+
return limit.count;
|
|
23
|
+
}
|
|
24
|
+
reset(key) {
|
|
25
|
+
this.limits.delete(key);
|
|
26
|
+
}
|
|
27
|
+
// Cleanup expired entries
|
|
28
|
+
cleanup() {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
for (const [key, limit] of this.limits.entries()) {
|
|
31
|
+
if (limit.resetAt < now) {
|
|
32
|
+
this.limits.delete(key);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Default storage instance
|
|
38
|
+
const defaultStorage = new InMemoryRateLimitStorage();
|
|
39
|
+
// Cleanup every minute
|
|
40
|
+
setInterval(() => defaultStorage.cleanup(), 60000);
|
|
41
|
+
/**
|
|
42
|
+
* Parse time window string to milliseconds
|
|
43
|
+
*/
|
|
44
|
+
function parseWindow(window) {
|
|
45
|
+
const match = window.match(/^(\d+)([smhd])$/);
|
|
46
|
+
if (!match) {
|
|
47
|
+
throw new Error(`Invalid time window format: ${window}. Use format like '1m', '1h', '1d'`);
|
|
48
|
+
}
|
|
49
|
+
const value = parseInt(match[1], 10);
|
|
50
|
+
const unit = match[2];
|
|
51
|
+
const multipliers = {
|
|
52
|
+
s: 1000,
|
|
53
|
+
m: 60 * 1000,
|
|
54
|
+
h: 60 * 60 * 1000,
|
|
55
|
+
d: 24 * 60 * 60 * 1000,
|
|
56
|
+
};
|
|
57
|
+
return value * multipliers[unit];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Rate limit decorator - limits the number of requests per time window
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* @Tool({ name: 'send_email', ... })
|
|
65
|
+
* @RateLimit({ requests: 10, window: '1m' }) // 10 requests per minute
|
|
66
|
+
* async sendEmail(input: any, context: ExecutionContext) {
|
|
67
|
+
* // Send email
|
|
68
|
+
* }
|
|
69
|
+
*
|
|
70
|
+
* // With custom key (per user)
|
|
71
|
+
* @RateLimit({
|
|
72
|
+
* requests: 100,
|
|
73
|
+
* window: '1h',
|
|
74
|
+
* key: (ctx) => ctx.auth?.subject || 'anonymous'
|
|
75
|
+
* })
|
|
76
|
+
* async createOrder(input: any, context: ExecutionContext) { }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function RateLimit(options) {
|
|
80
|
+
return (target, propertyKey, descriptor) => {
|
|
81
|
+
const originalMethod = descriptor.value;
|
|
82
|
+
const windowMs = parseWindow(options.window);
|
|
83
|
+
descriptor.value = async function (...args) {
|
|
84
|
+
const context = args[1];
|
|
85
|
+
const storage = options.storage || defaultStorage;
|
|
86
|
+
// Generate rate limit key
|
|
87
|
+
let rateLimitKey;
|
|
88
|
+
if (options.key) {
|
|
89
|
+
rateLimitKey = options.key(context);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Default: use auth subject or 'anonymous'
|
|
93
|
+
rateLimitKey = context?.auth?.subject || 'anonymous';
|
|
94
|
+
}
|
|
95
|
+
const fullKey = `${target.constructor.name}:${String(propertyKey)}:${rateLimitKey}`;
|
|
96
|
+
// Check rate limit
|
|
97
|
+
const count = await storage.increment(fullKey, windowMs);
|
|
98
|
+
if (count > options.requests) {
|
|
99
|
+
const message = options.message ||
|
|
100
|
+
`Rate limit exceeded. Maximum ${options.requests} requests per ${options.window}`;
|
|
101
|
+
if (context?.logger) {
|
|
102
|
+
context.logger.warn(`[RateLimit] Limit exceeded for key: ${fullKey}`);
|
|
103
|
+
}
|
|
104
|
+
throw new Error(message);
|
|
105
|
+
}
|
|
106
|
+
if (context?.logger) {
|
|
107
|
+
context.logger.info(`[RateLimit] Request ${count}/${options.requests} for key: ${fullKey}`);
|
|
108
|
+
}
|
|
109
|
+
// Execute original method
|
|
110
|
+
return await originalMethod.apply(this, args);
|
|
111
|
+
};
|
|
112
|
+
// Store metadata
|
|
113
|
+
Reflect.defineMetadata(RATE_LIMIT_KEY, options, target, propertyKey);
|
|
114
|
+
return descriptor;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get rate limit options from metadata
|
|
119
|
+
*/
|
|
120
|
+
export function getRateLimitMetadata(target, propertyKey) {
|
|
121
|
+
return Reflect.getMetadata(RATE_LIMIT_KEY, target, propertyKey);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Reset rate limit for a specific key
|
|
125
|
+
*/
|
|
126
|
+
export async function resetRateLimit(key) {
|
|
127
|
+
await defaultStorage.reset(key);
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=rate-limit.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.decorator.js","sourceRoot":"","sources":["../../../src/core/decorators/rate-limit.decorator.ts"],"names":[],"mappings":"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"}
|