@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.
Files changed (189) hide show
  1. package/dist/api/admin.js +438 -0
  2. package/dist/api/admin.js.map +1 -0
  3. package/dist/api/agents.js +21 -0
  4. package/dist/api/agents.js.map +1 -0
  5. package/dist/api/api-keys.js +122 -0
  6. package/dist/api/api-keys.js.map +1 -0
  7. package/dist/api/auth.js +399 -0
  8. package/dist/api/auth.js.map +1 -0
  9. package/dist/api/chat.js +900 -0
  10. package/dist/api/chat.js.map +1 -0
  11. package/dist/api/config.js +91 -0
  12. package/dist/api/config.js.map +1 -0
  13. package/dist/api/documents.js +237 -0
  14. package/dist/api/documents.js.map +1 -0
  15. package/dist/api/export.js +107 -0
  16. package/dist/api/export.js.map +1 -0
  17. package/dist/api/health.js +25 -0
  18. package/dist/api/health.js.map +1 -0
  19. package/dist/api/mcp-server.js +84 -0
  20. package/dist/api/mcp-server.js.map +1 -0
  21. package/dist/api/mcp.js +400 -0
  22. package/dist/api/mcp.js.map +1 -0
  23. package/dist/api/mentions.js +94 -0
  24. package/dist/api/mentions.js.map +1 -0
  25. package/dist/api/oauth.js +366 -0
  26. package/dist/api/oauth.js.map +1 -0
  27. package/dist/api/payments.js +473 -0
  28. package/dist/api/payments.js.map +1 -0
  29. package/dist/api/projects.js +301 -0
  30. package/dist/api/projects.js.map +1 -0
  31. package/dist/api/scheduled-prompts.js +617 -0
  32. package/dist/api/scheduled-prompts.js.map +1 -0
  33. package/dist/api/search.js +85 -0
  34. package/dist/api/search.js.map +1 -0
  35. package/dist/api/share.js +188 -0
  36. package/dist/api/share.js.map +1 -0
  37. package/dist/api/slack.js +468 -0
  38. package/dist/api/slack.js.map +1 -0
  39. package/dist/api/teams.js +693 -0
  40. package/dist/api/teams.js.map +1 -0
  41. package/dist/api/templates.js +134 -0
  42. package/dist/api/templates.js.map +1 -0
  43. package/dist/api/threads.js +323 -0
  44. package/dist/api/threads.js.map +1 -0
  45. package/dist/api/upload.js +57 -0
  46. package/dist/api/upload.js.map +1 -0
  47. package/dist/api/user.js +111 -0
  48. package/dist/api/user.js.map +1 -0
  49. package/dist/api/v1/openai.js +245 -0
  50. package/dist/api/v1/openai.js.map +1 -0
  51. package/dist/app.js +168 -0
  52. package/dist/app.js.map +1 -0
  53. package/dist/bin/cli.js +57 -0
  54. package/dist/bin/cli.js.map +1 -0
  55. package/dist/commands/db-sync.js +108 -0
  56. package/dist/commands/db-sync.js.map +1 -0
  57. package/dist/config/loader.js +374 -0
  58. package/dist/config/loader.js.map +1 -0
  59. package/dist/documents/extractors.js +136 -0
  60. package/dist/documents/extractors.js.map +1 -0
  61. package/dist/extensions/glob.js +53 -0
  62. package/dist/extensions/glob.js.map +1 -0
  63. package/dist/extensions/loader.js +72 -0
  64. package/dist/extensions/loader.js.map +1 -0
  65. package/dist/index.js +25 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/loaders/index.js +75 -0
  68. package/dist/loaders/index.js.map +1 -0
  69. package/dist/mcp/client.js +551 -0
  70. package/dist/mcp/client.js.map +1 -0
  71. package/dist/mcp/server.js +335 -0
  72. package/dist/mcp/server.js.map +1 -0
  73. package/dist/middleware/apiKeyAuth.js +136 -0
  74. package/dist/middleware/apiKeyAuth.js.map +1 -0
  75. package/dist/middleware/auth.js +192 -0
  76. package/dist/middleware/auth.js.map +1 -0
  77. package/dist/middleware/errorHandler.js +41 -0
  78. package/dist/middleware/errorHandler.js.map +1 -0
  79. package/dist/middleware/mcpServerAuth.js +164 -0
  80. package/dist/middleware/mcpServerAuth.js.map +1 -0
  81. package/dist/middleware/requestLogger.js +9 -0
  82. package/dist/middleware/requestLogger.js.map +1 -0
  83. package/dist/middleware/team.js +132 -0
  84. package/dist/middleware/team.js.map +1 -0
  85. package/dist/oauth/server.js +410 -0
  86. package/dist/oauth/server.js.map +1 -0
  87. package/dist/queue/cli.js +93 -0
  88. package/dist/queue/cli.js.map +1 -0
  89. package/dist/queue/handlers/index.js +91 -0
  90. package/dist/queue/handlers/index.js.map +1 -0
  91. package/dist/queue/handlers/scheduled-prompt.js +270 -0
  92. package/dist/queue/handlers/scheduled-prompt.js.map +1 -0
  93. package/dist/queue/index.js +91 -0
  94. package/dist/queue/index.js.map +1 -0
  95. package/dist/queue/providers/memory.js +296 -0
  96. package/dist/queue/providers/memory.js.map +1 -0
  97. package/dist/queue/providers/sqs.js +275 -0
  98. package/dist/queue/providers/sqs.js.map +1 -0
  99. package/dist/queue/scheduler.js +355 -0
  100. package/dist/queue/scheduler.js.map +1 -0
  101. package/dist/queue/types.js +5 -0
  102. package/dist/queue/types.js.map +1 -0
  103. package/dist/queue/worker.js +230 -0
  104. package/dist/queue/worker.js.map +1 -0
  105. package/dist/registry/index.js +40 -0
  106. package/dist/registry/index.js.map +1 -0
  107. package/dist/server.js +207 -0
  108. package/dist/server.js.map +1 -0
  109. package/dist/services/agent.js +530 -0
  110. package/dist/services/agent.js.map +1 -0
  111. package/dist/services/agents.js +194 -0
  112. package/dist/services/agents.js.map +1 -0
  113. package/dist/services/documents.js +507 -0
  114. package/dist/services/documents.js.map +1 -0
  115. package/dist/services/email/index.js +91 -0
  116. package/dist/services/email/index.js.map +1 -0
  117. package/dist/services/email/providers/ses.js +97 -0
  118. package/dist/services/email/providers/ses.js.map +1 -0
  119. package/dist/services/email/templates.js +194 -0
  120. package/dist/services/email/templates.js.map +1 -0
  121. package/dist/services/email/types.js +5 -0
  122. package/dist/services/email/types.js.map +1 -0
  123. package/dist/services/encryption.js +69 -0
  124. package/dist/services/encryption.js.map +1 -0
  125. package/dist/services/oauth-discovery.js +226 -0
  126. package/dist/services/oauth-discovery.js.map +1 -0
  127. package/dist/services/pendingConfirmation.js +105 -0
  128. package/dist/services/pendingConfirmation.js.map +1 -0
  129. package/dist/services/scheduledPrompts.js +70 -0
  130. package/dist/services/scheduledPrompts.js.map +1 -0
  131. package/dist/services/slack/client.js +174 -0
  132. package/dist/services/slack/client.js.map +1 -0
  133. package/dist/services/slack/events.js +189 -0
  134. package/dist/services/slack/events.js.map +1 -0
  135. package/dist/services/slack/index.js +6 -0
  136. package/dist/services/slack/index.js.map +1 -0
  137. package/dist/services/slack/notifications.js +124 -0
  138. package/dist/services/slack/notifications.js.map +1 -0
  139. package/dist/services/slack/signature.js +74 -0
  140. package/dist/services/slack/signature.js.map +1 -0
  141. package/dist/services/slack/thread-context.js +191 -0
  142. package/dist/services/slack/thread-context.js.map +1 -0
  143. package/dist/services/toolConfirmation.js +55 -0
  144. package/dist/services/toolConfirmation.js.map +1 -0
  145. package/dist/services/usage.js +241 -0
  146. package/dist/services/usage.js.map +1 -0
  147. package/dist/ssr/build.js +90 -0
  148. package/dist/ssr/build.js.map +1 -0
  149. package/dist/ssr/components/SSRMessageList.js +120 -0
  150. package/dist/ssr/components/SSRMessageList.js.map +1 -0
  151. package/dist/ssr/entry.client.js +8 -0
  152. package/dist/ssr/entry.client.js.map +1 -0
  153. package/dist/ssr/entry.server.js +71 -0
  154. package/dist/ssr/entry.server.js.map +1 -0
  155. package/dist/ssr/handler.js +51 -0
  156. package/dist/ssr/handler.js.map +1 -0
  157. package/dist/ssr/root.js +184 -0
  158. package/dist/ssr/root.js.map +1 -0
  159. package/dist/ssr/routes/login.js +140 -0
  160. package/dist/ssr/routes/login.js.map +1 -0
  161. package/dist/ssr/routes/pricing.js +195 -0
  162. package/dist/ssr/routes/pricing.js.map +1 -0
  163. package/dist/ssr/routes/privacy.js +39 -0
  164. package/dist/ssr/routes/privacy.js.map +1 -0
  165. package/dist/ssr/routes/register.js +148 -0
  166. package/dist/ssr/routes/register.js.map +1 -0
  167. package/dist/ssr/routes/shared.$shareId.js +153 -0
  168. package/dist/ssr/routes/shared.$shareId.js.map +1 -0
  169. package/dist/ssr/routes/terms.js +39 -0
  170. package/dist/ssr/routes/terms.js.map +1 -0
  171. package/dist/storage/index.js +43 -0
  172. package/dist/storage/index.js.map +1 -0
  173. package/dist/storage/providers/database.js +38 -0
  174. package/dist/storage/providers/database.js.map +1 -0
  175. package/dist/storage/providers/filesystem.js +51 -0
  176. package/dist/storage/providers/filesystem.js.map +1 -0
  177. package/dist/storage/types.js +2 -0
  178. package/dist/storage/types.js.map +1 -0
  179. package/dist/tools/documents.js +336 -0
  180. package/dist/tools/documents.js.map +1 -0
  181. package/dist/tools/get-plan-usage.js +82 -0
  182. package/dist/tools/get-plan-usage.js.map +1 -0
  183. package/dist/tools/index.js +106 -0
  184. package/dist/tools/index.js.map +1 -0
  185. package/dist/tools/types.js +2 -0
  186. package/dist/tools/types.js.map +1 -0
  187. package/dist/tools/web-scrape.js +145 -0
  188. package/dist/tools/web-scrape.js.map +1 -0
  189. 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"}