@chaaskit/server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/admin.js +438 -0
- package/dist/api/admin.js.map +1 -0
- package/dist/api/agents.js +21 -0
- package/dist/api/agents.js.map +1 -0
- package/dist/api/api-keys.js +122 -0
- package/dist/api/api-keys.js.map +1 -0
- package/dist/api/auth.js +399 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/chat.js +900 -0
- package/dist/api/chat.js.map +1 -0
- package/dist/api/config.js +91 -0
- package/dist/api/config.js.map +1 -0
- package/dist/api/documents.js +237 -0
- package/dist/api/documents.js.map +1 -0
- package/dist/api/export.js +107 -0
- package/dist/api/export.js.map +1 -0
- package/dist/api/health.js +25 -0
- package/dist/api/health.js.map +1 -0
- package/dist/api/mcp-server.js +84 -0
- package/dist/api/mcp-server.js.map +1 -0
- package/dist/api/mcp.js +400 -0
- package/dist/api/mcp.js.map +1 -0
- package/dist/api/mentions.js +94 -0
- package/dist/api/mentions.js.map +1 -0
- package/dist/api/oauth.js +366 -0
- package/dist/api/oauth.js.map +1 -0
- package/dist/api/payments.js +473 -0
- package/dist/api/payments.js.map +1 -0
- package/dist/api/projects.js +301 -0
- package/dist/api/projects.js.map +1 -0
- package/dist/api/scheduled-prompts.js +617 -0
- package/dist/api/scheduled-prompts.js.map +1 -0
- package/dist/api/search.js +85 -0
- package/dist/api/search.js.map +1 -0
- package/dist/api/share.js +188 -0
- package/dist/api/share.js.map +1 -0
- package/dist/api/slack.js +468 -0
- package/dist/api/slack.js.map +1 -0
- package/dist/api/teams.js +693 -0
- package/dist/api/teams.js.map +1 -0
- package/dist/api/templates.js +134 -0
- package/dist/api/templates.js.map +1 -0
- package/dist/api/threads.js +323 -0
- package/dist/api/threads.js.map +1 -0
- package/dist/api/upload.js +57 -0
- package/dist/api/upload.js.map +1 -0
- package/dist/api/user.js +111 -0
- package/dist/api/user.js.map +1 -0
- package/dist/api/v1/openai.js +245 -0
- package/dist/api/v1/openai.js.map +1 -0
- package/dist/app.js +168 -0
- package/dist/app.js.map +1 -0
- package/dist/bin/cli.js +57 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/commands/db-sync.js +108 -0
- package/dist/commands/db-sync.js.map +1 -0
- package/dist/config/loader.js +374 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/documents/extractors.js +136 -0
- package/dist/documents/extractors.js.map +1 -0
- package/dist/extensions/glob.js +53 -0
- package/dist/extensions/glob.js.map +1 -0
- package/dist/extensions/loader.js +72 -0
- package/dist/extensions/loader.js.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/index.js +75 -0
- package/dist/loaders/index.js.map +1 -0
- package/dist/mcp/client.js +551 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/server.js +335 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/middleware/apiKeyAuth.js +136 -0
- package/dist/middleware/apiKeyAuth.js.map +1 -0
- package/dist/middleware/auth.js +192 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/errorHandler.js +41 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/mcpServerAuth.js +164 -0
- package/dist/middleware/mcpServerAuth.js.map +1 -0
- package/dist/middleware/requestLogger.js +9 -0
- package/dist/middleware/requestLogger.js.map +1 -0
- package/dist/middleware/team.js +132 -0
- package/dist/middleware/team.js.map +1 -0
- package/dist/oauth/server.js +410 -0
- package/dist/oauth/server.js.map +1 -0
- package/dist/queue/cli.js +93 -0
- package/dist/queue/cli.js.map +1 -0
- package/dist/queue/handlers/index.js +91 -0
- package/dist/queue/handlers/index.js.map +1 -0
- package/dist/queue/handlers/scheduled-prompt.js +270 -0
- package/dist/queue/handlers/scheduled-prompt.js.map +1 -0
- package/dist/queue/index.js +91 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/providers/memory.js +296 -0
- package/dist/queue/providers/memory.js.map +1 -0
- package/dist/queue/providers/sqs.js +275 -0
- package/dist/queue/providers/sqs.js.map +1 -0
- package/dist/queue/scheduler.js +355 -0
- package/dist/queue/scheduler.js.map +1 -0
- package/dist/queue/types.js +5 -0
- package/dist/queue/types.js.map +1 -0
- package/dist/queue/worker.js +230 -0
- package/dist/queue/worker.js.map +1 -0
- package/dist/registry/index.js +40 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/server.js +207 -0
- package/dist/server.js.map +1 -0
- package/dist/services/agent.js +530 -0
- package/dist/services/agent.js.map +1 -0
- package/dist/services/agents.js +194 -0
- package/dist/services/agents.js.map +1 -0
- package/dist/services/documents.js +507 -0
- package/dist/services/documents.js.map +1 -0
- package/dist/services/email/index.js +91 -0
- package/dist/services/email/index.js.map +1 -0
- package/dist/services/email/providers/ses.js +97 -0
- package/dist/services/email/providers/ses.js.map +1 -0
- package/dist/services/email/templates.js +194 -0
- package/dist/services/email/templates.js.map +1 -0
- package/dist/services/email/types.js +5 -0
- package/dist/services/email/types.js.map +1 -0
- package/dist/services/encryption.js +69 -0
- package/dist/services/encryption.js.map +1 -0
- package/dist/services/oauth-discovery.js +226 -0
- package/dist/services/oauth-discovery.js.map +1 -0
- package/dist/services/pendingConfirmation.js +105 -0
- package/dist/services/pendingConfirmation.js.map +1 -0
- package/dist/services/scheduledPrompts.js +70 -0
- package/dist/services/scheduledPrompts.js.map +1 -0
- package/dist/services/slack/client.js +174 -0
- package/dist/services/slack/client.js.map +1 -0
- package/dist/services/slack/events.js +189 -0
- package/dist/services/slack/events.js.map +1 -0
- package/dist/services/slack/index.js +6 -0
- package/dist/services/slack/index.js.map +1 -0
- package/dist/services/slack/notifications.js +124 -0
- package/dist/services/slack/notifications.js.map +1 -0
- package/dist/services/slack/signature.js +74 -0
- package/dist/services/slack/signature.js.map +1 -0
- package/dist/services/slack/thread-context.js +191 -0
- package/dist/services/slack/thread-context.js.map +1 -0
- package/dist/services/toolConfirmation.js +55 -0
- package/dist/services/toolConfirmation.js.map +1 -0
- package/dist/services/usage.js +241 -0
- package/dist/services/usage.js.map +1 -0
- package/dist/ssr/build.js +90 -0
- package/dist/ssr/build.js.map +1 -0
- package/dist/ssr/components/SSRMessageList.js +120 -0
- package/dist/ssr/components/SSRMessageList.js.map +1 -0
- package/dist/ssr/entry.client.js +8 -0
- package/dist/ssr/entry.client.js.map +1 -0
- package/dist/ssr/entry.server.js +71 -0
- package/dist/ssr/entry.server.js.map +1 -0
- package/dist/ssr/handler.js +51 -0
- package/dist/ssr/handler.js.map +1 -0
- package/dist/ssr/root.js +184 -0
- package/dist/ssr/root.js.map +1 -0
- package/dist/ssr/routes/login.js +140 -0
- package/dist/ssr/routes/login.js.map +1 -0
- package/dist/ssr/routes/pricing.js +195 -0
- package/dist/ssr/routes/pricing.js.map +1 -0
- package/dist/ssr/routes/privacy.js +39 -0
- package/dist/ssr/routes/privacy.js.map +1 -0
- package/dist/ssr/routes/register.js +148 -0
- package/dist/ssr/routes/register.js.map +1 -0
- package/dist/ssr/routes/shared.$shareId.js +153 -0
- package/dist/ssr/routes/shared.$shareId.js.map +1 -0
- package/dist/ssr/routes/terms.js +39 -0
- package/dist/ssr/routes/terms.js.map +1 -0
- package/dist/storage/index.js +43 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/providers/database.js +38 -0
- package/dist/storage/providers/database.js.map +1 -0
- package/dist/storage/providers/filesystem.js +51 -0
- package/dist/storage/providers/filesystem.js.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/tools/documents.js +336 -0
- package/dist/tools/documents.js.map +1 -0
- package/dist/tools/get-plan-usage.js +82 -0
- package/dist/tools/get-plan-usage.js.map +1 -0
- package/dist/tools/index.js +106 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/web-scrape.js +145 -0
- package/dist/tools/web-scrape.js.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.1 Server Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements OAuth 2.1 with PKCE for MCP client authentication.
|
|
5
|
+
* Supports:
|
|
6
|
+
* - Dynamic client registration (RFC 7591)
|
|
7
|
+
* - Authorization code flow with PKCE
|
|
8
|
+
* - Token refresh
|
|
9
|
+
* - Token revocation
|
|
10
|
+
*/
|
|
11
|
+
import crypto from 'crypto';
|
|
12
|
+
import bcrypt from 'bcryptjs';
|
|
13
|
+
import { db } from '@chaaskit/db';
|
|
14
|
+
import { getConfig } from '../config/loader.js';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Helpers
|
|
17
|
+
// =============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Generate a cryptographically secure random string
|
|
20
|
+
*/
|
|
21
|
+
function generateSecureToken(length = 32) {
|
|
22
|
+
return crypto.randomBytes(length).toString('hex');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Hash a token for storage
|
|
26
|
+
*/
|
|
27
|
+
function hashToken(token) {
|
|
28
|
+
return crypto.createHash('sha256').update(token).digest('hex');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Verify PKCE code challenge
|
|
32
|
+
*/
|
|
33
|
+
function verifyCodeChallenge(codeVerifier, codeChallenge, method) {
|
|
34
|
+
if (method === 'S256') {
|
|
35
|
+
const hash = crypto.createHash('sha256').update(codeVerifier).digest();
|
|
36
|
+
const computed = hash
|
|
37
|
+
.toString('base64')
|
|
38
|
+
.replace(/\+/g, '-')
|
|
39
|
+
.replace(/\//g, '_')
|
|
40
|
+
.replace(/=/g, '');
|
|
41
|
+
return computed === codeChallenge;
|
|
42
|
+
}
|
|
43
|
+
// Plain method (not recommended but supported)
|
|
44
|
+
return codeVerifier === codeChallenge;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get OAuth configuration with defaults
|
|
48
|
+
*/
|
|
49
|
+
function getOAuthConfig() {
|
|
50
|
+
const config = getConfig();
|
|
51
|
+
const oauthConfig = config.mcp?.server?.oauth;
|
|
52
|
+
return {
|
|
53
|
+
enabled: oauthConfig?.enabled ?? false,
|
|
54
|
+
allowDynamicRegistration: oauthConfig?.allowDynamicRegistration ?? false,
|
|
55
|
+
accessTokenTTLSeconds: oauthConfig?.accessTokenTTLSeconds ?? 3600,
|
|
56
|
+
refreshTokenTTLSeconds: oauthConfig?.refreshTokenTTLSeconds ?? 30 * 24 * 60 * 60, // 30 days
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// Client Registration
|
|
61
|
+
// =============================================================================
|
|
62
|
+
/**
|
|
63
|
+
* Register a new OAuth client (RFC 7591 Dynamic Client Registration)
|
|
64
|
+
*/
|
|
65
|
+
export async function registerClient(registration) {
|
|
66
|
+
const oauthConfig = getOAuthConfig();
|
|
67
|
+
if (!oauthConfig.allowDynamicRegistration) {
|
|
68
|
+
throw new Error('Dynamic client registration is not enabled');
|
|
69
|
+
}
|
|
70
|
+
// Generate client credentials
|
|
71
|
+
const clientId = `mcp_${generateSecureToken(16)}`;
|
|
72
|
+
const clientSecret = generateSecureToken(32);
|
|
73
|
+
// Determine auth method
|
|
74
|
+
const tokenEndpointAuthMethod = registration.token_endpoint_auth_method || 'none';
|
|
75
|
+
const needsSecret = tokenEndpointAuthMethod !== 'none';
|
|
76
|
+
// Create client in database
|
|
77
|
+
await db.oAuthClient.create({
|
|
78
|
+
data: {
|
|
79
|
+
clientId,
|
|
80
|
+
clientSecretHash: needsSecret ? await bcrypt.hash(clientSecret, 10) : null,
|
|
81
|
+
clientName: registration.client_name,
|
|
82
|
+
clientUri: registration.client_uri,
|
|
83
|
+
redirectUris: JSON.stringify(registration.redirect_uris),
|
|
84
|
+
grantTypes: JSON.stringify(registration.grant_types || ['authorization_code', 'refresh_token']),
|
|
85
|
+
responseTypes: JSON.stringify(registration.response_types || ['code']),
|
|
86
|
+
tokenEndpointAuth: tokenEndpointAuthMethod,
|
|
87
|
+
isActive: true,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
console.log(`[OAuth] Registered new client: ${registration.client_name} (${clientId})`);
|
|
91
|
+
return {
|
|
92
|
+
client_id: clientId,
|
|
93
|
+
client_secret: needsSecret ? clientSecret : undefined,
|
|
94
|
+
client_name: registration.client_name,
|
|
95
|
+
redirect_uris: registration.redirect_uris,
|
|
96
|
+
grant_types: registration.grant_types || ['authorization_code', 'refresh_token'],
|
|
97
|
+
response_types: registration.response_types || ['code'],
|
|
98
|
+
token_endpoint_auth_method: tokenEndpointAuthMethod,
|
|
99
|
+
client_uri: registration.client_uri,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// Authorization Code
|
|
104
|
+
// =============================================================================
|
|
105
|
+
/**
|
|
106
|
+
* Generate an authorization code for the OAuth flow
|
|
107
|
+
*/
|
|
108
|
+
export async function generateAuthorizationCode(params) {
|
|
109
|
+
const { clientId, userId, redirectUri, scope, codeChallenge, codeChallengeMethod } = params;
|
|
110
|
+
// Verify client exists
|
|
111
|
+
const client = await db.oAuthClient.findUnique({
|
|
112
|
+
where: { clientId },
|
|
113
|
+
});
|
|
114
|
+
if (!client || !client.isActive) {
|
|
115
|
+
throw new Error('Invalid client');
|
|
116
|
+
}
|
|
117
|
+
// Verify redirect URI
|
|
118
|
+
const allowedRedirectUris = JSON.parse(client.redirectUris);
|
|
119
|
+
if (!allowedRedirectUris.includes(redirectUri)) {
|
|
120
|
+
throw new Error('Invalid redirect URI');
|
|
121
|
+
}
|
|
122
|
+
// Generate authorization code
|
|
123
|
+
const code = generateSecureToken(32);
|
|
124
|
+
// Store in database (expires in 10 minutes)
|
|
125
|
+
await db.oAuthAuthorizationCode.create({
|
|
126
|
+
data: {
|
|
127
|
+
code,
|
|
128
|
+
clientId: client.id,
|
|
129
|
+
userId,
|
|
130
|
+
redirectUri,
|
|
131
|
+
scope,
|
|
132
|
+
codeChallenge,
|
|
133
|
+
codeChallengeMethod: codeChallengeMethod || 'S256',
|
|
134
|
+
expiresAt: new Date(Date.now() + 10 * 60 * 1000),
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
console.log(`[OAuth] Generated auth code for user ${userId}, client ${clientId}`);
|
|
138
|
+
return code;
|
|
139
|
+
}
|
|
140
|
+
// =============================================================================
|
|
141
|
+
// Token Exchange
|
|
142
|
+
// =============================================================================
|
|
143
|
+
/**
|
|
144
|
+
* Exchange an authorization code for tokens
|
|
145
|
+
*/
|
|
146
|
+
export async function exchangeCodeForTokens(params) {
|
|
147
|
+
const { code, clientId, redirectUri, codeVerifier } = params;
|
|
148
|
+
const oauthConfig = getOAuthConfig();
|
|
149
|
+
// Find the authorization code
|
|
150
|
+
const authCode = await db.oAuthAuthorizationCode.findUnique({
|
|
151
|
+
where: { code },
|
|
152
|
+
include: {
|
|
153
|
+
client: true,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
if (!authCode) {
|
|
157
|
+
throw new Error('Invalid authorization code');
|
|
158
|
+
}
|
|
159
|
+
// Verify code hasn't expired
|
|
160
|
+
if (authCode.expiresAt < new Date()) {
|
|
161
|
+
await db.oAuthAuthorizationCode.delete({ where: { id: authCode.id } });
|
|
162
|
+
throw new Error('Authorization code expired');
|
|
163
|
+
}
|
|
164
|
+
// Verify code hasn't been used
|
|
165
|
+
if (authCode.usedAt) {
|
|
166
|
+
throw new Error('Authorization code already used');
|
|
167
|
+
}
|
|
168
|
+
// Verify client
|
|
169
|
+
if (authCode.client.clientId !== clientId) {
|
|
170
|
+
throw new Error('Client mismatch');
|
|
171
|
+
}
|
|
172
|
+
// Verify redirect URI
|
|
173
|
+
if (authCode.redirectUri !== redirectUri) {
|
|
174
|
+
throw new Error('Redirect URI mismatch');
|
|
175
|
+
}
|
|
176
|
+
// Verify PKCE code verifier
|
|
177
|
+
if (!verifyCodeChallenge(codeVerifier, authCode.codeChallenge, authCode.codeChallengeMethod)) {
|
|
178
|
+
throw new Error('Invalid code verifier');
|
|
179
|
+
}
|
|
180
|
+
// Mark code as used
|
|
181
|
+
await db.oAuthAuthorizationCode.update({
|
|
182
|
+
where: { id: authCode.id },
|
|
183
|
+
data: { usedAt: new Date() },
|
|
184
|
+
});
|
|
185
|
+
// Generate tokens
|
|
186
|
+
const accessToken = generateSecureToken(32);
|
|
187
|
+
const refreshToken = generateSecureToken(32);
|
|
188
|
+
const accessTokenExpiresAt = new Date(Date.now() + oauthConfig.accessTokenTTLSeconds * 1000);
|
|
189
|
+
const refreshTokenExpiresAt = new Date(Date.now() + oauthConfig.refreshTokenTTLSeconds * 1000);
|
|
190
|
+
// Store tokens
|
|
191
|
+
await db.oAuthToken.create({
|
|
192
|
+
data: {
|
|
193
|
+
tokenHash: hashToken(accessToken),
|
|
194
|
+
refreshTokenHash: hashToken(refreshToken),
|
|
195
|
+
clientId: authCode.client.id,
|
|
196
|
+
userId: authCode.userId,
|
|
197
|
+
scope: authCode.scope,
|
|
198
|
+
expiresAt: accessTokenExpiresAt,
|
|
199
|
+
refreshExpiresAt: refreshTokenExpiresAt,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
console.log(`[OAuth] Issued tokens for user ${authCode.userId}, client ${clientId}`);
|
|
203
|
+
return {
|
|
204
|
+
access_token: accessToken,
|
|
205
|
+
token_type: 'Bearer',
|
|
206
|
+
expires_in: oauthConfig.accessTokenTTLSeconds,
|
|
207
|
+
refresh_token: refreshToken,
|
|
208
|
+
scope: authCode.scope || undefined,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Refresh an access token
|
|
213
|
+
*/
|
|
214
|
+
export async function refreshAccessToken(params) {
|
|
215
|
+
const { refreshToken, clientId } = params;
|
|
216
|
+
const oauthConfig = getOAuthConfig();
|
|
217
|
+
const refreshTokenHash = hashToken(refreshToken);
|
|
218
|
+
// Find the token
|
|
219
|
+
const token = await db.oAuthToken.findUnique({
|
|
220
|
+
where: { refreshTokenHash },
|
|
221
|
+
include: {
|
|
222
|
+
client: true,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
if (!token) {
|
|
226
|
+
throw new Error('Invalid refresh token');
|
|
227
|
+
}
|
|
228
|
+
// Verify client
|
|
229
|
+
if (token.client.clientId !== clientId) {
|
|
230
|
+
throw new Error('Client mismatch');
|
|
231
|
+
}
|
|
232
|
+
// Verify token isn't revoked
|
|
233
|
+
if (token.revokedAt) {
|
|
234
|
+
throw new Error('Token has been revoked');
|
|
235
|
+
}
|
|
236
|
+
// Verify refresh token hasn't expired
|
|
237
|
+
if (token.refreshExpiresAt && token.refreshExpiresAt < new Date()) {
|
|
238
|
+
throw new Error('Refresh token expired');
|
|
239
|
+
}
|
|
240
|
+
// Generate new access token (keep same refresh token)
|
|
241
|
+
const newAccessToken = generateSecureToken(32);
|
|
242
|
+
const accessTokenExpiresAt = new Date(Date.now() + oauthConfig.accessTokenTTLSeconds * 1000);
|
|
243
|
+
// Update token record
|
|
244
|
+
await db.oAuthToken.update({
|
|
245
|
+
where: { id: token.id },
|
|
246
|
+
data: {
|
|
247
|
+
tokenHash: hashToken(newAccessToken),
|
|
248
|
+
expiresAt: accessTokenExpiresAt,
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
console.log(`[OAuth] Refreshed token for user ${token.userId}, client ${clientId}`);
|
|
252
|
+
return {
|
|
253
|
+
access_token: newAccessToken,
|
|
254
|
+
token_type: 'Bearer',
|
|
255
|
+
expires_in: oauthConfig.accessTokenTTLSeconds,
|
|
256
|
+
scope: token.scope || undefined,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// =============================================================================
|
|
260
|
+
// Token Revocation
|
|
261
|
+
// =============================================================================
|
|
262
|
+
/**
|
|
263
|
+
* Revoke a token
|
|
264
|
+
*/
|
|
265
|
+
export async function revokeToken(params) {
|
|
266
|
+
const { token, tokenTypeHint } = params;
|
|
267
|
+
const tokenHash = hashToken(token);
|
|
268
|
+
// Try to find by access token hash
|
|
269
|
+
let oauthToken = await db.oAuthToken.findUnique({
|
|
270
|
+
where: { tokenHash },
|
|
271
|
+
});
|
|
272
|
+
// If not found and hint is refresh_token, try refresh token hash
|
|
273
|
+
if (!oauthToken && tokenTypeHint === 'refresh_token') {
|
|
274
|
+
oauthToken = await db.oAuthToken.findUnique({
|
|
275
|
+
where: { refreshTokenHash: tokenHash },
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// If still not found, try refresh token hash anyway
|
|
279
|
+
if (!oauthToken) {
|
|
280
|
+
oauthToken = await db.oAuthToken.findUnique({
|
|
281
|
+
where: { refreshTokenHash: tokenHash },
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (oauthToken && !oauthToken.revokedAt) {
|
|
285
|
+
await db.oAuthToken.update({
|
|
286
|
+
where: { id: oauthToken.id },
|
|
287
|
+
data: { revokedAt: new Date() },
|
|
288
|
+
});
|
|
289
|
+
console.log(`[OAuth] Revoked token for user ${oauthToken.userId}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Revoke all tokens for a client-user pair
|
|
294
|
+
*/
|
|
295
|
+
export async function revokeAllTokensForClient(clientId, userId) {
|
|
296
|
+
const client = await db.oAuthClient.findUnique({
|
|
297
|
+
where: { clientId },
|
|
298
|
+
});
|
|
299
|
+
if (!client) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
await db.oAuthToken.updateMany({
|
|
303
|
+
where: {
|
|
304
|
+
clientId: client.id,
|
|
305
|
+
userId,
|
|
306
|
+
revokedAt: null,
|
|
307
|
+
},
|
|
308
|
+
data: { revokedAt: new Date() },
|
|
309
|
+
});
|
|
310
|
+
console.log(`[OAuth] Revoked all tokens for user ${userId}, client ${clientId}`);
|
|
311
|
+
}
|
|
312
|
+
// =============================================================================
|
|
313
|
+
// Token Validation
|
|
314
|
+
// =============================================================================
|
|
315
|
+
/**
|
|
316
|
+
* Validate an access token and return token info
|
|
317
|
+
*/
|
|
318
|
+
export async function validateAccessToken(accessToken) {
|
|
319
|
+
const tokenHash = hashToken(accessToken);
|
|
320
|
+
const token = await db.oAuthToken.findUnique({
|
|
321
|
+
where: { tokenHash },
|
|
322
|
+
include: {
|
|
323
|
+
client: true,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
if (!token) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
// Check if expired
|
|
330
|
+
if (token.expiresAt < new Date()) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
// Check if revoked
|
|
334
|
+
if (token.revokedAt) {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
// Check if client is still active
|
|
338
|
+
if (!token.client.isActive) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
userId: token.userId,
|
|
343
|
+
clientId: token.client.clientId,
|
|
344
|
+
scope: token.scope || undefined,
|
|
345
|
+
expiresAt: token.expiresAt,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
// =============================================================================
|
|
349
|
+
// Client Management
|
|
350
|
+
// =============================================================================
|
|
351
|
+
/**
|
|
352
|
+
* Get OAuth apps authorized by a user
|
|
353
|
+
*/
|
|
354
|
+
export async function getAuthorizedApps(userId) {
|
|
355
|
+
// Find all active tokens for this user
|
|
356
|
+
const tokens = await db.oAuthToken.findMany({
|
|
357
|
+
where: {
|
|
358
|
+
userId,
|
|
359
|
+
revokedAt: null,
|
|
360
|
+
},
|
|
361
|
+
include: {
|
|
362
|
+
client: true,
|
|
363
|
+
},
|
|
364
|
+
orderBy: {
|
|
365
|
+
createdAt: 'desc',
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
// Group by client (use most recent token per client)
|
|
369
|
+
const clientMap = new Map();
|
|
370
|
+
for (const token of tokens) {
|
|
371
|
+
if (!clientMap.has(token.client.clientId)) {
|
|
372
|
+
clientMap.set(token.client.clientId, {
|
|
373
|
+
clientId: token.client.clientId,
|
|
374
|
+
clientName: token.client.clientName,
|
|
375
|
+
clientUri: token.client.clientUri || undefined,
|
|
376
|
+
scope: token.scope || undefined,
|
|
377
|
+
authorizedAt: token.createdAt,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return Array.from(clientMap.values());
|
|
382
|
+
}
|
|
383
|
+
// =============================================================================
|
|
384
|
+
// Server Metadata
|
|
385
|
+
// =============================================================================
|
|
386
|
+
/**
|
|
387
|
+
* Get OAuth 2.0 Authorization Server Metadata (RFC 8414)
|
|
388
|
+
*/
|
|
389
|
+
export function getAuthorizationServerMetadata() {
|
|
390
|
+
const config = getConfig();
|
|
391
|
+
const oauthConfig = getOAuthConfig();
|
|
392
|
+
const apiUrl = process.env.API_URL || 'http://localhost:3000';
|
|
393
|
+
const metadata = {
|
|
394
|
+
issuer: apiUrl,
|
|
395
|
+
authorization_endpoint: `${apiUrl}/oauth/authorize`,
|
|
396
|
+
token_endpoint: `${apiUrl}/oauth/token`,
|
|
397
|
+
revocation_endpoint: `${apiUrl}/oauth/revoke`,
|
|
398
|
+
response_types_supported: ['code'],
|
|
399
|
+
grant_types_supported: ['authorization_code', 'refresh_token'],
|
|
400
|
+
token_endpoint_auth_methods_supported: ['none', 'client_secret_basic', 'client_secret_post'],
|
|
401
|
+
code_challenge_methods_supported: ['S256'],
|
|
402
|
+
scopes_supported: ['mcp:tools', 'mcp:resources'],
|
|
403
|
+
};
|
|
404
|
+
// Add registration endpoint if enabled
|
|
405
|
+
if (oauthConfig.allowDynamicRegistration) {
|
|
406
|
+
metadata.registration_endpoint = `${apiUrl}/oauth/register`;
|
|
407
|
+
}
|
|
408
|
+
return metadata;
|
|
409
|
+
}
|
|
410
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/oauth/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Standalone Queue Worker CLI
|
|
4
|
+
*
|
|
5
|
+
* Runs queue workers as a separate process from the main server.
|
|
6
|
+
* Useful for:
|
|
7
|
+
* - Scaling workers independently from web servers
|
|
8
|
+
* - Running workers on dedicated compute (e.g., ECS tasks, K8s jobs)
|
|
9
|
+
* - Separating concerns in production deployments
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* pnpm queue-worker
|
|
13
|
+
*
|
|
14
|
+
* Environment variables:
|
|
15
|
+
* QUEUE_CONCURRENCY - Number of concurrent job processors (default: 5)
|
|
16
|
+
* QUEUE_POLL_INTERVAL - Fallback poll interval in ms (default: 1000)
|
|
17
|
+
* QUEUE_SHUTDOWN_TIMEOUT - Graceful shutdown timeout in ms (default: 30000)
|
|
18
|
+
* SCHEDULER_ENABLED - Enable the scheduler (default: false)
|
|
19
|
+
* SCHEDULER_POLL_INTERVAL - Scheduler poll interval in ms (default: 60000)
|
|
20
|
+
*/
|
|
21
|
+
import 'dotenv/config';
|
|
22
|
+
import { loadConfigAsync, getConfig } from '../config/loader.js';
|
|
23
|
+
import { initializeQueueProvider, closeQueueProvider, getQueueProvider, startWorker, stopWorker, startScheduler, stopScheduler, } from './index.js';
|
|
24
|
+
// Parse environment variables
|
|
25
|
+
const concurrency = parseInt(process.env.QUEUE_CONCURRENCY || '5', 10);
|
|
26
|
+
const pollInterval = parseInt(process.env.QUEUE_POLL_INTERVAL || '1000', 10);
|
|
27
|
+
const shutdownTimeout = parseInt(process.env.QUEUE_SHUTDOWN_TIMEOUT || '30000', 10);
|
|
28
|
+
const schedulerEnabled = process.env.SCHEDULER_ENABLED === 'true';
|
|
29
|
+
const schedulerPollInterval = parseInt(process.env.SCHEDULER_POLL_INTERVAL || '60000', 10);
|
|
30
|
+
async function main() {
|
|
31
|
+
console.log('[Queue Worker] Starting standalone worker...');
|
|
32
|
+
console.log(`[Queue Worker] Concurrency: ${concurrency}`);
|
|
33
|
+
console.log(`[Queue Worker] Scheduler: ${schedulerEnabled ? 'enabled' : 'disabled'}`);
|
|
34
|
+
// Load application config
|
|
35
|
+
await loadConfigAsync();
|
|
36
|
+
const config = getConfig();
|
|
37
|
+
if (!config.queue?.enabled) {
|
|
38
|
+
console.error('[Queue Worker] Queue system is disabled in config');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
// Initialize queue provider
|
|
42
|
+
await initializeQueueProvider(config.queue);
|
|
43
|
+
const provider = getQueueProvider();
|
|
44
|
+
// Start worker
|
|
45
|
+
const workerConfig = {
|
|
46
|
+
mode: 'standalone',
|
|
47
|
+
concurrency,
|
|
48
|
+
pollInterval,
|
|
49
|
+
shutdownTimeout,
|
|
50
|
+
};
|
|
51
|
+
console.log('[Queue Worker] Starting worker...');
|
|
52
|
+
await startWorker({ provider, config: workerConfig });
|
|
53
|
+
console.log('[Queue Worker] Worker started');
|
|
54
|
+
// Start scheduler if enabled
|
|
55
|
+
if (schedulerEnabled || config.queue.scheduler?.enabled) {
|
|
56
|
+
const schedulerConfig = {
|
|
57
|
+
enabled: true,
|
|
58
|
+
pollInterval: schedulerPollInterval,
|
|
59
|
+
};
|
|
60
|
+
console.log('[Queue Worker] Starting scheduler...');
|
|
61
|
+
await startScheduler({ provider, config: schedulerConfig });
|
|
62
|
+
console.log('[Queue Worker] Scheduler started');
|
|
63
|
+
}
|
|
64
|
+
// Setup graceful shutdown
|
|
65
|
+
let isShuttingDown = false;
|
|
66
|
+
const shutdown = async (signal) => {
|
|
67
|
+
if (isShuttingDown) {
|
|
68
|
+
console.log('[Queue Worker] Forced shutdown');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
isShuttingDown = true;
|
|
72
|
+
console.log(`[Queue Worker] Received ${signal}, shutting down...`);
|
|
73
|
+
try {
|
|
74
|
+
await stopScheduler();
|
|
75
|
+
await stopWorker();
|
|
76
|
+
await closeQueueProvider();
|
|
77
|
+
console.log('[Queue Worker] Shutdown complete');
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error('[Queue Worker] Error during shutdown:', error);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
86
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
87
|
+
console.log('[Queue Worker] Ready and waiting for jobs...');
|
|
88
|
+
}
|
|
89
|
+
main().catch((error) => {
|
|
90
|
+
console.error('[Queue Worker] Fatal error:', error);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/queue/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Handler Registry
|
|
3
|
+
*
|
|
4
|
+
* Provides a central registry for job handlers. Job handlers are functions
|
|
5
|
+
* that process jobs of a specific type.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { registerJobHandler } from './queue/handlers/index.js';
|
|
10
|
+
*
|
|
11
|
+
* registerJobHandler('email:send', async (job, ctx) => {
|
|
12
|
+
* ctx.log('Sending email to', job.payload.to);
|
|
13
|
+
* await sendEmail(job.payload);
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
// Registry of job handlers by type
|
|
18
|
+
const handlers = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* Register a handler for a specific job type.
|
|
21
|
+
*
|
|
22
|
+
* @param type - The job type to handle (e.g., 'email:send', 'report:generate')
|
|
23
|
+
* @param handler - The function that processes jobs of this type
|
|
24
|
+
* @param description - Optional description for debugging/monitoring
|
|
25
|
+
*/
|
|
26
|
+
export function registerJobHandler(type, handler, description) {
|
|
27
|
+
if (handlers.has(type)) {
|
|
28
|
+
console.warn(`[Queue] Overwriting existing handler for job type: ${type}`);
|
|
29
|
+
}
|
|
30
|
+
handlers.set(type, {
|
|
31
|
+
handler: handler,
|
|
32
|
+
description,
|
|
33
|
+
});
|
|
34
|
+
console.log(`[Queue] Registered handler for job type: ${type}${description ? ` (${description})` : ''}`);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the handler for a specific job type.
|
|
38
|
+
*
|
|
39
|
+
* @param type - The job type
|
|
40
|
+
* @returns The registered handler, or undefined if not found
|
|
41
|
+
*/
|
|
42
|
+
export function getJobHandler(type) {
|
|
43
|
+
return handlers.get(type);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a handler exists for a specific job type.
|
|
47
|
+
*
|
|
48
|
+
* @param type - The job type
|
|
49
|
+
* @returns True if a handler is registered
|
|
50
|
+
*/
|
|
51
|
+
export function hasJobHandler(type) {
|
|
52
|
+
return handlers.has(type);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get all registered job types.
|
|
56
|
+
*
|
|
57
|
+
* @returns Array of registered job type strings
|
|
58
|
+
*/
|
|
59
|
+
export function getRegisteredJobTypes() {
|
|
60
|
+
return Array.from(handlers.keys());
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Unregister a handler (mainly for testing).
|
|
64
|
+
*
|
|
65
|
+
* @param type - The job type to unregister
|
|
66
|
+
*/
|
|
67
|
+
export function unregisterJobHandler(type) {
|
|
68
|
+
return handlers.delete(type);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clear all handlers (mainly for testing).
|
|
72
|
+
*/
|
|
73
|
+
export function clearJobHandlers() {
|
|
74
|
+
handlers.clear();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Execute a job using its registered handler.
|
|
78
|
+
*
|
|
79
|
+
* @param job - The job to execute
|
|
80
|
+
* @param ctx - The job context
|
|
81
|
+
* @returns The result from the handler
|
|
82
|
+
* @throws Error if no handler is registered for the job type
|
|
83
|
+
*/
|
|
84
|
+
export async function executeJob(job, ctx) {
|
|
85
|
+
const registered = handlers.get(job.type);
|
|
86
|
+
if (!registered) {
|
|
87
|
+
throw new Error(`No handler registered for job type: ${job.type}`);
|
|
88
|
+
}
|
|
89
|
+
return registered.handler(job, ctx);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/queue/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,mCAAmC;AACnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,OAAsC,EACtC,WAAoB;IAEpB,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,sDAAsD,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;QACjB,OAAO,EAAE,OAAqB;QAC9B,WAAW;KACZ,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,4CAA4C,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3G,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAA0B,EAC1B,GAAe;IAEf,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE1C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAqB,CAAC;AAC1D,CAAC"}
|