interaqt 0.3.0 → 0.3.1
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/agent/.claude/agents/code-generation-handler.md +2 -0
- package/agent/.claude/agents/computation-generation-handler.md +1 -0
- package/agent/.claude/agents/implement-design-handler.md +4 -13
- package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
- package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
- package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
- package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
- package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
- package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
- package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
- package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
- package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
- package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
- package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
- package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
- package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
- package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
- package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
- package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
- package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
- package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
- package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
- package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
- package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
- package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
- package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
- package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
- package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
- package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
- package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
- package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
- package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
- package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
- package/agent/agentspace/knowledge/usage/README.md +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
# 10. How to Use Global Dictionaries
|
|
2
|
+
|
|
3
|
+
Global dictionaries are an important mechanism in the interaqt framework for managing global state and configuration. They provide a declarative way to define and maintain system-level data that can be referenced and reacted to by other components throughout the application.
|
|
4
|
+
|
|
5
|
+
## 10.1 Understanding Dictionary Concepts
|
|
6
|
+
|
|
7
|
+
### 10.1.1 Global State Management
|
|
8
|
+
|
|
9
|
+
Global dictionaries provide a centralized state management solution:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Traditional global state management problems
|
|
13
|
+
let globalConfig = {
|
|
14
|
+
maxUsers: 1000,
|
|
15
|
+
maintenanceMode: false,
|
|
16
|
+
currentTheme: 'light'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Problem: Need to manually notify all dependents when state changes
|
|
20
|
+
function updateConfig(key: string, value: any) {
|
|
21
|
+
globalConfig[key] = value;
|
|
22
|
+
// Need to manually notify all dependent components ❌
|
|
23
|
+
notifyAllComponents();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Reactive solution using dictionaries
|
|
27
|
+
const maxUsersDict = Dictionary.create({
|
|
28
|
+
name: 'maxUsers',
|
|
29
|
+
type: 'number',
|
|
30
|
+
collection: false
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const maintenanceModeDict = Dictionary.create({
|
|
34
|
+
name: 'maintenanceMode',
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
collection: false
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// ✅ When dictionary values change, all dependent computations automatically update
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 10.1.2 Dictionary vs Entity
|
|
43
|
+
|
|
44
|
+
Main differences between dictionaries and entities:
|
|
45
|
+
|
|
46
|
+
| Feature | Dictionary | Entity |
|
|
47
|
+
|---------|------------|--------|
|
|
48
|
+
| **Scope** | Globally unique | Can have multiple instances |
|
|
49
|
+
| **Storage Location** | `state` table | Dedicated entity table |
|
|
50
|
+
| **Identification** | By name | By ID |
|
|
51
|
+
| **Relationship Support** | No relationships | Supports complex relationships |
|
|
52
|
+
| **Purpose** | Global config, statistics | Business data |
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Dictionary: Globally unique configuration
|
|
56
|
+
const systemConfig = Dictionary.create({
|
|
57
|
+
name: 'systemConfig',
|
|
58
|
+
type: 'object',
|
|
59
|
+
collection: false
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Entity: Can have multiple user instances
|
|
63
|
+
const userEntity = Entity.create({
|
|
64
|
+
name: 'User',
|
|
65
|
+
properties: [
|
|
66
|
+
Property.create({name: 'username', type: 'string'})
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 10.1.3 Use Cases
|
|
72
|
+
|
|
73
|
+
Global dictionaries are suitable for:
|
|
74
|
+
|
|
75
|
+
- **System Configuration**: Application settings, feature flags
|
|
76
|
+
- **Global Statistics**: Total users, total sales
|
|
77
|
+
- **Cached Data**: Frequently accessed computation results
|
|
78
|
+
- **Status Flags**: Maintenance mode, system status
|
|
79
|
+
- **External Data**: Local cache of third-party API data
|
|
80
|
+
|
|
81
|
+
## 10.2 Defining Dictionaries
|
|
82
|
+
|
|
83
|
+
### 10.2.1 Basic Dictionary Definition
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { Dictionary } from 'interaqt';
|
|
87
|
+
|
|
88
|
+
// Define system configuration dictionary
|
|
89
|
+
const systemConfig = Dictionary.create({
|
|
90
|
+
name: 'systemConfig', // Dictionary name, globally unique
|
|
91
|
+
type: 'object', // Data type
|
|
92
|
+
collection: false, // Whether it's a collection type
|
|
93
|
+
args: { // Type parameters (optional)
|
|
94
|
+
maxLength: 1000
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Define total user count statistics
|
|
99
|
+
const totalUsers = Dictionary.create({
|
|
100
|
+
name: 'totalUsers',
|
|
101
|
+
type: 'number',
|
|
102
|
+
collection: false
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Define system tags list
|
|
106
|
+
const systemTags = Dictionary.create({
|
|
107
|
+
name: 'systemTags',
|
|
108
|
+
type: 'string',
|
|
109
|
+
collection: true // Collection type, stores string array
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 10.2.2 Supported Data Types
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// String type
|
|
117
|
+
const appName = Dictionary.create({
|
|
118
|
+
name: 'appName',
|
|
119
|
+
type: 'string',
|
|
120
|
+
collection: false
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Number type
|
|
124
|
+
const version = Dictionary.create({
|
|
125
|
+
name: 'version',
|
|
126
|
+
type: 'number',
|
|
127
|
+
collection: false
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Boolean type
|
|
131
|
+
const isMaintenanceMode = Dictionary.create({
|
|
132
|
+
name: 'isMaintenanceMode',
|
|
133
|
+
type: 'boolean',
|
|
134
|
+
collection: false
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Object type
|
|
138
|
+
const appSettings = Dictionary.create({
|
|
139
|
+
name: 'appSettings',
|
|
140
|
+
type: 'object',
|
|
141
|
+
collection: false
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Collection type
|
|
145
|
+
const supportedLanguages = Dictionary.create({
|
|
146
|
+
name: 'supportedLanguages',
|
|
147
|
+
type: 'string',
|
|
148
|
+
collection: true
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const dailyStats = Dictionary.create({
|
|
152
|
+
name: 'dailyStats',
|
|
153
|
+
type: 'object',
|
|
154
|
+
collection: true
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 10.2.3 Dictionary Naming Conventions
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// ✅ Good naming examples
|
|
162
|
+
const userCount = Dictionary.create({
|
|
163
|
+
name: 'userCount', // Camel case
|
|
164
|
+
type: 'number',
|
|
165
|
+
collection: false
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const systemConfig = Dictionary.create({
|
|
169
|
+
name: 'sysConfig', // Concise and clear
|
|
170
|
+
type: 'object',
|
|
171
|
+
collection: false
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// ❌ Naming patterns to avoid
|
|
175
|
+
const dict1 = Dictionary.create({
|
|
176
|
+
name: 'dict1', // Unclear name
|
|
177
|
+
type: 'string',
|
|
178
|
+
collection: false
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const user_total_count = Dictionary.create({
|
|
182
|
+
name: 'user_total_count', // Using underscores (not recommended)
|
|
183
|
+
type: 'number',
|
|
184
|
+
collection: false
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## 10.3 Reactive Computations with Dictionaries
|
|
189
|
+
|
|
190
|
+
### 10.3.1 Global Statistics Based on Entities
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Create user entity
|
|
194
|
+
const userEntity = Entity.create({
|
|
195
|
+
name: 'User',
|
|
196
|
+
properties: [
|
|
197
|
+
Property.create({name: 'username', type: 'string'}),
|
|
198
|
+
Property.create({name: 'email', type: 'string'}),
|
|
199
|
+
Property.create({name: 'isActive', type: 'boolean'})
|
|
200
|
+
]
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Create total user count statistics dictionary
|
|
204
|
+
const totalUsers = Dictionary.create({
|
|
205
|
+
name: 'totalUsers',
|
|
206
|
+
type: 'number',
|
|
207
|
+
collection: false,
|
|
208
|
+
defaultValue: () => 0,
|
|
209
|
+
computation: Count.create({
|
|
210
|
+
record: userEntity
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Create active user count statistics dictionary
|
|
215
|
+
const activeUsers = Dictionary.create({
|
|
216
|
+
name: 'activeUsers',
|
|
217
|
+
type: 'number',
|
|
218
|
+
collection: false,
|
|
219
|
+
defaultValue: () => 0,
|
|
220
|
+
computation: Count.create({
|
|
221
|
+
record: userEntity
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Usage example
|
|
226
|
+
const controller = new Controller({
|
|
227
|
+
system,
|
|
228
|
+
entities: [userEntity], // Entities
|
|
229
|
+
relations: [], // Relations
|
|
230
|
+
activities: [], // Activities
|
|
231
|
+
interactions: [], // Interactions
|
|
232
|
+
dict: [totalUsers, activeUsers], // Dictionaries
|
|
233
|
+
recordMutationSideEffects: [] // recordMutationSideEffects
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await controller.setup(true);
|
|
237
|
+
|
|
238
|
+
// When creating users, statistics automatically update
|
|
239
|
+
await system.storage.create('User', {
|
|
240
|
+
username: 'alice',
|
|
241
|
+
email: 'alice@example.com',
|
|
242
|
+
isActive: true
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Get statistics results
|
|
246
|
+
const total = await system.storage.get('state', 'totalUsers');
|
|
247
|
+
const active = await system.storage.get('state', 'activeUsers');
|
|
248
|
+
console.log(`Total users: ${total}, Active users: ${active}`);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### 10.3.2 Global Statistics Based on Relations
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// Create friend relation
|
|
255
|
+
const friendRelation = Relation.create({
|
|
256
|
+
name: 'Friend',
|
|
257
|
+
source: userEntity,
|
|
258
|
+
sourceProperty: 'friends',
|
|
259
|
+
target: userEntity,
|
|
260
|
+
targetProperty: 'friendOf',
|
|
261
|
+
type: 'n:n',
|
|
262
|
+
properties: [
|
|
263
|
+
Property.create({name: 'since', type: 'string'}),
|
|
264
|
+
Property.create({name: 'closeness', type: 'number'})
|
|
265
|
+
]
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Count total friendships
|
|
269
|
+
const totalFriendships = Dictionary.create({
|
|
270
|
+
name: 'totalFriendships',
|
|
271
|
+
type: 'number',
|
|
272
|
+
collection: false,
|
|
273
|
+
defaultValue: () => 0,
|
|
274
|
+
computation: Count.create({
|
|
275
|
+
record: friendRelation
|
|
276
|
+
})
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Count close friendships (closeness > 8)
|
|
280
|
+
const closeFriendships = Dictionary.create({
|
|
281
|
+
name: 'closeFriendships',
|
|
282
|
+
type: 'number',
|
|
283
|
+
collection: false,
|
|
284
|
+
defaultValue: () => 0,
|
|
285
|
+
computation: Count.create({
|
|
286
|
+
record: friendRelation
|
|
287
|
+
})
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Calculate average closeness
|
|
291
|
+
const averageCloseness = Dictionary.create({
|
|
292
|
+
name: 'averageCloseness',
|
|
293
|
+
type: 'number',
|
|
294
|
+
collection: false,
|
|
295
|
+
defaultValue: () => 0,
|
|
296
|
+
computation: WeightedSummation.create({
|
|
297
|
+
record: friendRelation,
|
|
298
|
+
attributeQuery: ['closeness'],
|
|
299
|
+
callback: (friendship: any) => ({
|
|
300
|
+
weight: 1,
|
|
301
|
+
value: friendship.closeness || 0
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 10.3.3 Global Counting Based on Interactions
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
// Create login interaction
|
|
311
|
+
const loginInteraction = Interaction.create({
|
|
312
|
+
name: 'login',
|
|
313
|
+
action: Action.create({name: 'login'}),
|
|
314
|
+
payload: Payload.create({
|
|
315
|
+
items: [
|
|
316
|
+
PayloadItem.create({
|
|
317
|
+
name: 'user',
|
|
318
|
+
base: userEntity,
|
|
319
|
+
isRef: true
|
|
320
|
+
})
|
|
321
|
+
]
|
|
322
|
+
})
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Count total logins
|
|
326
|
+
const totalLogins = Dictionary.create({
|
|
327
|
+
name: 'totalLogins',
|
|
328
|
+
type: 'number',
|
|
329
|
+
collection: false,
|
|
330
|
+
defaultValue: () => 0,
|
|
331
|
+
computation: Count.create({
|
|
332
|
+
record: InteractionEventEntity
|
|
333
|
+
})
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Count today's logins
|
|
337
|
+
const todayLogins = Dictionary.create({
|
|
338
|
+
name: 'todayLogins',
|
|
339
|
+
type: 'number',
|
|
340
|
+
collection: false,
|
|
341
|
+
defaultValue: () => 0,
|
|
342
|
+
computation: Count.create({
|
|
343
|
+
record: InteractionEventEntity
|
|
344
|
+
})
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 10.3.4 Complex Global Computations
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// Create order entity
|
|
352
|
+
const orderEntity = Entity.create({
|
|
353
|
+
name: 'Order',
|
|
354
|
+
properties: [
|
|
355
|
+
Property.create({name: 'amount', type: 'number'}),
|
|
356
|
+
Property.create({name: 'status', type: 'string'}),
|
|
357
|
+
Property.create({name: 'createdAt', type: 'string'})
|
|
358
|
+
]
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Use Transform for complex global statistics
|
|
362
|
+
const salesSummary = Dictionary.create({
|
|
363
|
+
name: 'salesSummary',
|
|
364
|
+
type: 'object',
|
|
365
|
+
collection: false,
|
|
366
|
+
defaultValue: () => ({}),
|
|
367
|
+
computation: Transform.create({
|
|
368
|
+
record: orderEntity,
|
|
369
|
+
attributeQuery: ['amount', 'status', 'createdAt'],
|
|
370
|
+
callback: (orders: any[]) => {
|
|
371
|
+
const completed = orders.filter(order => order.status === 'completed');
|
|
372
|
+
const pending = orders.filter(order => order.status === 'pending');
|
|
373
|
+
|
|
374
|
+
const totalRevenue = completed.reduce((sum, order) => sum + order.amount, 0);
|
|
375
|
+
const averageOrderValue = completed.length > 0 ? totalRevenue / completed.length : 0;
|
|
376
|
+
|
|
377
|
+
// Calculate monthly statistics
|
|
378
|
+
const monthlyStats = {};
|
|
379
|
+
completed.forEach(order => {
|
|
380
|
+
const month = new Date(order.createdAt).toISOString().slice(0, 7); // YYYY-MM
|
|
381
|
+
if (!monthlyStats[month]) {
|
|
382
|
+
monthlyStats[month] = { count: 0, revenue: 0 };
|
|
383
|
+
}
|
|
384
|
+
monthlyStats[month].count++;
|
|
385
|
+
monthlyStats[month].revenue += order.amount;
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
totalOrders: orders.length,
|
|
390
|
+
completedOrders: completed.length,
|
|
391
|
+
pendingOrders: pending.length,
|
|
392
|
+
totalRevenue,
|
|
393
|
+
averageOrderValue,
|
|
394
|
+
monthlyStats,
|
|
395
|
+
lastUpdated: new Date().toISOString()
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
})
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## 10.4 Using Dictionaries in Business Logic
|
|
403
|
+
|
|
404
|
+
### 10.4.1 Reading Dictionary Values
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
// Basic reading
|
|
408
|
+
const userCount = await system.storage.get('state', 'totalUsers');
|
|
409
|
+
console.log(`Current user count: ${userCount}`);
|
|
410
|
+
|
|
411
|
+
// Reading object type dictionary
|
|
412
|
+
const salesSummary = await system.storage.get('state', 'salesSummary');
|
|
413
|
+
console.log(`Total revenue: ${salesSummary.totalRevenue}`);
|
|
414
|
+
console.log(`Average order value: ${salesSummary.averageOrderValue}`);
|
|
415
|
+
|
|
416
|
+
// Reading collection type dictionary
|
|
417
|
+
const supportedLanguages = await system.storage.get('state', 'supportedLanguages');
|
|
418
|
+
console.log(`Supported languages: ${supportedLanguages.join(', ')}`);
|
|
419
|
+
|
|
420
|
+
// Batch reading multiple dictionary values
|
|
421
|
+
async function getSystemStatus() {
|
|
422
|
+
const [userCount, activeUsers, maintenanceMode] = await Promise.all([
|
|
423
|
+
system.storage.get('state', 'totalUsers'),
|
|
424
|
+
system.storage.get('state', 'activeUsers'),
|
|
425
|
+
system.storage.get('state', 'maintenanceMode')
|
|
426
|
+
]);
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
userCount,
|
|
430
|
+
activeUsers,
|
|
431
|
+
maintenanceMode,
|
|
432
|
+
timestamp: Date.now()
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 10.4.2 Setting Dictionary Values
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
// Set simple values
|
|
441
|
+
await system.storage.set('state', 'maxUsers', 5000);
|
|
442
|
+
await system.storage.set('state', 'maintenanceMode', true);
|
|
443
|
+
|
|
444
|
+
// Set object values
|
|
445
|
+
await system.storage.set('state', 'systemConfig', {
|
|
446
|
+
theme: 'dark',
|
|
447
|
+
language: 'zh-CN',
|
|
448
|
+
notifications: true,
|
|
449
|
+
maxFileSize: 10 * 1024 * 1024 // 10MB
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// Set collection values
|
|
453
|
+
await system.storage.set('state', 'supportedLanguages', [
|
|
454
|
+
'zh-CN', 'en-US', 'ja-JP', 'ko-KR'
|
|
455
|
+
]);
|
|
456
|
+
|
|
457
|
+
// Conditional setting (only set if doesn't exist)
|
|
458
|
+
async function setDefaultConfig() {
|
|
459
|
+
const existingConfig = await system.storage.get('state', 'systemConfig');
|
|
460
|
+
if (!existingConfig) {
|
|
461
|
+
await system.storage.set('state', 'systemConfig', {
|
|
462
|
+
theme: 'light',
|
|
463
|
+
language: 'en-US',
|
|
464
|
+
notifications: false
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### 10.4.3 Conditional Logic Based on Dictionaries
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// Using dictionary values for conditional logic in interactions
|
|
474
|
+
const createUserInteraction = Interaction.create({
|
|
475
|
+
name: 'createUser',
|
|
476
|
+
action: Action.create({name: 'createUser'}),
|
|
477
|
+
payload: Payload.create({
|
|
478
|
+
items: [
|
|
479
|
+
PayloadItem.create({
|
|
480
|
+
name: 'userData',
|
|
481
|
+
base: userEntity
|
|
482
|
+
})
|
|
483
|
+
]
|
|
484
|
+
})
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// Use Attributive to control permissions based on dictionary values
|
|
488
|
+
const MaxUsersReachedAttributive = Attributive.create({
|
|
489
|
+
name: 'MaxUsersNotReached',
|
|
490
|
+
content: async function(context: any) {
|
|
491
|
+
const currentUserCount = await context.system.storage.get('state', 'totalUsers');
|
|
492
|
+
const maxUsers = await context.system.storage.get('state', 'maxUsers');
|
|
493
|
+
return currentUserCount < maxUsers;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// Add dictionary-based permission control to interaction
|
|
498
|
+
createUserInteraction.attributives = [MaxUsersReachedAttributive];
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### 10.4.4 Combining Dictionaries with Computations
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
// Create a property computation that depends on global dictionaries
|
|
505
|
+
const UserScoreComputed = createClass({
|
|
506
|
+
name: 'UserScoreComputed',
|
|
507
|
+
public: {
|
|
508
|
+
baseScore: {
|
|
509
|
+
type: 'number',
|
|
510
|
+
required: false
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
class UserScoreComputation implements DataBasedComputation {
|
|
516
|
+
static computationType = UserScoreComputed
|
|
517
|
+
static contextType = 'property' as const
|
|
518
|
+
state = {}
|
|
519
|
+
dataDeps: {[key: string]: DataDep} = {}
|
|
520
|
+
|
|
521
|
+
constructor(
|
|
522
|
+
public controller: Controller,
|
|
523
|
+
public args: KlassInstance<typeof UserScoreComputed>,
|
|
524
|
+
public dataContext: PropertyDataContext
|
|
525
|
+
) {
|
|
526
|
+
// Depend on global configuration dictionary
|
|
527
|
+
this.dataDeps = {
|
|
528
|
+
globalConfig: {
|
|
529
|
+
type: 'global',
|
|
530
|
+
source: Dictionary.create({
|
|
531
|
+
name: 'scoringConfig',
|
|
532
|
+
type: 'object',
|
|
533
|
+
collection: false
|
|
534
|
+
})
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async compute(deps: {globalConfig: any}, context: any) {
|
|
540
|
+
const baseScore = this.args.baseScore || 0;
|
|
541
|
+
const config = deps.globalConfig || {};
|
|
542
|
+
|
|
543
|
+
// Calculate user score based on global configuration
|
|
544
|
+
const multiplier = config.scoreMultiplier || 1;
|
|
545
|
+
const bonus = config.newUserBonus || 0;
|
|
546
|
+
|
|
547
|
+
return (baseScore * multiplier) + bonus;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Export computation handler
|
|
552
|
+
export const UserScoreHandles = [UserScoreComputation];
|
|
553
|
+
|
|
554
|
+
// Use in user entity
|
|
555
|
+
userEntity.properties.push(
|
|
556
|
+
Property.create({
|
|
557
|
+
name: 'score',
|
|
558
|
+
type: 'number',
|
|
559
|
+
computation: UserScoreComputed.create({
|
|
560
|
+
baseScore: 100
|
|
561
|
+
})
|
|
562
|
+
})
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
// Create scoring configuration dictionary
|
|
566
|
+
const scoringConfig = Dictionary.create({
|
|
567
|
+
name: 'scoringConfig',
|
|
568
|
+
type: 'object',
|
|
569
|
+
collection: false
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
// Set configuration values
|
|
573
|
+
await system.storage.set('state', 'scoringConfig', {
|
|
574
|
+
scoreMultiplier: 1.5,
|
|
575
|
+
newUserBonus: 50
|
|
576
|
+
});
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## 10.5 Advanced Dictionary Usage
|
|
580
|
+
|
|
581
|
+
### 10.5.1 Dynamic Configuration Management
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
// Create feature flags dictionary
|
|
585
|
+
const featureFlags = Dictionary.create({
|
|
586
|
+
name: 'featureFlags',
|
|
587
|
+
type: 'object',
|
|
588
|
+
collection: false
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
// Set feature flags
|
|
592
|
+
await system.storage.set('state', 'featureFlags', {
|
|
593
|
+
enableNewUI: true,
|
|
594
|
+
enableBetaFeatures: false,
|
|
595
|
+
enableAnalytics: true,
|
|
596
|
+
maxUploadSize: 50 * 1024 * 1024 // 50MB
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
// Create configuration management utility class
|
|
600
|
+
class ConfigManager {
|
|
601
|
+
constructor(private system: MonoSystem) {}
|
|
602
|
+
|
|
603
|
+
async isFeatureEnabled(featureName: string): Promise<boolean> {
|
|
604
|
+
const flags = await this.system.storage.get('state', 'featureFlags');
|
|
605
|
+
return flags?.[featureName] === true;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
async getFeatureConfig(featureName: string): Promise<any> {
|
|
609
|
+
const flags = await this.system.storage.get('state', 'featureFlags');
|
|
610
|
+
return flags?.[featureName];
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
async enableFeature(featureName: string): Promise<void> {
|
|
614
|
+
const flags = await this.system.storage.get('state', 'featureFlags') || {};
|
|
615
|
+
flags[featureName] = true;
|
|
616
|
+
await this.system.storage.set('state', 'featureFlags', flags);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async disableFeature(featureName: string): Promise<void> {
|
|
620
|
+
const flags = await this.system.storage.get('state', 'featureFlags') || {};
|
|
621
|
+
flags[featureName] = false;
|
|
622
|
+
await this.system.storage.set('state', 'featureFlags', flags);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
async updateFeatureConfig(featureName: string, config: any): Promise<void> {
|
|
626
|
+
const flags = await this.system.storage.get('state', 'featureFlags') || {};
|
|
627
|
+
flags[featureName] = config;
|
|
628
|
+
await this.system.storage.set('state', 'featureFlags', flags);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Use configuration manager
|
|
633
|
+
const configManager = new ConfigManager(system);
|
|
634
|
+
|
|
635
|
+
// Check if feature is enabled
|
|
636
|
+
if (await configManager.isFeatureEnabled('enableNewUI')) {
|
|
637
|
+
console.log('New UI is enabled');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Get upload size limit
|
|
641
|
+
const maxUploadSize = await configManager.getFeatureConfig('maxUploadSize');
|
|
642
|
+
console.log(`Max upload size: ${maxUploadSize} bytes`);
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
### 10.5.2 Caching Mechanism
|
|
646
|
+
|
|
647
|
+
```typescript
|
|
648
|
+
// Create cache dictionary
|
|
649
|
+
const apiCache = Dictionary.create({
|
|
650
|
+
name: 'apiCache',
|
|
651
|
+
type: 'object',
|
|
652
|
+
collection: false
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// Cache manager
|
|
656
|
+
class CacheManager {
|
|
657
|
+
constructor(private system: MonoSystem, private ttl: number = 3600000) {} // Default 1 hour TTL
|
|
658
|
+
|
|
659
|
+
async get(key: string): Promise<any> {
|
|
660
|
+
const cache = await this.system.storage.get('state', 'apiCache') || {};
|
|
661
|
+
const item = cache[key];
|
|
662
|
+
|
|
663
|
+
if (!item) return null;
|
|
664
|
+
|
|
665
|
+
// Check if expired
|
|
666
|
+
if (Date.now() - item.timestamp > this.ttl) {
|
|
667
|
+
await this.delete(key);
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return item.data;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
async set(key: string, data: any): Promise<void> {
|
|
675
|
+
const cache = await this.system.storage.get('state', 'apiCache') || {};
|
|
676
|
+
cache[key] = {
|
|
677
|
+
data,
|
|
678
|
+
timestamp: Date.now()
|
|
679
|
+
};
|
|
680
|
+
await this.system.storage.set('state', 'apiCache', cache);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
async delete(key: string): Promise<void> {
|
|
684
|
+
const cache = await this.system.storage.get('state', 'apiCache') || {};
|
|
685
|
+
delete cache[key];
|
|
686
|
+
await this.system.storage.set('state', 'apiCache', cache);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
async clear(): Promise<void> {
|
|
690
|
+
await this.system.storage.set('state', 'apiCache', {});
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
async cleanup(): Promise<void> {
|
|
694
|
+
const cache = await this.system.storage.get('state', 'apiCache') || {};
|
|
695
|
+
const now = Date.now();
|
|
696
|
+
|
|
697
|
+
Object.keys(cache).forEach(key => {
|
|
698
|
+
if (now - cache[key].timestamp > this.ttl) {
|
|
699
|
+
delete cache[key];
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
await this.system.storage.set('state', 'apiCache', cache);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Use cache manager
|
|
708
|
+
const cacheManager = new CacheManager(system, 1800000); // 30-minute TTL
|
|
709
|
+
|
|
710
|
+
// Cache API responses
|
|
711
|
+
async function fetchUserProfile(userId: string) {
|
|
712
|
+
const cacheKey = `user_profile_${userId}`;
|
|
713
|
+
|
|
714
|
+
// Try to get from cache
|
|
715
|
+
let profile = await cacheManager.get(cacheKey);
|
|
716
|
+
if (profile) {
|
|
717
|
+
console.log('Cache hit');
|
|
718
|
+
return profile;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Cache miss, call API
|
|
722
|
+
console.log('Cache miss, fetching from API');
|
|
723
|
+
profile = await callExternalAPI(`/users/${userId}`);
|
|
724
|
+
|
|
725
|
+
// Store in cache
|
|
726
|
+
await cacheManager.set(cacheKey, profile);
|
|
727
|
+
|
|
728
|
+
return profile;
|
|
729
|
+
}
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### 10.5.3 Real-time Statistics Dashboard
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
// Create real-time statistics dictionary
|
|
736
|
+
const realtimeStats = Dictionary.create({
|
|
737
|
+
name: 'realtimeStats',
|
|
738
|
+
type: 'object',
|
|
739
|
+
collection: false,
|
|
740
|
+
computation: Transform.create({
|
|
741
|
+
record: userEntity,
|
|
742
|
+
attributeQuery: ['isActive', 'createdAt', 'lastLoginAt'],
|
|
743
|
+
callback: (users: any[]) => {
|
|
744
|
+
const now = Date.now();
|
|
745
|
+
const oneHourAgo = now - 3600000;
|
|
746
|
+
const oneDayAgo = now - 86400000;
|
|
747
|
+
const oneWeekAgo = now - 604800000;
|
|
748
|
+
|
|
749
|
+
const activeUsers = users.filter(user => user.isActive);
|
|
750
|
+
const recentLogins = users.filter(user =>
|
|
751
|
+
user.lastLoginAt && new Date(user.lastLoginAt).getTime() > oneHourAgo
|
|
752
|
+
);
|
|
753
|
+
const newUsersToday = users.filter(user =>
|
|
754
|
+
new Date(user.createdAt).getTime() > oneDayAgo
|
|
755
|
+
);
|
|
756
|
+
const newUsersThisWeek = users.filter(user =>
|
|
757
|
+
new Date(user.createdAt).getTime() > oneWeekAgo
|
|
758
|
+
);
|
|
759
|
+
|
|
760
|
+
return {
|
|
761
|
+
totalUsers: users.length,
|
|
762
|
+
activeUsers: activeUsers.length,
|
|
763
|
+
inactiveUsers: users.length - activeUsers.length,
|
|
764
|
+
recentLogins: recentLogins.length,
|
|
765
|
+
newUsersToday: newUsersToday.length,
|
|
766
|
+
newUsersThisWeek: newUsersThisWeek.length,
|
|
767
|
+
userGrowthRate: newUsersThisWeek.length / Math.max(users.length - newUsersThisWeek.length, 1),
|
|
768
|
+
timestamp: now
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
})
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// Dashboard data accessor
|
|
775
|
+
class Dashboard {
|
|
776
|
+
constructor(private system: MonoSystem) {}
|
|
777
|
+
|
|
778
|
+
async getRealtimeStats() {
|
|
779
|
+
return await this.system.storage.get('state', 'realtimeStats');
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
async getSystemHealth() {
|
|
783
|
+
const [stats, config, cache] = await Promise.all([
|
|
784
|
+
this.system.storage.get('state', 'realtimeStats'),
|
|
785
|
+
this.system.storage.get('state', 'systemConfig'),
|
|
786
|
+
this.system.storage.get('state', 'apiCache')
|
|
787
|
+
]);
|
|
788
|
+
|
|
789
|
+
return {
|
|
790
|
+
userStats: stats,
|
|
791
|
+
systemConfig: config,
|
|
792
|
+
cacheSize: Object.keys(cache || {}).length,
|
|
793
|
+
lastUpdated: Date.now()
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
async getPerformanceMetrics() {
|
|
798
|
+
const stats = await this.getRealtimeStats();
|
|
799
|
+
const cacheHitRate = await this.calculateCacheHitRate();
|
|
800
|
+
|
|
801
|
+
return {
|
|
802
|
+
userEngagement: stats.recentLogins / stats.activeUsers,
|
|
803
|
+
growthRate: stats.userGrowthRate,
|
|
804
|
+
cacheHitRate,
|
|
805
|
+
systemLoad: await this.getSystemLoad()
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
private async calculateCacheHitRate(): Promise<number> {
|
|
810
|
+
// Cache hit rate calculation logic can be implemented here
|
|
811
|
+
return 0.85; // Example value
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
private async getSystemLoad(): Promise<number> {
|
|
815
|
+
// System load calculation logic can be implemented here
|
|
816
|
+
return 0.3; // Example value
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
## 10.6 Best Practices
|
|
822
|
+
|
|
823
|
+
### 10.6.1 Naming and Organization
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
// ✅ Good naming examples grouped by function
|
|
827
|
+
const userStats = Dictionary.create({
|
|
828
|
+
name: 'userStats',
|
|
829
|
+
type: 'object',
|
|
830
|
+
collection: false
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
const systemConfig = Dictionary.create({
|
|
834
|
+
name: 'systemConfig',
|
|
835
|
+
type: 'object',
|
|
836
|
+
collection: false
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
const featureFlags = Dictionary.create({
|
|
840
|
+
name: 'featureFlags',
|
|
841
|
+
type: 'object',
|
|
842
|
+
collection: false
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// ✅ Use constants to manage dictionary names
|
|
846
|
+
const DICT_NAMES = {
|
|
847
|
+
USER_STATS: 'userStats',
|
|
848
|
+
SYSTEM_CONFIG: 'systemConfig',
|
|
849
|
+
FEATURE_FLAGS: 'featureFlags',
|
|
850
|
+
API_CACHE: 'apiCache'
|
|
851
|
+
} as const;
|
|
852
|
+
|
|
853
|
+
// Use constants
|
|
854
|
+
const userStatsValue = await system.storage.get('state', DICT_NAMES.USER_STATS);
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### 10.6.2 Type Safety
|
|
858
|
+
|
|
859
|
+
```typescript
|
|
860
|
+
// Define dictionary value types
|
|
861
|
+
interface SystemConfig {
|
|
862
|
+
theme: 'light' | 'dark';
|
|
863
|
+
language: string;
|
|
864
|
+
notifications: boolean;
|
|
865
|
+
maxFileSize: number;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
interface UserStats {
|
|
869
|
+
totalUsers: number;
|
|
870
|
+
activeUsers: number;
|
|
871
|
+
newUsersToday: number;
|
|
872
|
+
lastUpdated: number;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Create type-safe dictionary accessor
|
|
876
|
+
class TypedDictionary {
|
|
877
|
+
constructor(private system: MonoSystem) {}
|
|
878
|
+
|
|
879
|
+
async getSystemConfig(): Promise<SystemConfig | null> {
|
|
880
|
+
return await this.system.storage.get('state', 'systemConfig');
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
async setSystemConfig(config: SystemConfig): Promise<void> {
|
|
884
|
+
await this.system.storage.set('state', 'systemConfig', config);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
async getUserStats(): Promise<UserStats | null> {
|
|
888
|
+
return await this.system.storage.get('state', 'userStats');
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
async updateSystemConfig(updates: Partial<SystemConfig>): Promise<void> {
|
|
892
|
+
const current = await this.getSystemConfig() || {} as SystemConfig;
|
|
893
|
+
const updated = { ...current, ...updates };
|
|
894
|
+
await this.setSystemConfig(updated);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
### 10.6.3 Performance Optimization
|
|
900
|
+
|
|
901
|
+
```typescript
|
|
902
|
+
// Batch reading dictionary values
|
|
903
|
+
class DictionaryBatch {
|
|
904
|
+
constructor(private system: MonoSystem) {}
|
|
905
|
+
|
|
906
|
+
async getMultiple(keys: string[]): Promise<Record<string, any>> {
|
|
907
|
+
const promises = keys.map(key =>
|
|
908
|
+
this.system.storage.get('state', key).then(value => [key, value])
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
const results = await Promise.all(promises);
|
|
912
|
+
return Object.fromEntries(results);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
async setMultiple(updates: Record<string, any>): Promise<void> {
|
|
916
|
+
const promises = Object.entries(updates).map(([key, value]) =>
|
|
917
|
+
this.system.storage.set('state', key, value)
|
|
918
|
+
);
|
|
919
|
+
|
|
920
|
+
await Promise.all(promises);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Usage example
|
|
925
|
+
const batch = new DictionaryBatch(system);
|
|
926
|
+
|
|
927
|
+
// Batch reading
|
|
928
|
+
const configs = await batch.getMultiple([
|
|
929
|
+
'systemConfig',
|
|
930
|
+
'featureFlags',
|
|
931
|
+
'userStats'
|
|
932
|
+
]);
|
|
933
|
+
|
|
934
|
+
// Batch updating
|
|
935
|
+
await batch.setMultiple({
|
|
936
|
+
'systemConfig': { theme: 'dark' },
|
|
937
|
+
'featureFlags': { enableNewUI: true },
|
|
938
|
+
'lastUpdated': Date.now()
|
|
939
|
+
});
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
Global dictionaries provide the interaqt framework with powerful global state management capabilities. Through proper use of dictionaries, you can implement system configuration management, real-time statistics, caching mechanisms, and other features, providing a solid foundation for building complex reactive applications.
|