fluxmail 0.16.0 → 0.17.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 (79) hide show
  1. package/dist/auth.d.ts +22 -1
  2. package/dist/auth.d.ts.map +1 -1
  3. package/dist/auth.js +29 -3
  4. package/dist/auth.js.map +1 -1
  5. package/dist/authorization.d.ts +2 -0
  6. package/dist/authorization.d.ts.map +1 -1
  7. package/dist/authorization.js +9 -4
  8. package/dist/authorization.js.map +1 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +93 -5
  11. package/dist/cli.js.map +1 -1
  12. package/dist/cliMail.d.ts.map +1 -1
  13. package/dist/cliMail.js +21 -1
  14. package/dist/cliMail.js.map +1 -1
  15. package/dist/deploymentConfig.d.ts +1 -1
  16. package/dist/deploymentConfig.d.ts.map +1 -1
  17. package/dist/deploymentConfig.js +1 -1
  18. package/dist/deploymentConfig.js.map +1 -1
  19. package/dist/http/app.d.ts +3 -0
  20. package/dist/http/app.d.ts.map +1 -1
  21. package/dist/http/app.js +37 -22
  22. package/dist/http/app.js.map +1 -1
  23. package/dist/http/identity.d.ts +20 -0
  24. package/dist/http/identity.d.ts.map +1 -1
  25. package/dist/http/identity.js +146 -0
  26. package/dist/http/identity.js.map +1 -1
  27. package/dist/http/oauth.d.ts +28 -0
  28. package/dist/http/oauth.d.ts.map +1 -0
  29. package/dist/http/oauth.js +552 -0
  30. package/dist/http/oauth.js.map +1 -0
  31. package/dist/http/oauthPages.d.ts +36 -0
  32. package/dist/http/oauthPages.d.ts.map +1 -0
  33. package/dist/http/oauthPages.js +213 -0
  34. package/dist/http/oauthPages.js.map +1 -0
  35. package/dist/http/rest.d.ts.map +1 -1
  36. package/dist/http/rest.js +13 -7
  37. package/dist/http/rest.js.map +1 -1
  38. package/dist/mcp/attachmentContent.d.ts +1 -1
  39. package/dist/mcp/attachmentContent.d.ts.map +1 -1
  40. package/dist/mcp/buildServer.d.ts +1 -1
  41. package/dist/mcp/buildServer.d.ts.map +1 -1
  42. package/dist/mcp/buildServer.js +77 -46
  43. package/dist/mcp/buildServer.js.map +1 -1
  44. package/dist/mcp/clientTelemetry.d.ts +19 -0
  45. package/dist/mcp/clientTelemetry.d.ts.map +1 -0
  46. package/dist/mcp/clientTelemetry.js +152 -0
  47. package/dist/mcp/clientTelemetry.js.map +1 -0
  48. package/dist/mcp/outputSchemas.d.ts +6 -6
  49. package/dist/oauth/clientMetadata.d.ts +39 -0
  50. package/dist/oauth/clientMetadata.d.ts.map +1 -0
  51. package/dist/oauth/clientMetadata.js +234 -0
  52. package/dist/oauth/clientMetadata.js.map +1 -0
  53. package/dist/oauth/redirectUris.d.ts +13 -0
  54. package/dist/oauth/redirectUris.d.ts.map +1 -0
  55. package/dist/oauth/redirectUris.js +78 -0
  56. package/dist/oauth/redirectUris.js.map +1 -0
  57. package/dist/permissions.d.ts +4 -0
  58. package/dist/permissions.d.ts.map +1 -1
  59. package/dist/permissions.js +10 -0
  60. package/dist/permissions.js.map +1 -1
  61. package/dist/service/emailService.d.ts.map +1 -1
  62. package/dist/service/emailService.js +4 -1
  63. package/dist/service/emailService.js.map +1 -1
  64. package/dist/service/publicErrors.d.ts +4 -0
  65. package/dist/service/publicErrors.d.ts.map +1 -1
  66. package/dist/service/publicErrors.js +16 -1
  67. package/dist/service/publicErrors.js.map +1 -1
  68. package/dist/storage/db.d.ts +824 -2
  69. package/dist/storage/db.d.ts.map +1 -1
  70. package/dist/storage/db.js +142 -1
  71. package/dist/storage/db.js.map +1 -1
  72. package/dist/storage/members.d.ts.map +1 -1
  73. package/dist/storage/members.js +2 -0
  74. package/dist/storage/members.js.map +1 -1
  75. package/dist/storage/oauth.d.ts +178 -0
  76. package/dist/storage/oauth.d.ts.map +1 -0
  77. package/dist/storage/oauth.js +556 -0
  78. package/dist/storage/oauth.js.map +1 -0
  79. package/package.json +9 -6
@@ -0,0 +1,556 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ import { and, count, eq, gt, inArray, isNull, lte, notExists, or, sql } from 'drizzle-orm';
3
+ import { authRateLimits, mcpOauthClients, mcpOauthCodes, mcpOauthGrants, mcpOauthRequests, mcpOauthTokens, members, } from './db.js';
4
+ import { MCP_CAPABILITIES, isMcpCapability } from '../permissions.js';
5
+ export const OAUTH_ACCESS_TOKEN_TTL_MS = 15 * 60 * 1000;
6
+ export const OAUTH_REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 60 * 1000;
7
+ export const OAUTH_GRANT_TTL_MS = 90 * 24 * 60 * 60 * 1000;
8
+ export const OAUTH_CODE_TTL_MS = 60 * 1000;
9
+ export const OAUTH_REQUEST_TTL_MS = 10 * 60 * 1000;
10
+ export const OAUTH_MAX_CLIENTS = 1_000;
11
+ export const OAUTH_MAX_CLIENTS_PER_HOST = 20;
12
+ const UNUSED_CLIENT_TTL_MS = 24 * 60 * 60 * 1000;
13
+ const PRUNE_BATCH = 100;
14
+ const GRANT_TOUCH_INTERVAL_MS = 60 * 60 * 1000;
15
+ export const OFFLINE_ACCESS_SCOPE = 'offline_access';
16
+ export const OAUTH_SCOPES = [...MCP_CAPABILITIES, OFFLINE_ACCESS_SCOPE];
17
+ function secretHash(secret) {
18
+ return createHash('sha256').update(secret).digest('hex');
19
+ }
20
+ function sameHash(a, b) {
21
+ const left = Buffer.from(a, 'hex');
22
+ const right = Buffer.from(b, 'hex');
23
+ return left.length === right.length && timingSafeEqual(left, right);
24
+ }
25
+ export function isOAuthScope(value) {
26
+ return value === OFFLINE_ACCESS_SCOPE || isMcpCapability(value);
27
+ }
28
+ /** Keep known scopes in canonical order. */
29
+ export function canonicalOAuthScopes(scopes) {
30
+ const set = new Set(scopes);
31
+ return OAUTH_SCOPES.filter((scope) => set.has(scope));
32
+ }
33
+ export function mailScopesOf(scopes) {
34
+ const set = new Set(scopes);
35
+ return MCP_CAPABILITIES.filter((scope) => set.has(scope));
36
+ }
37
+ function parseStringArray(value) {
38
+ const parsed = JSON.parse(value);
39
+ if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === 'string')) {
40
+ throw new Error('Stored OAuth value must be a JSON array of strings.');
41
+ }
42
+ return parsed;
43
+ }
44
+ function parseAccountIds(value) {
45
+ return value === null ? null : [...new Set(parseStringArray(value))];
46
+ }
47
+ function clientFromRow(row) {
48
+ return {
49
+ id: row.id,
50
+ kind: row.kind,
51
+ name: row.name,
52
+ redirectUris: parseStringArray(row.redirectUris),
53
+ scopes: mailScopesOf(parseStringArray(row.scopes)),
54
+ metadataHost: row.metadataHost,
55
+ metadataExpiresAt: row.metadataExpiresAt,
56
+ createdAt: row.createdAt,
57
+ lastUsedAt: row.lastUsedAt,
58
+ };
59
+ }
60
+ function pruneUnusedClients(db, now) {
61
+ const unused = db
62
+ .select({ id: mcpOauthClients.id })
63
+ .from(mcpOauthClients)
64
+ .where(and(lte(mcpOauthClients.createdAt, now - UNUSED_CLIENT_TTL_MS), notExists(db.select().from(mcpOauthGrants).where(eq(mcpOauthGrants.clientId, mcpOauthClients.id))), notExists(db.select().from(mcpOauthRequests).where(eq(mcpOauthRequests.clientId, mcpOauthClients.id)))))
65
+ .limit(PRUNE_BATCH)
66
+ .all();
67
+ if (unused.length) {
68
+ db.delete(mcpOauthClients)
69
+ .where(inArray(mcpOauthClients.id, unused.map((row) => row.id)))
70
+ .run();
71
+ }
72
+ }
73
+ /** Remove expired protocol state, ended grants, and clients nobody uses. */
74
+ export function pruneOAuthState(db, now = Date.now()) {
75
+ db.transaction((tx) => {
76
+ tx.delete(mcpOauthRequests).where(lte(mcpOauthRequests.expiresAt, now)).run();
77
+ tx.delete(mcpOauthCodes).where(lte(mcpOauthCodes.expiresAt, now)).run();
78
+ // Ended grants take their tokens and codes with them through cascades.
79
+ tx.delete(mcpOauthGrants)
80
+ .where(or(lte(mcpOauthGrants.expiresAt, now), sql `${mcpOauthGrants.revokedAt} IS NOT NULL`))
81
+ .run();
82
+ // Rotated refresh tokens stay until they expire so their reuse is still detected.
83
+ tx.delete(mcpOauthTokens).where(lte(mcpOauthTokens.expiresAt, now)).run();
84
+ pruneUnusedClients(tx, now);
85
+ });
86
+ }
87
+ /**
88
+ * Count an attempt in a fixed window shared across processes. Returns false
89
+ * once the limit is reached.
90
+ */
91
+ export function reserveOAuthRateLimit(db, name, limit, windowMs, now = Date.now()) {
92
+ const key = `oauth:${secretHash(name)}`;
93
+ return db.transaction((tx) => {
94
+ const row = tx.select().from(authRateLimits).where(eq(authRateLimits.key, key)).get();
95
+ if (!row || row.windowStartedAt <= now - windowMs) {
96
+ tx.insert(authRateLimits)
97
+ .values({ key, attempts: 1, windowStartedAt: now })
98
+ .onConflictDoUpdate({ target: authRateLimits.key, set: { attempts: 1, windowStartedAt: now } })
99
+ .run();
100
+ return true;
101
+ }
102
+ if (row.attempts >= limit)
103
+ return false;
104
+ tx.update(authRateLimits)
105
+ .set({ attempts: row.attempts + 1 })
106
+ .where(eq(authRateLimits.key, key))
107
+ .run();
108
+ return true;
109
+ }, { behavior: 'immediate' });
110
+ }
111
+ /** Store a dynamically registered public client. Returns null when the client limit is reached. */
112
+ export function registerOAuthClient(db, input, now = Date.now()) {
113
+ pruneOAuthState(db, now);
114
+ return db.transaction((tx) => {
115
+ const total = tx.select({ value: count() }).from(mcpOauthClients).get()?.value ?? 0;
116
+ if (total >= OAUTH_MAX_CLIENTS)
117
+ return null;
118
+ const row = {
119
+ id: `client_${randomBytes(16).toString('hex')}`,
120
+ kind: 'registered',
121
+ name: input.name,
122
+ redirectUris: JSON.stringify([...new Set(input.redirectUris)]),
123
+ scopes: JSON.stringify(mailScopesOf(input.scopes)),
124
+ metadataHost: null,
125
+ metadataExpiresAt: null,
126
+ createdAt: now,
127
+ lastUsedAt: null,
128
+ };
129
+ tx.insert(mcpOauthClients).values(row).run();
130
+ return clientFromRow(row);
131
+ }, { behavior: 'immediate' });
132
+ }
133
+ /**
134
+ * Create or refresh a client described by a metadata document. New clients
135
+ * count toward the global and per-host limits.
136
+ */
137
+ export function storeMetadataOAuthClient(db, input, now = Date.now()) {
138
+ return db.transaction((tx) => {
139
+ const values = {
140
+ name: input.name,
141
+ redirectUris: JSON.stringify([...new Set(input.redirectUris)]),
142
+ // Metadata documents cannot narrow scopes; consent decides what the client receives.
143
+ scopes: JSON.stringify(MCP_CAPABILITIES),
144
+ metadataHost: input.host,
145
+ metadataExpiresAt: input.expiresAt,
146
+ };
147
+ const existing = tx.select().from(mcpOauthClients).where(eq(mcpOauthClients.id, input.id)).get();
148
+ if (existing) {
149
+ tx.update(mcpOauthClients).set(values).where(eq(mcpOauthClients.id, input.id)).run();
150
+ return { status: 'stored', client: clientFromRow({ ...existing, ...values }) };
151
+ }
152
+ const total = tx.select({ value: count() }).from(mcpOauthClients).get()?.value ?? 0;
153
+ const perHost = tx.select({ value: count() }).from(mcpOauthClients).where(eq(mcpOauthClients.metadataHost, input.host)).get()
154
+ ?.value ?? 0;
155
+ if (total >= OAUTH_MAX_CLIENTS || perHost >= OAUTH_MAX_CLIENTS_PER_HOST)
156
+ return { status: 'limit' };
157
+ const row = {
158
+ id: input.id,
159
+ kind: 'metadata_document',
160
+ ...values,
161
+ createdAt: now,
162
+ lastUsedAt: null,
163
+ };
164
+ tx.insert(mcpOauthClients).values(row).run();
165
+ return { status: 'stored', client: clientFromRow(row) };
166
+ }, { behavior: 'immediate' });
167
+ }
168
+ export function getOAuthClient(db, id) {
169
+ const row = db.select().from(mcpOauthClients).where(eq(mcpOauthClients.id, id)).get();
170
+ return row ? clientFromRow(row) : null;
171
+ }
172
+ export function countOAuthClients(db, host) {
173
+ return (db
174
+ .select({ value: count() })
175
+ .from(mcpOauthClients)
176
+ .where(host ? eq(mcpOauthClients.metadataHost, host) : undefined)
177
+ .get()?.value ?? 0);
178
+ }
179
+ function requestFromRow(row) {
180
+ return {
181
+ id: row.id,
182
+ clientId: row.clientId,
183
+ redirectUri: row.redirectUri,
184
+ state: row.state,
185
+ codeChallenge: row.codeChallenge,
186
+ scopes: canonicalOAuthScopes(parseStringArray(row.scopes)),
187
+ memberId: row.memberId,
188
+ expiresAt: row.expiresAt,
189
+ };
190
+ }
191
+ /** Save a validated authorization request. The CSRF token is returned once. */
192
+ export function createOAuthAuthorizationRequest(db, input, now = Date.now()) {
193
+ const csrf = randomBytes(32).toString('hex');
194
+ const row = {
195
+ id: randomBytes(16).toString('hex'),
196
+ clientId: input.clientId,
197
+ redirectUri: input.redirectUri,
198
+ state: input.state ?? null,
199
+ codeChallenge: input.codeChallenge,
200
+ scopes: JSON.stringify(canonicalOAuthScopes(input.scopes)),
201
+ csrfHash: secretHash(csrf),
202
+ memberId: null,
203
+ createdAt: now,
204
+ expiresAt: now + OAUTH_REQUEST_TTL_MS,
205
+ };
206
+ db.transaction((tx) => {
207
+ // Keep this client referenced while cleanup removes its ended grants.
208
+ tx.insert(mcpOauthRequests).values(row).run();
209
+ pruneOAuthState(tx, now);
210
+ }, { behavior: 'immediate' });
211
+ return { request: requestFromRow(row), csrf };
212
+ }
213
+ /** Find an unexpired request whose CSRF token matches. */
214
+ export function getOAuthAuthorizationRequest(db, id, csrf, now = Date.now()) {
215
+ const row = db
216
+ .select()
217
+ .from(mcpOauthRequests)
218
+ .where(and(eq(mcpOauthRequests.id, id), gt(mcpOauthRequests.expiresAt, now)))
219
+ .get();
220
+ if (!row || !/^[0-9a-f]{64}$/.test(csrf) || !sameHash(row.csrfHash, secretHash(csrf)))
221
+ return null;
222
+ return requestFromRow(row);
223
+ }
224
+ /** Record the signed-in member on a request and rotate its CSRF token. */
225
+ export function signInOAuthAuthorizationRequest(db, id, memberId, now = Date.now()) {
226
+ const csrf = randomBytes(32).toString('hex');
227
+ const updated = db
228
+ .update(mcpOauthRequests)
229
+ .set({ memberId, csrfHash: secretHash(csrf) })
230
+ .where(and(eq(mcpOauthRequests.id, id), gt(mcpOauthRequests.expiresAt, now)))
231
+ .run();
232
+ return updated.changes === 1 ? csrf : null;
233
+ }
234
+ export function deleteOAuthAuthorizationRequest(db, id) {
235
+ db.delete(mcpOauthRequests).where(eq(mcpOauthRequests.id, id)).run();
236
+ }
237
+ /**
238
+ * Turn a signed-in request into a grant and a single-use authorization code.
239
+ * The request is deleted in the same transaction, so it cannot be approved twice.
240
+ */
241
+ export function approveOAuthAuthorizationRequest(db, input, now = Date.now()) {
242
+ const code = `fmc_${randomBytes(32).toString('hex')}`;
243
+ return db.transaction((tx) => {
244
+ const row = tx
245
+ .select()
246
+ .from(mcpOauthRequests)
247
+ .where(and(eq(mcpOauthRequests.id, input.requestId), eq(mcpOauthRequests.memberId, input.memberId), gt(mcpOauthRequests.expiresAt, now)))
248
+ .get();
249
+ if (!row)
250
+ return null;
251
+ const requested = new Set(requestFromRow(row).scopes);
252
+ const scopes = mailScopesOf(input.scopes).filter((scope) => requested.has(scope));
253
+ if (!scopes.length)
254
+ return null;
255
+ tx.delete(mcpOauthRequests).where(eq(mcpOauthRequests.id, row.id)).run();
256
+ const grantId = `grant_${randomBytes(8).toString('hex')}`;
257
+ tx.insert(mcpOauthGrants)
258
+ .values({
259
+ id: grantId,
260
+ clientId: row.clientId,
261
+ memberId: input.memberId,
262
+ scopes: JSON.stringify(scopes),
263
+ accountIds: input.accountIds === null ? null : JSON.stringify([...new Set(input.accountIds)]),
264
+ createdAt: now,
265
+ expiresAt: now + OAUTH_GRANT_TTL_MS,
266
+ lastUsedAt: null,
267
+ revokedAt: null,
268
+ })
269
+ .run();
270
+ // Every grant gets a refresh token, so clients that omit offline_access
271
+ // are not asked to sign in again every 15 minutes.
272
+ const tokenScopes = canonicalOAuthScopes([...scopes, OFFLINE_ACCESS_SCOPE]);
273
+ tx.insert(mcpOauthCodes)
274
+ .values({
275
+ codeHash: secretHash(code),
276
+ grantId,
277
+ redirectUri: row.redirectUri,
278
+ codeChallenge: row.codeChallenge,
279
+ scopes: JSON.stringify(tokenScopes),
280
+ createdAt: now,
281
+ expiresAt: now + OAUTH_CODE_TTL_MS,
282
+ consumedAt: null,
283
+ })
284
+ .run();
285
+ tx.update(mcpOauthClients).set({ lastUsedAt: now }).where(eq(mcpOauthClients.id, row.clientId)).run();
286
+ return { code, grantId, redirectUri: row.redirectUri, state: row.state };
287
+ }, { behavior: 'immediate' });
288
+ }
289
+ function pkceMatches(verifier, challenge) {
290
+ if (!/^[A-Za-z0-9\-._~]{43,128}$/.test(verifier))
291
+ return false;
292
+ const expected = Buffer.from(createHash('sha256').update(verifier).digest('base64url'));
293
+ const actual = Buffer.from(challenge);
294
+ return expected.length === actual.length && timingSafeEqual(expected, actual);
295
+ }
296
+ function activeGrant(tx, grantId, now) {
297
+ const grant = tx.select().from(mcpOauthGrants).where(eq(mcpOauthGrants.id, grantId)).get();
298
+ if (!grant || grant.revokedAt !== null || grant.expiresAt <= now)
299
+ return null;
300
+ const member = tx.select().from(members).where(eq(members.id, grant.memberId)).get();
301
+ return member?.status === 'active' ? grant : null;
302
+ }
303
+ function revokeGrantInTx(tx, grantId, now) {
304
+ const revoked = tx
305
+ .update(mcpOauthGrants)
306
+ .set({ revokedAt: now })
307
+ .where(and(eq(mcpOauthGrants.id, grantId), isNull(mcpOauthGrants.revokedAt)))
308
+ .run();
309
+ tx.delete(mcpOauthTokens).where(eq(mcpOauthTokens.grantId, grantId)).run();
310
+ tx.delete(mcpOauthCodes).where(eq(mcpOauthCodes.grantId, grantId)).run();
311
+ return revoked.changes > 0;
312
+ }
313
+ function issueTokens(tx, grant, scopes, now) {
314
+ const accessToken = `fmo_${randomBytes(32).toString('hex')}`;
315
+ const accessExpiresAt = Math.min(now + OAUTH_ACCESS_TOKEN_TTL_MS, grant.expiresAt);
316
+ const serialized = JSON.stringify(scopes);
317
+ tx.insert(mcpOauthTokens)
318
+ .values({
319
+ tokenHash: secretHash(accessToken),
320
+ grantId: grant.id,
321
+ kind: 'access',
322
+ scopes: serialized,
323
+ createdAt: now,
324
+ expiresAt: accessExpiresAt,
325
+ rotatedAt: null,
326
+ })
327
+ .run();
328
+ let refreshToken;
329
+ if (scopes.includes(OFFLINE_ACCESS_SCOPE)) {
330
+ refreshToken = `fmr_${randomBytes(32).toString('hex')}`;
331
+ tx.insert(mcpOauthTokens)
332
+ .values({
333
+ tokenHash: secretHash(refreshToken),
334
+ grantId: grant.id,
335
+ kind: 'refresh',
336
+ scopes: serialized,
337
+ createdAt: now,
338
+ expiresAt: Math.min(now + OAUTH_REFRESH_TOKEN_TTL_MS, grant.expiresAt),
339
+ rotatedAt: null,
340
+ })
341
+ .run();
342
+ }
343
+ return {
344
+ accessToken,
345
+ ...(refreshToken ? { refreshToken } : {}),
346
+ expiresIn: Math.max(1, Math.floor((accessExpiresAt - now) / 1000)),
347
+ scopes: [...scopes],
348
+ };
349
+ }
350
+ const INVALID_GRANT = (description) => ({ ok: false, error: 'invalid_grant', description });
351
+ /** Exchange an authorization code. Replaying a used code revokes its grant. */
352
+ export function exchangeOAuthAuthorizationCode(db, input, now = Date.now()) {
353
+ return db.transaction((tx) => {
354
+ const row = tx
355
+ .select()
356
+ .from(mcpOauthCodes)
357
+ .where(eq(mcpOauthCodes.codeHash, secretHash(input.code)))
358
+ .get();
359
+ if (!row)
360
+ return INVALID_GRANT('The authorization code is invalid.');
361
+ const grant = tx.select().from(mcpOauthGrants).where(eq(mcpOauthGrants.id, row.grantId)).get();
362
+ if (!grant || grant.clientId !== input.clientId)
363
+ return INVALID_GRANT('The authorization code is invalid.');
364
+ if (row.consumedAt !== null) {
365
+ revokeGrantInTx(tx, grant.id, now);
366
+ return INVALID_GRANT('The authorization code was already used.');
367
+ }
368
+ if (row.expiresAt <= now)
369
+ return INVALID_GRANT('The authorization code has expired.');
370
+ if (row.redirectUri !== input.redirectUri)
371
+ return INVALID_GRANT('redirect_uri does not match the authorization.');
372
+ if (!pkceMatches(input.codeVerifier, row.codeChallenge))
373
+ return INVALID_GRANT('PKCE verification failed.');
374
+ const active = activeGrant(tx, grant.id, now);
375
+ if (!active)
376
+ return INVALID_GRANT('The authorization is no longer active.');
377
+ tx.update(mcpOauthCodes).set({ consumedAt: now }).where(eq(mcpOauthCodes.codeHash, row.codeHash)).run();
378
+ return {
379
+ ok: true,
380
+ tokens: issueTokens(tx, active, canonicalOAuthScopes(parseStringArray(row.scopes)), now),
381
+ };
382
+ }, { behavior: 'immediate' });
383
+ }
384
+ /**
385
+ * Rotate a refresh token. Reusing a rotated token revokes the grant. A refresh
386
+ * can keep or narrow its scopes but never add one.
387
+ */
388
+ export function refreshOAuthTokens(db, input, now = Date.now()) {
389
+ return db.transaction((tx) => {
390
+ const row = tx
391
+ .select()
392
+ .from(mcpOauthTokens)
393
+ .where(and(eq(mcpOauthTokens.tokenHash, secretHash(input.refreshToken)), eq(mcpOauthTokens.kind, 'refresh')))
394
+ .get();
395
+ if (!row)
396
+ return INVALID_GRANT('The refresh token is invalid.');
397
+ const grant = tx.select().from(mcpOauthGrants).where(eq(mcpOauthGrants.id, row.grantId)).get();
398
+ if (!grant || grant.clientId !== input.clientId)
399
+ return INVALID_GRANT('The refresh token is invalid.');
400
+ if (row.rotatedAt !== null) {
401
+ revokeGrantInTx(tx, grant.id, now);
402
+ return INVALID_GRANT('The refresh token was already used.');
403
+ }
404
+ if (row.expiresAt <= now)
405
+ return INVALID_GRANT('The refresh token has expired.');
406
+ const active = activeGrant(tx, grant.id, now);
407
+ if (!active)
408
+ return INVALID_GRANT('The authorization is no longer active.');
409
+ const current = canonicalOAuthScopes(parseStringArray(row.scopes));
410
+ let scopes = current;
411
+ if (input.scopes) {
412
+ if (!input.scopes.every((scope) => current.includes(scope))) {
413
+ return { ok: false, error: 'invalid_scope', description: 'A refresh cannot add scopes.' };
414
+ }
415
+ scopes = canonicalOAuthScopes([...input.scopes, OFFLINE_ACCESS_SCOPE]);
416
+ }
417
+ if (!mailScopesOf(scopes).length) {
418
+ return { ok: false, error: 'invalid_scope', description: 'Request at least one mail scope.' };
419
+ }
420
+ tx.update(mcpOauthTokens).set({ rotatedAt: now }).where(eq(mcpOauthTokens.tokenHash, row.tokenHash)).run();
421
+ return { ok: true, tokens: issueTokens(tx, active, scopes, now) };
422
+ }, { behavior: 'immediate' });
423
+ }
424
+ /**
425
+ * Revoke the grant behind a token when the token belongs to the client.
426
+ * Unknown tokens are ignored, as RFC 7009 requires.
427
+ */
428
+ export function revokeOAuthToken(db, input, now = Date.now()) {
429
+ db.transaction((tx) => {
430
+ const row = tx
431
+ .select({ grantId: mcpOauthTokens.grantId, clientId: mcpOauthGrants.clientId })
432
+ .from(mcpOauthTokens)
433
+ .innerJoin(mcpOauthGrants, eq(mcpOauthGrants.id, mcpOauthTokens.grantId))
434
+ .where(eq(mcpOauthTokens.tokenHash, secretHash(input.token)))
435
+ .get();
436
+ if (row && row.clientId === input.clientId)
437
+ revokeGrantInTx(tx, row.grantId, now);
438
+ }, { behavior: 'immediate' });
439
+ }
440
+ /** Verify an access token against its live grant and member. */
441
+ export function authenticateOAuthAccessToken(db, token, now = Date.now()) {
442
+ const row = db
443
+ .select({
444
+ tokenScopes: mcpOauthTokens.scopes,
445
+ tokenExpiresAt: mcpOauthTokens.expiresAt,
446
+ grantId: mcpOauthGrants.id,
447
+ clientId: mcpOauthGrants.clientId,
448
+ memberId: mcpOauthGrants.memberId,
449
+ grantScopes: mcpOauthGrants.scopes,
450
+ accountIds: mcpOauthGrants.accountIds,
451
+ grantExpiresAt: mcpOauthGrants.expiresAt,
452
+ revokedAt: mcpOauthGrants.revokedAt,
453
+ lastUsedAt: mcpOauthGrants.lastUsedAt,
454
+ role: members.role,
455
+ status: members.status,
456
+ })
457
+ .from(mcpOauthTokens)
458
+ .innerJoin(mcpOauthGrants, eq(mcpOauthGrants.id, mcpOauthTokens.grantId))
459
+ .innerJoin(members, eq(members.id, mcpOauthGrants.memberId))
460
+ .where(and(eq(mcpOauthTokens.tokenHash, secretHash(token)), eq(mcpOauthTokens.kind, 'access')))
461
+ .get();
462
+ if (!row || row.tokenExpiresAt <= now || row.grantExpiresAt <= now || row.revokedAt !== null)
463
+ return null;
464
+ if (row.status !== 'active')
465
+ return null;
466
+ try {
467
+ const granted = new Set(parseStringArray(row.grantScopes));
468
+ const scopes = mailScopesOf(parseStringArray(row.tokenScopes)).filter((scope) => granted.has(scope));
469
+ if (!scopes.length)
470
+ return null;
471
+ const accountIds = parseAccountIds(row.accountIds);
472
+ if (row.lastUsedAt === null || now - row.lastUsedAt >= GRANT_TOUCH_INTERVAL_MS) {
473
+ db.update(mcpOauthGrants).set({ lastUsedAt: now }).where(eq(mcpOauthGrants.id, row.grantId)).run();
474
+ }
475
+ return {
476
+ grantId: row.grantId,
477
+ clientId: row.clientId,
478
+ memberId: row.memberId,
479
+ role: row.role,
480
+ scopes,
481
+ accountIds,
482
+ };
483
+ }
484
+ catch {
485
+ return null;
486
+ }
487
+ }
488
+ /** Active grants, optionally for one member, newest first. */
489
+ export function listOAuthGrants(db, memberId, now = Date.now()) {
490
+ return db
491
+ .select({ grant: mcpOauthGrants, clientName: mcpOauthClients.name, clientKind: mcpOauthClients.kind })
492
+ .from(mcpOauthGrants)
493
+ .innerJoin(mcpOauthClients, eq(mcpOauthClients.id, mcpOauthGrants.clientId))
494
+ .where(and(isNull(mcpOauthGrants.revokedAt), gt(mcpOauthGrants.expiresAt, now), memberId ? eq(mcpOauthGrants.memberId, memberId) : undefined))
495
+ .all()
496
+ .map(({ grant, clientName, clientKind }) => ({
497
+ id: grant.id,
498
+ clientId: grant.clientId,
499
+ clientName,
500
+ clientKind: clientKind,
501
+ memberId: grant.memberId,
502
+ scopes: mailScopesOf(parseStringArray(grant.scopes)),
503
+ accountIds: parseAccountIds(grant.accountIds),
504
+ createdAt: grant.createdAt,
505
+ expiresAt: grant.expiresAt,
506
+ lastUsedAt: grant.lastUsedAt,
507
+ }))
508
+ .sort((a, b) => b.createdAt - a.createdAt || a.id.localeCompare(b.id));
509
+ }
510
+ export function getOAuthGrant(db, grantId, now = Date.now()) {
511
+ return listOAuthGrants(db, undefined, now).find((grant) => grant.id === grantId) ?? null;
512
+ }
513
+ /** Revoke one active grant. Pass memberId to limit the change to that member's grants. */
514
+ export function revokeOAuthGrant(db, grantId, memberId, now = Date.now()) {
515
+ return db.transaction((tx) => {
516
+ const grant = tx.select().from(mcpOauthGrants).where(eq(mcpOauthGrants.id, grantId)).get();
517
+ if (!grant || grant.revokedAt !== null || grant.expiresAt <= now)
518
+ return false;
519
+ if (memberId && grant.memberId !== memberId)
520
+ return false;
521
+ return revokeGrantInTx(tx, grant.id, now);
522
+ }, { behavior: 'immediate' });
523
+ }
524
+ /** Revoke every grant a member approved, for suspension and password changes. */
525
+ export function revokeMemberOAuthGrants(db, memberId, now = Date.now()) {
526
+ db.delete(mcpOauthRequests).where(eq(mcpOauthRequests.memberId, memberId)).run();
527
+ const grants = db
528
+ .select({ id: mcpOauthGrants.id })
529
+ .from(mcpOauthGrants)
530
+ .where(and(eq(mcpOauthGrants.memberId, memberId), isNull(mcpOauthGrants.revokedAt)))
531
+ .all();
532
+ if (!grants.length)
533
+ return 0;
534
+ const ids = grants.map((grant) => grant.id);
535
+ db.update(mcpOauthGrants).set({ revokedAt: now }).where(inArray(mcpOauthGrants.id, ids)).run();
536
+ db.delete(mcpOauthTokens).where(inArray(mcpOauthTokens.grantId, ids)).run();
537
+ db.delete(mcpOauthCodes).where(inArray(mcpOauthCodes.grantId, ids)).run();
538
+ return ids.length;
539
+ }
540
+ /** Replace the mailbox narrowing of an active grant. Existing tokens use it on their next request. */
541
+ export function updateOAuthGrantAccounts(db, grantId, accountIds, now = Date.now()) {
542
+ return (db
543
+ .update(mcpOauthGrants)
544
+ .set({ accountIds: accountIds === null ? null : JSON.stringify([...new Set(accountIds)]) })
545
+ .where(and(eq(mcpOauthGrants.id, grantId), isNull(mcpOauthGrants.revokedAt), gt(mcpOauthGrants.expiresAt, now)))
546
+ .run().changes > 0);
547
+ }
548
+ /** Count active grants per member for listings. */
549
+ export function countActiveOAuthGrants(db, memberId, now = Date.now()) {
550
+ return (db
551
+ .select({ value: count() })
552
+ .from(mcpOauthGrants)
553
+ .where(and(eq(mcpOauthGrants.memberId, memberId), isNull(mcpOauthGrants.revokedAt), gt(mcpOauthGrants.expiresAt, now)))
554
+ .get()?.value ?? 0);
555
+ }
556
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/storage/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EACL,cAAc,EACd,eAAe,EACf,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,OAAO,GAER,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAsB,MAAM,mBAAmB,CAAC;AAE1F,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACxD,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACnE,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACnD,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AACvC,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAC7C,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACjD,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE/C,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,gBAAgB,EAAE,oBAAoB,CAAU,CAAC;AA8DjF,SAAS,UAAU,CAAC,MAAc;IAChC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,CAAS;IACpC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK,KAAK,oBAAoB,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,oBAAoB,CAAC,MAAwB;IAC3D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAY,CAAC;IAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,KAAoB;IAC3C,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CAAC,GAAwC;IAC7D,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,IAAI,EAAE,GAAG,CAAC,IAAuB;QACjC,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,YAAY,EAAE,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC;QAChD,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;QACxC,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,EAAc,EAAE,GAAW;IACrD,MAAM,MAAM,GAAG,EAAE;SACd,MAAM,CAAC,EAAE,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,CAAC;SAClC,IAAI,CAAC,eAAe,CAAC;SACrB,KAAK,CACJ,GAAG,CACD,GAAG,CAAC,eAAe,CAAC,SAAS,EAAE,GAAG,GAAG,oBAAoB,CAAC,EAC1D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,EAClG,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CACvG,CACF;SACA,KAAK,CAAC,WAAW,CAAC;SAClB,GAAG,EAAE,CAAC;IACT,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC;aACvB,KAAK,CACJ,OAAO,CACL,eAAe,CAAC,EAAE,EAClB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAC5B,CACF;aACA,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,EAAc,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC9D,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;QACpB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9E,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACxE,uEAAuE;QACvE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,GAAG,CAAA,GAAG,cAAc,CAAC,SAAS,cAAc,CAAC,CAAC;aAC3F,GAAG,EAAE,CAAC;QACT,kFAAkF;QAClF,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC1E,kBAAkB,CAAC,EAA2B,EAAE,GAAG,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,EAAc,EACd,IAAY,EACZ,KAAa,EACb,QAAgB,EAChB,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,GAAG,GAAG,SAAS,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACtF,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,GAAG,QAAQ,EAAE,CAAC;YAClD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;iBACtB,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC;iBAClD,kBAAkB,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,EAAE,CAAC;iBAC9F,GAAG,EAAE,CAAC;YACT,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxC,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;aACnC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aAClC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,mBAAmB,CACjC,EAAc,EACd,KAA0F,EAC1F,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACzB,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC;QACpF,IAAI,KAAK,IAAI,iBAAiB;YAAE,OAAO,IAAI,CAAC;QAC5C,MAAM,GAAG,GAAG;YACV,EAAE,EAAE,UAAU,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAC/C,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YAC9D,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAClD,YAAY,EAAE,IAAI;YAClB,iBAAiB,EAAE,IAAI;YACvB,SAAS,EAAE,GAAG;YACd,UAAU,EAAE,IAAI;SAC6B,CAAC;QAChD,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC7C,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAID;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,EAAc,EACd,KAAqG,EACrG,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,MAAM,GAAG;YACb,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YAC9D,qFAAqF;YACrF,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;YACxC,YAAY,EAAE,KAAK,CAAC,IAAI;YACxB,iBAAiB,EAAE,KAAK,CAAC,SAAS;SACnC,CAAC;QACF,MAAM,QAAQ,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACjG,IAAI,QAAQ,EAAE,CAAC;YACb,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACrF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC,EAAW,CAAC;QAC1F,CAAC;QACD,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC;QACpF,MAAM,OAAO,GACX,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE;YAC3G,EAAE,KAAK,IAAI,CAAC,CAAC;QACjB,IAAI,KAAK,IAAI,iBAAiB,IAAI,OAAO,IAAI,0BAA0B;YAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAW,CAAC;QAC7G,MAAM,GAAG,GAAG;YACV,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,IAAI,EAAE,mBAAmB;YACzB,GAAG,MAAM;YACT,SAAS,EAAE,GAAG;YACd,UAAU,EAAE,IAAI;SAC6B,CAAC;QAChD,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,EAAW,CAAC;IACnE,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAc,EAAE,EAAU;IACvD,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACtF,OAAO,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAc,EAAE,IAAa;IAC7D,OAAO,CACL,EAAE;SACC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;SAC1B,IAAI,CAAC,eAAe,CAAC;SACrB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;SAChE,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAyC;IAC/D,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,MAAM,EAAE,oBAAoB,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1D,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,SAAS,EAAE,GAAG,CAAC,SAAS;KACzB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,+BAA+B,CAC7C,EAAc,EACd,KAMC,EACD,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG;QACV,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI;QAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1D,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC;QAC1B,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG,GAAG,oBAAoB;KACS,CAAC;IACjD,EAAE,CAAC,WAAW,CACZ,CAAC,EAAE,EAAE,EAAE;QACL,sEAAsE;QACtE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9C,eAAe,CAAC,EAA2B,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;AAChD,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,4BAA4B,CAC1C,EAAc,EACd,EAAU,EACV,IAAY,EACZ,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,GAAG,GAAG,EAAE;SACX,MAAM,EAAE;SACR,IAAI,CAAC,gBAAgB,CAAC;SACtB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;SAC5E,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACnG,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,+BAA+B,CAC7C,EAAc,EACd,EAAU,EACV,QAAgB,EAChB,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,EAAE;SACf,MAAM,CAAC,gBAAgB,CAAC;SACxB,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;SAC7C,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;SAC5E,GAAG,EAAE,CAAC;IACT,OAAO,OAAO,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,EAAc,EAAE,EAAU;IACxE,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gCAAgC,CAC9C,EAAc,EACd,KAKC,EACD,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,IAAI,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IACtD,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,GAAG,GAAG,EAAE;aACX,MAAM,EAAE;aACR,IAAI,CAAC,gBAAgB,CAAC;aACtB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,SAAS,CAAC,EACxC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,EAC7C,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CACpC,CACF;aACA,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAS,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAChC,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACzE,MAAM,OAAO,GAAG,SAAS,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC;YACN,EAAE,EAAE,OAAO;YACX,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YAC9B,UAAU,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;YAC7F,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,kBAAkB;YACnC,UAAU,EAAE,IAAI;YAChB,SAAS,EAAE,IAAI;SAChB,CAAC;aACD,GAAG,EAAE,CAAC;QACT,wEAAwE;QACxE,mDAAmD;QACnD,MAAM,WAAW,GAAG,oBAAoB,CAAC,CAAC,GAAG,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;QAC5E,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC;aACrB,MAAM,CAAC;YACN,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC;YAC1B,OAAO;YACP,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YACnC,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG,GAAG,iBAAiB;YAClC,UAAU,EAAE,IAAI;SACjB,CAAC;aACD,GAAG,EAAE,CAAC;QACT,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACtG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;IAC3E,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB,EAAE,SAAiB;IACtD,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACxF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,OAAO,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAChF,CAAC;AAID,SAAS,WAAW,CAAC,EAAM,EAAE,OAAe,EAAE,GAAW;IACvD,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC3F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAC9E,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACrF,OAAO,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,SAAS,eAAe,CAAC,EAAM,EAAE,OAAe,EAAE,GAAW;IAC3D,MAAM,OAAO,GAAG,EAAE;SACf,MAAM,CAAC,cAAc,CAAC;SACtB,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;SACvB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;SAC5E,GAAG,EAAE,CAAC;IACT,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC3E,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACzE,OAAO,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,WAAW,CAClB,EAAM,EACN,KAAyC,EACzC,MAA6B,EAC7B,GAAW;IAEX,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAC7D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,yBAAyB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACnF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1C,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;SACtB,MAAM,CAAC;QACN,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC;QAClC,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,UAAU;QAClB,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,eAAe;QAC1B,SAAS,EAAE,IAAI;KAChB,CAAC;SACD,GAAG,EAAE,CAAC;IACT,IAAI,YAAgC,CAAC;IACrC,IAAI,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC1C,YAAY,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACxD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,MAAM,CAAC;YACN,SAAS,EAAE,UAAU,CAAC,YAAY,CAAC;YACnC,OAAO,EAAE,KAAK,CAAC,EAAE;YACjB,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,UAAU;YAClB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,0BAA0B,EAAE,KAAK,CAAC,SAAS,CAAC;YACtE,SAAS,EAAE,IAAI;SAChB,CAAC;aACD,GAAG,EAAE,CAAC;IACX,CAAC;IACD,OAAO;QACL,WAAW;QACX,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,eAAe,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QAClE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,aAAa,GAAG,CAAC,WAAmB,EAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC,CAAC;AAEtH,+EAA+E;AAC/E,MAAM,UAAU,8BAA8B,CAC5C,EAAc,EACd,KAAoF,EACpF,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,GAAG,GAAG,EAAE;aACX,MAAM,EAAE;aACR,IAAI,CAAC,aAAa,CAAC;aACnB,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;aACzD,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,GAAG;YAAE,OAAO,aAAa,CAAC,oCAAoC,CAAC,CAAC;QACrE,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;YAAE,OAAO,aAAa,CAAC,oCAAoC,CAAC,CAAC;QAC5G,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC5B,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACnC,OAAO,aAAa,CAAC,0CAA0C,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG;YAAE,OAAO,aAAa,CAAC,qCAAqC,CAAC,CAAC;QACtF,IAAI,GAAG,CAAC,WAAW,KAAK,KAAK,CAAC,WAAW;YAAE,OAAO,aAAa,CAAC,gDAAgD,CAAC,CAAC;QAClH,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,aAAa,CAAC;YAAE,OAAO,aAAa,CAAC,2BAA2B,CAAC,CAAC;QAC3G,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,aAAa,CAAC,wCAAwC,CAAC,CAAC;QAC5E,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACxG,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,oBAAoB,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC;SAChF,CAAC;IACb,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,EAAc,EACd,KAA6E,EAC7E,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,GAAG,GAAG,EAAE;aACX,MAAM,EAAE;aACR,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;aAC5G,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,GAAG;YAAE,OAAO,aAAa,CAAC,+BAA+B,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;YAAE,OAAO,aAAa,CAAC,+BAA+B,CAAC,CAAC;QACvG,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC3B,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACnC,OAAO,aAAa,CAAC,qCAAqC,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG;YAAE,OAAO,aAAa,CAAC,gCAAgC,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,aAAa,CAAC,wCAAwC,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QACnE,IAAI,MAAM,GAAG,OAAO,CAAC;QACrB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,OAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC1E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,8BAA8B,EAAW,CAAC;YACrG,CAAC;YACD,MAAM,GAAG,oBAAoB,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,kCAAkC,EAAW,CAAC;QACzG,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC3G,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAW,CAAC;IAC7E,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAc,EAAE,KAA0C,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC3G,EAAE,CAAC,WAAW,CACZ,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,GAAG,GAAG,EAAE;aACX,MAAM,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE,CAAC;aAC9E,IAAI,CAAC,cAAc,CAAC;aACpB,SAAS,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;aACxE,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;aAC5D,GAAG,EAAE,CAAC;QACT,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;YAAE,eAAe,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACpF,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,4BAA4B,CAC1C,EAAc,EACd,KAAa,EACb,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,MAAM,GAAG,GAAG,EAAE;SACX,MAAM,CAAC;QACN,WAAW,EAAE,cAAc,CAAC,MAAM;QAClC,cAAc,EAAE,cAAc,CAAC,SAAS;QACxC,OAAO,EAAE,cAAc,CAAC,EAAE;QAC1B,QAAQ,EAAE,cAAc,CAAC,QAAQ;QACjC,QAAQ,EAAE,cAAc,CAAC,QAAQ;QACjC,WAAW,EAAE,cAAc,CAAC,MAAM;QAClC,UAAU,EAAE,cAAc,CAAC,UAAU;QACrC,cAAc,EAAE,cAAc,CAAC,SAAS;QACxC,SAAS,EAAE,cAAc,CAAC,SAAS;QACnC,UAAU,EAAE,cAAc,CAAC,UAAU;QACrC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC;SACD,IAAI,CAAC,cAAc,CAAC;SACpB,SAAS,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;SACxE,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;SAC3D,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;SAC9F,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1G,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,YAAY,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QACrG,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAChC,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,IAAI,uBAAuB,EAAE,CAAC;YAC/E,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACrG,CAAC;QACD,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAkB;YAC5B,MAAM;YACN,UAAU;SACX,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,EAAc,EAAE,QAAiB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACjF,OAAO,EAAE;SACN,MAAM,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,CAAC,IAAI,EAAE,CAAC;SACrG,IAAI,CAAC,cAAc,CAAC;SACpB,SAAS,CAAC,eAAe,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;SAC3E,KAAK,CACJ,GAAG,CACD,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,EAChC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,EACjC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAC7D,CACF;SACA,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3C,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU;QACV,UAAU,EAAE,UAA6B;QACzC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,YAAY,CAAC,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACpD,UAAU,EAAE,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC;QAC7C,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC,CAAC;SACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAc,EAAE,OAAe,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC7E,OAAO,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,IAAI,CAAC;AAC3F,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,gBAAgB,CAAC,EAAc,EAAE,OAAe,EAAE,QAAiB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACnG,OAAO,EAAE,CAAC,WAAW,CACnB,CAAC,EAAE,EAAE,EAAE;QACL,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC3F,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG;YAAE,OAAO,KAAK,CAAC;QAC/E,IAAI,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC1D,OAAO,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC,EACD,EAAE,QAAQ,EAAE,WAAW,EAAE,CAC1B,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,uBAAuB,CAAC,EAAmB,EAAE,QAAgB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC7F,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACjF,MAAM,MAAM,GAAG,EAAE;SACd,MAAM,CAAC,EAAE,EAAE,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC;SACjC,IAAI,CAAC,cAAc,CAAC;SACpB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;SACnF,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5C,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC/F,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC5E,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1E,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,wBAAwB,CACtC,EAAc,EACd,OAAe,EACf,UAAoC,EACpC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,OAAO,CACL,EAAE;SACC,MAAM,CAAC,cAAc,CAAC;SACtB,GAAG,CAAC,EAAE,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1F,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;SAC/G,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CACrB,CAAC;AACJ,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,sBAAsB,CAAC,EAAc,EAAE,QAAgB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IACvF,OAAO,CACL,EAAE;SACC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;SAC1B,IAAI,CAAC,cAAc,CAAC;SACpB,KAAK,CACJ,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAChH;SACA,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,CACrB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxmail",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "mcpName": "io.github.fluxmailai/fluxmail",
5
5
  "description": "Self-hosted email API with MCP and REST support for Gmail, Outlook, and IMAP/SMTP",
6
6
  "keywords": [
@@ -66,7 +66,8 @@
66
66
  "dependencies": {
67
67
  "@hono/node-server": "^1.14.3",
68
68
  "@hono/zod-openapi": "0.19.10",
69
- "@modelcontextprotocol/sdk": "^1.13.0",
69
+ "@modelcontextprotocol/core": "2.4.0",
70
+ "@modelcontextprotocol/server": "2.4.0",
70
71
  "@node-rs/argon2": "2.0.2",
71
72
  "better-sqlite3": "^13.0.3",
72
73
  "commander": "^13.1.0",
@@ -80,12 +81,14 @@
80
81
  "update-notifier": "7.3.1",
81
82
  "zod": "^3.25.67",
82
83
  "zod-to-json-schema": "3.25.2",
83
- "@fluxmail/core": "0.16.0",
84
- "@fluxmail/provider-gmail": "0.16.0",
85
- "@fluxmail/provider-imap": "0.16.0",
86
- "@fluxmail/provider-outlook": "0.16.0"
84
+ "@fluxmail/core": "0.17.0",
85
+ "@fluxmail/provider-gmail": "0.17.0",
86
+ "@fluxmail/provider-imap": "0.17.0",
87
+ "@fluxmail/provider-outlook": "0.17.0"
87
88
  },
88
89
  "devDependencies": {
90
+ "@modelcontextprotocol/client": "2.4.0",
91
+ "@modelcontextprotocol/node": "2.1.2",
89
92
  "@types/better-sqlite3": "^7.6.13",
90
93
  "@types/mime-types": "^3.0.1",
91
94
  "@types/node": "^22.15.0",