@structured-world/gitlab-mcp 5.7.0 → 5.8.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 (92) hide show
  1. package/README.md +236 -1
  2. package/dist/config.d.ts +5 -0
  3. package/dist/config.js +6 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/entities/core/registry.js +53 -20
  6. package/dist/entities/core/registry.js.map +1 -1
  7. package/dist/entities/core/schema-readonly.d.ts +172 -442
  8. package/dist/entities/core/schema.d.ts +65 -173
  9. package/dist/entities/files/registry.js +42 -19
  10. package/dist/entities/files/registry.js.map +1 -1
  11. package/dist/entities/files/schema-readonly.d.ts +24 -124
  12. package/dist/entities/files/schema.d.ts +17 -82
  13. package/dist/entities/labels/registry.js +39 -6
  14. package/dist/entities/labels/registry.js.map +1 -1
  15. package/dist/entities/labels/schema-readonly.d.ts +6 -24
  16. package/dist/entities/labels/schema.d.ts +5 -37
  17. package/dist/entities/milestones/registry.js +44 -11
  18. package/dist/entities/milestones/registry.js.map +1 -1
  19. package/dist/entities/milestones/schema-readonly.d.ts +20 -100
  20. package/dist/entities/milestones/schema.d.ts +11 -48
  21. package/dist/entities/mrs/registry.js +56 -23
  22. package/dist/entities/mrs/registry.js.map +1 -1
  23. package/dist/entities/mrs/schema-readonly.d.ts +68 -243
  24. package/dist/entities/mrs/schema.d.ts +142 -885
  25. package/dist/entities/pipelines/registry.js +46 -13
  26. package/dist/entities/pipelines/registry.js.map +1 -1
  27. package/dist/entities/pipelines/schema-readonly.d.ts +115 -525
  28. package/dist/entities/pipelines/schema.d.ts +30 -104
  29. package/dist/entities/shared.d.ts +110 -787
  30. package/dist/entities/utils.d.ts +2 -2
  31. package/dist/entities/variables/registry.js +40 -7
  32. package/dist/entities/variables/registry.js.map +1 -1
  33. package/dist/entities/variables/schema-readonly.d.ts +3 -28
  34. package/dist/entities/variables/schema.d.ts +20 -80
  35. package/dist/entities/wiki/registry.js +39 -6
  36. package/dist/entities/wiki/registry.js.map +1 -1
  37. package/dist/entities/wiki/schema-readonly.d.ts +4 -35
  38. package/dist/entities/wiki/schema.d.ts +3 -31
  39. package/dist/entities/workitems/registry.js +40 -7
  40. package/dist/entities/workitems/registry.js.map +1 -1
  41. package/dist/entities/workitems/schema-readonly.d.ts +35 -32
  42. package/dist/entities/workitems/schema-readonly.js +1 -1
  43. package/dist/entities/workitems/schema-readonly.js.map +1 -1
  44. package/dist/entities/workitems/schema.d.ts +21 -45
  45. package/dist/middleware/index.d.ts +1 -0
  46. package/dist/middleware/index.js +8 -0
  47. package/dist/middleware/index.js.map +1 -0
  48. package/dist/middleware/oauth-auth.d.ts +4 -0
  49. package/dist/middleware/oauth-auth.js +135 -0
  50. package/dist/middleware/oauth-auth.js.map +1 -0
  51. package/dist/oauth/config.d.ts +19 -0
  52. package/dist/oauth/config.js +70 -0
  53. package/dist/oauth/config.js.map +1 -0
  54. package/dist/oauth/endpoints/authorize.d.ts +3 -0
  55. package/dist/oauth/endpoints/authorize.js +414 -0
  56. package/dist/oauth/endpoints/authorize.js.map +1 -0
  57. package/dist/oauth/endpoints/index.d.ts +3 -0
  58. package/dist/oauth/endpoints/index.js +13 -0
  59. package/dist/oauth/endpoints/index.js.map +1 -0
  60. package/dist/oauth/endpoints/metadata.d.ts +4 -0
  61. package/dist/oauth/endpoints/metadata.js +36 -0
  62. package/dist/oauth/endpoints/metadata.js.map +1 -0
  63. package/dist/oauth/endpoints/token.d.ts +2 -0
  64. package/dist/oauth/endpoints/token.js +159 -0
  65. package/dist/oauth/endpoints/token.js.map +1 -0
  66. package/dist/oauth/gitlab-device-flow.d.ts +8 -0
  67. package/dist/oauth/gitlab-device-flow.js +172 -0
  68. package/dist/oauth/gitlab-device-flow.js.map +1 -0
  69. package/dist/oauth/index.d.ts +8 -0
  70. package/dist/oauth/index.js +48 -0
  71. package/dist/oauth/index.js.map +1 -0
  72. package/dist/oauth/session-store.d.ts +37 -0
  73. package/dist/oauth/session-store.js +182 -0
  74. package/dist/oauth/session-store.js.map +1 -0
  75. package/dist/oauth/token-context.d.ts +8 -0
  76. package/dist/oauth/token-context.js +40 -0
  77. package/dist/oauth/token-context.js.map +1 -0
  78. package/dist/oauth/token-utils.d.ts +14 -0
  79. package/dist/oauth/token-utils.js +148 -0
  80. package/dist/oauth/token-utils.js.map +1 -0
  81. package/dist/oauth/types.d.ts +94 -0
  82. package/dist/oauth/types.js +3 -0
  83. package/dist/oauth/types.js.map +1 -0
  84. package/dist/server.js +147 -9
  85. package/dist/server.js.map +1 -1
  86. package/dist/structured-world-gitlab-mcp-5.8.0.tgz +0 -0
  87. package/dist/tsconfig.build.tsbuildinfo +1 -1
  88. package/dist/utils/fetch.d.ts +3 -7
  89. package/dist/utils/fetch.js +82 -54
  90. package/dist/utils/fetch.js.map +1 -1
  91. package/package.json +23 -23
  92. package/dist/structured-world-gitlab-mcp-5.7.0.tgz +0 -0
@@ -0,0 +1,414 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authorizeHandler = authorizeHandler;
4
+ exports.pollHandler = pollHandler;
5
+ const config_1 = require("../config");
6
+ const session_store_1 = require("../session-store");
7
+ const gitlab_device_flow_1 = require("../gitlab-device-flow");
8
+ const token_utils_1 = require("../token-utils");
9
+ const metadata_1 = require("./metadata");
10
+ const logger_1 = require("../../logger");
11
+ async function authorizeHandler(req, res) {
12
+ const config = (0, config_1.loadOAuthConfig)();
13
+ if (!config) {
14
+ res.status(500).json({
15
+ error: "server_error",
16
+ error_description: "OAuth not configured",
17
+ });
18
+ return;
19
+ }
20
+ const { client_id, redirect_uri, response_type, state, code_challenge, code_challenge_method } = req.query;
21
+ if (response_type !== "code") {
22
+ res.status(400).json({
23
+ error: "unsupported_response_type",
24
+ error_description: 'Only "code" response type is supported',
25
+ });
26
+ return;
27
+ }
28
+ if (!client_id) {
29
+ res.status(400).json({
30
+ error: "invalid_request",
31
+ error_description: "client_id is required",
32
+ });
33
+ return;
34
+ }
35
+ if (!code_challenge) {
36
+ res.status(400).json({
37
+ error: "invalid_request",
38
+ error_description: "code_challenge is required (PKCE)",
39
+ });
40
+ return;
41
+ }
42
+ if (code_challenge_method !== "S256") {
43
+ res.status(400).json({
44
+ error: "invalid_request",
45
+ error_description: 'code_challenge_method must be "S256"',
46
+ });
47
+ return;
48
+ }
49
+ try {
50
+ const deviceResponse = await (0, gitlab_device_flow_1.initiateDeviceFlow)(config);
51
+ const flowState = (0, token_utils_1.generateRandomString)(32);
52
+ session_store_1.sessionStore.storeDeviceFlow(flowState, {
53
+ deviceCode: deviceResponse.device_code,
54
+ userCode: deviceResponse.user_code,
55
+ verificationUri: deviceResponse.verification_uri,
56
+ verificationUriComplete: deviceResponse.verification_uri_complete,
57
+ expiresAt: Date.now() + deviceResponse.expires_in * 1000,
58
+ interval: deviceResponse.interval,
59
+ clientId: client_id,
60
+ codeChallenge: code_challenge,
61
+ codeChallengeMethod: code_challenge_method,
62
+ state: state ?? "",
63
+ redirectUri: redirect_uri,
64
+ });
65
+ logger_1.logger.info({
66
+ flowState: flowState.substring(0, 8) + "...",
67
+ userCode: deviceResponse.user_code,
68
+ }, "Device flow initiated for authorization");
69
+ const baseUrl = (0, metadata_1.getBaseUrl)(req);
70
+ const html = getDeviceFlowHTML({
71
+ userCode: deviceResponse.user_code,
72
+ verificationUri: deviceResponse.verification_uri,
73
+ verificationUriComplete: deviceResponse.verification_uri_complete,
74
+ flowState,
75
+ pollUrl: `${baseUrl}/oauth/poll`,
76
+ expiresIn: deviceResponse.expires_in,
77
+ });
78
+ res.setHeader("Content-Type", "text/html");
79
+ res.send(html);
80
+ }
81
+ catch (error) {
82
+ logger_1.logger.error({ err: error }, "Failed to initiate device flow");
83
+ res.status(500).json({
84
+ error: "server_error",
85
+ error_description: "Failed to initiate authentication",
86
+ });
87
+ }
88
+ }
89
+ async function pollHandler(req, res) {
90
+ const config = (0, config_1.loadOAuthConfig)();
91
+ if (!config) {
92
+ res.status(500).json({ error: "server_error" });
93
+ return;
94
+ }
95
+ const { flow_state } = req.query;
96
+ if (!flow_state) {
97
+ res
98
+ .status(400)
99
+ .json({ status: "failed", error: "Missing flow_state" });
100
+ return;
101
+ }
102
+ const flow = session_store_1.sessionStore.getDeviceFlow(flow_state);
103
+ if (!flow) {
104
+ res.status(400).json({ status: "expired", error: "Flow not found" });
105
+ return;
106
+ }
107
+ if (Date.now() > flow.expiresAt) {
108
+ session_store_1.sessionStore.deleteDeviceFlow(flow_state);
109
+ res
110
+ .status(400)
111
+ .json({ status: "expired", error: "Device code expired" });
112
+ return;
113
+ }
114
+ try {
115
+ const tokenResponse = await (0, gitlab_device_flow_1.pollDeviceFlowOnce)(flow.deviceCode, config);
116
+ if (tokenResponse) {
117
+ const userInfo = await (0, gitlab_device_flow_1.getGitLabUser)(tokenResponse.access_token);
118
+ const sessionId = (0, token_utils_1.generateSessionId)();
119
+ const now = Date.now();
120
+ const authCode = (0, token_utils_1.generateAuthorizationCode)();
121
+ session_store_1.sessionStore.storeAuthCode({
122
+ code: authCode,
123
+ sessionId,
124
+ clientId: flow.clientId,
125
+ codeChallenge: flow.codeChallenge,
126
+ codeChallengeMethod: flow.codeChallengeMethod,
127
+ redirectUri: flow.redirectUri,
128
+ expiresAt: now + 10 * 60 * 1000,
129
+ });
130
+ session_store_1.sessionStore.createSession({
131
+ id: sessionId,
132
+ mcpAccessToken: "",
133
+ mcpRefreshToken: "",
134
+ mcpTokenExpiry: 0,
135
+ gitlabAccessToken: tokenResponse.access_token,
136
+ gitlabRefreshToken: tokenResponse.refresh_token,
137
+ gitlabTokenExpiry: (0, token_utils_1.calculateTokenExpiry)(tokenResponse.expires_in),
138
+ gitlabUserId: userInfo.id,
139
+ gitlabUsername: userInfo.username,
140
+ clientId: flow.clientId,
141
+ scopes: ["mcp:tools", "mcp:resources"],
142
+ createdAt: now,
143
+ updatedAt: now,
144
+ });
145
+ session_store_1.sessionStore.deleteDeviceFlow(flow_state);
146
+ logger_1.logger.info({
147
+ sessionId: sessionId.substring(0, 8) + "...",
148
+ userId: userInfo.id,
149
+ username: userInfo.username,
150
+ }, "Device flow authorization completed");
151
+ const response = {
152
+ status: "complete",
153
+ redirect_uri: flow.redirectUri,
154
+ code: authCode,
155
+ state: flow.state ? flow.state : undefined,
156
+ };
157
+ res.json(response);
158
+ }
159
+ else {
160
+ res.json({ status: "pending" });
161
+ }
162
+ }
163
+ catch (error) {
164
+ const message = error instanceof Error ? error.message : "Unknown error";
165
+ if (message.includes("expired") || message.includes("denied") || message.includes("invalid")) {
166
+ session_store_1.sessionStore.deleteDeviceFlow(flow_state);
167
+ res.json({ status: "failed", error: message });
168
+ }
169
+ else {
170
+ logger_1.logger.warn({ err: error }, "Device flow poll error");
171
+ res.json({ status: "pending" });
172
+ }
173
+ }
174
+ }
175
+ function getDeviceFlowHTML(params) {
176
+ const linkUrl = params.verificationUriComplete ?? params.verificationUri;
177
+ return `<!DOCTYPE html>
178
+ <html lang="en">
179
+ <head>
180
+ <meta charset="UTF-8">
181
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
182
+ <title>GitLab MCP - Authentication</title>
183
+ <style>
184
+ * {
185
+ box-sizing: border-box;
186
+ margin: 0;
187
+ padding: 0;
188
+ }
189
+ body {
190
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
191
+ max-width: 600px;
192
+ margin: 0 auto;
193
+ padding: 40px 20px;
194
+ background: #f5f5f5;
195
+ min-height: 100vh;
196
+ }
197
+ .container {
198
+ background: white;
199
+ padding: 40px;
200
+ border-radius: 12px;
201
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
202
+ }
203
+ h1 {
204
+ color: #333;
205
+ margin-bottom: 20px;
206
+ font-size: 24px;
207
+ }
208
+ p {
209
+ color: #666;
210
+ line-height: 1.6;
211
+ margin-bottom: 16px;
212
+ }
213
+ .code-container {
214
+ background: #f8f9fa;
215
+ border: 2px dashed #ddd;
216
+ border-radius: 8px;
217
+ padding: 24px;
218
+ margin: 24px 0;
219
+ text-align: center;
220
+ }
221
+ .code {
222
+ font-size: 36px;
223
+ font-weight: bold;
224
+ letter-spacing: 6px;
225
+ color: #333;
226
+ font-family: 'Courier New', monospace;
227
+ }
228
+ .code-label {
229
+ font-size: 12px;
230
+ color: #888;
231
+ text-transform: uppercase;
232
+ margin-bottom: 8px;
233
+ }
234
+ .link-button {
235
+ display: inline-block;
236
+ background: #fc6d26;
237
+ color: white;
238
+ padding: 14px 28px;
239
+ border-radius: 6px;
240
+ text-decoration: none;
241
+ font-weight: 500;
242
+ margin: 16px 0;
243
+ transition: background 0.2s;
244
+ }
245
+ .link-button:hover {
246
+ background: #e24329;
247
+ }
248
+ .status {
249
+ padding: 16px;
250
+ border-radius: 8px;
251
+ margin: 24px 0;
252
+ font-weight: 500;
253
+ }
254
+ .status.pending {
255
+ background: #fff3cd;
256
+ color: #856404;
257
+ border: 1px solid #ffeeba;
258
+ }
259
+ .status.success {
260
+ background: #d4edda;
261
+ color: #155724;
262
+ border: 1px solid #c3e6cb;
263
+ }
264
+ .status.error {
265
+ background: #f8d7da;
266
+ color: #721c24;
267
+ border: 1px solid #f5c6cb;
268
+ }
269
+ .instructions {
270
+ background: #e8f4fd;
271
+ border-left: 4px solid #0366d6;
272
+ padding: 16px;
273
+ margin: 24px 0;
274
+ border-radius: 0 8px 8px 0;
275
+ }
276
+ .instructions ol {
277
+ margin-left: 20px;
278
+ }
279
+ .instructions li {
280
+ margin: 8px 0;
281
+ color: #444;
282
+ }
283
+ .timer {
284
+ font-size: 14px;
285
+ color: #888;
286
+ margin-top: 16px;
287
+ }
288
+ .gitlab-logo {
289
+ width: 40px;
290
+ height: 40px;
291
+ margin-bottom: 16px;
292
+ }
293
+ </style>
294
+ </head>
295
+ <body>
296
+ <div class="container">
297
+ <svg class="gitlab-logo" viewBox="0 0 380 380" xmlns="http://www.w3.org/2000/svg">
298
+ <path d="M190.2 350.2l62.5-192.5H127.7l62.5 192.5z" fill="#e24329"/>
299
+ <path d="M190.2 350.2l-62.5-192.5H38.4l151.8 192.5z" fill="#fc6d26"/>
300
+ <path d="M38.4 157.7L9.1 247.6c-2.7 8.2.1 17.2 6.9 22.5l174.2 126.6L38.4 157.7z" fill="#fca326"/>
301
+ <path d="M38.4 157.7h89.3L91.4 48.5c-3.3-10.2-17.8-10.2-21.1 0L38.4 157.7z" fill="#e24329"/>
302
+ <path d="M190.2 350.2l62.5-192.5h89.3L190.2 350.2z" fill="#fc6d26"/>
303
+ <path d="M342 157.7l29.3 89.9c2.7 8.2-.1 17.2-6.9 22.5L190.2 396.7 342 157.7z" fill="#fca326"/>
304
+ <path d="M342 157.7h-89.3l36.3-109.2c3.3-10.2 17.8-10.2 21.1 0L342 157.7z" fill="#e24329"/>
305
+ </svg>
306
+
307
+ <h1>Authenticate with GitLab</h1>
308
+
309
+ <p>To complete authentication, visit GitLab and enter the code below:</p>
310
+
311
+ <div class="code-container">
312
+ <div class="code-label">Your Code</div>
313
+ <div class="code">${params.userCode}</div>
314
+ </div>
315
+
316
+ <div style="text-align: center;">
317
+ <a href="${linkUrl}" target="_blank" rel="noopener" class="link-button">
318
+ Open GitLab Authentication Page
319
+ </a>
320
+ </div>
321
+
322
+ <div class="instructions">
323
+ <strong>Instructions:</strong>
324
+ <ol>
325
+ <li>Click the button above to open GitLab</li>
326
+ <li>Sign in to your GitLab account if needed</li>
327
+ <li>Enter the code shown above</li>
328
+ <li>Click "Authorize" to grant access</li>
329
+ <li>Return here - you'll be redirected automatically</li>
330
+ </ol>
331
+ </div>
332
+
333
+ <div id="status" class="status pending">
334
+ Waiting for authentication...
335
+ </div>
336
+
337
+ <div class="timer" id="timer">
338
+ Code expires in <span id="countdown">${params.expiresIn}</span> seconds
339
+ </div>
340
+ </div>
341
+
342
+ <script>
343
+ const pollUrl = '${params.pollUrl}?flow_state=${params.flowState}';
344
+ const pollInterval = 5000; // 5 seconds
345
+ let countdown = ${params.expiresIn};
346
+
347
+ // Update countdown timer
348
+ const countdownEl = document.getElementById('countdown');
349
+ const timerInterval = setInterval(() => {
350
+ countdown--;
351
+ if (countdown <= 0) {
352
+ clearInterval(timerInterval);
353
+ document.getElementById('status').className = 'status error';
354
+ document.getElementById('status').textContent = 'Code expired. Please refresh to try again.';
355
+ document.getElementById('timer').style.display = 'none';
356
+ } else {
357
+ countdownEl.textContent = countdown;
358
+ }
359
+ }, 1000);
360
+
361
+ // Poll for completion
362
+ async function poll() {
363
+ try {
364
+ const response = await fetch(pollUrl);
365
+ const data = await response.json();
366
+
367
+ const statusEl = document.getElementById('status');
368
+
369
+ if (data.status === 'complete') {
370
+ clearInterval(timerInterval);
371
+ statusEl.className = 'status success';
372
+ statusEl.textContent = 'Authentication successful! Redirecting...';
373
+
374
+ // Build redirect URL with authorization code
375
+ if (data.redirect_uri) {
376
+ const redirectUrl = new URL(data.redirect_uri);
377
+ redirectUrl.searchParams.set('code', data.code);
378
+ if (data.state) {
379
+ redirectUrl.searchParams.set('state', data.state);
380
+ }
381
+
382
+ // Redirect after a brief delay
383
+ setTimeout(() => {
384
+ window.location.href = redirectUrl.toString();
385
+ }, 1000);
386
+ }
387
+ return;
388
+ }
389
+
390
+ if (data.status === 'failed' || data.status === 'expired') {
391
+ clearInterval(timerInterval);
392
+ statusEl.className = 'status error';
393
+ statusEl.textContent = 'Authentication failed: ' + (data.error || 'Unknown error');
394
+ document.getElementById('timer').style.display = 'none';
395
+ return;
396
+ }
397
+
398
+ // Still pending, continue polling
399
+ setTimeout(poll, pollInterval);
400
+
401
+ } catch (error) {
402
+ console.error('Poll error:', error);
403
+ // Continue polling on transient errors
404
+ setTimeout(poll, pollInterval);
405
+ }
406
+ }
407
+
408
+ // Start polling
409
+ setTimeout(poll, pollInterval);
410
+ </script>
411
+ </body>
412
+ </html>`;
413
+ }
414
+ //# sourceMappingURL=authorize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../../src/oauth/endpoints/authorize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { metadataHandler, healthHandler, getBaseUrl } from "./metadata";
2
+ export { authorizeHandler, pollHandler } from "./authorize";
3
+ export { tokenHandler } from "./token";
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tokenHandler = exports.pollHandler = exports.authorizeHandler = exports.getBaseUrl = exports.healthHandler = exports.metadataHandler = void 0;
4
+ var metadata_1 = require("./metadata");
5
+ Object.defineProperty(exports, "metadataHandler", { enumerable: true, get: function () { return metadata_1.metadataHandler; } });
6
+ Object.defineProperty(exports, "healthHandler", { enumerable: true, get: function () { return metadata_1.healthHandler; } });
7
+ Object.defineProperty(exports, "getBaseUrl", { enumerable: true, get: function () { return metadata_1.getBaseUrl; } });
8
+ var authorize_1 = require("./authorize");
9
+ Object.defineProperty(exports, "authorizeHandler", { enumerable: true, get: function () { return authorize_1.authorizeHandler; } });
10
+ Object.defineProperty(exports, "pollHandler", { enumerable: true, get: function () { return authorize_1.pollHandler; } });
11
+ var token_1 = require("./token");
12
+ Object.defineProperty(exports, "tokenHandler", { enumerable: true, get: function () { return token_1.tokenHandler; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/oauth/endpoints/index.ts"],"names":[],"mappings":";;;AAMA,uCAAwE;AAA/D,2GAAA,eAAe,OAAA;AAAE,yGAAA,aAAa,OAAA;AAAE,sGAAA,UAAU,OAAA;AACnD,yCAA4D;AAAnD,6GAAA,gBAAgB,OAAA;AAAE,wGAAA,WAAW,OAAA;AACtC,iCAAuC;AAA9B,qGAAA,YAAY,OAAA"}
@@ -0,0 +1,4 @@
1
+ import { Request, Response } from "express";
2
+ export declare function getBaseUrl(req: Request): string;
3
+ export declare function metadataHandler(req: Request, res: Response): void;
4
+ export declare function healthHandler(req: Request, res: Response): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBaseUrl = getBaseUrl;
4
+ exports.metadataHandler = metadataHandler;
5
+ exports.healthHandler = healthHandler;
6
+ const config_1 = require("../../config");
7
+ function getBaseUrl(req) {
8
+ const forwardedProto = req.get("x-forwarded-proto");
9
+ const protocol = forwardedProto ?? req.protocol ?? "http";
10
+ const forwardedHost = req.get("x-forwarded-host");
11
+ const host = forwardedHost ?? req.get("host") ?? `${config_1.HOST}:${config_1.PORT}`;
12
+ return `${protocol}://${host}`;
13
+ }
14
+ function metadataHandler(req, res) {
15
+ const baseUrl = getBaseUrl(req);
16
+ const metadata = {
17
+ issuer: baseUrl,
18
+ authorization_endpoint: `${baseUrl}/authorize`,
19
+ token_endpoint: `${baseUrl}/token`,
20
+ response_types_supported: ["code"],
21
+ grant_types_supported: ["authorization_code", "refresh_token"],
22
+ code_challenge_methods_supported: ["S256"],
23
+ token_endpoint_auth_methods_supported: ["none"],
24
+ scopes_supported: ["mcp:tools", "mcp:resources"],
25
+ mcp_version: "2025-03-26",
26
+ };
27
+ res.json(metadata);
28
+ }
29
+ function healthHandler(req, res) {
30
+ res.json({
31
+ status: "ok",
32
+ mode: "oauth",
33
+ timestamp: new Date().toISOString(),
34
+ });
35
+ }
36
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/oauth/endpoints/metadata.ts"],"names":[],"mappings":";;AAoBA,gCAUC;AAaD,0CAsCC;AAUD,sCAMC;AAvFD,yCAA0C;AAU1C,SAAgB,UAAU,CAAC,GAAY;IAErC,MAAM,cAAc,GAAG,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,cAAc,IAAI,GAAG,CAAC,QAAQ,IAAI,MAAM,CAAC;IAG1D,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,aAAa,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,aAAI,IAAI,aAAI,EAAE,CAAC;IAEnE,OAAO,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC;AACjC,CAAC;AAaD,SAAgB,eAAe,CAAC,GAAY,EAAE,GAAa;IACzD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAGhC,MAAM,QAAQ,GAAG;QAEf,MAAM,EAAE,OAAO;QAGf,sBAAsB,EAAE,GAAG,OAAO,YAAY;QAG9C,cAAc,EAAE,GAAG,OAAO,QAAQ;QAGlC,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAGlC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAG9D,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAI1C,qCAAqC,EAAE,CAAC,MAAM,CAAC;QAG/C,gBAAgB,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC;QAMhD,WAAW,EAAE,YAAY;KAC1B,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACrB,CAAC;AAUD,SAAgB,aAAa,CAAC,GAAY,EAAE,GAAa;IACvD,GAAG,CAAC,IAAI,CAAC;QACP,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Request, Response } from "express";
2
+ export declare function tokenHandler(req: Request, res: Response): Promise<void>;
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tokenHandler = tokenHandler;
4
+ const config_1 = require("../config");
5
+ const session_store_1 = require("../session-store");
6
+ const token_utils_1 = require("../token-utils");
7
+ const gitlab_device_flow_1 = require("../gitlab-device-flow");
8
+ const metadata_1 = require("./metadata");
9
+ const logger_1 = require("../../logger");
10
+ async function tokenHandler(req, res) {
11
+ const config = (0, config_1.loadOAuthConfig)();
12
+ if (!config) {
13
+ sendError(res, 500, "server_error", "OAuth not configured");
14
+ return;
15
+ }
16
+ const { grant_type } = req.body;
17
+ switch (grant_type) {
18
+ case "authorization_code":
19
+ await handleAuthorizationCode(req, res, config);
20
+ break;
21
+ case "refresh_token":
22
+ await handleRefreshToken(req, res, config);
23
+ break;
24
+ default:
25
+ sendError(res, 400, "unsupported_grant_type", `Grant type "${grant_type}" is not supported`);
26
+ }
27
+ }
28
+ async function handleAuthorizationCode(req, res, config) {
29
+ const { code, code_verifier, redirect_uri } = req.body;
30
+ if (!code) {
31
+ sendError(res, 400, "invalid_request", "Missing authorization code");
32
+ return;
33
+ }
34
+ if (!code_verifier) {
35
+ sendError(res, 400, "invalid_request", "Missing code_verifier (PKCE required)");
36
+ return;
37
+ }
38
+ const authCode = session_store_1.sessionStore.getAuthCode(code);
39
+ if (!authCode) {
40
+ sendError(res, 400, "invalid_grant", "Invalid or expired authorization code");
41
+ return;
42
+ }
43
+ if (Date.now() > authCode.expiresAt) {
44
+ session_store_1.sessionStore.deleteAuthCode(code);
45
+ sendError(res, 400, "invalid_grant", "Authorization code has expired");
46
+ return;
47
+ }
48
+ if (!(0, token_utils_1.verifyCodeChallenge)(code_verifier, authCode.codeChallenge, authCode.codeChallengeMethod)) {
49
+ sendError(res, 400, "invalid_grant", "Invalid code_verifier");
50
+ return;
51
+ }
52
+ if (authCode.redirectUri && redirect_uri !== authCode.redirectUri) {
53
+ sendError(res, 400, "invalid_grant", "redirect_uri does not match");
54
+ return;
55
+ }
56
+ const session = session_store_1.sessionStore.getSession(authCode.sessionId);
57
+ if (!session) {
58
+ sendError(res, 400, "invalid_grant", "Session not found");
59
+ return;
60
+ }
61
+ const baseUrl = (0, metadata_1.getBaseUrl)(req);
62
+ const accessToken = (0, token_utils_1.createJWT)({
63
+ iss: baseUrl,
64
+ sub: session.gitlabUserId.toString(),
65
+ aud: authCode.clientId,
66
+ sid: session.id,
67
+ scope: session.scopes.join(" "),
68
+ gitlab_user: session.gitlabUsername,
69
+ }, config.sessionSecret, config.tokenTtl);
70
+ const refreshToken = (0, token_utils_1.generateRefreshToken)();
71
+ session_store_1.sessionStore.updateSession(session.id, {
72
+ mcpAccessToken: accessToken,
73
+ mcpRefreshToken: refreshToken,
74
+ mcpTokenExpiry: (0, token_utils_1.calculateTokenExpiry)(config.tokenTtl),
75
+ });
76
+ session_store_1.sessionStore.deleteAuthCode(code);
77
+ logger_1.logger.info({
78
+ sessionId: session.id.substring(0, 8) + "...",
79
+ userId: session.gitlabUserId,
80
+ }, "MCP tokens issued via authorization_code grant");
81
+ const response = {
82
+ access_token: accessToken,
83
+ token_type: "Bearer",
84
+ expires_in: config.tokenTtl,
85
+ refresh_token: refreshToken,
86
+ scope: session.scopes.join(" "),
87
+ };
88
+ res.json(response);
89
+ }
90
+ async function handleRefreshToken(req, res, config) {
91
+ const { refresh_token } = req.body;
92
+ if (!refresh_token) {
93
+ sendError(res, 400, "invalid_request", "Missing refresh_token");
94
+ return;
95
+ }
96
+ const session = session_store_1.sessionStore.getSessionByRefreshToken(refresh_token);
97
+ if (!session) {
98
+ sendError(res, 400, "invalid_grant", "Invalid refresh token");
99
+ return;
100
+ }
101
+ let updatedSession = session;
102
+ if ((0, token_utils_1.isTokenExpiringSoon)(session.gitlabTokenExpiry)) {
103
+ try {
104
+ const newTokens = await (0, gitlab_device_flow_1.refreshGitLabToken)(session.gitlabRefreshToken, config);
105
+ session_store_1.sessionStore.updateSession(session.id, {
106
+ gitlabAccessToken: newTokens.access_token,
107
+ gitlabRefreshToken: newTokens.refresh_token,
108
+ gitlabTokenExpiry: (0, token_utils_1.calculateTokenExpiry)(newTokens.expires_in),
109
+ });
110
+ const refreshedSession = session_store_1.sessionStore.getSession(session.id);
111
+ if (!refreshedSession) {
112
+ sendError(res, 400, "invalid_grant", "Session lost during refresh");
113
+ return;
114
+ }
115
+ updatedSession = refreshedSession;
116
+ logger_1.logger.debug({ sessionId: session.id.substring(0, 8) + "..." }, "GitLab token refreshed");
117
+ }
118
+ catch (error) {
119
+ logger_1.logger.error({ err: error }, "Failed to refresh GitLab token");
120
+ sendError(res, 400, "invalid_grant", "Failed to refresh underlying GitLab token");
121
+ return;
122
+ }
123
+ }
124
+ const baseUrl = (0, metadata_1.getBaseUrl)(req);
125
+ const accessToken = (0, token_utils_1.createJWT)({
126
+ iss: baseUrl,
127
+ sub: updatedSession.gitlabUserId.toString(),
128
+ aud: updatedSession.clientId,
129
+ sid: updatedSession.id,
130
+ scope: updatedSession.scopes.join(" "),
131
+ gitlab_user: updatedSession.gitlabUsername,
132
+ }, config.sessionSecret, config.tokenTtl);
133
+ const newRefreshToken = (0, token_utils_1.generateRefreshToken)();
134
+ session_store_1.sessionStore.updateSession(updatedSession.id, {
135
+ mcpAccessToken: accessToken,
136
+ mcpRefreshToken: newRefreshToken,
137
+ mcpTokenExpiry: (0, token_utils_1.calculateTokenExpiry)(config.tokenTtl),
138
+ });
139
+ logger_1.logger.info({
140
+ sessionId: updatedSession.id.substring(0, 8) + "...",
141
+ userId: updatedSession.gitlabUserId,
142
+ }, "MCP tokens refreshed via refresh_token grant");
143
+ const response = {
144
+ access_token: accessToken,
145
+ token_type: "Bearer",
146
+ expires_in: config.tokenTtl,
147
+ refresh_token: newRefreshToken,
148
+ scope: updatedSession.scopes.join(" "),
149
+ };
150
+ res.json(response);
151
+ }
152
+ function sendError(res, status, error, description) {
153
+ const response = {
154
+ error,
155
+ error_description: description,
156
+ };
157
+ res.status(status).json(response);
158
+ }
159
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/oauth/endpoints/token.ts"],"names":[],"mappings":";;AAmCA,oCAqBC;AA5CD,sCAAyD;AACzD,oDAAgD;AAChD,gDAMwB;AACxB,8DAA2D;AAC3D,yCAAwC;AACxC,yCAAsC;AAY/B,KAAK,UAAU,YAAY,CAAC,GAAY,EAAE,GAAa;IAC5D,MAAM,MAAM,GAAG,IAAA,wBAAe,GAAE,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,IAA+B,CAAC;IAE3D,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,oBAAoB;YACvB,MAAM,uBAAuB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAChD,MAAM;QAER,KAAK,eAAe;YAClB,MAAM,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YAC3C,MAAM;QAER;YACE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,wBAAwB,EAAE,eAAe,UAAU,oBAAoB,CAAC,CAAC;IACjG,CAAC;AACH,CAAC;AAQD,KAAK,UAAU,uBAAuB,CACpC,GAAY,EACZ,GAAa,EACb,MAAmB;IAEnB,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,IAIjD,CAAC;IAGF,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,4BAA4B,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,uCAAuC,CAAC,CAAC;QAChF,OAAO;IACT,CAAC;IAGD,MAAM,QAAQ,GAAG,4BAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,uCAAuC,CAAC,CAAC;QAC9E,OAAO;IACT,CAAC;IAGD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QACpC,4BAAY,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAClC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,gCAAgC,CAAC,CAAC;QACvE,OAAO;IACT,CAAC;IAGD,IAAI,CAAC,IAAA,iCAAmB,EAAC,aAAa,EAAE,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC9F,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,uBAAuB,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAGD,IAAI,QAAQ,CAAC,WAAW,IAAI,YAAY,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;QAClE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,6BAA6B,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAGD,MAAM,OAAO,GAAG,4BAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,mBAAmB,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IAGD,MAAM,OAAO,GAAG,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;IAEhC,MAAM,WAAW,GAAG,IAAA,uBAAS,EAC3B;QACE,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC,QAAQ,EAAE;QACpC,GAAG,EAAE,QAAQ,CAAC,QAAQ;QACtB,GAAG,EAAE,OAAO,CAAC,EAAE;QACf,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAC/B,WAAW,EAAE,OAAO,CAAC,cAAc;KACpC,EACD,MAAM,CAAC,aAAa,EACpB,MAAM,CAAC,QAAQ,CAChB,CAAC;IAEF,MAAM,YAAY,GAAG,IAAA,kCAAoB,GAAE,CAAC;IAG5C,4BAAY,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE;QACrC,cAAc,EAAE,WAAW;QAC3B,eAAe,EAAE,YAAY;QAC7B,cAAc,EAAE,IAAA,kCAAoB,EAAC,MAAM,CAAC,QAAQ,CAAC;KACtD,CAAC,CAAC;IAGH,4BAAY,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAElC,eAAM,CAAC,IAAI,CACT;QACE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;QAC7C,MAAM,EAAE,OAAO,CAAC,YAAY;KAC7B,EACD,gDAAgD,CACjD,CAAC;IAGF,MAAM,QAAQ,GAAqB;QACjC,YAAY,EAAE,WAAW;QACzB,UAAU,EAAE,QAAQ;QACpB,UAAU,EAAE,MAAM,CAAC,QAAQ;QAC3B,aAAa,EAAE,YAAY;QAC3B,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KAChC,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACrB,CAAC;AAQD,KAAK,UAAU,kBAAkB,CAAC,GAAY,EAAE,GAAa,EAAE,MAAmB;IAChF,MAAM,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,IAAkC,CAAC;IAEjE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,uBAAuB,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IAGD,MAAM,OAAO,GAAG,4BAAY,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC;IACrE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,uBAAuB,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAGD,IAAI,cAAc,GAAiB,OAAO,CAAC;IAE3C,IAAI,IAAA,iCAAmB,EAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAA,uCAAkB,EAAC,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;YAE/E,4BAAY,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE;gBACrC,iBAAiB,EAAE,SAAS,CAAC,YAAY;gBACzC,kBAAkB,EAAE,SAAS,CAAC,aAAa;gBAC3C,iBAAiB,EAAE,IAAA,kCAAoB,EAAC,SAAS,CAAC,UAAU,CAAC;aAC9D,CAAC,CAAC;YAGH,MAAM,gBAAgB,GAAG,4BAAY,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACtB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,6BAA6B,CAAC,CAAC;gBACpE,OAAO;YACT,CAAC;YACD,cAAc,GAAG,gBAAgB,CAAC;YAElC,eAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,wBAAwB,CAAC,CAAC;QAC5F,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAc,EAAE,EAAE,gCAAgC,CAAC,CAAC;YACxE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,2CAA2C,CAAC,CAAC;YAClF,OAAO;QACT,CAAC;IACH,CAAC;IAGD,MAAM,OAAO,GAAG,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;IAEhC,MAAM,WAAW,GAAG,IAAA,uBAAS,EAC3B;QACE,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,cAAc,CAAC,YAAY,CAAC,QAAQ,EAAE;QAC3C,GAAG,EAAE,cAAc,CAAC,QAAQ;QAC5B,GAAG,EAAE,cAAc,CAAC,EAAE;QACtB,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACtC,WAAW,EAAE,cAAc,CAAC,cAAc;KAC3C,EACD,MAAM,CAAC,aAAa,EACpB,MAAM,CAAC,QAAQ,CAChB,CAAC;IAEF,MAAM,eAAe,GAAG,IAAA,kCAAoB,GAAE,CAAC;IAG/C,4BAAY,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,EAAE;QAC5C,cAAc,EAAE,WAAW;QAC3B,eAAe,EAAE,eAAe;QAChC,cAAc,EAAE,IAAA,kCAAoB,EAAC,MAAM,CAAC,QAAQ,CAAC;KACtD,CAAC,CAAC;IAEH,eAAM,CAAC,IAAI,CACT;QACE,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;QACpD,MAAM,EAAE,cAAc,CAAC,YAAY;KACpC,EACD,8CAA8C,CAC/C,CAAC;IAGF,MAAM,QAAQ,GAAqB;QACjC,YAAY,EAAE,WAAW;QACzB,UAAU,EAAE,QAAQ;QACpB,UAAU,EAAE,MAAM,CAAC,QAAQ;QAC3B,aAAa,EAAE,eAAe;QAC9B,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KACvC,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACrB,CAAC;AAKD,SAAS,SAAS,CAAC,GAAa,EAAE,MAAc,EAAE,KAAa,EAAE,WAAmB;IAClF,MAAM,QAAQ,GAAuB;QACnC,KAAK;QACL,iBAAiB,EAAE,WAAW;KAC/B,CAAC;IACF,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC"}