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 +102 -0
- package/examples/basic.ts +41 -1
- package/examples/browser-vanilla.html +358 -0
- package/examples/node-server.ts +308 -0
- package/examples/platform.ts +115 -0
- package/examples/react-app.tsx +357 -0
- package/examples/session-advanced.ts +13 -0
- package/examples/store-advanced.ts +13 -0
- package/index.cjs +331 -119
- package/index.js +331 -119
- package/package.json +17 -12
- package/types/memorio.d.ts +22 -0
- package/types/session.d.ts +7 -6
- package/types/state.d.ts +1 -6
- package/types/store.d.ts +6 -7
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memorio Node.js Server Example
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to use Memorio in a Node.js server environment.
|
|
5
|
+
* Includes context isolation for multi-tenant applications.
|
|
6
|
+
*
|
|
7
|
+
* Run: npx ts-node examples/node-server.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import '../index'
|
|
11
|
+
|
|
12
|
+
// ============================================
|
|
13
|
+
// 1. BASIC USAGE
|
|
14
|
+
// ============================================
|
|
15
|
+
|
|
16
|
+
console.log('=== 1. Basic Node.js Usage ===')
|
|
17
|
+
|
|
18
|
+
// Check platform
|
|
19
|
+
console.log('Platform:', memorio.isNode() ? 'Node.js ✅' : 'Other')
|
|
20
|
+
|
|
21
|
+
// Check persistence (false in Node.js - uses memory fallback)
|
|
22
|
+
console.log('Store persistent:', store.isPersistent) // false
|
|
23
|
+
console.log('Session persistent:', session.isPersistent) // false
|
|
24
|
+
|
|
25
|
+
// State works exactly like in browser
|
|
26
|
+
state.appName = 'My Server App'
|
|
27
|
+
state.startTime = Date.now()
|
|
28
|
+
state.config = {
|
|
29
|
+
port: 3000,
|
|
30
|
+
env: 'production'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log('App name:', state.appName)
|
|
34
|
+
console.log('Config:', state.config)
|
|
35
|
+
|
|
36
|
+
// ============================================
|
|
37
|
+
// 2. CACHE (In-Memory - Perfect for Server)
|
|
38
|
+
// ============================================
|
|
39
|
+
|
|
40
|
+
console.log('\n=== 2. Cache (In-Memory) ===')
|
|
41
|
+
|
|
42
|
+
// Cache is perfect for temporary server data
|
|
43
|
+
cache.set('apiResponse', { data: 'cached value' })
|
|
44
|
+
cache.set('userCount', 42)
|
|
45
|
+
|
|
46
|
+
console.log('Cached API response:', cache.get('apiResponse'))
|
|
47
|
+
console.log('User count:', cache.get('userCount'))
|
|
48
|
+
|
|
49
|
+
// Clear cache when needed
|
|
50
|
+
cache.remove('apiResponse')
|
|
51
|
+
// cache.clearAll() - clear all
|
|
52
|
+
|
|
53
|
+
// ============================================
|
|
54
|
+
// 3. STORE & SESSION (Memory Fallback in Node.js)
|
|
55
|
+
// ============================================
|
|
56
|
+
|
|
57
|
+
console.log('\n=== 3. Store & Session (Memory Fallback) ===')
|
|
58
|
+
|
|
59
|
+
// Store and session work but don't persist (no localStorage in Node.js)
|
|
60
|
+
store.set('serverConfig', { debug: true })
|
|
61
|
+
session.set('requestData', { path: '/api/users' })
|
|
62
|
+
|
|
63
|
+
console.log('Server config:', store.get('serverConfig'))
|
|
64
|
+
console.log('Request data:', session.get('requestData'))
|
|
65
|
+
|
|
66
|
+
// ⚠️ Data is lost on process restart!
|
|
67
|
+
// For persistence in Node.js, use a database
|
|
68
|
+
|
|
69
|
+
// ============================================
|
|
70
|
+
// 4. CONTEXT ISOLATION (Multi-Tenant)
|
|
71
|
+
// ============================================
|
|
72
|
+
|
|
73
|
+
console.log('\n=== 4. Context Isolation (Multi-Tenant) ===')
|
|
74
|
+
|
|
75
|
+
// Create isolated contexts for different tenants/requests
|
|
76
|
+
const userAContext = memorio.createContext('tenant-A')
|
|
77
|
+
const userBContext = memorio.createContext('tenant-B')
|
|
78
|
+
|
|
79
|
+
// Each context has completely separate data
|
|
80
|
+
userAContext.state.user = { name: 'Alice', id: 1 }
|
|
81
|
+
userAContext.state.secret = 'Alice secret data'
|
|
82
|
+
userAContext.cache.set('temp', 'A temp data')
|
|
83
|
+
|
|
84
|
+
userBContext.state.user = { name: 'Bob', id: 2 }
|
|
85
|
+
userBContext.state.secret = 'Bob secret data'
|
|
86
|
+
userBContext.cache.set('temp', 'B temp data')
|
|
87
|
+
|
|
88
|
+
// Verify isolation
|
|
89
|
+
console.log('User A name:', userAContext.state.user.name) // Alice
|
|
90
|
+
console.log('User B name:', userBContext.state.user.name) // Bob
|
|
91
|
+
|
|
92
|
+
// Global state is separate
|
|
93
|
+
console.log('Global state:', state.appName) // 'My Server App'
|
|
94
|
+
console.log('User A global secret:', userAContext.state.secret) // 'Alice secret data'
|
|
95
|
+
console.log('User B global secret:', userBContext.state.secret) // 'Bob secret data'
|
|
96
|
+
|
|
97
|
+
// ============================================
|
|
98
|
+
// 5. EXPRESS.JS MIDDLEWARE EXAMPLE
|
|
99
|
+
// ============================================
|
|
100
|
+
|
|
101
|
+
console.log('\n=== 5. Express.js Middleware Example ===')
|
|
102
|
+
|
|
103
|
+
/*
|
|
104
|
+
// In a real Express app:
|
|
105
|
+
|
|
106
|
+
import express from 'express'
|
|
107
|
+
const app = express()
|
|
108
|
+
|
|
109
|
+
// Middleware to create isolated context per request
|
|
110
|
+
app.use((req, res, next) => {
|
|
111
|
+
// Create unique context for this request
|
|
112
|
+
const ctx = memorio.createContext(`req-${req.id}`)
|
|
113
|
+
|
|
114
|
+
// Attach to request for use in handlers
|
|
115
|
+
req.memorio = ctx
|
|
116
|
+
|
|
117
|
+
// Clean up on response finish
|
|
118
|
+
res.on('finish', () => {
|
|
119
|
+
memorio.deleteContext(ctx.id)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
next()
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Route handler using isolated context
|
|
126
|
+
app.get('/api/user', (req, res) => {
|
|
127
|
+
const ctx = req.memorio
|
|
128
|
+
|
|
129
|
+
// Set request-specific state
|
|
130
|
+
ctx.state.requestId = req.id
|
|
131
|
+
ctx.state.startTime = Date.now()
|
|
132
|
+
|
|
133
|
+
// Cache data for this request
|
|
134
|
+
ctx.cache.set('query', req.query)
|
|
135
|
+
|
|
136
|
+
// Get user data
|
|
137
|
+
const user = getUserFromDB(req.params.id)
|
|
138
|
+
|
|
139
|
+
// Return response
|
|
140
|
+
res.json({
|
|
141
|
+
user,
|
|
142
|
+
requestId: ctx.state.requestId
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
app.listen(3000)
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
console.log('See code comments for Express.js integration')
|
|
150
|
+
|
|
151
|
+
// ============================================
|
|
152
|
+
// 6. WEBSOCKET EXAMPLE
|
|
153
|
+
// ============================================
|
|
154
|
+
|
|
155
|
+
console.log('\n=== 6. WebSocket Example ===')
|
|
156
|
+
|
|
157
|
+
/*
|
|
158
|
+
// For WebSocket connections:
|
|
159
|
+
|
|
160
|
+
const activeConnections = new Map()
|
|
161
|
+
|
|
162
|
+
function handleConnection(ws, userId) {
|
|
163
|
+
// Create isolated context for this user
|
|
164
|
+
const ctx = memorio.createContext(`ws-${userId}`)
|
|
165
|
+
|
|
166
|
+
// Store user data
|
|
167
|
+
ctx.state.userId = userId
|
|
168
|
+
ctx.state.connected = true
|
|
169
|
+
|
|
170
|
+
// Store in connection map
|
|
171
|
+
activeConnections.set(userId, ctx)
|
|
172
|
+
|
|
173
|
+
ws.on('message', (message) => {
|
|
174
|
+
// Process message using isolated context
|
|
175
|
+
ctx.cache.set('lastMessage', message)
|
|
176
|
+
handleMessage(ctx, message)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
ws.on('close', () => {
|
|
180
|
+
// Clean up
|
|
181
|
+
ctx.state.connected = false
|
|
182
|
+
activeConnections.delete(userId)
|
|
183
|
+
memorio.deleteContext(ctx.id)
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
console.log('See code comments for WebSocket integration')
|
|
189
|
+
|
|
190
|
+
// ============================================
|
|
191
|
+
// 7. JOB QUEUE / WORKER EXAMPLE
|
|
192
|
+
// ============================================
|
|
193
|
+
|
|
194
|
+
console.log('\n=== 7. Job Queue Example ===')
|
|
195
|
+
|
|
196
|
+
/*
|
|
197
|
+
// For background jobs:
|
|
198
|
+
|
|
199
|
+
async function processJob(jobId, jobData) {
|
|
200
|
+
// Create isolated context for this job
|
|
201
|
+
const ctx = memorio.createContext(`job-${jobId}`)
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
// Track job progress
|
|
205
|
+
ctx.state.jobId = jobId
|
|
206
|
+
ctx.state.status = 'processing'
|
|
207
|
+
ctx.state.progress = 0
|
|
208
|
+
|
|
209
|
+
// Process in stages
|
|
210
|
+
for (let i = 0; i < 10; i++) {
|
|
211
|
+
await doWork(jobData)
|
|
212
|
+
ctx.state.progress = (i + 1) * 10
|
|
213
|
+
|
|
214
|
+
// Cache intermediate results
|
|
215
|
+
ctx.cache.set(`stage-${i}`, true)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
ctx.state.status = 'completed'
|
|
219
|
+
return { success: true }
|
|
220
|
+
|
|
221
|
+
} catch (error) {
|
|
222
|
+
ctx.state.status = 'failed'
|
|
223
|
+
ctx.state.error = error.message
|
|
224
|
+
throw error
|
|
225
|
+
|
|
226
|
+
} finally {
|
|
227
|
+
// Clean up after job completes
|
|
228
|
+
memorio.deleteContext(ctx.id)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
console.log('See code comments for Job Queue integration')
|
|
234
|
+
|
|
235
|
+
// ============================================
|
|
236
|
+
// 8. CLI APPLICATION EXAMPLE
|
|
237
|
+
// ============================================
|
|
238
|
+
|
|
239
|
+
console.log('\n=== 8. CLI Application ===')
|
|
240
|
+
|
|
241
|
+
// Memorio works great in CLI apps too
|
|
242
|
+
state.command = 'build'
|
|
243
|
+
state.options = {
|
|
244
|
+
minify: true,
|
|
245
|
+
sourceMap: false
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
console.log('Command:', state.command)
|
|
249
|
+
console.log('Options:', state.options)
|
|
250
|
+
|
|
251
|
+
// ============================================
|
|
252
|
+
// 9. PLATFORM DETECTION
|
|
253
|
+
// ============================================
|
|
254
|
+
|
|
255
|
+
console.log('\n=== 9. Platform Detection ===')
|
|
256
|
+
|
|
257
|
+
const caps = memorio.getCapabilities()
|
|
258
|
+
console.log('Platform:', caps.platform)
|
|
259
|
+
console.log('localStorage:', caps.hasLocalStorage ? '✅' : '❌')
|
|
260
|
+
console.log('sessionStorage:', caps.hasSessionStorage ? '✅' : '❌')
|
|
261
|
+
console.log('IndexedDB:', caps.hasIndexedDB ? '✅' : '❌')
|
|
262
|
+
console.log('Session ID:', caps.sessionId.substring(0, 8) + '...')
|
|
263
|
+
|
|
264
|
+
// ============================================
|
|
265
|
+
// 10. CLEANUP
|
|
266
|
+
// ============================================
|
|
267
|
+
|
|
268
|
+
console.log('\n=== 10. Cleanup ===')
|
|
269
|
+
|
|
270
|
+
// List all contexts
|
|
271
|
+
console.log('Active contexts:', memorio.listContexts())
|
|
272
|
+
|
|
273
|
+
// Clean up when done
|
|
274
|
+
memorio.deleteContext('tenant-A')
|
|
275
|
+
memorio.deleteContext('tenant-B')
|
|
276
|
+
|
|
277
|
+
console.log('After cleanup:', memorio.listContexts())
|
|
278
|
+
|
|
279
|
+
// ============================================
|
|
280
|
+
// SUMMARY
|
|
281
|
+
// ============================================
|
|
282
|
+
|
|
283
|
+
console.log('\n=== Summary ===')
|
|
284
|
+
console.log(`
|
|
285
|
+
MEMORIO NODE.JS USAGE:
|
|
286
|
+
|
|
287
|
+
✅ WORKS:
|
|
288
|
+
- state: In-memory global state
|
|
289
|
+
- cache: In-memory temporary cache
|
|
290
|
+
- store: In-memory (NOT persistent!)
|
|
291
|
+
- session: In-memory (NOT persistent!)
|
|
292
|
+
- createContext: Perfect for isolation
|
|
293
|
+
|
|
294
|
+
⚠️ NOTES:
|
|
295
|
+
- store/session don't persist in Node.js
|
|
296
|
+
- Use database for persistence
|
|
297
|
+
- Always use contexts for request isolation
|
|
298
|
+
- Clean up contexts after use
|
|
299
|
+
|
|
300
|
+
🔧 BEST PRACTICES:
|
|
301
|
+
1. Create context per request: createContext(\`req-\${req.id}\`)
|
|
302
|
+
2. Use cache for temporary data
|
|
303
|
+
3. Use state for request-scoped data
|
|
304
|
+
4. Delete contexts after response
|
|
305
|
+
5. Check isPersistent before relying on persistence
|
|
306
|
+
`)
|
|
307
|
+
|
|
308
|
+
console.log('\nNode.js example complete!')
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memorio Platform & Context Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates:
|
|
5
|
+
* - Platform detection
|
|
6
|
+
* - Checking storage persistence
|
|
7
|
+
* - Context isolation for server-side multi-tenancy
|
|
8
|
+
*
|
|
9
|
+
* Run: npx ts-node examples/platform.ts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import '../index'
|
|
13
|
+
|
|
14
|
+
// ============================================
|
|
15
|
+
// PLATFORM DETECTION
|
|
16
|
+
// ============================================
|
|
17
|
+
|
|
18
|
+
console.log('=== Platform Detection ===')
|
|
19
|
+
console.log('Memorio version:', memorio.version)
|
|
20
|
+
|
|
21
|
+
// Check which platform we're on
|
|
22
|
+
if (memorio.isBrowser()) {
|
|
23
|
+
console.log('Running in: Browser')
|
|
24
|
+
console.log('store.isPersistent:', store.isPersistent) // true
|
|
25
|
+
console.log('session.isPersistent:', session.isPersistent) // true
|
|
26
|
+
} else if (memorio.isNode()) {
|
|
27
|
+
console.log('Running in: Node.js')
|
|
28
|
+
console.log('store.isPersistent:', store.isPersistent) // false (memory fallback)
|
|
29
|
+
console.log('session.isPersistent:', session.isPersistent) // false (memory fallback)
|
|
30
|
+
} else if (memorio.isDeno()) {
|
|
31
|
+
console.log('Running in: Deno')
|
|
32
|
+
console.log('store.isPersistent:', store.isPersistent) // false (memory fallback)
|
|
33
|
+
console.log('session.isPersistent:', session.isPersistent) // false (memory fallback)
|
|
34
|
+
} else if (memorio.isEdge()) {
|
|
35
|
+
console.log('Running in: Edge Worker')
|
|
36
|
+
console.log('store.isPersistent:', store.isPersistent) // true
|
|
37
|
+
console.log('session.isPersistent:', session.isPersistent) // true
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Get detailed capabilities
|
|
41
|
+
const caps = memorio.getCapabilities()
|
|
42
|
+
console.log('\nCapabilities:')
|
|
43
|
+
console.log(' Platform:', caps.platform)
|
|
44
|
+
console.log(' localStorage:', caps.hasLocalStorage ? '✅' : '❌')
|
|
45
|
+
console.log(' sessionStorage:', caps.hasSessionStorage ? '✅' : '❌')
|
|
46
|
+
console.log(' IndexedDB:', caps.hasIndexedDB ? '✅' : '❌')
|
|
47
|
+
console.log(' Session ID:', caps.sessionId)
|
|
48
|
+
|
|
49
|
+
// ============================================
|
|
50
|
+
// CONTEXT ISOLATION (Server-Side)
|
|
51
|
+
// ============================================
|
|
52
|
+
|
|
53
|
+
console.log('\n=== Context Isolation ===')
|
|
54
|
+
console.log('Use memorio.createContext() for multi-tenant server applications')
|
|
55
|
+
|
|
56
|
+
// Example: Simulating different users/requests
|
|
57
|
+
// In a real app, you'd create a context per HTTP request
|
|
58
|
+
|
|
59
|
+
// Create isolated context for User A
|
|
60
|
+
const userAContext = memorio.createContext('user-A')
|
|
61
|
+
userAContext.state.name = 'Mario'
|
|
62
|
+
userAContext.store.set('preferences', { theme: 'dark' })
|
|
63
|
+
userAContext.session.set('token', 'user-A-token')
|
|
64
|
+
|
|
65
|
+
// Create isolated context for User B
|
|
66
|
+
const userBContext = memorio.createContext('user-B')
|
|
67
|
+
userBContext.state.name = 'Luigi'
|
|
68
|
+
userBContext.store.set('preferences', { theme: 'light' })
|
|
69
|
+
userBContext.session.set('token', 'user-B-token')
|
|
70
|
+
|
|
71
|
+
// Verify isolation - each context has its own data
|
|
72
|
+
console.log('\nUser A context:')
|
|
73
|
+
console.log(' state.name:', userAContext.state.name) // 'Mario'
|
|
74
|
+
console.log(' store.preferences:', userAContext.store.get('preferences')) // { theme: 'dark' }
|
|
75
|
+
console.log(' session.token:', userAContext.session.get('token')) // 'user-A-token'
|
|
76
|
+
|
|
77
|
+
console.log('\nUser B context:')
|
|
78
|
+
console.log(' state.name:', userBContext.state.name) // 'Luigi'
|
|
79
|
+
console.log(' store.preferences:', userBContext.store.get('preferences')) // { theme: 'light' }
|
|
80
|
+
console.log(' session.token:', userBContext.session.get('token')) // 'user-B-token'
|
|
81
|
+
|
|
82
|
+
// Global state is separate from contexts
|
|
83
|
+
console.log('\nGlobal state (not affected by contexts):')
|
|
84
|
+
console.log(' state.name:', state.name) // undefined
|
|
85
|
+
|
|
86
|
+
// List all contexts
|
|
87
|
+
console.log('\nActive contexts:', memorio.listContexts()) // ['user-A', 'user-B']
|
|
88
|
+
|
|
89
|
+
// Cleanup - delete a context when done
|
|
90
|
+
memorio.deleteContext('user-A')
|
|
91
|
+
console.log('After deleting user-A:', memorio.listContexts()) // ['user-B']
|
|
92
|
+
|
|
93
|
+
// ============================================
|
|
94
|
+
// USE CASE: EXPRESS/FASTIFY MIDDLEWARE EXAMPLE
|
|
95
|
+
// ============================================
|
|
96
|
+
|
|
97
|
+
console.log('\n=== Server Use Case ===')
|
|
98
|
+
console.log(`
|
|
99
|
+
// Example: Express middleware for request isolation
|
|
100
|
+
app.use((req, res, next) => {
|
|
101
|
+
// Create isolated context per request
|
|
102
|
+
const ctx = memorio.createContext(\`req-\${req.id}\`)
|
|
103
|
+
req.memorio = ctx
|
|
104
|
+
next()
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// In your route handler:
|
|
108
|
+
app.get('/user', (req, res) => {
|
|
109
|
+
// This state is isolated per request
|
|
110
|
+
req.memorio.state.user = getUserData()
|
|
111
|
+
req.memorio.store.set('cache', data)
|
|
112
|
+
})
|
|
113
|
+
`)
|
|
114
|
+
|
|
115
|
+
console.log('\nPlatform & Context example complete!')
|