@nitrostack/core 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/LICENSE +201 -0
- package/README.md +80 -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 +31 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +46 -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/secure-secret.d.ts +136 -0
- package/dist/auth/secure-secret.d.ts.map +1 -0
- package/dist/auth/secure-secret.js +182 -0
- package/dist/auth/secure-secret.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 +174 -0
- package/dist/auth/simple-jwt.d.ts.map +1 -0
- package/dist/auth/simple-jwt.js +162 -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 +59 -0
- package/dist/auth/token-validation.d.ts.map +1 -0
- package/dist/auth/token-validation.js +241 -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/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 +59 -0
- package/dist/core/app-decorator.d.ts.map +1 -0
- package/dist/core/app-decorator.js +322 -0
- package/dist/core/app-decorator.js.map +1 -0
- package/dist/core/builders.d.ts +50 -0
- package/dist/core/builders.d.ts.map +1 -0
- package/dist/core/builders.js +139 -0
- package/dist/core/builders.js.map +1 -0
- package/dist/core/component.d.ts +111 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/component.js +228 -0
- package/dist/core/component.js.map +1 -0
- package/dist/core/config-module.d.ts +62 -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 +63 -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 +190 -0
- package/dist/core/decorators.d.ts.map +1 -0
- package/dist/core/decorators.js +170 -0
- package/dist/core/decorators.js.map +1 -0
- package/dist/core/di/container.d.ts +64 -0
- package/dist/core/di/container.d.ts.map +1 -0
- package/dist/core/di/container.js +105 -0
- package/dist/core/di/container.js.map +1 -0
- package/dist/core/di/injectable.decorator.d.ts +62 -0
- package/dist/core/di/injectable.decorator.d.ts.map +1 -0
- package/dist/core/di/injectable.decorator.js +66 -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 +72 -0
- package/dist/core/events/event.decorator.js.map +1 -0
- package/dist/core/events/log-emitter.d.ts +14 -0
- package/dist/core/events/log-emitter.d.ts.map +1 -0
- package/dist/core/events/log-emitter.js +20 -0
- package/dist/core/events/log-emitter.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 +39 -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 +57 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +59 -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 +53 -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 +93 -0
- package/dist/core/module.d.ts.map +1 -0
- package/dist/core/module.js +87 -0
- package/dist/core/module.js.map +1 -0
- package/dist/core/oauth-module.d.ts +123 -0
- package/dist/core/oauth-module.d.ts.map +1 -0
- package/dist/core/oauth-module.js +324 -0
- package/dist/core/oauth-module.js.map +1 -0
- package/dist/core/pipes/pipe.decorator.d.ts +64 -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 +41 -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 +46 -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 +47 -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 +129 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +617 -0
- package/dist/core/server.js.map +1 -0
- package/dist/core/tool.d.ts +108 -0
- package/dist/core/tool.d.ts.map +1 -0
- package/dist/core/tool.js +241 -0
- package/dist/core/tool.js.map +1 -0
- package/dist/core/transports/discovery-http-server.d.ts +19 -0
- package/dist/core/transports/discovery-http-server.d.ts.map +1 -0
- package/dist/core/transports/discovery-http-server.js +54 -0
- package/dist/core/transports/discovery-http-server.js.map +1 -0
- package/dist/core/transports/http-server.d.ts +108 -0
- package/dist/core/transports/http-server.d.ts.map +1 -0
- package/dist/core/transports/http-server.js +293 -0
- package/dist/core/transports/http-server.js.map +1 -0
- package/dist/core/transports/streamable-http.d.ts +177 -0
- package/dist/core/transports/streamable-http.d.ts.map +1 -0
- package/dist/core/transports/streamable-http.js +1287 -0
- package/dist/core/transports/streamable-http.js.map +1 -0
- package/dist/core/types.d.ts +195 -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 +103 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +161 -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/package.json +89 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
var OAuthModule_1;
|
|
14
|
+
import 'reflect-metadata';
|
|
15
|
+
/**
|
|
16
|
+
* OAuth Module - Enable OAuth 2.1 authentication in your MCP server
|
|
17
|
+
*
|
|
18
|
+
* This module provides:
|
|
19
|
+
* - Protected Resource Metadata (RFC 9728)
|
|
20
|
+
* - Token validation with audience binding (RFC 8707)
|
|
21
|
+
* - Token introspection (RFC 7662)
|
|
22
|
+
* - PKCE support (RFC 7636)
|
|
23
|
+
*
|
|
24
|
+
* Compatible with OpenAI Apps SDK and MCP specification.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { McpApplicationFactory, OAuthModule } from 'nitrostack';
|
|
29
|
+
* import { AppModule } from './app.module.js';
|
|
30
|
+
*
|
|
31
|
+
* @McpApp({
|
|
32
|
+
* module: AppModule,
|
|
33
|
+
* server: {
|
|
34
|
+
* name: 'OAuth MCP Server',
|
|
35
|
+
* version: '1.0.0',
|
|
36
|
+
* },
|
|
37
|
+
* })
|
|
38
|
+
* @Module({
|
|
39
|
+
* name: 'app',
|
|
40
|
+
* imports: [
|
|
41
|
+
* // Enable OAuth 2.1 authentication
|
|
42
|
+
* OAuthModule.forRoot({
|
|
43
|
+
* resourceUri: process.env.RESOURCE_URI!,
|
|
44
|
+
* authorizationServers: [process.env.AUTH_SERVER_URL!],
|
|
45
|
+
* scopesSupported: ['mcp:read', 'mcp:write', 'tools:execute'],
|
|
46
|
+
* tokenIntrospectionEndpoint: process.env.INTROSPECTION_ENDPOINT,
|
|
47
|
+
* tokenIntrospectionClientId: process.env.INTROSPECTION_CLIENT_ID,
|
|
48
|
+
* tokenIntrospectionClientSecret: process.env.INTROSPECTION_CLIENT_SECRET,
|
|
49
|
+
* }),
|
|
50
|
+
* ],
|
|
51
|
+
* })
|
|
52
|
+
* export class AppModule {}
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
import { Injectable, Inject } from './di/injectable.decorator.js';
|
|
56
|
+
import { NitroStackServer } from './server.js';
|
|
57
|
+
import { DiscoveryHttpServer } from './transports/discovery-http-server.js';
|
|
58
|
+
let OAuthModule = class OAuthModule {
|
|
59
|
+
static { OAuthModule_1 = this; }
|
|
60
|
+
config;
|
|
61
|
+
server;
|
|
62
|
+
logger;
|
|
63
|
+
static config = null;
|
|
64
|
+
discoveryServer = null;
|
|
65
|
+
wellKnownHandler = (req, res) => {
|
|
66
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
67
|
+
res.end(JSON.stringify({
|
|
68
|
+
issuer: this.config.issuer,
|
|
69
|
+
token_endpoint: `${this.config.authorizationServers[0]}/oauth/token`,
|
|
70
|
+
// Add other metadata as needed
|
|
71
|
+
}));
|
|
72
|
+
};
|
|
73
|
+
resourceMetadataHandler = (req, res) => {
|
|
74
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
75
|
+
// RFC 9728 - Protected Resource Metadata format
|
|
76
|
+
const metadata = {
|
|
77
|
+
resource: this.config.resourceUri,
|
|
78
|
+
authorization_servers: this.config.authorizationServers,
|
|
79
|
+
};
|
|
80
|
+
// Add optional fields
|
|
81
|
+
if (this.config.scopesSupported && this.config.scopesSupported.length > 0) {
|
|
82
|
+
metadata.scopes_supported = this.config.scopesSupported;
|
|
83
|
+
}
|
|
84
|
+
res.end(JSON.stringify(metadata));
|
|
85
|
+
};
|
|
86
|
+
constructor(config, server, logger) {
|
|
87
|
+
this.config = config;
|
|
88
|
+
this.server = server;
|
|
89
|
+
this.logger = logger;
|
|
90
|
+
OAuthModule_1.config = config;
|
|
91
|
+
}
|
|
92
|
+
onModuleInit() {
|
|
93
|
+
// Register the discovery endpoints
|
|
94
|
+
// Handlers are now arrow functions, so no need to bind
|
|
95
|
+
}
|
|
96
|
+
async start() {
|
|
97
|
+
this.logger.info('OAuthModule: start method called');
|
|
98
|
+
const transportType = this.server._transportType;
|
|
99
|
+
// Get port from environment or config, fallback to 3005
|
|
100
|
+
// Check MCP_SERVER_PORT first (set by dev command), then PORT, then config
|
|
101
|
+
const port = process.env.MCP_SERVER_PORT
|
|
102
|
+
? parseInt(process.env.MCP_SERVER_PORT)
|
|
103
|
+
: process.env.PORT
|
|
104
|
+
? parseInt(process.env.PORT)
|
|
105
|
+
: (this.config.http?.port || 3005);
|
|
106
|
+
if (transportType === 'stdio') {
|
|
107
|
+
this.logger.info(`OAuthModule: Running in STDIO mode, starting DiscoveryHttpServer on port ${port}`);
|
|
108
|
+
// In stdio mode, start a separate discovery server for OAuth endpoints
|
|
109
|
+
this.discoveryServer = new DiscoveryHttpServer(port, this.logger);
|
|
110
|
+
this.registerDiscoveryHandlers(this.discoveryServer);
|
|
111
|
+
await this.discoveryServer.start();
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this.logger.info(`OAuthModule: Running in ${transportType} mode, registering handlers with main server`);
|
|
115
|
+
// In http or dual mode, register the handlers with the main server
|
|
116
|
+
const httpTransport = this.server._httpTransport;
|
|
117
|
+
if (httpTransport) {
|
|
118
|
+
this.registerDiscoveryHandlers(httpTransport);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Fallback: if httpTransport is not available, start a discovery server anyway
|
|
122
|
+
// This handles edge cases where the transport setup fails or is delayed
|
|
123
|
+
this.logger.warn(`OAuthModule: httpTransport not found for ${transportType} mode. Starting fallback DiscoveryHttpServer on port ${port}`);
|
|
124
|
+
this.discoveryServer = new DiscoveryHttpServer(port, this.logger);
|
|
125
|
+
this.registerDiscoveryHandlers(this.discoveryServer);
|
|
126
|
+
await this.discoveryServer.start();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async stop() {
|
|
131
|
+
if (this.discoveryServer) {
|
|
132
|
+
await this.discoveryServer.stop();
|
|
133
|
+
this.discoveryServer = null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
registerDiscoveryHandlers(server) {
|
|
137
|
+
server.on('/.well-known/oauth-authorization-server', this.wellKnownHandler);
|
|
138
|
+
server.on('/.well-known/oauth-protected-resource', this.resourceMetadataHandler);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Configure OAuth module for the application
|
|
142
|
+
*/
|
|
143
|
+
static forRoot(config) {
|
|
144
|
+
// Validate required fields
|
|
145
|
+
if (!config.resourceUri) {
|
|
146
|
+
throw new Error('OAuthModule: resourceUri is required');
|
|
147
|
+
}
|
|
148
|
+
if (!config.authorizationServers || config.authorizationServers.length === 0) {
|
|
149
|
+
throw new Error('OAuthModule: at least one authorizationServer is required');
|
|
150
|
+
}
|
|
151
|
+
// Set default audience to resourceUri if not provided
|
|
152
|
+
if (!config.audience) {
|
|
153
|
+
config.audience = config.resourceUri;
|
|
154
|
+
}
|
|
155
|
+
this.config = config;
|
|
156
|
+
return {
|
|
157
|
+
module: OAuthModule_1,
|
|
158
|
+
providers: [
|
|
159
|
+
{ provide: 'OAUTH_CONFIG', useValue: config }
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get current OAuth configuration
|
|
165
|
+
*/
|
|
166
|
+
static getConfig() {
|
|
167
|
+
return this.config;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Validate an access token
|
|
171
|
+
*
|
|
172
|
+
* Performs:
|
|
173
|
+
* 1. Token introspection (if endpoint configured)
|
|
174
|
+
* 2. Audience validation (RFC 8807)
|
|
175
|
+
* 3. Issuer validation (if configured)
|
|
176
|
+
* 4. Custom validation (if configured)
|
|
177
|
+
*/
|
|
178
|
+
static async validateToken(token) {
|
|
179
|
+
if (!this.config) {
|
|
180
|
+
return { valid: false, error: 'OAuth module not configured' };
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
// Decode the header to check token type and provide helpful error message
|
|
184
|
+
try {
|
|
185
|
+
const headerPart = token.split('.')[0];
|
|
186
|
+
const decodedHeader = JSON.parse(Buffer.from(headerPart, 'base64').toString());
|
|
187
|
+
// Check if we received a JWE (encrypted) token instead of JWT
|
|
188
|
+
if (decodedHeader.alg === 'dir' || decodedHeader.enc) {
|
|
189
|
+
return {
|
|
190
|
+
valid: false,
|
|
191
|
+
error: 'Received encrypted JWE token. MCP servers require unencrypted JWT access tokens. Check your OAuth provider application settings to ensure ID Token Encryption is disabled and that the "audience" parameter is being sent in authorization requests.'
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (headerError) {
|
|
196
|
+
// If header decode fails, continue with normal validation
|
|
197
|
+
}
|
|
198
|
+
// If introspection endpoint is configured, use it
|
|
199
|
+
if (this.config.tokenIntrospectionEndpoint) {
|
|
200
|
+
return await this.introspectToken(token);
|
|
201
|
+
}
|
|
202
|
+
// For JWT tokens without introspection, decode and validate
|
|
203
|
+
// Note: In production, you should validate JWT signature
|
|
204
|
+
const payload = this.decodeToken(token);
|
|
205
|
+
if (!payload) {
|
|
206
|
+
return { valid: false, error: 'Invalid token format' };
|
|
207
|
+
}
|
|
208
|
+
// Validate audience (RFC 8707 - critical for security)
|
|
209
|
+
if (payload.aud) {
|
|
210
|
+
const audiences = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
|
|
211
|
+
if (!audiences.includes(this.config.audience)) {
|
|
212
|
+
return {
|
|
213
|
+
valid: false,
|
|
214
|
+
error: `Token audience mismatch. Expected: ${this.config.audience}, Got: ${audiences.join(', ')}`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Validate issuer
|
|
219
|
+
if (this.config.issuer && payload.iss !== this.config.issuer) {
|
|
220
|
+
return {
|
|
221
|
+
valid: false,
|
|
222
|
+
error: `Token issuer mismatch. Expected: ${this.config.issuer}, Got: ${payload.iss}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
// Check expiration
|
|
226
|
+
const expiration = payload.exp;
|
|
227
|
+
if (expiration && expiration < Date.now() / 1000) {
|
|
228
|
+
return { valid: false, error: 'Token expired' };
|
|
229
|
+
}
|
|
230
|
+
// Custom validation
|
|
231
|
+
if (this.config.customValidation) {
|
|
232
|
+
const customValid = await this.config.customValidation(payload);
|
|
233
|
+
if (!customValid) {
|
|
234
|
+
return { valid: false, error: 'Custom validation failed' };
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return { valid: true, payload };
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
return { valid: false, error: error instanceof Error ? error.message : String(error) };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Introspect token using RFC 7662
|
|
245
|
+
* @private
|
|
246
|
+
*/
|
|
247
|
+
static async introspectToken(token) {
|
|
248
|
+
if (!this.config?.tokenIntrospectionEndpoint) {
|
|
249
|
+
return { valid: false, error: 'Introspection endpoint not configured' };
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
const auth = Buffer.from(`${this.config.tokenIntrospectionClientId}:${this.config.tokenIntrospectionClientSecret}`).toString('base64');
|
|
253
|
+
const response = await fetch(this.config.tokenIntrospectionEndpoint, {
|
|
254
|
+
method: 'POST',
|
|
255
|
+
headers: {
|
|
256
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
257
|
+
'Authorization': `Basic ${auth}`,
|
|
258
|
+
},
|
|
259
|
+
body: new URLSearchParams({
|
|
260
|
+
token: token,
|
|
261
|
+
token_type_hint: 'access_token',
|
|
262
|
+
}),
|
|
263
|
+
});
|
|
264
|
+
if (!response.ok) {
|
|
265
|
+
return {
|
|
266
|
+
valid: false,
|
|
267
|
+
error: `Introspection failed: ${response.status} ${response.statusText}`,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
const result = await response.json();
|
|
271
|
+
if (!result.active) {
|
|
272
|
+
return { valid: false, error: 'Token is not active' };
|
|
273
|
+
}
|
|
274
|
+
// Validate audience from introspection response
|
|
275
|
+
if (result.aud) {
|
|
276
|
+
const audiences = Array.isArray(result.aud) ? result.aud : [result.aud];
|
|
277
|
+
if (!audiences.includes(this.config.audience)) {
|
|
278
|
+
return {
|
|
279
|
+
valid: false,
|
|
280
|
+
error: `Token audience mismatch. Expected: ${this.config.audience}`,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return { valid: true, payload: result };
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
return { valid: false, error: `Introspection error: ${error instanceof Error ? error.message : String(error)}` };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Decode JWT token (without validation)
|
|
292
|
+
* @private
|
|
293
|
+
*/
|
|
294
|
+
static decodeToken(token) {
|
|
295
|
+
try {
|
|
296
|
+
const parts = token.split('.');
|
|
297
|
+
if (parts.length !== 3)
|
|
298
|
+
return null;
|
|
299
|
+
// Convert base64url to base64 by replacing URL-safe characters
|
|
300
|
+
let base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
301
|
+
// Add padding if necessary
|
|
302
|
+
const padding = base64.length % 4;
|
|
303
|
+
if (padding === 2) {
|
|
304
|
+
base64 += '==';
|
|
305
|
+
}
|
|
306
|
+
else if (padding === 3) {
|
|
307
|
+
base64 += '=';
|
|
308
|
+
}
|
|
309
|
+
const payload = JSON.parse(Buffer.from(base64, 'base64').toString('utf8'));
|
|
310
|
+
return payload;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
OAuthModule = OAuthModule_1 = __decorate([
|
|
318
|
+
Injectable(),
|
|
319
|
+
__param(0, Inject('OAUTH_CONFIG')),
|
|
320
|
+
__param(2, Inject('Logger')),
|
|
321
|
+
__metadata("design:paramtypes", [Object, NitroStackServer, Object])
|
|
322
|
+
], OAuthModule);
|
|
323
|
+
export { OAuthModule };
|
|
324
|
+
//# sourceMappingURL=oauth-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-module.js","sourceRoot":"","sources":["../../src/core/oauth-module.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,OAAO,kBAAkB,CAAC;AA+E1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAGrE,IAAM,WAAW,GAAjB,MAAM,WAAW;;IA8BY;IACxB;IACkB;IA/BpB,MAAM,CAAC,MAAM,GAA6B,IAAI,CAAC;IAC/C,eAAe,GAA+B,IAAI,CAAC;IAEnD,gBAAgB,GAAG,CAAC,GAAY,EAAE,GAA0G,EAAE,EAAE;QACtJ,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,cAAc,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,cAAc;YACpE,+BAA+B;SAChC,CAAC,CAAC,CAAC;IACN,CAAC,CAAC;IAEM,uBAAuB,GAAG,CAAC,GAAY,EAAE,GAA0G,EAAE,EAAE;QAC7J,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,gDAAgD;QAChD,MAAM,QAAQ,GAAuF;YACnG,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACjC,qBAAqB,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB;SACxD,CAAC;QAEF,sBAAsB;QACtB,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1E,QAAQ,CAAC,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;QAC1D,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,YACkC,MAAyB,EACjD,MAAwB,EACN,MAAc;QAFR,WAAM,GAAN,MAAM,CAAmB;QACjD,WAAM,GAAN,MAAM,CAAkB;QACN,WAAM,GAAN,MAAM,CAAQ;QAExC,aAAW,CAAC,MAAM,GAAG,MAAM,CAAC;IAC9B,CAAC;IAEM,YAAY;QACjB,mCAAmC;QACnC,uDAAuD;IACzD,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACrD,MAAM,aAAa,GAAI,IAAI,CAAC,MAAc,CAAC,cAAc,CAAC;QAE1D,wDAAwD;QACxD,2EAA2E;QAC3E,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe;YACtC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;YACvC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI;gBAChB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC5B,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC;QAEvC,IAAI,aAAa,KAAK,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4EAA4E,IAAI,EAAE,CAAC,CAAC;YACrG,uEAAuE;YACvE,IAAI,CAAC,eAAe,GAAG,IAAI,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAClE,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACrD,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,aAAa,8CAA8C,CAAC,CAAC;YACzG,mEAAmE;YACnE,MAAM,aAAa,GAAI,IAAI,CAAC,MAAc,CAAC,cAAc,CAAC;YAC1D,IAAI,aAAa,EAAE,CAAC;gBAClB,IAAI,CAAC,yBAAyB,CAAC,aAAa,CAAC,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACN,+EAA+E;gBAC/E,wEAAwE;gBACxE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,aAAa,wDAAwD,IAAI,EAAE,CAAC,CAAC;gBAC1I,IAAI,CAAC,eAAe,GAAG,IAAI,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClE,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBACrD,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC;IAEO,yBAAyB,CAAC,MAA8E;QAC9G,MAAM,CAAC,EAAE,CAAC,yCAAyC,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC5E,MAAM,CAAC,EAAE,CAAC,uCAAuC,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACnF,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,MAAyB;QACtC,2BAA2B;QAC3B,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,MAAM,CAAC,oBAAoB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QAED,sDAAsD;QACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC;QACvC,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,OAAO;YACL,MAAM,EAAE,aAAW;YACnB,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE;aAC9C;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,SAAS;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAa;QAKtC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC;QAChE,CAAC;QAED,IAAI,CAAC;YACH,0EAA0E;YAC1E,IAAI,CAAC;gBACH,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACvC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAE/E,8DAA8D;gBAC9D,IAAI,aAAa,CAAC,GAAG,KAAK,KAAK,IAAI,aAAa,CAAC,GAAG,EAAE,CAAC;oBACrD,OAAO;wBACL,KAAK,EAAE,KAAK;wBACZ,KAAK,EAAE,sPAAsP;qBAC9P,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,WAAW,EAAE,CAAC;gBACrB,0DAA0D;YAC5D,CAAC;YAED,kDAAkD;YAClD,IAAI,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE,CAAC;gBAC3C,OAAO,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC3C,CAAC;YAED,4DAA4D;YAC5D,yDAAyD;YACzD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAExC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;YACzD,CAAC;YAED,uDAAuD;YACvD,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;gBAChB,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC3E,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAS,CAAC,EAAE,CAAC;oBAC/C,OAAO;wBACL,KAAK,EAAE,KAAK;wBACZ,KAAK,EAAE,sCAAsC,IAAI,CAAC,MAAM,CAAC,QAAQ,UAAU,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;qBAClG,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,kBAAkB;YAClB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC7D,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,oCAAoC,IAAI,CAAC,MAAM,CAAC,MAAM,UAAU,OAAO,CAAC,GAAG,EAAE;iBACrF,CAAC;YACJ,CAAC;YAED,mBAAmB;YACnB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAyB,CAAC;YACrD,IAAI,UAAU,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;gBACjD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;YAClD,CAAC;YAED,oBAAoB;YACpB,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBACjC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;gBAChE,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC;gBAC7D,CAAC;YACH,CAAC;YAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAElC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACzF,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,KAAa;QAKhD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,0BAA0B,EAAE,CAAC;YAC7C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC;QAC1E,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CACtB,GAAG,IAAI,CAAC,MAAM,CAAC,0BAA0B,IAAI,IAAI,CAAC,MAAM,CAAC,8BAA8B,EAAE,CAC1F,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAErB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,0BAA0B,EAAE;gBACnE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;oBACnD,eAAe,EAAE,SAAS,IAAI,EAAE;iBACjC;gBACD,IAAI,EAAE,IAAI,eAAe,CAAC;oBACxB,KAAK,EAAE,KAAK;oBACZ,eAAe,EAAE,cAAc;iBAChC,CAAC;aACH,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,yBAAyB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE;iBACzE,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAmD,CAAC;YAEtF,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACnB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;YACxD,CAAC;YAED,gDAAgD;YAChD,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;gBACf,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACxE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAS,CAAC,EAAE,CAAC;oBAC/C,OAAO;wBACL,KAAK,EAAE,KAAK;wBACZ,KAAK,EAAE,sCAAsC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;qBACpE,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAiC,EAAE,CAAC;QAErE,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACnH,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,MAAM,CAAC,WAAW,CAAC,KAAa;QACtC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAEpC,+DAA+D;YAC/D,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAE5D,2BAA2B;YAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YAClC,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;gBAClB,MAAM,IAAI,IAAI,CAAC;YACjB,CAAC;iBAAM,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,CAAC;YAChB,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC/C,CAAC;YAEF,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;;AA7SU,WAAW;IADvB,UAAU,EAAE;IA+BR,WAAA,MAAM,CAAC,cAAc,CAAC,CAAA;IAEtB,WAAA,MAAM,CAAC,QAAQ,CAAC,CAAA;6CADD,gBAAgB;GA/BvB,WAAW,CA8SvB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { PipeConstructor } from './pipe.interface.js';
|
|
3
|
+
import type { ClassConstructor } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Marks a class as a pipe
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* @Pipe()
|
|
10
|
+
* export class ValidationPipe implements PipeInterface {
|
|
11
|
+
* transform(value: unknown, metadata: ArgumentMetadata) {
|
|
12
|
+
* // Validate and transform
|
|
13
|
+
* return value;
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function Pipe(): ClassDecorator;
|
|
19
|
+
/**
|
|
20
|
+
* Apply pipes to tool input (entire input object)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* @Tool({ name: 'create_user', ... })
|
|
25
|
+
* @UsePipes(ValidationPipe, TransformPipe)
|
|
26
|
+
* async createUser(input: unknown) { }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function UsePipes(...pipes: PipeConstructor[]): MethodDecorator;
|
|
30
|
+
/**
|
|
31
|
+
* Parameter decorator to apply pipes to specific parameters
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* @Tool({ name: 'create_user', ... })
|
|
36
|
+
* async createUser(@Body(ValidationPipe) input: CreateUserDto) { }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function Body(...pipes: PipeConstructor[]): ParameterDecorator;
|
|
40
|
+
/**
|
|
41
|
+
* Shorthand for validation pipe
|
|
42
|
+
*/
|
|
43
|
+
export declare function Validated(): ParameterDecorator;
|
|
44
|
+
/**
|
|
45
|
+
* Parameter pipes metadata
|
|
46
|
+
*/
|
|
47
|
+
interface ParamPipeMetadata {
|
|
48
|
+
type: string;
|
|
49
|
+
pipes: PipeConstructor[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get pipes for a method
|
|
53
|
+
*/
|
|
54
|
+
export declare function getPipeMetadata(target: object, propertyKey: string | symbol): PipeConstructor[];
|
|
55
|
+
/**
|
|
56
|
+
* Get parameter pipes for a method
|
|
57
|
+
*/
|
|
58
|
+
export declare function getParamPipesMetadata(target: object, propertyKey: string | symbol): Record<number, ParamPipeMetadata>;
|
|
59
|
+
/**
|
|
60
|
+
* Check if a class is marked as a pipe
|
|
61
|
+
*/
|
|
62
|
+
export declare function isPipe(target: ClassConstructor): boolean;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=pipe.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe.decorator.d.ts","sourceRoot":"","sources":["../../../src/core/pipes/pipe.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,IAAI,cAAc,CAIrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,CAUrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,GAAG,KAAK,EAAE,eAAe,EAAE,GAAG,kBAAkB,CAWpE;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAE9C;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,EAAE,CAE/F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAErH;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAExD"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
const PIPE_KEY = 'nitrostack:pipe';
|
|
3
|
+
const IS_PIPE_KEY = 'nitrostack:is_pipe';
|
|
4
|
+
const PARAM_PIPES_KEY = 'nitrostack:param_pipes';
|
|
5
|
+
/**
|
|
6
|
+
* Marks a class as a pipe
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* @Pipe()
|
|
11
|
+
* export class ValidationPipe implements PipeInterface {
|
|
12
|
+
* transform(value: unknown, metadata: ArgumentMetadata) {
|
|
13
|
+
* // Validate and transform
|
|
14
|
+
* return value;
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function Pipe() {
|
|
20
|
+
return (target) => {
|
|
21
|
+
Reflect.defineMetadata(IS_PIPE_KEY, true, target);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Apply pipes to tool input (entire input object)
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* @Tool({ name: 'create_user', ... })
|
|
30
|
+
* @UsePipes(ValidationPipe, TransformPipe)
|
|
31
|
+
* async createUser(input: unknown) { }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function UsePipes(...pipes) {
|
|
35
|
+
return (target, propertyKey, descriptor) => {
|
|
36
|
+
const existingPipes = Reflect.getMetadata(PIPE_KEY, target, propertyKey) || [];
|
|
37
|
+
Reflect.defineMetadata(PIPE_KEY, [...existingPipes, ...pipes], target, propertyKey);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parameter decorator to apply pipes to specific parameters
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* @Tool({ name: 'create_user', ... })
|
|
46
|
+
* async createUser(@Body(ValidationPipe) input: CreateUserDto) { }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function Body(...pipes) {
|
|
50
|
+
return (target, propertyKey, parameterIndex) => {
|
|
51
|
+
if (!propertyKey)
|
|
52
|
+
return;
|
|
53
|
+
const existingParams = Reflect.getMetadata(PARAM_PIPES_KEY, target, propertyKey) || {};
|
|
54
|
+
existingParams[parameterIndex] = {
|
|
55
|
+
type: 'body',
|
|
56
|
+
pipes,
|
|
57
|
+
};
|
|
58
|
+
Reflect.defineMetadata(PARAM_PIPES_KEY, existingParams, target, propertyKey);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Shorthand for validation pipe
|
|
63
|
+
*/
|
|
64
|
+
export function Validated() {
|
|
65
|
+
return Body(); // Can be enhanced with default validation pipe
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get pipes for a method
|
|
69
|
+
*/
|
|
70
|
+
export function getPipeMetadata(target, propertyKey) {
|
|
71
|
+
return Reflect.getMetadata(PIPE_KEY, target, propertyKey) || [];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get parameter pipes for a method
|
|
75
|
+
*/
|
|
76
|
+
export function getParamPipesMetadata(target, propertyKey) {
|
|
77
|
+
return Reflect.getMetadata(PARAM_PIPES_KEY, target, propertyKey) || {};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if a class is marked as a pipe
|
|
81
|
+
*/
|
|
82
|
+
export function isPipe(target) {
|
|
83
|
+
return Reflect.getMetadata(IS_PIPE_KEY, target) === true;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=pipe.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe.decorator.js","sourceRoot":"","sources":["../../../src/core/pipes/pipe.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AACnC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AACzC,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,MAAc,EAAE,EAAE;QACxB,OAAO,CAAC,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAG,KAAwB;IAClD,OAAO,CAAC,MAAc,EAAE,WAA4B,EAAE,UAA8B,EAAE,EAAE;QACtF,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;QAC/E,OAAO,CAAC,cAAc,CACpB,QAAQ,EACR,CAAC,GAAG,aAAa,EAAE,GAAG,KAAK,CAAC,EAC5B,MAAM,EACN,WAAW,CACZ,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,IAAI,CAAC,GAAG,KAAwB;IAC9C,OAAO,CAAC,MAAc,EAAE,WAAwC,EAAE,cAAsB,EAAE,EAAE;QAC1F,IAAI,CAAC,WAAW;YAAE,OAAO;QAEzB,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,eAAe,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;QACvF,cAAc,CAAC,cAAc,CAAC,GAAG;YAC/B,IAAI,EAAE,MAAM;YACZ,KAAK;SACN,CAAC;QACF,OAAO,CAAC,cAAc,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC/E,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,EAAE,CAAC,CAAC,+CAA+C;AAChE,CAAC;AAUD;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,WAA4B;IAC1E,OAAO,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AAClE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAc,EAAE,WAA4B;IAChF,OAAO,OAAO,CAAC,WAAW,CAAC,eAAe,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AACzE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,MAAwB;IAC7C,OAAO,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* Constructor type for metatype
|
|
4
|
+
*/
|
|
5
|
+
type MetaType = new (...args: unknown[]) => unknown;
|
|
6
|
+
/**
|
|
7
|
+
* Argument metadata for pipe transformation
|
|
8
|
+
*/
|
|
9
|
+
export interface ArgumentMetadata {
|
|
10
|
+
type: 'body' | 'param' | 'query' | 'custom';
|
|
11
|
+
metatype?: MetaType;
|
|
12
|
+
data?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Pipe Interface
|
|
16
|
+
*
|
|
17
|
+
* Pipes are used to transform and validate input data before it reaches the tool handler.
|
|
18
|
+
* Similar to NestJS pipes.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* @Pipe()
|
|
23
|
+
* export class ValidationPipe implements PipeInterface {
|
|
24
|
+
* transform(value: unknown, metadata: ArgumentMetadata) {
|
|
25
|
+
* if (!this.isValid(value)) {
|
|
26
|
+
* throw new Error('Validation failed');
|
|
27
|
+
* }
|
|
28
|
+
* return value;
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export interface PipeInterface<T = unknown, R = unknown> {
|
|
34
|
+
transform(value: T, metadata: ArgumentMetadata): R | Promise<R>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Pipe constructor type
|
|
38
|
+
*/
|
|
39
|
+
export type PipeConstructor = new (...args: unknown[]) => PipeInterface;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=pipe.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe.interface.d.ts","sourceRoot":"","sources":["../../../src/core/pipes/pipe.interface.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B;;GAEG;AACH,KAAK,QAAQ,GAAG,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACrD,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,gBAAgB,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACjE;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe.interface.js","sourceRoot":"","sources":["../../../src/core/pipes/pipe.interface.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { PromptDefinition, ExecutionContext, PromptMessage, PromptArgument, PromptArgumentValue } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* MCP Prompt metadata structure
|
|
4
|
+
*/
|
|
5
|
+
interface McpPrompt {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
arguments: PromptArgument[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Prompt class provides a clean abstraction for defining and executing prompts
|
|
12
|
+
*/
|
|
13
|
+
export declare class Prompt {
|
|
14
|
+
private definition;
|
|
15
|
+
constructor(definition: PromptDefinition);
|
|
16
|
+
/**
|
|
17
|
+
* Get prompt name
|
|
18
|
+
*/
|
|
19
|
+
get name(): string;
|
|
20
|
+
/**
|
|
21
|
+
* Get prompt description
|
|
22
|
+
*/
|
|
23
|
+
get description(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Get prompt arguments
|
|
26
|
+
*/
|
|
27
|
+
get arguments(): PromptArgument[];
|
|
28
|
+
/**
|
|
29
|
+
* Execute the prompt with provided arguments
|
|
30
|
+
*/
|
|
31
|
+
execute(args: Record<string, PromptArgumentValue>, context: ExecutionContext): Promise<PromptMessage[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Validate prompt arguments
|
|
34
|
+
*/
|
|
35
|
+
private validateArguments;
|
|
36
|
+
/**
|
|
37
|
+
* Create prompt metadata for MCP protocol
|
|
38
|
+
*/
|
|
39
|
+
toMcpPrompt(): McpPrompt;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Helper function to create a prompt
|
|
43
|
+
*/
|
|
44
|
+
export declare function createPrompt(definition: PromptDefinition): Prompt;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/core/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAc,MAAM,YAAY,CAAC;AAGhI;;GAEG;AACH,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,UAAU,CAAmB;gBAEzB,UAAU,EAAE,gBAAgB;IAIxC;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,cAAc,EAAE,CAEhC;IAED;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAoB7G;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAYzB;;OAEG;IACH,WAAW,IAAI,SAAS;CAOzB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,gBAAgB,GAAG,MAAM,CAEjE"}
|