@memberjunction/encryption 0.0.1 → 2.130.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/README.md +391 -28
- package/dist/EncryptionEngine.d.ts +351 -0
- package/dist/EncryptionEngine.d.ts.map +1 -0
- package/dist/EncryptionEngine.js +683 -0
- package/dist/EncryptionEngine.js.map +1 -0
- package/dist/EncryptionKeySourceBase.d.ts +203 -0
- package/dist/EncryptionKeySourceBase.d.ts.map +1 -0
- package/dist/EncryptionKeySourceBase.js +133 -0
- package/dist/EncryptionKeySourceBase.js.map +1 -0
- package/dist/actions/EnableFieldEncryptionAction.d.ts +87 -0
- package/dist/actions/EnableFieldEncryptionAction.d.ts.map +1 -0
- package/dist/actions/EnableFieldEncryptionAction.js +308 -0
- package/dist/actions/EnableFieldEncryptionAction.js.map +1 -0
- package/dist/actions/RotateEncryptionKeyAction.d.ts +79 -0
- package/dist/actions/RotateEncryptionKeyAction.d.ts.map +1 -0
- package/dist/actions/RotateEncryptionKeyAction.js +343 -0
- package/dist/actions/RotateEncryptionKeyAction.js.map +1 -0
- package/dist/actions/index.d.ts +12 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +17 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +216 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +15 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/providers/AWSKMSKeySource.d.ts +110 -0
- package/dist/providers/AWSKMSKeySource.d.ts.map +1 -0
- package/dist/providers/AWSKMSKeySource.js +245 -0
- package/dist/providers/AWSKMSKeySource.js.map +1 -0
- package/dist/providers/AzureKeyVaultKeySource.d.ts +109 -0
- package/dist/providers/AzureKeyVaultKeySource.d.ts.map +1 -0
- package/dist/providers/AzureKeyVaultKeySource.js +268 -0
- package/dist/providers/AzureKeyVaultKeySource.js.map +1 -0
- package/dist/providers/ConfigFileKeySource.d.ts +173 -0
- package/dist/providers/ConfigFileKeySource.d.ts.map +1 -0
- package/dist/providers/ConfigFileKeySource.js +310 -0
- package/dist/providers/ConfigFileKeySource.js.map +1 -0
- package/dist/providers/EnvVarKeySource.d.ts +152 -0
- package/dist/providers/EnvVarKeySource.d.ts.map +1 -0
- package/dist/providers/EnvVarKeySource.js +251 -0
- package/dist/providers/EnvVarKeySource.js.map +1 -0
- package/package.json +65 -6
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Core encryption engine for MemberJunction field-level encryption.
|
|
3
|
+
*
|
|
4
|
+
* The EncryptionEngine is the central class for all encryption and decryption
|
|
5
|
+
* operations. It provides:
|
|
6
|
+
*
|
|
7
|
+
* - AES-256-GCM/CBC encryption with authenticated encryption support
|
|
8
|
+
* - Pluggable key sources via the ClassFactory pattern
|
|
9
|
+
* - Multi-level caching for performance (inherited from EncryptionEngineBase)
|
|
10
|
+
* - Self-describing encrypted value format
|
|
11
|
+
* - Key rotation support with explicit lookup overrides
|
|
12
|
+
*
|
|
13
|
+
* ## Usage
|
|
14
|
+
*
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { EncryptionEngine } from '@memberjunction/encryption';
|
|
17
|
+
*
|
|
18
|
+
* // First, configure the engine to load metadata
|
|
19
|
+
* await EncryptionEngine.Instance.Config(false, contextUser);
|
|
20
|
+
*
|
|
21
|
+
* // Encrypt a value
|
|
22
|
+
* const encrypted = await EncryptionEngine.Instance.Encrypt(
|
|
23
|
+
* 'sensitive-data',
|
|
24
|
+
* encryptionKeyId,
|
|
25
|
+
* contextUser
|
|
26
|
+
* );
|
|
27
|
+
*
|
|
28
|
+
* // Decrypt a value
|
|
29
|
+
* const decrypted = await EncryptionEngine.Instance.Decrypt(encrypted, contextUser);
|
|
30
|
+
*
|
|
31
|
+
* // Check if a value is encrypted
|
|
32
|
+
* if (EncryptionEngine.Instance.IsEncrypted(someValue)) {
|
|
33
|
+
* // Handle encrypted value
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* ## Security Design
|
|
38
|
+
*
|
|
39
|
+
* - Keys are never stored in memory longer than needed
|
|
40
|
+
* - Authenticated encryption (GCM) prevents tampering
|
|
41
|
+
* - Random IVs for each encryption operation
|
|
42
|
+
* - Self-describing format enables proper key lookup
|
|
43
|
+
* - Secure defaults (fail-safe on errors)
|
|
44
|
+
*
|
|
45
|
+
* @module @memberjunction/encryption
|
|
46
|
+
*/
|
|
47
|
+
/// <reference types="node" />
|
|
48
|
+
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
49
|
+
import { EncryptionEngineBase } from '@memberjunction/core-entities';
|
|
50
|
+
import { EncryptedValueParts } from './interfaces';
|
|
51
|
+
/**
|
|
52
|
+
* Core encryption engine for field-level encryption operations.
|
|
53
|
+
*
|
|
54
|
+
* This class extends EncryptionEngineBase to inherit metadata caching for
|
|
55
|
+
* encryption keys, algorithms, and key sources. It adds the actual
|
|
56
|
+
* encryption/decryption operations using Node.js crypto.
|
|
57
|
+
*
|
|
58
|
+
* Use `EncryptionEngine.Instance` to access the singleton.
|
|
59
|
+
*
|
|
60
|
+
* ## Thread Safety
|
|
61
|
+
*
|
|
62
|
+
* The engine is designed to be safe for concurrent use in async contexts.
|
|
63
|
+
* Cache operations are atomic Map operations and crypto operations
|
|
64
|
+
* use per-call state.
|
|
65
|
+
*
|
|
66
|
+
* ## Error Handling
|
|
67
|
+
*
|
|
68
|
+
* The engine throws descriptive errors for:
|
|
69
|
+
* - Missing keys or configurations
|
|
70
|
+
* - Invalid encrypted value format
|
|
71
|
+
* - Decryption failures (including auth tag mismatch)
|
|
72
|
+
* - Key length mismatches
|
|
73
|
+
*
|
|
74
|
+
* Callers should catch and handle errors appropriately.
|
|
75
|
+
*/
|
|
76
|
+
export declare class EncryptionEngine extends EncryptionEngineBase {
|
|
77
|
+
/**
|
|
78
|
+
* Cache for decrypted key material.
|
|
79
|
+
* Maps 'keyId:version' to Buffer.
|
|
80
|
+
* This is separate from the base class caches since key material
|
|
81
|
+
* is sensitive and needs different handling.
|
|
82
|
+
*
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
private _keyMaterialCache;
|
|
86
|
+
/**
|
|
87
|
+
* Cache for initialized key source instances.
|
|
88
|
+
* Maps driver class name to provider instance.
|
|
89
|
+
*
|
|
90
|
+
* @private
|
|
91
|
+
*/
|
|
92
|
+
private _keySourceCache;
|
|
93
|
+
/**
|
|
94
|
+
* Cache TTL for key material in milliseconds.
|
|
95
|
+
* Can be configured for testing or specific deployment needs.
|
|
96
|
+
*
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
private readonly _keyMaterialCacheTtlMs;
|
|
100
|
+
/**
|
|
101
|
+
* Gets the singleton instance of the encryption engine.
|
|
102
|
+
*
|
|
103
|
+
* The instance is created on first access and reused thereafter.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const engine = EncryptionEngine.Instance;
|
|
108
|
+
* await engine.Config(false, contextUser);
|
|
109
|
+
* const encrypted = await engine.Encrypt(data, keyId, contextUser);
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
static get Instance(): EncryptionEngine;
|
|
113
|
+
/**
|
|
114
|
+
* Configures the engine by loading encryption metadata from the database.
|
|
115
|
+
*
|
|
116
|
+
* This overrides the base Config to ensure proper initialization.
|
|
117
|
+
* Must be called before performing encryption/decryption operations.
|
|
118
|
+
*
|
|
119
|
+
* @param forceRefresh - If true, reloads data even if already loaded
|
|
120
|
+
* @param contextUser - User context for database access (required server-side)
|
|
121
|
+
* @param provider - Optional metadata provider override
|
|
122
|
+
*/
|
|
123
|
+
Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Encrypts a value using the specified encryption key.
|
|
126
|
+
*
|
|
127
|
+
* The method:
|
|
128
|
+
* 1. Gets the key configuration from cached metadata
|
|
129
|
+
* 2. Retrieves key material from the configured source (cached)
|
|
130
|
+
* 3. Generates a random IV
|
|
131
|
+
* 4. Encrypts the data using the configured algorithm
|
|
132
|
+
* 5. Returns a self-describing encrypted string
|
|
133
|
+
*
|
|
134
|
+
* ## Encrypted Format
|
|
135
|
+
*
|
|
136
|
+
* The result format is:
|
|
137
|
+
* `$ENC$<keyId>$<algorithm>$<iv>$<ciphertext>[$<authTag>]`
|
|
138
|
+
*
|
|
139
|
+
* This format contains all information needed for decryption.
|
|
140
|
+
*
|
|
141
|
+
* @param plaintext - The value to encrypt (string or Buffer)
|
|
142
|
+
* @param encryptionKeyId - UUID of the encryption key to use
|
|
143
|
+
* @param contextUser - User context for database access
|
|
144
|
+
* @returns The encrypted value as a string
|
|
145
|
+
*
|
|
146
|
+
* @throws Error if the key cannot be found or is invalid
|
|
147
|
+
* @throws Error if key material retrieval fails
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* const encrypted = await engine.Encrypt(
|
|
152
|
+
* 'secret-api-key',
|
|
153
|
+
* '550e8400-e29b-41d4-a716-446655440000',
|
|
154
|
+
* currentUser
|
|
155
|
+
* );
|
|
156
|
+
* // Returns: $ENC$550e8400-....$AES-256-GCM$<iv>$<ciphertext>$<authTag>
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
Encrypt(plaintext: string | Buffer, encryptionKeyId: string, contextUser?: UserInfo): Promise<string>;
|
|
160
|
+
/**
|
|
161
|
+
* Decrypts an encrypted value.
|
|
162
|
+
*
|
|
163
|
+
* If the value is not encrypted (doesn't start with marker), returns it unchanged.
|
|
164
|
+
*
|
|
165
|
+
* The method:
|
|
166
|
+
* 1. Parses the encrypted value to extract key ID and parameters
|
|
167
|
+
* 2. Gets the key configuration from cached metadata
|
|
168
|
+
* 3. Retrieves key material from the configured source (cached)
|
|
169
|
+
* 4. Decrypts using the algorithm and IV from the encrypted value
|
|
170
|
+
* 5. Verifies the auth tag for AEAD algorithms
|
|
171
|
+
*
|
|
172
|
+
* @param value - The value to decrypt (may or may not be encrypted)
|
|
173
|
+
* @param contextUser - User context for database access
|
|
174
|
+
* @returns The decrypted plaintext, or original value if not encrypted
|
|
175
|
+
*
|
|
176
|
+
* @throws Error if decryption fails (invalid key, corrupted data, auth tag mismatch)
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* // Decrypt an encrypted value
|
|
181
|
+
* const plaintext = await engine.Decrypt(encryptedValue, contextUser);
|
|
182
|
+
*
|
|
183
|
+
* // Non-encrypted values pass through unchanged
|
|
184
|
+
* const same = await engine.Decrypt('plain-text', contextUser);
|
|
185
|
+
* // Returns: 'plain-text'
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
Decrypt(value: string, contextUser?: UserInfo): Promise<string>;
|
|
189
|
+
/**
|
|
190
|
+
* Checks if a value is encrypted.
|
|
191
|
+
*
|
|
192
|
+
* Encrypted values start with the marker prefix (default: '$ENC$').
|
|
193
|
+
* This also checks for the encrypted sentinel value.
|
|
194
|
+
* This is a fast, synchronous check that doesn't require database access.
|
|
195
|
+
*
|
|
196
|
+
* @param value - The value to check
|
|
197
|
+
* @param encryptionMarker - Optional custom marker to check for (defaults to '$ENC$')
|
|
198
|
+
* @returns `true` if the value appears to be encrypted or is the sentinel value
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* if (engine.IsEncrypted(fieldValue)) {
|
|
203
|
+
* const decrypted = await engine.Decrypt(fieldValue, user);
|
|
204
|
+
* }
|
|
205
|
+
*
|
|
206
|
+
* // With custom marker from key
|
|
207
|
+
* const key = engine.GetKeyByID(keyId);
|
|
208
|
+
* if (engine.IsEncrypted(fieldValue, key?.Marker)) {
|
|
209
|
+
* const decrypted = await engine.Decrypt(fieldValue, user);
|
|
210
|
+
* }
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
IsEncrypted(value: unknown, encryptionMarker?: string): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Parses an encrypted value string into its component parts.
|
|
216
|
+
*
|
|
217
|
+
* Use this when you need to inspect the encrypted value without decrypting.
|
|
218
|
+
*
|
|
219
|
+
* @param value - The encrypted value string
|
|
220
|
+
* @returns Parsed components (marker, keyId, algorithm, iv, ciphertext, authTag)
|
|
221
|
+
*
|
|
222
|
+
* @throws Error if the format is invalid
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* const parts = engine.ParseEncryptedValue(encryptedValue);
|
|
227
|
+
* console.log(`Encrypted with key: ${parts.keyId}`);
|
|
228
|
+
* console.log(`Algorithm: ${parts.algorithm}`);
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
ParseEncryptedValue(value: string): EncryptedValueParts;
|
|
232
|
+
/**
|
|
233
|
+
* Validates that key material is accessible at a given lookup value.
|
|
234
|
+
*
|
|
235
|
+
* Used before key rotation to verify the new key exists and is valid.
|
|
236
|
+
* This prevents starting a rotation that would fail mid-way.
|
|
237
|
+
*
|
|
238
|
+
* @param lookupValue - The key source lookup value to validate
|
|
239
|
+
* @param encryptionKeyId - The key ID (to get source configuration)
|
|
240
|
+
* @param contextUser - User context for database access
|
|
241
|
+
*
|
|
242
|
+
* @throws Error if the key material cannot be accessed or is invalid
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* // Before rotation, validate the new key is ready
|
|
247
|
+
* await engine.ValidateKeyMaterial(
|
|
248
|
+
* 'MJ_ENCRYPTION_KEY_PII_NEW',
|
|
249
|
+
* existingKeyId,
|
|
250
|
+
* contextUser
|
|
251
|
+
* );
|
|
252
|
+
* // If no error, safe to proceed with rotation
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
ValidateKeyMaterial(lookupValue: string, encryptionKeyId: string, contextUser?: UserInfo): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Encrypts a value using a specific key lookup (for key rotation).
|
|
258
|
+
*
|
|
259
|
+
* During key rotation, we need to encrypt with the new key material
|
|
260
|
+
* before updating the key metadata. This method allows specifying
|
|
261
|
+
* an alternate lookup value for the key material.
|
|
262
|
+
*
|
|
263
|
+
* @param plaintext - The value to encrypt
|
|
264
|
+
* @param encryptionKeyId - The key ID (for algorithm/marker config)
|
|
265
|
+
* @param keyLookupValue - Alternate lookup value for key material
|
|
266
|
+
* @param contextUser - User context for database access
|
|
267
|
+
* @returns The encrypted value string
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* // During rotation, encrypt with new key before metadata update
|
|
272
|
+
* const newEncrypted = await engine.EncryptWithLookup(
|
|
273
|
+
* decryptedData,
|
|
274
|
+
* keyId,
|
|
275
|
+
* 'MJ_ENCRYPTION_KEY_PII_NEW',
|
|
276
|
+
* contextUser
|
|
277
|
+
* );
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
EncryptWithLookup(plaintext: string | Buffer, encryptionKeyId: string, keyLookupValue: string, contextUser?: UserInfo): Promise<string>;
|
|
281
|
+
/**
|
|
282
|
+
* Clears key material and source caches.
|
|
283
|
+
*
|
|
284
|
+
* Call after key rotation or configuration changes to ensure
|
|
285
|
+
* fresh data is loaded. The base class metadata caches are
|
|
286
|
+
* handled separately via RefreshAllItems().
|
|
287
|
+
*/
|
|
288
|
+
ClearCaches(): void;
|
|
289
|
+
/**
|
|
290
|
+
* Clears all caches including base class metadata caches.
|
|
291
|
+
*
|
|
292
|
+
* This is more aggressive than ClearCaches() and should be used
|
|
293
|
+
* when you need to completely refresh all cached data.
|
|
294
|
+
*/
|
|
295
|
+
ClearAllCaches(): Promise<void>;
|
|
296
|
+
/**
|
|
297
|
+
* Ensures the engine is configured before operations.
|
|
298
|
+
*
|
|
299
|
+
* @private
|
|
300
|
+
*/
|
|
301
|
+
private ensureConfigured;
|
|
302
|
+
/**
|
|
303
|
+
* Builds a KeyConfiguration object from the cached metadata.
|
|
304
|
+
*
|
|
305
|
+
* @private
|
|
306
|
+
*/
|
|
307
|
+
private buildKeyConfiguration;
|
|
308
|
+
/**
|
|
309
|
+
* Performs the actual encryption operation.
|
|
310
|
+
*
|
|
311
|
+
* @private
|
|
312
|
+
*/
|
|
313
|
+
private performEncryption;
|
|
314
|
+
/**
|
|
315
|
+
* Performs the actual decryption operation.
|
|
316
|
+
*
|
|
317
|
+
* @private
|
|
318
|
+
*/
|
|
319
|
+
private performDecryption;
|
|
320
|
+
/**
|
|
321
|
+
* Gets key material from cache or source.
|
|
322
|
+
*
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
325
|
+
private getKeyMaterial;
|
|
326
|
+
/**
|
|
327
|
+
* Gets key material using an overridden lookup value (for rotation).
|
|
328
|
+
*
|
|
329
|
+
* @private
|
|
330
|
+
*/
|
|
331
|
+
private getKeyMaterialWithLookup;
|
|
332
|
+
/**
|
|
333
|
+
* Gets or creates a key source instance.
|
|
334
|
+
*
|
|
335
|
+
* @private
|
|
336
|
+
*/
|
|
337
|
+
private getOrCreateKeySource;
|
|
338
|
+
/**
|
|
339
|
+
* Validates that key material has the correct length for the algorithm.
|
|
340
|
+
*
|
|
341
|
+
* @private
|
|
342
|
+
*/
|
|
343
|
+
private validateKeyLength;
|
|
344
|
+
/**
|
|
345
|
+
* Validates that a string is a valid UUID.
|
|
346
|
+
*
|
|
347
|
+
* @private
|
|
348
|
+
*/
|
|
349
|
+
private isValidUUID;
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=EncryptionEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptionEngine.d.ts","sourceRoot":"","sources":["../src/EncryptionEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;;AAIH,OAAO,EAAE,iBAAiB,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EACH,mBAAmB,EAEtB,MAAM,cAAc,CAAC;AAkBtB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,gBAAiB,SAAQ,oBAAoB;IACtD;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB,CAA8C;IAEvE;;;;;OAKG;IACH,OAAO,CAAC,eAAe,CAAmD;IAE1E;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA6C;IAEpF;;;;;;;;;;;OAWG;IACH,WAA2B,QAAQ,IAAI,gBAAgB,CAEtD;IAED;;;;;;;;;OASG;IACmB,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACG,OAAO,CACT,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,MAAM,CAAC;IA2BlB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,OAAO,CACT,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO;IAI/D;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB;IA2CvD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,mBAAmB,CACrB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,iBAAiB,CACnB,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;;;OAMG;IACH,WAAW,IAAI,IAAI;IAKnB;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IASrC;;;;OAIG;YACW,gBAAgB;IAM9B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA0D7B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAiDzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAuEzB;;;;OAIG;YACW,cAAc;IA8B5B;;;;OAIG;YACW,wBAAwB;IActC;;;;OAIG;YACW,oBAAoB;IAmDlC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAazB;;;;OAIG;IACH,OAAO,CAAC,WAAW;CAStB"}
|