fluxmail 0.4.1 → 0.6.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 (147) hide show
  1. package/README.md +6 -4
  2. package/dist/accounts/defaultGoogleOAuth.d.ts +4 -0
  3. package/dist/accounts/defaultGoogleOAuth.d.ts.map +1 -0
  4. package/dist/accounts/defaultGoogleOAuth.js +7 -0
  5. package/dist/accounts/defaultGoogleOAuth.js.map +1 -0
  6. package/dist/accounts/gmailConnection.js +2 -2
  7. package/dist/accounts/gmailConnection.js.map +1 -1
  8. package/dist/accounts/googleAuth.d.ts +16 -9
  9. package/dist/accounts/googleAuth.d.ts.map +1 -1
  10. package/dist/accounts/googleAuth.js +52 -20
  11. package/dist/accounts/googleAuth.js.map +1 -1
  12. package/dist/accounts/microsoftAuth.d.ts +5 -2
  13. package/dist/accounts/microsoftAuth.d.ts.map +1 -1
  14. package/dist/accounts/microsoftAuth.js +25 -22
  15. package/dist/accounts/microsoftAuth.js.map +1 -1
  16. package/dist/accounts/registry.d.ts +11 -9
  17. package/dist/accounts/registry.d.ts.map +1 -1
  18. package/dist/accounts/registry.js +169 -98
  19. package/dist/accounts/registry.js.map +1 -1
  20. package/dist/auth.d.ts +106 -0
  21. package/dist/auth.d.ts.map +1 -0
  22. package/dist/auth.js +455 -0
  23. package/dist/auth.js.map +1 -0
  24. package/dist/authorization.d.ts +9 -0
  25. package/dist/authorization.d.ts.map +1 -0
  26. package/dist/authorization.js +23 -0
  27. package/dist/authorization.js.map +1 -0
  28. package/dist/cli.d.ts +15 -1
  29. package/dist/cli.d.ts.map +1 -1
  30. package/dist/cli.js +1096 -403
  31. package/dist/cli.js.map +1 -1
  32. package/dist/cliInstances.d.ts +51 -0
  33. package/dist/cliInstances.d.ts.map +1 -0
  34. package/dist/cliInstances.js +237 -0
  35. package/dist/cliInstances.js.map +1 -0
  36. package/dist/cliMail.d.ts +9 -0
  37. package/dist/cliMail.d.ts.map +1 -0
  38. package/dist/cliMail.js +450 -0
  39. package/dist/cliMail.js.map +1 -0
  40. package/dist/config.d.ts +95 -118
  41. package/dist/config.d.ts.map +1 -1
  42. package/dist/config.js +351 -286
  43. package/dist/config.js.map +1 -1
  44. package/dist/configMigration.d.ts +8 -0
  45. package/dist/configMigration.d.ts.map +1 -0
  46. package/dist/configMigration.js +234 -0
  47. package/dist/configMigration.js.map +1 -0
  48. package/dist/context.d.ts +8 -2
  49. package/dist/context.d.ts.map +1 -1
  50. package/dist/context.js +29 -8
  51. package/dist/context.js.map +1 -1
  52. package/dist/deploymentConfig.d.ts +190 -0
  53. package/dist/deploymentConfig.d.ts.map +1 -0
  54. package/dist/deploymentConfig.js +539 -0
  55. package/dist/deploymentConfig.js.map +1 -0
  56. package/dist/http/admin.d.ts +75 -3
  57. package/dist/http/admin.d.ts.map +1 -1
  58. package/dist/http/admin.js +347 -79
  59. package/dist/http/admin.js.map +1 -1
  60. package/dist/http/app.d.ts +4 -1
  61. package/dist/http/app.d.ts.map +1 -1
  62. package/dist/http/app.js +119 -63
  63. package/dist/http/app.js.map +1 -1
  64. package/dist/http/identity.d.ts +114 -0
  65. package/dist/http/identity.d.ts.map +1 -0
  66. package/dist/http/identity.js +936 -0
  67. package/dist/http/identity.js.map +1 -0
  68. package/dist/http/operationRoutes.d.ts +8 -0
  69. package/dist/http/operationRoutes.d.ts.map +1 -0
  70. package/dist/http/operationRoutes.js +13 -0
  71. package/dist/http/operationRoutes.js.map +1 -0
  72. package/dist/http/rest.d.ts +16 -4
  73. package/dist/http/rest.d.ts.map +1 -1
  74. package/dist/http/rest.js +213 -71
  75. package/dist/http/rest.js.map +1 -1
  76. package/dist/index.d.ts +5 -3
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +5 -3
  79. package/dist/index.js.map +1 -1
  80. package/dist/instanceConfig.d.ts +36 -0
  81. package/dist/instanceConfig.d.ts.map +1 -0
  82. package/dist/instanceConfig.js +157 -0
  83. package/dist/instanceConfig.js.map +1 -0
  84. package/dist/licensing/activation.d.ts +2 -1
  85. package/dist/licensing/activation.d.ts.map +1 -1
  86. package/dist/licensing/activation.js +2 -3
  87. package/dist/licensing/activation.js.map +1 -1
  88. package/dist/licensing/entitlements.d.ts.map +1 -1
  89. package/dist/licensing/entitlements.js +2 -2
  90. package/dist/licensing/entitlements.js.map +1 -1
  91. package/dist/licensing/refresher.d.ts +6 -1
  92. package/dist/licensing/refresher.d.ts.map +1 -1
  93. package/dist/licensing/refresher.js +18 -7
  94. package/dist/licensing/refresher.js.map +1 -1
  95. package/dist/logging.d.ts +87 -0
  96. package/dist/logging.d.ts.map +1 -0
  97. package/dist/logging.js +612 -0
  98. package/dist/logging.js.map +1 -0
  99. package/dist/mcp/buildServer.d.ts +3 -1
  100. package/dist/mcp/buildServer.d.ts.map +1 -1
  101. package/dist/mcp/buildServer.js +27 -24
  102. package/dist/mcp/buildServer.js.map +1 -1
  103. package/dist/permissions.d.ts +1 -1
  104. package/dist/permissions.d.ts.map +1 -1
  105. package/dist/permissions.js +10 -4
  106. package/dist/permissions.js.map +1 -1
  107. package/dist/scheduler/sendScheduler.d.ts +4 -3
  108. package/dist/scheduler/sendScheduler.d.ts.map +1 -1
  109. package/dist/scheduler/sendScheduler.js +15 -3
  110. package/dist/scheduler/sendScheduler.js.map +1 -1
  111. package/dist/service/emailService.d.ts +10 -17
  112. package/dist/service/emailService.d.ts.map +1 -1
  113. package/dist/service/emailService.js +28 -38
  114. package/dist/service/emailService.js.map +1 -1
  115. package/dist/storage/adminAudit.d.ts +15 -2
  116. package/dist/storage/adminAudit.d.ts.map +1 -1
  117. package/dist/storage/adminAudit.js +22 -27
  118. package/dist/storage/adminAudit.js.map +1 -1
  119. package/dist/storage/apiKeys.d.ts +8 -8
  120. package/dist/storage/apiKeys.d.ts.map +1 -1
  121. package/dist/storage/apiKeys.js +16 -11
  122. package/dist/storage/apiKeys.js.map +1 -1
  123. package/dist/storage/db.d.ts +596 -31
  124. package/dist/storage/db.d.ts.map +1 -1
  125. package/dist/storage/db.js +383 -45
  126. package/dist/storage/db.js.map +1 -1
  127. package/dist/storage/fileLock.d.ts +7 -0
  128. package/dist/storage/fileLock.d.ts.map +1 -0
  129. package/dist/storage/fileLock.js +183 -0
  130. package/dist/storage/fileLock.js.map +1 -0
  131. package/dist/storage/gmailConnectionGrants.d.ts +3 -4
  132. package/dist/storage/gmailConnectionGrants.d.ts.map +1 -1
  133. package/dist/storage/gmailConnectionGrants.js +6 -6
  134. package/dist/storage/gmailConnectionGrants.js.map +1 -1
  135. package/dist/storage/members.d.ts +11 -0
  136. package/dist/storage/members.d.ts.map +1 -1
  137. package/dist/storage/members.js +70 -6
  138. package/dist/storage/members.js.map +1 -1
  139. package/dist/telemetry.d.ts +17 -2
  140. package/dist/telemetry.d.ts.map +1 -1
  141. package/dist/telemetry.js +34 -19
  142. package/dist/telemetry.js.map +1 -1
  143. package/dist/updateNotifier.d.ts +18 -0
  144. package/dist/updateNotifier.d.ts.map +1 -0
  145. package/dist/updateNotifier.js +128 -0
  146. package/dist/updateNotifier.js.map +1 -0
  147. package/package.json +38 -5
package/dist/auth.js ADDED
@@ -0,0 +1,455 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { hostname } from 'node:os';
3
+ import { hash, verify } from '@node-rs/argon2';
4
+ import { and, eq, gt, isNull, lte, sql } from 'drizzle-orm';
5
+ import { EmailError } from '@fluxmail/core';
6
+ import { accounts, apiKeys, authRateLimits, instanceSettings, memberAuthTokens, memberCredentials, memberSessions, members, } from './storage/db.js';
7
+ import { authenticateApiKey } from './storage/apiKeys.js';
8
+ import { addMember, findMember, getMember } from './storage/members.js';
9
+ import { FULL_PERMISSION_POLICY } from './permissions.js';
10
+ import { assertMemberLimit, getEntitlements } from './licensing/entitlements.js';
11
+ const SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1000;
12
+ const ENROLLMENT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
13
+ const PASSWORD_RESET_TTL_MS = 60 * 60 * 1000;
14
+ const RATE_WINDOW_MS = 15 * 60 * 1000;
15
+ const SESSION_TOUCH_INTERVAL_MS = 60 * 60 * 1000;
16
+ const COMMON_PASSWORDS = new Set([
17
+ '12345678',
18
+ '123456789012345',
19
+ 'correcthorsebatterystaple',
20
+ 'letmeinletmeinletmein',
21
+ 'password',
22
+ 'passwordpassword',
23
+ 'qwertyuiop',
24
+ 'qwertyqwertyqwerty',
25
+ ]);
26
+ const ARGON_OPTIONS = {
27
+ algorithm: 2,
28
+ memoryCost: 19_456,
29
+ timeCost: 2,
30
+ parallelism: 1,
31
+ outputLen: 32,
32
+ };
33
+ const dummyPasswordHash = hash('fluxmail-invalid-login-padding', ARGON_OPTIONS);
34
+ function secretHash(secret) {
35
+ return createHash('sha256').update(secret).digest('hex');
36
+ }
37
+ function normalizedEmail(email) {
38
+ const normalized = email.trim().toLowerCase();
39
+ if (normalized.length > 320 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(normalized)) {
40
+ throw new EmailError('invalid_request', 'Enter a valid member email address.');
41
+ }
42
+ return normalized;
43
+ }
44
+ function rateKey(kind, value) {
45
+ return `${kind}:${secretHash(value.trim().toLowerCase())}`;
46
+ }
47
+ function reserveLoginAttempt(db, emailKey, ipKey, now) {
48
+ return db.transaction((tx) => {
49
+ tx.delete(authRateLimits)
50
+ .where(lte(authRateLimits.windowStartedAt, now - RATE_WINDOW_MS))
51
+ .run();
52
+ const emailRow = tx.select().from(authRateLimits).where(eq(authRateLimits.key, emailKey)).get();
53
+ const ipRow = tx.select().from(authRateLimits).where(eq(authRateLimits.key, ipKey)).get();
54
+ if ((emailRow?.attempts ?? 0) >= 5 || (ipRow?.attempts ?? 0) >= 30)
55
+ return null;
56
+ const reserve = (key, row) => {
57
+ if (!row) {
58
+ tx.insert(authRateLimits).values({ key, attempts: 1, windowStartedAt: now }).run();
59
+ return now;
60
+ }
61
+ tx.update(authRateLimits)
62
+ .set({ attempts: row.attempts + 1 })
63
+ .where(eq(authRateLimits.key, key))
64
+ .run();
65
+ return row.windowStartedAt;
66
+ };
67
+ reserve(emailKey, emailRow);
68
+ return { ipWindowStartedAt: reserve(ipKey, ipRow) };
69
+ });
70
+ }
71
+ function releaseLoginAttempt(db, key, windowStartedAt) {
72
+ db.transaction((tx) => {
73
+ const row = tx
74
+ .select()
75
+ .from(authRateLimits)
76
+ .where(and(eq(authRateLimits.key, key), eq(authRateLimits.windowStartedAt, windowStartedAt)))
77
+ .get();
78
+ if (!row)
79
+ return;
80
+ if (row.attempts <= 1) {
81
+ tx.delete(authRateLimits).where(eq(authRateLimits.key, key)).run();
82
+ return;
83
+ }
84
+ tx.update(authRateLimits)
85
+ .set({ attempts: row.attempts - 1 })
86
+ .where(and(eq(authRateLimits.key, key), eq(authRateLimits.windowStartedAt, windowStartedAt)))
87
+ .run();
88
+ });
89
+ }
90
+ export function normalizeAndValidatePassword(password, member) {
91
+ const normalized = password.normalize('NFC');
92
+ const length = [...normalized].length;
93
+ if (length < 8 || length > 256) {
94
+ throw new EmailError('invalid_request', 'Password must contain between 8 and 256 characters.');
95
+ }
96
+ const lower = normalized.toLowerCase();
97
+ const context = [member?.name, member?.email, member?.email?.split('@')[0], 'fluxmail']
98
+ .filter((value) => Boolean(value && value.length >= 3))
99
+ .map((value) => value.toLowerCase());
100
+ if (COMMON_PASSWORDS.has(lower.trim()) || context.some((value) => lower.includes(value))) {
101
+ throw new EmailError('invalid_request', 'Choose a password that is not common or based on your member details.');
102
+ }
103
+ return normalized;
104
+ }
105
+ export async function hashPassword(password, member) {
106
+ return hash(normalizeAndValidatePassword(password, member), ARGON_OPTIONS);
107
+ }
108
+ async function passwordMatches(passwordHash, password) {
109
+ try {
110
+ return await verify(passwordHash, password.normalize('NFC'));
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ }
116
+ export function isBootstrapComplete(db) {
117
+ return db.select().from(instanceSettings).where(eq(instanceSettings.key, 'bootstrap_complete')).get()?.value === '1';
118
+ }
119
+ function markBootstrapComplete(db) {
120
+ db.insert(instanceSettings)
121
+ .values({ key: 'bootstrap_complete', value: '1' })
122
+ .onConflictDoUpdate({ target: instanceSettings.key, set: { value: '1' } })
123
+ .run();
124
+ }
125
+ async function replacePassword(db, member, password) {
126
+ const passwordHash = await hashPassword(password, member);
127
+ storePasswordHash(db, member.id, passwordHash);
128
+ }
129
+ function storePasswordHash(db, memberId, passwordHash) {
130
+ const current = db.select().from(memberCredentials).where(eq(memberCredentials.memberId, memberId)).get();
131
+ db.insert(memberCredentials)
132
+ .values({
133
+ memberId,
134
+ passwordHash,
135
+ passwordVersion: (current?.passwordVersion ?? 0) + 1,
136
+ updatedAt: Date.now(),
137
+ })
138
+ .onConflictDoUpdate({
139
+ target: memberCredentials.memberId,
140
+ set: {
141
+ passwordHash,
142
+ passwordVersion: (current?.passwordVersion ?? 0) + 1,
143
+ updatedAt: Date.now(),
144
+ },
145
+ })
146
+ .run();
147
+ }
148
+ export async function setupInitialAdmin(db, input) {
149
+ if (isBootstrapComplete(db))
150
+ throw new EmailError('invalid_request', 'This instance has already been set up.');
151
+ const existing = db.select().from(members).all();
152
+ let member;
153
+ if (existing.length === 0) {
154
+ if (!input.name?.trim())
155
+ throw new EmailError('invalid_request', 'Administrator name is required.');
156
+ const email = normalizedEmail(input.email);
157
+ const passwordHash = await hashPassword(input.password, {
158
+ name: input.name.trim(),
159
+ email,
160
+ });
161
+ member = addMember(db, {
162
+ name: input.name,
163
+ email,
164
+ role: 'admin',
165
+ status: 'pending',
166
+ completeBootstrap: false,
167
+ });
168
+ storePasswordHash(db, member.id, passwordHash);
169
+ }
170
+ else {
171
+ if (!input.existingAdmin) {
172
+ const candidates = existing
173
+ .filter((candidate) => candidate.role === 'admin')
174
+ .map((candidate) => `${candidate.id} (${candidate.name}${candidate.email ? `, ${candidate.email}` : ''})`)
175
+ .join(', ');
176
+ throw new EmailError('invalid_request', `Choose an existing administrator with --existing-admin. Available: ${candidates || 'none'}.`);
177
+ }
178
+ member = findMember(db, input.existingAdmin);
179
+ if (member.role !== 'admin')
180
+ throw new EmailError('permission_denied', 'The claimed member must be an administrator.');
181
+ const email = normalizedEmail(input.email);
182
+ const passwordHash = await hashPassword(input.password, { ...member, email });
183
+ db.update(members).set({ email, status: 'pending' }).where(eq(members.id, member.id)).run();
184
+ storePasswordHash(db, member.id, passwordHash);
185
+ db.update(accounts).set({ ownerMemberId: member.id }).where(isNull(accounts.ownerMemberId)).run();
186
+ member = getMember(db, member.id);
187
+ }
188
+ db.update(members).set({ status: 'active' }).where(eq(members.id, member.id)).run();
189
+ member = getMember(db, member.id);
190
+ markBootstrapComplete(db);
191
+ return { member, session: issueSession(db, member.id, input.deviceName ?? `CLI on ${hostname()}`) };
192
+ }
193
+ export function issueMemberAuthToken(db, input) {
194
+ const member = getMember(db, input.memberId);
195
+ if (member.status === 'suspended')
196
+ throw new EmailError('permission_denied', 'Suspended members cannot enroll or reset passwords.');
197
+ if (input.kind === 'enrollment') {
198
+ if (member.status !== 'pending') {
199
+ throw new EmailError('invalid_request', 'Enrollment codes can only be issued to pending members.');
200
+ }
201
+ if (!member.email) {
202
+ throw new EmailError('invalid_request', 'Set the member email before issuing an enrollment code.');
203
+ }
204
+ }
205
+ else if (member.status !== 'active') {
206
+ throw new EmailError('invalid_request', 'Password resets can only be issued to active members.');
207
+ }
208
+ const now = Date.now();
209
+ const expiresAt = now + (input.kind === 'enrollment' ? ENROLLMENT_TTL_MS : PASSWORD_RESET_TTL_MS);
210
+ const token = `fmt_${randomBytes(32).toString('hex')}`;
211
+ db.transaction((tx) => {
212
+ tx.delete(memberAuthTokens)
213
+ .where(and(eq(memberAuthTokens.memberId, member.id), eq(memberAuthTokens.kind, input.kind)))
214
+ .run();
215
+ tx.insert(memberAuthTokens)
216
+ .values({
217
+ id: `token_${randomBytes(8).toString('hex')}`,
218
+ memberId: member.id,
219
+ kind: input.kind,
220
+ tokenHash: secretHash(token),
221
+ createdByMemberId: input.createdByMemberId ?? null,
222
+ createdAt: now,
223
+ expiresAt,
224
+ })
225
+ .run();
226
+ });
227
+ return { token, expiresAt };
228
+ }
229
+ async function consumeMemberAuthToken(db, input) {
230
+ const now = Date.now();
231
+ const row = db
232
+ .select()
233
+ .from(memberAuthTokens)
234
+ .where(and(eq(memberAuthTokens.tokenHash, secretHash(input.token)), eq(memberAuthTokens.kind, input.kind), isNull(memberAuthTokens.usedAt), gt(memberAuthTokens.expiresAt, now)))
235
+ .get();
236
+ if (!row)
237
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
238
+ let member = getMember(db, row.memberId);
239
+ if (member.status === 'suspended')
240
+ throw new EmailError('permission_denied', 'This member is suspended.');
241
+ if (input.kind === 'enrollment' && member.status !== 'pending') {
242
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
243
+ }
244
+ if (input.kind === 'password_reset' && member.status !== 'active') {
245
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
246
+ }
247
+ if (input.kind === 'enrollment') {
248
+ assertMemberLimit(Math.max(db.select().from(members).all().length - 1, 0), getEntitlements(db));
249
+ }
250
+ const passwordHash = await hashPassword(input.password, member);
251
+ const claimedAt = Date.now();
252
+ db.transaction((tx) => {
253
+ const claimed = tx
254
+ .update(memberAuthTokens)
255
+ .set({ usedAt: claimedAt })
256
+ .where(and(eq(memberAuthTokens.id, row.id), isNull(memberAuthTokens.usedAt), gt(memberAuthTokens.expiresAt, claimedAt)))
257
+ .run();
258
+ if (claimed.changes !== 1) {
259
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
260
+ }
261
+ const credential = tx.select().from(memberCredentials).where(eq(memberCredentials.memberId, member.id)).get();
262
+ tx.insert(memberCredentials)
263
+ .values({
264
+ memberId: member.id,
265
+ passwordHash,
266
+ passwordVersion: (credential?.passwordVersion ?? 0) + 1,
267
+ updatedAt: claimedAt,
268
+ })
269
+ .onConflictDoUpdate({
270
+ target: memberCredentials.memberId,
271
+ set: {
272
+ passwordHash,
273
+ passwordVersion: (credential?.passwordVersion ?? 0) + 1,
274
+ updatedAt: claimedAt,
275
+ },
276
+ })
277
+ .run();
278
+ tx.update(memberSessions)
279
+ .set({ revokedAt: claimedAt })
280
+ .where(and(eq(memberSessions.memberId, member.id), isNull(memberSessions.revokedAt)))
281
+ .run();
282
+ if (input.kind === 'enrollment') {
283
+ tx.update(members).set({ status: 'active' }).where(eq(members.id, member.id)).run();
284
+ }
285
+ });
286
+ member = getMember(db, member.id);
287
+ return { member, session: issueSession(db, member.id, input.deviceName) };
288
+ }
289
+ export function enrollMember(db, input) {
290
+ return consumeMemberAuthToken(db, { ...input, kind: 'enrollment' });
291
+ }
292
+ export function resetPassword(db, input) {
293
+ return consumeMemberAuthToken(db, { ...input, kind: 'password_reset' });
294
+ }
295
+ export function issueSession(db, memberId, deviceName) {
296
+ const member = getMember(db, memberId);
297
+ if (member.status !== 'active')
298
+ throw new EmailError('permission_denied', 'This member is not active.');
299
+ const now = Date.now();
300
+ const id = `session_${randomBytes(8).toString('hex')}`;
301
+ const token = `fms_${randomBytes(32).toString('hex')}`;
302
+ const info = {
303
+ id,
304
+ memberId,
305
+ deviceName: deviceName.trim() || 'Unknown device',
306
+ createdAt: now,
307
+ expiresAt: now + SESSION_TTL_MS,
308
+ lastUsedAt: now,
309
+ current: true,
310
+ };
311
+ db.insert(memberSessions)
312
+ .values({
313
+ id: info.id,
314
+ memberId: info.memberId,
315
+ deviceName: info.deviceName,
316
+ createdAt: info.createdAt,
317
+ expiresAt: info.expiresAt,
318
+ lastUsedAt: info.lastUsedAt,
319
+ tokenHash: secretHash(token),
320
+ revokedAt: null,
321
+ })
322
+ .run();
323
+ return { token, info };
324
+ }
325
+ export async function loginWithPassword(db, input) {
326
+ if (!isBootstrapComplete(db))
327
+ throw new EmailError('permission_denied', 'This instance has not finished setup.');
328
+ const email = normalizedEmail(input.email);
329
+ const now = Date.now();
330
+ const emailKey = rateKey('email', email);
331
+ const ipKey = rateKey('ip', input.ipAddress || 'unknown');
332
+ const reservation = reserveLoginAttempt(db, emailKey, ipKey, now);
333
+ if (!reservation) {
334
+ throw new EmailError('rate_limited', 'Too many login attempts. Try again later.');
335
+ }
336
+ const memberRow = db
337
+ .select()
338
+ .from(members)
339
+ .where(sql `lower(${members.email}) = ${email}`)
340
+ .get();
341
+ const credential = memberRow
342
+ ? db.select().from(memberCredentials).where(eq(memberCredentials.memberId, memberRow.id)).get()
343
+ : undefined;
344
+ const matches = await passwordMatches(credential?.passwordHash ?? (await dummyPasswordHash), input.password);
345
+ if (!memberRow || !credential || !matches || memberRow.status !== 'active') {
346
+ throw new EmailError('permission_denied', 'Email or password is incorrect.');
347
+ }
348
+ db.delete(authRateLimits).where(eq(authRateLimits.key, emailKey)).run();
349
+ releaseLoginAttempt(db, ipKey, reservation.ipWindowStartedAt);
350
+ const member = getMember(db, memberRow.id);
351
+ return { member, session: issueSession(db, member.id, input.deviceName) };
352
+ }
353
+ export function authenticateBearer(db, token) {
354
+ if (token.startsWith('fmk_')) {
355
+ const auth = authenticateApiKey(db, token);
356
+ if (!auth)
357
+ return null;
358
+ return {
359
+ kind: 'api_key',
360
+ principalId: auth.keyId,
361
+ keyId: auth.keyId,
362
+ memberId: auth.memberId,
363
+ role: auth.role,
364
+ permissions: auth.permissions,
365
+ accountIds: auth.accountIds,
366
+ };
367
+ }
368
+ if (!token.startsWith('fms_'))
369
+ return null;
370
+ const now = Date.now();
371
+ const row = db
372
+ .select()
373
+ .from(memberSessions)
374
+ .where(eq(memberSessions.tokenHash, secretHash(token)))
375
+ .get();
376
+ if (!row || row.revokedAt !== null || row.expiresAt <= now)
377
+ return null;
378
+ const member = getMember(db, row.memberId);
379
+ if (member.status !== 'active')
380
+ return null;
381
+ if (now - row.lastUsedAt >= SESSION_TOUCH_INTERVAL_MS) {
382
+ db.update(memberSessions).set({ lastUsedAt: now }).where(eq(memberSessions.id, row.id)).run();
383
+ }
384
+ return {
385
+ kind: 'session',
386
+ principalId: row.id,
387
+ sessionId: row.id,
388
+ memberId: member.id,
389
+ role: member.role,
390
+ permissions: FULL_PERMISSION_POLICY,
391
+ accountIds: null,
392
+ };
393
+ }
394
+ export function listMemberSessions(db, memberId, currentSessionId) {
395
+ const now = Date.now();
396
+ return db
397
+ .select()
398
+ .from(memberSessions)
399
+ .where(eq(memberSessions.memberId, memberId))
400
+ .all()
401
+ .filter((row) => row.revokedAt === null && row.expiresAt > now)
402
+ .map((row) => ({
403
+ id: row.id,
404
+ memberId: row.memberId,
405
+ deviceName: row.deviceName,
406
+ createdAt: row.createdAt,
407
+ expiresAt: row.expiresAt,
408
+ lastUsedAt: row.lastUsedAt,
409
+ current: row.id === currentSessionId,
410
+ }));
411
+ }
412
+ export function revokeSession(db, memberId, sessionId) {
413
+ return (db
414
+ .update(memberSessions)
415
+ .set({ revokedAt: Date.now() })
416
+ .where(and(eq(memberSessions.id, sessionId), eq(memberSessions.memberId, memberId), isNull(memberSessions.revokedAt)))
417
+ .run().changes > 0);
418
+ }
419
+ export async function changePassword(db, input) {
420
+ const member = getMember(db, input.memberId);
421
+ const credential = db.select().from(memberCredentials).where(eq(memberCredentials.memberId, member.id)).get();
422
+ if (!credential || !(await passwordMatches(credential.passwordHash, input.currentPassword))) {
423
+ throw new EmailError('permission_denied', 'Current password is incorrect.');
424
+ }
425
+ await replacePassword(db, member, input.newPassword);
426
+ db.update(memberSessions)
427
+ .set({ revokedAt: Date.now() })
428
+ .where(and(eq(memberSessions.memberId, member.id), sql `${memberSessions.id} != ${input.keepSessionId}`, isNull(memberSessions.revokedAt)))
429
+ .run();
430
+ }
431
+ export async function recoverAdminPassword(db, ref, password) {
432
+ if (!isBootstrapComplete(db)) {
433
+ throw new EmailError('invalid_request', 'Finish instance setup before using administrator recovery.');
434
+ }
435
+ const member = findMember(db, ref);
436
+ if (member.role !== 'admin')
437
+ throw new EmailError('permission_denied', 'Break-glass recovery is limited to administrators.');
438
+ if (!member.email) {
439
+ throw new EmailError('invalid_request', 'Claim this administrator with setup before using break-glass recovery.');
440
+ }
441
+ const passwordHash = await hashPassword(password, member);
442
+ storePasswordHash(db, member.id, passwordHash);
443
+ if (member.status !== 'active')
444
+ db.update(members).set({ status: 'active' }).where(eq(members.id, member.id)).run();
445
+ db.update(memberSessions)
446
+ .set({ revokedAt: Date.now() })
447
+ .where(and(eq(memberSessions.memberId, member.id), isNull(memberSessions.revokedAt)))
448
+ .run();
449
+ markBootstrapComplete(db);
450
+ return getMember(db, member.id);
451
+ }
452
+ export function deleteAllApiKeys(db) {
453
+ return db.delete(apiKeys).run().changes;
454
+ }
455
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EACL,QAAQ,EACR,OAAO,EACP,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,OAAO,GAER,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAoC,MAAM,sBAAsB,CAAC;AAC1G,OAAO,EAAE,sBAAsB,EAAyB,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEjF,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAChD,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAClD,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC7C,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACtC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACjD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,UAAU;IACV,iBAAiB;IACjB,2BAA2B;IAC3B,uBAAuB;IACvB,UAAU;IACV,kBAAkB;IAClB,YAAY;IACZ,oBAAoB;CACrB,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG;IACpB,SAAS,EAAE,CAAC;IACZ,UAAU,EAAE,MAAM;IAClB,QAAQ,EAAE,CAAC;IACX,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,EAAE;CACL,CAAC;AAEX,MAAM,iBAAiB,GAAG,IAAI,CAAC,gCAAgC,EAAE,aAAa,CAAC,CAAC;AAoChF,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,eAAe,CAAC,KAAa;IACpC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,UAAU,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,qCAAqC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,OAAO,CAAC,IAAoB,EAAE,KAAa;IAClD,OAAO,GAAG,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;AAC7D,CAAC;AAMD,SAAS,mBAAmB,CAC1B,EAAc,EACd,QAAgB,EAChB,KAAa,EACb,GAAW;IAEX,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;QAC3B,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,eAAe,EAAE,GAAG,GAAG,cAAc,CAAC,CAAC;aAChE,GAAG,EAAE,CAAC;QACT,MAAM,QAAQ,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAChG,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC1F,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE;YAAE,OAAO,IAAI,CAAC;QAEhF,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,GAAoB,EAAU,EAAE;YAC5D,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;gBACnF,OAAO,GAAG,CAAC;YACb,CAAC;YACD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;iBACtB,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;iBACnC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;iBAClC,GAAG,EAAE,CAAC;YACT,OAAO,GAAG,CAAC,eAAe,CAAC;QAC7B,CAAC,CAAC;QACF,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC5B,OAAO,EAAE,iBAAiB,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAc,EAAE,GAAW,EAAE,eAAuB;IAC/E,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;QACpB,MAAM,GAAG,GAAG,EAAE;aACX,MAAM,EAAE;aACR,IAAI,CAAC,cAAc,CAAC;aACpB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;aAC5F,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,GAAG,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;YACtB,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACnE,OAAO;QACT,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;aACnC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;aAC5F,GAAG,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,QAAgB,EAAE,MAA2C;IACxG,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC;IACtC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,qDAAqD,CAAC,CAAC;IACjG,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC;SACpF,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;SACvE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IACvC,IAAI,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACzF,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,uEAAuE,CAAC,CAAC;IACnH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,MAA2C;IAC9F,OAAO,IAAI,CAAC,4BAA4B,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,YAAoB,EAAE,QAAgB;IACnE,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,EAAc;IAChD,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,KAAK,GAAG,CAAC;AACvH,CAAC;AAED,SAAS,qBAAqB,CAAC,EAAc;IAC3C,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC;SACxB,MAAM,CAAC,EAAE,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;SACjD,kBAAkB,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC;SACzE,GAAG,EAAE,CAAC;AACX,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,EAAc,EAAE,MAAkB,EAAE,QAAgB;IACjF,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC1D,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAc,EAAE,QAAgB,EAAE,YAAoB;IAC/E,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1G,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC;SACzB,MAAM,CAAC;QACN,QAAQ;QACR,YAAY;QACZ,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC;QACpD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;SACD,kBAAkB,CAAC;QAClB,MAAM,EAAE,iBAAiB,CAAC,QAAQ;QAClC,GAAG,EAAE;YACH,YAAY;YACZ,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC;YACpD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB;KACF,CAAC;SACD,GAAG,EAAE,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAc,EACd,KAAsG;IAEtG,IAAI,mBAAmB,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,wCAAwC,CAAC,CAAC;IAC/G,MAAM,QAAQ,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC;IACjD,IAAI,MAAkB,CAAC;IACvB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE;YAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,iCAAiC,CAAC,CAAC;QACpG,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE;YACtD,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE;YACvB,KAAK;SACN,CAAC,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE;YACrB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK;YACL,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,SAAS;YACjB,iBAAiB,EAAE,KAAK;SACzB,CAAC,CAAC;QACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,QAAQ;iBACxB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC;iBACjD,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,KAAK,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;iBACzG,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,IAAI,UAAU,CAClB,iBAAiB,EACjB,sEAAsE,UAAU,IAAI,MAAM,GAAG,CAC9F,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;YACzB,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,8CAA8C,CAAC,CAAC;QAC5F,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9E,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC5F,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAC/C,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAClG,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACpF,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAClC,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,IAAI,UAAU,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,EAAc,EACd,KAAkF;IAElF,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;QAC/B,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,qDAAqD,CAAC,CAAC;IACnG,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,yDAAyD,CAAC,CAAC;QACrG,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,yDAAyD,CAAC,CAAC;QACrG,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,uDAAuD,CAAC,CAAC;IACnG,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;IAClG,MAAM,KAAK,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IACvD,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;QACpB,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC;aACxB,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;aAC3F,GAAG,EAAE,CAAC;QACT,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC;aACxB,MAAM,CAAC;YACN,EAAE,EAAE,SAAS,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAC7C,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC;YAC5B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,IAAI,IAAI;YAClD,SAAS,EAAE,GAAG;YACd,SAAS;SACV,CAAC;aACD,GAAG,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAC9B,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,EAAc,EACd,KAAyF;IAEzF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,EAAE;SACX,MAAM,EAAE;SACR,IAAI,CAAC,gBAAgB,CAAC;SACtB,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EACvD,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EACrC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAC/B,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,CAAC,CACpC,CACF;SACA,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,oEAAoE,CAAC,CAAC;IACrH,IAAI,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;QAAE,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,2BAA2B,CAAC,CAAC;IAC1G,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/D,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,oEAAoE,CAAC,CAAC;IAC7G,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClE,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,oEAAoE,CAAC,CAAC;IAC7G,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAChC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IAClG,CAAC;IACD,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE;QACpB,MAAM,OAAO,GAAG,EAAE;aACf,MAAM,CAAC,gBAAgB,CAAC;aACxB,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;aAC1B,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,EAC/B,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAC/B,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAC1C,CACF;aACA,GAAG,EAAE,CAAC;QACT,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,oEAAoE,CAAC,CAAC;QAC7G,CAAC;QACD,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9G,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC;aACzB,MAAM,CAAC;YACN,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,YAAY;YACZ,eAAe,EAAE,CAAC,UAAU,EAAE,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC;YACvD,SAAS,EAAE,SAAS;SACrB,CAAC;aACD,kBAAkB,CAAC;YAClB,MAAM,EAAE,iBAAiB,CAAC,QAAQ;YAClC,GAAG,EAAE;gBACH,YAAY;gBACZ,eAAe,EAAE,CAAC,UAAU,EAAE,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC;gBACvD,SAAS,EAAE,SAAS;aACrB;SACF,CAAC;aACD,GAAG,EAAE,CAAC;QACT,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;aACtB,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;aAC7B,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;aACpF,GAAG,EAAE,CAAC;QACT,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACtF,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAClC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,EAAc,EACd,KAA8D;IAE9D,OAAO,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,EAAc,EACd,KAA8D;IAE9D,OAAO,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,EAAc,EACd,QAAgB,EAChB,UAAkB;IAElB,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,4BAA4B,CAAC,CAAC;IACxG,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,EAAE,GAAG,WAAW,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IACvD,MAAM,IAAI,GAAgB;QACxB,EAAE;QACF,QAAQ;QACR,UAAU,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,gBAAgB;QACjD,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG,GAAG,cAAc;QAC/B,UAAU,EAAE,GAAG;QACf,OAAO,EAAE,IAAI;KACd,CAAC;IACF,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;SACtB,MAAM,CAAC;QACN,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC;QAC5B,SAAS,EAAE,IAAI;KAChB,CAAC;SACD,GAAG,EAAE,CAAC;IACT,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAc,EACd,KAAiF;IAEjF,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,uCAAuC,CAAC,CAAC;IACjH,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,mBAAmB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,2CAA2C,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,SAAS,GAAG,EAAE;SACjB,MAAM,EAAE;SACR,IAAI,CAAC,OAAO,CAAC;SACb,KAAK,CAAC,GAAG,CAAA,SAAS,OAAO,CAAC,KAAK,OAAO,KAAK,EAAE,CAAC;SAC9C,GAAG,EAAE,CAAC;IACT,MAAM,UAAU,GAAG,SAAS;QAC1B,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QAC/F,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,YAAY,IAAI,CAAC,MAAM,iBAAiB,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7G,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC3E,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,iCAAiC,CAAC,CAAC;IAC/E,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACxE,mBAAmB,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IAC3C,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAc,EAAE,KAAa;IAC9D,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,OAAO;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,IAAI,CAAC,KAAK;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,EAAE;SACX,MAAM,EAAE;SACR,IAAI,CAAC,cAAc,CAAC;SACpB,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;SACtD,GAAG,EAAE,CAAC;IACT,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IACxE,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,IAAI,yBAAyB,EAAE,CAAC;QACtD,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,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAChG,CAAC;IACD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,GAAG,CAAC,EAAE;QACnB,SAAS,EAAE,GAAG,CAAC,EAAE;QACjB,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,sBAAsB;QACnC,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAc,EAAE,QAAgB,EAAE,gBAAyB;IAC5F,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,OAAO,EAAE;SACN,MAAM,EAAE;SACR,IAAI,CAAC,cAAc,CAAC;SACpB,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SAC5C,GAAG,EAAE;SACL,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI,IAAI,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC;SAC9D,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACb,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,gBAAgB;KACrC,CAAC,CAAC,CAAC;AACR,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAc,EAAE,QAAgB,EAAE,SAAiB;IAC/E,OAAO,CACL,EAAE;SACC,MAAM,CAAC,cAAc,CAAC;SACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SAC9B,KAAK,CACJ,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAC/G;SACA,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAc,EACd,KAAgG;IAEhG,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC9G,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,gCAAgC,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IACrD,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;SACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SAC9B,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,EACtC,GAAG,CAAA,GAAG,cAAc,CAAC,EAAE,OAAO,KAAK,CAAC,aAAa,EAAE,EACnD,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CACjC,CACF;SACA,GAAG,EAAE,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EAAc,EAAE,GAAW,EAAE,QAAgB;IACtF,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,4DAA4D,CAAC,CAAC;IACxG,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACnC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QACzB,MAAM,IAAI,UAAU,CAAC,mBAAmB,EAAE,oDAAoD,CAAC,CAAC;IAClG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,wEAAwE,CAAC,CAAC;IACpH,CAAC;IACD,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC1D,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IAC/C,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;QAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACpH,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;SACtB,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SAC9B,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC;SACpF,GAAG,EAAE,CAAC;IACT,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,OAAO,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAc;IAC7C,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Account } from '@fluxmail/core';
2
+ import type { Principal } from './auth.js';
3
+ import { type AdminCapability, type Capability } from './permissions.js';
4
+ export declare function canAccessAccount(principal: Principal, account: Account): boolean;
5
+ export declare function canSeeAccountMetadata(principal: Principal, account: Account): boolean;
6
+ export declare function allowsCapability(principal: Principal, capability: Capability): boolean;
7
+ export declare function canAdminister(principal: Principal, capability: AdminCapability): boolean;
8
+ export declare function canManageOwnedAccount(principal: Principal, account: Account): boolean;
9
+ //# sourceMappingURL=authorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAiB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAExF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAMhF;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAMrF;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAEtF;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,OAAO,CAIxF;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAErF"}
@@ -0,0 +1,23 @@
1
+ import { hasCapability } from './permissions.js';
2
+ export function canAccessAccount(principal, account) {
3
+ const granted = account.ownerMemberId === principal.memberId ||
4
+ account.sharedWithAll ||
5
+ account.grantedMemberIds.includes(principal.memberId);
6
+ return granted && (principal.accountIds === null || principal.accountIds.includes(account.id));
7
+ }
8
+ export function canSeeAccountMetadata(principal, account) {
9
+ if (canAccessAccount(principal, account))
10
+ return true;
11
+ return (canAdminister(principal, 'admin.accounts') &&
12
+ (principal.accountIds === null || principal.accountIds.includes(account.id)));
13
+ }
14
+ export function allowsCapability(principal, capability) {
15
+ return principal.kind === 'session' || hasCapability(principal.permissions, capability);
16
+ }
17
+ export function canAdminister(principal, capability) {
18
+ return (principal.role === 'admin' && (principal.kind === 'session' || hasCapability(principal.permissions, capability)));
19
+ }
20
+ export function canManageOwnedAccount(principal, account) {
21
+ return principal.role === 'admin' || account.ownerMemberId === principal.memberId;
22
+ }
23
+ //# sourceMappingURL=authorization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAyC,MAAM,kBAAkB,CAAC;AAExF,MAAM,UAAU,gBAAgB,CAAC,SAAoB,EAAE,OAAgB;IACrE,MAAM,OAAO,GACX,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC,QAAQ;QAC5C,OAAO,CAAC,aAAa;QACrB,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACxD,OAAO,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,KAAK,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAoB,EAAE,OAAgB;IAC1E,IAAI,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,CACL,aAAa,CAAC,SAAS,EAAE,gBAAgB,CAAC;QAC1C,CAAC,SAAS,CAAC,UAAU,KAAK,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAoB,EAAE,UAAsB;IAC3E,OAAO,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAoB,EAAE,UAA2B;IAC7E,OAAO,CACL,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CACjH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAoB,EAAE,OAAgB;IAC1E,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC,QAAQ,CAAC;AACpF,CAAC"}
package/dist/cli.d.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
+ import { serve } from '@hono/node-server';
3
4
  import { type ApiKeyInfo } from './storage/apiKeys.js';
4
5
  import { type PermissionPolicy } from './permissions.js';
6
+ import { type Telemetry } from './telemetry.js';
7
+ import { type CliUpdateNotifierFactory } from './updateNotifier.js';
5
8
  interface PermissionOptions {
6
9
  profile?: string;
7
10
  allow: string[];
@@ -9,8 +12,19 @@ interface PermissionOptions {
9
12
  }
10
13
  export declare function permissionPolicyFromOptions(opts: PermissionOptions, requireSelection?: boolean): PermissionPolicy;
11
14
  export declare function permissionPolicyForUpdate(opts: PermissionOptions, existing: Pick<ApiKeyInfo, 'permissionProfile'>): PermissionPolicy;
15
+ export interface CliProgramOptions {
16
+ telemetry?: Telemetry;
17
+ updateNotifierFactory?: CliUpdateNotifierFactory;
18
+ passwordPrompt?: (label: string) => Promise<string>;
19
+ }
20
+ export declare function waitForServerListening(server: ReturnType<typeof serve>): Promise<void>;
21
+ interface EndEventSource {
22
+ once(event: 'end', listener: () => void): unknown;
23
+ }
24
+ export declare function shutdownTelemetryAndLogging(): Promise<void>;
25
+ export declare function installStdioShutdownHandler(stream: EndEventSource): void;
12
26
  /** Build the command tree without parsing arguments or running command actions. */
13
- export declare function createCliProgram(): Command;
27
+ export declare function createCliProgram(options?: CliProgramOptions): Command;
14
28
  export declare function runCli(argv?: readonly string[]): Promise<void>;
15
29
  export {};
16
30
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAgB9B,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAqC1B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAqBD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,UAAQ,GAAG,gBAAgB,CAoB/G;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,GAC9C,gBAAgB,CAQlB;AAyED,mFAAmF;AACnF,wBAAgB,gBAAgB,IAAI,OAAO,CA06B1C;AAED,wBAAsB,MAAM,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlF"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAwB1C,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAapE,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAexB,OAAO,EAAmD,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAsCrH,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAcD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,UAAQ,GAAG,gBAAgB,CAoB/G;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,GAC9C,gBAAgB,CAQlB;AA+HD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,qBAAqB,CAAC,EAAE,wBAAwB,CAAC;IACjD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACrD;AAkDD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAatF;AAED,UAAU,cAAc;IACtB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CACnD;AAUD,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC,CAQjE;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAExE;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAylDzE;AAED,wBAAsB,MAAM,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlF"}