memorio 2.6.6 → 2.7.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.
package/README.md CHANGED
@@ -39,6 +39,8 @@
39
39
  - [Testing](#testing)
40
40
  - [Security](#security)
41
41
  - [License](#license)
42
+ - [Cross-Platform Support](#cross-platform-support)
43
+ - [Platform & Context Isolation](docs/markdown/PLATFORM.md)
42
44
 
43
45
  ## Features
44
46
 
@@ -48,6 +50,9 @@
48
50
  - Type-safe with full TypeScript support
49
51
  - Comprehensive test coverage
50
52
  - Easy debugging with proxy-based state
53
+ - **Cross-platform**: Works in Browser, Node.js, Deno, and Edge Workers
54
+ - **Session Isolation**: Each session/request gets isolated state namespace
55
+ - **Context System**: Multi-tenant server-side isolation with `memorio.createContext()`
51
56
 
52
57
  ## ⚠️ Enterprise Use
53
58
 
@@ -311,3 +316,100 @@ Security scans and reports are available at:
311
316
  MIT License
312
317
 
313
318
  Copyrigth (c) [Dario Passariello](https://dario.passariello.ca/)
319
+
320
+ ---
321
+
322
+ ## Cross-Platform Support
323
+
324
+ Memorio is designed to work across multiple JavaScript environments:
325
+
326
+ ### Platform Compatibility
327
+
328
+ | Feature | Browser | Node.js | Deno | Edge Workers |
329
+ |---------|---------|---------|------|---------------|
330
+ | `state` | ✅ | ✅ | ✅ | ✅ |
331
+ | `observer` | ✅ | ✅ | ✅ | ✅ |
332
+ | `useObserver` | ✅ | ⚠️ | ⚠️ | ✅ |
333
+ | `cache` | ✅ | ✅ | ✅ | ✅ |
334
+ | `store` | ✅ (localStorage) | ⚠️ (memory) | ⚠️ (memory) | ✅ (localStorage) |
335
+ | `session` | ✅ (sessionStorage) | ⚠️ (memory) | ⚠️ (memory) | ✅ (sessionStorage) |
336
+ | `idb` | ✅ | ❌ | ❌ | ⚠️ |
337
+
338
+ - ✅ Full support
339
+ - ⚠️ Partial support (fallback to in-memory)
340
+ - ❌ Not available
341
+
342
+ ### Session Isolation
343
+
344
+ Memorio provides automatic session isolation to prevent state leakage between different requests or contexts:
345
+
346
+ - **Unique Session IDs**: Each import gets a unique session identifier
347
+ - **Namespaced Storage**: `store` and `session` keys are prefixed with session ID
348
+ - **State Isolation**: `state` is isolated per-instance
349
+
350
+ This ensures that in server-side environments (Node.js/Deno), different requests don't share state data.
351
+
352
+ ### Best Practices
353
+
354
+ 1. **For Client-Side**: Use all features freely - store, session, idb work with real browser storage
355
+ 2. **For Server-Side**: Use `state` and `cache` for in-memory data; store/session fall back to memory
356
+ 3. **For Edge Workers**: Same as browser; localStorage/sessionStorage available
357
+
358
+ ### Checking Platform
359
+
360
+ ```javascript
361
+ // Platform detection is available via the internal module
362
+ // Note: Public API coming in future versions
363
+ ```
364
+
365
+ ---
366
+
367
+ ## Cross-Platform Support
368
+
369
+ Memorio is designed to work across multiple JavaScript environments:
370
+
371
+ ### Platform Compatibility
372
+
373
+ | Feature | Browser | Node.js | Deno | Edge Workers |
374
+ |---------|---------|---------|------|---------------|
375
+ | `state` | ✅ | ✅ | ✅ | ✅ |
376
+ | `observer` | ✅ | ✅ | ✅ | ✅ |
377
+ | `useObserver` | ✅ | ⚠️ | ⚠️ | ✅ |
378
+ | `cache` | ✅ | ✅ | ✅ | ✅ |
379
+ | `store` | ✅ (localStorage) | ⚠️ (memory) | ⚠️ (memory) | ✅ (localStorage) |
380
+ | `session` | ✅ (sessionStorage) | ⚠️ (memory) | ⚠️ (memory) | ✅ (sessionStorage) |
381
+ | `idb` | ✅ | ❌ | ❌ | ⚠️ |
382
+
383
+ - ✅ Full support
384
+ - ⚠️ Partial support (fallback to in-memory)
385
+ - ❌ Not available
386
+
387
+ ### Session Isolation
388
+
389
+ Memorio provides automatic session isolation to prevent state leakage between different requests or contexts:
390
+
391
+ - **Unique Session IDs**: Each import gets a unique session identifier
392
+ - **Namespaced Storage**: `store` and `session` keys are prefixed with session ID
393
+ - **State Isolation**: `state` is isolated per-instance
394
+
395
+ This ensures that in server-side environments (Node.js/Deno), different requests don't share state data.
396
+
397
+ ### Best Practices
398
+
399
+ 1. **For Client-Side**: Use all features freely - store, session, idb work with real browser storage
400
+ 2. **For Server-Side**: Use `state` and `cache` for in-memory data; store/session fall back to memory
401
+ 3. **For Edge Workers**: Same as browser; localStorage/sessionStorage available
402
+
403
+ ### Checking Platform
404
+
405
+ ```javascript
406
+ import { isBrowser, isNode, isDeno, getCapabilities } from 'memorio';
407
+
408
+ console.log('Browser:', isBrowser()); // true in browser
409
+ console.log('Node.js:', isNode()); // true in Node.js
410
+ console.log('Deno:', isDeno()); // true in Deno
411
+
412
+ const caps = getCapabilities();
413
+ console.log('Platform:', caps.platform); // 'browser' | 'node' | 'deno' | 'edge'
414
+ console.log('Persistent:', store.isPersistent); // true if using real storage
415
+ ```
package/examples/basic.ts CHANGED
@@ -5,16 +5,46 @@
5
5
  * - State management
6
6
  * - Store (localStorage)
7
7
  * - Session storage
8
+ * - Platform detection
8
9
  *
9
10
  * Run: npx ts-node examples/basic.ts
10
11
  */
11
12
 
12
13
  import '../index'
13
14
 
15
+ // ============================================
16
+ // PLATFORM DETECTION
17
+ // ============================================
18
+
19
+ console.log('=== Platform Detection ===')
20
+ console.log('Memorio version:', memorio.version)
21
+
22
+ // Check platform
23
+ if (memorio.isBrowser()) {
24
+ console.log('Platform: Browser')
25
+ } else if (memorio.isNode()) {
26
+ console.log('Platform: Node.js')
27
+ } else if (memorio.isDeno()) {
28
+ console.log('Platform: Deno')
29
+ } else if (memorio.isEdge()) {
30
+ console.log('Platform: Edge Worker')
31
+ }
32
+
33
+ // Get capabilities
34
+ const caps = memorio.getCapabilities()
35
+ console.log('Capabilities:', {
36
+ platform: caps.platform,
37
+ hasLocalStorage: caps.hasLocalStorage,
38
+ hasSessionStorage: caps.hasSessionStorage,
39
+ hasIndexedDB: caps.hasIndexedDB
40
+ })
41
+
14
42
  // ============================================
15
43
  // STATE - In-memory reactive state
16
44
  // ============================================
17
45
 
46
+ console.log('\n=== State Management ===')
47
+
18
48
  // Set some state values
19
49
  state.name = 'Mario'
20
50
  state.age = 30
@@ -36,6 +66,11 @@ console.log('All states:', state.list)
36
66
  // STORE - Persistent localStorage
37
67
  // ============================================
38
68
 
69
+ console.log('\n=== Store (Persistent Storage) ===')
70
+
71
+ // Check persistence
72
+ console.log('Is persistent:', store.isPersistent) // true in browser, false in Node.js/Deno
73
+
39
74
  // Save to localStorage
40
75
  store.set('username', 'mario')
41
76
  store.set('preferences', { theme: 'dark', language: 'en' })
@@ -52,6 +87,11 @@ console.log('Storage size:', store.size(), 'bytes')
52
87
  // SESSION - Temporary session storage
53
88
  // ============================================
54
89
 
90
+ console.log('\n=== Session (Temporary Storage) ===')
91
+
92
+ // Check persistence
93
+ console.log('Is persistent:', session.isPersistent) // true in browser, false in Node.js/Deno
94
+
55
95
  // Save session data (cleared when tab closes)
56
96
  session.set('token', 'abc123xyz')
57
97
  session.set('userId', 42)
@@ -72,4 +112,4 @@ session.remove('token')
72
112
  store.removeAll()
73
113
  session.removeAll()
74
114
 
75
- console.log('Example complete!')
115
+ console.log('\nExample complete!')
@@ -0,0 +1,358 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Memorio Vanilla JS Example</title>
8
+ <style>
9
+ /* Simple CSS */
10
+ body {
11
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
12
+ max-width: 800px;
13
+ margin: 0 auto;
14
+ padding: 20px;
15
+ background: #f5f5f5;
16
+ }
17
+
18
+ .card {
19
+ background: white;
20
+ border-radius: 8px;
21
+ padding: 20px;
22
+ margin-bottom: 20px;
23
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
24
+ }
25
+
26
+ h1 {
27
+ color: #333;
28
+ }
29
+
30
+ h2 {
31
+ color: #666;
32
+ margin-top: 0;
33
+ }
34
+
35
+ button {
36
+ background: #007bff;
37
+ color: white;
38
+ border: none;
39
+ padding: 10px 20px;
40
+ border-radius: 4px;
41
+ cursor: pointer;
42
+ margin: 5px;
43
+ }
44
+
45
+ button:hover {
46
+ background: #0056b3;
47
+ }
48
+
49
+ button.danger {
50
+ background: #dc3545;
51
+ }
52
+
53
+ button.danger:hover {
54
+ background: #c82333;
55
+ }
56
+
57
+ button.success {
58
+ background: #28a745;
59
+ }
60
+
61
+ button.success:hover {
62
+ background: #218838;
63
+ }
64
+
65
+ input,
66
+ select {
67
+ padding: 8px;
68
+ border: 1px solid #ddd;
69
+ border-radius: 4px;
70
+ margin: 5px;
71
+ }
72
+
73
+ pre {
74
+ background: #f8f9fa;
75
+ padding: 10px;
76
+ border-radius: 4px;
77
+ overflow-x: auto;
78
+ }
79
+
80
+ .output {
81
+ background: #e9ecef;
82
+ padding: 10px;
83
+ border-radius: 4px;
84
+ font-family: monospace;
85
+ white-space: pre-wrap;
86
+ }
87
+
88
+ .grid {
89
+ display: grid;
90
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
91
+ gap: 10px;
92
+ }
93
+
94
+ .stat {
95
+ background: #e7f3ff;
96
+ padding: 10px;
97
+ border-radius: 4px;
98
+ text-align: center;
99
+ }
100
+
101
+ .stat-value {
102
+ font-size: 24px;
103
+ font-weight: bold;
104
+ color: #007bff;
105
+ }
106
+
107
+ .stat-label {
108
+ font-size: 12px;
109
+ color: #666;
110
+ }
111
+ </style>
112
+ </head>
113
+
114
+ <body>
115
+ <h1>🧠 Memorio Vanilla JS Demo</h1>
116
+
117
+ <!-- State Section -->
118
+ <div class="card">
119
+ <h2>1. State (Reactive)</h2>
120
+ <p>Global reactive state - changes trigger UI updates automatically</p>
121
+
122
+ <div class="grid">
123
+ <div class="stat">
124
+ <div class="stat-value" id="counter">0</div>
125
+ <div class="stat-label">Counter</div>
126
+ </div>
127
+ <div class="stat">
128
+ <div class="stat-value" id="username">-</div>
129
+ <div class="stat-label">Username</div>
130
+ </div>
131
+ <div class="stat">
132
+ <div class="stat-value" id="theme">light</div>
133
+ <div class="stat-label">Theme</div>
134
+ </div>
135
+ </div>
136
+
137
+ <br>
138
+ <button onclick="state.counter++">Increment Counter</button>
139
+ <button onclick="state.counter--">Decrement</button>
140
+ <button onclick="state.counter = 0">Reset</button>
141
+
142
+ <h3>Set Username:</h3>
143
+ <input type="text" id="nameInput" placeholder="Enter name">
144
+ <button onclick="state.username = document.getElementById('nameInput').value">Set</button>
145
+
146
+ <h3>Theme:</h3>
147
+ <button onclick="state.theme = 'light'">Light</button>
148
+ <button onclick="state.theme = 'dark'">Dark</button>
149
+
150
+ <h3>All State:</h3>
151
+ <pre id="stateOutput" class="output"></pre>
152
+ </div>
153
+
154
+ <!-- Store Section -->
155
+ <div class="card">
156
+ <h2>2. Store (localStorage)</h2>
157
+ <p>Permanent storage - survives page refresh</p>
158
+ <p>Persistent: <span id="storePersistent">checking...</span></p>
159
+
160
+ <input type="text" id="storeKey" placeholder="Key">
161
+ <input type="text" id="storeValue" placeholder="Value">
162
+ <button
163
+ onclick="store.set(document.getElementById('storeKey').value, document.getElementById('storeValue').value)">Save</button>
164
+ <button
165
+ onclick="document.getElementById('storeOutput').textContent = JSON.stringify(store.get(document.getElementById('storeKey').value), null, 2)">Get</button>
166
+ <button class="danger" onclick="store.remove(document.getElementById('storeKey').value)">Delete</button>
167
+
168
+ <h3>All Store Data:</h3>
169
+ <pre id="storeOutput" class="output"></pre>
170
+ </div>
171
+
172
+ <!-- Session Section -->
173
+ <div class="card">
174
+ <h2>3. Session (sessionStorage)</h2>
175
+ <p>Temporary storage - cleared when tab closes</p>
176
+ <p>Persistent: <span id="sessionPersistent">checking...</span></p>
177
+
178
+ <input type="text" id="sessionKey" placeholder="Key">
179
+ <input type="text" id="sessionValue" placeholder="Value">
180
+ <button
181
+ onclick="session.set(document.getElementById('sessionKey').value, document.getElementById('sessionValue').value)">Save</button>
182
+ <button
183
+ onclick="document.getElementById('sessionOutput').textContent = JSON.stringify(session.get(document.getElementById('sessionKey').value), null, 2)">Get</button>
184
+ <button class="danger" onclick="session.remove(document.getElementById('sessionKey').value)">Delete</button>
185
+
186
+ <h3>All Session Data:</h3>
187
+ <pre id="sessionOutput" class="output"></pre>
188
+ </div>
189
+
190
+ <!-- Cache Section -->
191
+ <div class="card">
192
+ <h2>4. Cache (In-Memory)</h2>
193
+ <p>Temporary cache - cleared on refresh</p>
194
+
195
+ <input type="text" id="cacheKey" placeholder="Key">
196
+ <input type="text" id="cacheValue" placeholder="Value">
197
+ <button
198
+ onclick="cache.set(document.getElementById('cacheKey').value, document.getElementById('cacheValue').value)">Save</button>
199
+ <button
200
+ onclick="document.getElementById('cacheOutput').textContent = JSON.stringify(cache.get(document.getElementById('cacheKey').value), null, 2)">Get</button>
201
+ <button class="danger" onclick="cache.remove(document.getElementById('cacheKey').value)">Delete</button>
202
+
203
+ <h3>All Cache Data:</h3>
204
+ <pre id="cacheOutput" class="output"></pre>
205
+ </div>
206
+
207
+ <!-- Observer Section -->
208
+ <div class="card">
209
+ <h2>5. Observer (Auto-Reactive)</h2>
210
+ <p>Watch for state changes automatically</p>
211
+
212
+ <button class="success" id="startObserver">Start Observer</button>
213
+ <button class="danger" id="stopObserver">Stop Observer</button>
214
+ <button onclick="state.testValue = Math.random()">Trigger Change</button>
215
+
216
+ <h3>Observer Log:</h3>
217
+ <pre id="observerLog" class="output"></pre>
218
+ </div>
219
+
220
+ <!-- Platform Info -->
221
+ <div class="card">
222
+ <h2>6. Platform Info</h2>
223
+ <div id="platformInfo" class="output"></div>
224
+ </div>
225
+
226
+ <!-- Load Memorio -->
227
+ <script src="https://cdn.jsdelivr.net/npm/memorio/dist/index.cjs"></script>
228
+
229
+ <script>
230
+ // ============================================
231
+ // MEMORIO VANILLA JS EXAMPLE
232
+ // ============================================
233
+
234
+ // 1. REACTIVE STATE
235
+ // -----------------
236
+
237
+ // Initialize state
238
+ state.counter = 0
239
+ state.username = 'Guest'
240
+ state.theme = 'light'
241
+ state.testValue = 0
242
+
243
+ // Update UI when state changes
244
+ function updateStateUI() {
245
+ document.getElementById('counter').textContent = state.counter
246
+ document.getElementById('username').textContent = state.username
247
+ document.getElementById('theme').textContent = state.theme
248
+ document.getElementById('stateOutput').textContent = JSON.stringify({
249
+ counter: state.counter,
250
+ username: state.username,
251
+ theme: state.theme,
252
+ testValue: state.testValue
253
+ }, null, 2)
254
+ }
255
+
256
+ // Use observer to react to changes
257
+ useObserver(() => {
258
+ updateStateUI()
259
+ document.body.className = state.theme
260
+ }, [state.counter, state.username, state.theme, state.testValue])
261
+
262
+ // 2. PERSISTENT STORE
263
+ // -------------------
264
+
265
+ // Check persistence
266
+ document.getElementById('storePersistent').textContent = store.isPersistent ? '✅ Yes (localStorage)' : '❌ No (memory)'
267
+
268
+ // Save sample data
269
+ store.set('visits', '0')
270
+ store.set('lastVisit', new Date().toISOString())
271
+
272
+ function updateStoreUI() {
273
+ document.getElementById('storeOutput').textContent = 'Visits: ' + store.get('visits') + '\nLast Visit: ' + store.get('lastVisit')
274
+ }
275
+ updateStoreUI()
276
+
277
+ // Increment visits
278
+ let visits = parseInt(store.get('visits') || '0')
279
+ store.set('visits', (visits + 1).toString())
280
+
281
+ // 3. SESSION STORAGE
282
+ // ------------------
283
+
284
+ document.getElementById('sessionPersistent').textContent = session.isPersistent ? '✅ Yes (sessionStorage)' : '❌ No (memory)'
285
+
286
+ session.set('pageViews', '0')
287
+
288
+ function updateSessionUI() {
289
+ document.getElementById('sessionOutput').textContent = 'Page Views: ' + session.get('pageViews')
290
+ }
291
+ updateSessionUI()
292
+
293
+ // Increment page views
294
+ let pageViews = parseInt(session.get('pageViews') || '0')
295
+ session.set('pageViews', (pageViews + 1).toString())
296
+
297
+ // 4. CACHE (In-Memory)
298
+ // --------------------
299
+
300
+ cache.set('tempData', { computed: true, timestamp: Date.now() })
301
+
302
+ function updateCacheUI() {
303
+ document.getElementById('cacheOutput').textContent = JSON.stringify(cache.get('tempData'), null, 2)
304
+ }
305
+ updateCacheUI()
306
+
307
+ // 5. OBSERVER
308
+ // -----------
309
+
310
+ let observerActive = false
311
+ const logEl = document.getElementById('observerLog')
312
+
313
+ document.getElementById('startObserver').onclick = () => {
314
+ observerActive = true
315
+ logEl.textContent += 'Observer started!\n'
316
+ }
317
+
318
+ document.getElementById('stopObserver').onclick = () => {
319
+ observerActive = false
320
+ logEl.textContent += 'Observer stopped!\n'
321
+ }
322
+
323
+ // This creates a persistent observer
324
+ useObserver((newVal, oldVal) => {
325
+ if (observerActive) {
326
+ logEl.textContent += `Changed: ${oldVal} → ${newVal}\n`
327
+ logEl.scrollTop = logEl.scrollHeight
328
+ }
329
+ }, [state.testValue])
330
+
331
+ // 6. PLATFORM INFO
332
+ // ----------------
333
+
334
+ const platformInfo = document.getElementById('platformInfo')
335
+ platformInfo.textContent = `
336
+ Platform Detection:
337
+ -----------------
338
+ Browser: ${memorio.isBrowser() ? '✅' : '❌'}
339
+ Node.js: ${memorio.isNode() ? '✅' : '❌'}
340
+ Deno: ${memorio.isDeno() ? '✅' : '❌'}
341
+ Edge: ${memorio.isEdge() ? '✅' : '❌'}
342
+
343
+ Capabilities:
344
+ -------------
345
+ localStorage: ${memorio.getCapabilities().hasLocalStorage ? '✅' : '❌'}
346
+ sessionStorage: ${memorio.getCapabilities().hasSessionStorage ? '✅' : '❌'}
347
+ IndexedDB: ${memorio.getCapabilities().hasIndexedDB ? '✅' : '❌'}
348
+
349
+ Session ID: ${memorio.getCapabilities().sessionId.substring(0, 8)}...
350
+ `.trim()
351
+
352
+ // Log welcome
353
+ console.log('🧠 Memorio loaded!')
354
+ console.log('Platform:', memorio.getCapabilities().platform)
355
+ </script>
356
+ </body>
357
+
358
+ </html>