memorio 4.7.3 โ†’ 4.9.5

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.
@@ -1,10 +1,17 @@
1
1
  import type {
2
2
  MemoryEntry,
3
+ MemorySync,
4
+ MemoryOperation,
5
+ SyncProvider,
6
+ SyncConfig,
7
+ SyncAck,
8
+ SyncDirection,
3
9
  RememberOptions,
4
10
  RecallOptions,
5
11
  ContextOptions,
6
12
  ContextEntry,
7
- MemoryStats
13
+ MemoryStats,
14
+ PatchOperation
8
15
  } from './memory'
9
16
 
10
17
  /**
@@ -24,15 +31,10 @@ interface _memorio {
24
31
  array: unknown[]
25
32
  dispatch: _dispatch
26
33
  setDescription: (description: string) => void
27
- logger?: {
28
- log: (...args: unknown[]) => void
29
- debug: (...args: unknown[]) => void
30
- info: (...args: unknown[]) => void
31
- warn: (...args: unknown[]) => void
32
- error: (...args: unknown[]) => void
33
- }
34
+ logger?: any
34
35
  objPath?: (prop: string, object: string[], separator?: string) => string
35
36
  propertyName?: string | ((container: any, object: any) => string | null)
37
+
36
38
  debug?: boolean
37
39
  // State management properties
38
40
  _tracking?: boolean
@@ -70,7 +72,9 @@ interface _memorio {
70
72
  cache: any
71
73
  }
72
74
  help?: () => void
73
- // Schema validation
75
+ global?: () => void
76
+ env?: { isDev: boolean; isProd: boolean }
77
+ // Schema validation
74
78
  registerSchema?: (path: string, schema: any) => void
75
79
  validate?: (path: string, value: any) => { valid: boolean; errors?: string[] }
76
80
  unregisterSchema?: (path: string) => boolean
@@ -96,6 +100,11 @@ interface _memorio {
96
100
  stateGet?: (path: string) => any
97
101
  stateSchema?: () => Array<{ path: string; type: string; defined: boolean }>
98
102
  memory?: MemoryAPI
103
+ // Development-only surfaces (excluded from production builds via `if (DEV)`).
104
+ // Not a security boundary on its own - rely on your backend for auth.
105
+ devtools?: any
106
+ inspect?: () => string[]
107
+ [key: string]: any
99
108
  }
100
109
 
101
110
  interface MemoryAPI {
@@ -103,13 +112,37 @@ interface MemoryAPI {
103
112
  recall<T>(query: string, opts?: RecallOptions): Promise<T | null>
104
113
  update(key: string, value: any, opts?: Partial<RememberOptions>): Promise<void>
105
114
  forget(key: string): Promise<void>
115
+ patch(key: string, patches: PatchOperation[]): Promise<void>
106
116
  context(opts?: ContextOptions): Promise<ContextEntry[]>
107
117
  stats(): Promise<MemoryStats>
108
118
  forgetExpired(): Promise<number>
109
119
  clear(): Promise<void>
120
+ /**
121
+ * Configure the optional cloud-sync layer. Supplying a `provider` (an
122
+ * application-owned object that knows how to talk to your backend) enables
123
+ * the local operation journal. The `namespace` (tenant/user/device)
124
+ * partitions the journal so contexts/tenants cannot read each other's
125
+ * operations. Memorio never handles credentials - auth lives in the
126
+ * provider/backend.
127
+ */
128
+ configure(opts: SyncConfig): MemoryAPI
129
+ /** Local operation journal. Writes are namespaced and durable (SQLite when
130
+ * available, else localStorage). Use `replay()` to push `pending()` entries
131
+ * to the configured provider. */
132
+ journal: MemoryJournal
133
+ }
134
+
135
+ interface MemoryJournal {
136
+ append(entry: MemoryEntry, operation: MemoryOperation): Promise<MemoryEntry>
137
+ pending(): Promise<MemoryEntry[]>
138
+ markSynced(ids: string[]): Promise<number>
139
+ get(id: string): Promise<MemoryEntry | null>
140
+ clear(): Promise<void>
141
+ replay(): Promise<SyncAck>
142
+ status(): Promise<'store'>
110
143
  }
111
144
 
112
- type memorio = _memorio
145
+ type memorio = _memorio
113
146
  declare var memorio: _memorio
114
147
 
115
148
  interface GlobalMemorio {
package/types/memory.d.ts CHANGED
@@ -9,6 +9,80 @@ export type MemoryType =
9
9
 
10
10
  export type MemoryStatus = 'active' | 'obsolete' | 'superseded'
11
11
 
12
+ /**
13
+ * A field-level patch operation recorded in the sync journal instead of
14
+ * recording the entire entity. Enables automatic merging when two devices
15
+ * edit different fields of the same object.
16
+ */
17
+ export interface PatchOperation {
18
+ op: 'set' | 'delete'
19
+ path: string
20
+ value?: unknown
21
+ }
22
+
23
+ /**
24
+ * Logical operations recorded in the local sync journal.
25
+ * The `delete` operation creates an explicit tombstone entry so concurrent
26
+ * updates/replay do not resurrect deleted values.
27
+ */
28
+ export type MemoryOperation =
29
+ | 'remember'
30
+ | 'update'
31
+ | 'forget'
32
+ | 'expire'
33
+ | 'confirm'
34
+ | 'supersede'
35
+ | 'delete'
36
+ | 'patch'
37
+
38
+ /**
39
+ * Synchronization state of a journal entry against a remote/cloud backend.
40
+ */
41
+ export type MemorySync = 'pending' | 'synced' | 'conflict' | 'error'
42
+
43
+ export type SyncDirection = 'up' | 'down' | 'both'
44
+
45
+ /**
46
+ * Pluggable cloud/sync transport. Memorio never ships a credential flow:
47
+ * the application supplies a `provider` that knows how to talk to its backend
48
+ * (REST, WebSocket, Supabase, a custom agent server, ...). Memorio owns the
49
+ * local journal, the provider only moves operations.
50
+ */
51
+ export interface SyncProvider {
52
+ /** Pushes pending local operations; returns ids that were accepted */
53
+ push(ops: MemoryEntry[]): Promise<{ synced: string[]; conflicts?: string[]; error?: string }>
54
+ /** Optional pull of remote operations newer than `since` (epoch ms) */
55
+ pull?(since?: number): Promise<MemoryEntry[]>
56
+ /**
57
+ * Optional conflict resolution for concurrent writes on the same path.
58
+ * Receives the local and remote entries; return 'local', 'remote', or 'merge'.
59
+ * Uses HLC timestamps for causal comparison when available.
60
+ */
61
+ resolve?(op: MemoryEntry): Promise<'local' | 'remote' | 'merge'>
62
+ /**
63
+ * Optional conflict resolver with HLC context. Called when two devices
64
+ * wrote concurrently to the same key/path. Implementations can use
65
+ * `local.hlc` and `remote.hlc` for causal determination.
66
+ */
67
+ resolveConflict?(local: MemoryEntry, remote: MemoryEntry): Promise<'local' | 'remote' | 'merge'>
68
+ }
69
+
70
+ export interface SyncConfig {
71
+ /** Sync provider implementation (application supplied) */
72
+ provider?: SyncProvider
73
+ /** Which direction to sync; 'both' is the default */
74
+ direction?: SyncDirection
75
+ /** Auto-sync on every local write? defaults to true */
76
+ auto?: boolean
77
+ }
78
+
79
+ export interface SyncAck {
80
+ synced: string[]
81
+ conflicts?: string[]
82
+ error?: string
83
+ resolved?: { id: string; resolution: 'local' | 'remote' | 'merge' }[]
84
+ }
85
+
12
86
  export interface MemoryEntry<T = any> {
13
87
  id: string
14
88
  key: string
@@ -23,6 +97,27 @@ export interface MemoryEntry<T = any> {
23
97
  createdAt: number
24
98
  lastConfirmedAt: number
25
99
  supersededId?: string | null
100
+ /** Monotonic per-key write counter, used for last-writer / conflict resolution */
101
+ version?: number
102
+ /** Epoch ms of the last mutation that touched this entry */
103
+ updatedAt?: number
104
+ /** Last logical operation that produced this entry */
105
+ operation?: MemoryOperation
106
+ /** Local-cloud sync state of the entry (undefined => not tracked for sync) */
107
+ sync?: MemorySync
108
+ /**
109
+ * Hybrid Logical Clock timestamp for causal ordering across devices.
110
+ * Replaces wall-clock-only ordering which is vulnerable to clock drift.
111
+ */
112
+ hlc?: string
113
+ /**
114
+ * Field-level path for path-level journaling (e.g. "user.role").
115
+ * When set, the journal entry represents a patch to a sub-path
116
+ * rather than a full entity replacement.
117
+ */
118
+ path?: string
119
+ /** Array of JSON Patch-style operations for compound path-level mutations. */
120
+ patches?: PatchOperation[]
26
121
  }
27
122
 
28
123
  export interface RememberOptions<T = any> {
package/types/schema.d.ts CHANGED
@@ -1,53 +1,53 @@
1
- /// MEMORIO SCHEMA TYPES
2
- /// Ambient declarations for the schema validation system.
3
-
4
- ///
5
- // Schema type โ€” describes the expected runtime shape of a value.
6
- ///
7
- interface _schemaDef {
8
- /** Expected runtime type of the value. */
9
- type?: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'any'
10
- /** Required property names when type is 'object'. */
11
- required?: string[]
12
- /** Nested property schemas (validated recursively). */
13
- properties?: Record<string, _schemaDef>
14
- /** Minimum: value for numbers, length for strings. */
15
- min?: number
16
- /** Maximum: value for numbers, length for strings. */
17
- max?: number
18
- /** Regex pattern a string value must match. */
19
- pattern?: RegExp
20
- /** Whitelist of allowed values. */
21
- enum?: any[]
22
- /** Custom validator: return true for pass, or a string describing the error. */
23
- validator?: (value: any) => boolean | string
24
- }
25
-
26
- ///
27
- // Result of a validation check.
28
- ///
29
- interface _validationResult {
30
- /** Whether the value passed all checks. */
31
- valid: boolean
32
- /** Array of human-readable error strings (present when valid is false). */
33
- errors?: string[]
34
- }
35
-
36
- ///
37
- // Schema namespace โ€” the public `memorio.schema`-style helpers live on `memorio`.
38
- ///
39
- interface _schemaHelpers {
40
- /** Registers a schema (or custom validator) for a state path. */
41
- register: (path: string, schema: _schemaDef | ((value: any) => boolean | string)) => void
42
- /** Validates a value against a registered schema. */
43
- validate: (path: string, value: any) => _validationResult
44
- /** Removes a previously registered schema. */
45
- unregister: (path: string) => boolean
46
- /** Lists all registered schema paths. */
47
- list: () => string[]
48
- /** Retrieves the schema registered for a path. */
49
- get: (path: string) => _schemaDef | undefined
50
- }
51
-
52
- declare var _schemaDef: _schemaDef
53
- declare var _validationResult: _validationResult
1
+ /// MEMORIO SCHEMA TYPES
2
+ /// Ambient declarations for the schema validation system.
3
+
4
+ ///
5
+ // Schema type - describes the expected runtime shape of a value.
6
+ ///
7
+ interface _schemaDef {
8
+ /** Expected runtime type of the value. */
9
+ type?: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'any'
10
+ /** Required property names when type is 'object'. */
11
+ required?: string[]
12
+ /** Nested property schemas (validated recursively). */
13
+ properties?: Record<string, _schemaDef>
14
+ /** Minimum: value for numbers, length for strings. */
15
+ min?: number
16
+ /** Maximum: value for numbers, length for strings. */
17
+ max?: number
18
+ /** Regex pattern a string value must match. */
19
+ pattern?: RegExp
20
+ /** Whitelist of allowed values. */
21
+ enum?: any[]
22
+ /** Custom validator: return true for pass, or a string describing the error. */
23
+ validator?: (value: any) => boolean | string
24
+ }
25
+
26
+ ///
27
+ // Result of a validation check.
28
+ ///
29
+ interface _validationResult {
30
+ /** Whether the value passed all checks. */
31
+ valid: boolean
32
+ /** Array of human-readable error strings (present when valid is false). */
33
+ errors?: string[]
34
+ }
35
+
36
+ ///
37
+ // Schema namespace - the public `memorio.schema`-style helpers live on `memorio`.
38
+ ///
39
+ interface _schemaHelpers {
40
+ /** Registers a schema (or custom validator) for a state path. */
41
+ register: (path: string, schema: _schemaDef | ((value: any) => boolean | string)) => void
42
+ /** Validates a value against a registered schema. */
43
+ validate: (path: string, value: any) => _validationResult
44
+ /** Removes a previously registered schema. */
45
+ unregister: (path: string) => boolean
46
+ /** Lists all registered schema paths. */
47
+ list: () => string[]
48
+ /** Retrieves the schema registered for a path. */
49
+ get: (path: string) => _schemaDef | undefined
50
+ }
51
+
52
+ declare var _schemaDef: _schemaDef
53
+ declare var _validationResult: _validationResult
@@ -0,0 +1,35 @@
1
+ /*!
2
+ memorio
3
+ Copyright (c) 2019 Dario Passariello <dariopassariello@gmail.com>
4
+ Licensed under MIT License, see
5
+ dario.passariello.ca
6
+ */
7
+
8
+ /**
9
+ * Memorio SQLite module.
10
+ *
11
+ * Backed by the optional `sql.js` package (SQLite compiled to WebAssembly).
12
+ * Lazily loaded in the browser; disabled in non-browser environments.
13
+ */
14
+ interface _sqlite {
15
+ /** Database connection tools (create, get, delete, list, size, export, import). */
16
+ db: any
17
+ /** SQL execution tools (run, select). */
18
+ query: any
19
+ /** CRUD shortcut helpers (set, get). */
20
+ data: any
21
+ /** Lazy-load / configure the sql.js engine (wasm loader, locateFile, etc.). */
22
+ config: (opts: any) => any
23
+ /** Promise that resolves once the sql.js engine has been initialized. */
24
+ ready: Promise<void> | null
25
+ /** True when running outside a supported browser environment. */
26
+ _disabled?: boolean
27
+ /** Human readable reason the module is disabled, when applicable. */
28
+ _warning?: string
29
+ [key: string]: any
30
+ }
31
+
32
+ declare var sqlite: _sqlite
33
+ type sqlite = _sqlite
34
+
35
+ declare var sqlbases: any[]
package/markdown/CACHE.md DELETED
@@ -1,90 +0,0 @@
1
- # Cache - Memorio
2
-
3
- > โœ… **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
4
-
5
- Cache provides in-memory storage with a simple API. Data is lost on page refresh or process restart.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install memorio
11
- ```
12
-
13
- ```javascript
14
- import 'memorio';
15
- ```
16
-
17
- ---
18
-
19
- ## Quick Examples
20
-
21
- ### Example 1: Basic Usage
22
-
23
- ```javascript
24
- // Save data
25
- cache.set('username', 'Mario');
26
- cache.set('score', 1500);
27
-
28
- // Read data
29
- console.debug(cache.get('username')); // "Mario"
30
- console.debug(cache.get('score')); // 1500
31
- ```
32
-
33
- ### Example 2: Intermediate
34
-
35
- ```javascript
36
- // Store objects
37
- cache.set('user', { name: 'Luigi', level: 5 });
38
- const user = cache.get('user');
39
- console.debug(user.name); // "Luigi"
40
-
41
- // Remove single item
42
- cache.remove('username');
43
-
44
- // Clear all cache
45
- cache.removeAll();
46
- ```
47
-
48
- ---
49
-
50
- ## API Reference
51
-
52
- ### Methods
53
-
54
- | Method | Parameters | Returns | Description |
55
- |--------|------------|---------|-------------|
56
- | `cache.get(name)` | `name: string` | `any` | Get value from cache |
57
- | `cache.set(name, value)` | `name: string, value: any` | `void` | Save value to cache |
58
- | `cache.remove(name)` | `name: string` | `boolean` | Remove single item |
59
- | `cache.removeAll()` | `none` | `boolean` | Clear all cache |
60
-
61
- ---
62
-
63
- ## Storage Comparison
64
-
65
- | Feature | Cache | Store | Session | IDB |
66
- |---------|-------|-------|---------|-----|
67
- | Platform Support | All (universal) | Browser/Edge | Browser/Edge | Browser only |
68
- | Lifetime | Until refresh | Forever | Until tab closes | Forever |
69
- | Capacity | Unlimited | ~5-10 MB | ~5-10 MB | 50+ MB |
70
- | Use case | Temporary data | User preferences | Auth tokens | Large data |
71
-
72
- ---
73
-
74
- ## Platform Support
75
-
76
- | Platform | Support | Notes |
77
- |----------|---------|-------|
78
- | Browser | โœ… Full | In-memory, lost on refresh |
79
- | Node.js | โœ… Full | In-memory, lost on restart |
80
- | Deno | โœ… Full | In-memory, lost on restart |
81
- | Edge Workers | โœ… Full | In-memory, lost on function cold start |
82
-
83
- ---
84
-
85
- ## Best Practices
86
-
87
- 1. Use for temporary data that doesn't need persistence
88
- 2. Great for computed values or API response caching
89
- 3. Data is lost on page refresh - don't use for important data
90
- 4. Clear with `cache.removeAll()` when no longer needed
@@ -1,161 +0,0 @@
1
- # Changelog - Memorio
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- ---
6
-
7
- ## v4.6.1 (Security Patch) - 2026-08-14 - CRITICAL Security Fix
8
-
9
- ### ๐Ÿ” Security NOTICE (v4.6.0)
10
-
11
- **CRITICAL**: A Gitea Personal Access Token was accidentally committed to `.npmrc` in v4.6.0
12
-
13
- **Affected**: `v4.6.0` tag and all builds from that version
14
-
15
- **Action Required**:
16
- - **IMMEDIATE**: Revoke ALL tokens on Gitea Packages by admin access
17
- - **GENERATE**: Create new PAT with scope `write:package` only
18
- - **CONFIGURE**: Add as secret `PAT` in GitHub Actions or Gitea Actions
19
- - **UPGRADE**: Use v4.6.1 where the token is replaced with `${PAT}` environment variable
20
-
21
- The hardcoded token `2f398d5d7a734781e96108fdd0dbbabad41ef77a` has been removed in v4.6.1.
22
-
23
- ### ๐Ÿ› Bug Fixes
24
-
25
- - **SECURITY**: Removed hardcoded Gitea PAT from `.npmrc` (exposed token remediated)
26
- - Replaced with environment variable `${PAT}` for secure authentication
27
-
28
- ### ๐Ÿ“ Documentation Updates
29
-
30
- - `.npmrc`: Token replaced with environment variable reference
31
- - `.gitea/workflows/npm.yml`: Configured to use secrets `GITEA_USER` and `PAT`
32
-
33
- ---
34
-
35
- ## v4.6.0 (Previous - SECURITY ISSUE) - 2026-08-13 - Refactoring & Documentation
36
-
37
- **โš ๏ธ WARNING**: This version had a hardcoded PAT token that was later remediated in v4.6.1**
38
-
39
- ### ๐Ÿ› Bug Fixes
40
-
41
- - Fixed circular import in `idb/index.ts` โ†’ `core/global`
42
- - Fixed dead `globalThis._propertyAccessLog` reference in `observer`
43
- - Fixed `dispatch.remove(f)` tuple bug in `functions/dispatch.ts`
44
- - Fixed `logger.isDebugEnabled` using wrong module reference
45
- - Removed dead `propertyAccessLog` / `pushPropertyAccess` from `core/internal.ts`
46
- - Removed duplicate path-tracking block in `state` get handler
47
- - Removed redundant `?? key` fallback in `state` set handler
48
-
49
- ### ๐Ÿ”ง Code Refactoring
50
-
51
- - **Self-contained modules**: All modules now work independently without internal `globalThis.memorio.*` reads/writes
52
- - **Module-local state**: Created `core/internal.ts` for module-local singletons
53
- - **Bootstrap-only global**: `core/global.ts` now only publishes to `globalThis.memorio` at initialization
54
- - **Removed dead code**: `core/constructor.ts` deleted (unused)
55
- - **Extracted helpers**: `_read`/`_write`/`_remove` in `store` and `session` to eliminate duplication
56
- - **Fixed circular imports**: `dispatch` โ†’ `observer` via `globalThis.events`
57
-
58
- ### ๐Ÿ“ Documentation Updates
59
-
60
- - `docs/README.md`: Added Classic `import { state } from 'memorio'` section, improved badges layout, enhanced "Why memorio?" comparison table
61
- - `docs/markdown/STORE.md`: Added classic import note
62
- - `docs/markdown/IMPORT.md`: New file for named export guide
63
- - `docs/SUMMARY.md`: Updated to include `IMPORT.md`
64
- - `README.md`: Badge corrections, header cleanup, removed unverified bundle size claims
65
-
66
- ### ๐Ÿ†• GitHub Actions / Gitea Workflows
67
-
68
- - Added `.gitea/workflows/npm.yml` for automatic npm package publishing to Gitea Packages on `v*` tags
69
- - Requires `GITEA_USER` and `PAT` secrets
70
-
71
- ### ๐Ÿงช Tests
72
-
73
- - **Result: 9 suites ยท 101 passed ยท 4 skipped ยท 1 todo**
74
- - All lint and typecheck clean
75
-
76
- ---
77
-
78
- ## v3.0.2 (Current) - 2026-05-19 - Bug Fix, Security & API Expansion
79
-
80
- ### ๐Ÿ› Bug Fixes
81
-
82
- - Removed dead code: `buildPathTracker` from `functions/state/index.ts` (unused Proxy builder, exported nowhere)
83
- - Removed double `delete` in state `removeAll` handler (redundant null-check + delete on same key)
84
- - Removed unbound `globalThis.state` reference in state init (would throw `ReferenceError` in strict mode)
85
- - Removed `Object.freeze(observer)` referencing undeclared variable (`ReferenceError` on module load)
86
- - Removed `confirm()` synchronous blocking call from `idb.db.delete` (library must not block main thread)
87
-
88
- ### ๐Ÿ”’ Security Improvements
89
-
90
- - Removed `esbuild-sass-plugin` and `esbuild-scss-modules-plugin` from `devDependencies` (unnecessary for a library with no styles)
91
- - Removed `injectStyle: true`, `sassPlugin()` and `.css` loader from `tsup.config.ts`
92
- - Deleted `tsup.plugin.injectCss.ts` (code injection vector completely removed from build pipeline)
93
- - `console.error`/`console.warn` โ†’ `console.debug` in `devtools` and `idb` error handlers (consistent debug-only logging policy)
94
- - `store.set()` now blocks function values instead of silently logging and continuing
95
- - All `PRIVATE License` headers in `functions/idb/` replaced with `MIT License`
96
-
97
- ### ๐Ÿ”ง Code Quality
98
-
99
- - Added JSDoc to `observerFunction` in `functions/observer/index.ts`
100
- - Added JSDoc to `cache` global in `functions/cache/index.ts`
101
- - `lint` and `tsc` pass clean - 0 vulnerabilities from `npm audit`
102
-
103
- ### ๐Ÿ†• API - New in 3.0.2
104
-
105
- | Function | Description |
106
- |----------|-------------|
107
- | `memorio.isBrowser()` | Returns `true` when running in a browser |
108
- | `memorio.isNode()` | Returns `true` when running in Node.js |
109
- | `memorio.isDeno()` | Returns `true` when running in Deno |
110
- | `memorio.isEdge()` | Returns `true` in Cloudflare Workers, Vercel Edge, etc. |
111
- | `memorio.getCapabilities()` | Full capabilities object (`platform`, `hasLocalStorage`, `hasIndexedDB`, โ€ฆ) |
112
- | `memorio.createContext(name?)` | Create multi-tenant isolated context |
113
- | `memorio.listContexts()` | List all active isolated contexts |
114
- | `memorio.deleteContext(id)` | Delete isolated context by ID |
115
- | `memorio.isolate(name?)` | Shorthand alias for `createContext` |
116
-
117
- ### ๐Ÿงช Tests
118
- - **Result: 8 suites ยท 95 passed ยท 3 skipped ยท 0 failed**
119
-
120
- ### ๐Ÿ—‘๏ธ Dependency Changes
121
-
122
- | Removed | Reason |
123
- |---------|--------|
124
- | `esbuild-sass-plugin@3.7.0` | No SCSS in a library |
125
- | `esbuild-scss-modules-plugin@1.1.1` | No SCSS in a library |
126
- | 36 transitive packages | Removed from `node_modules` |
127
-
128
- ### ๐Ÿ“ Documentation Updates
129
-
130
- - `docs/README.md`: replaced `console.debug` with `console.debug` in usage examples; fixed `esbuild` badge โ†’ `tsup`
131
- - `.github/CHANGELOG.md`: restructured with fix / security / changed sections
132
- - `.github/HISTORY.md`: complete rewrite through v3.0.2
133
- - `.github/SECURITY.md`: NIST/NSA standard + OWASP Top 10 mapping
134
- - `.github/CITATION.cff`: license PRIVATE โ†’ MIT to match `package.json`
135
- - `.project/*`: all context documents updated to v3.0.2
136
-
137
- ---
138
-
139
- ## v2.9.0 - 2026-05-13
140
-
141
- ### Added
142
- - DevTools - `memorio.devtools.inspect()`, `stats()`, `exportData()`
143
- - Logger with full history, stats and export
144
- - Platform detection (`isBrowser`, `isNode`, `isDeno`, `isEdge`, `getCapabilities`)
145
- - Session isolation via `crypto.randomUUID()`
146
-
147
- ### Changed
148
- - Updated dependencies to latest versions
149
- - Improved cross-platform support (Deno, Edge Workers, Node.js)
150
-
151
- ### Security
152
- - Secure random session IDs replaced `Math.random()`
153
- - Key validation (max 512 chars + character whitelist)
154
-
155
- ---
156
-
157
- ## v2.5.0 - 2026-02-17
158
-
159
- - Initial release of memorio (state, store, session, cache, idb)
160
- - Observer pattern (`observer`)
161
- - `useObserver` React hook