interaqt 1.1.0 → 1.1.2

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 (105) hide show
  1. package/README.md +329 -0
  2. package/agent/skill/interaqt-patterns.md +536 -0
  3. package/agent/skill/interaqt-recipes.md +501 -0
  4. package/agent/skill/interaqt-reference.md +409 -0
  5. package/dist/builtins/interaction/Interaction.d.ts +16 -10
  6. package/dist/builtins/interaction/Interaction.d.ts.map +1 -1
  7. package/dist/builtins/interaction/activity/ActivityManager.d.ts.map +1 -1
  8. package/dist/builtins/interaction/errors/ActivityErrors.d.ts +2 -2
  9. package/dist/builtins/interaction/errors/ActivityErrors.d.ts.map +1 -1
  10. package/dist/builtins/interaction/errors/InteractionErrors.d.ts +1 -1
  11. package/dist/builtins/interaction/errors/InteractionErrors.d.ts.map +1 -1
  12. package/dist/core/BoolExp.d.ts +2 -1
  13. package/dist/core/BoolExp.d.ts.map +1 -1
  14. package/dist/core/Computation.d.ts +3 -8
  15. package/dist/core/Computation.d.ts.map +1 -1
  16. package/dist/core/Custom.d.ts +2 -2
  17. package/dist/core/Custom.d.ts.map +1 -1
  18. package/dist/core/EventSource.d.ts +18 -16
  19. package/dist/core/EventSource.d.ts.map +1 -1
  20. package/dist/core/Property.d.ts +0 -3
  21. package/dist/core/Property.d.ts.map +1 -1
  22. package/dist/core/RealDictionary.d.ts +0 -3
  23. package/dist/core/RealDictionary.d.ts.map +1 -1
  24. package/dist/core/Relation.d.ts.map +1 -1
  25. package/dist/core/StateNode.d.ts +3 -3
  26. package/dist/core/StateNode.d.ts.map +1 -1
  27. package/dist/core/StateTransfer.d.ts +2 -6
  28. package/dist/core/StateTransfer.d.ts.map +1 -1
  29. package/dist/core/Transform.d.ts +2 -2
  30. package/dist/core/Transform.d.ts.map +1 -1
  31. package/dist/core/interfaces.d.ts +0 -9
  32. package/dist/core/interfaces.d.ts.map +1 -1
  33. package/dist/core/types.d.ts +0 -29
  34. package/dist/core/types.d.ts.map +1 -1
  35. package/dist/core/utils.d.ts +22 -6
  36. package/dist/core/utils.d.ts.map +1 -1
  37. package/dist/drivers/Mysql.d.ts +5 -5
  38. package/dist/drivers/Mysql.d.ts.map +1 -1
  39. package/dist/drivers/PGLite.d.ts +5 -5
  40. package/dist/drivers/PGLite.d.ts.map +1 -1
  41. package/dist/drivers/PostgreSQL.d.ts +5 -5
  42. package/dist/drivers/PostgreSQL.d.ts.map +1 -1
  43. package/dist/drivers/SQLite.d.ts +5 -5
  44. package/dist/drivers/SQLite.d.ts.map +1 -1
  45. package/dist/index.js +194 -228
  46. package/dist/index.js.map +1 -1
  47. package/dist/runtime/Controller.d.ts +14 -14
  48. package/dist/runtime/Controller.d.ts.map +1 -1
  49. package/dist/runtime/MonoSystem.d.ts +4 -4
  50. package/dist/runtime/MonoSystem.d.ts.map +1 -1
  51. package/dist/runtime/Scheduler.d.ts +3 -3
  52. package/dist/runtime/Scheduler.d.ts.map +1 -1
  53. package/dist/runtime/System.d.ts +50 -51
  54. package/dist/runtime/System.d.ts.map +1 -1
  55. package/dist/runtime/computations/Any.d.ts +4 -4
  56. package/dist/runtime/computations/Any.d.ts.map +1 -1
  57. package/dist/runtime/computations/Average.d.ts +2 -2
  58. package/dist/runtime/computations/Average.d.ts.map +1 -1
  59. package/dist/runtime/computations/Computation.d.ts +41 -47
  60. package/dist/runtime/computations/Computation.d.ts.map +1 -1
  61. package/dist/runtime/computations/Count.d.ts +4 -4
  62. package/dist/runtime/computations/Count.d.ts.map +1 -1
  63. package/dist/runtime/computations/Every.d.ts +4 -4
  64. package/dist/runtime/computations/Every.d.ts.map +1 -1
  65. package/dist/runtime/computations/RealTime.d.ts +9 -17
  66. package/dist/runtime/computations/RealTime.d.ts.map +1 -1
  67. package/dist/runtime/computations/StateMachine.d.ts +2 -2
  68. package/dist/runtime/computations/Summation.d.ts +2 -2
  69. package/dist/runtime/computations/Summation.d.ts.map +1 -1
  70. package/dist/runtime/computations/TransitionFinder.d.ts +9 -4
  71. package/dist/runtime/computations/TransitionFinder.d.ts.map +1 -1
  72. package/dist/runtime/computations/WeightedSummation.d.ts +2 -2
  73. package/dist/runtime/computations/WeightedSummation.d.ts.map +1 -1
  74. package/dist/runtime/errors/ComputationErrors.d.ts +3 -3
  75. package/dist/runtime/errors/ComputationErrors.d.ts.map +1 -1
  76. package/dist/runtime/errors/ConditionErrors.d.ts +6 -6
  77. package/dist/runtime/errors/ConditionErrors.d.ts.map +1 -1
  78. package/dist/runtime/errors/FrameworkError.d.ts +4 -4
  79. package/dist/runtime/errors/FrameworkError.d.ts.map +1 -1
  80. package/dist/runtime/errors/SideEffectError.d.ts +1 -1
  81. package/dist/runtime/errors/SideEffectError.d.ts.map +1 -1
  82. package/dist/runtime/errors/SystemErrors.d.ts +1 -1
  83. package/dist/runtime/errors/SystemErrors.d.ts.map +1 -1
  84. package/dist/runtime/errors/index.d.ts +5 -5
  85. package/dist/runtime/errors/index.d.ts.map +1 -1
  86. package/dist/runtime/types/computation.d.ts +11 -0
  87. package/dist/runtime/types/computation.d.ts.map +1 -0
  88. package/dist/runtime/util.d.ts +6 -6
  89. package/dist/runtime/util.d.ts.map +1 -1
  90. package/dist/storage/erstorage/MatchExp.d.ts +4 -4
  91. package/dist/storage/erstorage/MatchExp.d.ts.map +1 -1
  92. package/dist/storage/erstorage/QueryExecutor.d.ts +1 -1
  93. package/dist/storage/erstorage/QueryExecutor.d.ts.map +1 -1
  94. package/dist/storage/erstorage/RecordQuery.d.ts +5 -5
  95. package/dist/storage/erstorage/RecordQuery.d.ts.map +1 -1
  96. package/dist/storage/erstorage/SQLBuilder.d.ts +11 -11
  97. package/dist/storage/erstorage/SQLBuilder.d.ts.map +1 -1
  98. package/dist/storage/erstorage/Setup.d.ts +1 -1
  99. package/dist/storage/erstorage/util/RecursiveContext.d.ts +4 -10
  100. package/dist/storage/erstorage/util/RecursiveContext.d.ts.map +1 -1
  101. package/dist/storage/erstorage/util.d.ts +3 -3
  102. package/dist/storage/erstorage/util.d.ts.map +1 -1
  103. package/dist/storage/utils.d.ts +2 -2
  104. package/dist/storage/utils.d.ts.map +1 -1
  105. package/package.json +4 -1
package/README.md ADDED
@@ -0,0 +1,329 @@
1
+ <p align="center">
2
+ <h1 align="center">interaqt</h1>
3
+ <p align="center">
4
+ <strong>A declarative reactive backend framework where you define <em>what data is</em>, not how to change it.</strong>
5
+ </p>
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/interaqt"><img src="https://img.shields.io/npm/v/interaqt.svg" alt="npm version"></a>
8
+ <a href="https://www.npmjs.com/package/interaqt"><img src="https://img.shields.io/npm/dm/interaqt.svg" alt="npm downloads"></a>
9
+ <a href="https://github.com/InteraqtDev/interaqt/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/interaqt.svg" alt="license"></a>
10
+ <a href="https://github.com/InteraqtDev/interaqt"><img src="https://img.shields.io/badge/TypeScript-strict-blue.svg" alt="TypeScript"></a>
11
+ <a href="#"><img src="https://img.shields.io/badge/coverage-92.41%25-brightgreen.svg" alt="coverage"></a>
12
+ </p>
13
+ </p>
14
+
15
+ ---
16
+
17
+ ## The Problem
18
+
19
+ Traditional backend development forces you to think in terms of **operations** — "when X happens, update Y, then Z, then W." This imperative approach scatters related logic across handlers, creates consistency bugs, and makes systems increasingly brittle as complexity grows.
20
+
21
+ ```typescript
22
+ // The imperative way: fragile chains of manual updates
23
+ async function likePost(userId, postId) {
24
+ await createLike(userId, postId);
25
+ const count = await countLikes(postId);
26
+ await updatePost(postId, { likeCount: count }); // easy to forget
27
+ await notifyAuthor(postId); // easy to break
28
+ }
29
+ ```
30
+
31
+ ## The Solution
32
+
33
+ interaqt flips the model. Instead of describing *procedures*, you **declare what your data is** — and the framework keeps everything consistent, automatically.
34
+
35
+ ```typescript
36
+ // The interaqt way: declare what data IS
37
+ const Post = Entity.create({
38
+ name: 'Post',
39
+ properties: [
40
+ Property.create({ name: 'title', type: 'string' }),
41
+ Property.create({
42
+ name: 'likeCount',
43
+ // "like count IS the number of like relationships"
44
+ computation: Count.create({ record: LikeRelation })
45
+ })
46
+ ]
47
+ })
48
+ ```
49
+
50
+ No update handlers. No sync bugs. When a like relationship is created, `likeCount` updates itself — because it's *defined* as the count of likes.
51
+
52
+ ---
53
+
54
+ ## Core Ideas
55
+
56
+ **1. Only Interactions create data** — User interactions are the single source of truth. Everything else is derived.
57
+
58
+ **2. Data is a function of events** — Properties, counts, states, and aggregates are declared as computations over events and relations, not manually maintained.
59
+
60
+ **3. Unidirectional flow** — `Interaction → Event → Computation → Data`. No reverse wiring. No tangled update cycles.
61
+
62
+ ---
63
+
64
+ ## Quick Example: Social Post System
65
+
66
+ ```typescript
67
+ import {
68
+ Entity, Property, Relation, Interaction, Action,
69
+ Payload, PayloadItem, Controller, MonoSystem,
70
+ Count, Transform, InteractionEventEntity
71
+ } from 'interaqt'
72
+
73
+ // --- Define your data model ---
74
+
75
+ const User = Entity.create({
76
+ name: 'User',
77
+ properties: [
78
+ Property.create({ name: 'name', type: 'string' }),
79
+ Property.create({
80
+ name: 'postCount',
81
+ computation: Count.create({ record: AuthorRelation })
82
+ })
83
+ ]
84
+ })
85
+
86
+ const Post = Entity.create({
87
+ name: 'Post',
88
+ properties: [
89
+ Property.create({ name: 'title', type: 'string' }),
90
+ Property.create({ name: 'content', type: 'string' }),
91
+ Property.create({
92
+ name: 'likeCount',
93
+ computation: Count.create({ record: LikeRelation })
94
+ })
95
+ ]
96
+ })
97
+
98
+ // --- Define relationships ---
99
+
100
+ const AuthorRelation = Relation.create({
101
+ source: User,
102
+ sourceProperty: 'posts',
103
+ target: Post,
104
+ targetProperty: 'author',
105
+ type: 'n:1'
106
+ })
107
+
108
+ const LikeRelation = Relation.create({
109
+ source: User,
110
+ sourceProperty: 'likedPosts',
111
+ target: Post,
112
+ targetProperty: 'likedBy',
113
+ type: 'n:n'
114
+ })
115
+
116
+ // --- Define interactions ---
117
+
118
+ const CreatePost = Interaction.create({
119
+ name: 'CreatePost',
120
+ action: Action.create({ name: 'createPost' }),
121
+ payload: Payload.create({
122
+ items: [
123
+ PayloadItem.create({ name: 'title', type: 'string', required: true }),
124
+ PayloadItem.create({ name: 'content', type: 'string', required: true })
125
+ ]
126
+ })
127
+ })
128
+
129
+ const LikePost = Interaction.create({
130
+ name: 'LikePost',
131
+ action: Action.create({ name: 'likePost' }),
132
+ payload: Payload.create({
133
+ items: [
134
+ PayloadItem.create({ name: 'postId', base: Post, isRef: true })
135
+ ]
136
+ })
137
+ })
138
+
139
+ // --- Boot the system ---
140
+
141
+ const system = new MonoSystem(new PGLiteDB())
142
+ const controller = new Controller({
143
+ system,
144
+ entities: [User, Post],
145
+ relations: [AuthorRelation, LikeRelation],
146
+ eventSources: [CreatePost, LikePost]
147
+ })
148
+
149
+ await controller.setup(true)
150
+
151
+ // --- Use it ---
152
+
153
+ await controller.dispatch(CreatePost, {
154
+ user: { id: 'user-1' },
155
+ payload: { title: 'Hello World', content: 'My first post' }
156
+ })
157
+
158
+ await controller.dispatch(LikePost, {
159
+ user: { id: 'user-2' },
160
+ payload: { postId: 'post-1' }
161
+ })
162
+
163
+ // post.likeCount is now 1 — automatically.
164
+ // user.postCount is now 1 — automatically.
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Reactive Computations
170
+
171
+ The real power of interaqt lives in its computation primitives. Attach them to any Property, Entity, or Relation — they react to data changes automatically.
172
+
173
+ | Computation | What it declares |
174
+ |---|---|
175
+ | **Count** | "This value IS the number of related records" |
176
+ | **Summation** | "This value IS the sum over a field in related records" |
177
+ | **WeightedSummation** | "This value IS a weighted sum (e.g., inventory = stock − sold)" |
178
+ | **Average** | "This value IS the average of a field across relations" |
179
+ | **Every** | "This boolean IS true when ALL related records satisfy a condition" |
180
+ | **Any** | "This boolean IS true when ANY related record satisfies a condition" |
181
+ | **Transform** | "This entity/relation IS created when a matching event occurs" |
182
+ | **StateMachine** | "This value IS the current state, transitioning on specific events" |
183
+
184
+ ### Example: E-commerce Inventory
185
+
186
+ ```typescript
187
+ const Product = Entity.create({
188
+ name: 'Product',
189
+ properties: [
190
+ Property.create({ name: 'initialStock', type: 'number' }),
191
+ Property.create({
192
+ name: 'currentStock',
193
+ // "current stock IS initial stock minus total quantities ordered"
194
+ computation: WeightedSummation.create({
195
+ record: OrderItemRelation,
196
+ callback: (item) => ({ weight: -1, value: item.quantity })
197
+ })
198
+ }),
199
+ Property.create({
200
+ name: 'totalSales',
201
+ computation: WeightedSummation.create({
202
+ record: OrderItemRelation,
203
+ callback: (item) => ({ weight: 1, value: item.quantity })
204
+ })
205
+ })
206
+ ]
207
+ })
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Architecture
213
+
214
+ ```
215
+ src/
216
+ ├── core/ Data model: Entity, Relation, Property, Computation definitions
217
+ ├── runtime/ Execution: Controller, System, Scheduler, computation handles
218
+ ├── storage/ Persistence: ERStorage, SQL builder, query executors
219
+ ├── builtins/ Built-in EventSource types: Interaction, Activity, User
220
+ └── drivers/ Database adapters
221
+ ```
222
+
223
+ **Dependency direction:** `builtins → runtime → storage → core`. Clean layers, no circular imports.
224
+
225
+ ---
226
+
227
+ ## Database Support
228
+
229
+ interaqt works with the database you already use:
230
+
231
+ | Driver | Package | Use Case |
232
+ |---|---|---|
233
+ | **PostgreSQL** | `pg` | Production |
234
+ | **SQLite** | `better-sqlite3` | Embedded / edge |
235
+ | **MySQL** | `mysql2` | Production |
236
+ | **PGLite** | `@electric-sql/pglite` | Testing (in-memory) |
237
+
238
+ ```typescript
239
+ import { MonoSystem } from 'interaqt'
240
+
241
+ // Pick your driver
242
+ import { PostgreSQLDB } from 'interaqt/drivers'
243
+ const system = new MonoSystem(new PostgreSQLDB({ /* connection config */ }))
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Installation
249
+
250
+ ```bash
251
+ npm install interaqt
252
+ ```
253
+
254
+ Then install the database driver you need:
255
+
256
+ ```bash
257
+ # PostgreSQL
258
+ npm install pg
259
+
260
+ # SQLite
261
+ npm install better-sqlite3
262
+
263
+ # MySQL
264
+ npm install mysql2
265
+
266
+ # In-memory (for testing)
267
+ npm install @electric-sql/pglite
268
+ ```
269
+
270
+ ---
271
+
272
+ ## Key Concepts at a Glance
273
+
274
+ | Concept | Role |
275
+ |---|---|
276
+ | **Entity** | A data type (User, Post, Order, ...) |
277
+ | **Property** | A field on an entity — can be a static value or a reactive computation |
278
+ | **Relation** | A typed connection between entities (1:1, 1:n, n:n) |
279
+ | **Interaction** | An event triggered by a user — the *only* way new data enters the system |
280
+ | **Action** | An identifier for an interaction type (not a handler — no logic!) |
281
+ | **Computation** | A reactive declaration: Count, Transform, StateMachine, etc. |
282
+ | **Activity** | An ordered sequence of related Interactions for complex workflows |
283
+ | **Controller** | The single dispatch entry point: `controller.dispatch(interaction, args)` |
284
+
285
+ ---
286
+
287
+ ## Advanced Features
288
+
289
+ - **StateMachine** — Model entity lifecycles with explicit state transitions triggered by events
290
+ - **Filtered Entities** — Virtual views over entities, like reactive database views
291
+ - **Activities** — Compose multi-step business workflows from ordered Interactions
292
+ - **Attributive Permissions** — Declarative, entity-aware access control
293
+ - **Dictionary** — Global reactive key-value state
294
+ - **Hard Deletion** — Built-in support for both soft and hard delete patterns
295
+ - **Side Effects** — Hook into record mutations for external integrations (email, payments, file uploads)
296
+
297
+ ---
298
+
299
+ ## Development
300
+
301
+ ```bash
302
+ git clone https://github.com/InteraqtDev/interaqt.git
303
+ cd interaqt
304
+
305
+ npm install
306
+ npm test # Run all tests
307
+ npm run test:runtime # Runtime tests only
308
+ npm run test:storage # Storage tests only
309
+ npm run test:core # Core tests only
310
+ npm run build # Build to dist/
311
+ ```
312
+
313
+ ---
314
+
315
+ ## Philosophy
316
+
317
+ > **Stop thinking "how to do." Start thinking "what it is."**
318
+
319
+ In interaqt, you never write update logic. You declare:
320
+ - *what* each piece of data is (a count, a sum, a state, a transformation)
321
+ - *when* entities and relations come into existence (through Interactions)
322
+
323
+ The framework handles propagation, consistency, and persistence. Your business logic becomes a clear, auditable set of declarations rather than a tangled web of imperative handlers.
324
+
325
+ ---
326
+
327
+ ## License
328
+
329
+ [MIT](./LICENSE)