memorio 4.9.35 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +95 -516
  3. package/SECURITY.md +159 -33
  4. package/SUMMARY.md +59 -45
  5. package/adr/001-state-proxy-model.md +95 -0
  6. package/adr/002-observer-semantics.md +179 -0
  7. package/adr/003-deep-mutation-semantics.md +128 -0
  8. package/adr/004-array-mutation-semantics.md +127 -0
  9. package/adr/005-scheduler-contract.md +148 -0
  10. package/adr/006-context-isolation.md +91 -0
  11. package/adr/007-mutation-records.md +117 -0
  12. package/adr/008-transactions.md +105 -0
  13. package/adr/009-history-model.md +109 -0
  14. package/adr/README.md +46 -0
  15. package/adr/template.md +48 -0
  16. package/bin/cli.js +68 -0
  17. package/examples/basic.ts +115 -115
  18. package/examples/browser-vanilla.html +358 -358
  19. package/examples/cache.ts +72 -72
  20. package/examples/cross-platform-guards.ts +57 -57
  21. package/examples/history.ts +104 -0
  22. package/examples/idb.ts +109 -109
  23. package/examples/multi-tenant-context.ts +44 -44
  24. package/examples/node-server.ts +308 -308
  25. package/examples/observer.ts +60 -60
  26. package/examples/platform.ts +115 -115
  27. package/examples/react-app.tsx +362 -362
  28. package/examples/react-observer.tsx +63 -63
  29. package/examples/semantic-memory.ts +60 -60
  30. package/examples/session-advanced.ts +91 -91
  31. package/examples/sqlite-batched-writes.ts +57 -57
  32. package/examples/state-advanced.ts +89 -89
  33. package/examples/store-advanced.ts +117 -117
  34. package/examples/sync.ts +90 -0
  35. package/examples/typed-and-schema.ts +102 -100
  36. package/examples/useObserver.tsx +140 -141
  37. package/global.cjs +5733 -0
  38. package/global.d.ts +8 -0
  39. package/global.js +5667 -0
  40. package/index.cjs +2202 -1041
  41. package/index.d.ts +2 -0
  42. package/index.js +2178 -1040
  43. package/llms.txt +113 -8
  44. package/markdown/AUDIT-REPORT.md +134 -0
  45. package/markdown/CACHE.md +191 -0
  46. package/markdown/DEVTOOLS.md +128 -0
  47. package/markdown/DISPATCH.md +176 -0
  48. package/markdown/HISTORY.md +198 -0
  49. package/markdown/IDB.md +177 -0
  50. package/markdown/IMPORT.md +152 -0
  51. package/markdown/INSPECT.md +122 -0
  52. package/markdown/LOGGER.md +153 -0
  53. package/markdown/MEMORY-ATTACHMENT.md +95 -0
  54. package/markdown/MEMORY.md +161 -0
  55. package/markdown/OBSERVER.md +208 -0
  56. package/markdown/PLATFORM.md +277 -0
  57. package/markdown/REDUX.md +54 -0
  58. package/markdown/SCHEMA.md +175 -0
  59. package/markdown/SESSION.md +164 -0
  60. package/markdown/SQLITE.md +189 -0
  61. package/markdown/STATE.md +159 -0
  62. package/markdown/STORE.md +170 -0
  63. package/markdown/SYNC.md +318 -0
  64. package/markdown/TYPED.md +164 -0
  65. package/markdown/USEOBSERVER.md +256 -0
  66. package/modules/redux.cjs +701 -177
  67. package/modules/redux.cjs.map +1 -1
  68. package/modules/redux.js +701 -177
  69. package/modules/redux.js.map +1 -1
  70. package/package.json +26 -4
  71. package/types/broadcast.d.ts +61 -0
  72. package/types/computed.d.ts +96 -0
  73. package/types/encryption.d.ts +129 -0
  74. package/types/env.d.ts +19 -9
  75. package/types/exports.d.ts +29 -0
  76. package/types/history.d.ts +13 -1
  77. package/types/memorio.d.ts +25 -6
  78. package/types/mutation.d.ts +75 -0
  79. package/types/security.d.ts +67 -0
  80. package/types/session.d.ts +23 -5
  81. package/types/store.d.ts +19 -3
  82. package/vsix/memorio.vsix +0 -0
package/modules/redux.cjs CHANGED
@@ -178,7 +178,10 @@ var DEV;
178
178
  var init_env = __esm({
179
179
  "core/env.ts"() {
180
180
  init_cjs_shims();
181
- DEV = typeof process !== "undefined" ? false : true;
181
+ DEV = false ;
182
+ if (typeof globalThis !== "undefined") {
183
+ globalThis["__DEV__"] = DEV;
184
+ }
182
185
  }
183
186
  });
184
187
 
@@ -198,6 +201,241 @@ var init_message = __esm({
198
201
  }
199
202
  });
200
203
 
204
+ // functions/encryption/index.ts
205
+ function _hasWebCrypto() {
206
+ const g2 = globalThis;
207
+ return typeof g2.crypto !== "undefined" && typeof g2.crypto.subtle !== "undefined" && typeof g2.crypto.subtle.encrypt === "function";
208
+ }
209
+ function _b64encode(buf) {
210
+ const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
211
+ if (typeof btoa === "function") {
212
+ let binary = "";
213
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
214
+ return btoa(binary);
215
+ }
216
+ if (typeof Buffer !== "undefined") {
217
+ return Buffer.from(bytes).toString("base64");
218
+ }
219
+ return "";
220
+ }
221
+ function _b64decode(b64) {
222
+ if (typeof Buffer !== "undefined") {
223
+ return new Uint8Array(Buffer.from(b64, "base64"));
224
+ }
225
+ if (typeof atob === "function") {
226
+ const binary = atob(b64);
227
+ const out = new Uint8Array(binary.length);
228
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
229
+ return out;
230
+ }
231
+ throw new Error("memorio encryption: no base64 decoder available");
232
+ }
233
+ function _isEncrypted(value) {
234
+ return typeof value === "object" && value !== null && value.__memorio_encrypted === true && typeof value.alg === "string";
235
+ }
236
+ var AES_GCM, PBKDF2_ITERATIONS, encryption;
237
+ var init_encryption = __esm({
238
+ "functions/encryption/index.ts"() {
239
+ init_cjs_shims();
240
+ init_env();
241
+ init_message();
242
+ __name(_hasWebCrypto, "_hasWebCrypto");
243
+ __name(_b64encode, "_b64encode");
244
+ __name(_b64decode, "_b64decode");
245
+ __name(_isEncrypted, "_isEncrypted");
246
+ AES_GCM = { name: "AES-GCM", length: 256 };
247
+ PBKDF2_ITERATIONS = 6e5;
248
+ encryption = {
249
+ ///
250
+ // Capability detection
251
+ ///
252
+ isAvailable() {
253
+ return _hasWebCrypto();
254
+ },
255
+ ///
256
+ // Derive a CryptoKey from a password using PBKDF2.
257
+ //
258
+ // @param password The password string.
259
+ // @param salt Salt (string or Uint8Array). Defaults to a static value.
260
+ // @param alg 'AES-GCM' (default) or 'AES-CBC'.
261
+ // @returns A Promise<CryptoKey>.
262
+ ///
263
+ async deriveKey(password, salt, alg = "AES-GCM", iterations = PBKDF2_ITERATIONS) {
264
+ if (!_hasWebCrypto()) {
265
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
266
+ }
267
+ const enc = new TextEncoder();
268
+ const saltBytes = typeof salt === "string" ? enc.encode(salt) : salt ?? enc.encode("memorio:salt");
269
+ const keyMaterial = await globalThis.crypto.subtle.importKey(
270
+ "raw",
271
+ enc.encode(password),
272
+ { name: "PBKDF2" },
273
+ false,
274
+ ["deriveKey"]
275
+ );
276
+ return globalThis.crypto.subtle.deriveKey(
277
+ { name: "PBKDF2", salt: saltBytes, iterations, hash: "SHA-256" },
278
+ keyMaterial,
279
+ { name: alg, length: 256 },
280
+ false,
281
+ ["encrypt", "decrypt"]
282
+ );
283
+ },
284
+ ///
285
+ // Generate a fresh random CryptoKey (AES-GCM, 256-bit).
286
+ ///
287
+ async generateKey(alg = "AES-GCM") {
288
+ if (!_hasWebCrypto()) {
289
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
290
+ }
291
+ return globalThis.crypto.subtle.generateKey(
292
+ { name: alg, length: 256 },
293
+ true,
294
+ ["encrypt", "decrypt"]
295
+ );
296
+ },
297
+ ///
298
+ // Generate a random salt for PBKDF2 key derivation.
299
+ ///
300
+ generateSalt(bytes = 16) {
301
+ const arr = new Uint8Array(bytes);
302
+ globalThis.crypto?.getRandomValues?.(arr);
303
+ return _b64encode(arr);
304
+ },
305
+ ///
306
+ // Export a CryptoKey to portable base64 strings so it can be stored
307
+ // (e.g. in an httpOnly cookie) and re-imported later with importKey().
308
+ //
309
+ // @param cryptoKey A raw CryptoKey (not a password string).
310
+ // @returns { key: string, iv: string } base64-encoded.
311
+ ///
312
+ async exportKey(cryptoKey) {
313
+ if (!_hasWebCrypto()) {
314
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
315
+ }
316
+ const exported = await globalThis.crypto.subtle.exportKey("raw", cryptoKey);
317
+ return {
318
+ key: _b64encode(exported),
319
+ iv: ""
320
+ };
321
+ },
322
+ ///
323
+ // Import a CryptoKey from base64 strings produced by exportKey().
324
+ //
325
+ // @param keyData Base64-encoded raw key bytes.
326
+ // @param _ivData Ignored (kept for API compatibility with exportKey return).
327
+ // @returns A Promise<CryptoKey>.
328
+ ///
329
+ async importKey(keyData, _ivData) {
330
+ if (!_hasWebCrypto()) {
331
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
332
+ }
333
+ const keyBytes = _b64decode(keyData);
334
+ if (keyBytes.length !== 32) {
335
+ throw new Error(`memorio encryption: AES-256 key must be exactly 32 bytes, got ${keyBytes.length}`);
336
+ }
337
+ return globalThis.crypto.subtle.importKey(
338
+ "raw",
339
+ keyBytes,
340
+ AES_GCM,
341
+ true,
342
+ ["encrypt", "decrypt"]
343
+ );
344
+ },
345
+ ///
346
+ // Encrypt a JavaScript value.
347
+ //
348
+ // @param value The value to encrypt (any JSON-serializable object).
349
+ // @param key A CryptoKey or a password string (password is derived via PBKDF2).
350
+ // @param keyId Optional label, stored in the envelope for key rotation.
351
+ // @returns An EncryptedEnvelope object.
352
+ ///
353
+ async encrypt(value, key, keyId) {
354
+ const cryptoKey = typeof key === "string" ? await this.deriveKey(key, void 0, "AES-GCM") : key;
355
+ const data = new TextEncoder().encode(JSON.stringify(value));
356
+ const iv = new Uint8Array(12);
357
+ globalThis.crypto.getRandomValues(iv);
358
+ const ciphertext = await globalThis.crypto.subtle.encrypt(
359
+ { name: "AES-GCM", iv },
360
+ cryptoKey,
361
+ data
362
+ );
363
+ const envelope = {
364
+ __memorio_encrypted: true,
365
+ v: 1,
366
+ alg: "AES-GCM",
367
+ iv: _b64encode(iv),
368
+ data: _b64encode(ciphertext)
369
+ };
370
+ if (keyId) envelope.keyId = keyId;
371
+ if (DEV) message_default(`encryption: encrypted value (alg=${envelope.alg})`);
372
+ return envelope;
373
+ },
374
+ ///
375
+ // Decrypt an EncryptedEnvelope.
376
+ //
377
+ // @param envelope The envelope object returned by encrypt().
378
+ // @param key A CryptoKey or a password string.
379
+ // @returns The original value (parsed from JSON).
380
+ ///
381
+ async decrypt(envelope, key) {
382
+ if (!_isEncrypted(envelope)) {
383
+ throw new Error("memorio encryption: value is not a valid encrypted envelope");
384
+ }
385
+ const cryptoKey = typeof key === "string" ? await this.deriveKey(key, void 0, "AES-GCM") : key;
386
+ const iv = _b64decode(envelope.iv);
387
+ const data = _b64decode(envelope.data);
388
+ const decrypted = await globalThis.crypto.subtle.decrypt(
389
+ { name: "AES-GCM", iv },
390
+ cryptoKey,
391
+ data
392
+ );
393
+ return JSON.parse(new TextDecoder().decode(new Uint8Array(decrypted)));
394
+ },
395
+ ///
396
+ // Convenience: encrypt with a password (derives the key internally).
397
+ // Returns a JSON string you can store anywhere.
398
+ ///
399
+ async encryptWithPassword(value, password, salt, keyId) {
400
+ const env = await this.encrypt(value, password, keyId);
401
+ return JSON.stringify(env);
402
+ },
403
+ ///
404
+ // Convenience: decrypt a JSON envelope string with a password.
405
+ ///
406
+ async decryptWithPassword(envelopeJson, password, _salt) {
407
+ const envelope = JSON.parse(envelopeJson);
408
+ return this.decrypt(envelope, password);
409
+ },
410
+ ///
411
+ // Type guard: check whether a value is an encrypted envelope.
412
+ ///
413
+ isEncrypted(value) {
414
+ return _isEncrypted(value);
415
+ },
416
+ ///
417
+ // Configure a default encryption key for auto-encrypt mode.
418
+ // When set on `store` or `session`, all writes are encrypted and all
419
+ // reads attempt decryption automatically.
420
+ ///
421
+ config(opts) {
422
+ if (opts.key !== void 0) this._defaultKey = opts.key;
423
+ if (opts.keyId !== void 0) this._defaultKeyId = opts.keyId;
424
+ return this;
425
+ },
426
+ ///
427
+ // Internal: resolve the configured default key.
428
+ ///
429
+ get _key() {
430
+ return this._defaultKey ?? null;
431
+ },
432
+ get _keyId() {
433
+ return this._defaultKeyId;
434
+ }
435
+ };
436
+ }
437
+ });
438
+
201
439
  // core/platform.ts
202
440
  function getSessionStorage() {
203
441
  try {
@@ -234,6 +472,7 @@ var init_platform = __esm({
234
472
  "core/platform.ts"() {
235
473
  init_cjs_shims();
236
474
  init_internal();
475
+ init_encryption();
237
476
  __name(getSessionStorage, "getSessionStorage");
238
477
  __name(getLocalStorage, "getLocalStorage");
239
478
  __name(hasIndexedDB, "hasIndexedDB");
@@ -808,9 +1047,25 @@ var dispatch = {
808
1047
  const wrapped = /* @__PURE__ */ __name((e) => {
809
1048
  const target = e;
810
1049
  if (globalThis.queueMicrotask) {
811
- globalThis.queueMicrotask(() => cb(target));
1050
+ globalThis.queueMicrotask(() => {
1051
+ try {
1052
+ cb(target);
1053
+ } catch (err) {
1054
+ if (typeof console !== "undefined") {
1055
+ console.error("[memorio dispatch] observer error:", err);
1056
+ }
1057
+ }
1058
+ });
812
1059
  } else {
813
- Promise.resolve().then(() => cb(target));
1060
+ Promise.resolve().then(() => {
1061
+ try {
1062
+ cb(target);
1063
+ } catch (err) {
1064
+ if (typeof console !== "undefined") {
1065
+ console.error("[memorio dispatch] observer error:", err);
1066
+ }
1067
+ }
1068
+ });
814
1069
  }
815
1070
  }, "wrapped");
816
1071
  globalThis.addEventListener(name, wrapped);
@@ -948,6 +1203,7 @@ init_cjs_shims();
948
1203
  init_platform();
949
1204
  init_internal();
950
1205
  init_message();
1206
+ init_encryption();
951
1207
  var _localStorage = getLocalStorage();
952
1208
  var _fallbackStorageByContext = /* @__PURE__ */ new Map();
953
1209
  function _getFallbackStorage() {
@@ -960,6 +1216,14 @@ function _getFallbackStorage() {
960
1216
  }
961
1217
  __name(_getFallbackStorage, "_getFallbackStorage");
962
1218
  var _hasStorage = _localStorage !== null;
1219
+ var _encryptionKey = null;
1220
+ var _onError = null;
1221
+ var _maxObjectSize = 0;
1222
+ var _maxTotalSize = 0;
1223
+ function _isEncryptedEnvelope(value) {
1224
+ return encryption.isEncrypted(value);
1225
+ }
1226
+ __name(_isEncryptedEnvelope, "_isEncryptedEnvelope");
963
1227
  function _getPrefix() {
964
1228
  const contextName = internal_default.currentContext || "";
965
1229
  return contextName ? `${contextName}-` : `memorio_store_`;
@@ -1013,16 +1277,24 @@ if (globalThis[STORE_INSTANCE_KEY]) {
1013
1277
  /**
1014
1278
  * Gets a value from storage.
1015
1279
  * @param name The key to retrieve.
1016
- * @returns The parsed value or null if not found.
1280
+ * @param opts Optional { decrypt: key } to decrypt an encrypted envelope.
1281
+ * When no key is passed, encrypted envelopes are returned as-is.
1282
+ * If a default key was configured via store.config(), it is used automatically.
1283
+ * @returns The parsed value, a Promise<parsed value> when decrypting, or null if not found.
1017
1284
  */
1018
1285
  get: {
1019
- value: /* @__PURE__ */ __name((name) => {
1286
+ value: /* @__PURE__ */ __name((name, opts) => {
1020
1287
  if (!name) {
1021
1288
  console.warn("[memorio store] store.get() called with empty or null key - returning null");
1022
1289
  return null;
1023
1290
  }
1024
1291
  try {
1025
- return _read(_prefixKey(name));
1292
+ const raw = _read(_prefixKey(name));
1293
+ const key = opts?.decrypt ?? _encryptionKey;
1294
+ if (key && _isEncryptedEnvelope(raw)) {
1295
+ return encryption.decrypt(raw, key);
1296
+ }
1297
+ return raw;
1026
1298
  } catch (err) {
1027
1299
  message(`Error parsing store item '${name}': ${err}`);
1028
1300
  }
@@ -1047,10 +1319,13 @@ if (globalThis[STORE_INSTANCE_KEY]) {
1047
1319
  * Sets a value in storage.
1048
1320
  * @param name The key to set.
1049
1321
  * @param value The value to store (objects, arrays, primitives).
1050
- * @returns true if written, false if the key was rejected.
1322
+ * @param opts Optional { encrypt: key } to encrypt the value before storage.
1323
+ * If a default key was configured via store.config(), it is used automatically.
1324
+ * When encryption is used, returns a Promise<boolean>.
1325
+ * @returns true if written, false if rejected or error.
1051
1326
  */
1052
1327
  set: {
1053
- value: /* @__PURE__ */ __name((name, value) => {
1328
+ value: /* @__PURE__ */ __name((name, value, opts) => {
1054
1329
  if (!name) {
1055
1330
  console.warn("[memorio store] store.set() called with empty or null key - write aborted");
1056
1331
  return false;
@@ -1062,15 +1337,66 @@ if (globalThis[STORE_INSTANCE_KEY]) {
1062
1337
  message("Storing functions is not secure and is blocked for safety.");
1063
1338
  return false;
1064
1339
  }
1340
+ if (_maxObjectSize > 0 || _maxTotalSize > 0) {
1341
+ let serializedSize = 0;
1342
+ try {
1343
+ serializedSize = new TextEncoder().encode(JSON.stringify(value)).length;
1344
+ } catch {
1345
+ serializedSize = 0;
1346
+ }
1347
+ if (_maxObjectSize > 0 && serializedSize > _maxObjectSize) {
1348
+ const err = new Error(`Object size (${serializedSize} bytes) exceeds maxObjectSize (${_maxObjectSize} bytes)`);
1349
+ _onError?.(err, { operation: "set" });
1350
+ return false;
1351
+ }
1352
+ if (_maxTotalSize > 0) {
1353
+ const currentTotal = store.size() * 1024;
1354
+ const existingItemSize = _hasStorage ? _localStorage.getItem(prefixedName)?.length ?? 0 : _getFallbackStorage().get(prefixedName)?.length ?? 0;
1355
+ const projected = currentTotal * 1024 - existingItemSize + serializedSize;
1356
+ if (projected > _maxTotalSize) {
1357
+ const err = new Error(`Total store size (${projected} bytes) exceeds maxTotalSize (${_maxTotalSize} bytes)`);
1358
+ _onError?.(err, { operation: "set" });
1359
+ return false;
1360
+ }
1361
+ }
1362
+ }
1363
+ const key = opts?.encrypt ?? _encryptionKey;
1364
+ if (key) {
1365
+ return encryption.encrypt(value, key).then((env) => {
1366
+ _write(prefixedName, env);
1367
+ return true;
1368
+ }).catch((err) => {
1369
+ message(`Error encrypting store item '${name}': ${err}`);
1370
+ _onError?.(err, { operation: "set" });
1371
+ return false;
1372
+ });
1373
+ }
1065
1374
  try {
1066
1375
  _write(prefixedName, value);
1067
1376
  } catch (err) {
1068
1377
  message(`Error setting store item '${name}': ${err}`);
1378
+ _onError?.(err, { operation: "set" });
1069
1379
  return false;
1070
1380
  }
1071
1381
  return true;
1072
1382
  }, "value")
1073
1383
  },
1384
+ /**
1385
+ * Configure store-wide behavior.
1386
+ * @param opts Optional { encryptionKey } to enable automatic encryption
1387
+ * for all set/get operations. When set, values are encrypted
1388
+ * on write and decrypted on read (if the value is an envelope).
1389
+ * @returns The store instance for chaining.
1390
+ */
1391
+ config: {
1392
+ value: /* @__PURE__ */ __name((opts) => {
1393
+ if (opts.encryptionKey !== void 0) _encryptionKey = opts.encryptionKey;
1394
+ if (opts.onError !== void 0) _onError = opts.onError;
1395
+ if (opts.maxObjectSize !== void 0) _maxObjectSize = opts.maxObjectSize;
1396
+ if (opts.maxTotalSize !== void 0) _maxTotalSize = opts.maxTotalSize;
1397
+ return store;
1398
+ }, "value")
1399
+ },
1074
1400
  /**
1075
1401
  * Removes a value from storage.
1076
1402
  * @param name The key to remove.
@@ -1217,10 +1543,211 @@ if (globalThis[STORE_INSTANCE_KEY]) {
1217
1543
 
1218
1544
  // functions/state/index.ts
1219
1545
  init_env();
1546
+
1547
+ // core/mutation/engine.ts
1548
+ init_cjs_shims();
1549
+ init_internal();
1550
+
1551
+ // core/hlc.ts
1552
+ init_cjs_shims();
1553
+ var NODE_ID_KEY = "__memorio_hlc_node";
1554
+ function getNodeId() {
1555
+ if (typeof globalThis === "undefined") return "node";
1556
+ try {
1557
+ if (typeof sessionStorage !== "undefined" && sessionStorage) {
1558
+ let id = sessionStorage.getItem(NODE_ID_KEY);
1559
+ if (!id) {
1560
+ id = generateNodeId();
1561
+ sessionStorage.setItem(NODE_ID_KEY, id);
1562
+ }
1563
+ return id;
1564
+ }
1565
+ } catch {
1566
+ }
1567
+ if (!globalThis.__memorioHlcNodeId) {
1568
+ globalThis.__memorioHlcNodeId = generateNodeId();
1569
+ }
1570
+ return globalThis.__memorioHlcNodeId;
1571
+ }
1572
+ __name(getNodeId, "getNodeId");
1573
+ function generateNodeId() {
1574
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
1575
+ return crypto.randomUUID().slice(0, 8);
1576
+ }
1577
+ return Math.random().toString(36).slice(2, 10);
1578
+ }
1579
+ __name(generateNodeId, "generateNodeId");
1580
+ var HLC_KEY = "__memorio_hlc_local";
1581
+ var local = globalThis[HLC_KEY] || {
1582
+ physical: 0,
1583
+ logical: 0,
1584
+ node: getNodeId()
1585
+ };
1586
+ if (!globalThis[HLC_KEY]) {
1587
+ globalThis[HLC_KEY] = local;
1588
+ }
1589
+ function tick(_incoming) {
1590
+ const now2 = Date.now();
1591
+ const base = local.physical;
1592
+ let physical;
1593
+ let logical;
1594
+ if (now2 > base) {
1595
+ physical = now2;
1596
+ logical = 0;
1597
+ } else if (now2 < base) {
1598
+ physical = base;
1599
+ logical = local.logical + 1;
1600
+ } else {
1601
+ physical = base;
1602
+ logical = local.logical + 1;
1603
+ }
1604
+ local.physical = physical;
1605
+ local.logical = logical;
1606
+ return { physical, logical, node: local.node };
1607
+ }
1608
+ __name(tick, "tick");
1609
+ function receive(remote) {
1610
+ const now2 = Date.now();
1611
+ if (remote.physical > local.physical) {
1612
+ local.physical = remote.physical > now2 ? remote.physical : now2;
1613
+ local.logical = 1;
1614
+ } else if (remote.physical === local.physical) {
1615
+ local.logical = Math.max(local.logical, remote.logical) + 1;
1616
+ }
1617
+ local.node = getNodeId();
1618
+ return { ...local };
1619
+ }
1620
+ __name(receive, "receive");
1621
+ function compare(a, b) {
1622
+ if (a.physical !== b.physical) {
1623
+ return a.physical < b.physical ? -1 : 1;
1624
+ }
1625
+ if (a.logical !== b.logical) {
1626
+ return a.logical < b.logical ? -1 : 1;
1627
+ }
1628
+ if (a.node !== b.node) {
1629
+ return a.node < b.node ? -1 : 1;
1630
+ }
1631
+ return 0;
1632
+ }
1633
+ __name(compare, "compare");
1634
+ function happenedBefore(a, b) {
1635
+ return compare(a, b) < 0;
1636
+ }
1637
+ __name(happenedBefore, "happenedBefore");
1638
+ function serialize(hlc2) {
1639
+ return `hlc:${hlc2.physical}:${hlc2.logical}:${hlc2.node}`;
1640
+ }
1641
+ __name(serialize, "serialize");
1642
+ function parse(serialized) {
1643
+ if (!serialized.startsWith("hlc:")) return null;
1644
+ const parts = serialized.split(":");
1645
+ if (parts.length !== 4) return null;
1646
+ const physical = parseInt(parts[1], 10);
1647
+ const logical = parseInt(parts[2], 10);
1648
+ const node = parts[3];
1649
+ if (isNaN(physical) || isNaN(logical)) return null;
1650
+ return { physical, logical, node };
1651
+ }
1652
+ __name(parse, "parse");
1653
+ var hlc = {
1654
+ tick,
1655
+ receive,
1656
+ compare,
1657
+ happenedBefore,
1658
+ serialize,
1659
+ parse,
1660
+ getNodeId
1661
+ };
1662
+
1663
+ // core/mutation/id.ts
1664
+ init_cjs_shims();
1665
+ function generateMutationId() {
1666
+ const now2 = hlc.tick();
1667
+ return "m_" + encodeHLC(now2);
1668
+ }
1669
+ __name(generateMutationId, "generateMutationId");
1670
+ function encodeHLC(hlcValue) {
1671
+ const timePart = hlcValue.physical.toString(36);
1672
+ const logicalPart = hlcValue.logical.toString(36).padStart(2, "0");
1673
+ const nodePart = hlcValue.node.slice(0, 4);
1674
+ return `${timePart}${logicalPart}${nodePart}`;
1675
+ }
1676
+ __name(encodeHLC, "encodeHLC");
1677
+
1678
+ // core/mutation/patch.ts
1679
+ init_cjs_shims();
1680
+
1681
+ // core/mutation/transaction.ts
1682
+ init_cjs_shims();
1683
+ init_internal();
1684
+ var TX_REGISTRY_KEY = "__memorio_transaction_registry__";
1685
+ var registry = globalThis[TX_REGISTRY_KEY] || /* @__PURE__ */ new Map();
1686
+ if (!globalThis[TX_REGISTRY_KEY]) {
1687
+ globalThis[TX_REGISTRY_KEY] = registry;
1688
+ }
1689
+ var TX_STACK_KEY = "__memorio_transaction_stack__";
1690
+ var txStack = globalThis[TX_STACK_KEY] || [];
1691
+ if (!globalThis[TX_STACK_KEY]) {
1692
+ globalThis[TX_STACK_KEY] = txStack;
1693
+ }
1694
+ function getActiveTxId() {
1695
+ return txStack.length > 0 ? txStack[txStack.length - 1] : null;
1696
+ }
1697
+ __name(getActiveTxId, "getActiveTxId");
1698
+ function tagForTransaction() {
1699
+ const txId = getActiveTxId();
1700
+ if (!txId) return void 0;
1701
+ const ctx = registry.get(txId);
1702
+ if (ctx && ctx.active) {
1703
+ return txId;
1704
+ }
1705
+ return void 0;
1706
+ }
1707
+ __name(tagForTransaction, "tagForTransaction");
1708
+ function registerMutationInTransaction(mutationId) {
1709
+ const txId = getActiveTxId();
1710
+ if (!txId) return;
1711
+ const ctx = registry.get(txId);
1712
+ if (ctx && ctx.active) {
1713
+ ctx.mutations.push(mutationId);
1714
+ }
1715
+ }
1716
+ __name(registerMutationInTransaction, "registerMutationInTransaction");
1717
+
1718
+ // core/mutation/engine.ts
1719
+ function createMutation(path, operation, before, after, options) {
1720
+ const now2 = hlc.tick();
1721
+ const mutation = {
1722
+ id: generateMutationId(),
1723
+ path,
1724
+ operation,
1725
+ after,
1726
+ before,
1727
+ timestamp: now2.physical,
1728
+ hlc: hlc.serialize(now2),
1729
+ context: options?.context || internal_default.currentContext || void 0,
1730
+ source: options?.source,
1731
+ transactionId: options?.transactionId || (operation !== "length" ? tagForTransaction() : void 0),
1732
+ // Legacy fields for backward compatibility
1733
+ action: operation === "set" ? "set" : "delete",
1734
+ newValue: after,
1735
+ previousValue: before
1736
+ };
1737
+ if (mutation.transactionId) {
1738
+ registerMutationInTransaction(mutation.id);
1739
+ }
1740
+ return mutation;
1741
+ }
1742
+ __name(createMutation, "createMutation");
1743
+
1744
+ // functions/state/index.ts
1220
1745
  var TARGET = /* @__PURE__ */ Symbol("memorio.target");
1221
1746
  var wrapperCache = /* @__PURE__ */ new WeakMap();
1747
+ var arrayRootDedup = /* @__PURE__ */ new Set();
1222
1748
  var deepRaw = /* @__PURE__ */ __name((val, seen = null) => {
1223
1749
  if (val === null || typeof val !== "object") return val;
1750
+ if (!seen) seen = /* @__PURE__ */ new WeakSet();
1224
1751
  if (val[TARGET] !== void 0) return deepRaw(val[TARGET], seen);
1225
1752
  if (seen) {
1226
1753
  if (seen.has(val)) return val;
@@ -1283,8 +1810,8 @@ var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
1283
1810
  if (prop === "removeAll") {
1284
1811
  return () => {
1285
1812
  try {
1286
- for (const key in target) {
1287
- if (typeof target[key] !== "function" && !["list", "remove", "removeAll", "lock", "unlock"].includes(key)) {
1813
+ for (const key of Reflect.ownKeys(target)) {
1814
+ if (typeof target[key] !== "function" && !["list", "remove", "removeAll", "lock", "unlock", "persist"].includes(key)) {
1288
1815
  delete target[key];
1289
1816
  }
1290
1817
  }
@@ -1358,6 +1885,16 @@ var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
1358
1885
  }
1359
1886
  );
1360
1887
  event("state." + path);
1888
+ if (Array.isArray(target) && tree.length > 0) {
1889
+ const rootName = "state." + tree.join(".");
1890
+ if (!arrayRootDedup.has(rootName)) {
1891
+ arrayRootDedup.add(rootName);
1892
+ event(rootName);
1893
+ if (typeof globalThis.queueMicrotask === "function") {
1894
+ globalThis.queueMicrotask(() => arrayRootDedup.clear());
1895
+ }
1896
+ }
1897
+ }
1361
1898
  Reflect.set(target, key, rawValue);
1362
1899
  internal_default.bumpStateVersion();
1363
1900
  if (target[key] && typeof target[key] === "object") {
@@ -1414,6 +1951,17 @@ var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
1414
1951
  const path = objPath(prop, tree);
1415
1952
  const previousValue = Reflect.get(target, prop);
1416
1953
  callback({ action: "delete", path, target, previousValue });
1954
+ event("state." + path);
1955
+ if (Array.isArray(target) && tree.length > 0) {
1956
+ const rootName = "state." + tree.join(".");
1957
+ if (!arrayRootDedup.has(rootName)) {
1958
+ arrayRootDedup.add(rootName);
1959
+ event(rootName);
1960
+ if (typeof globalThis.queueMicrotask === "function") {
1961
+ globalThis.queueMicrotask(() => arrayRootDedup.clear());
1962
+ }
1963
+ }
1964
+ }
1417
1965
  return Reflect.deleteProperty(target, prop);
1418
1966
  } catch (error) {
1419
1967
  console.error("Error in deleteProperty trap:", error);
@@ -1435,57 +1983,83 @@ if (globalThis[STATE_INSTANCE_KEY]) {
1435
1983
  state2 = globalThis[STATE_INSTANCE_KEY];
1436
1984
  } else {
1437
1985
  state2 = buildProxy({}, (mutation) => {
1438
- if (internal_default.historyEnabled) {
1439
- internal_default.recordMutation({
1440
- path: mutation.path,
1441
- action: mutation.action,
1442
- newValue: mutation.newValue,
1443
- previousValue: mutation.previousValue,
1444
- timestamp: Date.now()
1445
- });
1986
+ if (internal_default.historyEnabled && internal_default._recording !== false) {
1987
+ const operation = mutation.action === "delete" ? "delete" : "set";
1988
+ const record = createMutation(
1989
+ mutation.path,
1990
+ operation,
1991
+ mutation.previousValue,
1992
+ mutation.newValue,
1993
+ {
1994
+ context: mutation.context,
1995
+ source: mutation.source
1996
+ }
1997
+ );
1998
+ internal_default.recordMutation(record);
1446
1999
  }
1447
2000
  });
1448
- state2.lock = () => {
1449
- internal_default.locked = true;
1450
- message_default("State is now locked. All modifications are blocked.");
1451
- };
1452
- state2.unlock = () => {
1453
- internal_default.locked = false;
1454
- message_default("State is now unlocked. Modifications are allowed.");
1455
- };
1456
- state2.persist = (path) => {
1457
- if (typeof path !== "string" || !path.length) {
1458
- if (DEV) console.warn('[memorio state] state.persist() requires a non-empty path string (e.g. "state.user")');
1459
- return () => {
1460
- };
1461
- }
1462
- const normalized = path.startsWith("state.") ? path : "state." + path;
1463
- const key = normalized.replace(/^state\./, "");
1464
- const segments = key.split(".");
1465
- const initial = store.get(key);
1466
- if (initial !== void 0 && initial !== null) {
1467
- let acc = state2;
1468
- for (let i = 0; i < segments.length; i++) {
1469
- const seg = segments[i];
1470
- if (i === segments.length - 1) {
1471
- acc[seg] = deepRaw(initial);
1472
- } else {
1473
- if (acc[seg] === void 0 || acc[seg] === null) acc[seg] = {};
1474
- acc = acc[seg];
2001
+ const _rawTarget = state2[TARGET];
2002
+ try {
2003
+ Object.defineProperty(_rawTarget, "lock", {
2004
+ value: /* @__PURE__ */ __name(() => {
2005
+ internal_default.locked = true;
2006
+ message_default("State is now locked. All modifications are blocked.");
2007
+ }, "value"),
2008
+ writable: true,
2009
+ configurable: true,
2010
+ enumerable: false
2011
+ });
2012
+ Object.defineProperty(_rawTarget, "unlock", {
2013
+ value: /* @__PURE__ */ __name(() => {
2014
+ internal_default.locked = false;
2015
+ message_default("State is now unlocked. Modifications are allowed.");
2016
+ }, "value"),
2017
+ writable: true,
2018
+ configurable: true,
2019
+ enumerable: false
2020
+ });
2021
+ } catch (e) {
2022
+ if (DEV) console.warn("[memorio state] lock/unlock defineProperty failed:", e);
2023
+ }
2024
+ try {
2025
+ Object.defineProperty(_rawTarget, "persist", {
2026
+ value: /* @__PURE__ */ __name((path) => {
2027
+ if (typeof path !== "string" || !path.length) {
2028
+ if (DEV) console.warn('[memorio state] state.persist() requires a non-empty path string (e.g. "state.user")');
2029
+ return () => {
2030
+ };
1475
2031
  }
1476
- }
1477
- }
1478
- const handler = /* @__PURE__ */ __name(() => {
1479
- let current = state2;
1480
- for (const seg of segments) {
1481
- current = current === void 0 || current === null ? void 0 : current[seg];
1482
- }
1483
- store.set(key, deepRaw(current));
1484
- }, "handler");
1485
- const off = dispatch.listen(normalized, handler);
1486
- return typeof off === "function" ? off : () => {
1487
- };
1488
- };
2032
+ const normalized = path.startsWith("state.") ? path : "state." + path;
2033
+ const key = normalized.replace(/^state\./, "");
2034
+ const segments = key.split(".");
2035
+ const initial = store.get(key);
2036
+ if (initial !== void 0 && initial !== null) {
2037
+ let acc = state2;
2038
+ for (let i = 0; i < segments.length - 1; i++) {
2039
+ const seg = segments[i];
2040
+ if (acc[seg] === void 0 || acc[seg] === null) acc[seg] = {};
2041
+ acc = acc[seg];
2042
+ }
2043
+ if (acc) acc[segments[segments.length - 1]] = deepRaw(initial);
2044
+ }
2045
+ const handler = /* @__PURE__ */ __name(() => {
2046
+ let current = state2;
2047
+ for (const seg of segments) {
2048
+ current = current === void 0 || current === null ? void 0 : current[seg];
2049
+ }
2050
+ store.set(key, deepRaw(current));
2051
+ }, "handler");
2052
+ const off = dispatch.listen(normalized, handler);
2053
+ return typeof off === "function" ? off : () => {
2054
+ };
2055
+ }, "value"),
2056
+ writable: true,
2057
+ configurable: true,
2058
+ enumerable: false
2059
+ });
2060
+ } catch (e) {
2061
+ if (DEV) console.warn("[memorio state] persist defineProperty failed:", e);
2062
+ }
1489
2063
  globalThis[STATE_INSTANCE_KEY] = state2;
1490
2064
  }
1491
2065
 
@@ -1494,6 +2068,7 @@ init_cjs_shims();
1494
2068
  init_platform();
1495
2069
  init_internal();
1496
2070
  init_message();
2071
+ init_encryption();
1497
2072
  var _sessionStorage = getSessionStorage();
1498
2073
  var _fallbackStorageByContext2 = /* @__PURE__ */ new Map();
1499
2074
  function _getFallbackStorage2() {
@@ -1506,6 +2081,14 @@ function _getFallbackStorage2() {
1506
2081
  }
1507
2082
  __name(_getFallbackStorage2, "_getFallbackStorage");
1508
2083
  var _hasStorage2 = _sessionStorage !== null;
2084
+ var _encryptionKey2 = null;
2085
+ var _onError2 = null;
2086
+ var _maxObjectSize2 = 0;
2087
+ var _maxTotalSize2 = 0;
2088
+ function _isEncryptedEnvelope2(value) {
2089
+ return encryption.isEncrypted(value);
2090
+ }
2091
+ __name(_isEncryptedEnvelope2, "_isEncryptedEnvelope");
1509
2092
  function _getPrefix2() {
1510
2093
  const contextName = internal_default.currentContext || "";
1511
2094
  return contextName ? `${contextName}-` : `memorio_session_`;
@@ -1559,16 +2142,22 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
1559
2142
  /**
1560
2143
  * Gets a value from storage.
1561
2144
  * @param name The key to retrieve.
1562
- * @returns The parsed value or null if not found.
2145
+ * @param opts Optional { decrypt: key } to decrypt an encrypted envelope.
2146
+ * @returns The parsed value, a Promise when decrypting, or null if not found.
1563
2147
  */
1564
2148
  get: {
1565
- value: /* @__PURE__ */ __name((name) => {
2149
+ value: /* @__PURE__ */ __name((name, opts) => {
1566
2150
  if (!name) {
1567
2151
  console.warn("[memorio session] session.get() called with empty or null key - returning null");
1568
2152
  return null;
1569
2153
  }
1570
2154
  try {
1571
- return _read2(_prefixKey2(name));
2155
+ const raw = _read2(_prefixKey2(name));
2156
+ const key = opts?.decrypt ?? _encryptionKey2;
2157
+ if (key && _isEncryptedEnvelope2(raw)) {
2158
+ return encryption.decrypt(raw, key);
2159
+ }
2160
+ return raw;
1572
2161
  } catch (err) {
1573
2162
  message(`Error parsing session item '${name}':${err}`);
1574
2163
  }
@@ -1579,10 +2168,11 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
1579
2168
  * Sets a value in storage.
1580
2169
  * @param name The key to set.
1581
2170
  * @param value The value to store.
1582
- * @returns true if written, false if the key was rejected.
2171
+ * @param opts Optional { encrypt: key } to encrypt before storage.
2172
+ * @returns true if written, false if rejected. Returns a Promise when encrypting.
1583
2173
  */
1584
2174
  set: {
1585
- value: /* @__PURE__ */ __name((name, value) => {
2175
+ value: /* @__PURE__ */ __name((name, value, opts) => {
1586
2176
  if (!name) {
1587
2177
  console.warn("[memorio session] session.set() called with empty or null key - write aborted");
1588
2178
  return false;
@@ -1594,15 +2184,63 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
1594
2184
  message("It's not secure to session functions.");
1595
2185
  return false;
1596
2186
  }
2187
+ if (_maxObjectSize2 > 0 || _maxTotalSize2 > 0) {
2188
+ let serializedSize = 0;
2189
+ try {
2190
+ serializedSize = new TextEncoder().encode(JSON.stringify(value)).length;
2191
+ } catch {
2192
+ serializedSize = 0;
2193
+ }
2194
+ if (_maxObjectSize2 > 0 && serializedSize > _maxObjectSize2) {
2195
+ const err = new Error(`Object size (${serializedSize} bytes) exceeds maxObjectSize (${_maxObjectSize2} bytes)`);
2196
+ _onError2?.(err, { operation: "set" });
2197
+ return false;
2198
+ }
2199
+ if (_maxTotalSize2 > 0) {
2200
+ const currentTotal = session.size() * 1024;
2201
+ const existingItemSize = _sessionStorage ? _sessionStorage.getItem(prefixedName)?.length ?? 0 : _getFallbackStorage2().get(prefixedName)?.length ?? 0;
2202
+ const projected = currentTotal - existingItemSize + serializedSize;
2203
+ if (projected > _maxTotalSize2) {
2204
+ const err = new Error(`Total session size (${projected} bytes) exceeds maxTotalSize (${_maxTotalSize2} bytes)`);
2205
+ _onError2?.(err, { operation: "set" });
2206
+ return false;
2207
+ }
2208
+ }
2209
+ }
2210
+ const key = opts?.encrypt ?? _encryptionKey2;
2211
+ if (key) {
2212
+ return encryption.encrypt(value, key).then((env) => {
2213
+ _write2(prefixedName, env);
2214
+ return true;
2215
+ }).catch((err) => {
2216
+ message(`Error encrypting session item '${name}': ${err}`);
2217
+ _onError2?.(err, { operation: "set" });
2218
+ return false;
2219
+ });
2220
+ }
1597
2221
  try {
1598
2222
  _write2(prefixedName, value);
1599
2223
  } catch (err) {
1600
2224
  message(`Error setting session item '${name}': ${err}`);
2225
+ _onError2?.(err, { operation: "set" });
1601
2226
  return false;
1602
2227
  }
1603
2228
  return true;
1604
2229
  }, "value")
1605
2230
  },
2231
+ /**
2232
+ * Configure session-wide behavior.
2233
+ * @param opts { encryptionKey, onError, maxObjectSize, maxTotalSize }
2234
+ */
2235
+ config: {
2236
+ value: /* @__PURE__ */ __name((opts) => {
2237
+ if (opts.encryptionKey !== void 0) _encryptionKey2 = opts.encryptionKey;
2238
+ if (opts.onError !== void 0) _onError2 = opts.onError;
2239
+ if (opts.maxObjectSize !== void 0) _maxObjectSize2 = opts.maxObjectSize;
2240
+ if (opts.maxTotalSize !== void 0) _maxTotalSize2 = opts.maxTotalSize;
2241
+ return session;
2242
+ }, "value")
2243
+ },
1606
2244
  /**
1607
2245
  * Removes a value from storage.
1608
2246
  * @param name The key to remove.
@@ -1747,120 +2385,6 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
1747
2385
 
1748
2386
  // functions/memory/index.ts
1749
2387
  init_idb();
1750
-
1751
- // core/hlc.ts
1752
- init_cjs_shims();
1753
- var NODE_ID_KEY = "__memorio_hlc_node";
1754
- function getNodeId() {
1755
- if (typeof globalThis === "undefined") return "node";
1756
- try {
1757
- if (typeof sessionStorage !== "undefined" && sessionStorage) {
1758
- let id = sessionStorage.getItem(NODE_ID_KEY);
1759
- if (!id) {
1760
- id = generateNodeId();
1761
- sessionStorage.setItem(NODE_ID_KEY, id);
1762
- }
1763
- return id;
1764
- }
1765
- } catch {
1766
- }
1767
- if (!globalThis.__memorioHlcNodeId) {
1768
- globalThis.__memorioHlcNodeId = generateNodeId();
1769
- }
1770
- return globalThis.__memorioHlcNodeId;
1771
- }
1772
- __name(getNodeId, "getNodeId");
1773
- function generateNodeId() {
1774
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
1775
- return crypto.randomUUID().slice(0, 8);
1776
- }
1777
- return Math.random().toString(36).slice(2, 10);
1778
- }
1779
- __name(generateNodeId, "generateNodeId");
1780
- var HLC_KEY = "__memorio_hlc_local";
1781
- var local = globalThis[HLC_KEY] || {
1782
- physical: 0,
1783
- logical: 0,
1784
- node: getNodeId()
1785
- };
1786
- if (!globalThis[HLC_KEY]) {
1787
- globalThis[HLC_KEY] = local;
1788
- }
1789
- function tick(_incoming) {
1790
- const now2 = Date.now();
1791
- const base = local.physical;
1792
- let physical;
1793
- let logical;
1794
- if (now2 > base) {
1795
- physical = now2;
1796
- logical = 0;
1797
- } else if (now2 < base) {
1798
- physical = base;
1799
- logical = local.logical + 1;
1800
- } else {
1801
- physical = base;
1802
- logical = local.logical + 1;
1803
- }
1804
- local.physical = physical;
1805
- local.logical = logical;
1806
- return { physical, logical, node: local.node };
1807
- }
1808
- __name(tick, "tick");
1809
- function receive(remote) {
1810
- const now2 = Date.now();
1811
- if (remote.physical > local.physical) {
1812
- local.physical = remote.physical > now2 ? remote.physical : now2;
1813
- local.logical = 1;
1814
- } else if (remote.physical === local.physical) {
1815
- local.logical = Math.max(local.logical, remote.logical) + 1;
1816
- }
1817
- local.node = getNodeId();
1818
- return { ...local };
1819
- }
1820
- __name(receive, "receive");
1821
- function compare(a, b) {
1822
- if (a.physical !== b.physical) {
1823
- return a.physical < b.physical ? -1 : 1;
1824
- }
1825
- if (a.logical !== b.logical) {
1826
- return a.logical < b.logical ? -1 : 1;
1827
- }
1828
- if (a.node !== b.node) {
1829
- return a.node < b.node ? -1 : 1;
1830
- }
1831
- return 0;
1832
- }
1833
- __name(compare, "compare");
1834
- function happenedBefore(a, b) {
1835
- return compare(a, b) < 0;
1836
- }
1837
- __name(happenedBefore, "happenedBefore");
1838
- function serialize(hlc2) {
1839
- return `hlc:${hlc2.physical}:${hlc2.logical}:${hlc2.node}`;
1840
- }
1841
- __name(serialize, "serialize");
1842
- function parse(serialized) {
1843
- if (!serialized.startsWith("hlc:")) return null;
1844
- const parts = serialized.split(":");
1845
- if (parts.length !== 4) return null;
1846
- const physical = parseInt(parts[1], 10);
1847
- const logical = parseInt(parts[2], 10);
1848
- const node = parts[3];
1849
- if (isNaN(physical) || isNaN(logical)) return null;
1850
- return { physical, logical, node };
1851
- }
1852
- __name(parse, "parse");
1853
- var hlc = {
1854
- tick,
1855
- receive,
1856
- compare,
1857
- happenedBefore,
1858
- serialize,
1859
- parse,
1860
- getNodeId
1861
- };
1862
-
1863
- // functions/memory/index.ts
1864
2388
  init_env();
1865
2389
 
1866
2390
  // functions/memory/journal.ts