@optimystic/db-core 0.0.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 (345) hide show
  1. package/README.md +328 -0
  2. package/dist/index.min.js +18 -0
  3. package/dist/index.min.js.map +7 -0
  4. package/dist/src/blocks/block-store.d.ts +12 -0
  5. package/dist/src/blocks/block-store.d.ts.map +1 -0
  6. package/dist/src/blocks/block-store.js +2 -0
  7. package/dist/src/blocks/block-store.js.map +1 -0
  8. package/dist/src/blocks/block-types.d.ts +3 -0
  9. package/dist/src/blocks/block-types.d.ts.map +1 -0
  10. package/dist/src/blocks/block-types.js +9 -0
  11. package/dist/src/blocks/block-types.js.map +1 -0
  12. package/dist/src/blocks/helpers.d.ts +4 -0
  13. package/dist/src/blocks/helpers.d.ts.map +1 -0
  14. package/dist/src/blocks/helpers.js +12 -0
  15. package/dist/src/blocks/helpers.js.map +1 -0
  16. package/dist/src/blocks/index.d.ts +5 -0
  17. package/dist/src/blocks/index.d.ts.map +1 -0
  18. package/dist/src/blocks/index.js +5 -0
  19. package/dist/src/blocks/index.js.map +1 -0
  20. package/dist/src/blocks/structs.d.ts +14 -0
  21. package/dist/src/blocks/structs.d.ts.map +1 -0
  22. package/dist/src/blocks/structs.js +2 -0
  23. package/dist/src/blocks/structs.js.map +1 -0
  24. package/dist/src/btree/btree.d.ts +135 -0
  25. package/dist/src/btree/btree.d.ts.map +1 -0
  26. package/dist/src/btree/btree.js +727 -0
  27. package/dist/src/btree/btree.js.map +1 -0
  28. package/dist/src/btree/independent-trunk.d.ts +17 -0
  29. package/dist/src/btree/independent-trunk.d.ts.map +1 -0
  30. package/dist/src/btree/independent-trunk.js +41 -0
  31. package/dist/src/btree/independent-trunk.js.map +1 -0
  32. package/dist/src/btree/index.d.ts +6 -0
  33. package/dist/src/btree/index.d.ts.map +1 -0
  34. package/dist/src/btree/index.js +6 -0
  35. package/dist/src/btree/index.js.map +1 -0
  36. package/dist/src/btree/key-range.d.ts +13 -0
  37. package/dist/src/btree/key-range.d.ts.map +1 -0
  38. package/dist/src/btree/key-range.js +20 -0
  39. package/dist/src/btree/key-range.js.map +1 -0
  40. package/dist/src/btree/keyset.d.ts +4 -0
  41. package/dist/src/btree/keyset.d.ts.map +1 -0
  42. package/dist/src/btree/keyset.js +4 -0
  43. package/dist/src/btree/keyset.js.map +1 -0
  44. package/dist/src/btree/nodes.d.ts +16 -0
  45. package/dist/src/btree/nodes.d.ts.map +1 -0
  46. package/dist/src/btree/nodes.js +9 -0
  47. package/dist/src/btree/nodes.js.map +1 -0
  48. package/dist/src/btree/path.d.ts +22 -0
  49. package/dist/src/btree/path.d.ts.map +1 -0
  50. package/dist/src/btree/path.js +39 -0
  51. package/dist/src/btree/path.js.map +1 -0
  52. package/dist/src/btree/tree-block.d.ts +7 -0
  53. package/dist/src/btree/tree-block.d.ts.map +1 -0
  54. package/dist/src/btree/tree-block.js +5 -0
  55. package/dist/src/btree/tree-block.js.map +1 -0
  56. package/dist/src/btree/trunk.d.ts +13 -0
  57. package/dist/src/btree/trunk.d.ts.map +1 -0
  58. package/dist/src/btree/trunk.js +2 -0
  59. package/dist/src/btree/trunk.js.map +1 -0
  60. package/dist/src/chain/chain-nodes.d.ts +18 -0
  61. package/dist/src/chain/chain-nodes.d.ts.map +1 -0
  62. package/dist/src/chain/chain-nodes.js +10 -0
  63. package/dist/src/chain/chain-nodes.js.map +1 -0
  64. package/dist/src/chain/chain.d.ts +75 -0
  65. package/dist/src/chain/chain.d.ts.map +1 -0
  66. package/dist/src/chain/chain.js +268 -0
  67. package/dist/src/chain/chain.js.map +1 -0
  68. package/dist/src/chain/index.d.ts +2 -0
  69. package/dist/src/chain/index.d.ts.map +1 -0
  70. package/dist/src/chain/index.js +2 -0
  71. package/dist/src/chain/index.js.map +1 -0
  72. package/dist/src/cluster/i-cluster.d.ts +5 -0
  73. package/dist/src/cluster/i-cluster.d.ts.map +1 -0
  74. package/dist/src/cluster/i-cluster.js +2 -0
  75. package/dist/src/cluster/i-cluster.js.map +1 -0
  76. package/dist/src/cluster/index.d.ts +3 -0
  77. package/dist/src/cluster/index.d.ts.map +1 -0
  78. package/dist/src/cluster/index.js +3 -0
  79. package/dist/src/cluster/index.js.map +1 -0
  80. package/dist/src/cluster/structs.d.ts +47 -0
  81. package/dist/src/cluster/structs.d.ts.map +1 -0
  82. package/dist/src/cluster/structs.js +2 -0
  83. package/dist/src/cluster/structs.js.map +1 -0
  84. package/dist/src/collection/action.d.ts +26 -0
  85. package/dist/src/collection/action.d.ts.map +1 -0
  86. package/dist/src/collection/action.js +2 -0
  87. package/dist/src/collection/action.js.map +1 -0
  88. package/dist/src/collection/collection.d.ts +48 -0
  89. package/dist/src/collection/collection.d.ts.map +1 -0
  90. package/dist/src/collection/collection.js +175 -0
  91. package/dist/src/collection/collection.js.map +1 -0
  92. package/dist/src/collection/index.d.ts +4 -0
  93. package/dist/src/collection/index.d.ts.map +1 -0
  94. package/dist/src/collection/index.js +4 -0
  95. package/dist/src/collection/index.js.map +1 -0
  96. package/dist/src/collection/struct.d.ts +16 -0
  97. package/dist/src/collection/struct.d.ts.map +1 -0
  98. package/dist/src/collection/struct.js +2 -0
  99. package/dist/src/collection/struct.js.map +1 -0
  100. package/dist/src/collections/diary/diary.d.ts +9 -0
  101. package/dist/src/collections/diary/diary.d.ts.map +1 -0
  102. package/dist/src/collections/diary/diary.js +37 -0
  103. package/dist/src/collections/diary/diary.js.map +1 -0
  104. package/dist/src/collections/diary/index.d.ts +3 -0
  105. package/dist/src/collections/diary/index.d.ts.map +1 -0
  106. package/dist/src/collections/diary/index.js +3 -0
  107. package/dist/src/collections/diary/index.js.map +1 -0
  108. package/dist/src/collections/diary/struct.d.ts +2 -0
  109. package/dist/src/collections/diary/struct.d.ts.map +1 -0
  110. package/dist/src/collections/diary/struct.js +3 -0
  111. package/dist/src/collections/diary/struct.js.map +1 -0
  112. package/dist/src/collections/index.d.ts +3 -0
  113. package/dist/src/collections/index.d.ts.map +1 -0
  114. package/dist/src/collections/index.js +3 -0
  115. package/dist/src/collections/index.js.map +1 -0
  116. package/dist/src/collections/tree/collection-trunk.d.ts +11 -0
  117. package/dist/src/collections/tree/collection-trunk.d.ts.map +1 -0
  118. package/dist/src/collections/tree/collection-trunk.js +22 -0
  119. package/dist/src/collections/tree/collection-trunk.js.map +1 -0
  120. package/dist/src/collections/tree/index.d.ts +3 -0
  121. package/dist/src/collections/tree/index.d.ts.map +1 -0
  122. package/dist/src/collections/tree/index.js +3 -0
  123. package/dist/src/collections/tree/index.js.map +1 -0
  124. package/dist/src/collections/tree/struct.d.ts +12 -0
  125. package/dist/src/collections/tree/struct.d.ts.map +1 -0
  126. package/dist/src/collections/tree/struct.js +4 -0
  127. package/dist/src/collections/tree/struct.js.map +1 -0
  128. package/dist/src/collections/tree/tree.d.ts +34 -0
  129. package/dist/src/collections/tree/tree.d.ts.map +1 -0
  130. package/dist/src/collections/tree/tree.js +100 -0
  131. package/dist/src/collections/tree/tree.js.map +1 -0
  132. package/dist/src/index.d.ts +18 -0
  133. package/dist/src/index.d.ts.map +1 -0
  134. package/dist/src/index.js +18 -0
  135. package/dist/src/index.js.map +1 -0
  136. package/dist/src/log/index.d.ts +3 -0
  137. package/dist/src/log/index.d.ts.map +1 -0
  138. package/dist/src/log/index.js +3 -0
  139. package/dist/src/log/index.js.map +1 -0
  140. package/dist/src/log/log.d.ts +57 -0
  141. package/dist/src/log/log.d.ts.map +1 -0
  142. package/dist/src/log/log.js +131 -0
  143. package/dist/src/log/log.js.map +1 -0
  144. package/dist/src/log/struct.d.ts +36 -0
  145. package/dist/src/log/struct.d.ts.map +1 -0
  146. package/dist/src/log/struct.js +3 -0
  147. package/dist/src/log/struct.js.map +1 -0
  148. package/dist/src/network/i-key-network.d.ts +21 -0
  149. package/dist/src/network/i-key-network.d.ts.map +1 -0
  150. package/dist/src/network/i-key-network.js +2 -0
  151. package/dist/src/network/i-key-network.js.map +1 -0
  152. package/dist/src/network/i-peer-network.d.ts +8 -0
  153. package/dist/src/network/i-peer-network.d.ts.map +1 -0
  154. package/dist/src/network/i-peer-network.js +2 -0
  155. package/dist/src/network/i-peer-network.js.map +1 -0
  156. package/dist/src/network/i-repo.d.ts +17 -0
  157. package/dist/src/network/i-repo.d.ts.map +1 -0
  158. package/dist/src/network/i-repo.js +2 -0
  159. package/dist/src/network/i-repo.js.map +1 -0
  160. package/dist/src/network/index.d.ts +6 -0
  161. package/dist/src/network/index.d.ts.map +1 -0
  162. package/dist/src/network/index.js +6 -0
  163. package/dist/src/network/index.js.map +1 -0
  164. package/dist/src/network/repo-protocol.d.ts +19 -0
  165. package/dist/src/network/repo-protocol.d.ts.map +1 -0
  166. package/dist/src/network/repo-protocol.js +2 -0
  167. package/dist/src/network/repo-protocol.js.map +1 -0
  168. package/dist/src/network/struct.d.ts +115 -0
  169. package/dist/src/network/struct.d.ts.map +1 -0
  170. package/dist/src/network/struct.js +2 -0
  171. package/dist/src/network/struct.js.map +1 -0
  172. package/dist/src/transaction/actions-engine.d.ts +37 -0
  173. package/dist/src/transaction/actions-engine.d.ts.map +1 -0
  174. package/dist/src/transaction/actions-engine.js +67 -0
  175. package/dist/src/transaction/actions-engine.js.map +1 -0
  176. package/dist/src/transaction/context.d.ts +60 -0
  177. package/dist/src/transaction/context.d.ts.map +1 -0
  178. package/dist/src/transaction/context.js +91 -0
  179. package/dist/src/transaction/context.js.map +1 -0
  180. package/dist/src/transaction/coordinator.d.ts +118 -0
  181. package/dist/src/transaction/coordinator.d.ts.map +1 -0
  182. package/dist/src/transaction/coordinator.js +417 -0
  183. package/dist/src/transaction/coordinator.js.map +1 -0
  184. package/dist/src/transaction/index.d.ts +10 -0
  185. package/dist/src/transaction/index.d.ts.map +1 -0
  186. package/dist/src/transaction/index.js +7 -0
  187. package/dist/src/transaction/index.js.map +1 -0
  188. package/dist/src/transaction/session.d.ts +80 -0
  189. package/dist/src/transaction/session.d.ts.map +1 -0
  190. package/dist/src/transaction/session.js +161 -0
  191. package/dist/src/transaction/session.js.map +1 -0
  192. package/dist/src/transaction/transaction.d.ts +156 -0
  193. package/dist/src/transaction/transaction.d.ts.map +1 -0
  194. package/dist/src/transaction/transaction.js +31 -0
  195. package/dist/src/transaction/transaction.js.map +1 -0
  196. package/dist/src/transaction/validator.d.ts +46 -0
  197. package/dist/src/transaction/validator.d.ts.map +1 -0
  198. package/dist/src/transaction/validator.js +97 -0
  199. package/dist/src/transaction/validator.js.map +1 -0
  200. package/dist/src/transactor/index.d.ts +4 -0
  201. package/dist/src/transactor/index.d.ts.map +1 -0
  202. package/dist/src/transactor/index.js +4 -0
  203. package/dist/src/transactor/index.js.map +1 -0
  204. package/dist/src/transactor/network-transactor.d.ts +36 -0
  205. package/dist/src/transactor/network-transactor.d.ts.map +1 -0
  206. package/dist/src/transactor/network-transactor.js +297 -0
  207. package/dist/src/transactor/network-transactor.js.map +1 -0
  208. package/dist/src/transactor/transactor-source.d.ts +24 -0
  209. package/dist/src/transactor/transactor-source.d.ts.map +1 -0
  210. package/dist/src/transactor/transactor-source.js +62 -0
  211. package/dist/src/transactor/transactor-source.js.map +1 -0
  212. package/dist/src/transactor/transactor.d.ts +38 -0
  213. package/dist/src/transactor/transactor.d.ts.map +1 -0
  214. package/dist/src/transactor/transactor.js +2 -0
  215. package/dist/src/transactor/transactor.js.map +1 -0
  216. package/dist/src/transform/atomic.d.ts +8 -0
  217. package/dist/src/transform/atomic.d.ts.map +1 -0
  218. package/dist/src/transform/atomic.js +14 -0
  219. package/dist/src/transform/atomic.js.map +1 -0
  220. package/dist/src/transform/cache-source.d.ts +13 -0
  221. package/dist/src/transform/cache-source.d.ts.map +1 -0
  222. package/dist/src/transform/cache-source.js +52 -0
  223. package/dist/src/transform/cache-source.js.map +1 -0
  224. package/dist/src/transform/helpers.d.ts +25 -0
  225. package/dist/src/transform/helpers.d.ts.map +1 -0
  226. package/dist/src/transform/helpers.js +105 -0
  227. package/dist/src/transform/helpers.js.map +1 -0
  228. package/dist/src/transform/index.d.ts +6 -0
  229. package/dist/src/transform/index.d.ts.map +1 -0
  230. package/dist/src/transform/index.js +6 -0
  231. package/dist/src/transform/index.js.map +1 -0
  232. package/dist/src/transform/struct.d.ts +19 -0
  233. package/dist/src/transform/struct.d.ts.map +1 -0
  234. package/dist/src/transform/struct.js +2 -0
  235. package/dist/src/transform/struct.js.map +1 -0
  236. package/dist/src/transform/tracker.d.ts +22 -0
  237. package/dist/src/transform/tracker.d.ts.map +1 -0
  238. package/dist/src/transform/tracker.js +64 -0
  239. package/dist/src/transform/tracker.js.map +1 -0
  240. package/dist/src/utility/actor.d.ts +11 -0
  241. package/dist/src/utility/actor.d.ts.map +1 -0
  242. package/dist/src/utility/actor.js +39 -0
  243. package/dist/src/utility/actor.js.map +1 -0
  244. package/dist/src/utility/batch-coordinator.d.ts +56 -0
  245. package/dist/src/utility/batch-coordinator.d.ts.map +1 -0
  246. package/dist/src/utility/batch-coordinator.js +127 -0
  247. package/dist/src/utility/batch-coordinator.js.map +1 -0
  248. package/dist/src/utility/block-id-to-bytes.d.ts +3 -0
  249. package/dist/src/utility/block-id-to-bytes.d.ts.map +1 -0
  250. package/dist/src/utility/block-id-to-bytes.js +7 -0
  251. package/dist/src/utility/block-id-to-bytes.js.map +1 -0
  252. package/dist/src/utility/ensured.d.ts +3 -0
  253. package/dist/src/utility/ensured.d.ts.map +1 -0
  254. package/dist/src/utility/ensured.js +24 -0
  255. package/dist/src/utility/ensured.js.map +1 -0
  256. package/dist/src/utility/groupby.d.ts +8 -0
  257. package/dist/src/utility/groupby.d.ts.map +1 -0
  258. package/dist/src/utility/groupby.js +15 -0
  259. package/dist/src/utility/groupby.js.map +1 -0
  260. package/dist/src/utility/is-record-empty.d.ts +3 -0
  261. package/dist/src/utility/is-record-empty.d.ts.map +1 -0
  262. package/dist/src/utility/is-record-empty.js +7 -0
  263. package/dist/src/utility/is-record-empty.js.map +1 -0
  264. package/dist/src/utility/latches.d.ts +11 -0
  265. package/dist/src/utility/latches.d.ts.map +1 -0
  266. package/dist/src/utility/latches.js +36 -0
  267. package/dist/src/utility/latches.js.map +1 -0
  268. package/dist/src/utility/nameof.d.ts +3 -0
  269. package/dist/src/utility/nameof.d.ts.map +1 -0
  270. package/dist/src/utility/nameof.js +5 -0
  271. package/dist/src/utility/nameof.js.map +1 -0
  272. package/dist/src/utility/pending.d.ts +13 -0
  273. package/dist/src/utility/pending.d.ts.map +1 -0
  274. package/dist/src/utility/pending.js +37 -0
  275. package/dist/src/utility/pending.js.map +1 -0
  276. package/package.json +56 -0
  277. package/src/blocks/block-store.ts +13 -0
  278. package/src/blocks/block-types.ts +11 -0
  279. package/src/blocks/helpers.ts +13 -0
  280. package/src/blocks/index.ts +5 -0
  281. package/src/blocks/structs.ts +17 -0
  282. package/src/btree/btree.ts +804 -0
  283. package/src/btree/independent-trunk.ts +54 -0
  284. package/src/btree/index.ts +5 -0
  285. package/src/btree/key-range.ts +15 -0
  286. package/src/btree/keyset.ts +6 -0
  287. package/src/btree/nodes.ts +25 -0
  288. package/src/btree/path.ts +37 -0
  289. package/src/btree/tree-block.ts +11 -0
  290. package/src/btree/trunk.ts +14 -0
  291. package/src/chain/chain-nodes.ts +24 -0
  292. package/src/chain/chain.ts +324 -0
  293. package/src/chain/index.ts +2 -0
  294. package/src/cluster/i-cluster.ts +6 -0
  295. package/src/cluster/index.ts +2 -0
  296. package/src/cluster/structs.ts +46 -0
  297. package/src/collection/action.ts +31 -0
  298. package/src/collection/collection.ts +200 -0
  299. package/src/collection/index.ts +3 -0
  300. package/src/collection/struct.ts +20 -0
  301. package/src/collections/diary/diary.ts +43 -0
  302. package/src/collections/diary/index.ts +2 -0
  303. package/src/collections/diary/struct.ts +3 -0
  304. package/src/collections/index.ts +2 -0
  305. package/src/collections/tree/collection-trunk.ts +25 -0
  306. package/src/collections/tree/index.ts +2 -0
  307. package/src/collections/tree/readme.md +19 -0
  308. package/src/collections/tree/struct.ts +18 -0
  309. package/src/collections/tree/tree.ts +124 -0
  310. package/src/index.ts +17 -0
  311. package/src/log/index.ts +2 -0
  312. package/src/log/log.ts +155 -0
  313. package/src/log/struct.ts +40 -0
  314. package/src/network/i-key-network.ts +24 -0
  315. package/src/network/i-peer-network.ts +8 -0
  316. package/src/network/i-repo.ts +19 -0
  317. package/src/network/index.ts +5 -0
  318. package/src/network/repo-protocol.ts +12 -0
  319. package/src/network/struct.ts +137 -0
  320. package/src/transaction/actions-engine.ts +83 -0
  321. package/src/transaction/context.ts +103 -0
  322. package/src/transaction/coordinator.ts +583 -0
  323. package/src/transaction/index.ts +30 -0
  324. package/src/transaction/session.ts +182 -0
  325. package/src/transaction/transaction.ts +205 -0
  326. package/src/transaction/validator.ts +150 -0
  327. package/src/transactor/index.ts +4 -0
  328. package/src/transactor/network-transactor.ts +435 -0
  329. package/src/transactor/transactor-source.ts +65 -0
  330. package/src/transactor/transactor.ts +44 -0
  331. package/src/transform/atomic.ts +16 -0
  332. package/src/transform/cache-source.ts +57 -0
  333. package/src/transform/helpers.ts +117 -0
  334. package/src/transform/index.ts +5 -0
  335. package/src/transform/struct.ts +22 -0
  336. package/src/transform/tracker.ts +70 -0
  337. package/src/utility/actor.ts +62 -0
  338. package/src/utility/batch-coordinator.ts +174 -0
  339. package/src/utility/block-id-to-bytes.ts +8 -0
  340. package/src/utility/ensured.ts +32 -0
  341. package/src/utility/groupby.ts +18 -0
  342. package/src/utility/is-record-empty.ts +5 -0
  343. package/src/utility/latches.ts +42 -0
  344. package/src/utility/nameof.ts +7 -0
  345. package/src/utility/pending.ts +41 -0
@@ -0,0 +1,182 @@
1
+ import type { TransactionCoordinator } from "./coordinator.js";
2
+ import type { Transaction, ExecutionResult, ITransactionEngine, TransactionStamp, CollectionActions } from "./transaction.js";
3
+ import { createTransactionStamp, createTransactionId } from "./transaction.js";
4
+
5
+ /**
6
+ * TransactionSession manages incremental transaction building.
7
+ *
8
+ * This is the high-level API for building transactions incrementally:
9
+ * - Stamp is created at BEGIN (stable throughout transaction)
10
+ * - Execute statements one at a time
11
+ * - Engine translates statements to actions (if not already provided)
12
+ * - Actions are immediately applied to collections via coordinator.applyActions()
13
+ * - On commit, all statements are compiled into a complete Transaction
14
+ * - The Transaction is then committed through coordinator.commit() for PEND/COMMIT orchestration
15
+ *
16
+ * Usage:
17
+ * const session = new TransactionSession(coordinator, engine);
18
+ * await session.execute('INSERT INTO users (id, name) VALUES (?, ?)', [1, 'Alice']);
19
+ * await session.execute('SELECT * FROM orders WHERE user_id = ?', [1]);
20
+ * const result = await session.commit();
21
+ *
22
+ * For validation/replay, use engine.execute() directly with a complete Transaction.
23
+ */
24
+ export class TransactionSession {
25
+ private readonly statements: string[] = [];
26
+ private readonly stamp: TransactionStamp;
27
+ private committed = false;
28
+ private rolledBack = false;
29
+
30
+ constructor(
31
+ private readonly coordinator: TransactionCoordinator,
32
+ private readonly engine: ITransactionEngine,
33
+ peerId: string = 'local', // TODO: Get from coordinator or config
34
+ schemaHash: string = '' // TODO: Get from engine
35
+ ) {
36
+ // Create stamp at BEGIN (stable throughout transaction)
37
+ this.stamp = createTransactionStamp(
38
+ peerId,
39
+ Date.now(),
40
+ schemaHash,
41
+ 'unknown' // TODO: Get engine ID from engine
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Execute a statement.
47
+ *
48
+ * If actions are provided, they are applied directly.
49
+ * Otherwise, the engine translates the statement to actions.
50
+ *
51
+ * @param statement - The statement to execute (engine-specific, e.g., SQL statement)
52
+ * @param actions - Optional pre-computed actions (for Quereus module case)
53
+ * @returns Execution result with any returned values
54
+ */
55
+ async execute(statement: string, actions?: CollectionActions[]): Promise<{ success: boolean; error?: string }> {
56
+ if (this.committed) {
57
+ return { success: false, error: 'Transaction already committed' };
58
+ }
59
+ if (this.rolledBack) {
60
+ return { success: false, error: 'Transaction already rolled back' };
61
+ }
62
+
63
+ try {
64
+ // If actions not provided, enlist engine to translate statement
65
+ let actionsToApply: CollectionActions[];
66
+ if (actions) {
67
+ actionsToApply = actions;
68
+ } else {
69
+ // Create a temporary transaction with just this statement for translation
70
+ const tempTransaction: Transaction = {
71
+ stamp: this.stamp,
72
+ statements: [statement],
73
+ reads: [],
74
+ id: 'temp' // Temporary ID for translation only
75
+ };
76
+ const result = await this.engine.execute(tempTransaction);
77
+ if (!result.success || !result.actions) {
78
+ return { success: false, error: result.error || 'Failed to translate statement' };
79
+ }
80
+ actionsToApply = result.actions;
81
+ }
82
+
83
+ // Apply actions through coordinator
84
+ await this.coordinator.applyActions(actionsToApply, this.stamp.id);
85
+
86
+ // Accumulate the statement for later compilation
87
+ this.statements.push(statement);
88
+
89
+ return { success: true };
90
+ } catch (error) {
91
+ return {
92
+ success: false,
93
+ error: `Failed to execute statement: ${error instanceof Error ? error.message : String(error)}`
94
+ };
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Commit the transaction.
100
+ *
101
+ * Compiles all statements into a complete Transaction and commits through coordinator.
102
+ */
103
+ async commit(): Promise<ExecutionResult> {
104
+ if (this.committed) {
105
+ return { success: false, error: 'Transaction already committed' };
106
+ }
107
+ if (this.rolledBack) {
108
+ return { success: false, error: 'Transaction already rolled back' };
109
+ }
110
+
111
+ // Create the complete transaction
112
+ const transaction: Transaction = {
113
+ stamp: this.stamp,
114
+ statements: this.statements,
115
+ reads: [], // TODO: Track reads during statement execution
116
+ id: createTransactionId(this.stamp.id, this.statements, [])
117
+ };
118
+
119
+ // Commit through coordinator (which will orchestrate PEND/COMMIT)
120
+ await this.coordinator.commit(transaction);
121
+
122
+ this.committed = true;
123
+ return { success: true };
124
+ }
125
+
126
+ /**
127
+ * Rollback the transaction (discard local state).
128
+ *
129
+ * Note: Actions have already been applied to collections' trackers.
130
+ * Rollback just prevents commit and clears session state.
131
+ * Collections will discard tracker state when they sync or update.
132
+ */
133
+ async rollback(): Promise<void> {
134
+ if (this.committed) {
135
+ throw new Error('Cannot rollback: transaction already committed');
136
+ }
137
+ if (this.rolledBack) {
138
+ throw new Error('Transaction already rolled back');
139
+ }
140
+
141
+ // Rollback through coordinator
142
+ await this.coordinator.rollback(this.stamp.id);
143
+ this.rolledBack = true;
144
+ this.statements.length = 0;
145
+ }
146
+
147
+ /**
148
+ * Get the transaction stamp ID (stable throughout transaction).
149
+ */
150
+ getStampId(): string {
151
+ return this.stamp.id;
152
+ }
153
+
154
+ /**
155
+ * Get the transaction stamp (full metadata).
156
+ */
157
+ getStamp(): TransactionStamp {
158
+ return this.stamp;
159
+ }
160
+
161
+ /**
162
+ * Get the list of accumulated statements.
163
+ */
164
+ getStatements(): readonly string[] {
165
+ return this.statements;
166
+ }
167
+
168
+ /**
169
+ * Check if the transaction has been committed.
170
+ */
171
+ isCommitted(): boolean {
172
+ return this.committed;
173
+ }
174
+
175
+ /**
176
+ * Check if the transaction has been rolled back.
177
+ */
178
+ isRolledBack(): boolean {
179
+ return this.rolledBack;
180
+ }
181
+ }
182
+
@@ -0,0 +1,205 @@
1
+ import type { BlockId } from "../blocks/index.js";
2
+ import type { CollectionId } from "../collection/index.js";
3
+
4
+ /**
5
+ * Transaction Stamp: Created at BEGIN, stable throughout transaction lifecycle.
6
+ *
7
+ * The stamp contains metadata about the transaction's origin and context.
8
+ * The id is computed as a hash of these fields.
9
+ */
10
+ export type TransactionStamp = {
11
+ /** Peer that initiated the transaction */
12
+ peerId: string;
13
+
14
+ /** When transaction started (milliseconds since epoch) */
15
+ timestamp: number;
16
+
17
+ /** Hash of schema version(s) for validation */
18
+ schemaHash: string;
19
+
20
+ /** Which engine (e.g., 'quereus@0.5.3', 'actions@1.0.0') */
21
+ engineId: string;
22
+
23
+ /** Hash of the stamp fields (computed) - stable identifier throughout transaction */
24
+ id: string;
25
+ };
26
+
27
+ /**
28
+ * Transaction: Finalized at COMMIT with complete statement history.
29
+ *
30
+ * Transactions span multiple collections and use pluggable engines for interpreting the statements.
31
+ * The engine re-executes the statements to verify the resulting operations match what was proposed.
32
+ */
33
+ export type Transaction = {
34
+ /** The transaction stamp (includes stable id) */
35
+ stamp: TransactionStamp;
36
+
37
+ /** Engine-specific statements (for replay/validation)
38
+ * Array of statements executed during the transaction.
39
+ * - For Quereus: SQL statements
40
+ * - For ActionsEngine: JSON-encoded actions
41
+ */
42
+ statements: string[];
43
+
44
+ /** Read dependencies for optimistic concurrency control */
45
+ reads: ReadDependency[];
46
+
47
+ /** Transaction identifier (hash of stamp.id + statements + reads)
48
+ * Final transaction identity, used in logs
49
+ */
50
+ id: string;
51
+ };
52
+
53
+ /**
54
+ * Read dependency for optimistic concurrency control.
55
+ * Tracks which block revisions were read during transaction execution.
56
+ */
57
+ export type ReadDependency = {
58
+ blockId: BlockId;
59
+ /** Expected revision number at time of read */
60
+ revision: number;
61
+ };
62
+
63
+ /**
64
+ * Transaction reference embedded in actions.
65
+ * Just the transaction ID - full transaction can be looked up separately if needed.
66
+ */
67
+ export type TransactionRef = string; // The transaction ID
68
+
69
+ /**
70
+ * Create a transaction stamp with computed id.
71
+ * The id is a hash of the stamp fields.
72
+ */
73
+ export function createTransactionStamp(
74
+ peerId: string,
75
+ timestamp: number,
76
+ schemaHash: string,
77
+ engineId: string
78
+ ): TransactionStamp {
79
+ const stampData = JSON.stringify({ peerId, timestamp, schemaHash, engineId });
80
+ const id = `stamp:${hashString(stampData)}`;
81
+ return { peerId, timestamp, schemaHash, engineId, id };
82
+ }
83
+
84
+ /**
85
+ * Create a transaction id from stamp id, statements, and reads.
86
+ * This is the final transaction identity used in logs.
87
+ */
88
+ export function createTransactionId(
89
+ stampId: string,
90
+ statements: string[],
91
+ reads: ReadDependency[]
92
+ ): string {
93
+ const txData = JSON.stringify({ stampId, statements, reads });
94
+ return `tx:${hashString(txData)}`;
95
+ }
96
+
97
+ /**
98
+ * Simple hash function for creating IDs.
99
+ * Uses a basic hash for now - can be replaced with proper cryptographic hash later.
100
+ */
101
+ function hashString(str: string): string {
102
+ let hash = 0;
103
+ for (let i = 0; i < str.length; i++) {
104
+ const char = str.charCodeAt(i);
105
+ hash = ((hash << 5) - hash) + char;
106
+ hash = hash & hash; // Convert to 32-bit integer
107
+ }
108
+ return Math.abs(hash).toString(36);
109
+ }
110
+
111
+ /**
112
+ * Transaction engine interface.
113
+ * Pluggable engines implement this to process transaction statements.
114
+ *
115
+ * Engines are responsible for:
116
+ * 1. Parsing the engine-specific statements
117
+ * 2. Executing/re-executing to produce actions
118
+ * 3. Returning the resulting actions per collection
119
+ */
120
+ export interface ITransactionEngine {
121
+ /**
122
+ * Process a transaction statements to produce actions.
123
+ *
124
+ * Used both for:
125
+ * - Initial execution (client creating transaction)
126
+ * - Re-execution (validators verifying transaction)
127
+ *
128
+ * @param transaction - The transaction to process
129
+ * @returns The resulting actions from execution
130
+ */
131
+ execute(transaction: Transaction): Promise<ExecutionResult>;
132
+ }
133
+
134
+ /**
135
+ * Result of transaction execution.
136
+ */
137
+ export type ExecutionResult = {
138
+ /** Whether execution succeeded */
139
+ success: boolean;
140
+ /** Actions produced by executing the transaction */
141
+ actions?: CollectionActions[];
142
+ /** Results from executing actions (e.g., return values from reads) */
143
+ results?: Map<CollectionId, any[]>;
144
+ /** Error message if execution failed */
145
+ error?: string;
146
+ };
147
+
148
+ /**
149
+ * Actions for a specific collection resulting from transaction execution.
150
+ */
151
+ export type CollectionActions = {
152
+ /** Collection identifier */
153
+ collectionId: string;
154
+ /** Actions to apply to this collection */
155
+ actions: unknown[];
156
+ };
157
+
158
+ /**
159
+ * Result of transaction validation.
160
+ */
161
+ export type ValidationResult = {
162
+ /** Whether validation succeeded */
163
+ valid: boolean;
164
+ /** Reason for validation failure (if valid=false) */
165
+ reason?: string;
166
+ /** The operations hash computed during validation (for debugging) */
167
+ computedHash?: string;
168
+ };
169
+
170
+ /**
171
+ * Transaction validator interface.
172
+ * Pluggable validators implement this to verify transaction integrity.
173
+ *
174
+ * Validators are invoked when a node receives a PendRequest with a transaction.
175
+ * They re-execute the transaction and verify the operations match.
176
+ */
177
+ export interface ITransactionValidator {
178
+ /**
179
+ * Validate a transaction by re-executing and comparing operations hash.
180
+ *
181
+ * Validation steps:
182
+ * 1. Verify stamp.engineId matches a known engine
183
+ * 2. Verify stamp.schemaHash matches local schema
184
+ * 3. Verify read dependencies (no stale reads)
185
+ * 4. Re-execute transaction.statements through engine (isolated state)
186
+ * 5. Collect operations from re-execution
187
+ * 6. Compute hash of operations
188
+ * 7. Compare with sender's operationsHash
189
+ *
190
+ * @param transaction - The transaction to validate
191
+ * @param operationsHash - The hash to compare against
192
+ * @returns Validation result
193
+ */
194
+ validate(transaction: Transaction, operationsHash: string): Promise<ValidationResult>;
195
+
196
+ /**
197
+ * Get the schema hash for a given engine.
198
+ * Used to verify the sender's schema matches local schema.
199
+ *
200
+ * @param engineId - The engine identifier
201
+ * @returns The schema hash, or undefined if engine not found
202
+ */
203
+ getSchemaHash(engineId: string): Promise<string | undefined>;
204
+ }
205
+
@@ -0,0 +1,150 @@
1
+ import type { BlockId, CollectionId, IBlock, BlockOperations, Transforms, ITransactor } from '../index.js';
2
+ import type { Transaction, ITransactionEngine, ITransactionValidator, ValidationResult, CollectionActions } from './transaction.js';
3
+ import type { Collection } from '../collection/collection.js';
4
+ import { Tracker } from '../transform/tracker.js';
5
+
6
+ /**
7
+ * Represents an operation on a block within a collection.
8
+ * Must match the Operation type in coordinator.ts for consistent hashing.
9
+ */
10
+ type Operation =
11
+ | { readonly type: 'insert'; readonly collectionId: CollectionId; readonly blockId: BlockId; readonly block: IBlock }
12
+ | { readonly type: 'update'; readonly collectionId: CollectionId; readonly blockId: BlockId; readonly operations: BlockOperations }
13
+ | { readonly type: 'delete'; readonly collectionId: CollectionId; readonly blockId: BlockId };
14
+
15
+ /**
16
+ * Engine registration for validation.
17
+ */
18
+ export type EngineRegistration = {
19
+ /** The transaction engine instance */
20
+ engine: ITransactionEngine;
21
+ /** Get the current schema hash for this engine */
22
+ getSchemaHash: () => Promise<string>;
23
+ };
24
+
25
+ /**
26
+ * Factory function to create a validation coordinator.
27
+ * This allows isolated execution of transactions for validation.
28
+ */
29
+ export type ValidationCoordinatorFactory = () => {
30
+ /** Apply actions to collections in isolated state */
31
+ applyActions(actions: CollectionActions[], stampId: string): Promise<void>;
32
+ /** Get all transforms from the validation state */
33
+ getTransforms(): Map<CollectionId, Transforms>;
34
+ /** Dispose of the validation coordinator */
35
+ dispose(): void;
36
+ };
37
+
38
+ /**
39
+ * Transaction validator implementation.
40
+ *
41
+ * Validates transactions by re-executing them and comparing operations hash.
42
+ * Used by cluster participants when receiving PendRequests.
43
+ */
44
+ export class TransactionValidator implements ITransactionValidator {
45
+ constructor(
46
+ private readonly engines: Map<string, EngineRegistration>,
47
+ private readonly createValidationCoordinator: ValidationCoordinatorFactory
48
+ ) {}
49
+
50
+ async validate(transaction: Transaction, operationsHash: string): Promise<ValidationResult> {
51
+ const { stamp, statements } = transaction;
52
+
53
+ // 1. Verify engine exists
54
+ const registration = this.engines.get(stamp.engineId);
55
+ if (!registration) {
56
+ return {
57
+ valid: false,
58
+ reason: `Unknown engine: ${stamp.engineId}`
59
+ };
60
+ }
61
+
62
+ // 2. Verify schema hash matches
63
+ const localSchemaHash = await registration.getSchemaHash();
64
+ if (localSchemaHash !== stamp.schemaHash) {
65
+ return {
66
+ valid: false,
67
+ reason: `Schema mismatch: local=${localSchemaHash}, sender=${stamp.schemaHash}`
68
+ };
69
+ }
70
+
71
+ // 3. Verify read dependencies (optimistic concurrency)
72
+ // TODO: Implement read dependency validation
73
+ // For now, we skip this check - will be implemented with proper block versioning
74
+
75
+ // 4. Create isolated validation coordinator
76
+ const validationCoordinator = this.createValidationCoordinator();
77
+
78
+ try {
79
+ // 5. Re-execute transaction through engine
80
+ const result = await registration.engine.execute(transaction);
81
+ if (!result.success) {
82
+ return {
83
+ valid: false,
84
+ reason: `Re-execution failed: ${result.error}`
85
+ };
86
+ }
87
+
88
+ // 6. Apply actions to validation coordinator (builds transforms)
89
+ if (result.actions && result.actions.length > 0) {
90
+ await validationCoordinator.applyActions(result.actions, stamp.id);
91
+ }
92
+
93
+ // 7. Collect operations from validation coordinator
94
+ const transforms = validationCoordinator.getTransforms();
95
+ const allOperations = this.collectOperations(transforms);
96
+
97
+ // 8. Compute hash
98
+ const computedHash = this.hashOperations(allOperations);
99
+
100
+ // 9. Compare with sender's hash
101
+ if (computedHash !== operationsHash) {
102
+ return {
103
+ valid: false,
104
+ reason: `Operations hash mismatch`,
105
+ computedHash
106
+ };
107
+ }
108
+
109
+ return { valid: true, computedHash };
110
+ } finally {
111
+ validationCoordinator.dispose();
112
+ }
113
+ }
114
+
115
+ async getSchemaHash(engineId: string): Promise<string | undefined> {
116
+ const registration = this.engines.get(engineId);
117
+ return registration ? await registration.getSchemaHash() : undefined;
118
+ }
119
+
120
+ /**
121
+ * Collect all operations from transforms.
122
+ */
123
+ private collectOperations(transforms: Map<CollectionId, Transforms>): readonly Operation[] {
124
+ return Array.from(transforms.entries()).flatMap(([collectionId, t]) => [
125
+ ...Object.entries(t.inserts).map(([blockId, block]) =>
126
+ ({ type: 'insert' as const, collectionId, blockId, block })
127
+ ),
128
+ ...Object.entries(t.updates).map(([blockId, operations]) =>
129
+ ({ type: 'update' as const, collectionId, blockId, operations })
130
+ ),
131
+ ...t.deletes.map(blockId =>
132
+ ({ type: 'delete' as const, collectionId, blockId })
133
+ )
134
+ ]);
135
+ }
136
+
137
+ /**
138
+ * Compute hash of all operations.
139
+ * Must match TransactionCoordinator.hashOperations for consistent validation.
140
+ */
141
+ private hashOperations(operations: readonly Operation[]): string {
142
+ const operationsData = JSON.stringify(operations);
143
+ const hash = Array.from(operationsData).reduce((acc, char) => {
144
+ const charCode = char.charCodeAt(0);
145
+ return ((acc << 5) - acc + charCode) & acc;
146
+ }, 0);
147
+ return `ops:${Math.abs(hash).toString(36)}`;
148
+ }
149
+ }
150
+
@@ -0,0 +1,4 @@
1
+ export * from "./network-transactor.js";
2
+ export * from "./transactor-source.js";
3
+ export * from "./transactor.js";
4
+