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.
Files changed (35) hide show
  1. package/agent/.claude/agents/code-generation-handler.md +2 -0
  2. package/agent/.claude/agents/computation-generation-handler.md +1 -0
  3. package/agent/.claude/agents/implement-design-handler.md +4 -13
  4. package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
  5. package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
  6. package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
  7. package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
  8. package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
  9. package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
  10. package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
  11. package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
  12. package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
  13. package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
  14. package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
  15. package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
  16. package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
  17. package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
  18. package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
  19. package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
  20. package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
  21. package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
  22. package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
  23. package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
  24. package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
  25. package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
  26. package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
  27. package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
  28. package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
  29. package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
  30. package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
  31. package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
  32. package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
  33. package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
  34. package/agent/agentspace/knowledge/usage/README.md +148 -0
  35. package/package.json +1 -1
@@ -0,0 +1,1606 @@
1
+ # Chapter 13: API Reference
2
+
3
+ This chapter provides detailed reference documentation for all core APIs in the interaqt framework, including complete parameter descriptions, type definitions, and usage examples.
4
+
5
+ ## 13.1 Entity-Related APIs
6
+
7
+ ### Entity.create()
8
+
9
+ Create entity definition. Entities are the basic units of data in the system.
10
+
11
+ **Syntax**
12
+ ```typescript
13
+ Entity.create(config: EntityConfig): KlassInstance<typeof Entity>
14
+ ```
15
+
16
+ **Parameters**
17
+ - `config.name` (string, required): Entity name, must match `/^[a-zA-Z0-9_]+$/` format
18
+ - `config.properties` (Property[], required): Entity property list, defaults to empty array
19
+ - `config.computation` (Computation[], optional): Entity-level computed data
20
+ - `config.baseEntity` (Entity|Relation, optional): Base entity for filtered entity (used to create filtered entities)
21
+ - `config.filterCondition` (MatchExp, optional): Filter condition (used to create filtered entities)
22
+
23
+ **Examples**
24
+ ```typescript
25
+ // Create basic entity
26
+ const User = Entity.create({
27
+ name: 'User',
28
+ properties: [
29
+ Property.create({ name: 'username', type: 'string' }),
30
+ Property.create({ name: 'email', type: 'string' })
31
+ ]
32
+ })
33
+
34
+ // Create filtered entity
35
+ const ActiveUser = Entity.create({
36
+ name: 'ActiveUser',
37
+ baseEntity: User,
38
+ filterCondition: MatchExp.atom({
39
+ key: 'status',
40
+ value: ['=', 'active']
41
+ })
42
+ })
43
+ ```
44
+
45
+ ### Property.create()
46
+
47
+ Create entity property definition.
48
+
49
+ **Syntax**
50
+ ```typescript
51
+ Property.create(config: PropertyConfig): KlassInstance<typeof Property>
52
+ ```
53
+
54
+ **Parameters**
55
+ - `config.name` (string, required): Property name, must be 1-5 characters long
56
+ - `config.type` (string, required): Property type, options: 'string' | 'number' | 'boolean'
57
+ - `config.collection` (boolean, optional): Whether it's a collection type
58
+ - `config.defaultValue` (function, optional): Default value function
59
+ - `config.computed` (function, optional): Computed property function
60
+ - `config.computation` (Computation, optional): Property computed data
61
+
62
+ **Examples**
63
+ ```typescript
64
+ // Basic property
65
+ const username = Property.create({
66
+ name: 'username',
67
+ type: 'string'
68
+ })
69
+
70
+ // Property with default value
71
+ const createdAt = Property.create({
72
+ name: 'createdAt',
73
+ type: 'string',
74
+ defaultValue: () => new Date().toISOString()
75
+ })
76
+
77
+ // Computed property
78
+ const fullName = Property.create({
79
+ name: 'fullName',
80
+ type: 'string',
81
+ computed: function(user) {
82
+ return `${user.firstName} ${user.lastName}`
83
+ }
84
+ })
85
+
86
+ // Property with reactive computation
87
+ const postCount = Property.create({
88
+ name: 'postCount',
89
+ type: 'number',
90
+ defaultValue: () => 0, // Must provide default value
91
+ computation: Count.create({
92
+ record: UserPostRelation
93
+ })
94
+ })
95
+ ```
96
+
97
+ ### Relation.create()
98
+
99
+ Create relationship definition between entities.
100
+
101
+ **Syntax**
102
+ ```typescript
103
+ Relation.create(config: RelationConfig): KlassInstance<typeof Relation>
104
+ ```
105
+
106
+ **Important: Auto-Generated Relation Names**
107
+
108
+ ⚠️ **DO NOT specify a `name` property when creating relations.** The framework automatically generates the relation name based on the source and target entities. For example:
109
+ - A relation between `User` and `Post` → automatically named `UserPost`
110
+ - A relation between `Post` and `Comment` → automatically named `PostComment`
111
+
112
+ **Parameters**
113
+ - `config.source` (Entity|Relation, required): Source entity of the relationship
114
+ - `config.sourceProperty` (string, required): Relationship property name in source entity
115
+ - `config.target` (Entity|Relation, required): Target entity of the relationship
116
+ - `config.targetProperty` (string, required): Relationship property name in target entity
117
+ - `config.type` (string, required): Relationship type, options: '1:1' | '1:n' | 'n:1' | 'n:n'
118
+ - `config.properties` (Property[], optional): Properties of the relationship itself
119
+ - `config.computation` (Computation, optional): Relationship-level computed data
120
+
121
+ **Note on Symmetric Relations**: The system automatically detects symmetric relations when `source === target` AND `sourceProperty === targetProperty`. There is no need to specify a `symmetric` parameter.
122
+
123
+ **Examples**
124
+ ```typescript
125
+ // One-to-many relationship
126
+ const UserPostRelation = Relation.create({
127
+ source: User,
128
+ sourceProperty: 'posts',
129
+ target: Post,
130
+ targetProperty: 'author',
131
+ type: '1:n'
132
+ })
133
+
134
+ // Many-to-many relationship
135
+ const UserTagRelation = Relation.create({
136
+ source: User,
137
+ sourceProperty: 'tags',
138
+ target: Tag,
139
+ targetProperty: 'users',
140
+ type: 'n:n'
141
+ })
142
+
143
+ // Symmetric relationship (friendship)
144
+ // Note: System detects symmetric relations automatically when source === target AND sourceProperty === targetProperty
145
+ const FriendRelation = Relation.create({
146
+ source: User,
147
+ sourceProperty: 'friends',
148
+ target: User,
149
+ targetProperty: 'friends', // Same as sourceProperty - automatically symmetric
150
+ type: 'n:n'
151
+ })
152
+
153
+ // Relationship with properties
154
+ const UserRoleRelation = Relation.create({
155
+ source: User,
156
+ sourceProperty: 'roles',
157
+ target: Role,
158
+ targetProperty: 'users',
159
+ type: 'n:n',
160
+ properties: [
161
+ Property.create({ name: 'assignedAt', type: 'string' }),
162
+ Property.create({ name: 'isActive', type: 'boolean' })
163
+ ]
164
+ })
165
+ ```
166
+
167
+ ## 13.2 Computation-Related APIs
168
+
169
+ ### Count.create()
170
+
171
+ Create count computation for counting records.
172
+
173
+ **Syntax**
174
+ ```typescript
175
+ Count.create(config: CountConfig): KlassInstance<typeof Count>
176
+ ```
177
+
178
+ **Parameters**
179
+ - `config.record` (Entity|Relation, required): Entity or relation to count
180
+ - `config.direction` (string, optional): Relationship direction, options: 'source' | 'target', only for relation counting
181
+ - `config.callback` (function, optional): Filter callback function, returns boolean to decide if included in count
182
+ - `config.attributeQuery` (AttributeQueryData, optional): Attribute query configuration to optimize data fetching
183
+ - `config.dataDeps` (object, optional): Data dependency configuration, format: `{[key: string]: DataDep}`
184
+
185
+ **Examples**
186
+ ```typescript
187
+ // Basic global count
188
+ const totalUsers = Count.create({
189
+ record: User
190
+ })
191
+
192
+ // Basic property count (user's post count)
193
+ const userPostCount = Property.create({
194
+ name: 'postCount',
195
+ type: 'number',
196
+ defaultValue: () => 0, // Must provide default value
197
+ computation: Count.create({
198
+ record: UserPostRelation
199
+ })
200
+ })
201
+
202
+ // Count with filter condition (only count published posts)
203
+ const publishedPostCount = Property.create({
204
+ name: 'publishedPostCount',
205
+ type: 'number',
206
+ defaultValue: () => 0,
207
+ computation: Count.create({
208
+ record: UserPostRelation,
209
+ attributeQuery: [['target', {attributeQuery: ['status']}]],
210
+ callback: function(relation) {
211
+ return relation.target.status === 'published'
212
+ }
213
+ })
214
+ })
215
+
216
+ // Count with data dependencies (filter based on global minimum score setting)
217
+ const minScoreThreshold = Dictionary.create({
218
+ name: 'minScoreThreshold',
219
+ type: 'number',
220
+ collection: false
221
+ })
222
+ const highScorePostCount = Property.create({
223
+ name: 'highScorePostCount',
224
+ type: 'number',
225
+ defaultValue: () => 0,
226
+ computation: Count.create({
227
+ record: UserPostRelation,
228
+ attributeQuery: [['target', {attributeQuery: ['score']}]],
229
+ dataDeps: {
230
+ minScore: {
231
+ type: 'global',
232
+ source: minScoreThreshold
233
+ }
234
+ },
235
+ callback: function(relation, dataDeps) {
236
+ return relation.target.score >= dataDeps.minScore
237
+ }
238
+ })
239
+ })
240
+
241
+ // Global count with filter and data dependencies
242
+ const userActiveDays = Dictionary.create({
243
+ name: 'userActiveDays',
244
+ type: 'number',
245
+ collection: false
246
+ })
247
+ const activeUsersCount = Dictionary.create({
248
+ name: 'activeUsersCount',
249
+ type: 'number',
250
+ collection: false,
251
+ computation: Count.create({
252
+ record: User,
253
+ attributeQuery: ['lastLoginDate'],
254
+ dataDeps: {
255
+ activeDays: {
256
+ type: 'global',
257
+ source: userActiveDays
258
+ }
259
+ },
260
+ callback: function(user, dataDeps) {
261
+ const daysSinceLogin = (Date.now() - new Date(user.lastLoginDate).getTime()) / (1000 * 60 * 60 * 24)
262
+ return daysSinceLogin <= dataDeps.activeDays
263
+ }
264
+ })
265
+ })
266
+
267
+ // Relation count with direction parameter
268
+ const authorPostCount = Property.create({
269
+ name: 'authoredPostCount',
270
+ type: 'number',
271
+ defaultValue: () => 0,
272
+ computation: Count.create({
273
+ record: UserPostRelation,
274
+ direction: 'target' // Count related posts from user perspective
275
+ })
276
+ })
277
+ ```
278
+
279
+ ### WeightedSummation.create()
280
+
281
+ Create weighted summation computation.
282
+
283
+ **Syntax**
284
+ ```typescript
285
+ WeightedSummation.create(config: WeightedSummationConfig): KlassInstance<typeof WeightedSummation>
286
+ ```
287
+
288
+ **Parameters**
289
+ - `config.record` (Entity|Relation, required): Entity or relation to compute
290
+ - `config.callback` (function, required): Callback function to calculate weight and value, returns `{weight: number, value: number}`
291
+ - `config.attributeQuery` (AttributeQueryData, required): Attribute query configuration
292
+
293
+ **Examples**
294
+ ```typescript
295
+ // Calculate user total score
296
+ const userTotalScore = Property.create({
297
+ name: 'totalScore',
298
+ type: 'number',
299
+ defaultValue: () => 0, // Must provide default value
300
+ computation: WeightedSummation.create({
301
+ record: UserScoreRelation,
302
+ callback: function(scoreRecord) {
303
+ return {
304
+ weight: scoreRecord.multiplier || 1,
305
+ value: scoreRecord.points
306
+ }
307
+ }
308
+ })
309
+ })
310
+
311
+ // Global weighted summation
312
+ const globalWeightedScore = WeightedSummation.create({
313
+ record: ScoreRecord,
314
+ callback: function(record) {
315
+ return {
316
+ weight: record.difficulty,
317
+ value: record.score
318
+ }
319
+ }
320
+ })
321
+ ```
322
+
323
+ ### Summation.create()
324
+
325
+ Create summation computation for summing specified fields.
326
+
327
+ **Syntax**
328
+ ```typescript
329
+ Summation.create(config: SummationConfig): KlassInstance<typeof Summation>
330
+ ```
331
+
332
+ **Parameters**
333
+ - `config.record` (Entity|Relation, required): Entity or relation to compute
334
+ - `config.attributeQuery` (AttributeQueryData, required): Attribute query configuration, specifies field path to sum
335
+ - `config.direction` (string, optional): Relationship direction, options: 'source' | 'target', only for relation summation
336
+
337
+ **How it works**
338
+
339
+ Summation sums the field pointed to by the leftmost path in `attributeQuery`. If any value in the path is `undefined`, `null`, `NaN`, or `Infinity`, that value will be treated as 0.
340
+
341
+ **Examples**
342
+ ```typescript
343
+ // Basic global summation (sum all transaction amounts)
344
+ const totalRevenue = Dictionary.create({
345
+ name: 'totalRevenue',
346
+ type: 'number',
347
+ collection: false,
348
+ computation: Summation.create({
349
+ record: Transaction,
350
+ attributeQuery: ['amount']
351
+ })
352
+ })
353
+
354
+ // Property-level summation (calculate user's total order amount)
355
+ const userTotalSpent = Property.create({
356
+ name: 'totalSpent',
357
+ type: 'number',
358
+ defaultValue: () => 0, // Must provide default value
359
+ computation: Summation.create({
360
+ record: UserOrderRelation,
361
+ attributeQuery: [['target', {attributeQuery: ['totalAmount']}]]
362
+ })
363
+ })
364
+
365
+ // Nested path summation (sum nested fields of related entities)
366
+ const departmentBudget = Property.create({
367
+ name: 'totalBudget',
368
+ type: 'number',
369
+ defaultValue: () => 0,
370
+ computation: Summation.create({
371
+ record: DepartmentProjectRelation,
372
+ attributeQuery: [['target', {
373
+ attributeQuery: [['budget', {
374
+ attributeQuery: ['allocatedAmount']
375
+ }]]
376
+ }]]
377
+ })
378
+ })
379
+
380
+ // Direct summation of relation properties
381
+ const totalShippingCost = Property.create({
382
+ name: 'totalShippingCost',
383
+ type: 'number',
384
+ defaultValue: () => 0,
385
+ computation: Summation.create({
386
+ record: OrderShipmentRelation,
387
+ attributeQuery: ['shippingFee'] // Relation's own property
388
+ })
389
+ })
390
+
391
+ // Global summation handling missing values
392
+ const totalBalance = Dictionary.create({
393
+ name: 'totalBalance',
394
+ type: 'number',
395
+ collection: false,
396
+ computation: Summation.create({
397
+ record: Account,
398
+ attributeQuery: ['balance'] // null or undefined values treated as 0
399
+ })
400
+ })
401
+ ```
402
+
403
+ **Working with Other Computations**
404
+
405
+ If you need complex summation logic (like conditional filtering, data transformation etc.), you can first use other computations (like Transform) to calculate the needed values on records, then use Summation for simple summing:
406
+
407
+ ```typescript
408
+ // First use Transform to calculate discounted price
409
+ const OrderItem = Entity.create({
410
+ name: 'OrderItem',
411
+ properties: [
412
+ Property.create({ name: 'price', type: 'number' }),
413
+ Property.create({ name: 'quantity', type: 'number' }),
414
+ Property.create({ name: 'discountRate', type: 'number' }),
415
+ Property.create({
416
+ name: 'finalPrice',
417
+ type: 'number',
418
+ computed: function(item) {
419
+ const subtotal = (item.price || 0) * (item.quantity || 0);
420
+ const discount = subtotal * (item.discountRate || 0);
421
+ return subtotal - discount;
422
+ }
423
+ })
424
+ ]
425
+ });
426
+
427
+ // Then use Summation to sum computed values
428
+ const orderTotal = Property.create({
429
+ name: 'total',
430
+ type: 'number',
431
+ defaultValue: () => 0,
432
+ computation: Summation.create({
433
+ record: OrderItemRelation,
434
+ attributeQuery: [['target', {attributeQuery: ['finalPrice']}]]
435
+ })
436
+ });
437
+ ```
438
+
439
+ ### Every.create()
440
+
441
+ Create boolean computation that checks if all records meet a condition.
442
+
443
+ **Syntax**
444
+ ```typescript
445
+ Every.create(config: EveryConfig): KlassInstance<typeof Every>
446
+ ```
447
+
448
+ **Parameters**
449
+ - `config.record` (Entity|Relation, required): Entity or relation to check
450
+ - `config.callback` (function, required): Condition check function, returns boolean
451
+ - `config.attributeQuery` (AttributeQueryData, required): Attribute query configuration
452
+ - `config.notEmpty` (boolean, optional): Return value when collection is empty
453
+
454
+ **Examples**
455
+ ```typescript
456
+ // Check if user completed all required courses
457
+ const completedAllRequired = Property.create({
458
+ name: 'completedAllRequired',
459
+ type: 'boolean',
460
+ defaultValue: () => false, // Must provide default value
461
+ computation: Every.create({
462
+ record: UserCourseRelation,
463
+ callback: function(courseRelation) {
464
+ return courseRelation.status === 'completed'
465
+ },
466
+ notEmpty: false
467
+ })
468
+ })
469
+ ```
470
+
471
+ ### Any.create()
472
+
473
+ Create boolean computation that checks if any record meets a condition.
474
+
475
+ **Syntax**
476
+ ```typescript
477
+ Any.create(config: AnyConfig): KlassInstance<typeof Any>
478
+ ```
479
+
480
+ **Parameters**
481
+ - `config.record` (Entity|Relation, required): Entity or relation to check
482
+ - `config.callback` (function, required): Condition check function, returns boolean
483
+ - `config.attributeQuery` (AttributeQueryData, required): Attribute query configuration
484
+
485
+ **Examples**
486
+ ```typescript
487
+ // Check if user has any pending tasks
488
+ const hasPendingTasks = Property.create({
489
+ name: 'hasPendingTasks',
490
+ type: 'boolean',
491
+ defaultValue: () => false, // Must provide default value
492
+ computation: Any.create({
493
+ record: UserTaskRelation,
494
+ callback: function(taskRelation) {
495
+ return taskRelation.status === 'pending'
496
+ }
497
+ })
498
+ })
499
+ ```
500
+
501
+ ### Transform.create()
502
+
503
+ Create custom transformation computation.
504
+
505
+ Transform is fundamentally about **transforming data from one collection to another collection**. It transforms sets of data (e.g., InteractionEventEntity → Entity/Relation, Entity → different Entity). Transform **cannot** be used for property computations within the same entity - use `getValue` for that purpose.
506
+
507
+ **Syntax**
508
+ ```typescript
509
+ Transform.create(config: TransformConfig): KlassInstance<typeof Transform>
510
+ ```
511
+
512
+ **Parameters**
513
+ - `config.record` (Entity|Relation, required): Entity or relation to transform from (source collection)
514
+ - `config.callback` (function, required): Transformation function that converts source data to target data
515
+ - `config.attributeQuery` (AttributeQueryData, required): Attribute query configuration
516
+
517
+
518
+ ### StateMachine.create()
519
+
520
+ Create state machine computation.
521
+
522
+ **Syntax**
523
+ ```typescript
524
+ StateMachine.create(config: StateMachineConfig): KlassInstance<typeof StateMachine>
525
+ ```
526
+
527
+ **Parameters**
528
+ - `config.states` (StateNode[], required): List of state nodes
529
+ - `config.transfers` (StateTransfer[], required): List of state transfers
530
+ - `config.defaultState` (StateNode, required): Default state
531
+
532
+ **Examples**
533
+ ```typescript
534
+ // First declare state nodes
535
+ const pendingState = StateNode.create({ name: 'pending' });
536
+ const confirmedState = StateNode.create({ name: 'confirmed' });
537
+ const shippedState = StateNode.create({ name: 'shipped' });
538
+ const deliveredState = StateNode.create({ name: 'delivered' });
539
+
540
+ // Order state machine
541
+ const OrderStateMachine = StateMachine.create({
542
+ states: [pendingState, confirmedState, shippedState, deliveredState],
543
+ transfers: [
544
+ StateTransfer.create({
545
+ current: pendingState,
546
+ next: confirmedState,
547
+ trigger: ConfirmOrderInteraction
548
+ })
549
+ ],
550
+ defaultState: pendingState
551
+ })
552
+ ```
553
+
554
+ ### RealTime.create()
555
+
556
+ Create real-time computation for handling time-based reactive computations. Real-time computations automatically manage state (lastRecomputeTime and nextRecomputeTime) and adopt different scheduling strategies based on return type.
557
+
558
+ **Syntax**
559
+ ```typescript
560
+ RealTime.create(config: RealTimeConfig): KlassInstance<typeof RealTime>
561
+ ```
562
+
563
+ **Parameters**
564
+ - `config.callback` (function, required): Real-time computation callback function, accepts `(now: Expression, dataDeps: any) => Expression | Inequality | Equation`
565
+ - `config.nextRecomputeTime` (function, optional): Recomputation interval function, accepts `(now: number, dataDeps: any) => number`, only valid for Expression type
566
+ - `config.dataDeps` (object, optional): Data dependency configuration, format: `{[key: string]: DataDep}`
567
+ - `config.attributeQuery` (AttributeQueryData, optional): Attribute query configuration
568
+
569
+ **Return Types and Scheduling Behavior**
570
+ - **Expression**: Returns numeric computation result, nextRecomputeTime = lastRecomputeTime + nextRecomputeTime function return value
571
+ - **Inequality**: Returns boolean comparison result, nextRecomputeTime = solve() result (critical time point for state change)
572
+ - **Equation**: Returns boolean equation result, nextRecomputeTime = solve() result (critical time point for state change)
573
+
574
+ **State Management**
575
+
576
+ RealTime computations automatically create and manage two state fields:
577
+ - `lastRecomputeTime`: Timestamp of last computation
578
+ - `nextRecomputeTime`: Timestamp of next computation
579
+
580
+ State field naming convention:
581
+ - Global computations: `_global_boundState_{computationName}_{stateName}`
582
+ - Property computations: `_record_boundState_{entityName}_{propertyName}_{stateName}`
583
+
584
+ **Examples**
585
+
586
+ ```typescript
587
+ // Expression type: manually specify recomputation interval
588
+ const currentTimestamp = Dictionary.create({
589
+ name: 'currentTimestamp',
590
+ type: 'number',
591
+ computation: RealTime.create({
592
+ nextRecomputeTime: (now: number, dataDeps: any) => 1000, // Update every second
593
+ callback: async (now: Expression, dataDeps: any) => {
594
+ return now.divide(1000); // Convert to seconds
595
+ }
596
+ })
597
+ });
598
+
599
+ // Inequality type: system automatically calculates critical time points
600
+ const isAfterDeadline = Dictionary.create({
601
+ name: 'isAfterDeadline',
602
+ type: 'boolean',
603
+ computation: RealTime.create({
604
+ dataDeps: {
605
+ project: {
606
+ type: 'records',
607
+ source: projectEntity,
608
+ attributeQuery: ['deadline']
609
+ }
610
+ },
611
+ callback: async (now: Expression, dataDeps: any) => {
612
+ const deadline = dataDeps.project?.[0]?.deadline || Date.now() + 86400000;
613
+ // System will automatically recompute at deadline time
614
+ return now.gt(deadline);
615
+ }
616
+ })
617
+ });
618
+
619
+ // Equation type: check time equations
620
+ const isExactHour = Dictionary.create({
621
+ name: 'isExactHour',
622
+ type: 'boolean',
623
+ computation: RealTime.create({
624
+ callback: async (now: Expression, dataDeps: any) => {
625
+ const millisecondsInHour = 3600000;
626
+ // System will automatically recompute at next exact hour
627
+ return now.modulo(millisecondsInHour).eq(0);
628
+ }
629
+ })
630
+ });
631
+
632
+ // Property-level real-time computation
633
+ const userEntity = Entity.create({
634
+ name: 'User',
635
+ properties: [
636
+ Property.create({ name: 'lastLoginAt', type: 'number' }),
637
+ Property.create({
638
+ name: 'isRecentlyActive',
639
+ type: 'boolean',
640
+ computation: RealTime.create({
641
+ dataDeps: {
642
+ _current: {
643
+ type: 'property',
644
+ attributeQuery: ['lastLoginAt']
645
+ }
646
+ },
647
+ callback: async (now: Expression, dataDeps: any) => {
648
+ const lastLogin = dataDeps._current?.lastLoginAt || 0;
649
+ const oneHourAgo = now.subtract(3600000);
650
+ return Expression.number(lastLogin).gt(oneHourAgo);
651
+ }
652
+ })
653
+ })
654
+ ]
655
+ });
656
+
657
+ // Complex data dependencies real-time computation
658
+ const businessMetrics = Dictionary.create({
659
+ name: 'businessMetrics',
660
+ type: 'object',
661
+ computation: RealTime.create({
662
+ nextRecomputeTime: (now: number, dataDeps: any) => 300000, // Update every 5 minutes
663
+ dataDeps: {
664
+ config: {
665
+ type: 'records',
666
+ source: configEntity,
667
+ attributeQuery: ['businessHourStart', 'businessHourEnd']
668
+ },
669
+ metrics: {
670
+ type: 'records',
671
+ source: metricsEntity,
672
+ attributeQuery: ['dailyTarget', 'currentValue']
673
+ }
674
+ },
675
+ callback: async (now: Expression, dataDeps: any) => {
676
+ const config = dataDeps.config?.[0] || {};
677
+ const metrics = dataDeps.metrics?.[0] || {};
678
+
679
+ const startHour = config.businessHourStart || 9;
680
+ const endHour = config.businessHourEnd || 17;
681
+ const currentHour = now.divide(3600000).modulo(24);
682
+
683
+ const isBusinessTime = currentHour.gt(startHour).and(currentHour.lt(endHour));
684
+ const progressRate = Expression.number(metrics.currentValue || 0).divide(metrics.dailyTarget || 1);
685
+
686
+ return {
687
+ isBusinessTime: isBusinessTime.evaluate({now: Date.now()}),
688
+ progressRate: progressRate.evaluate({now: Date.now()}),
689
+ timestamp: now.evaluate({now: Date.now()})
690
+ };
691
+ }
692
+ })
693
+ });
694
+ ```
695
+
696
+ **State Access Example**
697
+
698
+ ```typescript
699
+ // Get computation instance
700
+ const realTimeComputation = Array.from(controller.scheduler.computations.values()).find(
701
+ computation => computation.dataContext.type === 'global' &&
702
+ computation.dataContext.id === 'currentTimestamp'
703
+ );
704
+
705
+ // Get state key names
706
+ const lastRecomputeTimeKey = controller.scheduler.getBoundStateName(
707
+ realTimeComputation.dataContext,
708
+ 'lastRecomputeTime',
709
+ realTimeComputation.state.lastRecomputeTime
710
+ );
711
+
712
+ const nextRecomputeTimeKey = controller.scheduler.getBoundStateName(
713
+ realTimeComputation.dataContext,
714
+ 'nextRecomputeTime',
715
+ realTimeComputation.state.nextRecomputeTime
716
+ );
717
+
718
+ // Read state values
719
+ const lastRecomputeTime = await system.storage.get(DICTIONARY_RECORD, lastRecomputeTimeKey);
720
+ const nextRecomputeTime = await system.storage.get(DICTIONARY_RECORD, nextRecomputeTimeKey);
721
+ ```
722
+
723
+ ### Dictionary.create()
724
+
725
+ Create global dictionary for storing system-wide state and values.
726
+
727
+ **Syntax**
728
+ ```typescript
729
+ Dictionary.create(config: DictionaryConfig): KlassInstance<typeof Dictionary>
730
+ ```
731
+
732
+ **Parameters**
733
+ - `config.name` (string, required): Dictionary name
734
+ - `config.type` (string, required): Value type, must be one of PropertyTypes (e.g., 'string', 'number', 'boolean', 'object', etc.)
735
+ - `config.collection` (boolean, required): Whether it's a collection type, defaults to false
736
+ - `config.args` (object, optional): Type-specific arguments (e.g., string length, number range)
737
+ - `config.defaultValue` (function, optional): Default value generator function
738
+ - `config.computation` (Computation, optional): Reactive computation for the dictionary value
739
+
740
+ **Examples**
741
+ ```typescript
742
+ // Simple global counter
743
+ const userCountDict = Dictionary.create({
744
+ name: 'userCount',
745
+ type: 'number',
746
+ collection: false,
747
+ defaultValue: () => 0,
748
+ computation: Count.create({
749
+ record: User
750
+ })
751
+ })
752
+
753
+ // System configuration
754
+ const systemConfig = Dictionary.create({
755
+ name: 'config',
756
+ type: 'object',
757
+ collection: false,
758
+ defaultValue: () => ({
759
+ maxUsers: 1000,
760
+ maintenanceMode: false
761
+ })
762
+ })
763
+
764
+ // Real-time values
765
+ const currentTime = Dictionary.create({
766
+ name: 'currentTime',
767
+ type: 'number',
768
+ collection: false,
769
+ computation: RealTime.create({
770
+ nextRecomputeTime: () => 1000, // Update every second
771
+ callback: async (now) => {
772
+ return now.divide(1000);
773
+ }
774
+ })
775
+ })
776
+
777
+ // Collection type dictionary
778
+ const activeUsers = Dictionary.create({
779
+ name: 'activeUsers',
780
+ type: 'string',
781
+ collection: true,
782
+ defaultValue: () => [],
783
+ computation: Transform.create({
784
+ record: User,
785
+ attributeQuery: ['id', 'lastLoginTime'],
786
+ callback: (users) => {
787
+ const oneHourAgo = Date.now() - 3600000;
788
+ return users
789
+ .filter(u => u.lastLoginTime > oneHourAgo)
790
+ .map(u => u.id);
791
+ }
792
+ })
793
+ })
794
+ ```
795
+
796
+ **Usage in Controller**
797
+
798
+ Dictionaries are passed as the 6th parameter to Controller:
799
+
800
+ ```typescript
801
+ const controller = new Controller({
802
+ system: system,
803
+ entities: entities,
804
+ relations: relations,
805
+ activities: activities,
806
+ interactions: interactions,
807
+ dict: [userCountDict, systemConfig, currentTime, activeUsers],, // Dictionaries
808
+ recordMutationSideEffects: []
809
+ });
810
+ ```
811
+
812
+ ### StateNode.create()
813
+
814
+ Create state node for state machine computation.
815
+
816
+ **Syntax**
817
+ ```typescript
818
+ StateNode.create(config: StateNodeConfig): KlassInstance<typeof StateNode>
819
+ ```
820
+
821
+ **Parameters**
822
+ - `config.name` (string, required): State name identifier
823
+ - `config.computeValue` (function, optional): Function to compute value for this state
824
+
825
+ **Examples**
826
+ ```typescript
827
+ // Simple state node
828
+ const pendingState = StateNode.create({ name: 'pending' });
829
+
830
+ // State node with computed value
831
+ const activeState = StateNode.create({
832
+ name: 'active',
833
+ computeValue: (context) => {
834
+ // Compute state-specific value
835
+ return {
836
+ activatedAt: Date.now(),
837
+ priority: context.priority || 'normal'
838
+ };
839
+ }
840
+ });
841
+ ```
842
+
843
+ ### StateTransfer.create()
844
+
845
+ Create state transfer for state machine computation.
846
+
847
+ **Syntax**
848
+ ```typescript
849
+ StateTransfer.create(config: StateTransferConfig): KlassInstance<typeof StateTransfer>
850
+ ```
851
+
852
+ **Parameters**
853
+ - `config.trigger` (any, required): Trigger for the state transfer (usually an Interaction)
854
+ - `config.current` (StateNode, required): Current state node
855
+ - `config.next` (StateNode, required): Next state node
856
+ - `config.computeTarget` (function, optional): Function to dynamically compute the target state
857
+
858
+ **Examples**
859
+ ```typescript
860
+ // Simple state transfer
861
+ const approveTransfer = StateTransfer.create({
862
+ trigger: ApproveInteraction,
863
+ current: pendingState,
864
+ next: approvedState
865
+ });
866
+
867
+ // State transfer with dynamic target computation
868
+ const conditionalTransfer = StateTransfer.create({
869
+ trigger: ProcessInteraction,
870
+ current: pendingState,
871
+ next: approvedState, // Default next state
872
+ computeTarget: (context) => {
873
+ // Dynamically determine next state based on context
874
+ if (context.autoApprove) {
875
+ return approvedState;
876
+ } else if (context.requiresReview) {
877
+ return reviewState;
878
+ }
879
+ return rejectedState;
880
+ }
881
+ });
882
+ ```
883
+
884
+ ## 13.3 Interaction-Related APIs
885
+
886
+ ### Interaction.create()
887
+
888
+ Create user interaction definition.
889
+
890
+ **Syntax**
891
+ ```typescript
892
+ Interaction.create(config: InteractionConfig): KlassInstance<typeof Interaction>
893
+ ```
894
+
895
+ **Parameters**
896
+ - `config.name` (string, required): Interaction name
897
+ - `config.action` (Action, required): Interaction action
898
+ - `config.payload` (Payload, optional): Interaction parameters
899
+ - `config.conditions` (Condition|Conditions, optional): Execution conditions
900
+ - `config.sideEffects` (SideEffect[], optional): Side effect handlers
901
+ - `config.data` (Entity|Relation, optional): Associated data entity
902
+ - `config.query` (Query, optional): Query definition for data fetching
903
+
904
+ **Examples**
905
+ ```typescript
906
+ // Create post interaction
907
+ const CreatePostInteraction = Interaction.create({
908
+ name: 'createPost',
909
+ action: Action.create({ name: 'create' }),
910
+ payload: Payload.create({
911
+ items: [
912
+ PayloadItem.create({
913
+ name: 'postData',
914
+ base: Post,
915
+ required: true
916
+ })
917
+ ]
918
+ })
919
+ })
920
+ ```
921
+
922
+ ### Action.create()
923
+
924
+ Create interaction action identifier.
925
+
926
+ ⚠️ **Important: Action is not an "operation" but an identifier**
927
+
928
+ Action is just a name for interaction types, like event type labels. It contains no operation logic or execution code.
929
+
930
+ **Syntax**
931
+ ```typescript
932
+ Action.create(config: ActionConfig): KlassInstance<typeof Action>
933
+ ```
934
+
935
+ **Parameters**
936
+ - `config.name` (string, required): Action type identifier name
937
+
938
+ **Examples**
939
+ ```typescript
940
+ // These are just identifiers, containing no operation logic
941
+ const CreateAction = Action.create({ name: 'create' })
942
+ const UpdateAction = Action.create({ name: 'update' })
943
+ const DeleteAction = Action.create({ name: 'delete' })
944
+ const LikeAction = Action.create({ name: 'like' })
945
+
946
+ // ❌ Wrong understanding: thinking Action contains operation logic
947
+ const WrongAction = Action.create({
948
+ name: 'create',
949
+ execute: () => { /* ... */ } // ❌ Action has no execute method!
950
+ })
951
+
952
+ // ✅ Correct understanding: Action is just an identifier
953
+ const CorrectAction = Action.create({
954
+ name: 'create' // That's it!
955
+ })
956
+ ```
957
+
958
+ **Where is the operation logic?**
959
+
960
+ All operation logic is implemented through reactive computations (Transform, Count, etc.):
961
+
962
+ ```typescript
963
+ // Interaction just declares that users can create posts
964
+ const CreatePost = Interaction.create({
965
+ name: 'CreatePost',
966
+ action: Action.create({ name: 'create' }), // Just an identifier
967
+ payload: Payload.create({ /* ... */ })
968
+ });
969
+
970
+ // The actual "create" logic is in Transform
971
+ const UserPostRelation = Relation.create({
972
+ source: User,
973
+ target: Post,
974
+ computation: Transform.create({
975
+ record: InteractionEventEntity,
976
+ callback: (event) => {
977
+ if (event.interactionName === 'CreatePost') {
978
+ // This is where the actual creation logic is
979
+ return {
980
+ source: event.user.id,
981
+ target: {
982
+ title: event.payload.title,
983
+ content: event.payload.content
984
+ }
985
+ };
986
+ }
987
+ }
988
+ })
989
+ });
990
+ ```
991
+
992
+ ### Payload.create()
993
+
994
+ Create interaction parameter definition.
995
+
996
+ **Syntax**
997
+ ```typescript
998
+ Payload.create(config: PayloadConfig): KlassInstance<typeof Payload>
999
+ ```
1000
+
1001
+ **Parameters**
1002
+ - `config.items` (PayloadItem[], required): Parameter item list, defaults to empty array
1003
+
1004
+ **Examples**
1005
+ ```typescript
1006
+ const CreateUserPayload = Payload.create({
1007
+ items: [
1008
+ PayloadItem.create({
1009
+ name: 'userData',
1010
+ base: User,
1011
+ required: true
1012
+ }),
1013
+ PayloadItem.create({
1014
+ name: 'profileData',
1015
+ base: Profile,
1016
+ required: false
1017
+ })
1018
+ ]
1019
+ })
1020
+ ```
1021
+
1022
+ ### PayloadItem.create()
1023
+
1024
+ Create interaction parameter item.
1025
+
1026
+ **Syntax**
1027
+ ```typescript
1028
+ PayloadItem.create(config: PayloadItemConfig): KlassInstance<typeof PayloadItem>
1029
+ ```
1030
+
1031
+ **Parameters**
1032
+ - `config.name` (string, required): Parameter name
1033
+ - `config.base` (Entity, optional): Parameter entity type, only needed when isRef is true
1034
+ - `config.isRef` (boolean, optional): Whether it's a reference type, defaults to false
1035
+ - `config.required` (boolean, optional): Whether it's required, defaults to false
1036
+ - `config.isCollection` (boolean, optional): Whether it's a collection type, defaults to false
1037
+ - `config.attributives` (Attributive|Attributives, optional): Parameter permission attributives
1038
+ - `config.itemRef` (Attributive|Entity, optional): Used to reference entities defined in other interactions within Activity
1039
+
1040
+ **Examples**
1041
+ ```typescript
1042
+ // Reference existing user
1043
+ const userRef = PayloadItem.create({
1044
+ name: 'user',
1045
+ base: User,
1046
+ isRef: true,
1047
+ required: true
1048
+ })
1049
+
1050
+ // Create new post data
1051
+ const postData = PayloadItem.create({
1052
+ name: 'postData',
1053
+ base: Post,
1054
+ required: true,
1055
+ attributives: Attributive.create({
1056
+ name: 'ValidPost',
1057
+ content: function(post) {
1058
+ return post.title && post.content
1059
+ }
1060
+ })
1061
+ })
1062
+
1063
+ // Collection type reference
1064
+ const reviewersItem = PayloadItem.create({
1065
+ name: 'reviewers',
1066
+ base: User,
1067
+ isRef: true,
1068
+ isCollection: true,
1069
+ attributives: Attributives.create({
1070
+ content: BoolAtomData.create({data: ReviewerAttr, type: 'atom'})
1071
+ })
1072
+ })
1073
+
1074
+ // Activity item reference
1075
+ const activityItem = PayloadItem.create({
1076
+ name: 'to',
1077
+ base: User,
1078
+ isRef: true,
1079
+ attributives: boolExpToAttributives(BoolExp.atom(OtherAttr)),
1080
+ itemRef: userRefB
1081
+ })
1082
+ ```
1083
+
1084
+ ## 13.4 Activity-Related APIs
1085
+
1086
+ ### Activity.create()
1087
+
1088
+ Create business activity definition.
1089
+
1090
+ **Syntax**
1091
+ ```typescript
1092
+ Activity.create(config: ActivityConfig): KlassInstance<typeof Activity>
1093
+ ```
1094
+
1095
+ **Parameters**
1096
+ - `config.name` (string, required): Activity name
1097
+ - `config.interactions` (Interaction[], optional): List of interactions in the activity
1098
+ - `config.transfers` (Transfer[], optional): List of state transfers
1099
+ - `config.groups` (ActivityGroup[], optional): List of activity groups
1100
+ - `config.gateways` (Gateway[], optional): List of gateways
1101
+ - `config.events` (Event[], optional): List of events
1102
+
1103
+ **Examples**
1104
+ ```typescript
1105
+ const OrderProcessActivity = Activity.create({
1106
+ name: 'OrderProcess',
1107
+ interactions: [
1108
+ CreateOrderInteraction,
1109
+ ConfirmOrderInteraction,
1110
+ PayOrderInteraction,
1111
+ ShipOrderInteraction
1112
+ ],
1113
+ transfers: [
1114
+ Transfer.create({
1115
+ name: 'createToConfirm',
1116
+ source: CreateOrderInteraction,
1117
+ target: ConfirmOrderInteraction
1118
+ }),
1119
+ Transfer.create({
1120
+ name: 'confirmToPay',
1121
+ source: ConfirmOrderInteraction,
1122
+ target: PayOrderInteraction
1123
+ })
1124
+ ]
1125
+ })
1126
+ ```
1127
+
1128
+ ### Transfer.create()
1129
+
1130
+ Create activity state transfer.
1131
+
1132
+ **Syntax**
1133
+ ```typescript
1134
+ Transfer.create(config: TransferConfig): KlassInstance<typeof Transfer>
1135
+ ```
1136
+
1137
+ **Parameters**
1138
+ - `config.name` (string, required): Transfer name
1139
+ - `config.source` (Interaction|ActivityGroup|Gateway, required): Source node
1140
+ - `config.target` (Interaction|ActivityGroup|Gateway, required): Target node
1141
+
1142
+ **Examples**
1143
+ ```typescript
1144
+ const ApprovalTransfer = Transfer.create({
1145
+ name: 'submitToApprove',
1146
+ source: SubmitApplicationInteraction,
1147
+ target: ApproveApplicationInteraction
1148
+ })
1149
+ ```
1150
+
1151
+ ### Condition.create()
1152
+
1153
+ Create activity execution condition.
1154
+
1155
+ **Syntax**
1156
+ ```typescript
1157
+ Condition.create(config: ConditionConfig): KlassInstance<typeof Condition>
1158
+ ```
1159
+
1160
+ **Parameters**
1161
+ - `config.name` (string, required): Condition name
1162
+ - `config.content` (function, required): Condition judgment function
1163
+
1164
+ **Examples**
1165
+ ```typescript
1166
+ const OrderValueCondition = Condition.create({
1167
+ name: 'highValueOrder',
1168
+ content: function(order) {
1169
+ return order.totalAmount > 1000
1170
+ }
1171
+ })
1172
+ ```
1173
+
1174
+ ## 13.5 System-Related APIs
1175
+
1176
+ ### Controller
1177
+
1178
+ System controller that coordinates the work of various components.
1179
+
1180
+ **Constructor**
1181
+ ```typescript
1182
+ new Controller({
1183
+ system: System,
1184
+ entities: KlassInstance<typeof Entity>[],
1185
+ relations: KlassInstance<typeof Relation>[],
1186
+ activities: KlassInstance<typeof Activity>[],
1187
+ interactions: KlassInstance<typeof Interaction>[],
1188
+ dict?: KlassInstance<typeof Property>[], // Note: This is for global dictionaries, NOT computations
1189
+ recordMutationSideEffects?: RecordMutationSideEffect[]
1190
+ })
1191
+ ```
1192
+
1193
+ ⚠️ **IMPORTANT**: Controller does NOT accept a computations parameter. All computations should be defined within the `computation` field of Entity/Relation/Property definitions. The 6th parameter `dict` is for global dictionary definitions (Dictionary.create), not for computation definitions.
1194
+
1195
+ **Main Methods**
1196
+
1197
+ #### setup(install?: boolean)
1198
+ Initialize system.
1199
+ ```typescript
1200
+ await controller.setup(true) // Create database tables
1201
+ ```
1202
+
1203
+ #### callInteraction(interactionName: string, args: InteractionEventArgs)
1204
+ Call interaction.
1205
+ ```typescript
1206
+ const result = await controller.callInteraction('createPost', {
1207
+ user: { id: 'user1' },
1208
+ payload: { postData: { title: 'Hello', content: 'World' } }
1209
+ })
1210
+ ```
1211
+
1212
+ #### callActivityInteraction(activityName: string, interactionName: string, activityId: string, args: InteractionEventArgs)
1213
+ Call interaction within activity.
1214
+ ```typescript
1215
+ const result = await controller.callActivityInteraction(
1216
+ 'OrderProcess',
1217
+ 'confirmOrder',
1218
+ 'activity-instance-1',
1219
+ { user: { id: 'user1' }, payload: { orderData: {...} } }
1220
+ )
1221
+ ```
1222
+
1223
+ ### System
1224
+
1225
+ System abstract interface that defines basic services like storage and logging.
1226
+
1227
+ **Interface Definition**
1228
+ ```typescript
1229
+ interface System {
1230
+ conceptClass: Map<string, ReturnType<typeof createClass>>
1231
+ storage: Storage
1232
+ logger: SystemLogger
1233
+ setup: (entities: Entity[], relations: Relation[], states: ComputationState[], install?: boolean) => Promise<any>
1234
+ }
1235
+ ```
1236
+
1237
+ ### Storage
1238
+
1239
+ Storage layer interface providing data persistence functionality.
1240
+
1241
+ **Main Methods**
1242
+
1243
+ #### Entity/Relation Operations
1244
+
1245
+ 🔴 **CRITICAL: Always specify attributeQuery parameter!**
1246
+ - Without `attributeQuery`, only the `id` field is returned
1247
+ - This is a common source of bugs in tests and applications
1248
+ - Always explicitly list all fields you need
1249
+
1250
+ ```typescript
1251
+ // ❌ WRONG: Only returns { id: '...' }
1252
+ const user = await storage.findOne('User', MatchExp.atom({
1253
+ key: 'email',
1254
+ value: ['=', 'user@example.com']
1255
+ }))
1256
+ console.log(user.name) // undefined!
1257
+
1258
+ // ✅ CORRECT: Returns all specified fields
1259
+ const user = await storage.findOne('User',
1260
+ MatchExp.atom({
1261
+ key: 'email',
1262
+ value: ['=', 'user@example.com']
1263
+ }),
1264
+ undefined, // modifier
1265
+ ['id', 'name', 'email', 'role', 'createdAt'] // attributeQuery
1266
+ )
1267
+ console.log(user.name) // 'John Doe' ✓
1268
+
1269
+ // Create record
1270
+ await storage.create('User', { username: 'john', email: 'john@example.com' })
1271
+
1272
+ // Find single record (MUST specify attributeQuery!)
1273
+ const user = await storage.findOne('User', MatchExp.atom({
1274
+ key: 'username',
1275
+ value: ['=', 'john']
1276
+ }), undefined, ['id', 'username', 'email', 'status'])
1277
+
1278
+ // Find multiple records (MUST specify attributeQuery!)
1279
+ const users = await storage.find('User', MatchExp.atom({
1280
+ key: 'status',
1281
+ value: ['=', 'active']
1282
+ }), undefined, ['id', 'username', 'email', 'lastLoginDate'])
1283
+
1284
+ // Update record
1285
+ await storage.update('User', MatchExp.atom({
1286
+ key: 'id',
1287
+ value: ['=', 'user1']
1288
+ }), { status: 'inactive' })
1289
+
1290
+ // Delete record
1291
+ await storage.delete('User', MatchExp.atom({
1292
+ key: 'id',
1293
+ value: ['=', 'user1']
1294
+ }))
1295
+ ```
1296
+
1297
+ #### KV Storage Operations
1298
+ ```typescript
1299
+ // Set value
1300
+ await storage.set('config', 'maxUsers', 1000)
1301
+
1302
+ // Get value
1303
+ const maxUsers = await storage.get('config', 'maxUsers', 100) // Default value 100
1304
+ ```
1305
+
1306
+ ## 13.6 Utility Function APIs
1307
+
1308
+ ### MatchExp
1309
+
1310
+ Query expression builder for constructing complex query conditions.
1311
+
1312
+ #### MatchExp.atom(condition: MatchAtom)
1313
+ Create atomic query condition.
1314
+
1315
+ **Parameters**
1316
+ - `condition.key` (string): Field name, supports dot notation like 'user.profile.name'
1317
+ - `condition.value` ([string, any]): Array of operator and value
1318
+ - `condition.isReferenceValue` (boolean, optional): Whether it's a reference value
1319
+
1320
+ **Supported Operators**
1321
+ - `['=', value]`: Equals
1322
+ - `['!=', value]`: Not equals
1323
+ - `['>', value]`: Greater than
1324
+ - `['<', value]`: Less than
1325
+ - `['>=', value]`: Greater than or equal
1326
+ - `['<=', value]`: Less than or equal
1327
+ - `['like', pattern]`: Pattern matching
1328
+ - `['in', array]`: In array
1329
+ - `['between', [min, max]]`: In range
1330
+ - `['not', null]`: Not null
1331
+
1332
+ **Examples**
1333
+ ```typescript
1334
+ // Basic condition
1335
+ const condition1 = MatchExp.atom({
1336
+ key: 'status',
1337
+ value: ['=', 'active']
1338
+ })
1339
+
1340
+ // Range query
1341
+ const condition2 = MatchExp.atom({
1342
+ key: 'age',
1343
+ value: ['between', [18, 65]]
1344
+ })
1345
+
1346
+ // Relational query
1347
+ const condition3 = MatchExp.atom({
1348
+ key: 'user.profile.city',
1349
+ value: ['=', 'Beijing']
1350
+ })
1351
+
1352
+ // Combined conditions
1353
+ const complexCondition = MatchExp.atom({
1354
+ key: 'status',
1355
+ value: ['=', 'active']
1356
+ }).and({
1357
+ key: 'age',
1358
+ value: ['>', 18]
1359
+ }).or({
1360
+ key: 'vip',
1361
+ value: ['=', true]
1362
+ })
1363
+ ```
1364
+
1365
+ #### MatchExp.fromObject(condition: Object)
1366
+ Create query condition from object (all conditions connected with AND).
1367
+
1368
+ ```typescript
1369
+ const condition = MatchExp.fromObject({
1370
+ status: 'active',
1371
+ age: 25,
1372
+ city: 'Beijing'
1373
+ })
1374
+ // Equivalent to: status='active' AND age=25 AND city='Beijing'
1375
+ ```
1376
+
1377
+ ### Attributive.create()
1378
+
1379
+ Create permission attributive for access control.
1380
+
1381
+ **Syntax**
1382
+ ```typescript
1383
+ Attributive.create(config: AttributiveConfig): KlassInstance<typeof Attributive>
1384
+ ```
1385
+
1386
+ **Parameters**
1387
+ - `config.name` (string, optional): Attributive name
1388
+ - `config.content` (function, required): Permission judgment function
1389
+ - `config.isRef` (boolean, optional): Whether it's a reference
1390
+
1391
+ **Examples**
1392
+ ```typescript
1393
+ // Admin permission
1394
+ const AdminAttributive = Attributive.create({
1395
+ name: 'Admin',
1396
+ content: function(target, { user }) {
1397
+ return user.role === 'admin'
1398
+ }
1399
+ })
1400
+
1401
+ // Resource owner permission
1402
+ const OwnerAttributive = Attributive.create({
1403
+ name: 'Owner',
1404
+ content: function(target, { user }) {
1405
+ return target.userId === user.id
1406
+ }
1407
+ })
1408
+
1409
+ // Combined permissions (using BoolExp)
1410
+ const AdminOrOwnerAttributives = boolExpToAttributives(
1411
+ BoolExp.atom(AdminAttributive).or(OwnerAttributive)
1412
+ )
1413
+ ```
1414
+
1415
+ ### BoolExp
1416
+
1417
+ Boolean expression builder for constructing complex logical expressions.
1418
+
1419
+ #### BoolExp.atom(data: T)
1420
+ Create atomic expression.
1421
+
1422
+ ```typescript
1423
+ const expr1 = BoolExp.atom({ condition: 'isActive' })
1424
+ const expr2 = BoolExp.atom({ condition: 'isAdmin' })
1425
+
1426
+ // Combined expression
1427
+ const combined = expr1.and(expr2).or({ condition: 'isOwner' })
1428
+ ```
1429
+
1430
+ ## Type Definitions
1431
+
1432
+ ### Core Types
1433
+
1434
+ ```typescript
1435
+ // Entity instance types
1436
+ type EntityInstance = KlassInstance<typeof Entity>
1437
+ type RelationInstance = KlassInstance<typeof Relation>
1438
+ type InteractionInstance = KlassInstance<typeof Interaction>
1439
+ type ActivityInstance = KlassInstance<typeof Activity>
1440
+
1441
+ // Interaction event arguments
1442
+ type InteractionEventArgs = {
1443
+ user: { id: string, [key: string]: any }
1444
+ payload?: { [key: string]: any }
1445
+ [key: string]: any
1446
+ }
1447
+
1448
+ // Record mutation event
1449
+ type RecordMutationEvent = {
1450
+ recordName: string
1451
+ type: 'create' | 'update' | 'delete'
1452
+ record?: EntityIdRef & { [key: string]: any }
1453
+ oldRecord?: EntityIdRef & { [key: string]: any }
1454
+ }
1455
+
1456
+ // Entity reference
1457
+ type EntityIdRef = {
1458
+ id: string
1459
+ _rowId?: string
1460
+ [key: string]: any
1461
+ }
1462
+
1463
+ // Attribute query data
1464
+ type AttributeQueryData = (string | [string, { attributeQuery?: AttributeQueryData }])[]
1465
+ ```
1466
+
1467
+ ### Computation-Related Types
1468
+
1469
+ ```typescript
1470
+ // Computation context
1471
+ type DataContext = {
1472
+ type: 'global' | 'entity' | 'relation' | 'property'
1473
+ id: string | Entity | Relation
1474
+ host?: Entity | Relation
1475
+ }
1476
+
1477
+ // Computation dependency
1478
+ type DataDep = {
1479
+ type: 'records' | 'property'
1480
+ source?: Entity | Relation
1481
+ attributeQuery?: AttributeQueryData
1482
+ }
1483
+
1484
+ // Computation result
1485
+ type ComputationResult = any
1486
+ type ComputationResultPatch = {
1487
+ type: 'insert' | 'update' | 'delete'
1488
+ data?: any
1489
+ affectedId?: string
1490
+ }
1491
+ ```
1492
+
1493
+ ## Usage Examples
1494
+
1495
+ ### Complete Blog System Example
1496
+
1497
+ ```typescript
1498
+ import { Entity, Property, Relation, Interaction, Activity, Controller } from 'interaqt'
1499
+
1500
+ // 1. Define entities
1501
+ const User = Entity.create({
1502
+ name: 'User',
1503
+ properties: [
1504
+ Property.create({ name: 'username', type: 'string' }),
1505
+ Property.create({ name: 'email', type: 'string' }),
1506
+ Property.create({
1507
+ name: 'postCount',
1508
+ type: 'number',
1509
+ computation: Count.create({ record: UserPostRelation })
1510
+ })
1511
+ ]
1512
+ })
1513
+
1514
+ const Post = Entity.create({
1515
+ name: 'Post',
1516
+ properties: [
1517
+ Property.create({ name: 'title', type: 'string' }),
1518
+ Property.create({ name: 'content', type: 'string' }),
1519
+ Property.create({
1520
+ name: 'likeCount',
1521
+ type: 'number',
1522
+ computation: Count.create({ record: PostLikeRelation })
1523
+ })
1524
+ ]
1525
+ })
1526
+
1527
+ // 2. Define relations
1528
+ const UserPostRelation = Relation.create({
1529
+ source: User,
1530
+ sourceProperty: 'posts',
1531
+ target: Post,
1532
+ targetProperty: 'author',
1533
+ type: '1:n'
1534
+ })
1535
+
1536
+ const PostLikeRelation = Relation.create({
1537
+ source: Post,
1538
+ sourceProperty: 'likes',
1539
+ target: User,
1540
+ targetProperty: 'likedPosts',
1541
+ type: 'n:n'
1542
+ })
1543
+
1544
+ // 3. Define interactions
1545
+ const CreatePostInteraction = Interaction.create({
1546
+ name: 'createPost',
1547
+ action: Action.create({ name: 'create' }),
1548
+ payload: Payload.create({
1549
+ items: [
1550
+ PayloadItem.create({
1551
+ name: 'postData',
1552
+ base: Post,
1553
+ required: true
1554
+ })
1555
+ ]
1556
+ })
1557
+ })
1558
+
1559
+ const LikePostInteraction = Interaction.create({
1560
+ name: 'likePost',
1561
+ action: Action.create({ name: 'create' }),
1562
+ payload: Payload.create({
1563
+ items: [
1564
+ PayloadItem.create({
1565
+ name: 'post',
1566
+ base: Post,
1567
+ isRef: true,
1568
+ required: true
1569
+ })
1570
+ ]
1571
+ })
1572
+ })
1573
+
1574
+ // 4. Create controller and initialize system
1575
+ const controller = new Controller({
1576
+ system, // System implementation
1577
+ entities: [User, Post], // Entities
1578
+ relations: [UserPostRelation, PostLikeRelation], // Relations
1579
+ activities: [], // Activities
1580
+ interactions: [CreatePostInteraction, LikePostInteraction] // Interactions
1581
+ })
1582
+
1583
+ await controller.setup(true)
1584
+
1585
+ // 5. Use APIs
1586
+ // Create post
1587
+ const result = await controller.callInteraction('createPost', {
1588
+ user: { id: 'user1' },
1589
+ payload: {
1590
+ postData: {
1591
+ title: 'Hello World',
1592
+ content: 'This is my first post!'
1593
+ }
1594
+ }
1595
+ })
1596
+
1597
+ // Like post
1598
+ await controller.callInteraction('likePost', {
1599
+ user: { id: 'user2' },
1600
+ payload: {
1601
+ post: { id: result.recordId }
1602
+ }
1603
+ })
1604
+ ```
1605
+
1606
+ This API reference documentation covers all core APIs of the interaqt framework, providing complete parameter descriptions and practical usage examples. Developers can quickly get started and deeply use various framework features based on this documentation.