@bernierllc/auth-suite 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,468 @@
1
+ # @bernierllc/auth-suite
2
+
3
+ Complete authentication suite with multi-provider support, session management, role-based access control, and multi-factor authentication.
4
+
5
+ ## Features
6
+
7
+ - **🔐 Complete Authentication** - Built on @bernierllc/auth-service
8
+ - **💫 Enhanced Session Management** - Memory, Redis, or database storage with auto-cleanup
9
+ - **🛡️ Role-Based Access Control (RBAC)** - Hierarchical roles and permissions
10
+ - **📱 Multi-Factor Authentication** - TOTP, SMS, email, and backup codes
11
+ - **📊 Comprehensive Audit Logging** - Track all authentication events
12
+ - **🔌 OAuth/SAML/LDAP Integration** - Multiple provider support
13
+ - **🚀 Advanced Security Features** - Session management, permission checks
14
+ - **📈 Production Ready** - Built with crypto-utils for enterprise security
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @bernierllc/auth-suite
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { AuthSuite } from '@bernierllc/auth-suite';
26
+
27
+ // Initialize with enhanced features
28
+ const authSuite = new AuthSuite({
29
+ // Core auth configuration
30
+ jwt: {
31
+ secret: process.env.JWT_SECRET,
32
+ expiresIn: '15m',
33
+ refreshExpiresIn: '7d'
34
+ },
35
+
36
+ // Enhanced session management
37
+ sessions: {
38
+ enabled: true,
39
+ storage: 'memory', // or 'redis', 'database'
40
+ cleanup: {
41
+ enabled: true,
42
+ intervalMs: 60000, // 1 minute
43
+ maxIdleMs: 24 * 60 * 60 * 1000 // 24 hours
44
+ }
45
+ },
46
+
47
+ // Role-based access control
48
+ rbac: {
49
+ enabled: true,
50
+ hierarchical: true,
51
+ roles: [
52
+ {
53
+ name: 'admin',
54
+ description: 'System administrator',
55
+ permissions: ['*:*'] // All permissions
56
+ },
57
+ {
58
+ name: 'user',
59
+ description: 'Regular user',
60
+ permissions: ['profile:read', 'profile:update']
61
+ }
62
+ ],
63
+ permissions: [
64
+ {
65
+ name: 'profile:read',
66
+ description: 'Read user profile',
67
+ resource: 'profile',
68
+ actions: ['read']
69
+ }
70
+ ]
71
+ },
72
+
73
+ // Multi-factor authentication
74
+ mfaEnhanced: {
75
+ enabled: true,
76
+ providers: [
77
+ {
78
+ type: 'totp',
79
+ name: 'Google Authenticator',
80
+ enabled: true,
81
+ config: {}
82
+ }
83
+ ],
84
+ requirements: [
85
+ {
86
+ trigger: 'login',
87
+ providers: ['totp'],
88
+ conditions: {}
89
+ }
90
+ ]
91
+ },
92
+
93
+ // Audit logging
94
+ auditing: {
95
+ enabled: true,
96
+ events: ['login', 'logout', 'register', 'permission_change'],
97
+ storage: 'file',
98
+ retention: {
99
+ days: 90,
100
+ maxSize: '100MB'
101
+ }
102
+ }
103
+ });
104
+
105
+ // Register user with enhanced features
106
+ const registerResult = await authSuite.register({
107
+ username: 'johndoe',
108
+ email: 'john@example.com',
109
+ password: 'SecurePass123!',
110
+ firstName: 'John',
111
+ lastName: 'Doe',
112
+ acceptTerms: true
113
+ });
114
+
115
+ if (registerResult.success) {
116
+ console.log('User registered with session:', registerResult.session);
117
+ console.log('Assigned permissions:', registerResult.permissions);
118
+ }
119
+
120
+ // Login with potential MFA
121
+ const loginResult = await authSuite.login({
122
+ email: 'john@example.com',
123
+ password: 'SecurePass123!'
124
+ });
125
+
126
+ if (loginResult.mfaRequired) {
127
+ console.log('MFA required, challenge:', loginResult.mfaChallenge);
128
+
129
+ // Complete MFA verification
130
+ const mfaResult = await authSuite.completeMfaLogin(
131
+ loginResult.mfaChallenge.challengeId,
132
+ '123456' // TOTP code from authenticator app
133
+ );
134
+
135
+ if (mfaResult.success) {
136
+ console.log('Login complete with MFA');
137
+ }
138
+ }
139
+ ```
140
+
141
+ ## Core Features
142
+
143
+ ### Enhanced Session Management
144
+
145
+ ```typescript
146
+ // Session automatically created on login/register
147
+ const result = await authSuite.login(credentials);
148
+ if (result.success && result.session) {
149
+ console.log('Session ID:', result.session.sessionId);
150
+ console.log('Expires at:', result.session.expiresAt);
151
+ }
152
+
153
+ // Manual session management
154
+ const session = await authSuite.sessionManager.create('user-id', {
155
+ customData: 'value'
156
+ });
157
+
158
+ // Cleanup expired sessions
159
+ const cleaned = await authSuite.cleanup();
160
+ console.log(`Cleaned up ${cleaned.sessions} expired sessions`);
161
+ ```
162
+
163
+ ### Role-Based Access Control (RBAC)
164
+
165
+ ```typescript
166
+ // Check permissions
167
+ const permissionResult = await authSuite.checkPermission({
168
+ userId: 'user-123',
169
+ resource: 'documents',
170
+ action: 'delete',
171
+ context: { ownerId: 'user-123' }
172
+ });
173
+
174
+ if (permissionResult.allowed) {
175
+ console.log('User can delete documents');
176
+ } else {
177
+ console.log('Access denied:', permissionResult.reason);
178
+ }
179
+
180
+ // Assign roles
181
+ await authSuite.rbacManager.assignRole('user-123', 'admin');
182
+
183
+ // Get user permissions
184
+ const permissions = await authSuite.getUserPermissions('user-123');
185
+ console.log('User permissions:', permissions);
186
+ ```
187
+
188
+ ### Multi-Factor Authentication
189
+
190
+ ```typescript
191
+ // Setup MFA for user
192
+ const mfaSetup = await authSuite.setupMfa('user-123', 'totp');
193
+ console.log('Show QR code to user:', mfaSetup.qrCode);
194
+
195
+ // Verify setup
196
+ const setupVerified = await authSuite.mfaManager.verifySetup('user-123', '123456');
197
+
198
+ // Generate backup codes
199
+ const backupCodes = await authSuite.mfaManager.regenerateBackupCodes('user-123');
200
+ console.log('Backup codes:', backupCodes);
201
+
202
+ // Verify backup code
203
+ const backupValid = await authSuite.mfaManager.verifyBackupCode('user-123', 'backup-code');
204
+ ```
205
+
206
+ ### Audit Logging
207
+
208
+ ```typescript
209
+ // Logs are automatically generated for auth events
210
+ // Query audit logs
211
+ const auditLogs = await authSuite.getAuditLogs({
212
+ userId: 'user-123',
213
+ event: 'login',
214
+ startDate: new Date('2025-01-01'),
215
+ limit: 50
216
+ });
217
+
218
+ // Get audit statistics
219
+ const stats = await authSuite.auditManager.getLogStats();
220
+ console.log('Audit stats:', stats);
221
+
222
+ // Search logs
223
+ const searchResults = await authSuite.auditManager.searchLogs('failed login');
224
+ ```
225
+
226
+ ## Configuration
227
+
228
+ ### Complete Configuration Options
229
+
230
+ ```typescript
231
+ interface AuthSuiteConfig {
232
+ // Core auth service configuration
233
+ jwt: {
234
+ secret: string;
235
+ issuer?: string;
236
+ audience?: string;
237
+ expiresIn?: string | number;
238
+ refreshExpiresIn?: string | number;
239
+ algorithm?: JWTAlgorithm;
240
+ };
241
+
242
+ // Password policy
243
+ password: {
244
+ minLength: number;
245
+ requireUppercase: boolean;
246
+ requireLowercase: boolean;
247
+ requireNumbers: boolean;
248
+ requireSymbols: boolean;
249
+ preventReuse?: number;
250
+ maxAge?: number;
251
+ };
252
+
253
+ // Enhanced session management
254
+ sessions?: {
255
+ enabled?: boolean; // default: true
256
+ storage?: 'memory' | 'redis' | 'database'; // default: 'memory'
257
+ cleanup?: {
258
+ enabled: boolean; // default: true
259
+ intervalMs: number; // default: 60000 (1 minute)
260
+ maxIdleMs: number; // default: 24 hours
261
+ };
262
+ persistence?: {
263
+ enabled: boolean; // default: false
264
+ ttl: number; // default: 7 days
265
+ };
266
+ };
267
+
268
+ // Role-based access control
269
+ rbac?: {
270
+ enabled: boolean; // default: false
271
+ hierarchical: boolean; // default: false
272
+ roles: RoleDefinition[];
273
+ permissions: PermissionDefinition[];
274
+ };
275
+
276
+ // Multi-factor authentication
277
+ mfaEnhanced?: {
278
+ enabled: boolean; // default: false
279
+ providers: MfaProvider[];
280
+ requirements: MfaRequirement[];
281
+ backup: {
282
+ enabled: boolean; // default: true
283
+ codeCount: number; // default: 10
284
+ codeLength: number; // default: 8
285
+ };
286
+ };
287
+
288
+ // Audit logging
289
+ auditing?: {
290
+ enabled: boolean; // default: true
291
+ events: AuditEvent[];
292
+ storage: 'file' | 'database' | 'external'; // default: 'file'
293
+ retention: {
294
+ days: number; // default: 90
295
+ maxSize: string; // default: '100MB'
296
+ };
297
+ };
298
+
299
+ // Security settings
300
+ security: {
301
+ maxLoginAttempts: number;
302
+ lockoutDuration: number;
303
+ sessionTimeout: number;
304
+ requireEmailVerification: boolean;
305
+ allowMultipleSessions: boolean;
306
+ };
307
+ }
308
+ ```
309
+
310
+ ### Role Definition
311
+
312
+ ```typescript
313
+ interface RoleDefinition {
314
+ name: string;
315
+ description: string;
316
+ permissions: string[]; // e.g., ['users:read', 'documents:*']
317
+ parent?: string; // for hierarchical roles
318
+ metadata?: Record<string, any>;
319
+ }
320
+ ```
321
+
322
+ ### Permission Definition
323
+
324
+ ```typescript
325
+ interface PermissionDefinition {
326
+ name: string; // e.g., 'documents:delete'
327
+ description: string;
328
+ resource: string; // e.g., 'documents'
329
+ actions: string[]; // e.g., ['delete']
330
+ conditions?: PermissionCondition[]; // conditional permissions
331
+ }
332
+ ```
333
+
334
+ ## API Reference
335
+
336
+ ### Class: AuthSuite
337
+
338
+ #### Core Authentication
339
+
340
+ - `register(credentials: RegisterCredentials): Promise<AuthSuiteResult>`
341
+ - `login(credentials: LoginCredentials): Promise<AuthSuiteResult>`
342
+ - `verifyToken(token: string): Promise<User | null>`
343
+ - `logout(sessionId?: string): Promise<{success: boolean}>`
344
+
345
+ #### MFA Management
346
+
347
+ - `setupMfa(userId: string, type: string): Promise<{secret: string; qrCode?: string}>`
348
+ - `completeMfaLogin(challengeId: string, response: string): Promise<AuthSuiteResult>`
349
+
350
+ #### Permission Management
351
+
352
+ - `checkPermission(check: PermissionCheck): Promise<PermissionResult>`
353
+ - `getUserRoles(userId: string): Promise<string[]>`
354
+ - `getUserPermissions(userId: string): Promise<string[]>`
355
+
356
+ #### Audit and Cleanup
357
+
358
+ - `getAuditLogs(filters: AuditQueryFilters): Promise<AuditLog[]>`
359
+ - `cleanup(): Promise<{sessions: number; auditLogs: number}>`
360
+
361
+ ### Manager Classes
362
+
363
+ For advanced usage, managers can be used directly:
364
+
365
+ ```typescript
366
+ import {
367
+ MemorySessionManager,
368
+ BasicRBACManager,
369
+ TOTPMfaManager,
370
+ FileAuditManager
371
+ } from '@bernierllc/auth-suite';
372
+ ```
373
+
374
+ ## Integration with Crypto-Utils
375
+
376
+ This suite leverages `@bernierllc/crypto-utils` for:
377
+
378
+ - **JWT Generation & Verification** - Secure token handling
379
+ - **Magic Links** - Password reset functionality
380
+ - **API Key Generation** - MFA backup codes and secrets
381
+ - **Password Hashing** - Secure password storage
382
+
383
+ ## Dependencies
384
+
385
+ - `@bernierllc/auth-service` - Core authentication service
386
+ - `@bernierllc/crypto-utils` - Cryptographic utilities
387
+ - `@bernierllc/logger` - Structured logging
388
+ - `bcrypt` - Password hashing
389
+ - `uuid` - Unique ID generation
390
+
391
+ ## Production Considerations
392
+
393
+ ### Session Storage
394
+
395
+ For production deployments:
396
+
397
+ - **Memory**: Fast but not persistent, use for single-instance apps
398
+ - **Redis**: Recommended for multi-instance deployments
399
+ - **Database**: Use for full persistence and audit requirements
400
+
401
+ ### Security
402
+
403
+ - Use strong JWT secrets (256-bit minimum)
404
+ - Enable MFA for sensitive applications
405
+ - Configure appropriate session timeouts
406
+ - Monitor audit logs for suspicious activity
407
+ - Use HTTPS in production
408
+ - Implement rate limiting
409
+
410
+ ### Performance
411
+
412
+ - Cleanup expired sessions regularly
413
+ - Index audit log queries for performance
414
+ - Consider external audit log storage for high-volume applications
415
+ - Use Redis for session storage in clustered environments
416
+
417
+ ## Examples
418
+
419
+ ### Basic Usage
420
+
421
+ ```typescript
422
+ const authSuite = new AuthSuite({
423
+ jwt: { secret: process.env.JWT_SECRET },
424
+ sessions: { enabled: true },
425
+ auditing: { enabled: true }
426
+ });
427
+ ```
428
+
429
+ ### Enterprise Setup
430
+
431
+ ```typescript
432
+ const authSuite = new AuthSuite({
433
+ jwt: {
434
+ secret: process.env.JWT_SECRET,
435
+ expiresIn: '15m',
436
+ refreshExpiresIn: '7d',
437
+ issuer: 'mycompany.com'
438
+ },
439
+ rbac: {
440
+ enabled: true,
441
+ hierarchical: true,
442
+ roles: enterpriseRoles,
443
+ permissions: enterprisePermissions
444
+ },
445
+ mfaEnhanced: {
446
+ enabled: true,
447
+ providers: [
448
+ { type: 'totp', name: 'Authenticator', enabled: true, config: {} }
449
+ ],
450
+ requirements: [
451
+ { trigger: 'login', providers: ['totp'] }
452
+ ]
453
+ },
454
+ sessions: {
455
+ storage: 'redis',
456
+ cleanup: { enabled: true, intervalMs: 30000 }
457
+ },
458
+ auditing: {
459
+ enabled: true,
460
+ storage: 'database',
461
+ retention: { days: 365, maxSize: '1GB' }
462
+ }
463
+ });
464
+ ```
465
+
466
+ ## License
467
+
468
+ Copyright (c) 2025 Bernier LLC. All rights reserved.
@@ -0,0 +1,9 @@
1
+ export { AuthSuite } from './suite';
2
+ export type * from './types';
3
+ export type { EmailVerificationResult } from './types';
4
+ export { MemorySessionManager } from './managers/session-manager';
5
+ export { BasicRBACManager } from './managers/rbac-manager';
6
+ export { TOTPMfaManager } from './managers/mfa-manager';
7
+ export { FileAuditManager } from './managers/audit-manager';
8
+ export * from '@bernierllc/auth-service';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,mBAAmB,SAAS,CAAC;AAC7B,YAAY,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG5D,cAAc,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (c) 2025 Bernier LLC
4
+
5
+ This file is licensed to the client under a limited-use license.
6
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
7
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
21
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.FileAuditManager = exports.TOTPMfaManager = exports.BasicRBACManager = exports.MemorySessionManager = exports.AuthSuite = void 0;
25
+ // Main exports
26
+ var suite_1 = require("./suite");
27
+ Object.defineProperty(exports, "AuthSuite", { enumerable: true, get: function () { return suite_1.AuthSuite; } });
28
+ // Manager exports for advanced usage
29
+ var session_manager_1 = require("./managers/session-manager");
30
+ Object.defineProperty(exports, "MemorySessionManager", { enumerable: true, get: function () { return session_manager_1.MemorySessionManager; } });
31
+ var rbac_manager_1 = require("./managers/rbac-manager");
32
+ Object.defineProperty(exports, "BasicRBACManager", { enumerable: true, get: function () { return rbac_manager_1.BasicRBACManager; } });
33
+ var mfa_manager_1 = require("./managers/mfa-manager");
34
+ Object.defineProperty(exports, "TOTPMfaManager", { enumerable: true, get: function () { return mfa_manager_1.TOTPMfaManager; } });
35
+ var audit_manager_1 = require("./managers/audit-manager");
36
+ Object.defineProperty(exports, "FileAuditManager", { enumerable: true, get: function () { return audit_manager_1.FileAuditManager; } });
37
+ // Re-export auth-service for convenience
38
+ __exportStar(require("@bernierllc/auth-service"), exports);
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;;;;;;;;;;;;;;;AAEF,eAAe;AACf,iCAAoC;AAA3B,kGAAA,SAAS,OAAA;AAMlB,qCAAqC;AACrC,8DAAkE;AAAzD,uHAAA,oBAAoB,OAAA;AAC7B,wDAA2D;AAAlD,gHAAA,gBAAgB,OAAA;AACzB,sDAAwD;AAA/C,6GAAA,cAAc,OAAA;AACvB,0DAA4D;AAAnD,iHAAA,gBAAgB,OAAA;AAEzB,yCAAyC;AACzC,2DAAyC"}
@@ -0,0 +1,26 @@
1
+ import type { AuditManager, AuditLog, AuditQueryFilters } from '../types';
2
+ /**
3
+ * File-based audit manager
4
+ * For production use, consider database storage or external logging service
5
+ */
6
+ export declare class FileAuditManager implements AuditManager {
7
+ private logs;
8
+ private config;
9
+ private maxLogs;
10
+ constructor(config: any);
11
+ log(event: Omit<AuditLog, 'id' | 'timestamp'>): Promise<void>;
12
+ query(filters: AuditQueryFilters): Promise<AuditLog[]>;
13
+ cleanup(olderThanDays: number): Promise<number>;
14
+ getLogStats(): Promise<{
15
+ total: number;
16
+ byLevel: Record<string, number>;
17
+ byEvent: Record<string, number>;
18
+ oldestLog?: Date;
19
+ newestLog?: Date;
20
+ }>;
21
+ exportLogs(format?: 'json' | 'csv'): Promise<string>;
22
+ searchLogs(searchTerm: string): Promise<AuditLog[]>;
23
+ private parseMaxSize;
24
+ private exportToCsv;
25
+ }
26
+ //# sourceMappingURL=audit-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-manager.d.ts","sourceRoot":"","sources":["../../src/managers/audit-manager.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE1E;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,GAAG;IAKjB,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB7D,KAAK,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAsCtD,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY/C,WAAW,IAAI,OAAO,CAAC;QAC3B,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,SAAS,CAAC,EAAE,IAAI,CAAC;KAClB,CAAC;IA8BI,UAAU,CAAC,MAAM,GAAE,MAAM,GAAG,KAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ5D,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAyBzD,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,WAAW;CAuBpB"}