@edgebasejs/react-native 0.1.8 → 0.1.9
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 +18 -0
- package/dist/client-core/src/index.d.ts +4 -0
- package/dist/client-core/src/index.d.ts.map +1 -1
- package/dist/client-core/src/index.js +4 -0
- package/dist/client-core/src/index.js.map +1 -1
- package/dist/client-core/src/mutations/batch-processor-client.d.ts +67 -0
- package/dist/client-core/src/mutations/batch-processor-client.d.ts.map +1 -0
- package/dist/client-core/src/mutations/batch-processor-client.js +64 -0
- package/dist/client-core/src/mutations/batch-processor-client.js.map +1 -0
- package/dist/client-core/src/mutations/transaction-hook.d.ts +80 -0
- package/dist/client-core/src/mutations/transaction-hook.d.ts.map +1 -0
- package/dist/client-core/src/mutations/transaction-hook.js +204 -0
- package/dist/client-core/src/mutations/transaction-hook.js.map +1 -0
- package/dist/client-core/src/realtime/realtime-sync-manager.d.ts +55 -0
- package/dist/client-core/src/realtime/realtime-sync-manager.d.ts.map +1 -0
- package/dist/client-core/src/realtime/realtime-sync-manager.js +208 -0
- package/dist/client-core/src/realtime/realtime-sync-manager.js.map +1 -0
- package/dist/client-core/src/realtime/subscription-handler.d.ts +74 -0
- package/dist/client-core/src/realtime/subscription-handler.d.ts.map +1 -0
- package/dist/client-core/src/realtime/subscription-handler.js +224 -0
- package/dist/client-core/src/realtime/subscription-handler.js.map +1 -0
- package/dist/client-core/src/sync/sync-engine.d.ts +10 -0
- package/dist/client-core/src/sync/sync-engine.d.ts.map +1 -1
- package/dist/client-core/src/sync/sync-engine.js +37 -5
- package/dist/client-core/src/sync/sync-engine.js.map +1 -1
- package/dist/client-react-native/src/hooks/index.d.ts +10 -0
- package/dist/client-react-native/src/hooks/index.d.ts.map +1 -1
- package/dist/client-react-native/src/hooks/index.js +8 -0
- package/dist/client-react-native/src/hooks/index.js.map +1 -1
- package/dist/client-react-native/src/hooks/use-audit.d.ts +65 -0
- package/dist/client-react-native/src/hooks/use-audit.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-audit.js +201 -0
- package/dist/client-react-native/src/hooks/use-audit.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-batch-mutation.d.ts +56 -0
- package/dist/client-react-native/src/hooks/use-batch-mutation.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-batch-mutation.js +95 -0
- package/dist/client-react-native/src/hooks/use-batch-mutation.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-encryption.d.ts +45 -0
- package/dist/client-react-native/src/hooks/use-encryption.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-encryption.js +143 -0
- package/dist/client-react-native/src/hooks/use-encryption.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-file-manager.d.ts +38 -0
- package/dist/client-react-native/src/hooks/use-file-manager.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-file-manager.js +174 -0
- package/dist/client-react-native/src/hooks/use-file-manager.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-file-upload.d.ts +34 -0
- package/dist/client-react-native/src/hooks/use-file-upload.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-file-upload.js +85 -0
- package/dist/client-react-native/src/hooks/use-file-upload.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-mutation.d.ts.map +1 -1
- package/dist/client-react-native/src/hooks/use-mutation.js +34 -6
- package/dist/client-react-native/src/hooks/use-mutation.js.map +1 -1
- package/dist/client-react-native/src/hooks/use-search.d.ts +33 -0
- package/dist/client-react-native/src/hooks/use-search.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-search.js +174 -0
- package/dist/client-react-native/src/hooks/use-search.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-subscribe.d.ts +14 -0
- package/dist/client-react-native/src/hooks/use-subscribe.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-subscribe.js +165 -0
- package/dist/client-react-native/src/hooks/use-subscribe.js.map +1 -0
- package/dist/client-react-native/src/hooks/use-transaction.d.ts +27 -0
- package/dist/client-react-native/src/hooks/use-transaction.d.ts.map +1 -0
- package/dist/client-react-native/src/hooks/use-transaction.js +160 -0
- package/dist/client-react-native/src/hooks/use-transaction.js.map +1 -0
- package/dist/client-react-native/src/provider.d.ts +5 -2
- package/dist/client-react-native/src/provider.d.ts.map +1 -1
- package/dist/client-react-native/src/provider.js +23 -23
- package/dist/client-react-native/src/provider.js.map +1 -1
- package/dist/core/src/access-rules/column-security.d.ts +80 -0
- package/dist/core/src/access-rules/column-security.d.ts.map +1 -0
- package/dist/core/src/access-rules/column-security.js +191 -0
- package/dist/core/src/access-rules/column-security.js.map +1 -0
- package/dist/core/src/access-rules/engine.d.ts +26 -0
- package/dist/core/src/access-rules/engine.d.ts.map +1 -0
- package/dist/core/src/access-rules/engine.js +76 -0
- package/dist/core/src/access-rules/engine.js.map +1 -0
- package/dist/core/src/access-rules/index.d.ts +3 -0
- package/dist/core/src/access-rules/index.d.ts.map +1 -0
- package/dist/core/src/access-rules/index.js +3 -0
- package/dist/core/src/access-rules/index.js.map +1 -0
- package/dist/core/src/audit/audit-manager.d.ts +108 -0
- package/dist/core/src/audit/audit-manager.d.ts.map +1 -0
- package/dist/core/src/audit/audit-manager.js +265 -0
- package/dist/core/src/audit/audit-manager.js.map +1 -0
- package/dist/core/src/auth/auth-service.d.ts +71 -0
- package/dist/core/src/auth/auth-service.d.ts.map +1 -0
- package/dist/core/src/auth/auth-service.js +177 -0
- package/dist/core/src/auth/auth-service.js.map +1 -0
- package/dist/core/src/auth/index.d.ts +4 -0
- package/dist/core/src/auth/index.d.ts.map +1 -0
- package/dist/core/src/auth/index.js +4 -0
- package/dist/core/src/auth/index.js.map +1 -0
- package/dist/core/src/encryption/encryption-manager.d.ts +97 -0
- package/dist/core/src/encryption/encryption-manager.d.ts.map +1 -0
- package/dist/core/src/encryption/encryption-manager.js +224 -0
- package/dist/core/src/encryption/encryption-manager.js.map +1 -0
- package/dist/core/src/index.d.ts +16 -0
- package/dist/core/src/index.d.ts.map +1 -0
- package/dist/core/src/index.js +16 -0
- package/dist/core/src/index.js.map +1 -0
- package/dist/core/src/realtime/change-notifier.d.ts +50 -0
- package/dist/core/src/realtime/change-notifier.d.ts.map +1 -0
- package/dist/core/src/realtime/change-notifier.js +145 -0
- package/dist/core/src/realtime/change-notifier.js.map +1 -0
- package/dist/core/src/realtime/message-types.d.ts +39 -0
- package/dist/core/src/realtime/message-types.d.ts.map +1 -0
- package/dist/core/src/realtime/message-types.js +5 -0
- package/dist/core/src/realtime/message-types.js.map +1 -0
- package/dist/core/src/realtime/subscription-manager.d.ts +67 -0
- package/dist/core/src/realtime/subscription-manager.d.ts.map +1 -0
- package/dist/core/src/realtime/subscription-manager.js +229 -0
- package/dist/core/src/realtime/subscription-manager.js.map +1 -0
- package/dist/core/src/search/search-manager.d.ts +93 -0
- package/dist/core/src/search/search-manager.d.ts.map +1 -0
- package/dist/core/src/search/search-manager.js +258 -0
- package/dist/core/src/search/search-manager.js.map +1 -0
- package/dist/core/src/storage/file-manager.d.ts +138 -0
- package/dist/core/src/storage/file-manager.d.ts.map +1 -0
- package/dist/core/src/storage/file-manager.js +224 -0
- package/dist/core/src/storage/file-manager.js.map +1 -0
- package/dist/core/src/sync/batch-processor.d.ts +97 -0
- package/dist/core/src/sync/batch-processor.d.ts.map +1 -0
- package/dist/core/src/sync/batch-processor.js +313 -0
- package/dist/core/src/sync/batch-processor.js.map +1 -0
- package/dist/core/src/sync/csv-processor.d.ts +66 -0
- package/dist/core/src/sync/csv-processor.d.ts.map +1 -0
- package/dist/core/src/sync/csv-processor.js +223 -0
- package/dist/core/src/sync/csv-processor.js.map +1 -0
- package/dist/core/src/sync/index.d.ts +3 -0
- package/dist/core/src/sync/index.d.ts.map +1 -0
- package/dist/core/src/sync/index.js +3 -0
- package/dist/core/src/sync/index.js.map +1 -0
- package/dist/core/src/sync/sync-engine.d.ts +68 -0
- package/dist/core/src/sync/sync-engine.d.ts.map +1 -0
- package/dist/core/src/sync/sync-engine.js +317 -0
- package/dist/core/src/sync/sync-engine.js.map +1 -0
- package/dist/core/src/sync/transaction-manager.d.ts +83 -0
- package/dist/core/src/sync/transaction-manager.d.ts.map +1 -0
- package/dist/core/src/sync/transaction-manager.js +227 -0
- package/dist/core/src/sync/transaction-manager.js.map +1 -0
- package/dist/core/src/webhooks/webhook-manager.d.ts +137 -0
- package/dist/core/src/webhooks/webhook-manager.d.ts.map +1 -0
- package/dist/core/src/webhooks/webhook-manager.js +334 -0
- package/dist/core/src/webhooks/webhook-manager.js.map +1 -0
- package/package.json +4 -6
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encryption manager for field-level data encryption
|
|
3
|
+
* Handles encryption/decryption of sensitive fields at rest
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Encryption manager for field-level encryption
|
|
7
|
+
*/
|
|
8
|
+
export class EncryptionManager {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.configs = new Map();
|
|
11
|
+
this.currentKey = null;
|
|
12
|
+
this.keyHistory = new Map();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Register encryption configuration for an entity
|
|
16
|
+
*/
|
|
17
|
+
registerConfig(config) {
|
|
18
|
+
this.configs.set(config.entity, config);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get encryption configuration for an entity
|
|
22
|
+
*/
|
|
23
|
+
getConfig(entity) {
|
|
24
|
+
return this.configs.get(entity);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Initialize encryption key from master key
|
|
28
|
+
*/
|
|
29
|
+
async initializeKey(masterKey, version = 1) {
|
|
30
|
+
const algorithm = 'AES-GCM';
|
|
31
|
+
// Derive key from master key using PBKDF2
|
|
32
|
+
const keyMaterial = await this.deriveKeyMaterial(masterKey);
|
|
33
|
+
const cryptoKey = await crypto.subtle.deriveKey({
|
|
34
|
+
name: 'PBKDF2',
|
|
35
|
+
salt: new TextEncoder().encode('edgebase-salt-v1'), // In production, use unique salt
|
|
36
|
+
iterations: 100000,
|
|
37
|
+
hash: 'SHA-256',
|
|
38
|
+
}, keyMaterial, { name: 'AES-GCM', length: 256 }, false, // Not extractable
|
|
39
|
+
['encrypt', 'decrypt']);
|
|
40
|
+
const encryptionKey = {
|
|
41
|
+
id: `key_${version}_${Date.now()}`,
|
|
42
|
+
key: cryptoKey,
|
|
43
|
+
version,
|
|
44
|
+
algorithm,
|
|
45
|
+
createdAt: Date.now(),
|
|
46
|
+
};
|
|
47
|
+
this.currentKey = encryptionKey;
|
|
48
|
+
this.keyHistory.set(version, encryptionKey);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Rotate encryption key (for key rotation support)
|
|
52
|
+
*/
|
|
53
|
+
async rotateKey(newMasterKey) {
|
|
54
|
+
const newVersion = this.currentKey ? this.currentKey.version + 1 : 1;
|
|
55
|
+
await this.initializeKey(newMasterKey, newVersion);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Encrypt a value
|
|
59
|
+
*/
|
|
60
|
+
async encrypt(value) {
|
|
61
|
+
if (!this.currentKey) {
|
|
62
|
+
throw new Error('Encryption key not initialized');
|
|
63
|
+
}
|
|
64
|
+
// Convert value to string
|
|
65
|
+
const plaintext = typeof value === 'string' ? value : JSON.stringify(value);
|
|
66
|
+
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
67
|
+
// Generate random IV
|
|
68
|
+
const iv = crypto.getRandomValues(new Uint8Array(12)); // 12 bytes for GCM
|
|
69
|
+
// Encrypt
|
|
70
|
+
const ciphertextBuffer = await crypto.subtle.encrypt({
|
|
71
|
+
name: 'AES-GCM',
|
|
72
|
+
iv,
|
|
73
|
+
}, this.currentKey.key, plaintextBytes);
|
|
74
|
+
const ciphertext = this.arrayBufferToBase64(ciphertextBuffer);
|
|
75
|
+
const ivBase64 = this.arrayBufferToBase64(iv);
|
|
76
|
+
return {
|
|
77
|
+
ciphertext,
|
|
78
|
+
iv: ivBase64,
|
|
79
|
+
algorithm: this.currentKey.algorithm,
|
|
80
|
+
keyVersion: this.currentKey.version,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Decrypt a value
|
|
85
|
+
*/
|
|
86
|
+
async decrypt(encrypted) {
|
|
87
|
+
// Get appropriate key for decryption (supports key rotation)
|
|
88
|
+
const key = encrypted.keyVersion
|
|
89
|
+
? this.keyHistory.get(encrypted.keyVersion)
|
|
90
|
+
: this.currentKey;
|
|
91
|
+
if (!key) {
|
|
92
|
+
throw new Error(`Encryption key for version ${encrypted.keyVersion} not found`);
|
|
93
|
+
}
|
|
94
|
+
// Decode base64
|
|
95
|
+
const ciphertextBuffer = this.base64ToArrayBuffer(encrypted.ciphertext);
|
|
96
|
+
const iv = this.base64ToArrayBuffer(encrypted.iv);
|
|
97
|
+
// Decrypt
|
|
98
|
+
const plaintextBuffer = await crypto.subtle.decrypt({
|
|
99
|
+
name: encrypted.algorithm,
|
|
100
|
+
iv: iv,
|
|
101
|
+
}, key.key, ciphertextBuffer);
|
|
102
|
+
const plaintext = new TextDecoder().decode(plaintextBuffer);
|
|
103
|
+
// Try to parse as JSON (for objects/arrays)
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(plaintext);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return plaintext;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Encrypt fields in a record based on entity configuration
|
|
113
|
+
*/
|
|
114
|
+
async encryptRecord(entity, record) {
|
|
115
|
+
const config = this.configs.get(entity);
|
|
116
|
+
if (!config) {
|
|
117
|
+
return record; // No encryption config
|
|
118
|
+
}
|
|
119
|
+
const encrypted = { ...record };
|
|
120
|
+
for (const field of config.fields) {
|
|
121
|
+
if (field in record && record[field] !== null && record[field] !== undefined) {
|
|
122
|
+
// Encrypt the field
|
|
123
|
+
const encryptedValue = await this.encrypt(record[field]);
|
|
124
|
+
// Store as JSON string
|
|
125
|
+
encrypted[field] = JSON.stringify(encryptedValue);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return encrypted;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Decrypt fields in a record based on entity configuration
|
|
132
|
+
*/
|
|
133
|
+
async decryptRecord(entity, record) {
|
|
134
|
+
const config = this.configs.get(entity);
|
|
135
|
+
if (!config) {
|
|
136
|
+
return record; // No encryption config
|
|
137
|
+
}
|
|
138
|
+
const decrypted = { ...record };
|
|
139
|
+
for (const field of config.fields) {
|
|
140
|
+
if (field in record && record[field] !== null && record[field] !== undefined) {
|
|
141
|
+
try {
|
|
142
|
+
// Parse encrypted value
|
|
143
|
+
const encryptedValue = typeof record[field] === 'string'
|
|
144
|
+
? JSON.parse(record[field])
|
|
145
|
+
: record[field];
|
|
146
|
+
// Check if it's actually encrypted (has ciphertext and iv)
|
|
147
|
+
if (encryptedValue.ciphertext && encryptedValue.iv) {
|
|
148
|
+
// Decrypt the field
|
|
149
|
+
decrypted[field] = await this.decrypt(encryptedValue);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error(`Failed to decrypt field ${field}:`, error);
|
|
154
|
+
// Keep original value if decryption fails
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return decrypted;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check if a field should be encrypted
|
|
162
|
+
*/
|
|
163
|
+
shouldEncrypt(entity, field) {
|
|
164
|
+
const config = this.configs.get(entity);
|
|
165
|
+
return config ? config.fields.includes(field) : false;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get all encrypted fields for an entity
|
|
169
|
+
*/
|
|
170
|
+
getEncryptedFields(entity) {
|
|
171
|
+
const config = this.configs.get(entity);
|
|
172
|
+
return config ? config.fields : [];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Re-encrypt a record with a new key (for key rotation)
|
|
176
|
+
*/
|
|
177
|
+
async reencryptRecord(entity, record) {
|
|
178
|
+
// First decrypt with old keys
|
|
179
|
+
const decrypted = await this.decryptRecord(entity, record);
|
|
180
|
+
// Then encrypt with current key
|
|
181
|
+
return await this.encryptRecord(entity, decrypted);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Derive key material from master key
|
|
185
|
+
*/
|
|
186
|
+
async deriveKeyMaterial(masterKey) {
|
|
187
|
+
const keyBytes = new TextEncoder().encode(masterKey);
|
|
188
|
+
return await crypto.subtle.importKey('raw', keyBytes, 'PBKDF2', false, ['deriveKey']);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Convert ArrayBuffer to Base64
|
|
192
|
+
*/
|
|
193
|
+
arrayBufferToBase64(buffer) {
|
|
194
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
195
|
+
let binary = '';
|
|
196
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
197
|
+
binary += String.fromCharCode(bytes[i]);
|
|
198
|
+
}
|
|
199
|
+
return btoa(binary);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Convert Base64 to ArrayBuffer
|
|
203
|
+
*/
|
|
204
|
+
base64ToArrayBuffer(base64) {
|
|
205
|
+
const binary = atob(base64);
|
|
206
|
+
const bytes = new Uint8Array(binary.length);
|
|
207
|
+
for (let i = 0; i < binary.length; i++) {
|
|
208
|
+
bytes[i] = binary.charCodeAt(i);
|
|
209
|
+
}
|
|
210
|
+
return bytes;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Clear all encryption keys (security)
|
|
214
|
+
*/
|
|
215
|
+
clear() {
|
|
216
|
+
this.currentKey = null;
|
|
217
|
+
this.keyHistory.clear();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Global encryption manager instance
|
|
222
|
+
*/
|
|
223
|
+
export const encryptionManager = new EncryptionManager();
|
|
224
|
+
//# sourceMappingURL=encryption-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption-manager.js","sourceRoot":"","sources":["../../../../../core/src/encryption/encryption-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './auth';
|
|
2
|
+
export * from './sync';
|
|
3
|
+
export * from './access-rules';
|
|
4
|
+
export * from './access-rules/column-security';
|
|
5
|
+
export * from './realtime/subscription-manager';
|
|
6
|
+
export * from './realtime/change-notifier';
|
|
7
|
+
export * from './realtime/message-types';
|
|
8
|
+
export * from './sync/transaction-manager';
|
|
9
|
+
export * from './sync/batch-processor';
|
|
10
|
+
export * from './sync/csv-processor';
|
|
11
|
+
export * from './storage/file-manager';
|
|
12
|
+
export * from './webhooks/webhook-manager';
|
|
13
|
+
export * from './search/search-manager';
|
|
14
|
+
export * from './audit/audit-manager';
|
|
15
|
+
export * from './encryption/encryption-manager';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './auth';
|
|
2
|
+
export * from './sync';
|
|
3
|
+
export * from './access-rules';
|
|
4
|
+
export * from './access-rules/column-security';
|
|
5
|
+
export * from './realtime/subscription-manager';
|
|
6
|
+
export * from './realtime/change-notifier';
|
|
7
|
+
export * from './realtime/message-types';
|
|
8
|
+
export * from './sync/transaction-manager';
|
|
9
|
+
export * from './sync/batch-processor';
|
|
10
|
+
export * from './sync/csv-processor';
|
|
11
|
+
export * from './storage/file-manager';
|
|
12
|
+
export * from './webhooks/webhook-manager';
|
|
13
|
+
export * from './search/search-manager';
|
|
14
|
+
export * from './audit/audit-manager';
|
|
15
|
+
export * from './encryption/encryption-manager';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../core/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SubscriptionManager } from './subscription-manager';
|
|
2
|
+
import type { ChangeMessage } from './message-types';
|
|
3
|
+
import type { User } from '@edgebasejs/types';
|
|
4
|
+
export interface WebSocketClient {
|
|
5
|
+
send(message: string): void;
|
|
6
|
+
close(): void;
|
|
7
|
+
isOpen(): boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Notifies subscribed clients about data changes
|
|
11
|
+
* Manages broadcasting changes to WebSocket connections
|
|
12
|
+
*/
|
|
13
|
+
export declare class ChangeNotifier {
|
|
14
|
+
private subscriptionManager;
|
|
15
|
+
private clients;
|
|
16
|
+
constructor(subscriptionManager: SubscriptionManager);
|
|
17
|
+
/**
|
|
18
|
+
* Register a WebSocket client connection
|
|
19
|
+
*/
|
|
20
|
+
registerClient(connectionId: string, client: WebSocketClient): void;
|
|
21
|
+
/**
|
|
22
|
+
* Unregister a WebSocket client connection
|
|
23
|
+
*/
|
|
24
|
+
unregisterClient(connectionId: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Broadcast a change to all subscribed clients
|
|
27
|
+
*/
|
|
28
|
+
notifyChange(entity: string, operation: 'create' | 'update' | 'delete', record: Record<string, unknown>, recordId: string, user: User, version?: number): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Send a message to a specific connection
|
|
31
|
+
*/
|
|
32
|
+
private sendToConnection;
|
|
33
|
+
/**
|
|
34
|
+
* Broadcast a message to all clients
|
|
35
|
+
*/
|
|
36
|
+
broadcastToAll(message: ChangeMessage, filterSubscriptions?: string[]): void;
|
|
37
|
+
/**
|
|
38
|
+
* Send heartbeat to all connected clients
|
|
39
|
+
*/
|
|
40
|
+
sendHeartbeat(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Send error message to a specific client
|
|
43
|
+
*/
|
|
44
|
+
sendError(connectionId: string, code: string, message: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get connected clients count
|
|
47
|
+
*/
|
|
48
|
+
getConnectedClientsCount(): number;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=change-notifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-notifier.d.ts","sourceRoot":"","sources":["../../../../../core/src/realtime/change-notifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,cAAc;IAGb,OAAO,CAAC,mBAAmB;IAFvC,OAAO,CAAC,OAAO,CAAsC;gBAEjC,mBAAmB,EAAE,mBAAmB;IAE5D;;OAEG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI;IAInE;;OAEG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAI5C;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IA+BhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IA8B5E;;OAEG;IACH,aAAa,IAAI,IAAI;IAqBrB;;OAEG;IACH,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAoBpE;;OAEG;IACH,wBAAwB,IAAI,MAAM;CAGnC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notifies subscribed clients about data changes
|
|
3
|
+
* Manages broadcasting changes to WebSocket connections
|
|
4
|
+
*/
|
|
5
|
+
export class ChangeNotifier {
|
|
6
|
+
constructor(subscriptionManager) {
|
|
7
|
+
this.subscriptionManager = subscriptionManager;
|
|
8
|
+
this.clients = new Map();
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Register a WebSocket client connection
|
|
12
|
+
*/
|
|
13
|
+
registerClient(connectionId, client) {
|
|
14
|
+
this.clients.set(connectionId, client);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Unregister a WebSocket client connection
|
|
18
|
+
*/
|
|
19
|
+
unregisterClient(connectionId) {
|
|
20
|
+
this.clients.delete(connectionId);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Broadcast a change to all subscribed clients
|
|
24
|
+
*/
|
|
25
|
+
async notifyChange(entity, operation, record, recordId, user, version) {
|
|
26
|
+
const subscriptions = this.subscriptionManager.getSubscriptionsForEntity(entity);
|
|
27
|
+
for (const subscription of subscriptions) {
|
|
28
|
+
// Check if user has access (basic check - should be extended with full access rules)
|
|
29
|
+
// For now, assume user can see their own data
|
|
30
|
+
if (subscription.userId !== user.id) {
|
|
31
|
+
// In production, would check RLS rules here
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Check if subscription filters match the record
|
|
35
|
+
if (!this.subscriptionManager.matchesFilter(subscription, record)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// Send change message to client
|
|
39
|
+
const message = {
|
|
40
|
+
type: 'change',
|
|
41
|
+
entity,
|
|
42
|
+
operation,
|
|
43
|
+
record: operation !== 'delete' ? record : undefined,
|
|
44
|
+
recordId,
|
|
45
|
+
timestamp: Date.now(),
|
|
46
|
+
version,
|
|
47
|
+
};
|
|
48
|
+
this.sendToConnection(subscription.subscriptionId, message);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Send a message to a specific connection
|
|
53
|
+
*/
|
|
54
|
+
sendToConnection(subscriptionId, message) {
|
|
55
|
+
const subscription = this.subscriptionManager.getSubscription(subscriptionId);
|
|
56
|
+
if (!subscription)
|
|
57
|
+
return;
|
|
58
|
+
// Find the connection for this subscription
|
|
59
|
+
const subscriptions = this.subscriptionManager.getSubscriptionsForEntity(subscription.entity);
|
|
60
|
+
const matchingSub = subscriptions.find((s) => s.subscriptionId === subscriptionId);
|
|
61
|
+
if (!matchingSub)
|
|
62
|
+
return;
|
|
63
|
+
// This is a placeholder - in actual implementation, we'd need to track
|
|
64
|
+
// which connection ID corresponds to which subscription
|
|
65
|
+
// For now, we'll send to all connections and let them filter
|
|
66
|
+
this.broadcastToAll(message, [subscriptionId]);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Broadcast a message to all clients
|
|
70
|
+
*/
|
|
71
|
+
broadcastToAll(message, filterSubscriptions) {
|
|
72
|
+
const messageStr = JSON.stringify(message);
|
|
73
|
+
for (const [connectionId, client] of this.clients.entries()) {
|
|
74
|
+
if (!client.isOpen()) {
|
|
75
|
+
this.unregisterClient(connectionId);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
// If filter subscriptions provided, only send to relevant clients
|
|
79
|
+
if (filterSubscriptions) {
|
|
80
|
+
const subscriptions = this.subscriptionManager.getSubscriptionsForConnection(connectionId);
|
|
81
|
+
const hasMatchingSubscription = subscriptions.some((sub) => filterSubscriptions.includes(sub.subscriptionId));
|
|
82
|
+
if (!hasMatchingSubscription) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
client.send(messageStr);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error(`Failed to send message to client ${connectionId}:`, error);
|
|
91
|
+
this.unregisterClient(connectionId);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Send heartbeat to all connected clients
|
|
97
|
+
*/
|
|
98
|
+
sendHeartbeat() {
|
|
99
|
+
const heartbeatMsg = JSON.stringify({
|
|
100
|
+
type: 'heartbeat',
|
|
101
|
+
timestamp: Date.now(),
|
|
102
|
+
});
|
|
103
|
+
for (const [connectionId, client] of this.clients.entries()) {
|
|
104
|
+
if (!client.isOpen()) {
|
|
105
|
+
this.unregisterClient(connectionId);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
client.send(heartbeatMsg);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error(`Failed to send heartbeat to client ${connectionId}:`, error);
|
|
113
|
+
this.unregisterClient(connectionId);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Send error message to a specific client
|
|
119
|
+
*/
|
|
120
|
+
sendError(connectionId, code, message) {
|
|
121
|
+
const client = this.clients.get(connectionId);
|
|
122
|
+
if (!client || !client.isOpen()) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const errorMsg = JSON.stringify({
|
|
126
|
+
type: 'error',
|
|
127
|
+
code,
|
|
128
|
+
message,
|
|
129
|
+
});
|
|
130
|
+
try {
|
|
131
|
+
client.send(errorMsg);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
console.error(`Failed to send error to client ${connectionId}:`, error);
|
|
135
|
+
this.unregisterClient(connectionId);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get connected clients count
|
|
140
|
+
*/
|
|
141
|
+
getConnectedClientsCount() {
|
|
142
|
+
return this.clients.size;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=change-notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"change-notifier.js","sourceRoot":"","sources":["../../../../../core/src/realtime/change-notifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket message types for real-time subscriptions
|
|
3
|
+
*/
|
|
4
|
+
export type SubscriptionMessage = SubscribeMessage | UnsubscribeMessage | ChangeMessage | ErrorMessage | HeartbeatMessage;
|
|
5
|
+
export interface SubscribeMessage {
|
|
6
|
+
type: 'subscribe';
|
|
7
|
+
entity: string;
|
|
8
|
+
filters?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface UnsubscribeMessage {
|
|
11
|
+
type: 'unsubscribe';
|
|
12
|
+
entity: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ChangeMessage {
|
|
15
|
+
type: 'change';
|
|
16
|
+
entity: string;
|
|
17
|
+
operation: 'create' | 'update' | 'delete';
|
|
18
|
+
record?: Record<string, unknown>;
|
|
19
|
+
recordId?: string;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
version?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ErrorMessage {
|
|
24
|
+
type: 'error';
|
|
25
|
+
code: string;
|
|
26
|
+
message: string;
|
|
27
|
+
}
|
|
28
|
+
export interface HeartbeatMessage {
|
|
29
|
+
type: 'heartbeat';
|
|
30
|
+
timestamp: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SubscriptionState {
|
|
33
|
+
subscriptionId: string;
|
|
34
|
+
userId: string;
|
|
35
|
+
entity: string;
|
|
36
|
+
filters?: Record<string, unknown>;
|
|
37
|
+
createdAt: number;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=message-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-types.d.ts","sourceRoot":"","sources":["../../../../../core/src/realtime/message-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,mBAAmB,GAC3B,gBAAgB,GAChB,kBAAkB,GAClB,aAAa,GACb,YAAY,GACZ,gBAAgB,CAAC;AAErB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-types.js","sourceRoot":"","sources":["../../../../../core/src/realtime/message-types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { SyncDatabase } from '../sync/sync-engine';
|
|
2
|
+
import type { SubscriptionState } from './message-types';
|
|
3
|
+
/**
|
|
4
|
+
* Manages active WebSocket subscriptions
|
|
5
|
+
* Tracks which clients are subscribed to which entities and filters
|
|
6
|
+
*/
|
|
7
|
+
export declare class SubscriptionManager {
|
|
8
|
+
private db;
|
|
9
|
+
private subscriptions;
|
|
10
|
+
private userSubscriptions;
|
|
11
|
+
private entitySubscriptions;
|
|
12
|
+
private connectionSubscriptions;
|
|
13
|
+
constructor(db: SyncDatabase);
|
|
14
|
+
/**
|
|
15
|
+
* Create a new subscription
|
|
16
|
+
*/
|
|
17
|
+
subscribe(userId: string, connectionId: string, entity: string, filters?: Record<string, unknown>): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Remove a subscription
|
|
20
|
+
*/
|
|
21
|
+
unsubscribe(subscriptionId: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Remove all subscriptions for a connection
|
|
24
|
+
*/
|
|
25
|
+
disconnectClient(connectionId: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Get all subscriptions for an entity
|
|
28
|
+
*/
|
|
29
|
+
getSubscriptionsForEntity(entity: string): SubscriptionState[];
|
|
30
|
+
/**
|
|
31
|
+
* Get all subscriptions for a user
|
|
32
|
+
*/
|
|
33
|
+
getSubscriptionsForUser(userId: string): SubscriptionState[];
|
|
34
|
+
/**
|
|
35
|
+
* Get all subscriptions for a connection
|
|
36
|
+
*/
|
|
37
|
+
getSubscriptionsForConnection(connectionId: string): SubscriptionState[];
|
|
38
|
+
/**
|
|
39
|
+
* Update last heartbeat for a subscription
|
|
40
|
+
*/
|
|
41
|
+
updateHeartbeat(subscriptionId: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Get subscription by ID
|
|
44
|
+
*/
|
|
45
|
+
getSubscription(subscriptionId: string): SubscriptionState | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Check if a subscription matches a filter
|
|
48
|
+
*/
|
|
49
|
+
matchesFilter(subscription: SubscriptionState, data: Record<string, unknown>): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Load subscriptions from database on startup
|
|
52
|
+
*/
|
|
53
|
+
loadFromDatabase(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Cleanup expired subscriptions
|
|
56
|
+
*/
|
|
57
|
+
cleanup(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Get subscription statistics
|
|
60
|
+
*/
|
|
61
|
+
getStats(): {
|
|
62
|
+
totalSubscriptions: number;
|
|
63
|
+
activeConnections: number;
|
|
64
|
+
entitiesWithSubscriptions: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=subscription-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription-manager.d.ts","sourceRoot":"","sources":["../../../../../core/src/realtime/subscription-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;;GAGG;AACH,qBAAa,mBAAmB;IAMlB,OAAO,CAAC,EAAE;IALtB,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,mBAAmB,CAAkC;IAC7D,OAAO,CAAC,uBAAuB,CAAkC;gBAE7C,EAAE,EAAE,YAAY;IAEpC;;OAEG;IACG,SAAS,CACb,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,MAAM,CAAC;IAqDlB;;OAEG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBxD;;OAEG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3D;;OAEG;IACH,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAS9D;;OAEG;IACH,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAS5D;;OAEG;IACH,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,EAAE;IASxE;;OAEG;IACG,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5D;;OAEG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAItE;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAatF;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA4DvC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB9B;;OAEG;IACH,QAAQ,IAAI;QACV,kBAAkB,EAAE,MAAM,CAAC;QAC3B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,yBAAyB,EAAE,MAAM,CAAC;KACnC;CAOF"}
|