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/index.js CHANGED
@@ -7,6 +7,10 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
7
7
  var __esm = (fn, res) => function __init() {
8
8
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
9
  };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
10
14
  var init_esm_shims = __esm({
11
15
  "node_modules/tsup/assets/esm_shims.js"() {
12
16
  }
@@ -17,8 +21,11 @@ var DEV, PROD;
17
21
  var init_env = __esm({
18
22
  "core/env.ts"() {
19
23
  init_esm_shims();
20
- DEV = typeof process !== "undefined" ? false : true;
24
+ DEV = false ;
21
25
  PROD = !DEV;
26
+ if (typeof globalThis !== "undefined") {
27
+ globalThis["__DEV__"] = DEV;
28
+ }
22
29
  }
23
30
  });
24
31
 
@@ -202,6 +209,241 @@ var init_message = __esm({
202
209
  }
203
210
  });
204
211
 
212
+ // functions/encryption/index.ts
213
+ function _hasWebCrypto() {
214
+ const g3 = globalThis;
215
+ return typeof g3.crypto !== "undefined" && typeof g3.crypto.subtle !== "undefined" && typeof g3.crypto.subtle.encrypt === "function";
216
+ }
217
+ function _b64encode(buf) {
218
+ const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
219
+ if (typeof btoa === "function") {
220
+ let binary = "";
221
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
222
+ return btoa(binary);
223
+ }
224
+ if (typeof Buffer !== "undefined") {
225
+ return Buffer.from(bytes).toString("base64");
226
+ }
227
+ return "";
228
+ }
229
+ function _b64decode(b64) {
230
+ if (typeof Buffer !== "undefined") {
231
+ return new Uint8Array(Buffer.from(b64, "base64"));
232
+ }
233
+ if (typeof atob === "function") {
234
+ const binary = atob(b64);
235
+ const out = new Uint8Array(binary.length);
236
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
237
+ return out;
238
+ }
239
+ throw new Error("memorio encryption: no base64 decoder available");
240
+ }
241
+ function _isEncrypted(value) {
242
+ return typeof value === "object" && value !== null && value.__memorio_encrypted === true && typeof value.alg === "string";
243
+ }
244
+ var AES_GCM, PBKDF2_ITERATIONS, encryption;
245
+ var init_encryption = __esm({
246
+ "functions/encryption/index.ts"() {
247
+ init_esm_shims();
248
+ init_env();
249
+ init_message();
250
+ __name(_hasWebCrypto, "_hasWebCrypto");
251
+ __name(_b64encode, "_b64encode");
252
+ __name(_b64decode, "_b64decode");
253
+ __name(_isEncrypted, "_isEncrypted");
254
+ AES_GCM = { name: "AES-GCM", length: 256 };
255
+ PBKDF2_ITERATIONS = 6e5;
256
+ encryption = {
257
+ ///
258
+ // Capability detection
259
+ ///
260
+ isAvailable() {
261
+ return _hasWebCrypto();
262
+ },
263
+ ///
264
+ // Derive a CryptoKey from a password using PBKDF2.
265
+ //
266
+ // @param password The password string.
267
+ // @param salt Salt (string or Uint8Array). Defaults to a static value.
268
+ // @param alg 'AES-GCM' (default) or 'AES-CBC'.
269
+ // @returns A Promise<CryptoKey>.
270
+ ///
271
+ async deriveKey(password, salt, alg = "AES-GCM", iterations = PBKDF2_ITERATIONS) {
272
+ if (!_hasWebCrypto()) {
273
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
274
+ }
275
+ const enc = new TextEncoder();
276
+ const saltBytes = typeof salt === "string" ? enc.encode(salt) : salt ?? enc.encode("memorio:salt");
277
+ const keyMaterial = await globalThis.crypto.subtle.importKey(
278
+ "raw",
279
+ enc.encode(password),
280
+ { name: "PBKDF2" },
281
+ false,
282
+ ["deriveKey"]
283
+ );
284
+ return globalThis.crypto.subtle.deriveKey(
285
+ { name: "PBKDF2", salt: saltBytes, iterations, hash: "SHA-256" },
286
+ keyMaterial,
287
+ { name: alg, length: 256 },
288
+ false,
289
+ ["encrypt", "decrypt"]
290
+ );
291
+ },
292
+ ///
293
+ // Generate a fresh random CryptoKey (AES-GCM, 256-bit).
294
+ ///
295
+ async generateKey(alg = "AES-GCM") {
296
+ if (!_hasWebCrypto()) {
297
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
298
+ }
299
+ return globalThis.crypto.subtle.generateKey(
300
+ { name: alg, length: 256 },
301
+ true,
302
+ ["encrypt", "decrypt"]
303
+ );
304
+ },
305
+ ///
306
+ // Generate a random salt for PBKDF2 key derivation.
307
+ ///
308
+ generateSalt(bytes = 16) {
309
+ const arr = new Uint8Array(bytes);
310
+ globalThis.crypto?.getRandomValues?.(arr);
311
+ return _b64encode(arr);
312
+ },
313
+ ///
314
+ // Export a CryptoKey to portable base64 strings so it can be stored
315
+ // (e.g. in an httpOnly cookie) and re-imported later with importKey().
316
+ //
317
+ // @param cryptoKey A raw CryptoKey (not a password string).
318
+ // @returns { key: string, iv: string } base64-encoded.
319
+ ///
320
+ async exportKey(cryptoKey) {
321
+ if (!_hasWebCrypto()) {
322
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
323
+ }
324
+ const exported = await globalThis.crypto.subtle.exportKey("raw", cryptoKey);
325
+ return {
326
+ key: _b64encode(exported),
327
+ iv: ""
328
+ };
329
+ },
330
+ ///
331
+ // Import a CryptoKey from base64 strings produced by exportKey().
332
+ //
333
+ // @param keyData Base64-encoded raw key bytes.
334
+ // @param _ivData Ignored (kept for API compatibility with exportKey return).
335
+ // @returns A Promise<CryptoKey>.
336
+ ///
337
+ async importKey(keyData, _ivData) {
338
+ if (!_hasWebCrypto()) {
339
+ throw new Error("memorio encryption: Web Crypto API is not available in this environment");
340
+ }
341
+ const keyBytes = _b64decode(keyData);
342
+ if (keyBytes.length !== 32) {
343
+ throw new Error(`memorio encryption: AES-256 key must be exactly 32 bytes, got ${keyBytes.length}`);
344
+ }
345
+ return globalThis.crypto.subtle.importKey(
346
+ "raw",
347
+ keyBytes,
348
+ AES_GCM,
349
+ true,
350
+ ["encrypt", "decrypt"]
351
+ );
352
+ },
353
+ ///
354
+ // Encrypt a JavaScript value.
355
+ //
356
+ // @param value The value to encrypt (any JSON-serializable object).
357
+ // @param key A CryptoKey or a password string (password is derived via PBKDF2).
358
+ // @param keyId Optional label, stored in the envelope for key rotation.
359
+ // @returns An EncryptedEnvelope object.
360
+ ///
361
+ async encrypt(value, key, keyId) {
362
+ const cryptoKey = typeof key === "string" ? await this.deriveKey(key, void 0, "AES-GCM") : key;
363
+ const data = new TextEncoder().encode(JSON.stringify(value));
364
+ const iv = new Uint8Array(12);
365
+ globalThis.crypto.getRandomValues(iv);
366
+ const ciphertext = await globalThis.crypto.subtle.encrypt(
367
+ { name: "AES-GCM", iv },
368
+ cryptoKey,
369
+ data
370
+ );
371
+ const envelope = {
372
+ __memorio_encrypted: true,
373
+ v: 1,
374
+ alg: "AES-GCM",
375
+ iv: _b64encode(iv),
376
+ data: _b64encode(ciphertext)
377
+ };
378
+ if (keyId) envelope.keyId = keyId;
379
+ if (DEV) message_default(`encryption: encrypted value (alg=${envelope.alg})`);
380
+ return envelope;
381
+ },
382
+ ///
383
+ // Decrypt an EncryptedEnvelope.
384
+ //
385
+ // @param envelope The envelope object returned by encrypt().
386
+ // @param key A CryptoKey or a password string.
387
+ // @returns The original value (parsed from JSON).
388
+ ///
389
+ async decrypt(envelope, key) {
390
+ if (!_isEncrypted(envelope)) {
391
+ throw new Error("memorio encryption: value is not a valid encrypted envelope");
392
+ }
393
+ const cryptoKey = typeof key === "string" ? await this.deriveKey(key, void 0, "AES-GCM") : key;
394
+ const iv = _b64decode(envelope.iv);
395
+ const data = _b64decode(envelope.data);
396
+ const decrypted = await globalThis.crypto.subtle.decrypt(
397
+ { name: "AES-GCM", iv },
398
+ cryptoKey,
399
+ data
400
+ );
401
+ return JSON.parse(new TextDecoder().decode(new Uint8Array(decrypted)));
402
+ },
403
+ ///
404
+ // Convenience: encrypt with a password (derives the key internally).
405
+ // Returns a JSON string you can store anywhere.
406
+ ///
407
+ async encryptWithPassword(value, password, salt, keyId) {
408
+ const env = await this.encrypt(value, password, keyId);
409
+ return JSON.stringify(env);
410
+ },
411
+ ///
412
+ // Convenience: decrypt a JSON envelope string with a password.
413
+ ///
414
+ async decryptWithPassword(envelopeJson, password, _salt) {
415
+ const envelope = JSON.parse(envelopeJson);
416
+ return this.decrypt(envelope, password);
417
+ },
418
+ ///
419
+ // Type guard: check whether a value is an encrypted envelope.
420
+ ///
421
+ isEncrypted(value) {
422
+ return _isEncrypted(value);
423
+ },
424
+ ///
425
+ // Configure a default encryption key for auto-encrypt mode.
426
+ // When set on `store` or `session`, all writes are encrypted and all
427
+ // reads attempt decryption automatically.
428
+ ///
429
+ config(opts) {
430
+ if (opts.key !== void 0) this._defaultKey = opts.key;
431
+ if (opts.keyId !== void 0) this._defaultKeyId = opts.keyId;
432
+ return this;
433
+ },
434
+ ///
435
+ // Internal: resolve the configured default key.
436
+ ///
437
+ get _key() {
438
+ return this._defaultKey ?? null;
439
+ },
440
+ get _keyId() {
441
+ return this._defaultKeyId;
442
+ }
443
+ };
444
+ }
445
+ });
446
+
205
447
  // core/platform.ts
206
448
  function generateSessionId() {
207
449
  const anyGlobal = globalThis;
@@ -216,6 +458,9 @@ function generateSessionId() {
216
458
  return `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
217
459
  }
218
460
  function detectPlatform() {
461
+ if (_isBun()) {
462
+ return "bun";
463
+ }
219
464
  const globalAny = globalThis;
220
465
  if (globalAny.Deno && globalAny.Deno.version) {
221
466
  return "deno";
@@ -231,6 +476,13 @@ function detectPlatform() {
231
476
  }
232
477
  return "unknown";
233
478
  }
479
+ function _isBun() {
480
+ const globalAny = globalThis;
481
+ return typeof globalAny.Bun !== "undefined" && typeof globalAny.Bun.version === "string";
482
+ }
483
+ function isBun() {
484
+ return _isBun();
485
+ }
234
486
  function isBrowser() {
235
487
  const platform = detectPlatform();
236
488
  return platform === "browser";
@@ -284,6 +536,9 @@ function hasSqlJs() {
284
536
  }
285
537
  return typeof anyGlobal.window !== "undefined";
286
538
  }
539
+ function hasBunSqlite() {
540
+ return _isBun();
541
+ }
287
542
  function hasDispatchEvent() {
288
543
  return typeof globalThis.dispatchEvent === "function";
289
544
  }
@@ -296,6 +551,7 @@ function getCapabilities() {
296
551
  hasLocalStorage: getLocalStorage() !== null,
297
552
  hasIndexedDB: hasIndexedDB(),
298
553
  hasSqlJs: hasSqlJs(),
554
+ hasBunSqlite: hasBunSqlite(),
299
555
  hasDispatchEvent: hasDispatchEvent(),
300
556
  hasNavigator: typeof navigator !== "undefined",
301
557
  hasProcess: typeof process !== "undefined",
@@ -355,8 +611,9 @@ function initializePlatform() {
355
611
  };
356
612
  }
357
613
  }
358
- function createContext(name) {
614
+ function createContext(name, opts) {
359
615
  const contextId = name || `context_${generateSessionId()}`;
616
+ const encKey = opts?.encryptionKey;
360
617
  setCurrentContext(contextId);
361
618
  const contextStorage = {
362
619
  state: {},
@@ -365,10 +622,31 @@ function createContext(name) {
365
622
  cache: /* @__PURE__ */ new Map()
366
623
  };
367
624
  _contexts.set(contextId, contextStorage);
625
+ function _isEncrypted2(value) {
626
+ return encryption.isEncrypted(value);
627
+ }
628
+ __name(_isEncrypted2, "_isEncrypted");
368
629
  return {
369
630
  id: contextId,
370
631
  state: contextStorage.state,
371
- store: {
632
+ store: encKey ? {
633
+ get: /* @__PURE__ */ __name(async (key) => {
634
+ const data = contextStorage.store.get(key);
635
+ if (!data) return null;
636
+ const parsed = JSON.parse(data);
637
+ if (_isEncrypted2(parsed)) return encryption.decrypt(parsed, encKey);
638
+ return parsed;
639
+ }, "get"),
640
+ set: /* @__PURE__ */ __name(async (key, value) => {
641
+ const env = await encryption.encrypt(value, encKey);
642
+ contextStorage.store.set(key, JSON.stringify(env));
643
+ }, "set"),
644
+ remove: /* @__PURE__ */ __name((key) => contextStorage.store.delete(key), "remove"),
645
+ removeAll: /* @__PURE__ */ __name(() => contextStorage.store.clear(), "removeAll"),
646
+ clearAll: /* @__PURE__ */ __name(() => contextStorage.store.clear(), "clearAll"),
647
+ size: /* @__PURE__ */ __name(() => contextStorage.store.size, "size"),
648
+ isPersistent: false
649
+ } : {
372
650
  get: /* @__PURE__ */ __name((key) => {
373
651
  const data = contextStorage.store.get(key);
374
652
  return data ? JSON.parse(data) : null;
@@ -382,7 +660,24 @@ function createContext(name) {
382
660
  size: /* @__PURE__ */ __name(() => contextStorage.store.size, "size"),
383
661
  isPersistent: false
384
662
  },
385
- session: {
663
+ session: encKey ? {
664
+ get: /* @__PURE__ */ __name(async (key) => {
665
+ const data = contextStorage.session.get(key);
666
+ if (!data) return null;
667
+ const parsed = JSON.parse(data);
668
+ if (_isEncrypted2(parsed)) return encryption.decrypt(parsed, encKey);
669
+ return parsed;
670
+ }, "get"),
671
+ set: /* @__PURE__ */ __name(async (key, value) => {
672
+ const env = await encryption.encrypt(value, encKey);
673
+ contextStorage.session.set(key, JSON.stringify(env));
674
+ }, "set"),
675
+ remove: /* @__PURE__ */ __name((key) => contextStorage.session.delete(key), "remove"),
676
+ removeAll: /* @__PURE__ */ __name(() => contextStorage.session.clear(), "removeAll"),
677
+ clearAll: /* @__PURE__ */ __name(() => contextStorage.session.clear(), "clearAll"),
678
+ size: /* @__PURE__ */ __name(() => contextStorage.session.size, "size"),
679
+ isPersistent: false
680
+ } : {
386
681
  get: /* @__PURE__ */ __name((key) => {
387
682
  const data = contextStorage.session.get(key);
388
683
  return data ? JSON.parse(data) : null;
@@ -402,7 +697,8 @@ function createContext(name) {
402
697
  remove: /* @__PURE__ */ __name((key) => contextStorage.cache.delete(key), "remove"),
403
698
  removeAll: /* @__PURE__ */ __name(() => contextStorage.cache.clear(), "removeAll"),
404
699
  clear: /* @__PURE__ */ __name(() => contextStorage.cache.clear(), "clear")
405
- }
700
+ },
701
+ encryptionKey: encKey
406
702
  };
407
703
  }
408
704
  function listContexts() {
@@ -419,8 +715,11 @@ var init_platform = __esm({
419
715
  "core/platform.ts"() {
420
716
  init_esm_shims();
421
717
  init_internal();
718
+ init_encryption();
422
719
  __name(generateSessionId, "generateSessionId");
423
720
  __name(detectPlatform, "detectPlatform");
721
+ __name(_isBun, "_isBun");
722
+ __name(isBun, "isBun");
424
723
  __name(isBrowser, "isBrowser");
425
724
  __name(isNode, "isNode");
426
725
  __name(isDeno, "isDeno");
@@ -429,6 +728,7 @@ var init_platform = __esm({
429
728
  __name(getLocalStorage, "getLocalStorage");
430
729
  __name(hasIndexedDB, "hasIndexedDB");
431
730
  __name(hasSqlJs, "hasSqlJs");
731
+ __name(hasBunSqlite, "hasBunSqlite");
432
732
  __name(hasDispatchEvent, "hasDispatchEvent");
433
733
  __name(getCapabilities, "getCapabilities");
434
734
  _eventListenerStorage = /* @__PURE__ */ new Map();
@@ -454,6 +754,9 @@ function _getFallbackStorage() {
454
754
  }
455
755
  return _fallbackStorageByContext.get(key);
456
756
  }
757
+ function _isEncryptedEnvelope(value) {
758
+ return encryption.isEncrypted(value);
759
+ }
457
760
  function _getPrefix() {
458
761
  const contextName = internal_default.currentContext || "";
459
762
  return contextName ? `${contextName}-` : `memorio_store_`;
@@ -490,17 +793,23 @@ function _remove(prefixedName) {
490
793
  }
491
794
  return false;
492
795
  }
493
- var _localStorage, _fallbackStorageByContext, _hasStorage, STORE_INSTANCE_KEY, store;
796
+ var _localStorage, _fallbackStorageByContext, _hasStorage, _encryptionKey, _onError, _maxObjectSize, _maxTotalSize, STORE_INSTANCE_KEY, store;
494
797
  var init_store = __esm({
495
798
  "functions/store/index.ts"() {
496
799
  init_esm_shims();
497
800
  init_platform();
498
801
  init_internal();
499
802
  init_message();
803
+ init_encryption();
500
804
  _localStorage = getLocalStorage();
501
805
  _fallbackStorageByContext = /* @__PURE__ */ new Map();
502
806
  __name(_getFallbackStorage, "_getFallbackStorage");
503
807
  _hasStorage = _localStorage !== null;
808
+ _encryptionKey = null;
809
+ _onError = null;
810
+ _maxObjectSize = 0;
811
+ _maxTotalSize = 0;
812
+ __name(_isEncryptedEnvelope, "_isEncryptedEnvelope");
504
813
  __name(_getPrefix, "_getPrefix");
505
814
  __name(_prefixKey, "_prefixKey");
506
815
  __name(_read, "_read");
@@ -517,16 +826,24 @@ var init_store = __esm({
517
826
  /**
518
827
  * Gets a value from storage.
519
828
  * @param name The key to retrieve.
520
- * @returns The parsed value or null if not found.
829
+ * @param opts Optional { decrypt: key } to decrypt an encrypted envelope.
830
+ * When no key is passed, encrypted envelopes are returned as-is.
831
+ * If a default key was configured via store.config(), it is used automatically.
832
+ * @returns The parsed value, a Promise<parsed value> when decrypting, or null if not found.
521
833
  */
522
834
  get: {
523
- value: /* @__PURE__ */ __name((name) => {
835
+ value: /* @__PURE__ */ __name((name, opts) => {
524
836
  if (!name) {
525
837
  console.warn("[memorio store] store.get() called with empty or null key - returning null");
526
838
  return null;
527
839
  }
528
840
  try {
529
- return _read(_prefixKey(name));
841
+ const raw = _read(_prefixKey(name));
842
+ const key = opts?.decrypt ?? _encryptionKey;
843
+ if (key && _isEncryptedEnvelope(raw)) {
844
+ return encryption.decrypt(raw, key);
845
+ }
846
+ return raw;
530
847
  } catch (err) {
531
848
  message(`Error parsing store item '${name}': ${err}`);
532
849
  }
@@ -551,10 +868,13 @@ var init_store = __esm({
551
868
  * Sets a value in storage.
552
869
  * @param name The key to set.
553
870
  * @param value The value to store (objects, arrays, primitives).
554
- * @returns true if written, false if the key was rejected.
871
+ * @param opts Optional { encrypt: key } to encrypt the value before storage.
872
+ * If a default key was configured via store.config(), it is used automatically.
873
+ * When encryption is used, returns a Promise<boolean>.
874
+ * @returns true if written, false if rejected or error.
555
875
  */
556
876
  set: {
557
- value: /* @__PURE__ */ __name((name, value) => {
877
+ value: /* @__PURE__ */ __name((name, value, opts) => {
558
878
  if (!name) {
559
879
  console.warn("[memorio store] store.set() called with empty or null key - write aborted");
560
880
  return false;
@@ -566,15 +886,66 @@ var init_store = __esm({
566
886
  message("Storing functions is not secure and is blocked for safety.");
567
887
  return false;
568
888
  }
889
+ if (_maxObjectSize > 0 || _maxTotalSize > 0) {
890
+ let serializedSize = 0;
891
+ try {
892
+ serializedSize = new TextEncoder().encode(JSON.stringify(value)).length;
893
+ } catch {
894
+ serializedSize = 0;
895
+ }
896
+ if (_maxObjectSize > 0 && serializedSize > _maxObjectSize) {
897
+ const err = new Error(`Object size (${serializedSize} bytes) exceeds maxObjectSize (${_maxObjectSize} bytes)`);
898
+ _onError?.(err, { operation: "set" });
899
+ return false;
900
+ }
901
+ if (_maxTotalSize > 0) {
902
+ const currentTotal = store.size() * 1024;
903
+ const existingItemSize = _hasStorage ? _localStorage.getItem(prefixedName)?.length ?? 0 : _getFallbackStorage().get(prefixedName)?.length ?? 0;
904
+ const projected = currentTotal * 1024 - existingItemSize + serializedSize;
905
+ if (projected > _maxTotalSize) {
906
+ const err = new Error(`Total store size (${projected} bytes) exceeds maxTotalSize (${_maxTotalSize} bytes)`);
907
+ _onError?.(err, { operation: "set" });
908
+ return false;
909
+ }
910
+ }
911
+ }
912
+ const key = opts?.encrypt ?? _encryptionKey;
913
+ if (key) {
914
+ return encryption.encrypt(value, key).then((env) => {
915
+ _write(prefixedName, env);
916
+ return true;
917
+ }).catch((err) => {
918
+ message(`Error encrypting store item '${name}': ${err}`);
919
+ _onError?.(err, { operation: "set" });
920
+ return false;
921
+ });
922
+ }
569
923
  try {
570
924
  _write(prefixedName, value);
571
925
  } catch (err) {
572
926
  message(`Error setting store item '${name}': ${err}`);
927
+ _onError?.(err, { operation: "set" });
573
928
  return false;
574
929
  }
575
930
  return true;
576
931
  }, "value")
577
932
  },
933
+ /**
934
+ * Configure store-wide behavior.
935
+ * @param opts Optional { encryptionKey } to enable automatic encryption
936
+ * for all set/get operations. When set, values are encrypted
937
+ * on write and decrypted on read (if the value is an envelope).
938
+ * @returns The store instance for chaining.
939
+ */
940
+ config: {
941
+ value: /* @__PURE__ */ __name((opts) => {
942
+ if (opts.encryptionKey !== void 0) _encryptionKey = opts.encryptionKey;
943
+ if (opts.onError !== void 0) _onError = opts.onError;
944
+ if (opts.maxObjectSize !== void 0) _maxObjectSize = opts.maxObjectSize;
945
+ if (opts.maxTotalSize !== void 0) _maxTotalSize = opts.maxTotalSize;
946
+ return store;
947
+ }, "value")
948
+ },
578
949
  /**
579
950
  * Removes a value from storage.
580
951
  * @param name The key to remove.
@@ -945,8 +1316,8 @@ var init_table_size = __esm({
945
1316
  if (!db.objectStoreNames.contains(table)) return resolve(0);
946
1317
  let size = 0;
947
1318
  let count = 0;
948
- const transaction = db.transaction([table], "readonly");
949
- const store2 = transaction.objectStore(table);
1319
+ const transaction2 = db.transaction([table], "readonly");
1320
+ const store2 = transaction2.objectStore(table);
950
1321
  const request = store2.openCursor();
951
1322
  request.onsuccess = async (event) => {
952
1323
  const cursor = event.target.result;
@@ -990,8 +1361,8 @@ var init_data_delete = __esm({
990
1361
  db.close();
991
1362
  return reject(new Error(`Table ${table} not found`));
992
1363
  }
993
- const transaction = db.transaction(table, "readwrite");
994
- const objectStore = transaction.objectStore(table);
1364
+ const transaction2 = db.transaction(table, "readwrite");
1365
+ const objectStore = transaction2.objectStore(table);
995
1366
  const deleteRequest = objectStore.delete(key);
996
1367
  deleteRequest.onsuccess = () => {
997
1368
  db.close();
@@ -1015,8 +1386,8 @@ var init_data_delete = __esm({
1015
1386
  db.close();
1016
1387
  return reject(new Error(`Table ${table} not found`));
1017
1388
  }
1018
- const transaction = db.transaction(table, "readwrite");
1019
- const store2 = transaction.objectStore(table);
1389
+ const transaction2 = db.transaction(table, "readwrite");
1390
+ const store2 = transaction2.objectStore(table);
1020
1391
  const clearRequest = store2.clear();
1021
1392
  clearRequest.onsuccess = () => {
1022
1393
  db.close();
@@ -1050,8 +1421,8 @@ var init_data_set = __esm({
1050
1421
  db.close();
1051
1422
  return reject(new Error(`Table ${table} does not exist in ${storeName}`));
1052
1423
  }
1053
- const transaction = db.transaction(table, "readwrite");
1054
- const objectStore = transaction.objectStore(table);
1424
+ const transaction2 = db.transaction(table, "readwrite");
1425
+ const objectStore = transaction2.objectStore(table);
1055
1426
  const putRequest = objectStore.put(value);
1056
1427
  putRequest.onsuccess = () => {
1057
1428
  db.close();
@@ -1087,8 +1458,8 @@ var init_data_get = __esm({
1087
1458
  db.close();
1088
1459
  return reject(new Error(`Table ${table} not found in ${storeName}`));
1089
1460
  }
1090
- const transaction = db.transaction(table, "readonly");
1091
- const store2 = transaction.objectStore(table);
1461
+ const transaction2 = db.transaction(table, "readonly");
1462
+ const store2 = transaction2.objectStore(table);
1092
1463
  const getRequest = store2.get(key);
1093
1464
  getRequest.onsuccess = () => {
1094
1465
  db.close();
@@ -1160,6 +1531,91 @@ var init_idb = __esm({
1160
1531
  }
1161
1532
  });
1162
1533
 
1534
+ // functions/sqlite/tools/bun-sqlite-adapter.ts
1535
+ var bun_sqlite_adapter_exports = {};
1536
+ __export(bun_sqlite_adapter_exports, {
1537
+ BunSqlJsDatabase: () => BunSqlJsDatabase,
1538
+ createBunSqlJs: () => createBunSqlJs
1539
+ });
1540
+ async function _loadDatabase() {
1541
+ if (!_DatabaseClass) {
1542
+ const mod = await import('bun:sqlite');
1543
+ _DatabaseClass = mod.Database;
1544
+ }
1545
+ return _DatabaseClass;
1546
+ }
1547
+ async function createBunSqlJs() {
1548
+ await _loadDatabase();
1549
+ return {
1550
+ Database: BunSqlJsDatabase,
1551
+ version: "bun:sqlite"
1552
+ };
1553
+ }
1554
+ var _DatabaseClass, BunSqlJsDatabase;
1555
+ var init_bun_sqlite_adapter = __esm({
1556
+ "functions/sqlite/tools/bun-sqlite-adapter.ts"() {
1557
+ init_esm_shims();
1558
+ _DatabaseClass = null;
1559
+ __name(_loadDatabase, "_loadDatabase");
1560
+ BunSqlJsDatabase = class {
1561
+ static {
1562
+ __name(this, "BunSqlJsDatabase");
1563
+ }
1564
+ _db;
1565
+ _lastRunChanges = 0;
1566
+ constructor(data) {
1567
+ this._lastRunChanges = 0;
1568
+ if (typeof data === "string") {
1569
+ this._db = new _DatabaseClass(data);
1570
+ } else {
1571
+ this._db = new _DatabaseClass(":memory:");
1572
+ }
1573
+ }
1574
+ run(sql, params = []) {
1575
+ const info = this._db.run(sql, ...params);
1576
+ this._lastRunChanges = info?.changes ?? 0;
1577
+ return info;
1578
+ }
1579
+ getRowsModified() {
1580
+ return this._lastRunChanges;
1581
+ }
1582
+ prepare(sql, params = []) {
1583
+ const rows = params.length > 0 ? this._db.query(sql).all(...params) : this._db.query(sql).all();
1584
+ return {
1585
+ _rows: rows,
1586
+ _idx: -1,
1587
+ step() {
1588
+ this._idx++;
1589
+ return this._idx < this._rows.length;
1590
+ },
1591
+ getAsObject() {
1592
+ return this._rows[this._idx] || {};
1593
+ },
1594
+ get() {
1595
+ return this._rows[this._idx] ? Object.values(this._rows[this._idx]) : [];
1596
+ },
1597
+ free() {
1598
+ this._rows = null;
1599
+ }
1600
+ };
1601
+ }
1602
+ export() {
1603
+ throw new Error("Bun:sqlite does not support in-memory export - use store/session for persistence, or use the sql.js backend for export/import operations");
1604
+ }
1605
+ close() {
1606
+ try {
1607
+ this._db.close();
1608
+ } catch {
1609
+ }
1610
+ }
1611
+ get version() {
1612
+ return "bun:sqlite";
1613
+ }
1614
+ };
1615
+ __name(createBunSqlJs, "createBunSqlJs");
1616
+ }
1617
+ });
1618
+
1163
1619
  // functions/sqlite/tools/db.support.ts
1164
1620
  var db_support_exports2 = {};
1165
1621
  function _inDocument() {
@@ -1220,11 +1676,18 @@ var init_db_support2 = __esm({
1220
1676
  return g3.initSqlJs || g3;
1221
1677
  }, "_loadSqlJsFromCdn");
1222
1678
  sqlite.db.support = () => {
1223
- return hasSqlJs();
1679
+ return hasSqlJs() || hasBunSqlite();
1224
1680
  };
1225
1681
  sqlite.db.getSQL = async () => {
1226
1682
  if (_SQL) return _SQL;
1227
1683
  if (_loading) return _loading;
1684
+ if (hasBunSqlite()) {
1685
+ const { createBunSqlJs: createBunSqlJs2 } = await Promise.resolve().then(() => (init_bun_sqlite_adapter(), bun_sqlite_adapter_exports));
1686
+ _SQL = await createBunSqlJs2();
1687
+ globalThis.sqliteVersion = _SQL.version;
1688
+ message_default("Memorio SQLite: bun:sqlite engine loaded");
1689
+ return _SQL;
1690
+ }
1228
1691
  const g3 = globalThis;
1229
1692
  const cfg = g3.sqliteConfig || {};
1230
1693
  const p = (async () => {
@@ -1251,7 +1714,7 @@ var init_db_support2 = __esm({
1251
1714
  } catch (_) {
1252
1715
  }
1253
1716
  try {
1254
- sqlite._warning = "Memorio SQLite: sql.js could not be loaded. Install sql.js (npm i sql.js) and pass a loader via sqlite.config({ loader: () => <your sql.js import>() }).";
1717
+ sqlite._warning = "Memorio SQLite: sql.js could not be loaded. Install sql.js (npm i sql.js) and pass a loader via sqlite.config({ loader: () => import(<your sql.js import>()) }).";
1255
1718
  } catch (_) {
1256
1719
  }
1257
1720
  console.warn("Memorio SQLite: failed to load sql.js", err);
@@ -1274,7 +1737,7 @@ function _ns() {
1274
1737
  function _key(name) {
1275
1738
  return `memorio:sqlite:db:${_ns()}:${name}`;
1276
1739
  }
1277
- function _b64encode(buf) {
1740
+ function _b64encode2(buf) {
1278
1741
  const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
1279
1742
  let binary = "";
1280
1743
  const len = bytes.byteLength;
@@ -1282,7 +1745,7 @@ function _b64encode(buf) {
1282
1745
  if (typeof btoa === "function") return btoa(binary);
1283
1746
  return typeof Buffer !== "undefined" ? Buffer.from(bytes).toString("base64") : "";
1284
1747
  }
1285
- function _b64decode(b64) {
1748
+ function _b64decode2(b64) {
1286
1749
  if (typeof Buffer !== "undefined") {
1287
1750
  return new Uint8Array(Buffer.from(b64, "base64"));
1288
1751
  }
@@ -1304,7 +1767,7 @@ function saveSnapshot(name) {
1304
1767
  }
1305
1768
  try {
1306
1769
  const blob = db.export();
1307
- store.set(_key(name), _b64encode(blob));
1770
+ store.set(_key(name), _b64encode2(blob));
1308
1771
  message_default(`Memorio SQLite: persisted '${name}' to store`);
1309
1772
  resolve(true);
1310
1773
  } catch (err) {
@@ -1317,7 +1780,7 @@ function loadSnapshot(name) {
1317
1780
  const b64 = store.get(_key(name));
1318
1781
  if (!b64) return null;
1319
1782
  try {
1320
- return _b64decode(b64);
1783
+ return _b64decode2(b64);
1321
1784
  } catch {
1322
1785
  return null;
1323
1786
  }
@@ -1352,8 +1815,8 @@ var init_persist = __esm({
1352
1815
  _exportTimers = {};
1353
1816
  __name(_ns, "_ns");
1354
1817
  __name(_key, "_key");
1355
- __name(_b64encode, "_b64encode");
1356
- __name(_b64decode, "_b64decode");
1818
+ __name(_b64encode2, "_b64encode");
1819
+ __name(_b64decode2, "_b64decode");
1357
1820
  __name(saveSnapshot, "saveSnapshot");
1358
1821
  __name(loadSnapshot, "loadSnapshot");
1359
1822
  __name(removeSnapshot, "removeSnapshot");
@@ -1558,7 +2021,14 @@ var init_db_export = __esm({
1558
2021
  init_sqlite();
1559
2022
  sqlite.db.export = async (name = "memorio") => {
1560
2023
  const db = sqlite.db.get(name);
1561
- return db.export();
2024
+ try {
2025
+ return db.export();
2026
+ } catch (err) {
2027
+ if (db && db.version === "bun:sqlite") {
2028
+ throw new Error(`memorio sqlite: export is not supported under Bun's native sqlite. Use \`store\` or \`session\` for persistence instead. If you need a binary dump, run this code under the browser/sql.js backend.`);
2029
+ }
2030
+ throw err;
2031
+ }
1562
2032
  };
1563
2033
  }
1564
2034
  });
@@ -1642,13 +2112,14 @@ var init_data_get2 = __esm({
1642
2112
  });
1643
2113
 
1644
2114
  // functions/sqlite/index.ts
1645
- var _hasSqlJs, sqlite;
2115
+ var _hasSqlJs, _hasBunSqlite, sqlite;
1646
2116
  var init_sqlite = __esm({
1647
2117
  "functions/sqlite/index.ts"() {
1648
2118
  init_esm_shims();
1649
2119
  init_platform();
1650
2120
  init_env();
1651
2121
  _hasSqlJs = hasSqlJs();
2122
+ _hasBunSqlite = hasBunSqlite();
1652
2123
  sqlite = {
1653
2124
  db: {},
1654
2125
  query: {},
@@ -1675,7 +2146,7 @@ var init_sqlite = __esm({
1675
2146
  return g3.sqliteReady;
1676
2147
  }, "get")
1677
2148
  });
1678
- if (_hasSqlJs) {
2149
+ if (_hasSqlJs || _hasBunSqlite) {
1679
2150
  (async () => {
1680
2151
  Object.defineProperty(sqlite, "db", { value: {}, writable: false, configurable: true, enumerable: true });
1681
2152
  Object.defineProperty(sqlite, "query", { value: {}, writable: false, configurable: true, enumerable: true });
@@ -1703,11 +2174,11 @@ var init_sqlite = __esm({
1703
2174
  })();
1704
2175
  } else {
1705
2176
  sqlite._disabled = true;
1706
- sqlite._warning = 'SQLite (sql.js) is not available in this environment. It requires a browser with WebAssembly support. Install the optional "sql.js" package to enable it.';
2177
+ sqlite._warning = 'SQLite is not available in this environment. It requires a browser with WebAssembly (sql.js) or the Bun runtime (bun:sqlite). Install the optional "sql.js" package to enable it in browsers.';
1707
2178
  if (DEV) {
1708
2179
  globalThis.sqliteDisabled = true;
1709
2180
  globalThis.sqliteWarning = sqlite._warning;
1710
- console.warn("Memorio SQLite: sql.js is not available in this environment (requires browser + WebAssembly). Use store or session for persistence.");
2181
+ console.warn("Memorio SQLite: no engine available in this environment (requires browser + WebAssembly, or Bun runtime with bun:sqlite). Use store or session for persistence.");
1711
2182
  }
1712
2183
  }
1713
2184
  }
@@ -1750,9 +2221,25 @@ var dispatch = {
1750
2221
  const wrapped = /* @__PURE__ */ __name((e) => {
1751
2222
  const target = e;
1752
2223
  if (globalThis.queueMicrotask) {
1753
- globalThis.queueMicrotask(() => cb(target));
2224
+ globalThis.queueMicrotask(() => {
2225
+ try {
2226
+ cb(target);
2227
+ } catch (err) {
2228
+ if (typeof console !== "undefined") {
2229
+ console.error("[memorio dispatch] observer error:", err);
2230
+ }
2231
+ }
2232
+ });
1754
2233
  } else {
1755
- Promise.resolve().then(() => cb(target));
2234
+ Promise.resolve().then(() => {
2235
+ try {
2236
+ cb(target);
2237
+ } catch (err) {
2238
+ if (typeof console !== "undefined") {
2239
+ console.error("[memorio dispatch] observer error:", err);
2240
+ }
2241
+ }
2242
+ });
1756
2243
  }
1757
2244
  }, "wrapped");
1758
2245
  globalThis.addEventListener(name, wrapped);
@@ -1888,101 +2375,589 @@ var schema = {
1888
2375
  // functions/state/index.ts
1889
2376
  init_store();
1890
2377
  init_env();
1891
- var TARGET = /* @__PURE__ */ Symbol("memorio.target");
1892
- var wrapperCache = /* @__PURE__ */ new WeakMap();
1893
- var deepRaw = /* @__PURE__ */ __name((val, seen = null) => {
1894
- if (val === null || typeof val !== "object") return val;
1895
- if (val[TARGET] !== void 0) return deepRaw(val[TARGET], seen);
1896
- if (seen) {
1897
- if (seen.has(val)) return val;
1898
- seen.add(val);
2378
+
2379
+ // core/mutation/engine.ts
2380
+ init_esm_shims();
2381
+ init_internal();
2382
+
2383
+ // core/hlc.ts
2384
+ init_esm_shims();
2385
+ var NODE_ID_KEY = "__memorio_hlc_node";
2386
+ function getNodeId() {
2387
+ if (typeof globalThis === "undefined") return "node";
2388
+ try {
2389
+ if (typeof sessionStorage !== "undefined" && sessionStorage) {
2390
+ let id = sessionStorage.getItem(NODE_ID_KEY);
2391
+ if (!id) {
2392
+ id = generateNodeId();
2393
+ sessionStorage.setItem(NODE_ID_KEY, id);
2394
+ }
2395
+ return id;
2396
+ }
2397
+ } catch {
1899
2398
  }
1900
- const ctor = val.constructor?.name;
1901
- if (ctor !== "Object" && ctor !== "Array") return val;
1902
- const copy = Array.isArray(val) ? [] : {};
1903
- for (const k of Reflect.ownKeys(val)) {
1904
- if (!Object.prototype.propertyIsEnumerable.call(val, k)) continue;
1905
- copy[k] = deepRaw(val[k], seen);
2399
+ if (!globalThis.__memorioHlcNodeId) {
2400
+ globalThis.__memorioHlcNodeId = generateNodeId();
1906
2401
  }
1907
- return copy;
1908
- }, "deepRaw");
1909
- var objPath = /* @__PURE__ */ __name((prop, object, separator = ".") => {
1910
- return object.concat(prop).join(separator);
1911
- }, "objPath");
1912
- var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
1913
- const event = /* @__PURE__ */ __name((name) => {
1914
- try {
1915
- dispatch.set(name, { detail: { name } });
1916
- } catch (err) {
1917
- if (DEV) console.warn("[memorio state] event dispatch failed:", err);
1918
- }
1919
- return;
1920
- }, "event");
1921
- return new Proxy(
1922
- obj,
1923
- {
1924
- get(target, prop) {
1925
- if (prop === "__path") {
1926
- return tree.length > 0 ? "state." + tree.join(".") : "state";
1927
- }
1928
- if (prop === TARGET) {
1929
- return target;
1930
- }
1931
- if (target[TARGET] !== void 0) {
1932
- return target;
1933
- }
1934
- if (prop === "list") {
1935
- message_default('Some state could be hidden when you use "state.list". Use "state" to see the complete list ');
1936
- return deepRaw(target, /* @__PURE__ */ new WeakSet());
1937
- }
1938
- if (typeof prop === "string") {
1939
- const path2 = tree.length > 0 ? "state." + tree.concat(prop).join(".") : "state." + prop;
1940
- internal_default.lastAccessedPath = path2;
1941
- if (internal_default.tracking) {
1942
- internal_default.trackedPaths.add(path2);
1943
- }
1944
- }
1945
- if (prop === "_lastPath") {
1946
- return internal_default.lastAccessedPath;
1947
- }
1948
- if (prop === "remove") {
1949
- return (key) => {
1950
- delete target[key];
1951
- return true;
1952
- };
1953
- }
1954
- if (prop === "removeAll") {
1955
- return () => {
1956
- try {
1957
- for (const key in target) {
1958
- if (typeof target[key] !== "function" && !["list", "remove", "removeAll", "lock", "unlock"].includes(key)) {
1959
- delete target[key];
1960
- }
1961
- }
1962
- } catch (error) {
1963
- console.error(error);
1964
- }
1965
- return;
1966
- };
1967
- }
1968
- if (Object.isFrozen(target[prop])) return target[prop];
1969
- if (prop === "lock" || prop === "unlock") {
1970
- const value = Reflect.get(target, prop);
1971
- if (value) return value;
1972
- }
1973
- try {
1974
- const value = Reflect.get(target, prop);
1975
- if (value && typeof value === "object" && ["Array", "Object"].includes(value.constructor.name)) {
1976
- let wrapper = wrapperCache.get(value);
1977
- if (!wrapper) {
1978
- wrapper = buildProxy(value, callback, tree.concat(prop));
1979
- wrapperCache.set(value, wrapper);
1980
- }
1981
- return wrapper;
1982
- }
1983
- return value;
1984
- } catch (error) {
1985
- console.error("Error: ", error);
2402
+ return globalThis.__memorioHlcNodeId;
2403
+ }
2404
+ __name(getNodeId, "getNodeId");
2405
+ function generateNodeId() {
2406
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
2407
+ return crypto.randomUUID().slice(0, 8);
2408
+ }
2409
+ return Math.random().toString(36).slice(2, 10);
2410
+ }
2411
+ __name(generateNodeId, "generateNodeId");
2412
+ var HLC_KEY = "__memorio_hlc_local";
2413
+ var local = globalThis[HLC_KEY] || {
2414
+ physical: 0,
2415
+ logical: 0,
2416
+ node: getNodeId()
2417
+ };
2418
+ if (!globalThis[HLC_KEY]) {
2419
+ globalThis[HLC_KEY] = local;
2420
+ }
2421
+ function tick(_incoming) {
2422
+ const now2 = Date.now();
2423
+ const base = local.physical;
2424
+ let physical;
2425
+ let logical;
2426
+ if (now2 > base) {
2427
+ physical = now2;
2428
+ logical = 0;
2429
+ } else if (now2 < base) {
2430
+ physical = base;
2431
+ logical = local.logical + 1;
2432
+ } else {
2433
+ physical = base;
2434
+ logical = local.logical + 1;
2435
+ }
2436
+ local.physical = physical;
2437
+ local.logical = logical;
2438
+ return { physical, logical, node: local.node };
2439
+ }
2440
+ __name(tick, "tick");
2441
+ function receive(remote) {
2442
+ const now2 = Date.now();
2443
+ if (remote.physical > local.physical) {
2444
+ local.physical = remote.physical > now2 ? remote.physical : now2;
2445
+ local.logical = 1;
2446
+ } else if (remote.physical === local.physical) {
2447
+ local.logical = Math.max(local.logical, remote.logical) + 1;
2448
+ }
2449
+ local.node = getNodeId();
2450
+ return { ...local };
2451
+ }
2452
+ __name(receive, "receive");
2453
+ function compare(a, b) {
2454
+ if (a.physical !== b.physical) {
2455
+ return a.physical < b.physical ? -1 : 1;
2456
+ }
2457
+ if (a.logical !== b.logical) {
2458
+ return a.logical < b.logical ? -1 : 1;
2459
+ }
2460
+ if (a.node !== b.node) {
2461
+ return a.node < b.node ? -1 : 1;
2462
+ }
2463
+ return 0;
2464
+ }
2465
+ __name(compare, "compare");
2466
+ function happenedBefore(a, b) {
2467
+ return compare(a, b) < 0;
2468
+ }
2469
+ __name(happenedBefore, "happenedBefore");
2470
+ function serialize(hlc2) {
2471
+ return `hlc:${hlc2.physical}:${hlc2.logical}:${hlc2.node}`;
2472
+ }
2473
+ __name(serialize, "serialize");
2474
+ function parse(serialized) {
2475
+ if (!serialized.startsWith("hlc:")) return null;
2476
+ const parts = serialized.split(":");
2477
+ if (parts.length !== 4) return null;
2478
+ const physical = parseInt(parts[1], 10);
2479
+ const logical = parseInt(parts[2], 10);
2480
+ const node = parts[3];
2481
+ if (isNaN(physical) || isNaN(logical)) return null;
2482
+ return { physical, logical, node };
2483
+ }
2484
+ __name(parse, "parse");
2485
+ var hlc = {
2486
+ tick,
2487
+ receive,
2488
+ compare,
2489
+ happenedBefore,
2490
+ serialize,
2491
+ parse,
2492
+ getNodeId
2493
+ };
2494
+
2495
+ // core/mutation/id.ts
2496
+ init_esm_shims();
2497
+ function generateMutationId() {
2498
+ const now2 = hlc.tick();
2499
+ return "m_" + encodeHLC(now2);
2500
+ }
2501
+ __name(generateMutationId, "generateMutationId");
2502
+ function generateTransactionId() {
2503
+ const now2 = hlc.tick();
2504
+ return "tx_" + encodeHLC(now2);
2505
+ }
2506
+ __name(generateTransactionId, "generateTransactionId");
2507
+ function generateCommitId() {
2508
+ const now2 = hlc.tick();
2509
+ return "c_" + encodeHLC(now2);
2510
+ }
2511
+ __name(generateCommitId, "generateCommitId");
2512
+ function encodeHLC(hlcValue) {
2513
+ const timePart = hlcValue.physical.toString(36);
2514
+ const logicalPart = hlcValue.logical.toString(36).padStart(2, "0");
2515
+ const nodePart = hlcValue.node.slice(0, 4);
2516
+ return `${timePart}${logicalPart}${nodePart}`;
2517
+ }
2518
+ __name(encodeHLC, "encodeHLC");
2519
+
2520
+ // core/mutation/patch.ts
2521
+ init_esm_shims();
2522
+ function mutationToPatch(mutation) {
2523
+ if (mutation.before === mutation.after) return null;
2524
+ const op = mutationToPatchOp(mutation.operation, mutation.before, mutation.after);
2525
+ if (!op) return null;
2526
+ const patch = { op, path: mutation.path };
2527
+ if (op === "add" || op === "replace") {
2528
+ patch.value = mutation.after;
2529
+ }
2530
+ if (op === "replace") {
2531
+ patch.oldValue = mutation.before;
2532
+ }
2533
+ if (op === "remove") {
2534
+ patch.oldValue = mutation.before;
2535
+ }
2536
+ return patch;
2537
+ }
2538
+ __name(mutationToPatch, "mutationToPatch");
2539
+ function mutationToPatchOp(operation, _before, _after) {
2540
+ switch (operation) {
2541
+ case "set":
2542
+ if (_before === void 0) return "add";
2543
+ return "replace";
2544
+ case "delete":
2545
+ return "remove";
2546
+ case "insert":
2547
+ return "add";
2548
+ case "remove":
2549
+ return "remove";
2550
+ case "replace":
2551
+ return "replace";
2552
+ case "length":
2553
+ return "replace";
2554
+ default:
2555
+ return null;
2556
+ }
2557
+ }
2558
+ __name(mutationToPatchOp, "mutationToPatchOp");
2559
+ function diffToPatch(path2, before2, after2) {
2560
+ if (before2 === after2) return null;
2561
+ if (after2 === void 0) {
2562
+ return { op: "remove", path: path2, oldValue: before2 };
2563
+ }
2564
+ if (before2 === void 0) {
2565
+ return { op: "add", path: path2, value: after2 };
2566
+ }
2567
+ return { op: "replace", path: path2, value: after2, oldValue: before2 };
2568
+ }
2569
+ __name(diffToPatch, "diffToPatch");
2570
+ function canMerge(patch1, patch2) {
2571
+ return patch1.path === patch2.path && patch1.op === patch2.op;
2572
+ }
2573
+ __name(canMerge, "canMerge");
2574
+ function mergePatches(patch1, patch2) {
2575
+ const op = patch1.op === "remove" && patch2.op === "remove" ? "remove" : "replace";
2576
+ return {
2577
+ op,
2578
+ path: patch1.path,
2579
+ value: patch2.value ?? patch1.value,
2580
+ oldValue: patch1.oldValue
2581
+ };
2582
+ }
2583
+ __name(mergePatches, "mergePatches");
2584
+
2585
+ // core/mutation/transaction.ts
2586
+ init_esm_shims();
2587
+ init_internal();
2588
+ var TX_REGISTRY_KEY = "__memorio_transaction_registry__";
2589
+ var registry = globalThis[TX_REGISTRY_KEY] || /* @__PURE__ */ new Map();
2590
+ if (!globalThis[TX_REGISTRY_KEY]) {
2591
+ globalThis[TX_REGISTRY_KEY] = registry;
2592
+ }
2593
+ var TX_STACK_KEY = "__memorio_transaction_stack__";
2594
+ var txStack = globalThis[TX_STACK_KEY] || [];
2595
+ if (!globalThis[TX_STACK_KEY]) {
2596
+ globalThis[TX_STACK_KEY] = txStack;
2597
+ }
2598
+ function getActiveTxId() {
2599
+ return txStack.length > 0 ? txStack[txStack.length - 1] : null;
2600
+ }
2601
+ __name(getActiveTxId, "getActiveTxId");
2602
+ function setActiveTx(id) {
2603
+ if (id === null) {
2604
+ txStack.pop();
2605
+ } else {
2606
+ txStack.push(id);
2607
+ }
2608
+ }
2609
+ __name(setActiveTx, "setActiveTx");
2610
+ function beginTransaction(source, message2, metadata) {
2611
+ const id = generateTransactionId();
2612
+ const ctx = {
2613
+ id,
2614
+ startedAt: hlc.serialize(hlc.tick()),
2615
+ source,
2616
+ message: message2,
2617
+ metadata,
2618
+ mutations: [],
2619
+ active: true
2620
+ };
2621
+ registry.set(id, ctx);
2622
+ setActiveTx(id);
2623
+ return ctx;
2624
+ }
2625
+ __name(beginTransaction, "beginTransaction");
2626
+ function tagForTransaction() {
2627
+ const txId = getActiveTxId();
2628
+ if (!txId) return void 0;
2629
+ const ctx = registry.get(txId);
2630
+ if (ctx && ctx.active) {
2631
+ return txId;
2632
+ }
2633
+ return void 0;
2634
+ }
2635
+ __name(tagForTransaction, "tagForTransaction");
2636
+ function commitTransaction() {
2637
+ const txId = getActiveTxId();
2638
+ if (!txId) return null;
2639
+ const ctx = registry.get(txId);
2640
+ if (!ctx || !ctx.active) return null;
2641
+ ctx.active = false;
2642
+ ctx.committedAt = hlc.serialize(hlc.tick());
2643
+ const tx = {
2644
+ id: ctx.id,
2645
+ mutations: ctx.mutations,
2646
+ startedAt: ctx.startedAt,
2647
+ committedAt: ctx.committedAt,
2648
+ source: ctx.source,
2649
+ message: ctx.message,
2650
+ metadata: ctx.metadata
2651
+ };
2652
+ setActiveTx(null);
2653
+ return tx;
2654
+ }
2655
+ __name(commitTransaction, "commitTransaction");
2656
+ function _setPath(path2, value) {
2657
+ const parts = path2.replace(/^state\./, "").split(".");
2658
+ let current = globalThis.state;
2659
+ for (let i = 0; i < parts.length - 1; i++) {
2660
+ const part = parts[i];
2661
+ if (current[part] === void 0) {
2662
+ current[part] = {};
2663
+ }
2664
+ current = current[part];
2665
+ }
2666
+ current[parts[parts.length - 1]] = value;
2667
+ }
2668
+ __name(_setPath, "_setPath");
2669
+ function _deletePath(path2) {
2670
+ const parts = path2.replace(/^state\./, "").split(".");
2671
+ let current = globalThis.state;
2672
+ for (let i = 0; i < parts.length - 1; i++) {
2673
+ const part = parts[i];
2674
+ if (current[part] === void 0) return;
2675
+ current = current[part];
2676
+ }
2677
+ if (current.remove) {
2678
+ current.remove(parts[parts.length - 1]);
2679
+ } else {
2680
+ delete current[parts[parts.length - 1]];
2681
+ }
2682
+ }
2683
+ __name(_deletePath, "_deletePath");
2684
+ function _applyInverse(record) {
2685
+ const wasEnabled = internal_default.historyEnabled;
2686
+ const wasRecording = internal_default._recording;
2687
+ internal_default.historyEnabled = false;
2688
+ internal_default._recording = false;
2689
+ try {
2690
+ if (record.action === "set" || record.operation === "set") {
2691
+ if (record.previousValue === void 0) {
2692
+ _deletePath(record.path);
2693
+ } else {
2694
+ _setPath(record.path, record.previousValue);
2695
+ }
2696
+ } else if (record.action === "delete" || record.operation === "delete") {
2697
+ if (record.previousValue !== void 0) {
2698
+ _setPath(record.path, record.previousValue);
2699
+ }
2700
+ }
2701
+ } finally {
2702
+ internal_default.historyEnabled = wasEnabled;
2703
+ internal_default._recording = wasRecording;
2704
+ }
2705
+ }
2706
+ __name(_applyInverse, "_applyInverse");
2707
+ function abortTransaction() {
2708
+ const txId = getActiveTxId();
2709
+ if (!txId) return null;
2710
+ const ctx = registry.get(txId);
2711
+ if (!ctx || !ctx.active) return null;
2712
+ for (let i = ctx.mutations.length - 1; i >= 0; i--) {
2713
+ const undoStack = internal_default.undoStack;
2714
+ const idx = undoStack.findIndex((r) => r.id === ctx.mutations[i]);
2715
+ if (idx >= 0) {
2716
+ const record = undoStack[idx];
2717
+ internal_default.undoStack.splice(idx, 1);
2718
+ _applyInverse(record);
2719
+ }
2720
+ }
2721
+ ctx.active = false;
2722
+ ctx.committedAt = hlc.serialize(hlc.tick());
2723
+ const tx = {
2724
+ id: ctx.id,
2725
+ mutations: ctx.mutations,
2726
+ startedAt: ctx.startedAt,
2727
+ committedAt: ctx.committedAt,
2728
+ source: ctx.source,
2729
+ message: ctx.message,
2730
+ metadata: ctx.metadata
2731
+ };
2732
+ registry.delete(txId);
2733
+ setActiveTx(null);
2734
+ return tx;
2735
+ }
2736
+ __name(abortTransaction, "abortTransaction");
2737
+ function listTransactions() {
2738
+ const result = [];
2739
+ for (const ctx of registry.values()) {
2740
+ result.push({
2741
+ id: ctx.id,
2742
+ mutations: ctx.mutations,
2743
+ startedAt: ctx.startedAt,
2744
+ committedAt: ctx.committedAt,
2745
+ source: ctx.source,
2746
+ message: ctx.message,
2747
+ metadata: ctx.metadata
2748
+ });
2749
+ }
2750
+ return result;
2751
+ }
2752
+ __name(listTransactions, "listTransactions");
2753
+ function currentTransaction() {
2754
+ const txId = getActiveTxId();
2755
+ if (!txId) return null;
2756
+ const ctx = registry.get(txId);
2757
+ if (!ctx || !ctx.active) return null;
2758
+ return {
2759
+ id: ctx.id,
2760
+ mutations: ctx.mutations,
2761
+ startedAt: ctx.startedAt,
2762
+ source: ctx.source,
2763
+ message: ctx.message,
2764
+ metadata: ctx.metadata
2765
+ };
2766
+ }
2767
+ __name(currentTransaction, "currentTransaction");
2768
+ function registerMutationInTransaction(mutationId) {
2769
+ const txId = getActiveTxId();
2770
+ if (!txId) return;
2771
+ const ctx = registry.get(txId);
2772
+ if (ctx && ctx.active) {
2773
+ ctx.mutations.push(mutationId);
2774
+ }
2775
+ }
2776
+ __name(registerMutationInTransaction, "registerMutationInTransaction");
2777
+
2778
+ // core/mutation/engine.ts
2779
+ function currentTimestamp() {
2780
+ return hlc.serialize(hlc.tick());
2781
+ }
2782
+ __name(currentTimestamp, "currentTimestamp");
2783
+ function createMutation(path2, operation, before2, after2, options) {
2784
+ const now2 = hlc.tick();
2785
+ const mutation = {
2786
+ id: generateMutationId(),
2787
+ path: path2,
2788
+ operation,
2789
+ after: after2,
2790
+ before: before2,
2791
+ timestamp: now2.physical,
2792
+ hlc: hlc.serialize(now2),
2793
+ context: options?.context || internal_default.currentContext || void 0,
2794
+ source: options?.source,
2795
+ transactionId: options?.transactionId || (operation !== "length" ? tagForTransaction() : void 0),
2796
+ // Legacy fields for backward compatibility
2797
+ action: operation === "set" ? "set" : "delete",
2798
+ newValue: after2,
2799
+ previousValue: before2
2800
+ };
2801
+ if (mutation.transactionId) {
2802
+ registerMutationInTransaction(mutation.id);
2803
+ }
2804
+ return mutation;
2805
+ }
2806
+ __name(createMutation, "createMutation");
2807
+ function recordMutation(mutation) {
2808
+ if (!internal_default.historyEnabled) return;
2809
+ internal_default.recordMutation(mutation);
2810
+ }
2811
+ __name(recordMutation, "recordMutation");
2812
+ function toPatch(mutation) {
2813
+ return mutationToPatch(mutation);
2814
+ }
2815
+ __name(toPatch, "toPatch");
2816
+ function mutate(path2, value, options) {
2817
+ const normalizedPath = path2.startsWith("state.") ? path2 : "state." + path2;
2818
+ const keyPath = normalizedPath.replace(/^state\./, "");
2819
+ let current;
2820
+ try {
2821
+ const parts2 = keyPath.split(".");
2822
+ let obj = globalThis.state;
2823
+ for (const part of parts2) {
2824
+ obj = obj?.[part];
2825
+ }
2826
+ current = obj;
2827
+ } catch {
2828
+ current = void 0;
2829
+ }
2830
+ const operation = value === void 0 ? "delete" : "set";
2831
+ const mutation = createMutation(
2832
+ normalizedPath,
2833
+ operation,
2834
+ current,
2835
+ value === void 0 ? void 0 : value,
2836
+ options
2837
+ );
2838
+ const wasRecording = internal_default._recording;
2839
+ internal_default._recording = false;
2840
+ const parts = keyPath.split(".");
2841
+ let target = globalThis.state;
2842
+ for (let i = 0; i < parts.length - 1; i++) {
2843
+ if (target[parts[i]] === void 0) {
2844
+ target[parts[i]] = {};
2845
+ }
2846
+ target = target[parts[i]];
2847
+ }
2848
+ if (operation === "delete") {
2849
+ delete target[parts[parts.length - 1]];
2850
+ } else {
2851
+ target[parts[parts.length - 1]] = value;
2852
+ }
2853
+ internal_default._recording = wasRecording;
2854
+ recordMutation(mutation);
2855
+ return mutation;
2856
+ }
2857
+ __name(mutate, "mutate");
2858
+ function activeTransactionId() {
2859
+ return internal_default.currentTransactionId || null;
2860
+ }
2861
+ __name(activeTransactionId, "activeTransactionId");
2862
+
2863
+ // functions/state/index.ts
2864
+ var TARGET = /* @__PURE__ */ Symbol("memorio.target");
2865
+ var wrapperCache = /* @__PURE__ */ new WeakMap();
2866
+ var arrayRootDedup = /* @__PURE__ */ new Set();
2867
+ var deepRaw = /* @__PURE__ */ __name((val, seen = null) => {
2868
+ if (val === null || typeof val !== "object") return val;
2869
+ if (!seen) seen = /* @__PURE__ */ new WeakSet();
2870
+ if (val[TARGET] !== void 0) return deepRaw(val[TARGET], seen);
2871
+ if (seen) {
2872
+ if (seen.has(val)) return val;
2873
+ seen.add(val);
2874
+ }
2875
+ const ctor = val.constructor?.name;
2876
+ if (ctor !== "Object" && ctor !== "Array") return val;
2877
+ const copy = Array.isArray(val) ? [] : {};
2878
+ for (const k of Reflect.ownKeys(val)) {
2879
+ if (!Object.prototype.propertyIsEnumerable.call(val, k)) continue;
2880
+ copy[k] = deepRaw(val[k], seen);
2881
+ }
2882
+ return copy;
2883
+ }, "deepRaw");
2884
+ var objPath = /* @__PURE__ */ __name((prop, object, separator = ".") => {
2885
+ return object.concat(prop).join(separator);
2886
+ }, "objPath");
2887
+ var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
2888
+ const event = /* @__PURE__ */ __name((name) => {
2889
+ try {
2890
+ dispatch.set(name, { detail: { name } });
2891
+ } catch (err) {
2892
+ if (DEV) console.warn("[memorio state] event dispatch failed:", err);
2893
+ }
2894
+ return;
2895
+ }, "event");
2896
+ return new Proxy(
2897
+ obj,
2898
+ {
2899
+ get(target, prop) {
2900
+ if (prop === "__path") {
2901
+ return tree.length > 0 ? "state." + tree.join(".") : "state";
2902
+ }
2903
+ if (prop === TARGET) {
2904
+ return target;
2905
+ }
2906
+ if (target[TARGET] !== void 0) {
2907
+ return target;
2908
+ }
2909
+ if (prop === "list") {
2910
+ message_default('Some state could be hidden when you use "state.list". Use "state" to see the complete list ');
2911
+ return deepRaw(target, /* @__PURE__ */ new WeakSet());
2912
+ }
2913
+ if (typeof prop === "string") {
2914
+ const path2 = tree.length > 0 ? "state." + tree.concat(prop).join(".") : "state." + prop;
2915
+ internal_default.lastAccessedPath = path2;
2916
+ if (internal_default.tracking) {
2917
+ internal_default.trackedPaths.add(path2);
2918
+ }
2919
+ }
2920
+ if (prop === "_lastPath") {
2921
+ return internal_default.lastAccessedPath;
2922
+ }
2923
+ if (prop === "remove") {
2924
+ return (key) => {
2925
+ delete target[key];
2926
+ return true;
2927
+ };
2928
+ }
2929
+ if (prop === "removeAll") {
2930
+ return () => {
2931
+ try {
2932
+ for (const key of Reflect.ownKeys(target)) {
2933
+ if (typeof target[key] !== "function" && !["list", "remove", "removeAll", "lock", "unlock", "persist"].includes(key)) {
2934
+ delete target[key];
2935
+ }
2936
+ }
2937
+ } catch (error) {
2938
+ console.error(error);
2939
+ }
2940
+ return;
2941
+ };
2942
+ }
2943
+ if (Object.isFrozen(target[prop])) return target[prop];
2944
+ if (prop === "lock" || prop === "unlock") {
2945
+ const value = Reflect.get(target, prop);
2946
+ if (value) return value;
2947
+ }
2948
+ try {
2949
+ const value = Reflect.get(target, prop);
2950
+ if (value && typeof value === "object" && ["Array", "Object"].includes(value.constructor.name)) {
2951
+ let wrapper = wrapperCache.get(value);
2952
+ if (!wrapper) {
2953
+ wrapper = buildProxy(value, callback, tree.concat(prop));
2954
+ wrapperCache.set(value, wrapper);
2955
+ }
2956
+ return wrapper;
2957
+ }
2958
+ return value;
2959
+ } catch (error) {
2960
+ console.error("Error: ", error);
1986
2961
  return void 0;
1987
2962
  }
1988
2963
  },
@@ -2029,6 +3004,16 @@ var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
2029
3004
  }
2030
3005
  );
2031
3006
  event("state." + path2);
3007
+ if (Array.isArray(target) && tree.length > 0) {
3008
+ const rootName = "state." + tree.join(".");
3009
+ if (!arrayRootDedup.has(rootName)) {
3010
+ arrayRootDedup.add(rootName);
3011
+ event(rootName);
3012
+ if (typeof globalThis.queueMicrotask === "function") {
3013
+ globalThis.queueMicrotask(() => arrayRootDedup.clear());
3014
+ }
3015
+ }
3016
+ }
2032
3017
  Reflect.set(target, key, rawValue);
2033
3018
  internal_default.bumpStateVersion();
2034
3019
  if (target[key] && typeof target[key] === "object") {
@@ -2085,6 +3070,17 @@ var buildProxy = /* @__PURE__ */ __name((obj, callback, tree = []) => {
2085
3070
  const path2 = objPath(prop, tree);
2086
3071
  const previousValue = Reflect.get(target, prop);
2087
3072
  callback({ action: "delete", path: path2, target, previousValue });
3073
+ event("state." + path2);
3074
+ if (Array.isArray(target) && tree.length > 0) {
3075
+ const rootName = "state." + tree.join(".");
3076
+ if (!arrayRootDedup.has(rootName)) {
3077
+ arrayRootDedup.add(rootName);
3078
+ event(rootName);
3079
+ if (typeof globalThis.queueMicrotask === "function") {
3080
+ globalThis.queueMicrotask(() => arrayRootDedup.clear());
3081
+ }
3082
+ }
3083
+ }
2088
3084
  return Reflect.deleteProperty(target, prop);
2089
3085
  } catch (error) {
2090
3086
  console.error("Error in deleteProperty trap:", error);
@@ -2106,57 +3102,83 @@ if (globalThis[STATE_INSTANCE_KEY]) {
2106
3102
  state2 = globalThis[STATE_INSTANCE_KEY];
2107
3103
  } else {
2108
3104
  state2 = buildProxy({}, (mutation) => {
2109
- if (internal_default.historyEnabled) {
2110
- internal_default.recordMutation({
2111
- path: mutation.path,
2112
- action: mutation.action,
2113
- newValue: mutation.newValue,
2114
- previousValue: mutation.previousValue,
2115
- timestamp: Date.now()
2116
- });
3105
+ if (internal_default.historyEnabled && internal_default._recording !== false) {
3106
+ const operation = mutation.action === "delete" ? "delete" : "set";
3107
+ const record = createMutation(
3108
+ mutation.path,
3109
+ operation,
3110
+ mutation.previousValue,
3111
+ mutation.newValue,
3112
+ {
3113
+ context: mutation.context,
3114
+ source: mutation.source
3115
+ }
3116
+ );
3117
+ internal_default.recordMutation(record);
2117
3118
  }
2118
3119
  });
2119
- state2.lock = () => {
2120
- internal_default.locked = true;
2121
- message_default("State is now locked. All modifications are blocked.");
2122
- };
2123
- state2.unlock = () => {
2124
- internal_default.locked = false;
2125
- message_default("State is now unlocked. Modifications are allowed.");
2126
- };
2127
- state2.persist = (path2) => {
2128
- if (typeof path2 !== "string" || !path2.length) {
2129
- if (DEV) console.warn('[memorio state] state.persist() requires a non-empty path string (e.g. "state.user")');
2130
- return () => {
2131
- };
2132
- }
2133
- const normalized = path2.startsWith("state.") ? path2 : "state." + path2;
2134
- const key = normalized.replace(/^state\./, "");
2135
- const segments = key.split(".");
2136
- const initial = store.get(key);
2137
- if (initial !== void 0 && initial !== null) {
2138
- let acc = state2;
2139
- for (let i = 0; i < segments.length; i++) {
2140
- const seg = segments[i];
2141
- if (i === segments.length - 1) {
2142
- acc[seg] = deepRaw(initial);
2143
- } else {
2144
- if (acc[seg] === void 0 || acc[seg] === null) acc[seg] = {};
2145
- acc = acc[seg];
3120
+ const _rawTarget = state2[TARGET];
3121
+ try {
3122
+ Object.defineProperty(_rawTarget, "lock", {
3123
+ value: /* @__PURE__ */ __name(() => {
3124
+ internal_default.locked = true;
3125
+ message_default("State is now locked. All modifications are blocked.");
3126
+ }, "value"),
3127
+ writable: true,
3128
+ configurable: true,
3129
+ enumerable: false
3130
+ });
3131
+ Object.defineProperty(_rawTarget, "unlock", {
3132
+ value: /* @__PURE__ */ __name(() => {
3133
+ internal_default.locked = false;
3134
+ message_default("State is now unlocked. Modifications are allowed.");
3135
+ }, "value"),
3136
+ writable: true,
3137
+ configurable: true,
3138
+ enumerable: false
3139
+ });
3140
+ } catch (e) {
3141
+ if (DEV) console.warn("[memorio state] lock/unlock defineProperty failed:", e);
3142
+ }
3143
+ try {
3144
+ Object.defineProperty(_rawTarget, "persist", {
3145
+ value: /* @__PURE__ */ __name((path2) => {
3146
+ if (typeof path2 !== "string" || !path2.length) {
3147
+ if (DEV) console.warn('[memorio state] state.persist() requires a non-empty path string (e.g. "state.user")');
3148
+ return () => {
3149
+ };
2146
3150
  }
2147
- }
2148
- }
2149
- const handler = /* @__PURE__ */ __name(() => {
2150
- let current = state2;
2151
- for (const seg of segments) {
2152
- current = current === void 0 || current === null ? void 0 : current[seg];
2153
- }
2154
- store.set(key, deepRaw(current));
2155
- }, "handler");
2156
- const off = dispatch.listen(normalized, handler);
2157
- return typeof off === "function" ? off : () => {
2158
- };
2159
- };
3151
+ const normalized = path2.startsWith("state.") ? path2 : "state." + path2;
3152
+ const key = normalized.replace(/^state\./, "");
3153
+ const segments = key.split(".");
3154
+ const initial = store.get(key);
3155
+ if (initial !== void 0 && initial !== null) {
3156
+ let acc = state2;
3157
+ for (let i = 0; i < segments.length - 1; i++) {
3158
+ const seg = segments[i];
3159
+ if (acc[seg] === void 0 || acc[seg] === null) acc[seg] = {};
3160
+ acc = acc[seg];
3161
+ }
3162
+ if (acc) acc[segments[segments.length - 1]] = deepRaw(initial);
3163
+ }
3164
+ const handler = /* @__PURE__ */ __name(() => {
3165
+ let current = state2;
3166
+ for (const seg of segments) {
3167
+ current = current === void 0 || current === null ? void 0 : current[seg];
3168
+ }
3169
+ store.set(key, deepRaw(current));
3170
+ }, "handler");
3171
+ const off = dispatch.listen(normalized, handler);
3172
+ return typeof off === "function" ? off : () => {
3173
+ };
3174
+ }, "value"),
3175
+ writable: true,
3176
+ configurable: true,
3177
+ enumerable: false
3178
+ });
3179
+ } catch (e) {
3180
+ if (DEV) console.warn("[memorio state] persist defineProperty failed:", e);
3181
+ }
2160
3182
  globalThis[STATE_INSTANCE_KEY] = state2;
2161
3183
  }
2162
3184
 
@@ -2168,6 +3190,7 @@ init_esm_shims();
2168
3190
  init_platform();
2169
3191
  init_internal();
2170
3192
  init_message();
3193
+ init_encryption();
2171
3194
  var _sessionStorage = getSessionStorage();
2172
3195
  var _fallbackStorageByContext2 = /* @__PURE__ */ new Map();
2173
3196
  function _getFallbackStorage2() {
@@ -2180,6 +3203,14 @@ function _getFallbackStorage2() {
2180
3203
  }
2181
3204
  __name(_getFallbackStorage2, "_getFallbackStorage");
2182
3205
  var _hasStorage2 = _sessionStorage !== null;
3206
+ var _encryptionKey2 = null;
3207
+ var _onError2 = null;
3208
+ var _maxObjectSize2 = 0;
3209
+ var _maxTotalSize2 = 0;
3210
+ function _isEncryptedEnvelope2(value) {
3211
+ return encryption.isEncrypted(value);
3212
+ }
3213
+ __name(_isEncryptedEnvelope2, "_isEncryptedEnvelope");
2183
3214
  function _getPrefix2() {
2184
3215
  const contextName = internal_default.currentContext || "";
2185
3216
  return contextName ? `${contextName}-` : `memorio_session_`;
@@ -2233,16 +3264,22 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
2233
3264
  /**
2234
3265
  * Gets a value from storage.
2235
3266
  * @param name The key to retrieve.
2236
- * @returns The parsed value or null if not found.
3267
+ * @param opts Optional { decrypt: key } to decrypt an encrypted envelope.
3268
+ * @returns The parsed value, a Promise when decrypting, or null if not found.
2237
3269
  */
2238
3270
  get: {
2239
- value: /* @__PURE__ */ __name((name) => {
3271
+ value: /* @__PURE__ */ __name((name, opts) => {
2240
3272
  if (!name) {
2241
3273
  console.warn("[memorio session] session.get() called with empty or null key - returning null");
2242
3274
  return null;
2243
3275
  }
2244
3276
  try {
2245
- return _read2(_prefixKey2(name));
3277
+ const raw = _read2(_prefixKey2(name));
3278
+ const key = opts?.decrypt ?? _encryptionKey2;
3279
+ if (key && _isEncryptedEnvelope2(raw)) {
3280
+ return encryption.decrypt(raw, key);
3281
+ }
3282
+ return raw;
2246
3283
  } catch (err) {
2247
3284
  message(`Error parsing session item '${name}':${err}`);
2248
3285
  }
@@ -2253,10 +3290,11 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
2253
3290
  * Sets a value in storage.
2254
3291
  * @param name The key to set.
2255
3292
  * @param value The value to store.
2256
- * @returns true if written, false if the key was rejected.
3293
+ * @param opts Optional { encrypt: key } to encrypt before storage.
3294
+ * @returns true if written, false if rejected. Returns a Promise when encrypting.
2257
3295
  */
2258
3296
  set: {
2259
- value: /* @__PURE__ */ __name((name, value) => {
3297
+ value: /* @__PURE__ */ __name((name, value, opts) => {
2260
3298
  if (!name) {
2261
3299
  console.warn("[memorio session] session.set() called with empty or null key - write aborted");
2262
3300
  return false;
@@ -2268,15 +3306,63 @@ if (globalThis[SESSION_INSTANCE_KEY]) {
2268
3306
  message("It's not secure to session functions.");
2269
3307
  return false;
2270
3308
  }
3309
+ if (_maxObjectSize2 > 0 || _maxTotalSize2 > 0) {
3310
+ let serializedSize = 0;
3311
+ try {
3312
+ serializedSize = new TextEncoder().encode(JSON.stringify(value)).length;
3313
+ } catch {
3314
+ serializedSize = 0;
3315
+ }
3316
+ if (_maxObjectSize2 > 0 && serializedSize > _maxObjectSize2) {
3317
+ const err = new Error(`Object size (${serializedSize} bytes) exceeds maxObjectSize (${_maxObjectSize2} bytes)`);
3318
+ _onError2?.(err, { operation: "set" });
3319
+ return false;
3320
+ }
3321
+ if (_maxTotalSize2 > 0) {
3322
+ const currentTotal = session.size() * 1024;
3323
+ const existingItemSize = _sessionStorage ? _sessionStorage.getItem(prefixedName)?.length ?? 0 : _getFallbackStorage2().get(prefixedName)?.length ?? 0;
3324
+ const projected = currentTotal - existingItemSize + serializedSize;
3325
+ if (projected > _maxTotalSize2) {
3326
+ const err = new Error(`Total session size (${projected} bytes) exceeds maxTotalSize (${_maxTotalSize2} bytes)`);
3327
+ _onError2?.(err, { operation: "set" });
3328
+ return false;
3329
+ }
3330
+ }
3331
+ }
3332
+ const key = opts?.encrypt ?? _encryptionKey2;
3333
+ if (key) {
3334
+ return encryption.encrypt(value, key).then((env) => {
3335
+ _write2(prefixedName, env);
3336
+ return true;
3337
+ }).catch((err) => {
3338
+ message(`Error encrypting session item '${name}': ${err}`);
3339
+ _onError2?.(err, { operation: "set" });
3340
+ return false;
3341
+ });
3342
+ }
2271
3343
  try {
2272
3344
  _write2(prefixedName, value);
2273
3345
  } catch (err) {
2274
3346
  message(`Error setting session item '${name}': ${err}`);
3347
+ _onError2?.(err, { operation: "set" });
2275
3348
  return false;
2276
3349
  }
2277
3350
  return true;
2278
3351
  }, "value")
2279
3352
  },
3353
+ /**
3354
+ * Configure session-wide behavior.
3355
+ * @param opts { encryptionKey, onError, maxObjectSize, maxTotalSize }
3356
+ */
3357
+ config: {
3358
+ value: /* @__PURE__ */ __name((opts) => {
3359
+ if (opts.encryptionKey !== void 0) _encryptionKey2 = opts.encryptionKey;
3360
+ if (opts.onError !== void 0) _onError2 = opts.onError;
3361
+ if (opts.maxObjectSize !== void 0) _maxObjectSize2 = opts.maxObjectSize;
3362
+ if (opts.maxTotalSize !== void 0) _maxTotalSize2 = opts.maxTotalSize;
3363
+ return session;
3364
+ }, "value")
3365
+ },
2280
3366
  /**
2281
3367
  * Removes a value from storage.
2282
3368
  * @param name The key to remove.
@@ -2508,12 +3594,17 @@ var observerFunction = /* @__PURE__ */ __name((s, cb = null, option = true) => {
2508
3594
  const callbacks = Array.isArray(cb) ? cb : [cb];
2509
3595
  const obs = globalThis.observer;
2510
3596
  if (obs?.list?.[resolvedPath]) dispatch.remove(resolvedPath);
3597
+ const unsubs = [];
2511
3598
  callbacks.forEach((callback) => {
2512
3599
  if (typeof callback === "function") {
2513
- dispatch.listen(resolvedPath, callback, option);
3600
+ const off = dispatch.listen(resolvedPath, callback, option);
3601
+ if (typeof off === "function") unsubs.push(off);
2514
3602
  }
2515
3603
  });
2516
- return;
3604
+ if (unsubs.length === 1) return unsubs[0];
3605
+ if (unsubs.length > 1) return () => unsubs.forEach((u) => u());
3606
+ return () => {
3607
+ };
2517
3608
  }
2518
3609
  }, "observerFunction");
2519
3610
  var observer = observerFunction;
@@ -2576,7 +3667,6 @@ Object.defineProperties(
2576
3667
  init_esm_shims();
2577
3668
  init_message();
2578
3669
  init_internal();
2579
- init_env();
2580
3670
  var useObserver = /* @__PURE__ */ __name(((func, deps = []) => {
2581
3671
  if (!deps || typeof func !== "function") {
2582
3672
  return () => {
@@ -2620,37 +3710,616 @@ var useObserver = /* @__PURE__ */ __name(((func, deps = []) => {
2620
3710
  });
2621
3711
  }
2622
3712
  });
2623
- if (handlers.length > 0) {
2624
- message_default(`useObserver: Monitoring ${handlers.length} paths.`);
2625
- } else {
2626
- console.warn(`useObserver: No paths resolved for monitoring. Check your dependencies!`);
3713
+ if (handlers.length > 0) {
3714
+ message_default(`useObserver: Monitoring ${handlers.length} paths.`);
3715
+ } else {
3716
+ console.warn(`useObserver: No paths resolved for monitoring. Check your dependencies!`);
3717
+ }
3718
+ return () => {
3719
+ unsubs.forEach(({ path: path2, off }) => {
3720
+ off();
3721
+ message_default(`useObserver: Stopped monitoring "${path2}"`);
3722
+ });
3723
+ };
3724
+ } catch (err) {
3725
+ message_default(`useObserver Error: ${err}`);
3726
+ return () => {
3727
+ };
3728
+ }
3729
+ }), "useObserver");
3730
+
3731
+ // index.ts
3732
+ init_encryption();
3733
+
3734
+ // functions/computed/index.ts
3735
+ init_esm_shims();
3736
+ init_env();
3737
+ init_message();
3738
+ var DEFAULT_EQUALITY = /* @__PURE__ */ __name((prev, next) => {
3739
+ if (prev === next) return true;
3740
+ if (prev == null || next == null) return false;
3741
+ if (typeof prev !== typeof next) return false;
3742
+ if (typeof prev !== "object") return false;
3743
+ try {
3744
+ return JSON.stringify(prev) === JSON.stringify(next);
3745
+ } catch {
3746
+ return false;
3747
+ }
3748
+ }, "DEFAULT_EQUALITY");
3749
+ var computedMap = /* @__PURE__ */ new Map();
3750
+ function _normalizeKey(key) {
3751
+ if (!key || typeof key !== "string") return "";
3752
+ const normalized = key.startsWith("state.") ? key : `state.${key}`;
3753
+ return normalized;
3754
+ }
3755
+ __name(_normalizeKey, "_normalizeKey");
3756
+ function _invalidate(key) {
3757
+ const entry = computedMap.get(key);
3758
+ if (!entry) return;
3759
+ const newValue = _recompute(entry);
3760
+ if (entry.equality(entry.lastValue, newValue)) {
3761
+ return;
3762
+ }
3763
+ entry.lastValue = newValue;
3764
+ for (const sub of entry.subscribers) {
3765
+ try {
3766
+ sub(newValue);
3767
+ } catch (err) {
3768
+ if (DEV) console.error("[memorio computed] subscriber error:", err);
3769
+ }
3770
+ }
3771
+ dispatch.set("memorio:computed:" + key, { detail: { key, value: newValue } });
3772
+ }
3773
+ __name(_invalidate, "_invalidate");
3774
+ function _readStatePath(path2) {
3775
+ const entry = computedMap.get(path2);
3776
+ if (entry) {
3777
+ return entry.lastValue;
3778
+ }
3779
+ const normalized = path2.startsWith("state.") ? path2 : `state.${path2}`;
3780
+ const segments = normalized.replace(/^state\./, "").split(".");
3781
+ let current = globalThis.state;
3782
+ if (current) {
3783
+ for (const seg of segments) {
3784
+ if (current === null || current === void 0) break;
3785
+ try {
3786
+ current = current[seg];
3787
+ } catch {
3788
+ return void 0;
3789
+ }
3790
+ }
3791
+ }
3792
+ return current === void 0 ? null : current;
3793
+ }
3794
+ __name(_readStatePath, "_readStatePath");
3795
+ function _recompute(entry) {
3796
+ const newDeps = /* @__PURE__ */ new Set();
3797
+ const trackerGet = /* @__PURE__ */ __name((path2) => {
3798
+ if (!path2 || typeof path2 !== "string") return void 0;
3799
+ newDeps.add(path2);
3800
+ return _readStatePath(path2);
3801
+ }, "trackerGet");
3802
+ try {
3803
+ return entry.selector(trackerGet);
3804
+ } catch (err) {
3805
+ if (DEV) console.error("[memorio computed] selector error:", err);
3806
+ message_default(`[memorio computed] selector error: ${err}`);
3807
+ return entry.lastValue;
3808
+ }
3809
+ }
3810
+ __name(_recompute, "_recompute");
3811
+ function _setupDeps(key, entry, deps) {
3812
+ for (const off of entry._dispatchUnsubscribers) off();
3813
+ entry._dispatchUnsubscribers = [];
3814
+ for (const dep of deps) {
3815
+ if (computedMap.has(dep)) {
3816
+ const computedEvent = "memorio:computed:" + dep;
3817
+ const off = dispatch.listen(computedEvent, () => _invalidate(key));
3818
+ if (off) entry._dispatchUnsubscribers.push(off);
3819
+ } else {
3820
+ const off = dispatch.listen(dep, () => _invalidate(key));
3821
+ if (off) entry._dispatchUnsubscribers.push(off);
3822
+ }
3823
+ }
3824
+ entry.deps = deps;
3825
+ }
3826
+ __name(_setupDeps, "_setupDeps");
3827
+ function _compute(key, selector, opts) {
3828
+ const normalizedKey = _normalizeKey(key);
3829
+ const cacheKey = opts?.equalityKey ? `${opts.equalityKey}:${normalizedKey}` : normalizedKey;
3830
+ if (computedMap.has(cacheKey)) {
3831
+ const entry2 = computedMap.get(cacheKey);
3832
+ entry2.selector = selector;
3833
+ entry2.equality = opts?.equality || DEFAULT_EQUALITY;
3834
+ const newDeps2 = /* @__PURE__ */ new Set();
3835
+ const wrappedGet = /* @__PURE__ */ __name((path2) => {
3836
+ newDeps2.add(path2);
3837
+ return _readStatePath(path2);
3838
+ }, "wrappedGet");
3839
+ let newValue;
3840
+ try {
3841
+ newValue = selector(wrappedGet);
3842
+ } catch (err) {
3843
+ if (DEV) console.error("[memorio computed] selector error:", err);
3844
+ return entry2.lastValue;
3845
+ }
3846
+ if (entry2.equality(entry2.lastValue, newValue)) {
3847
+ return entry2.lastValue;
3848
+ }
3849
+ entry2.lastValue = newValue;
3850
+ _setupDeps(cacheKey, entry2, newDeps2);
3851
+ for (const sub of entry2.subscribers) {
3852
+ try {
3853
+ sub(newValue);
3854
+ } catch (err) {
3855
+ if (DEV) console.error("[memorio computed] subscriber error:", err);
3856
+ }
3857
+ }
3858
+ return newValue;
3859
+ }
3860
+ const newDeps = /* @__PURE__ */ new Set();
3861
+ const get = /* @__PURE__ */ __name((path2) => {
3862
+ newDeps.add(path2);
3863
+ return _readStatePath(path2);
3864
+ }, "get");
3865
+ let lastValue;
3866
+ try {
3867
+ lastValue = selector(get);
3868
+ } catch (err) {
3869
+ if (DEV) console.error("[memorio computed] selector error:", err);
3870
+ message_default(`[memorio computed] selector error: ${err}`);
3871
+ lastValue = null;
3872
+ }
3873
+ const entry = {
3874
+ selector,
3875
+ lastValue,
3876
+ deps: newDeps,
3877
+ equality: opts?.equality || DEFAULT_EQUALITY,
3878
+ subscribers: /* @__PURE__ */ new Set(),
3879
+ _dispatchUnsubscribers: []
3880
+ };
3881
+ computedMap.set(cacheKey, entry);
3882
+ _setupDeps(cacheKey, entry, newDeps);
3883
+ return lastValue;
3884
+ }
3885
+ __name(_compute, "_compute");
3886
+ function _getValue(key) {
3887
+ const normalizedKey = _normalizeKey(key);
3888
+ const entry = computedMap.get(normalizedKey);
3889
+ if (!entry) return null;
3890
+ return entry.lastValue;
3891
+ }
3892
+ __name(_getValue, "_getValue");
3893
+ function _subscribe(key, cb) {
3894
+ const normalizedKey = _normalizeKey(key);
3895
+ const entry = computedMap.get(normalizedKey);
3896
+ if (!entry) {
3897
+ if (DEV) console.warn(`[memorio computed] subscribe: no computed value registered for key '${key}'`);
3898
+ return () => {
3899
+ };
3900
+ }
3901
+ entry.subscribers.add(cb);
3902
+ return () => {
3903
+ entry.subscribers.delete(cb);
3904
+ };
3905
+ }
3906
+ __name(_subscribe, "_subscribe");
3907
+ function _remove3(key) {
3908
+ const normalizedKey = _normalizeKey(key);
3909
+ if (!computedMap.has(normalizedKey)) return false;
3910
+ const entry = computedMap.get(normalizedKey);
3911
+ for (const off of entry._dispatchUnsubscribers) off();
3912
+ computedMap.delete(normalizedKey);
3913
+ return true;
3914
+ }
3915
+ __name(_remove3, "_remove");
3916
+ function _list() {
3917
+ return Array.from(computedMap.keys());
3918
+ }
3919
+ __name(_list, "_list");
3920
+ function _clear() {
3921
+ for (const [, entry] of computedMap) {
3922
+ for (const off of entry._dispatchUnsubscribers) off();
3923
+ }
3924
+ computedMap.clear();
3925
+ }
3926
+ __name(_clear, "_clear");
3927
+ var computed = {
3928
+ compute: _compute,
3929
+ getValue: _getValue,
3930
+ subscribe: _subscribe,
3931
+ remove: _remove3,
3932
+ list: _list,
3933
+ clear: _clear
3934
+ };
3935
+
3936
+ // functions/broadcast/index.ts
3937
+ init_esm_shims();
3938
+ init_env();
3939
+ init_message();
3940
+ var _channel = null;
3941
+ var _storageListener = null;
3942
+ var _originalDispatchSet = null;
3943
+ var _installed = false;
3944
+ var _targets = "all";
3945
+ var _isLocalChange = false;
3946
+ function _hasBroadcastChannel() {
3947
+ return typeof BroadcastChannel !== "undefined";
3948
+ }
3949
+ __name(_hasBroadcastChannel, "_hasBroadcastChannel");
3950
+ function _hasStorageEvents() {
3951
+ return typeof window !== "undefined" && "addEventListener" in window;
3952
+ }
3953
+ __name(_hasStorageEvents, "_hasStorageEvents");
3954
+ function _shouldSync(target) {
3955
+ if (_targets === "all") return true;
3956
+ return _targets === target;
3957
+ }
3958
+ __name(_shouldSync, "_shouldSync");
3959
+ function _onBroadcastMessage(event) {
3960
+ let msg;
3961
+ try {
3962
+ msg = event.data;
3963
+ } catch {
3964
+ return;
3965
+ }
3966
+ if (!msg || !msg.__memorio_sync) return;
3967
+ if (!_shouldSync(msg.target)) return;
3968
+ if (_isLocalChange) return;
3969
+ try {
3970
+ if (msg.target === "state" || msg.target === "all") {
3971
+ const s = globalThis.state;
3972
+ if (s) {
3973
+ _isLocalChange = true;
3974
+ try {
3975
+ const segments = msg.path.replace(/^state\./, "").split(".");
3976
+ let current = s;
3977
+ for (let i = 0; i < segments.length - 1; i++) {
3978
+ const seg = segments[i];
3979
+ if (current[seg] === void 0 || current[seg] === null) {
3980
+ current[seg] = {};
3981
+ }
3982
+ current = current[seg];
3983
+ }
3984
+ const lastSeg = segments[segments.length - 1];
3985
+ if (msg.action === "set") {
3986
+ current[lastSeg] = msg.value;
3987
+ } else if (msg.action === "delete") {
3988
+ delete current[lastSeg];
3989
+ }
3990
+ } finally {
3991
+ queueMicrotask(() => {
3992
+ _isLocalChange = false;
3993
+ });
3994
+ }
3995
+ }
3996
+ }
3997
+ } catch (err) {
3998
+ if (DEV) console.error("[memorio broadcast] apply state error:", err);
3999
+ }
4000
+ }
4001
+ __name(_onBroadcastMessage, "_onBroadcastMessage");
4002
+ function _onStorageEvent(e) {
4003
+ if (!e.key) return;
4004
+ const prefixes = [
4005
+ ["memorio_store_", "store"],
4006
+ ["memorio_session_", "session"]
4007
+ ];
4008
+ for (const [prefix, target] of prefixes) {
4009
+ if (e.key.startsWith(prefix)) {
4010
+ if (!_shouldSync(target)) continue;
4011
+ const cleanKey = e.key.slice(prefix.length);
4012
+ dispatch.set(`memorio:broadcast:${target}:${cleanKey}`, {
4013
+ detail: { key: cleanKey, oldValue: e.oldValue, newValue: e.newValue }
4014
+ });
4015
+ break;
4016
+ }
4017
+ }
4018
+ }
4019
+ __name(_onStorageEvent, "_onStorageEvent");
4020
+ function _wrapDispatchSet() {
4021
+ if (_originalDispatchSet !== null) return;
4022
+ _originalDispatchSet = dispatch.set;
4023
+ const original = dispatch.set;
4024
+ dispatch.set = (name, value) => {
4025
+ original(name, value);
4026
+ if (name.startsWith("state.") && _shouldSync("state") && _channel) {
4027
+ _isLocalChange = true;
4028
+ try {
4029
+ _channel.postMessage({
4030
+ __memorio_sync: true,
4031
+ target: "state",
4032
+ action: "set",
4033
+ path: name,
4034
+ value: _extractStateValue(name),
4035
+ timestamp: Date.now()
4036
+ });
4037
+ } finally {
4038
+ queueMicrotask(() => {
4039
+ _isLocalChange = false;
4040
+ });
4041
+ }
4042
+ }
4043
+ };
4044
+ }
4045
+ __name(_wrapDispatchSet, "_wrapDispatchSet");
4046
+ function _restoreDispatchSet() {
4047
+ if (_originalDispatchSet !== null) {
4048
+ dispatch.set = _originalDispatchSet;
4049
+ _originalDispatchSet = null;
4050
+ }
4051
+ }
4052
+ __name(_restoreDispatchSet, "_restoreDispatchSet");
4053
+ function _extractStateValue(path2) {
4054
+ const s = globalThis.state;
4055
+ if (!s) return void 0;
4056
+ try {
4057
+ const segments = path2.replace(/^state\./, "").split(".");
4058
+ let current = s;
4059
+ for (const seg of segments) {
4060
+ if (current === null || current === void 0) break;
4061
+ current = current[seg];
4062
+ }
4063
+ return current === void 0 ? null : current;
4064
+ } catch {
4065
+ return null;
4066
+ }
4067
+ }
4068
+ __name(_extractStateValue, "_extractStateValue");
4069
+ var broadcast = {
4070
+ install: /* @__PURE__ */ __name((channelName, opts) => {
4071
+ if (_installed) return;
4072
+ const name = channelName || opts?.channelName || "memorio_sync";
4073
+ _targets = opts?.targets || "all";
4074
+ if (_hasBroadcastChannel()) {
4075
+ _channel = new BroadcastChannel(name);
4076
+ _channel.addEventListener("message", _onBroadcastMessage);
4077
+ _installed = true;
4078
+ _wrapDispatchSet();
4079
+ if (DEV) message_default(`memorio broadcast: installed (channel="${name}", targets="${_targets}")`);
4080
+ }
4081
+ if (_hasStorageEvents()) {
4082
+ _storageListener = _onStorageEvent;
4083
+ window.addEventListener("storage", _storageListener);
4084
+ _installed = true;
4085
+ if (!_hasBroadcastChannel() && DEV) {
4086
+ message_default(`memorio broadcast: using storage event fallback (targets="${_targets}")`);
4087
+ }
4088
+ }
4089
+ if (!_installed) {
4090
+ console.warn("[memorio broadcast] Neither BroadcastChannel nor storage events are available in this environment.");
4091
+ }
4092
+ }, "install"),
4093
+ uninstall: /* @__PURE__ */ __name(() => {
4094
+ if (_channel) {
4095
+ _channel.removeEventListener("message", _onBroadcastMessage);
4096
+ _channel.close();
4097
+ _channel = null;
4098
+ }
4099
+ if (_storageListener && typeof window !== "undefined") {
4100
+ window.removeEventListener("storage", _storageListener);
4101
+ _storageListener = null;
4102
+ }
4103
+ _restoreDispatchSet();
4104
+ _installed = false;
4105
+ }, "uninstall"),
4106
+ isInstalled: /* @__PURE__ */ __name(() => _installed, "isInstalled"),
4107
+ broadcast: /* @__PURE__ */ __name((msg) => {
4108
+ if (!_channel) return;
4109
+ _channel.postMessage({ ...msg, timestamp: Date.now() });
4110
+ }, "broadcast")
4111
+ };
4112
+
4113
+ // functions/security/index.ts
4114
+ init_esm_shims();
4115
+ init_env();
4116
+ function _safeRandomUUID() {
4117
+ const g3 = globalThis;
4118
+ if (typeof g3.crypto !== "undefined" && typeof g3.crypto.randomUUID === "function") {
4119
+ try {
4120
+ return g3.crypto.randomUUID();
4121
+ } catch {
4122
+ }
4123
+ }
4124
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
4125
+ }
4126
+ __name(_safeRandomUUID, "_safeRandomUUID");
4127
+ var REGEX_TIMEOUT_MS = 100;
4128
+ function _safeRegexTest(pattern, key) {
4129
+ if (/\(.*[+*?].*.*\)[+*?]/.test(pattern)) {
4130
+ if (DEV) console.warn(`[memorio security] Potentially dangerous regex blocked: ${pattern}`);
4131
+ return false;
4132
+ }
4133
+ if (pattern.length > 500) {
4134
+ if (DEV) console.warn("[memorio security] Regex pattern exceeds max length (500)");
4135
+ return false;
4136
+ }
4137
+ const startTime = Date.now();
4138
+ try {
4139
+ const regex = new RegExp(pattern);
4140
+ const result = regex.test(key);
4141
+ const elapsed = Date.now() - startTime;
4142
+ if (elapsed > REGEX_TIMEOUT_MS) {
4143
+ if (DEV) console.warn(`[memorio security] Slow regex detected (${elapsed}ms): ${pattern}`);
4144
+ }
4145
+ return result;
4146
+ } catch {
4147
+ return false;
4148
+ }
4149
+ }
4150
+ __name(_safeRegexTest, "_safeRegexTest");
4151
+ function addAccessRule(rules, pattern, perms) {
4152
+ const key = pattern instanceof RegExp ? pattern.source : pattern;
4153
+ rules.set(key, perms);
4154
+ return rules;
4155
+ }
4156
+ __name(addAccessRule, "addAccessRule");
4157
+ function hasPermission(rules, key, action, userId) {
4158
+ if (rules.size === 0) return true;
4159
+ for (const [pattern, perms] of rules) {
4160
+ let matches;
4161
+ if (typeof pattern === "function") {
4162
+ try {
4163
+ matches = pattern(key, userId);
4164
+ } catch {
4165
+ matches = false;
4166
+ }
4167
+ } else {
4168
+ matches = _safeRegexTest(pattern, key);
4169
+ }
4170
+ if (matches) {
4171
+ const allowed = perms.includes(action) || perms.includes("admin");
4172
+ if (!allowed) {
4173
+ logAudit({
4174
+ action,
4175
+ key,
4176
+ userId,
4177
+ success: false,
4178
+ error: "RBAC Denied: insufficient permissions"
4179
+ });
4180
+ }
4181
+ return allowed;
4182
+ }
4183
+ }
4184
+ logAudit({
4185
+ action: "permission_check",
4186
+ key,
4187
+ userId,
4188
+ success: false,
4189
+ error: "RBAC Denied: no matching rule"
4190
+ });
4191
+ return false;
4192
+ }
4193
+ __name(hasPermission, "hasPermission");
4194
+ var _auditLogger = null;
4195
+ function isAuditActive() {
4196
+ return _auditLogger !== null;
4197
+ }
4198
+ __name(isAuditActive, "isAuditActive");
4199
+ function setAuditLogger(logger3) {
4200
+ _auditLogger = logger3;
4201
+ }
4202
+ __name(setAuditLogger, "setAuditLogger");
4203
+ function logAudit(entry) {
4204
+ if (!_auditLogger) return;
4205
+ _auditLogger({
4206
+ timestamp: Date.now(),
4207
+ success: true,
4208
+ ...entry
4209
+ });
4210
+ }
4211
+ __name(logAudit, "logAudit");
4212
+ function sanitizeValue(value) {
4213
+ if (typeof value === "string") {
4214
+ let decoded = value.replace(/&#[xX]?[0-9a-fA-F]+;?/g, (match) => {
4215
+ const hexMatch = match.match(/&#x([0-9a-fA-F]+);?/i);
4216
+ if (hexMatch && hexMatch[1]) {
4217
+ return String.fromCharCode(parseInt(hexMatch[1], 16));
4218
+ }
4219
+ const decMatch = match.match(/&#([0-9]+);?/);
4220
+ if (decMatch && decMatch[1]) {
4221
+ return String.fromCharCode(parseInt(decMatch[1], 10));
4222
+ }
4223
+ return match;
4224
+ });
4225
+ try {
4226
+ decoded = decodeURIComponent(decoded);
4227
+ } catch {
2627
4228
  }
2628
- return () => {
2629
- unsubs.forEach(({ path: path2, off }) => {
2630
- off();
2631
- message_default(`useObserver: Stopped monitoring "${path2}"`);
2632
- });
2633
- };
2634
- } catch (err) {
2635
- message_default(`useObserver Error: ${err}`);
2636
- return () => {
2637
- };
4229
+ decoded = decoded.replace(/(javascript|vbscript|data:text\/html|about:blank|chrome:)/gi, "[SEC-REMOVED]");
4230
+ return decoded.replace(/<script\b[^>]*>[\s\S]*?<\s*\/\s*script\b[^>]*>/gi, "[SEC-REMOVED]").replace(/on\w+\s*=/gi, "[SEC-REMOVED]=").replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, "[SEC-REMOVED]").replace(/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi, "[SEC-REMOVED]").replace(/<embed\b[^>]*>/gi, "[SEC-REMOVED]").replace(/<svg\b[^<]*(?:(?!<\/svg>)<[^<]*)*<\/svg>/gi, "[SEC-REMOVED]").replace(/<form\b[^<]*(?:(?!<\/form>)<[^<]*)*<\/form>/gi, "[SEC-REMOVED]").replace(/<base\b[^<]*(?:(?!<\/base>)<[^<]*)*<\/base>/gi, "[SEC-REMOVED]").replace(/<link\b[^<]*(?:(?!<\/link>)<[^<]*)*<\/link>/gi, "[SEC-REMOVED]").replace(/<meta\b[^<]*(?:(?!<\/meta>)<[^<]*)*<\/meta>/gi, "[SEC-REMOVED]").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "[SEC-REMOVED]");
4231
+ }
4232
+ if (value && typeof value === "object" && !Array.isArray(value)) {
4233
+ const ctor = value.constructor?.name;
4234
+ if (ctor === "Object" || ctor === void 0) {
4235
+ const sanitized = {};
4236
+ for (const [k, v] of Object.entries(value)) {
4237
+ if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
4238
+ sanitized[k] = sanitizeValue(v);
4239
+ }
4240
+ return sanitized;
4241
+ }
4242
+ return value;
2638
4243
  }
2639
- }), "useObserver");
2640
- if (DEV && !("useObserver" in globalThis)) {
2641
- if (!globalThis.useObserver) globalThis.useObserver = null;
2642
- Object.defineProperty(
2643
- globalThis,
2644
- "useObserver",
2645
- {
2646
- value: useObserver,
2647
- writable: true,
2648
- enumerable: false,
2649
- configurable: true
4244
+ if (Array.isArray(value)) {
4245
+ return value.map((v) => sanitizeValue(v));
4246
+ }
4247
+ return value;
4248
+ }
4249
+ __name(sanitizeValue, "sanitizeValue");
4250
+ function validateKey(key) {
4251
+ return /^[a-zA-Z0-9_.-]+$/.test(key) && key.length <= 256 && key.length > 0;
4252
+ }
4253
+ __name(validateKey, "validateKey");
4254
+ function recordConsent(consents, userId, purpose, granted) {
4255
+ const record = {
4256
+ id: _safeRandomUUID(),
4257
+ purpose,
4258
+ granted,
4259
+ timestamp: Date.now()
4260
+ };
4261
+ const user = consents.get(userId) || [];
4262
+ user.push(record);
4263
+ consents.set(userId, user);
4264
+ return record;
4265
+ }
4266
+ __name(recordConsent, "recordConsent");
4267
+ function hasConsent(consents, userId, purpose) {
4268
+ const userConsents = consents.get(userId);
4269
+ if (!userConsents) return false;
4270
+ for (let i = userConsents.length - 1; i >= 0; i--) {
4271
+ const record = userConsents[i];
4272
+ if (record && record.purpose === purpose) {
4273
+ return record.granted;
2650
4274
  }
2651
- );
2652
- Object.freeze(globalThis.useObserver);
4275
+ }
4276
+ return false;
4277
+ }
4278
+ __name(hasConsent, "hasConsent");
4279
+ function revokeConsent(consents, userId, purpose) {
4280
+ return recordConsent(consents, userId, purpose, false);
4281
+ }
4282
+ __name(revokeConsent, "revokeConsent");
4283
+ function getConsents(consents, userId) {
4284
+ return consents.get(userId) || [];
4285
+ }
4286
+ __name(getConsents, "getConsents");
4287
+ function exportUserData(consents, userId) {
4288
+ return {
4289
+ userId,
4290
+ exportedAt: Date.now(),
4291
+ consents: consents.get(userId) || []
4292
+ };
2653
4293
  }
4294
+ __name(exportUserData, "exportUserData");
4295
+ function deleteUserData(consents, userId) {
4296
+ const count = consents.get(userId)?.length || 0;
4297
+ consents.delete(userId);
4298
+ return { success: true, deletedConsents: count };
4299
+ }
4300
+ __name(deleteUserData, "deleteUserData");
4301
+ var security = {
4302
+ // Re-exports for convenience
4303
+ safeRandomUUID: _safeRandomUUID,
4304
+ safeRegexTest: _safeRegexTest,
4305
+ // RBAC
4306
+ addAccessRule,
4307
+ hasPermission,
4308
+ // Audit logging
4309
+ isAuditActive,
4310
+ setAuditLogger,
4311
+ logAudit,
4312
+ // Input sanitization
4313
+ sanitizeValue,
4314
+ validateKey,
4315
+ // Consent management
4316
+ recordConsent,
4317
+ hasConsent,
4318
+ revokeConsent,
4319
+ getConsents,
4320
+ exportUserData,
4321
+ deleteUserData
4322
+ };
2654
4323
 
2655
4324
  // index.ts
2656
4325
  init_message();
@@ -2708,439 +4377,67 @@ var log = /* @__PURE__ */ __name((module, action, path2, value, previousValue) =
2708
4377
  );
2709
4378
  if (value !== void 0) {
2710
4379
  message_default(` \u2192 value:${value}`);
2711
- }
2712
- if (previousValue !== void 0) {
2713
- message_default(` \u2190 previous:${previousValue}`);
2714
- }
2715
- }
2716
- if (config.customHandler) {
2717
- config.customHandler(entry);
2718
- }
2719
- }, "log");
2720
- var getModuleColor = /* @__PURE__ */ __name((module) => {
2721
- const colors = {
2722
- state: "#4CAF50",
2723
- store: "#2196F3",
2724
- session: "#FF9800",
2725
- cache: "#9C27B0",
2726
- idb: "#F44336"
2727
- };
2728
- return colors[module] || "#888888";
2729
- }, "getModuleColor");
2730
- var getHistory = /* @__PURE__ */ __name(() => {
2731
- return [...logHistory];
2732
- }, "getHistory");
2733
- var clearHistory = /* @__PURE__ */ __name(() => {
2734
- logHistory.length = 0;
2735
- }, "clearHistory");
2736
- var getStats = /* @__PURE__ */ __name(() => {
2737
- const stats2 = {
2738
- total: logHistory.length,
2739
- state: 0,
2740
- store: 0,
2741
- session: 0,
2742
- cache: 0,
2743
- idb: 0,
2744
- set: 0,
2745
- get: 0,
2746
- delete: 0,
2747
- clear: 0
2748
- };
2749
- for (const entry of logHistory) {
2750
- if (entry) {
2751
- const module = entry.module;
2752
- const action = entry.action;
2753
- if (module && typeof stats2[module] === "number") stats2[module]++;
2754
- if (action && typeof stats2[action] === "number") stats2[action]++;
2755
- }
2756
- }
2757
- return stats2;
2758
- }, "getStats");
2759
- var exportLogs = /* @__PURE__ */ __name(() => {
2760
- return JSON.stringify(logHistory, null, 2);
2761
- }, "exportLogs");
2762
- var logger = {
2763
- configure,
2764
- enable,
2765
- disable,
2766
- isEnabled,
2767
- log,
2768
- getHistory,
2769
- clearHistory,
2770
- getStats,
2771
- exportLogs
2772
- };
2773
-
2774
- // functions/devtools/index.ts
2775
- init_esm_shims();
2776
- init_internal();
2777
- init_env();
2778
- var _state = globalThis.__memorio_state_instance__;
2779
- var _store = globalThis.__memorio_store_instance__;
2780
- var _session = globalThis.__memorio_session_instance__;
2781
- var _cache = globalThis.__memorio_cache_instance__;
2782
- function isDebugEnabled2() {
2783
- return DEV && internal_default.debug === true;
2784
- }
2785
- __name(isDebugEnabled2, "isDebugEnabled");
2786
- function extractStoreData() {
2787
- if (!_store) return {};
2788
- const result = {};
2789
- const store2 = _store;
2790
- if (typeof store2.list === "function") {
2791
- try {
2792
- return store2.list();
2793
- } catch {
2794
- }
2795
- }
2796
- if (typeof store2.get === "function") {
2797
- for (const key of Object.keys(store2)) {
2798
- if (!["get", "set", "remove", "delete", "removeAll", "clearAll", "size", "isPersistent", "list"].includes(key)) {
2799
- try {
2800
- const val = store2.get(key);
2801
- if (val !== null && val !== void 0) {
2802
- result[key] = val;
2803
- }
2804
- } catch {
2805
- }
2806
- }
2807
- }
2808
- }
2809
- return result;
2810
- }
2811
- __name(extractStoreData, "extractStoreData");
2812
- function extractSessionData() {
2813
- if (!_session) return {};
2814
- const result = {};
2815
- const session2 = _session;
2816
- if (typeof session2.list === "function") {
2817
- try {
2818
- return session2.list();
2819
- } catch {
2820
- }
2821
- }
2822
- if (typeof session2.get === "function") {
2823
- for (const key of Object.keys(session2)) {
2824
- if (!["get", "set", "remove", "delete", "removeAll", "clearAll", "size", "isPersistent", "list"].includes(key)) {
2825
- try {
2826
- const val = session2.get(key);
2827
- if (val !== null && val !== void 0) {
2828
- result[key] = val;
2829
- }
2830
- } catch {
2831
- }
2832
- }
2833
- }
2834
- }
2835
- return result;
2836
- }
2837
- __name(extractSessionData, "extractSessionData");
2838
- var inspect = /* @__PURE__ */ __name(() => {
2839
- if (!isDebugEnabled2()) return;
2840
- if (_state) {
2841
- const stateList = _state.list;
2842
- let stateData;
2843
- if (typeof stateList === "function") {
2844
- stateData = stateList();
2845
- } else if (typeof stateList === "object" && stateList !== null) {
2846
- stateData = stateList;
2847
- } else {
2848
- stateData = _state;
2849
- }
2850
- console.table(stateData);
2851
- }
2852
- if (_store) {
2853
- console.table(extractStoreData());
2854
- }
2855
- if (_session) {
2856
- console.table(extractSessionData());
2857
- }
2858
- if (_cache) {
2859
- const cacheList = _cache.list;
2860
- let cacheData2;
2861
- if (typeof cacheList === "function") {
2862
- cacheData2 = cacheList();
2863
- } else if (typeof cacheList === "object" && cacheList !== null) {
2864
- cacheData2 = cacheList;
2865
- } else {
2866
- cacheData2 = _cache;
2867
- }
2868
- console.table(cacheData2);
2869
- }
2870
- }, "inspect");
2871
- var stats = /* @__PURE__ */ __name(() => {
2872
- const getKeys = /* @__PURE__ */ __name((obj) => {
2873
- if (!obj) return 0;
2874
- if (typeof obj.list === "function") {
2875
- try {
2876
- const list = obj.list();
2877
- return Object.keys(list).length;
2878
- } catch {
2879
- }
2880
- }
2881
- return Object.keys(obj).length;
2882
- }, "getKeys");
2883
- return {
2884
- stateKeys: getKeys(_state),
2885
- storeKeys: getKeys(_store),
2886
- sessionKeys: getKeys(_session),
2887
- cacheKeys: getKeys(_cache),
2888
- idbDatabases: 0,
2889
- sqliteDbCount: 0,
2890
- lastUpdate: (/* @__PURE__ */ new Date()).toISOString()
2891
- };
2892
- }, "stats");
2893
- var clear = /* @__PURE__ */ __name((moduleName) => {
2894
- const targets = { state: _state, store: _store, session: _session, cache: _cache };
2895
- const target = targets[moduleName];
2896
- if (target && typeof target.clear === "function") {
2897
- target.clear();
2898
- } else if (target && typeof target.removeAll === "function") {
2899
- target.removeAll();
2900
- } else {
2901
- console.debug(`Module ${moduleName} not found or does not support clear()/removeAll()`);
2902
- }
2903
- }, "clear");
2904
- var clearAll = /* @__PURE__ */ __name(() => {
2905
- clear("state");
2906
- clear("store");
2907
- clear("session");
2908
- clear("cache");
2909
- }, "clearAll");
2910
- var exportData = /* @__PURE__ */ __name(() => {
2911
- const getStateData = /* @__PURE__ */ __name(() => {
2912
- if (!_state) return void 0;
2913
- try {
2914
- if (typeof _state.list === "function") {
2915
- return _state.list();
2916
- }
2917
- return _state;
2918
- } catch {
2919
- return void 0;
2920
- }
2921
- }, "getStateData");
2922
- const getStoreData = /* @__PURE__ */ __name(() => {
2923
- return extractStoreData();
2924
- }, "getStoreData");
2925
- const getSessionData = /* @__PURE__ */ __name(() => {
2926
- return extractSessionData();
2927
- }, "getSessionData");
2928
- const getCacheData = /* @__PURE__ */ __name(() => {
2929
- if (!_cache) return void 0;
2930
- try {
2931
- if (typeof _cache.list === "function") {
2932
- return _cache.list();
2933
- }
2934
- return _cache;
2935
- } catch {
2936
- return void 0;
2937
- }
2938
- }, "getCacheData");
2939
- const data = {
2940
- state: getStateData(),
2941
- store: getStoreData(),
2942
- session: getSessionData(),
2943
- cache: getCacheData(),
2944
- exportedAt: (/* @__PURE__ */ new Date()).toISOString()
2945
- };
2946
- return JSON.stringify(data, null, 2);
2947
- }, "exportData");
2948
- var importData = /* @__PURE__ */ __name((jsonString) => {
2949
- try {
2950
- const data = JSON.parse(jsonString);
2951
- if (data.state) {
2952
- Object.entries(data.state).forEach(([key, value]) => {
2953
- if (_state && key !== "list" && key !== "remove" && key !== "removeAll") {
2954
- ;
2955
- _state[key] = value;
2956
- }
2957
- });
2958
- }
2959
- if (data.store && _store && typeof _store.set === "function") {
2960
- Object.entries(data.store).forEach(([key, value]) => {
2961
- ;
2962
- _store.set(key, value);
2963
- });
2964
- }
2965
- if (data.session && _session && typeof _session.set === "function") {
2966
- Object.entries(data.session).forEach(([key, value]) => {
2967
- ;
2968
- _session.set(key, value);
2969
- });
2970
- }
2971
- if (data.cache && _cache) {
2972
- Object.entries(data.cache).forEach(([key, value]) => {
2973
- if (_cache && key !== "get" && key !== "set" && key !== "remove" && key !== "clear") {
2974
- ;
2975
- _cache[key] = value;
2976
- }
2977
- });
2978
- }
2979
- } catch (error) {
2980
- console.debug("Import failed:", error);
2981
- }
2982
- }, "importData");
2983
- var watch = /* @__PURE__ */ __name((moduleName, path2) => {
2984
- const targets = { state: _state, store: _store, session: _session, cache: _cache };
2985
- const target = targets[moduleName];
2986
- if (!target) {
2987
- console.debug(`Module ${moduleName} not found`);
2988
- return;
2989
- }
2990
- const initialValue = target[path2];
2991
- console.debug(`Watching ${moduleName}.${path2} (initial: ${JSON.stringify(initialValue)})`);
2992
- if (moduleName === "state" && globalThis.memorio?.dispatch) {
2993
- const handler = /* @__PURE__ */ __name((e) => {
2994
- const detail = e.detail;
2995
- if (detail?.name?.includes(path2)) {
2996
- console.debug(`Change: ${moduleName}.${path2} =`, e.detail.value);
2997
- }
2998
- }, "handler");
2999
- target.addEventListener?.("memorio-change", handler);
3000
- }
3001
- }, "watch");
3002
- var help = /* @__PURE__ */ __name(() => {
3003
- console.debug(`
3004
- Memorio DevTools Help
3005
-
3006
- Available commands:
3007
- memorio.devtools.inspect() - Inspect all state modules
3008
- memorio.devtools.stats() - Show statistics
3009
- memorio.devtools.clear('module') - Clear specific module
3010
- memorio.devtools.clearAll() - Clear all modules
3011
- memorio.devtools.exportData() - Export all data as JSON
3012
- memorio.devtools.importData(json) - Import data from JSON
3013
- memorio.devtools.watch(module, path) - Watch a path for changes
3014
- memorio.devtools.help() - Show this help
3015
-
3016
- Shortcuts (dev only):
3017
- state - global state proxy
3018
- store - localStorage wrapper
3019
- session - sessionStorage wrapper
3020
- cache - in-memory cache
3021
- `);
3022
- }, "help");
3023
- var devtools = {
3024
- inspect,
3025
- stats,
3026
- clear,
3027
- clearAll,
3028
- exportData,
3029
- importData,
3030
- watch,
3031
- help
3032
- };
3033
-
3034
- // core/hlc.ts
3035
- init_esm_shims();
3036
- var NODE_ID_KEY = "__memorio_hlc_node";
3037
- function getNodeId() {
3038
- if (typeof globalThis === "undefined") return "node";
3039
- try {
3040
- if (typeof sessionStorage !== "undefined" && sessionStorage) {
3041
- let id = sessionStorage.getItem(NODE_ID_KEY);
3042
- if (!id) {
3043
- id = generateNodeId();
3044
- sessionStorage.setItem(NODE_ID_KEY, id);
3045
- }
3046
- return id;
3047
- }
3048
- } catch {
3049
- }
3050
- if (!globalThis.__memorioHlcNodeId) {
3051
- globalThis.__memorioHlcNodeId = generateNodeId();
3052
- }
3053
- return globalThis.__memorioHlcNodeId;
3054
- }
3055
- __name(getNodeId, "getNodeId");
3056
- function generateNodeId() {
3057
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
3058
- return crypto.randomUUID().slice(0, 8);
3059
- }
3060
- return Math.random().toString(36).slice(2, 10);
3061
- }
3062
- __name(generateNodeId, "generateNodeId");
3063
- var HLC_KEY = "__memorio_hlc_local";
3064
- var local = globalThis[HLC_KEY] || {
3065
- physical: 0,
3066
- logical: 0,
3067
- node: getNodeId()
3068
- };
3069
- if (!globalThis[HLC_KEY]) {
3070
- globalThis[HLC_KEY] = local;
3071
- }
3072
- function tick(_incoming) {
3073
- const now2 = Date.now();
3074
- const base = local.physical;
3075
- let physical;
3076
- let logical;
3077
- if (now2 > base) {
3078
- physical = now2;
3079
- logical = 0;
3080
- } else if (now2 < base) {
3081
- physical = base;
3082
- logical = local.logical + 1;
3083
- } else {
3084
- physical = base;
3085
- logical = local.logical + 1;
3086
- }
3087
- local.physical = physical;
3088
- local.logical = logical;
3089
- return { physical, logical, node: local.node };
3090
- }
3091
- __name(tick, "tick");
3092
- function receive(remote) {
3093
- const now2 = Date.now();
3094
- if (remote.physical > local.physical) {
3095
- local.physical = remote.physical > now2 ? remote.physical : now2;
3096
- local.logical = 1;
3097
- } else if (remote.physical === local.physical) {
3098
- local.logical = Math.max(local.logical, remote.logical) + 1;
3099
- }
3100
- local.node = getNodeId();
3101
- return { ...local };
3102
- }
3103
- __name(receive, "receive");
3104
- function compare(a, b) {
3105
- if (a.physical !== b.physical) {
3106
- return a.physical < b.physical ? -1 : 1;
4380
+ }
4381
+ if (previousValue !== void 0) {
4382
+ message_default(` \u2190 previous:${previousValue}`);
4383
+ }
3107
4384
  }
3108
- if (a.logical !== b.logical) {
3109
- return a.logical < b.logical ? -1 : 1;
4385
+ if (config.customHandler) {
4386
+ config.customHandler(entry);
3110
4387
  }
3111
- if (a.node !== b.node) {
3112
- return a.node < b.node ? -1 : 1;
4388
+ }, "log");
4389
+ var getModuleColor = /* @__PURE__ */ __name((module) => {
4390
+ const colors = {
4391
+ state: "#4CAF50",
4392
+ store: "#2196F3",
4393
+ session: "#FF9800",
4394
+ cache: "#9C27B0",
4395
+ idb: "#F44336"
4396
+ };
4397
+ return colors[module] || "#888888";
4398
+ }, "getModuleColor");
4399
+ var getHistory = /* @__PURE__ */ __name(() => {
4400
+ return [...logHistory];
4401
+ }, "getHistory");
4402
+ var clearHistory = /* @__PURE__ */ __name(() => {
4403
+ logHistory.length = 0;
4404
+ }, "clearHistory");
4405
+ var getStats = /* @__PURE__ */ __name(() => {
4406
+ const stats = {
4407
+ total: logHistory.length,
4408
+ state: 0,
4409
+ store: 0,
4410
+ session: 0,
4411
+ cache: 0,
4412
+ idb: 0,
4413
+ set: 0,
4414
+ get: 0,
4415
+ delete: 0,
4416
+ clear: 0
4417
+ };
4418
+ for (const entry of logHistory) {
4419
+ if (entry) {
4420
+ const module = entry.module;
4421
+ const action = entry.action;
4422
+ if (module && typeof stats[module] === "number") stats[module]++;
4423
+ if (action && typeof stats[action] === "number") stats[action]++;
4424
+ }
3113
4425
  }
3114
- return 0;
3115
- }
3116
- __name(compare, "compare");
3117
- function happenedBefore(a, b) {
3118
- return compare(a, b) < 0;
3119
- }
3120
- __name(happenedBefore, "happenedBefore");
3121
- function serialize(hlc2) {
3122
- return `hlc:${hlc2.physical}:${hlc2.logical}:${hlc2.node}`;
3123
- }
3124
- __name(serialize, "serialize");
3125
- function parse(serialized) {
3126
- if (!serialized.startsWith("hlc:")) return null;
3127
- const parts = serialized.split(":");
3128
- if (parts.length !== 4) return null;
3129
- const physical = parseInt(parts[1], 10);
3130
- const logical = parseInt(parts[2], 10);
3131
- const node = parts[3];
3132
- if (isNaN(physical) || isNaN(logical)) return null;
3133
- return { physical, logical, node };
3134
- }
3135
- __name(parse, "parse");
3136
- var hlc = {
3137
- tick,
3138
- receive,
3139
- compare,
3140
- happenedBefore,
3141
- serialize,
3142
- parse,
3143
- getNodeId
4426
+ return stats;
4427
+ }, "getStats");
4428
+ var exportLogs = /* @__PURE__ */ __name(() => {
4429
+ return JSON.stringify(logHistory, null, 2);
4430
+ }, "exportLogs");
4431
+ var logger = {
4432
+ configure,
4433
+ enable,
4434
+ disable,
4435
+ isEnabled,
4436
+ log,
4437
+ getHistory,
4438
+ clearHistory,
4439
+ getStats,
4440
+ exportLogs
3144
4441
  };
3145
4442
 
3146
4443
  // core/fractional.ts
@@ -3304,214 +4601,53 @@ function reindex(items) {
3304
4601
  if (prev === null) {
3305
4602
  newItem.key = before(items[0].key);
3306
4603
  } else if (next === null) {
3307
- newItem.key = after(prev);
3308
- } else {
3309
- newItem.key = between(prev, next);
3310
- }
3311
- result.push(newItem);
3312
- prev = newItem.key;
3313
- }
3314
- return result;
3315
- }
3316
- __name(reindex, "reindex");
3317
- var fractional = {
3318
- generateBetween,
3319
- firstKey,
3320
- after,
3321
- before,
3322
- between,
3323
- reorder,
3324
- reindex
3325
- };
3326
-
3327
- // index.ts
3328
- init_internal();
3329
- init_platform();
3330
-
3331
- // core/global.ts
3332
- init_esm_shims();
3333
- init_platform();
3334
- init_internal();
3335
-
3336
- // package.json
3337
- var package_default = {
3338
- version: "4.9.35"};
3339
-
3340
- // core/global.ts
3341
- init_env();
3342
- init_store();
3343
- init_idb();
3344
- init_sqlite();
3345
- init_message();
3346
-
3347
- // functions/typed/index.ts
3348
- init_esm_shims();
3349
- function typed() {
3350
- return state2;
3351
- }
3352
- __name(typed, "typed");
3353
-
3354
- // functions/history/index.ts
3355
- init_esm_shims();
3356
- init_internal();
3357
- init_env();
3358
- init_message();
3359
- function _clone(value) {
3360
- if (value === null || typeof value !== "object") return value;
3361
- try {
3362
- return deepRaw(value, /* @__PURE__ */ new WeakSet());
3363
- } catch (err) {
3364
- if (DEV) console.warn("[memorio history] deep clone failed:", err);
3365
- return value;
3366
- }
3367
- }
3368
- __name(_clone, "_clone");
3369
- var snapshot = /* @__PURE__ */ __name(() => {
3370
- return deepRaw(state2, /* @__PURE__ */ new WeakSet());
3371
- }, "snapshot");
3372
- var diff = /* @__PURE__ */ __name((snap) => {
3373
- const changes = [];
3374
- const _walk = /* @__PURE__ */ __name((oldObj, newObj, prefix) => {
3375
- const oldKeys = oldObj ? Object.keys(oldObj) : [];
3376
- const newKeys = newObj ? Object.keys(newObj) : [];
3377
- for (const key of newKeys) {
3378
- const newPath = prefix ? `${prefix}.${key}` : key;
3379
- const oldVal = oldObj ? oldObj[key] : void 0;
3380
- const newVal = newObj[key];
3381
- if (oldVal !== newVal) {
3382
- const oldType = typeof oldVal;
3383
- const newType = typeof newVal;
3384
- if (oldType !== newType || oldVal === void 0) {
3385
- changes.push({ path: newPath, oldValue: oldVal, newValue: newVal });
3386
- } else if (oldVal && typeof oldVal === "object") {
3387
- _walk(oldVal, newVal, newPath);
3388
- } else if (oldVal !== newVal) {
3389
- changes.push({ path: newPath, oldValue: oldVal, newValue: newVal });
3390
- }
3391
- }
3392
- }
3393
- for (const key of oldKeys) {
3394
- if (!(key in (newObj || {}))) {
3395
- const newPath = prefix ? `${prefix}.${key}` : key;
3396
- changes.push({ path: newPath, oldValue: oldObj[key], newValue: void 0 });
3397
- }
3398
- }
3399
- }, "_walk");
3400
- _walk(snap, deepRaw(state2), "");
3401
- return changes;
3402
- }, "diff");
3403
- var enableHistory = /* @__PURE__ */ __name((enabled = true) => {
3404
- internal_default.historyEnabled = enabled;
3405
- message_default(`[memorio history] Tracking ${enabled ? "enabled" : "disabled"}`);
3406
- }, "enableHistory");
3407
- var trace = /* @__PURE__ */ __name(() => {
3408
- return [...internal_default.mutations];
3409
- }, "trace");
3410
- var canUndo = /* @__PURE__ */ __name(() => {
3411
- return internal_default.canUndo();
3412
- }, "canUndo");
3413
- var canRedo = /* @__PURE__ */ __name(() => {
3414
- return internal_default.canRedo();
3415
- }, "canRedo");
3416
- var undo = /* @__PURE__ */ __name(() => {
3417
- if (!internal_default.historyEnabled) {
3418
- message_default("[memorio history] History is not enabled");
3419
- return void 0;
3420
- }
3421
- const record = internal_default.popUndo();
3422
- if (!record) return void 0;
3423
- _applyInverse(record);
3424
- message_default(`[memorio history] Undid: ${record.action} ${record.path}`);
3425
- return record;
3426
- }, "undo");
3427
- var redo = /* @__PURE__ */ __name(() => {
3428
- if (!internal_default.historyEnabled) {
3429
- message_default("[memorio history] History is not enabled");
3430
- return void 0;
3431
- }
3432
- const record = internal_default.popRedo();
3433
- if (!record) return void 0;
3434
- _applyForward(record);
3435
- message_default(`[memorio history] Redid: ${record.action} ${record.path}`);
3436
- return record;
3437
- }, "redo");
3438
- function _applyInverse(record) {
3439
- const wasEnabled = internal_default.historyEnabled;
3440
- internal_default.historyEnabled = false;
3441
- try {
3442
- if (record.action === "set") {
3443
- if (record.previousValue === void 0) {
3444
- _deletePath(record.path);
3445
- } else {
3446
- _setPath(record.path, record.previousValue);
3447
- }
3448
- } else if (record.action === "delete") {
3449
- if (record.previousValue !== void 0) {
3450
- _setPath(record.path, record.previousValue);
3451
- }
3452
- }
3453
- } finally {
3454
- internal_default.historyEnabled = wasEnabled;
3455
- }
3456
- }
3457
- __name(_applyInverse, "_applyInverse");
3458
- function _applyForward(record) {
3459
- const wasEnabled = internal_default.historyEnabled;
3460
- internal_default.historyEnabled = false;
3461
- try {
3462
- if (record.action === "set") {
3463
- _setPath(record.path, record.newValue);
3464
- } else if (record.action === "delete") {
3465
- _deletePath(record.path);
3466
- }
3467
- } finally {
3468
- internal_default.historyEnabled = wasEnabled;
3469
- }
3470
- }
3471
- __name(_applyForward, "_applyForward");
3472
- function _setPath(path2, value) {
3473
- const parts = path2.split(".");
3474
- let current = state2;
3475
- for (let i = 0; i < parts.length - 1; i++) {
3476
- const part = parts[i];
3477
- if (current[part] === void 0) {
3478
- current[part] = {};
4604
+ newItem.key = after(prev);
4605
+ } else {
4606
+ newItem.key = between(prev, next);
3479
4607
  }
3480
- current = current[part];
4608
+ result.push(newItem);
4609
+ prev = newItem.key;
3481
4610
  }
3482
- current[parts[parts.length - 1]] = value;
4611
+ return result;
3483
4612
  }
3484
- __name(_setPath, "_setPath");
3485
- function _deletePath(path2) {
3486
- const parts = path2.split(".");
3487
- if (parts.length === 1) {
3488
- state2.remove(parts[0]);
3489
- return;
3490
- }
3491
- let current = state2;
3492
- for (let i = 0; i < parts.length - 1; i++) {
3493
- const part = parts[i];
3494
- if (current[part] === void 0) return;
3495
- current = current[part];
3496
- }
3497
- delete current[parts[parts.length - 1]];
4613
+ __name(reindex, "reindex");
4614
+ var fractional = {
4615
+ generateBetween,
4616
+ firstKey,
4617
+ after,
4618
+ before,
4619
+ between,
4620
+ reorder,
4621
+ reindex
4622
+ };
4623
+
4624
+ // index.ts
4625
+ init_internal();
4626
+ init_platform();
4627
+
4628
+ // core/global.ts
4629
+ init_esm_shims();
4630
+ init_platform();
4631
+ init_internal();
4632
+
4633
+ // package.json
4634
+ var package_default = {
4635
+ version: "5.1.0"};
4636
+
4637
+ // core/global.ts
4638
+ init_env();
4639
+ init_store();
4640
+ init_idb();
4641
+ init_sqlite();
4642
+ init_encryption();
4643
+ init_message();
4644
+
4645
+ // functions/typed/index.ts
4646
+ init_esm_shims();
4647
+ function typed() {
4648
+ return state2;
3498
4649
  }
3499
- __name(_deletePath, "_deletePath");
3500
- var rollback = /* @__PURE__ */ __name((snap) => {
3501
- state2.removeAll();
3502
- for (const key of Object.keys(snap)) {
3503
- state2[key] = _clone(snap[key]);
3504
- }
3505
- internal_default.clearHistory();
3506
- message_default("[memorio history] State rolled back to snapshot");
3507
- }, "rollback");
3508
- var clearHistory2 = /* @__PURE__ */ __name(() => {
3509
- internal_default.clearHistory();
3510
- message_default("[memorio history] History cleared");
3511
- }, "clearHistory");
3512
- var clearRedo = /* @__PURE__ */ __name(() => {
3513
- internal_default.clearRedo();
3514
- }, "clearRedo");
4650
+ __name(typed, "typed");
3515
4651
 
3516
4652
  // functions/memory/index.ts
3517
4653
  init_esm_shims();
@@ -4204,83 +5340,167 @@ var memory = {
4204
5340
  }
4205
5341
  };
4206
5342
 
4207
- // functions/inspect/index.ts
5343
+ // functions/history/index.ts
4208
5344
  init_esm_shims();
5345
+ init_internal();
4209
5346
  init_env();
4210
- var stateKeys = /* @__PURE__ */ __name(() => {
4211
- const raw = deepRaw(state2);
4212
- return Object.keys(raw).filter(
4213
- (k) => !["list", "remove", "removeAll", "lock", "unlock"].includes(k)
4214
- );
4215
- }, "stateKeys");
4216
- var pathExists = /* @__PURE__ */ __name((path2) => {
4217
- if (!path2 || typeof path2 !== "string") return false;
4218
- const parts = path2.replace(/^state\./, "").split(".");
4219
- let current = state2;
4220
- for (const part of parts) {
4221
- if (current === null || current === void 0) {
4222
- return false;
4223
- }
4224
- current = current[part];
5347
+ init_message();
5348
+ function _clone(value) {
5349
+ if (value === null || typeof value !== "object") return value;
5350
+ try {
5351
+ return deepRaw(value, /* @__PURE__ */ new WeakSet());
5352
+ } catch (err) {
5353
+ if (DEV) console.warn("[memorio history] deep clone failed:", err);
5354
+ return value;
4225
5355
  }
4226
- return current !== void 0;
4227
- }, "pathExists");
4228
- var stateType = /* @__PURE__ */ __name((path2) => {
4229
- const [exists, value] = _getValue(path2);
4230
- if (!exists || value === void 0) return "undefined";
4231
- return Array.isArray(value) ? "array" : typeof value;
4232
- }, "stateType");
4233
- var stateGet = /* @__PURE__ */ __name((path2) => {
4234
- const [exists, value] = _getValue(path2);
4235
- if (!exists || value === void 0) return void 0;
4236
- return _clone2(value);
4237
- }, "stateGet");
4238
- var stateSchema = /* @__PURE__ */ __name(() => {
4239
- const result = [];
4240
- const _walk = /* @__PURE__ */ __name((obj, prefix) => {
4241
- if (obj === null || typeof obj !== "object" || Array.isArray(obj)) {
4242
- return;
4243
- }
4244
- const keys = Object.keys(obj).filter(
4245
- (k) => !["list", "remove", "removeAll", "lock", "unlock"].includes(k)
4246
- );
4247
- for (const key of keys) {
5356
+ }
5357
+ __name(_clone, "_clone");
5358
+ var snapshot = /* @__PURE__ */ __name(() => {
5359
+ return deepRaw(state2, /* @__PURE__ */ new WeakSet());
5360
+ }, "snapshot");
5361
+ var diff = /* @__PURE__ */ __name((snap) => {
5362
+ const changes = [];
5363
+ const _walk = /* @__PURE__ */ __name((oldObj, newObj, prefix) => {
5364
+ const oldKeys = oldObj ? Object.keys(oldObj) : [];
5365
+ const newKeys = newObj ? Object.keys(newObj) : [];
5366
+ for (const key of newKeys) {
4248
5367
  const newPath = prefix ? `${prefix}.${key}` : key;
4249
- const value = obj[key];
4250
- const defined = value !== void 0;
4251
- const type = defined ? Array.isArray(value) ? "array" : typeof value : "undefined";
4252
- result.push({ path: newPath, type, defined });
4253
- if (defined && typeof value === "object" && !Array.isArray(value) && value.constructor?.name === "Object") {
4254
- _walk(value, newPath);
5368
+ const oldVal = oldObj ? oldObj[key] : void 0;
5369
+ const newVal = newObj[key];
5370
+ if (oldVal !== newVal) {
5371
+ const oldType = typeof oldVal;
5372
+ const newType = typeof newVal;
5373
+ if (oldType !== newType || oldVal === void 0) {
5374
+ changes.push({ path: newPath, oldValue: oldVal, newValue: newVal });
5375
+ } else if (oldVal && typeof oldVal === "object") {
5376
+ _walk(oldVal, newVal, newPath);
5377
+ } else if (oldVal !== newVal) {
5378
+ changes.push({ path: newPath, oldValue: oldVal, newValue: newVal });
5379
+ }
5380
+ }
5381
+ }
5382
+ for (const key of oldKeys) {
5383
+ if (!(key in (newObj || {}))) {
5384
+ const newPath = prefix ? `${prefix}.${key}` : key;
5385
+ changes.push({ path: newPath, oldValue: oldObj[key], newValue: void 0 });
4255
5386
  }
4256
5387
  }
4257
5388
  }, "_walk");
4258
- _walk(deepRaw(state2), "");
4259
- return result;
4260
- }, "stateSchema");
4261
- function _getValue(path2) {
4262
- if (!path2 || typeof path2 !== "string") return [false, void 0];
4263
- const parts = path2.replace(/^state\./, "").split(".");
5389
+ _walk(snap, deepRaw(state2), "");
5390
+ return changes;
5391
+ }, "diff");
5392
+ var enableHistory = /* @__PURE__ */ __name((enabled = true) => {
5393
+ internal_default.historyEnabled = enabled;
5394
+ message_default(`[memorio history] Tracking ${enabled ? "enabled" : "disabled"}`);
5395
+ }, "enableHistory");
5396
+ var trace = /* @__PURE__ */ __name(() => {
5397
+ return [...internal_default.mutations];
5398
+ }, "trace");
5399
+ var canUndo = /* @__PURE__ */ __name(() => {
5400
+ return internal_default.canUndo();
5401
+ }, "canUndo");
5402
+ var canRedo = /* @__PURE__ */ __name(() => {
5403
+ return internal_default.canRedo();
5404
+ }, "canRedo");
5405
+ var undo = /* @__PURE__ */ __name(() => {
5406
+ if (!internal_default.historyEnabled) {
5407
+ message_default("[memorio history] History is not enabled");
5408
+ return void 0;
5409
+ }
5410
+ const record = internal_default.popUndo();
5411
+ if (!record) return void 0;
5412
+ _applyInverse2(record);
5413
+ message_default(`[memorio history] Undid: ${record.action} ${record.path}`);
5414
+ return record;
5415
+ }, "undo");
5416
+ var redo = /* @__PURE__ */ __name(() => {
5417
+ if (!internal_default.historyEnabled) {
5418
+ message_default("[memorio history] History is not enabled");
5419
+ return void 0;
5420
+ }
5421
+ const record = internal_default.popRedo();
5422
+ if (!record) return void 0;
5423
+ _applyForward(record);
5424
+ message_default(`[memorio history] Redid: ${record.action} ${record.path}`);
5425
+ return record;
5426
+ }, "redo");
5427
+ function _applyInverse2(record) {
5428
+ const wasEnabled = internal_default.historyEnabled;
5429
+ internal_default.historyEnabled = false;
5430
+ try {
5431
+ if (record.action === "set") {
5432
+ if (record.previousValue === void 0) {
5433
+ _deletePath2(record.path);
5434
+ } else {
5435
+ _setPath2(record.path, record.previousValue);
5436
+ }
5437
+ } else if (record.action === "delete") {
5438
+ if (record.previousValue !== void 0) {
5439
+ _setPath2(record.path, record.previousValue);
5440
+ }
5441
+ }
5442
+ } finally {
5443
+ internal_default.historyEnabled = wasEnabled;
5444
+ }
5445
+ }
5446
+ __name(_applyInverse2, "_applyInverse");
5447
+ function _applyForward(record) {
5448
+ const wasEnabled = internal_default.historyEnabled;
5449
+ internal_default.historyEnabled = false;
5450
+ try {
5451
+ if (record.action === "set") {
5452
+ _setPath2(record.path, record.newValue);
5453
+ } else if (record.action === "delete") {
5454
+ _deletePath2(record.path);
5455
+ }
5456
+ } finally {
5457
+ internal_default.historyEnabled = wasEnabled;
5458
+ }
5459
+ }
5460
+ __name(_applyForward, "_applyForward");
5461
+ function _setPath2(path2, value) {
5462
+ const parts = path2.split(".");
4264
5463
  let current = state2;
4265
- for (const part of parts) {
4266
- if (current === null || current === void 0) {
4267
- return [false, void 0];
5464
+ for (let i = 0; i < parts.length - 1; i++) {
5465
+ const part = parts[i];
5466
+ if (current[part] === void 0) {
5467
+ current[part] = {};
4268
5468
  }
4269
5469
  current = current[part];
4270
5470
  }
4271
- return [current !== void 0, current];
5471
+ current[parts[parts.length - 1]] = value;
4272
5472
  }
4273
- __name(_getValue, "_getValue");
4274
- function _clone2(value) {
4275
- if (value === null || typeof value !== "object") return value;
4276
- try {
4277
- return deepRaw(value, /* @__PURE__ */ new WeakSet());
4278
- } catch (err) {
4279
- if (DEV) console.warn("[memorio inspect] deep clone failed:", err);
4280
- return value;
5473
+ __name(_setPath2, "_setPath");
5474
+ function _deletePath2(path2) {
5475
+ const parts = path2.split(".");
5476
+ if (parts.length === 1) {
5477
+ state2.remove(parts[0]);
5478
+ return;
5479
+ }
5480
+ let current = state2;
5481
+ for (let i = 0; i < parts.length - 1; i++) {
5482
+ const part = parts[i];
5483
+ if (current[part] === void 0) return;
5484
+ current = current[part];
4281
5485
  }
5486
+ delete current[parts[parts.length - 1]];
4282
5487
  }
4283
- __name(_clone2, "_clone");
5488
+ __name(_deletePath2, "_deletePath");
5489
+ var rollback = /* @__PURE__ */ __name((snap) => {
5490
+ state2.removeAll();
5491
+ for (const key of Object.keys(snap)) {
5492
+ state2[key] = _clone(snap[key]);
5493
+ }
5494
+ internal_default.clearHistory();
5495
+ message_default("[memorio history] State rolled back to snapshot");
5496
+ }, "rollback");
5497
+ var clearHistory2 = /* @__PURE__ */ __name(() => {
5498
+ internal_default.clearHistory();
5499
+ message_default("[memorio history] History cleared");
5500
+ }, "clearHistory");
5501
+ var clearRedo = /* @__PURE__ */ __name(() => {
5502
+ internal_default.clearRedo();
5503
+ }, "clearRedo");
4284
5504
 
4285
5505
  // core/global.ts
4286
5506
  if (!("memorio" in globalThis)) {
@@ -4315,6 +5535,26 @@ if (!("memorio" in globalThis)) {
4315
5535
  }
4316
5536
  );
4317
5537
  }
5538
+ if (typeof globalThis.addEventListener !== "function") {
5539
+ const listeners = {};
5540
+ globalThis.addEventListener = (name, cb) => {
5541
+ (listeners[name] = listeners[name] ?? []).push(cb);
5542
+ };
5543
+ globalThis.removeEventListener = (name, cb) => {
5544
+ const arr = listeners[name];
5545
+ if (arr) {
5546
+ const idx = arr.indexOf(cb);
5547
+ if (idx > -1) arr.splice(idx, 1);
5548
+ }
5549
+ };
5550
+ globalThis.dispatchEvent = (e) => {
5551
+ const type = (e && typeof e === "object" ? e.type : null) || String(e);
5552
+ const arr = listeners[type];
5553
+ if (arr) {
5554
+ arr.slice().forEach((cb) => cb(e));
5555
+ }
5556
+ };
5557
+ }
4318
5558
  if (typeof globalThis.addEventListener === "function") {
4319
5559
  dispatch.listen("memorio:memory:cleanup", async () => memory.forgetExpired?.());
4320
5560
  }
@@ -4328,16 +5568,18 @@ if (!("memorio" in globalThis)) {
4328
5568
  }
4329
5569
  );
4330
5570
  memorio.memory = memory;
5571
+ memorio.encryption = encryption;
4331
5572
  initializePlatform();
4332
5573
  memorio.isBrowser = isBrowser;
4333
5574
  memorio.isNode = isNode;
4334
5575
  memorio.isDeno = isDeno;
5576
+ memorio.isBun = isBun;
4335
5577
  memorio.isEdge = isEdge;
4336
5578
  memorio.getCapabilities = getCapabilities;
4337
5579
  memorio.createContext = createContext;
4338
5580
  memorio.listContexts = listContexts;
4339
5581
  memorio.deleteContext = deleteContext;
4340
- memorio.isolate = (name) => createContext(name);
5582
+ memorio.isolate = (name, opts) => createContext(name, opts);
4341
5583
  Object.defineProperty(memorio, "setContext", { writable: false, enumerable: false, value: /* @__PURE__ */ __name((id) => setCurrentContext(id), "value") });
4342
5584
  Object.defineProperty(memorio, "getContext", { writable: false, enumerable: false, value: /* @__PURE__ */ __name(() => internal_default.currentContext, "value") });
4343
5585
  memorio.registerSchema = schema.register;
@@ -4345,6 +5587,9 @@ if (!("memorio" in globalThis)) {
4345
5587
  memorio.unregisterSchema = schema.unregister;
4346
5588
  memorio.listSchemas = schema.list;
4347
5589
  memorio.typed = typed;
5590
+ memorio.computed = computed;
5591
+ memorio.broadcast = broadcast;
5592
+ memorio.security = security;
4348
5593
  memorio.snapshot = snapshot;
4349
5594
  memorio.diff = diff;
4350
5595
  memorio.undo = undo;
@@ -4356,10 +5601,17 @@ if (!("memorio" in globalThis)) {
4356
5601
  memorio.enableHistory = enableHistory;
4357
5602
  memorio.clearHistory = clearHistory2;
4358
5603
  memorio.clearRedo = clearRedo;
5604
+ memorio.mutate = mutate;
5605
+ memorio.createMutation = createMutation;
5606
+ memorio.recordMutation = recordMutation;
5607
+ memorio.toPatch = toPatch;
5608
+ memorio.transaction = beginTransaction;
5609
+ memorio.commitTransaction = commitTransaction;
5610
+ memorio.abortTransaction = abortTransaction;
5611
+ memorio.currentTransaction = currentTransaction;
4359
5612
  Object.defineProperty(memorio, "dispatch", { value: dispatch, writable: true, enumerable: false, configurable: true });
4360
- const isDev = DEV;
4361
5613
  memorio.env = {
4362
- isDev,
5614
+ isDev: DEV,
4363
5615
  isProd: PROD
4364
5616
  };
4365
5617
  memorio.global = function() {
@@ -4371,153 +5623,39 @@ if (!("memorio" in globalThis)) {
4371
5623
  idb,
4372
5624
  sqlite,
4373
5625
  observer,
4374
- useObserver
5626
+ useObserver,
5627
+ encryption,
5628
+ computed,
5629
+ broadcast,
5630
+ security
4375
5631
  };
4376
5632
  for (const key of Object.keys(globalDefinitions)) {
4377
5633
  if (!(key in globalThis)) {
4378
5634
  Object.defineProperty(globalThis, key, {
4379
5635
  value: globalDefinitions[key],
4380
5636
  writable: true,
4381
- enumerable: false,
4382
- configurable: true
5637
+ configurable: true,
5638
+ enumerable: false
4383
5639
  });
4384
5640
  }
4385
5641
  }
5642
+ if (typeof globalThis.useObserver === "function") {
5643
+ Object.freeze(globalThis.useObserver);
5644
+ }
4386
5645
  };
4387
- if (isDev) {
4388
- memorio.global();
4389
- }
4390
- if (DEV) {
4391
- Object.defineProperty(
4392
- memorio,
4393
- "debug",
4394
- {
4395
- get: /* @__PURE__ */ __name(() => internal_default.debug, "get"),
4396
- set: /* @__PURE__ */ __name((v) => {
4397
- internal_default.debug = v;
4398
- }, "set"),
4399
- enumerable: false
4400
- }
4401
- );
4402
- const caps = getCapabilities();
4403
- Object.defineProperty(memorio, "_platform", { writable: false, enumerable: false, value: caps.platform });
4404
- Object.defineProperty(memorio, "_capabilities", { writable: false, enumerable: false, value: caps });
4405
- Object.defineProperty(memorio, "_sessionId", { writable: false, enumerable: false, value: generateSessionId() });
4406
- memorio.logger = logger;
4407
- if (!("$state" in globalThis)) Object.defineProperty(globalThis, "$state", { get: /* @__PURE__ */ __name(() => globalThis.state, "get"), configurable: true });
4408
- if (!("$store" in globalThis)) Object.defineProperty(globalThis, "$store", { get: /* @__PURE__ */ __name(() => globalThis.store, "get"), configurable: true });
4409
- if (!("$session" in globalThis)) Object.defineProperty(globalThis, "$session", { get: /* @__PURE__ */ __name(() => globalThis.session, "get"), configurable: true });
4410
- if (!("$cache" in globalThis)) Object.defineProperty(globalThis, "$cache", { get: /* @__PURE__ */ __name(() => globalThis.cache, "get"), configurable: true });
4411
- memorio.devtools = devtools;
4412
- memorio.inspect = stateKeys;
4413
- memorio.stateKeys = stateKeys;
4414
- memorio.pathExists = pathExists;
4415
- memorio.stateType = stateType;
4416
- memorio.stateGet = stateGet;
4417
- memorio.stateSchema = stateSchema;
4418
- memorio.help = function() {
4419
- console.debug(`
4420
- \u{1F9E0} Memorio ${package_default.version} - Help
4421
-
4422
- Core Modules (runtime):
4423
- state - Reactive state management (DEV global)
4424
- store - Persistent storage (localStorage/Map)
4425
- session - Session storage (sessionStorage/Map)
4426
- cache - In-memory cache
4427
- idb - IndexedDB (browser only)
4428
- sqlite - SQLite in browser (sql.js, optional)
4429
-
4430
- Platform Detection:
4431
- memorio.isBrowser() - Browser environment
4432
- memorio.isNode() - Node.js environment
4433
- memorio.isDeno() - Deno environment
4434
- memorio.isEdge() - Edge/Worker environment
4435
- memorio.getCapabilities() - Full capabilities object
4436
-
4437
- Context Management:
4438
- memorio.isolate(name) - Create isolated context
4439
- memorio.listContexts() - List all contexts
4440
- memorio.deleteContext(id) - Delete a context
4441
-
4442
- Schema Validation (runtime):
4443
- memorio.registerSchema() - Register a validator for a state path
4444
- memorio.validate() - Manually validate a value
4445
- memorio.unregisterSchema() - Remove a registered schema
4446
- memorio.listSchemas() - List all registered schema paths
4447
- memorio.typed<T>() - Type-safe view of global state (compile-time only)
4448
-
4449
- History & Time Travel (runtime):
4450
- memorio.snapshot() - Capture a deep snapshot of state
4451
- memorio.diff(snap) - Diff snapshot against current state
4452
- memorio.undo() / redo() - Undo / redo the last mutation
4453
- memorio.canUndo() / canRedo() - Check availability
4454
- memorio.rollback(snap) - Restore state from a snapshot
4455
- memorio.trace() - List all recorded mutations
4456
- memorio.enableHistory() - Enable/disable mutation tracking
4457
- memorio.clearHistory() - Clear undo/redo stacks and trace log
4458
-
4459
- DevTools (development-only):
4460
- memorio.devtools.inspect() - Inspect all modules
4461
- memorio.devtools.stats() - Show statistics
4462
- memorio.devtools.watch() - Watch a path
4463
- memorio.devtools.exportData() - Export as JSON
4464
- memorio.devtools.importData() - Import from JSON
4465
- memorio.devtools.clear() - Clear specific module
4466
- memorio.devtools.clearAll() - Clear all modules
4467
-
4468
- Introspection (development-only):
4469
- memorio.stateKeys() - List top-level state keys
4470
- memorio.pathExists(path) - Check if a state path exists
4471
- memorio.stateType(path) - Get runtime type of a state value
4472
- memorio.stateGet(path) - Get a deep-cloned value at a path
4473
- memorio.stateSchema() - Get a schema report of all state paths
4474
-
4475
- Debug:
4476
- memorio.debug = true - Enable debug output (DEV only)
4477
-
4478
- Memory System (runtime):
4479
- memorio.memory.remember(key, value, opts) - Store a memory with type, confidence, scope, TTL, tags
4480
- memorio.memory.recall(key, opts) - Retrieve a memory with filtering
4481
- memorio.memory.update(key, value, opts) - Update an existing memory
4482
- memorio.memory.forget(key) - Delete a specific memory
4483
- memorio.memory.context(opts) - Get ranked relevant memories (semantic context for AI)
4484
- memorio.memory.stats() - Memory usage statistics
4485
- memorio.memory.forgetExpired() - Remove all expired entries
4486
- memorio.memory.clear() - Wipe all memories
4487
- memorio.memory.configure({ sync }) - Optional cloud-sync provider + namespace
4488
- memorio.memory.journal.pending() - Local op journal (SQLite/store)
4489
-
4490
- Scopes:
4491
- hot - In-memory reactive state (volatile, fastest)
4492
- session - sessionStorage (persists across page reloads, cleared on tab close)
4493
- local - localStorage (persistent, survives browser restart)
4494
- durable - IndexedDB (large datasets, async)
4495
- sql - SQLite / sql.js (browser, optional, full SQL)
4496
-
4497
- TTL options:
4498
- ttl: number (milliseconds) or null (never expires)
4499
-
4500
- Memory types:
4501
- fact, preference, decision, task, context
4502
-
4503
- Console shortcuts (DEV only):
4504
- state, store, session, cache, idb, sqlite - direct access to modules
4505
- $state, $store, $session, $cache - aliases for the above
4506
- `);
4507
- };
4508
- }
4509
5646
  }
4510
5647
 
4511
5648
  // index.ts
4512
- var devtools2 = DEV ? devtools : void 0;
5649
+ var transaction = beginTransaction;
5650
+ var devtools = void 0;
4513
5651
  var memorio2 = globalThis.memorio;
4514
5652
  var events = globalThis.events;
4515
5653
  var isolate = /* @__PURE__ */ __name((name) => createContext(name), "isolate");
4516
- var help2 = globalThis.memorio?.help;
5654
+ var help = globalThis.memorio?.help;
4517
5655
  var setContext = /* @__PURE__ */ __name((id) => internal_default.currentContext = id, "setContext");
4518
5656
  var getContext = /* @__PURE__ */ __name(() => internal_default.currentContext, "getContext");
4519
5657
  var index_default = memorio2;
4520
5658
 
4521
- export { DEV, PROD, cache, canRedo, canUndo, clearHistory2 as clearHistory, clearRedo, createContext, index_default as default, deleteContext, devtools2 as devtools, diff, dispatch, enableHistory, events, fractional, getCapabilities, getContext, help2 as help, hlc, idb, internal_default as internal, isBrowser, isDeno, isEdge, isNode, isolate, listContexts, listSchemas, logger, memorio2 as memorio, memory, message, observer, propertyName, redo, registerSchema, rollback, schema, session, setContext, snapshot, sqlite, state2 as state, store, trace, typed, undo, unregisterSchema, useObserver, validate };
5659
+ export { DEV, PROD, abortTransaction, activeTransactionId, beginTransaction, broadcast, cache, canMerge, canRedo, canUndo, clearHistory2 as clearHistory, clearRedo, commitTransaction, computed, createContext, createMutation, currentTimestamp, currentTransaction, index_default as default, deleteContext, devtools, diff, diffToPatch, dispatch, enableHistory, encryption, events, fractional, generateCommitId, generateMutationId, generateTransactionId, getCapabilities, getContext, help, hlc, idb, internal_default as internal, isBrowser, isBun, isDeno, isEdge, isNode, isolate, listContexts, listSchemas, listTransactions, logger, memorio2 as memorio, memory, mergePatches, message, mutate, mutationToPatch, observer, propertyName, recordMutation, redo, registerSchema, rollback, schema, security, session, setContext, snapshot, sqlite, state2 as state, store, toPatch, trace, transaction, typed, undo, unregisterSchema, useObserver, validate };
4522
5660
  //# sourceMappingURL=index.js.map
4523
5661
  //# sourceMappingURL=index.js.map