interaqt 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/agent/agentspace/knowledge/generator/api-reference.md +19 -21
  2. package/agent/agentspace/knowledge/generator/computation-implementation.md +6 -0
  3. package/agent/agentspace/knowledge/generator/integration-implementation-handler.md +2 -0
  4. package/agent/agentspace/knowledge/usage/04-reactive-computations.md +8 -0
  5. package/agent/agentspace/knowledge/usage/05-interactions.md +13 -0
  6. package/agent/agentspace/knowledge/usage/10-async-computations.md +13 -0
  7. package/agent/agentspace/knowledge/usage/13-testing.md +12 -2
  8. package/agent/agentspace/knowledge/usage/14-api-reference.md +10 -0
  9. package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +6 -1
  10. package/agent/agentspace/knowledge/usage/20-postgresql-concurrency-migration.md +105 -0
  11. package/agent/agentspace/knowledge/usage/README.md +1 -0
  12. package/agent/skill/interaqt-patterns.md +41 -36
  13. package/agent/skill/interaqt-recipes.md +164 -108
  14. package/agent/skill/interaqt-reference.md +264 -75
  15. package/dist/core/Custom.d.ts +18 -0
  16. package/dist/core/Custom.d.ts.map +1 -1
  17. package/dist/core/EventSource.d.ts +17 -0
  18. package/dist/core/EventSource.d.ts.map +1 -1
  19. package/dist/drivers/PGLite.d.ts +2 -0
  20. package/dist/drivers/PGLite.d.ts.map +1 -1
  21. package/dist/drivers/PostgreSQL.d.ts +27 -5
  22. package/dist/drivers/PostgreSQL.d.ts.map +1 -1
  23. package/dist/drivers/SQLite.d.ts +2 -0
  24. package/dist/drivers/SQLite.d.ts.map +1 -1
  25. package/dist/index.js +3651 -3042
  26. package/dist/index.js.map +1 -1
  27. package/dist/runtime/ComputationSourceMap.d.ts.map +1 -1
  28. package/dist/runtime/Controller.d.ts +1 -0
  29. package/dist/runtime/Controller.d.ts.map +1 -1
  30. package/dist/runtime/MonoSystem.d.ts +2 -0
  31. package/dist/runtime/MonoSystem.d.ts.map +1 -1
  32. package/dist/runtime/Scheduler.d.ts +14 -1
  33. package/dist/runtime/Scheduler.d.ts.map +1 -1
  34. package/dist/runtime/System.d.ts +40 -6
  35. package/dist/runtime/System.d.ts.map +1 -1
  36. package/dist/runtime/computations/Any.d.ts.map +1 -1
  37. package/dist/runtime/computations/Average.d.ts +2 -2
  38. package/dist/runtime/computations/Average.d.ts.map +1 -1
  39. package/dist/runtime/computations/Computation.d.ts +17 -0
  40. package/dist/runtime/computations/Computation.d.ts.map +1 -1
  41. package/dist/runtime/computations/Count.d.ts +5 -1
  42. package/dist/runtime/computations/Count.d.ts.map +1 -1
  43. package/dist/runtime/computations/Every.d.ts +1 -2
  44. package/dist/runtime/computations/Every.d.ts.map +1 -1
  45. package/dist/runtime/computations/StateMachine.d.ts.map +1 -1
  46. package/dist/runtime/computations/Summation.d.ts +3 -1
  47. package/dist/runtime/computations/Summation.d.ts.map +1 -1
  48. package/dist/runtime/computations/Transform.d.ts.map +1 -1
  49. package/dist/runtime/computations/WeightedSummation.d.ts +3 -1
  50. package/dist/runtime/computations/WeightedSummation.d.ts.map +1 -1
  51. package/dist/runtime/index.d.ts +1 -0
  52. package/dist/runtime/index.d.ts.map +1 -1
  53. package/dist/runtime/transaction.d.ts +15 -0
  54. package/dist/runtime/transaction.d.ts.map +1 -0
  55. package/dist/storage/erstorage/EntityQueryHandle.d.ts +1 -0
  56. package/dist/storage/erstorage/EntityQueryHandle.d.ts.map +1 -1
  57. package/dist/storage/erstorage/QueryExecutor.d.ts +1 -1
  58. package/dist/storage/erstorage/QueryExecutor.d.ts.map +1 -1
  59. package/dist/storage/erstorage/RecordQueryAgent.d.ts +1 -0
  60. package/dist/storage/erstorage/RecordQueryAgent.d.ts.map +1 -1
  61. package/package.json +2 -1
@@ -8,18 +8,21 @@
8
8
 
9
9
  ```typescript
10
10
  Entity.create(args: {
11
- name: string // PascalCase, singular, unique
12
- properties: PropertyInstance[] // Array of Property.create() results
11
+ name: string // PascalCase, singular, unique, must match /^[a-zA-Z0-9_]+$/
12
+ properties?: PropertyInstance[] // Array of Property.create() results (defaults to [])
13
13
  computation?: ComputationInstance // Transform for derived entities
14
- baseEntity?: EntityInstance // For filtered entities
15
- filterCondition?: MatchExp // For filtered entities
14
+ baseEntity?: EntityInstance | RelationInstance // For filtered entities
15
+ matchExpression?: MatchExp // Filter condition for filtered entities
16
+ inputEntities?: EntityInstance[] // For merged entities
17
+ commonProperties?: PropertyInstance[] // Shared attributes for merged entities
16
18
  }): EntityInstance
17
19
  ```
18
20
 
19
21
  Constraints:
20
22
  - NEVER pass `uuid` — the framework generates it
21
- - `name` must match `/^[a-zA-Z0-9_]+$/`
22
23
  - `computation` accepts only Transform (for creating derived entity collections)
24
+ - **Filtered entity**: set `baseEntity` + `matchExpression`
25
+ - **Merged entity**: set `inputEntities` + `commonProperties` (cannot define own `properties`)
23
26
 
24
27
  ---
25
28
 
@@ -27,21 +30,21 @@ Constraints:
27
30
 
28
31
  ```typescript
29
32
  Property.create(args: {
30
- name: string // Property name
31
- type?: 'string' | 'number' | 'boolean' | 'object'
33
+ name: string // Must match /^[a-zA-Z0-9_]+$/
34
+ type: string // Required: 'string' | 'number' | 'boolean' | 'object'
32
35
  collection?: boolean // true for array types
33
- defaultValue?: any | (() => any) // Static value or factory function
34
- getValue?: (record: any) => any // Computed from same-record fields (not persisted)
35
- computed?: (record: any) => any // Alias for getValue
36
- computation?: ComputationInstance // Reactive: Count, WeightedSummation, Every, Any, StateMachine
36
+ defaultValue?: Function // Factory function returning default value
37
+ computed?: (record: any) => any // Computed from same-record fields (not persisted)
38
+ computation?: ComputationInstance // Reactive: Count, Summation, WeightedSummation, Every, Any, StateMachine, Custom
37
39
  }): PropertyInstance
38
40
  ```
39
41
 
40
42
  Constraints:
41
- - `getValue`/`computed` are for same-record derivations only — NOT persisted
43
+ - `type` is REQUIRED always specify it
44
+ - `computed` is for same-record derivations only — NOT persisted
42
45
  - `computation` results ARE persisted and auto-updated
43
- - When using `computation`, ALWAYS provide `defaultValue`
44
- - NEVER use Transform on Property `computation` — Transform belongs on Entity `computation`
46
+ - When using `computation`, provide `defaultValue`
47
+ - NEVER use Transform on Property `computation` — Transform belongs on Entity/Relation `computation`
45
48
 
46
49
  ---
47
50
 
@@ -49,20 +52,33 @@ Constraints:
49
52
 
50
53
  ```typescript
51
54
  Relation.create(args: {
52
- source: EntityInstance // Source entity
55
+ // Base relation (all required for normal relations):
56
+ name?: string // Optional — auto-generated if omitted
57
+ source: EntityInstance | RelationInstance
53
58
  sourceProperty: string // Navigation property on source
54
- target: EntityInstance // Target entity
59
+ target: EntityInstance | RelationInstance
55
60
  targetProperty: string // Navigation property on target
56
61
  type: '1:1' | '1:n' | 'n:1' | 'n:n'
57
62
  properties?: PropertyInstance[] // Relation's own properties
58
63
  computation?: ComputationInstance // Transform for computed relations
64
+ isTargetReliance?: boolean // Defaults to false
65
+
66
+ // Filtered relation:
67
+ baseRelation?: RelationInstance // Base relation to filter from
68
+ matchExpression?: MatchExp // Filter condition
69
+
70
+ // Merged relation:
71
+ inputRelations?: RelationInstance[] // Relations to merge (must share same source/target)
72
+ commonProperties?: PropertyInstance[] // Shared attributes for merged relations
59
73
  }): RelationInstance
60
74
  ```
61
75
 
62
76
  Constraints:
63
- - NEVER specify `name` — auto-generated from source+target entity names
64
- - ALWAYS specify `type` explicitly
77
+ - `name` is optional — auto-generated as `${source.name}_${sourceProperty}_${targetProperty}_${target.name}`
78
+ - ALWAYS specify `type` explicitly for base relations
65
79
  - Symmetric relations: set `source === target` AND `sourceProperty === targetProperty`
80
+ - **Filtered relation**: requires `baseRelation` + `matchExpression` + `sourceProperty` + `targetProperty`
81
+ - **Merged relation**: requires `inputRelations` + `sourceProperty` + `targetProperty` (cannot specify `source`/`target`/`properties`)
66
82
 
67
83
  ---
68
84
 
@@ -73,10 +89,16 @@ Interaction.create(args: {
73
89
  name: string // Interaction identifier
74
90
  action: ActionInstance // Action.create() result (identifier only)
75
91
  payload?: PayloadInstance // Payload.create() result
76
- conditions?: ConditionInstance // Execution conditions
92
+ conditions?: ConditionsInstance | ConditionInstance // Execution conditions
93
+ data?: EntityInstance | RelationInstance // Entity/Relation to query (for data retrieval)
94
+ dataPolicy?: DataPolicyInstance // Fixed data access constraints
77
95
  }): InteractionInstance
78
96
  ```
79
97
 
98
+ Constraints:
99
+ - For data retrieval, use `GetAction` as action and specify `data`
100
+ - `conditions` accepts either a single `Condition` or a `Conditions` (combined with BoolExp)
101
+
80
102
  ---
81
103
 
82
104
  ## Action.create
@@ -89,6 +111,7 @@ Action.create(args: {
89
111
 
90
112
  Constraints:
91
113
  - Action is ONLY an identifier — no `handler`, `execute`, or `callback`
114
+ - Use `GetAction` (pre-built) for data retrieval interactions
92
115
 
93
116
  ---
94
117
 
@@ -101,37 +124,34 @@ Payload.create(args: {
101
124
 
102
125
  PayloadItem.create(args: {
103
126
  name: string // Parameter name
127
+ type: string // Required: data type
104
128
  base?: EntityInstance // Entity reference for validation
105
129
  isRef?: boolean // true = reference by ID to existing entity
106
130
  required?: boolean // true = mandatory parameter
107
131
  isCollection?: boolean // true = array of items
108
- attributives?: AttributiveInstance // Validation rules (only works when base is set)
132
+ itemRef?: AttributiveInstance | EntityInstance // Reference to entities defined in other interactions (for Activity)
109
133
  }): PayloadItemInstance
110
134
  ```
111
135
 
112
- Constraints:
113
- - Without `base`: framework only checks required/collection, no concept validation
114
- - With `base` + `isRef: true`: framework verifies entity exists by ID
115
- - With `base` + `attributives`: framework validates data against attributive rules
116
- - `attributives` are checked for EVERY item when `isCollection: true`
117
-
118
136
  ---
119
137
 
120
138
  ## Count.create
121
139
 
122
140
  ```typescript
123
141
  Count.create(args: {
124
- record: EntityInstance | RelationInstance // What to count
142
+ record?: EntityInstance | RelationInstance // What to count (for entity/global level)
143
+ property?: string // Relation property name (for property level)
125
144
  direction?: 'source' | 'target' // For relation counting
126
145
  callback?: (record: any) => boolean // Filter function
127
146
  attributeQuery?: AttributeQueryData // Fields to load for callback
128
- dataDeps?: DataDepsConfig // External data dependencies
147
+ dataDeps?: DataDependencies // External data dependencies
129
148
  }): CountInstance
130
149
  ```
131
150
 
132
151
  Constraints:
133
- - Place on Property `computation`, not Entity `computation`
134
- - ALWAYS provide `defaultValue` on the Property
152
+ - Use `record` for global/entity-level counting, `property` for property-level counting
153
+ - Place on Property `computation` or Dictionary `computation`
154
+ - Provide `defaultValue` on the Property when using as property computation
135
155
 
136
156
  ---
137
157
 
@@ -139,10 +159,12 @@ Constraints:
139
159
 
140
160
  ```typescript
141
161
  WeightedSummation.create(args: {
142
- record: RelationInstance // Relation to aggregate
143
- callback: (relation: any) => { weight: number, value: number }
162
+ record?: EntityInstance | RelationInstance // Entity/relation to aggregate (for global level)
163
+ property?: string // Relation property name (for property level)
164
+ direction?: 'source' | 'target' // For relation-based computation
165
+ callback: (record: any) => { weight: number, value: number }
144
166
  attributeQuery?: AttributeQueryData
145
- dataDeps?: DataDepsConfig
167
+ dataDeps?: DataDependencies
146
168
  }): WeightedSummationInstance
147
169
  ```
148
170
 
@@ -150,19 +172,41 @@ Result: `sum(weight * value) / sum(weight)`
150
172
 
151
173
  ---
152
174
 
175
+ ## Summation.create
176
+
177
+ ```typescript
178
+ Summation.create(args: {
179
+ record?: EntityInstance | RelationInstance // Entity/relation to sum (for global level)
180
+ property?: string // Relation property name (for property level)
181
+ direction?: 'source' | 'target' // For relation-based summation
182
+ attributeQuery: AttributeQueryData // Required: specifies field path to sum
183
+ }): SummationInstance
184
+ ```
185
+
186
+ Sums the field pointed to by the leftmost path in `attributeQuery`. Undefined/null/NaN/Infinity values are treated as 0.
187
+
188
+ ---
189
+
153
190
  ## Every.create / Any.create
154
191
 
155
192
  ```typescript
156
193
  Every.create(args: {
157
- record: RelationInstance
158
- callback: (relation: any) => boolean
194
+ record?: EntityInstance | RelationInstance // For global level
195
+ property?: string // Relation property name (for property level)
196
+ direction?: 'source' | 'target'
197
+ callback: (record: any) => boolean
159
198
  attributeQuery?: AttributeQueryData
199
+ dataDeps?: DataDependencies
200
+ notEmpty?: boolean // Return value when collection is empty
160
201
  }): EveryInstance
161
202
 
162
203
  Any.create(args: {
163
- record: RelationInstance
164
- callback: (relation: any) => boolean
204
+ record?: EntityInstance | RelationInstance
205
+ property?: string
206
+ direction?: 'source' | 'target'
207
+ callback: (record: any) => boolean
165
208
  attributeQuery?: AttributeQueryData
209
+ dataDeps?: DataDependencies
166
210
  }): AnyInstance
167
211
  ```
168
212
 
@@ -175,17 +219,33 @@ Any.create(args: {
175
219
 
176
220
  ```typescript
177
221
  Transform.create(args: {
178
- record: EntityInstance | RelationInstance // Source data
179
- callback: (record: any, dataDeps?: any) => any | null
222
+ // Mode 1: Entity/Relation Transform
223
+ record?: EntityInstance | RelationInstance // Source data
180
224
  attributeQuery?: AttributeQueryData
181
- dataDeps?: DataDepsConfig
225
+
226
+ // Mode 2: Event-Driven Transform
227
+ eventDeps?: {
228
+ [key: string]: {
229
+ recordName: string
230
+ type: 'create' | 'update' | 'delete'
231
+ record?: Record<string, unknown>
232
+ oldRecord?: Record<string, unknown>
233
+ }
234
+ }
235
+
236
+ // Common
237
+ callback: Function // (this: Controller, record/mutationEvent) => any | any[] | null
238
+ dataDeps?: { [key: string]: DataDep }
182
239
  }): TransformInstance
183
240
  ```
184
241
 
185
242
  Constraints:
186
243
  - Place on Entity `computation` or Relation `computation`, NEVER on Property
187
- - Return `null` from callback to skip (conditional transformation)
244
+ - Return `null`/`undefined` from callback to skip (conditional transformation)
245
+ - Return array to create multiple records from one source
188
246
  - NEVER reference the entity being defined as `record` (circular reference)
247
+ - Use `eventDeps` mode for interaction-based transformations (recommended)
248
+ - Use `record` mode for deriving entities from other entities
189
249
 
190
250
  ---
191
251
 
@@ -208,12 +268,16 @@ Place on Property `computation`. The property value equals the current state nod
208
268
  ```typescript
209
269
  StateNode.create(args: {
210
270
  name: string
211
- computeValue?: (lastValue: any) => any // Dynamic value when entering this state
271
+ computeValue?: (this: Controller, lastValue: any, event?: any) => any
212
272
  }): StateNodeInstance
213
273
  ```
214
274
 
215
275
  - Without `computeValue`: property value is the state name string
216
276
  - With `computeValue`: property value is the function's return value
277
+ - `lastValue`: previous property value before transition (undefined for initial state)
278
+ - `event`: the event record that triggered the transition (undefined during initialization)
279
+ - For interaction triggers: access `event.payload`, `event.user`, `event.interactionName`
280
+ - `this` is bound to the Controller instance — async functions can use `this.system.storage`
217
281
 
218
282
  ---
219
283
 
@@ -223,12 +287,28 @@ StateNode.create(args: {
223
287
  StateTransfer.create(args: {
224
288
  current: StateNodeInstance // From state
225
289
  next: StateNodeInstance // To state
226
- trigger: InteractionInstance // Interaction that causes transition
227
- computeTarget: (event: any) => { id: any } // Identifies which record to transition
290
+ trigger: RecordMutationEventPattern // Pattern to match against mutation events
291
+ computeTarget?: Function // Determines which records to transition
228
292
  }): StateTransferInstance
229
293
  ```
230
294
 
231
- `computeTarget` extracts the target entity ID from the interaction event payload.
295
+ **`trigger`** a partial pattern object, NOT an Interaction instance:
296
+ ```typescript
297
+ trigger: {
298
+ recordName: string // e.g. InteractionEventEntity.name
299
+ type: 'create' | 'update' | 'delete'
300
+ record?: Record<string, any> // deep partial match, e.g. { interactionName: myInteraction.name }
301
+ oldRecord?: Record<string, any>
302
+ keys?: string[]
303
+ }
304
+ ```
305
+
306
+ **`computeTarget`** — receives the mutation event, returns which record(s) to transition:
307
+ - Entity: `{ id: string }` or `{ id: string }[]`
308
+ - Relation: `{ source: { id: string }, target: { id: string } }`
309
+ - Return `undefined` to skip
310
+ - `this` is bound to Controller — async functions can use `this.system.storage`
311
+ - Required for property-level StateMachines; omit for global StateMachines
232
312
 
233
313
  ---
234
314
 
@@ -236,26 +316,34 @@ StateTransfer.create(args: {
236
316
 
237
317
  ```typescript
238
318
  new Controller(args: {
239
- system: MonoSystem
240
- entities: EntityInstance[]
241
- relations: RelationInstance[]
242
- activities: ActivityInstance[]
243
- interactions: InteractionInstance[]
244
- dict: DictionaryInstance[] // Global dictionaries, NOT computations
245
- recordMutationSideEffects?: any[]
319
+ system: System
320
+ entities?: EntityInstance[]
321
+ relations?: RelationInstance[]
322
+ eventSources?: EventSourceInstance[] // Interactions, custom EventSources, etc.
323
+ dict?: DictionaryInstance[] // Global dictionaries
324
+ recordMutationSideEffects?: RecordMutationSideEffect[]
325
+ computations?: (new (...args: any[]) => Computation)[] // Additional computation handle classes
326
+ ignoreGuard?: boolean // Skip guard checks when true
327
+ forceThrowDispatchError?: boolean // Throw errors instead of returning them
246
328
  }): Controller
247
329
 
248
- controller.setup(install: boolean): Promise<void>
249
- controller.callInteraction(name: string, args: {
250
- user: { id: string, [key: string]: any }
251
- payload?: { [key: string]: any }
252
- }): Promise<{ error?: { message: string, [key: string]: any }, [key: string]: any }>
330
+ controller.setup(install?: boolean): Promise<void>
331
+
332
+ controller.dispatch<TArgs, TResult>(
333
+ eventSource: EventSourceInstance<TArgs, TResult>,
334
+ args: TArgs
335
+ ): Promise<DispatchResponse>
336
+
337
+ // DispatchResponse = { error?, data?, effects?, sideEffects?, context? }
253
338
  ```
254
339
 
255
340
  Constraints:
256
- - ALWAYS call `setup(true)` before any `callInteraction`
341
+ - ALWAYS call `setup(true)` before any `dispatch`
257
342
  - `dict` is for Dictionary instances ONLY — never pass computations here
258
- - `callInteraction` NEVER throws errors are in `result.error`
343
+ - `dispatch` first parameter is the event source object reference, NOT a name string
344
+ - `dispatch` NEVER throws by default — errors are in `result.error`
345
+ - Set `forceThrowDispatchError: true` to make dispatch throw instead
346
+ - Controller automatically registers event source entities (e.g. `InteractionEventEntity`)
259
347
 
260
348
  ---
261
349
 
@@ -284,20 +372,29 @@ system.storage.find(
284
372
 
285
373
  system.storage.findOne(
286
374
  entityName: string,
287
- matchExp: MatchExp,
375
+ matchExp?: MatchExp,
288
376
  modifier?: any,
289
377
  attributeQuery?: AttributeQuery
290
378
  ): Promise<any>
291
379
 
292
380
  system.storage.create(entityName: string, data: object): Promise<any>
293
- system.storage.update(entityName: string, matchExp: MatchExp, data: object): Promise<void>
381
+ system.storage.update(entityName: string, matchExp: MatchExp, data: object): Promise<any>
294
382
  system.storage.delete(entityName: string, matchExp: MatchExp): Promise<void>
383
+
384
+ // Dictionary-specific API
385
+ system.storage.dict.get(key: string): Promise<any>
386
+ system.storage.dict.set(key: string, value: any): Promise<void>
387
+
388
+ // General KV storage
389
+ system.storage.get(itemName: string, id: string, initialValue?: any): Promise<any>
390
+ system.storage.set(itemName: string, id: string, value: any): Promise<any>
295
391
  ```
296
392
 
297
393
  Constraints:
298
394
  - ALWAYS pass `attributeQuery` to `find`/`findOne` — without it, only `id` is returned
299
395
  - Use `['*']` for all fields
300
396
  - `create`/`update`/`delete` bypass all validation — use ONLY for test setup
397
+ - When querying relations, use dot notation for source/target: `{ key: 'source.id', value: ['=', id] }`
301
398
 
302
399
  ---
303
400
 
@@ -306,12 +403,15 @@ Constraints:
306
403
  ```typescript
307
404
  MatchExp.atom(args: { key: string, value: [operator, value] }): MatchExp
308
405
 
309
- // Operators: '=', '!=', '>', '>=', '<', '<=', 'like', 'in', 'between', 'not', 'exist'
406
+ // Operators: '=', '!=', '>', '>=', '<', '<=', 'like', 'in', 'between', 'not'
310
407
 
311
408
  // Chaining
312
409
  matchExp.and(args: { key: string, value: [operator, value] }): MatchExp
313
410
  matchExp.or(args: { key: string, value: [operator, value] }): MatchExp
314
411
 
412
+ // From object (all AND)
413
+ MatchExp.fromObject({ status: 'active', age: 25 }): MatchExp
414
+
315
415
  // Nested field access
316
416
  MatchExp.atom({ key: 'author.name', value: ['=', 'Alice'] })
317
417
  ```
@@ -346,24 +446,43 @@ MatchExp.atom({ key: 'author.name', value: ['=', 'Alice'] })
346
446
 
347
447
  ```typescript
348
448
  Attributive.create(args: {
349
- name: string
449
+ name?: string
350
450
  content: (record: any, eventArgs: any) => boolean
351
451
  }): AttributiveInstance
352
452
  ```
353
453
 
354
- Used on PayloadItem `attributives` to validate referenced entities.
454
+ Used on Interaction `userAttributives` to validate user context.
355
455
 
356
456
  ---
357
457
 
358
458
  ## BoolExp
359
459
 
360
460
  ```typescript
361
- BoolExp.atom(attributive: AttributiveInstance): BoolExp
362
- boolExp.and(other: BoolExp): BoolExp
363
- boolExp.or(other: BoolExp): BoolExp
461
+ BoolExp.atom(data: T): BoolExp
462
+ boolExp.and(other: BoolExp | T): BoolExp
463
+ boolExp.or(other: BoolExp | T): BoolExp
364
464
  ```
365
465
 
366
- Combines multiple Attributives for complex validation logic.
466
+ Combines multiple Attributives, Conditions, or other expressions for complex logic.
467
+
468
+ ---
469
+
470
+ ## Condition.create / Conditions.create
471
+
472
+ ```typescript
473
+ Condition.create(args: {
474
+ name?: string
475
+ content: (this: Controller, event: InteractionEventArgs) => Promise<boolean>
476
+ }): ConditionInstance
477
+
478
+ Conditions.create(args: {
479
+ content: BoolExp<ConditionInstance> // Combined with AND/OR logic
480
+ }): ConditionsInstance
481
+ ```
482
+
483
+ - `content` returns `true` to allow, `false` to reject
484
+ - `this` is bound to Controller — can access `this.system.storage`
485
+ - Failed conditions return `{ error: { type: 'condition check failed' } }`
367
486
 
368
487
  ---
369
488
 
@@ -374,12 +493,53 @@ Dictionary.create(args: {
374
493
  name: string
375
494
  type: 'string' | 'number' | 'boolean' | 'object'
376
495
  collection?: boolean
377
- defaultValue?: any | (() => any)
496
+ defaultValue?: Function
378
497
  computation?: ComputationInstance
379
498
  }): DictionaryInstance
380
499
  ```
381
500
 
382
- Global state values. Pass to Controller's `dict` parameter. Access via `system.storage.get('state', name)`.
501
+ Global state values. Pass to Controller's `dict` parameter. Access via `system.storage.dict.get(name)` / `system.storage.dict.set(name, value)`.
502
+
503
+ ---
504
+
505
+ ## EventSource.create
506
+
507
+ ```typescript
508
+ EventSource.create(args: {
509
+ name: string // Event source identifier
510
+ entity: EntityInstance // Entity to persist event records
511
+ guard?: (this: Controller, args: TArgs) => Promise<void>
512
+ mapEventData?: (args: TArgs) => Record<string, any>
513
+ resolve?: (this: Controller, args: TArgs) => Promise<TResult>
514
+ afterDispatch?: (this: Controller, args: TArgs, result: { data?: TResult }) => Promise<Record<string, unknown> | void>
515
+ }): EventSourceInstance
516
+ ```
517
+
518
+ Custom event source for scheduled tasks, webhooks, or any non-interaction trigger. Dispatch via `controller.dispatch(eventSource, args)`.
519
+
520
+ ---
521
+
522
+ ## HardDeletionProperty.create
523
+
524
+ ```typescript
525
+ HardDeletionProperty.create(): PropertyInstance
526
+ ```
527
+
528
+ Creates a property named `_isDeleted_`. When its value transitions to `true` (via StateMachine), the Controller physically deletes the record. Use with `DELETED_STATE` / `NON_DELETED_STATE`.
529
+
530
+ ---
531
+
532
+ ## RecordMutationSideEffect.create
533
+
534
+ ```typescript
535
+ RecordMutationSideEffect.create(args: {
536
+ name: string
537
+ record: { name: string } // Entity/relation name to monitor
538
+ content: (this: Controller, event: RecordMutationEvent) => Promise<any>
539
+ }): RecordMutationSideEffect
540
+ ```
541
+
542
+ Triggers custom logic on record mutations within dispatch context. Results available in `dispatchResult.sideEffects`.
383
543
 
384
544
  ---
385
545
 
@@ -387,23 +547,52 @@ Global state values. Pass to Controller's `dict` parameter. Access via `system.s
387
547
 
388
548
  ```typescript
389
549
  import {
550
+ // Data model
390
551
  Entity, Property, Relation,
391
- Interaction, Action, Payload, PayloadItem,
552
+
553
+ // Event sources
554
+ EventSource, Interaction, Action, GetAction, Payload, PayloadItem,
392
555
  Activity,
393
- Count, Every, Any, Sum, Summation, WeightedSummation, Average,
556
+
557
+ // Computations
558
+ Count, Every, Any, Summation, WeightedSummation, Average,
394
559
  Transform, StateMachine, StateNode, StateTransfer,
395
- RealTime, Expression, Inequality, Equation, MathResolver,
396
- Attributive, Attributives, Condition, Conditions,
560
+ RealTime, Custom,
561
+
562
+ // Math (for RealTime)
563
+ Expression, Inequality, Equation, MathResolver,
564
+
565
+ // Validation & conditions
566
+ Attributive, Attributives, DataAttributive, DataAttributives,
567
+ Condition, Conditions,
568
+
569
+ // Data policy
570
+ DataPolicy,
571
+
572
+ // Expressions
397
573
  BoolExp, MatchExp,
574
+
575
+ // System
398
576
  Controller, MonoSystem, Dictionary,
577
+ RecordMutationSideEffect,
578
+ HardDeletionProperty, HARD_DELETION_PROPERTY_NAME,
579
+ NON_DELETED_STATE, DELETED_STATE,
580
+
581
+ // Built-in entities
399
582
  InteractionEventEntity,
583
+
584
+ // Drivers
400
585
  PGLiteDB, SQLiteDB, PostgreSQLDB, MysqlDB,
586
+
587
+ // Utilities
401
588
  KlassByName
402
589
  } from 'interaqt'
403
590
  ```
404
591
 
405
592
  Non-existent exports (commonly mistaken):
406
593
  - `InteractionEvent` → use `InteractionEventEntity`
407
- - `FilteredEntity` → use `Entity.create` with `baseEntity` + `filterCondition`
594
+ - `FilteredEntity` → use `Entity.create` with `baseEntity` + `matchExpression`
408
595
  - `RelationBasedEvery` → use `Every`
596
+ - `Sum` → use `Summation`
597
+ - `callInteraction` → use `controller.dispatch(eventSource, args)`
409
598
  - `User`, `Post`, etc. → no pre-built entities exist
@@ -1,5 +1,6 @@
1
1
  import { IInstance } from './interfaces.js';
2
2
  import { DataDep } from './Computation.js';
3
+ export type CustomConcurrency = 'serializable' | 'atomic-safe';
3
4
  export interface CustomInstance extends IInstance {
4
5
  name: string;
5
6
  dataDeps?: {
@@ -10,8 +11,18 @@ export interface CustomInstance extends IInstance {
10
11
  incrementalPatchCompute?: Function;
11
12
  createState?: Function;
12
13
  getInitialValue?: Function;
14
+ /**
15
+ * Runs inside the retryable transaction attempt when async task results are
16
+ * applied. Keep it deterministic and free of irreversible external IO.
17
+ */
13
18
  asyncReturn?: Function;
14
19
  useLastValue?: boolean;
20
+ /**
21
+ * Defaults to 'serializable'. Use 'atomic-safe' only when the custom
22
+ * computation's incremental path is built from framework atomic primitives or
23
+ * otherwise remains correct under READ COMMITTED retry boundaries.
24
+ */
25
+ concurrency?: CustomConcurrency;
15
26
  }
16
27
  export interface CustomCreateArgs {
17
28
  name: string;
@@ -25,6 +36,7 @@ export interface CustomCreateArgs {
25
36
  getInitialValue?: Function;
26
37
  asyncReturn?: Function;
27
38
  useLastValue?: boolean;
39
+ concurrency?: CustomConcurrency;
28
40
  }
29
41
  export declare class Custom implements CustomInstance {
30
42
  uuid: string;
@@ -43,6 +55,7 @@ export declare class Custom implements CustomInstance {
43
55
  getInitialValue?: Function;
44
56
  asyncReturn?: Function;
45
57
  useLastValue?: boolean;
58
+ concurrency?: CustomConcurrency;
46
59
  constructor(args: CustomCreateArgs, options?: {
47
60
  uuid?: string;
48
61
  });
@@ -95,6 +108,11 @@ export declare class Custom implements CustomInstance {
95
108
  collection: false;
96
109
  required: false;
97
110
  };
111
+ concurrency: {
112
+ type: "string";
113
+ collection: false;
114
+ required: false;
115
+ };
98
116
  };
99
117
  static create(args: CustomCreateArgs, options?: {
100
118
  uuid?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Custom.d.ts","sourceRoot":"","sources":["../../src/core/Custom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgC,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACtC,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,kBAAkB,CAAC,EAAE,QAAQ,CAAC;IAC9B,uBAAuB,CAAC,EAAE,QAAQ,CAAC;IACnC,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACtC,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,kBAAkB,CAAC,EAAE,QAAQ,CAAC;IAC9B,uBAAuB,CAAC,EAAE,QAAQ,CAAC;IACnC,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,MAAO,YAAW,cAAc;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,SAAY;IACjB,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACtC,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,kBAAkB,CAAC,EAAE,QAAQ,CAAC;IAC9B,uBAAuB,CAAC,EAAE,QAAQ,CAAC;IACnC,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;gBAElB,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IAe/D,MAAM,CAAC,OAAO,EAAG,IAAI,CAAU;IAC/B,MAAM,CAAC,WAAW,SAAY;IAC9B,MAAM,CAAC,SAAS,EAAE,cAAc,EAAE,CAAM;IAExC,MAAM,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA8CX;IAEF,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,cAAc;IAalF,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM;IAsBlD,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,GAAG,cAAc;IAcrE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,cAAc;IAI9C,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAIpC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc;CAc3C"}
1
+ {"version":3,"file":"Custom.d.ts","sourceRoot":"","sources":["../../src/core/Custom.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,26 @@ type CallbackThis = any;
4
4
  export interface EventSourceInstance<TArgs = unknown, TResult = void> extends IInstance {
5
5
  name: string;
6
6
  entity: EntityInstance;
7
+ /**
8
+ * Runs inside the dispatch transaction attempt. It may be replayed when the
9
+ * transaction is promoted or retried, so it must be deterministic and must
10
+ * not perform irreversible external IO.
11
+ */
7
12
  guard?: (this: CallbackThis, args: TArgs) => Promise<void>;
13
+ /**
14
+ * Runs inside the dispatch transaction attempt and may be replayed on retry.
15
+ */
8
16
  mapEventData?: (args: TArgs) => Record<string, unknown>;
17
+ /**
18
+ * Runs inside the dispatch transaction attempt and may be replayed on retry.
19
+ * External side effects should be modeled with record mutation side effects,
20
+ * which run after the final successful commit.
21
+ */
9
22
  resolve?: (this: CallbackThis, args: TArgs) => Promise<TResult>;
23
+ /**
24
+ * Runs before commit inside the retryable transaction attempt. It may produce
25
+ * response context, but it must not perform irreversible external IO.
26
+ */
10
27
  afterDispatch?: (this: CallbackThis, args: TArgs, result: {
11
28
  data?: TResult;
12
29
  }) => Promise<Record<string, unknown> | void>;