@interocitor/core 0.0.0-beta.2

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 (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +178 -0
  3. package/dist/adapters/cloudflare.d.ts +72 -0
  4. package/dist/adapters/cloudflare.d.ts.map +1 -0
  5. package/dist/adapters/cloudflare.js +227 -0
  6. package/dist/adapters/cloudflare.js.map +1 -0
  7. package/dist/adapters/google-drive.d.ts +64 -0
  8. package/dist/adapters/google-drive.d.ts.map +1 -0
  9. package/dist/adapters/google-drive.js +340 -0
  10. package/dist/adapters/google-drive.js.map +1 -0
  11. package/dist/adapters/memory.d.ts +45 -0
  12. package/dist/adapters/memory.d.ts.map +1 -0
  13. package/dist/adapters/memory.js +129 -0
  14. package/dist/adapters/memory.js.map +1 -0
  15. package/dist/adapters/webdav.d.ts +59 -0
  16. package/dist/adapters/webdav.d.ts.map +1 -0
  17. package/dist/adapters/webdav.js +247 -0
  18. package/dist/adapters/webdav.js.map +1 -0
  19. package/dist/core/codec.d.ts +20 -0
  20. package/dist/core/codec.d.ts.map +1 -0
  21. package/dist/core/codec.js +66 -0
  22. package/dist/core/codec.js.map +1 -0
  23. package/dist/core/compaction.d.ts +37 -0
  24. package/dist/core/compaction.d.ts.map +1 -0
  25. package/dist/core/compaction.js +134 -0
  26. package/dist/core/compaction.js.map +1 -0
  27. package/dist/core/crdt.d.ts +33 -0
  28. package/dist/core/crdt.d.ts.map +1 -0
  29. package/dist/core/crdt.js +188 -0
  30. package/dist/core/crdt.js.map +1 -0
  31. package/dist/core/flush.d.ts +9 -0
  32. package/dist/core/flush.d.ts.map +1 -0
  33. package/dist/core/flush.js +41 -0
  34. package/dist/core/flush.js.map +1 -0
  35. package/dist/core/hlc.d.ts +25 -0
  36. package/dist/core/hlc.d.ts.map +1 -0
  37. package/dist/core/hlc.js +76 -0
  38. package/dist/core/hlc.js.map +1 -0
  39. package/dist/core/internals.d.ts +25 -0
  40. package/dist/core/internals.d.ts.map +1 -0
  41. package/dist/core/internals.js +54 -0
  42. package/dist/core/internals.js.map +1 -0
  43. package/dist/core/manifest.d.ts +31 -0
  44. package/dist/core/manifest.d.ts.map +1 -0
  45. package/dist/core/manifest.js +111 -0
  46. package/dist/core/manifest.js.map +1 -0
  47. package/dist/core/pull.d.ts +26 -0
  48. package/dist/core/pull.d.ts.map +1 -0
  49. package/dist/core/pull.js +98 -0
  50. package/dist/core/pull.js.map +1 -0
  51. package/dist/core/row-id.d.ts +12 -0
  52. package/dist/core/row-id.d.ts.map +1 -0
  53. package/dist/core/row-id.js +12 -0
  54. package/dist/core/row-id.js.map +1 -0
  55. package/dist/core/schema-types.d.ts +13 -0
  56. package/dist/core/schema-types.d.ts.map +1 -0
  57. package/dist/core/schema-types.js +18 -0
  58. package/dist/core/schema-types.js.map +1 -0
  59. package/dist/core/schema-types.type-test.d.ts +2 -0
  60. package/dist/core/schema-types.type-test.d.ts.map +1 -0
  61. package/dist/core/schema-types.type-test.js +149 -0
  62. package/dist/core/schema-types.type-test.js.map +1 -0
  63. package/dist/core/sync-engine.d.ts +158 -0
  64. package/dist/core/sync-engine.d.ts.map +1 -0
  65. package/dist/core/sync-engine.js +714 -0
  66. package/dist/core/sync-engine.js.map +1 -0
  67. package/dist/core/table.d.ts +60 -0
  68. package/dist/core/table.d.ts.map +1 -0
  69. package/dist/core/table.js +106 -0
  70. package/dist/core/table.js.map +1 -0
  71. package/dist/core/types.d.ts +478 -0
  72. package/dist/core/types.d.ts.map +1 -0
  73. package/dist/core/types.js +7 -0
  74. package/dist/core/types.js.map +1 -0
  75. package/dist/crypto/encryption.d.ts +57 -0
  76. package/dist/crypto/encryption.d.ts.map +1 -0
  77. package/dist/crypto/encryption.js +195 -0
  78. package/dist/crypto/encryption.js.map +1 -0
  79. package/dist/crypto/keys.d.ts +48 -0
  80. package/dist/crypto/keys.d.ts.map +1 -0
  81. package/dist/crypto/keys.js +55 -0
  82. package/dist/crypto/keys.js.map +1 -0
  83. package/dist/handshake/channel.d.ts +117 -0
  84. package/dist/handshake/channel.d.ts.map +1 -0
  85. package/dist/handshake/channel.js +246 -0
  86. package/dist/handshake/channel.js.map +1 -0
  87. package/dist/handshake/index.d.ts +213 -0
  88. package/dist/handshake/index.d.ts.map +1 -0
  89. package/dist/handshake/index.js +182 -0
  90. package/dist/handshake/index.js.map +1 -0
  91. package/dist/handshake/qr.d.ts +100 -0
  92. package/dist/handshake/qr.d.ts.map +1 -0
  93. package/dist/handshake/qr.js +103 -0
  94. package/dist/handshake/qr.js.map +1 -0
  95. package/dist/index.d.ts +46 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +46 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/storage/credential-store.d.ts +99 -0
  100. package/dist/storage/credential-store.d.ts.map +1 -0
  101. package/dist/storage/credential-store.js +309 -0
  102. package/dist/storage/credential-store.js.map +1 -0
  103. package/dist/storage/local-store.d.ts +56 -0
  104. package/dist/storage/local-store.d.ts.map +1 -0
  105. package/dist/storage/local-store.js +411 -0
  106. package/dist/storage/local-store.js.map +1 -0
  107. package/package.json +68 -0
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Credential Store — pluggable persistence for key material.
3
+ *
4
+ * Safari ITP wipes localStorage after 7 days of inactivity.
5
+ * That kills the passphrase and device ID. Lost key = lost data.
6
+ *
7
+ * This module provides:
8
+ * - `LocalStorageCredentialStore` — current behaviour, extracted.
9
+ * - `WebAuthnCredentialStore` — OS keychain via navigator.credentials + largeBlob.
10
+ * - `createCredentialStore()` — auto-detects best backend.
11
+ *
12
+ * The engine uses `CredentialStore` for all key material persistence.
13
+ * Apps never touch this directly unless they want a custom backend.
14
+ */
15
+ // ─── localStorage backend ────────────────────────────────────────────
16
+ export class LocalStorageCredentialStore {
17
+ constructor(dbName) {
18
+ this.dbName = dbName;
19
+ }
20
+ keyKey() { return `interocitor-key:${this.dbName}`; }
21
+ get deviceKey() { return 'interocitor-device-id'; }
22
+ async save(creds) {
23
+ localStorage.setItem(this.keyKey(), creds.passphrase);
24
+ localStorage.setItem(this.deviceKey, creds.deviceId);
25
+ }
26
+ async load() {
27
+ const passphrase = localStorage.getItem(this.keyKey());
28
+ const deviceId = localStorage.getItem(this.deviceKey);
29
+ if (!passphrase || !deviceId)
30
+ return null;
31
+ return { passphrase, deviceId };
32
+ }
33
+ async clear() {
34
+ localStorage.removeItem(this.keyKey());
35
+ // Device ID intentionally kept — shared across meshes, survives credential clear.
36
+ }
37
+ }
38
+ // ─── WebAuthn + largeBlob backend ────────────────────────────────────
39
+ /**
40
+ * Stores credentials in the OS keychain via WebAuthn `largeBlob` extension.
41
+ *
42
+ * Survives Safari ITP, browser data clears, and profile resets.
43
+ * Requires a platform authenticator with largeBlob support (Touch ID,
44
+ * Face ID, Windows Hello). Falls back gracefully — `save()` rejects
45
+ * if the authenticator doesn't support largeBlob.
46
+ *
47
+ * Flow:
48
+ * 1. `save()` → `navigator.credentials.create()` with largeBlob write.
49
+ * User sees a biometric prompt. Credential ID stored in localStorage
50
+ * as a hint for faster `load()`, but not required.
51
+ * 2. `load()` → `navigator.credentials.get()` with largeBlob read.
52
+ * User sees a biometric prompt. Returns the blob.
53
+ * 3. If localStorage hint is gone (ITP wipe), load uses an empty
54
+ * allowCredentials list — the authenticator picks the right one.
55
+ */
56
+ export class WebAuthnCredentialStore {
57
+ constructor(dbName, rpId = globalThis.location?.hostname ?? 'localhost',
58
+ /** Human-readable app name shown in biometric prompts and OS keychain. */
59
+ displayName = 'Interocitor') {
60
+ this.dbName = dbName;
61
+ this.rpId = rpId;
62
+ this.displayName = displayName;
63
+ this.encoder = new TextEncoder();
64
+ this.decoder = new TextDecoder();
65
+ }
66
+ credIdKey() {
67
+ return `${WebAuthnCredentialStore.CRED_ID_KEY_PREFIX}${this.dbName}`;
68
+ }
69
+ encode(creds) {
70
+ return this.encoder.encode(JSON.stringify(creds));
71
+ }
72
+ decode(blob) {
73
+ return JSON.parse(this.decoder.decode(blob));
74
+ }
75
+ /** Read credential ID hint from localStorage (best-effort, survives only if ITP hasn't wiped). */
76
+ loadCredentialIdHint() {
77
+ try {
78
+ const stored = localStorage.getItem(this.credIdKey());
79
+ if (!stored)
80
+ return null;
81
+ const raw = Uint8Array.from(atob(stored), c => c.charCodeAt(0));
82
+ return raw.buffer;
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ saveCredentialIdHint(rawId) {
89
+ try {
90
+ const bytes = new Uint8Array(rawId);
91
+ let binary = '';
92
+ for (let i = 0; i < bytes.length; i++)
93
+ binary += String.fromCharCode(bytes[i]);
94
+ const b64 = btoa(binary);
95
+ localStorage.setItem(this.credIdKey(), b64);
96
+ }
97
+ catch { /* best-effort */ }
98
+ }
99
+ async save(creds) {
100
+ const blob = this.encode(creds);
101
+ const challenge = crypto.getRandomValues(new Uint8Array(32));
102
+ const userId = crypto.getRandomValues(new Uint8Array(16));
103
+ const credential = await navigator.credentials.create({
104
+ publicKey: {
105
+ rp: { name: this.displayName, id: this.rpId },
106
+ user: {
107
+ id: userId,
108
+ name: `${this.displayName.toLowerCase().replaceAll(/\s+/g, '-')}:${this.dbName}`,
109
+ displayName: this.displayName,
110
+ },
111
+ challenge,
112
+ pubKeyCredParams: [
113
+ { type: 'public-key', alg: -7 }, // ES256
114
+ { type: 'public-key', alg: -257 }, // RS256
115
+ ],
116
+ authenticatorSelection: {
117
+ authenticatorAttachment: 'platform',
118
+ residentKey: 'required',
119
+ userVerification: 'required',
120
+ },
121
+ extensions: {
122
+ largeBlob: { support: 'required' },
123
+ },
124
+ },
125
+ });
126
+ if (!credential)
127
+ throw new Error('WebAuthn credential creation cancelled');
128
+ // Write the blob in a separate get() call — largeBlob write requires
129
+ // an assertion, not registration, on most platforms.
130
+ this.saveCredentialIdHint(credential.rawId);
131
+ await this.writeLargeBlob(credential.rawId, blob);
132
+ }
133
+ async writeLargeBlob(credentialId, blob) {
134
+ const challenge = crypto.getRandomValues(new Uint8Array(32));
135
+ const assertion = await navigator.credentials.get({
136
+ publicKey: {
137
+ challenge,
138
+ rpId: this.rpId,
139
+ allowCredentials: [{
140
+ type: 'public-key',
141
+ id: credentialId,
142
+ }],
143
+ userVerification: 'required',
144
+ extensions: {
145
+ largeBlob: { write: blob },
146
+ },
147
+ },
148
+ });
149
+ if (!assertion)
150
+ throw new Error('WebAuthn assertion cancelled');
151
+ const results = assertion.getClientExtensionResults?.();
152
+ if (!results?.largeBlob?.written) {
153
+ throw new Error('largeBlob write failed — authenticator may not support it');
154
+ }
155
+ }
156
+ async load() {
157
+ const challenge = crypto.getRandomValues(new Uint8Array(32));
158
+ const credentialIdHint = this.loadCredentialIdHint();
159
+ const assertion = await navigator.credentials.get({
160
+ publicKey: {
161
+ challenge,
162
+ rpId: this.rpId,
163
+ // If we have the hint, scope to it. Otherwise let the authenticator
164
+ // show all resident credentials for this RP (discoverable flow).
165
+ allowCredentials: credentialIdHint
166
+ ? [{ type: 'public-key', id: credentialIdHint }]
167
+ : [],
168
+ userVerification: 'required',
169
+ extensions: {
170
+ largeBlob: { read: true },
171
+ },
172
+ },
173
+ });
174
+ if (!assertion)
175
+ return null;
176
+ const results = assertion.getClientExtensionResults?.();
177
+ const blob = results?.largeBlob?.blob;
178
+ if (!blob)
179
+ return null;
180
+ // Got credentials back — re-save the hint in case localStorage was wiped.
181
+ this.saveCredentialIdHint(assertion.rawId);
182
+ return this.decode(blob);
183
+ }
184
+ async clear() {
185
+ // Can't programmatically delete WebAuthn credentials.
186
+ // Remove the localStorage hint; the credential stays in the keychain
187
+ // but won't be found without the hint (or user manually picks it).
188
+ try {
189
+ localStorage.removeItem(this.credIdKey());
190
+ }
191
+ catch { /* ok */ }
192
+ }
193
+ }
194
+ WebAuthnCredentialStore.CRED_ID_KEY_PREFIX = 'interocitor-cred:';
195
+ // ─── Auto-detection ──────────────────────────────────────────────────
196
+ /** Check if WebAuthn with largeBlob is likely available. */
197
+ async function isWebAuthnLargeBlobAvailable() {
198
+ if (globalThis.PublicKeyCredential === undefined)
199
+ return false;
200
+ try {
201
+ // Check platform authenticator availability
202
+ const available = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
203
+ if (!available)
204
+ return false;
205
+ // No standard way to check largeBlob support without creating a credential.
206
+ // We rely on the 'required' support flag during create() to fail fast.
207
+ return true;
208
+ }
209
+ catch {
210
+ return false;
211
+ }
212
+ }
213
+ /**
214
+ * Create the best available credential store.
215
+ *
216
+ * Prefers WebAuthn (survives ITP) when available, falls back to
217
+ * localStorage. Returns a `FallbackCredentialStore` that tries
218
+ * WebAuthn first and uses localStorage as backup on every operation.
219
+ */
220
+ export function createCredentialStore(dbName, displayName) {
221
+ return new FallbackCredentialStore(dbName, displayName);
222
+ }
223
+ /**
224
+ * Tries WebAuthn on save/load; falls back to localStorage on failure.
225
+ *
226
+ * Save: always writes localStorage (silent). WebAuthn only written via
227
+ * explicit `secureWithBiometrics()` call — never automatically on first
228
+ * key generation. This avoids a confusing biometric prompt on first open.
229
+ *
230
+ * Load: tries localStorage first (fast). If empty (ITP wipe?), tries
231
+ * WebAuthn recovery (biometric prompt — user understands why at this point).
232
+ */
233
+ class FallbackCredentialStore {
234
+ constructor(dbName, displayName) {
235
+ this.dbName = dbName;
236
+ this.displayName = displayName;
237
+ this.webauthn = null;
238
+ this.webauthnChecked = false;
239
+ this.ls = new LocalStorageCredentialStore(dbName);
240
+ }
241
+ async getWebAuthn() {
242
+ if (this.webauthnChecked)
243
+ return this.webauthn;
244
+ this.webauthnChecked = true;
245
+ if (await isWebAuthnLargeBlobAvailable()) {
246
+ this.webauthn = new WebAuthnCredentialStore(this.dbName, undefined, this.displayName);
247
+ }
248
+ return this.webauthn;
249
+ }
250
+ async save(creds) {
251
+ // Save to localStorage only (silent, no prompt).
252
+ // WebAuthn enrollment happens via secureWithBiometrics().
253
+ await this.ls.save(creds);
254
+ }
255
+ /**
256
+ * Persist current credentials to the OS keychain via biometrics.
257
+ * Call this when the user takes an intentional action — after pairing,
258
+ * after a "Secure my keys" button press, etc. Not on first open.
259
+ *
260
+ * Returns true if saved, false if WebAuthn unavailable or user cancelled.
261
+ */
262
+ async secureWithBiometrics() {
263
+ const creds = await this.ls.load();
264
+ if (!creds)
265
+ return false;
266
+ const wa = await this.getWebAuthn();
267
+ if (!wa)
268
+ return false;
269
+ try {
270
+ await wa.save(creds);
271
+ return true;
272
+ }
273
+ catch {
274
+ return false;
275
+ }
276
+ }
277
+ async load() {
278
+ // Silent primary path only. No biometric prompt here.
279
+ return this.ls.load();
280
+ }
281
+ async restoreWithBiometrics() {
282
+ const wa = await this.getWebAuthn();
283
+ if (!wa)
284
+ return null;
285
+ try {
286
+ const restored = await wa.load();
287
+ if (restored) {
288
+ // Re-populate localStorage for normal silent opens after restore.
289
+ await this.ls.save(restored);
290
+ return restored;
291
+ }
292
+ }
293
+ catch {
294
+ // unavailable / cancelled / not found
295
+ }
296
+ return null;
297
+ }
298
+ async clear() {
299
+ await this.ls.clear();
300
+ const wa = await this.getWebAuthn();
301
+ if (wa) {
302
+ try {
303
+ await wa.clear();
304
+ }
305
+ catch { /* best-effort */ }
306
+ }
307
+ }
308
+ }
309
+ //# sourceMappingURL=credential-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/storage/credential-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Local storage layer — IndexedDB
3
+ *
4
+ * This is a cache, not the source of truth.
5
+ * If cleared, the app rehydrates from cloud.
6
+ *
7
+ * Stores:
8
+ * - rows: the current merged state of all tables
9
+ * - outbox: change entries pending upload
10
+ * - cursors: byte offsets into each device's change log
11
+ * - meta: device ID, last snapshot epoch, etc.
12
+ */
13
+ import type { Row, ChangeEntry, LocalStoreAdapter, DatabaseSchemaDefinition, WhereClause } from '../core/types.ts';
14
+ /**
15
+ * Default IndexedDB-backed local persistence layer used by {@link SyncEngine}.
16
+ *
17
+ * Most applications do not need to interact with this class directly unless
18
+ * they are supplying a custom `localStoreFactory` or swapping local storage at
19
+ * runtime for testing or advanced integrations.
20
+ */
21
+ export declare class LocalStore implements LocalStoreAdapter {
22
+ private db;
23
+ private readonly dbName;
24
+ private readonly dbVersion;
25
+ private readonly schema?;
26
+ /**
27
+ * @param dbName IndexedDB database name. Use distinct names to isolate
28
+ * multiple engine instances on the same origin.
29
+ * Default: "interocitor"
30
+ * @param dbVersion IndexedDB schema version. Default: 1
31
+ */
32
+ constructor(dbName?: string, dbVersion?: number, schema?: DatabaseSchemaDefinition);
33
+ open(): Promise<void>;
34
+ close(): void;
35
+ private ensureDB;
36
+ private rowKey;
37
+ getRow(table: string, rowId: string): Promise<Row | undefined>;
38
+ putRow(row: Row): Promise<void>;
39
+ putRows(rows: Row[]): Promise<void>;
40
+ getTable(table: string): Promise<Row[]>;
41
+ queryWhere(table: string, clause: WhereClause): Promise<Row[]>;
42
+ getTableNames(): Promise<string[]>;
43
+ getAllRows(): Promise<Row[]>;
44
+ clearRows(): Promise<void>;
45
+ pushOutbox(entry: ChangeEntry): Promise<void>;
46
+ drainOutbox(): Promise<ChangeEntry[]>;
47
+ outboxSize(): Promise<number>;
48
+ getCursor(deviceId: string): Promise<number>;
49
+ setCursor(deviceId: string, offset: number): Promise<void>;
50
+ getAllCursors(): Promise<Record<string, number>>;
51
+ getMeta(key: string): Promise<unknown>;
52
+ setMeta(key: string, value: unknown): Promise<void>;
53
+ /** Nuke everything. Used before full rehydration. */
54
+ clearAll(): Promise<void>;
55
+ }
56
+ //# sourceMappingURL=local-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["../../src/storage/local-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,GAAG,EACH,WAAW,EACX,iBAAiB,EACjB,wBAAwB,EAGxB,WAAW,EAEZ,MAAM,kBAAkB,CAAC;AA0O1B;;;;;;GAMG;AACH,qBAAa,UAAW,YAAW,iBAAiB;IAClD,OAAO,CAAC,EAAE,CAA4B;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA2B;IAEnD;;;;;OAKG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,wBAAwB;IAO5E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,MAAM;IAIR,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC;IAQ9D,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/B,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IASvC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAgC9D,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAelC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAO5B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAS1B,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7C,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAUrC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ7B,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO5C,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1D,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAehD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMtC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzD,qDAAqD;IAC/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAQhC"}