@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.
- package/README.md +328 -0
- package/dist/index.min.js +18 -0
- package/dist/index.min.js.map +7 -0
- package/dist/src/blocks/block-store.d.ts +12 -0
- package/dist/src/blocks/block-store.d.ts.map +1 -0
- package/dist/src/blocks/block-store.js +2 -0
- package/dist/src/blocks/block-store.js.map +1 -0
- package/dist/src/blocks/block-types.d.ts +3 -0
- package/dist/src/blocks/block-types.d.ts.map +1 -0
- package/dist/src/blocks/block-types.js +9 -0
- package/dist/src/blocks/block-types.js.map +1 -0
- package/dist/src/blocks/helpers.d.ts +4 -0
- package/dist/src/blocks/helpers.d.ts.map +1 -0
- package/dist/src/blocks/helpers.js +12 -0
- package/dist/src/blocks/helpers.js.map +1 -0
- package/dist/src/blocks/index.d.ts +5 -0
- package/dist/src/blocks/index.d.ts.map +1 -0
- package/dist/src/blocks/index.js +5 -0
- package/dist/src/blocks/index.js.map +1 -0
- package/dist/src/blocks/structs.d.ts +14 -0
- package/dist/src/blocks/structs.d.ts.map +1 -0
- package/dist/src/blocks/structs.js +2 -0
- package/dist/src/blocks/structs.js.map +1 -0
- package/dist/src/btree/btree.d.ts +135 -0
- package/dist/src/btree/btree.d.ts.map +1 -0
- package/dist/src/btree/btree.js +727 -0
- package/dist/src/btree/btree.js.map +1 -0
- package/dist/src/btree/independent-trunk.d.ts +17 -0
- package/dist/src/btree/independent-trunk.d.ts.map +1 -0
- package/dist/src/btree/independent-trunk.js +41 -0
- package/dist/src/btree/independent-trunk.js.map +1 -0
- package/dist/src/btree/index.d.ts +6 -0
- package/dist/src/btree/index.d.ts.map +1 -0
- package/dist/src/btree/index.js +6 -0
- package/dist/src/btree/index.js.map +1 -0
- package/dist/src/btree/key-range.d.ts +13 -0
- package/dist/src/btree/key-range.d.ts.map +1 -0
- package/dist/src/btree/key-range.js +20 -0
- package/dist/src/btree/key-range.js.map +1 -0
- package/dist/src/btree/keyset.d.ts +4 -0
- package/dist/src/btree/keyset.d.ts.map +1 -0
- package/dist/src/btree/keyset.js +4 -0
- package/dist/src/btree/keyset.js.map +1 -0
- package/dist/src/btree/nodes.d.ts +16 -0
- package/dist/src/btree/nodes.d.ts.map +1 -0
- package/dist/src/btree/nodes.js +9 -0
- package/dist/src/btree/nodes.js.map +1 -0
- package/dist/src/btree/path.d.ts +22 -0
- package/dist/src/btree/path.d.ts.map +1 -0
- package/dist/src/btree/path.js +39 -0
- package/dist/src/btree/path.js.map +1 -0
- package/dist/src/btree/tree-block.d.ts +7 -0
- package/dist/src/btree/tree-block.d.ts.map +1 -0
- package/dist/src/btree/tree-block.js +5 -0
- package/dist/src/btree/tree-block.js.map +1 -0
- package/dist/src/btree/trunk.d.ts +13 -0
- package/dist/src/btree/trunk.d.ts.map +1 -0
- package/dist/src/btree/trunk.js +2 -0
- package/dist/src/btree/trunk.js.map +1 -0
- package/dist/src/chain/chain-nodes.d.ts +18 -0
- package/dist/src/chain/chain-nodes.d.ts.map +1 -0
- package/dist/src/chain/chain-nodes.js +10 -0
- package/dist/src/chain/chain-nodes.js.map +1 -0
- package/dist/src/chain/chain.d.ts +75 -0
- package/dist/src/chain/chain.d.ts.map +1 -0
- package/dist/src/chain/chain.js +268 -0
- package/dist/src/chain/chain.js.map +1 -0
- package/dist/src/chain/index.d.ts +2 -0
- package/dist/src/chain/index.d.ts.map +1 -0
- package/dist/src/chain/index.js +2 -0
- package/dist/src/chain/index.js.map +1 -0
- package/dist/src/cluster/i-cluster.d.ts +5 -0
- package/dist/src/cluster/i-cluster.d.ts.map +1 -0
- package/dist/src/cluster/i-cluster.js +2 -0
- package/dist/src/cluster/i-cluster.js.map +1 -0
- package/dist/src/cluster/index.d.ts +3 -0
- package/dist/src/cluster/index.d.ts.map +1 -0
- package/dist/src/cluster/index.js +3 -0
- package/dist/src/cluster/index.js.map +1 -0
- package/dist/src/cluster/structs.d.ts +47 -0
- package/dist/src/cluster/structs.d.ts.map +1 -0
- package/dist/src/cluster/structs.js +2 -0
- package/dist/src/cluster/structs.js.map +1 -0
- package/dist/src/collection/action.d.ts +26 -0
- package/dist/src/collection/action.d.ts.map +1 -0
- package/dist/src/collection/action.js +2 -0
- package/dist/src/collection/action.js.map +1 -0
- package/dist/src/collection/collection.d.ts +48 -0
- package/dist/src/collection/collection.d.ts.map +1 -0
- package/dist/src/collection/collection.js +175 -0
- package/dist/src/collection/collection.js.map +1 -0
- package/dist/src/collection/index.d.ts +4 -0
- package/dist/src/collection/index.d.ts.map +1 -0
- package/dist/src/collection/index.js +4 -0
- package/dist/src/collection/index.js.map +1 -0
- package/dist/src/collection/struct.d.ts +16 -0
- package/dist/src/collection/struct.d.ts.map +1 -0
- package/dist/src/collection/struct.js +2 -0
- package/dist/src/collection/struct.js.map +1 -0
- package/dist/src/collections/diary/diary.d.ts +9 -0
- package/dist/src/collections/diary/diary.d.ts.map +1 -0
- package/dist/src/collections/diary/diary.js +37 -0
- package/dist/src/collections/diary/diary.js.map +1 -0
- package/dist/src/collections/diary/index.d.ts +3 -0
- package/dist/src/collections/diary/index.d.ts.map +1 -0
- package/dist/src/collections/diary/index.js +3 -0
- package/dist/src/collections/diary/index.js.map +1 -0
- package/dist/src/collections/diary/struct.d.ts +2 -0
- package/dist/src/collections/diary/struct.d.ts.map +1 -0
- package/dist/src/collections/diary/struct.js +3 -0
- package/dist/src/collections/diary/struct.js.map +1 -0
- package/dist/src/collections/index.d.ts +3 -0
- package/dist/src/collections/index.d.ts.map +1 -0
- package/dist/src/collections/index.js +3 -0
- package/dist/src/collections/index.js.map +1 -0
- package/dist/src/collections/tree/collection-trunk.d.ts +11 -0
- package/dist/src/collections/tree/collection-trunk.d.ts.map +1 -0
- package/dist/src/collections/tree/collection-trunk.js +22 -0
- package/dist/src/collections/tree/collection-trunk.js.map +1 -0
- package/dist/src/collections/tree/index.d.ts +3 -0
- package/dist/src/collections/tree/index.d.ts.map +1 -0
- package/dist/src/collections/tree/index.js +3 -0
- package/dist/src/collections/tree/index.js.map +1 -0
- package/dist/src/collections/tree/struct.d.ts +12 -0
- package/dist/src/collections/tree/struct.d.ts.map +1 -0
- package/dist/src/collections/tree/struct.js +4 -0
- package/dist/src/collections/tree/struct.js.map +1 -0
- package/dist/src/collections/tree/tree.d.ts +34 -0
- package/dist/src/collections/tree/tree.d.ts.map +1 -0
- package/dist/src/collections/tree/tree.js +100 -0
- package/dist/src/collections/tree/tree.js.map +1 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +18 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/log/index.d.ts +3 -0
- package/dist/src/log/index.d.ts.map +1 -0
- package/dist/src/log/index.js +3 -0
- package/dist/src/log/index.js.map +1 -0
- package/dist/src/log/log.d.ts +57 -0
- package/dist/src/log/log.d.ts.map +1 -0
- package/dist/src/log/log.js +131 -0
- package/dist/src/log/log.js.map +1 -0
- package/dist/src/log/struct.d.ts +36 -0
- package/dist/src/log/struct.d.ts.map +1 -0
- package/dist/src/log/struct.js +3 -0
- package/dist/src/log/struct.js.map +1 -0
- package/dist/src/network/i-key-network.d.ts +21 -0
- package/dist/src/network/i-key-network.d.ts.map +1 -0
- package/dist/src/network/i-key-network.js +2 -0
- package/dist/src/network/i-key-network.js.map +1 -0
- package/dist/src/network/i-peer-network.d.ts +8 -0
- package/dist/src/network/i-peer-network.d.ts.map +1 -0
- package/dist/src/network/i-peer-network.js +2 -0
- package/dist/src/network/i-peer-network.js.map +1 -0
- package/dist/src/network/i-repo.d.ts +17 -0
- package/dist/src/network/i-repo.d.ts.map +1 -0
- package/dist/src/network/i-repo.js +2 -0
- package/dist/src/network/i-repo.js.map +1 -0
- package/dist/src/network/index.d.ts +6 -0
- package/dist/src/network/index.d.ts.map +1 -0
- package/dist/src/network/index.js +6 -0
- package/dist/src/network/index.js.map +1 -0
- package/dist/src/network/repo-protocol.d.ts +19 -0
- package/dist/src/network/repo-protocol.d.ts.map +1 -0
- package/dist/src/network/repo-protocol.js +2 -0
- package/dist/src/network/repo-protocol.js.map +1 -0
- package/dist/src/network/struct.d.ts +115 -0
- package/dist/src/network/struct.d.ts.map +1 -0
- package/dist/src/network/struct.js +2 -0
- package/dist/src/network/struct.js.map +1 -0
- package/dist/src/transaction/actions-engine.d.ts +37 -0
- package/dist/src/transaction/actions-engine.d.ts.map +1 -0
- package/dist/src/transaction/actions-engine.js +67 -0
- package/dist/src/transaction/actions-engine.js.map +1 -0
- package/dist/src/transaction/context.d.ts +60 -0
- package/dist/src/transaction/context.d.ts.map +1 -0
- package/dist/src/transaction/context.js +91 -0
- package/dist/src/transaction/context.js.map +1 -0
- package/dist/src/transaction/coordinator.d.ts +118 -0
- package/dist/src/transaction/coordinator.d.ts.map +1 -0
- package/dist/src/transaction/coordinator.js +417 -0
- package/dist/src/transaction/coordinator.js.map +1 -0
- package/dist/src/transaction/index.d.ts +10 -0
- package/dist/src/transaction/index.d.ts.map +1 -0
- package/dist/src/transaction/index.js +7 -0
- package/dist/src/transaction/index.js.map +1 -0
- package/dist/src/transaction/session.d.ts +80 -0
- package/dist/src/transaction/session.d.ts.map +1 -0
- package/dist/src/transaction/session.js +161 -0
- package/dist/src/transaction/session.js.map +1 -0
- package/dist/src/transaction/transaction.d.ts +156 -0
- package/dist/src/transaction/transaction.d.ts.map +1 -0
- package/dist/src/transaction/transaction.js +31 -0
- package/dist/src/transaction/transaction.js.map +1 -0
- package/dist/src/transaction/validator.d.ts +46 -0
- package/dist/src/transaction/validator.d.ts.map +1 -0
- package/dist/src/transaction/validator.js +97 -0
- package/dist/src/transaction/validator.js.map +1 -0
- package/dist/src/transactor/index.d.ts +4 -0
- package/dist/src/transactor/index.d.ts.map +1 -0
- package/dist/src/transactor/index.js +4 -0
- package/dist/src/transactor/index.js.map +1 -0
- package/dist/src/transactor/network-transactor.d.ts +36 -0
- package/dist/src/transactor/network-transactor.d.ts.map +1 -0
- package/dist/src/transactor/network-transactor.js +297 -0
- package/dist/src/transactor/network-transactor.js.map +1 -0
- package/dist/src/transactor/transactor-source.d.ts +24 -0
- package/dist/src/transactor/transactor-source.d.ts.map +1 -0
- package/dist/src/transactor/transactor-source.js +62 -0
- package/dist/src/transactor/transactor-source.js.map +1 -0
- package/dist/src/transactor/transactor.d.ts +38 -0
- package/dist/src/transactor/transactor.d.ts.map +1 -0
- package/dist/src/transactor/transactor.js +2 -0
- package/dist/src/transactor/transactor.js.map +1 -0
- package/dist/src/transform/atomic.d.ts +8 -0
- package/dist/src/transform/atomic.d.ts.map +1 -0
- package/dist/src/transform/atomic.js +14 -0
- package/dist/src/transform/atomic.js.map +1 -0
- package/dist/src/transform/cache-source.d.ts +13 -0
- package/dist/src/transform/cache-source.d.ts.map +1 -0
- package/dist/src/transform/cache-source.js +52 -0
- package/dist/src/transform/cache-source.js.map +1 -0
- package/dist/src/transform/helpers.d.ts +25 -0
- package/dist/src/transform/helpers.d.ts.map +1 -0
- package/dist/src/transform/helpers.js +105 -0
- package/dist/src/transform/helpers.js.map +1 -0
- package/dist/src/transform/index.d.ts +6 -0
- package/dist/src/transform/index.d.ts.map +1 -0
- package/dist/src/transform/index.js +6 -0
- package/dist/src/transform/index.js.map +1 -0
- package/dist/src/transform/struct.d.ts +19 -0
- package/dist/src/transform/struct.d.ts.map +1 -0
- package/dist/src/transform/struct.js +2 -0
- package/dist/src/transform/struct.js.map +1 -0
- package/dist/src/transform/tracker.d.ts +22 -0
- package/dist/src/transform/tracker.d.ts.map +1 -0
- package/dist/src/transform/tracker.js +64 -0
- package/dist/src/transform/tracker.js.map +1 -0
- package/dist/src/utility/actor.d.ts +11 -0
- package/dist/src/utility/actor.d.ts.map +1 -0
- package/dist/src/utility/actor.js +39 -0
- package/dist/src/utility/actor.js.map +1 -0
- package/dist/src/utility/batch-coordinator.d.ts +56 -0
- package/dist/src/utility/batch-coordinator.d.ts.map +1 -0
- package/dist/src/utility/batch-coordinator.js +127 -0
- package/dist/src/utility/batch-coordinator.js.map +1 -0
- package/dist/src/utility/block-id-to-bytes.d.ts +3 -0
- package/dist/src/utility/block-id-to-bytes.d.ts.map +1 -0
- package/dist/src/utility/block-id-to-bytes.js +7 -0
- package/dist/src/utility/block-id-to-bytes.js.map +1 -0
- package/dist/src/utility/ensured.d.ts +3 -0
- package/dist/src/utility/ensured.d.ts.map +1 -0
- package/dist/src/utility/ensured.js +24 -0
- package/dist/src/utility/ensured.js.map +1 -0
- package/dist/src/utility/groupby.d.ts +8 -0
- package/dist/src/utility/groupby.d.ts.map +1 -0
- package/dist/src/utility/groupby.js +15 -0
- package/dist/src/utility/groupby.js.map +1 -0
- package/dist/src/utility/is-record-empty.d.ts +3 -0
- package/dist/src/utility/is-record-empty.d.ts.map +1 -0
- package/dist/src/utility/is-record-empty.js +7 -0
- package/dist/src/utility/is-record-empty.js.map +1 -0
- package/dist/src/utility/latches.d.ts +11 -0
- package/dist/src/utility/latches.d.ts.map +1 -0
- package/dist/src/utility/latches.js +36 -0
- package/dist/src/utility/latches.js.map +1 -0
- package/dist/src/utility/nameof.d.ts +3 -0
- package/dist/src/utility/nameof.d.ts.map +1 -0
- package/dist/src/utility/nameof.js +5 -0
- package/dist/src/utility/nameof.js.map +1 -0
- package/dist/src/utility/pending.d.ts +13 -0
- package/dist/src/utility/pending.d.ts.map +1 -0
- package/dist/src/utility/pending.js +37 -0
- package/dist/src/utility/pending.js.map +1 -0
- package/package.json +56 -0
- package/src/blocks/block-store.ts +13 -0
- package/src/blocks/block-types.ts +11 -0
- package/src/blocks/helpers.ts +13 -0
- package/src/blocks/index.ts +5 -0
- package/src/blocks/structs.ts +17 -0
- package/src/btree/btree.ts +804 -0
- package/src/btree/independent-trunk.ts +54 -0
- package/src/btree/index.ts +5 -0
- package/src/btree/key-range.ts +15 -0
- package/src/btree/keyset.ts +6 -0
- package/src/btree/nodes.ts +25 -0
- package/src/btree/path.ts +37 -0
- package/src/btree/tree-block.ts +11 -0
- package/src/btree/trunk.ts +14 -0
- package/src/chain/chain-nodes.ts +24 -0
- package/src/chain/chain.ts +324 -0
- package/src/chain/index.ts +2 -0
- package/src/cluster/i-cluster.ts +6 -0
- package/src/cluster/index.ts +2 -0
- package/src/cluster/structs.ts +46 -0
- package/src/collection/action.ts +31 -0
- package/src/collection/collection.ts +200 -0
- package/src/collection/index.ts +3 -0
- package/src/collection/struct.ts +20 -0
- package/src/collections/diary/diary.ts +43 -0
- package/src/collections/diary/index.ts +2 -0
- package/src/collections/diary/struct.ts +3 -0
- package/src/collections/index.ts +2 -0
- package/src/collections/tree/collection-trunk.ts +25 -0
- package/src/collections/tree/index.ts +2 -0
- package/src/collections/tree/readme.md +19 -0
- package/src/collections/tree/struct.ts +18 -0
- package/src/collections/tree/tree.ts +124 -0
- package/src/index.ts +17 -0
- package/src/log/index.ts +2 -0
- package/src/log/log.ts +155 -0
- package/src/log/struct.ts +40 -0
- package/src/network/i-key-network.ts +24 -0
- package/src/network/i-peer-network.ts +8 -0
- package/src/network/i-repo.ts +19 -0
- package/src/network/index.ts +5 -0
- package/src/network/repo-protocol.ts +12 -0
- package/src/network/struct.ts +137 -0
- package/src/transaction/actions-engine.ts +83 -0
- package/src/transaction/context.ts +103 -0
- package/src/transaction/coordinator.ts +583 -0
- package/src/transaction/index.ts +30 -0
- package/src/transaction/session.ts +182 -0
- package/src/transaction/transaction.ts +205 -0
- package/src/transaction/validator.ts +150 -0
- package/src/transactor/index.ts +4 -0
- package/src/transactor/network-transactor.ts +435 -0
- package/src/transactor/transactor-source.ts +65 -0
- package/src/transactor/transactor.ts +44 -0
- package/src/transform/atomic.ts +16 -0
- package/src/transform/cache-source.ts +57 -0
- package/src/transform/helpers.ts +117 -0
- package/src/transform/index.ts +5 -0
- package/src/transform/struct.ts +22 -0
- package/src/transform/tracker.ts +70 -0
- package/src/utility/actor.ts +62 -0
- package/src/utility/batch-coordinator.ts +174 -0
- package/src/utility/block-id-to-bytes.ts +8 -0
- package/src/utility/ensured.ts +32 -0
- package/src/utility/groupby.ts +18 -0
- package/src/utility/is-record-empty.ts +5 -0
- package/src/utility/latches.ts +42 -0
- package/src/utility/nameof.ts +7 -0
- package/src/utility/pending.ts +41 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import type { ITransactor, BlockId, CollectionId, Transforms, PendRequest, CommitRequest, ActionId, IBlock, BlockOperations } from "../index.js";
|
|
2
|
+
import type { Transaction, ExecutionResult, ITransactionEngine, CollectionActions } from "./transaction.js";
|
|
3
|
+
import type { PeerId } from "@libp2p/interface";
|
|
4
|
+
import type { Collection } from "../collection/collection.js";
|
|
5
|
+
import { TransactionContext } from "./context.js";
|
|
6
|
+
import { createActionsStatements } from "./actions-engine.js";
|
|
7
|
+
import { createTransactionStamp, createTransactionId } from "./transaction.js";
|
|
8
|
+
import { Log, blockIdsForTransforms, transformsFromTransform } from "../index.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents an operation on a block within a collection.
|
|
12
|
+
*/
|
|
13
|
+
type Operation =
|
|
14
|
+
| { readonly type: 'insert'; readonly collectionId: CollectionId; readonly blockId: BlockId; readonly block: IBlock }
|
|
15
|
+
| { readonly type: 'update'; readonly collectionId: CollectionId; readonly blockId: BlockId; readonly operations: BlockOperations }
|
|
16
|
+
| { readonly type: 'delete'; readonly collectionId: CollectionId; readonly blockId: BlockId };
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Coordinates multi-collection transactions.
|
|
20
|
+
*
|
|
21
|
+
* This is the ONLY interface for all mutations (single or multi-collection).
|
|
22
|
+
*
|
|
23
|
+
* Responsibilities:
|
|
24
|
+
* - Manage collections (create as needed)
|
|
25
|
+
* - Apply actions to collections (run handlers, write to logs)
|
|
26
|
+
* - Commit transactions by running consensus phases (GATHER, PEND, COMMIT)
|
|
27
|
+
*/
|
|
28
|
+
export class TransactionCoordinator {
|
|
29
|
+
constructor(
|
|
30
|
+
private readonly transactor: ITransactor,
|
|
31
|
+
private readonly collections: Map<CollectionId, Collection<any>>
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Apply actions to collections (called by engines during statement execution).
|
|
36
|
+
*
|
|
37
|
+
* This is the core method that engines call to apply actions to collections.
|
|
38
|
+
* Actions are tagged with the stamp ID and executed immediately through collections
|
|
39
|
+
* to update the local snapshot.
|
|
40
|
+
*
|
|
41
|
+
* @param actions - The actions to apply (per collection)
|
|
42
|
+
* @param stampId - The transaction stamp ID to tag actions with
|
|
43
|
+
*/
|
|
44
|
+
async applyActions(
|
|
45
|
+
actions: CollectionActions[],
|
|
46
|
+
stampId: string
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
for (const { collectionId, actions: collectionActions } of actions) {
|
|
49
|
+
// Get collection
|
|
50
|
+
const collection = this.collections.get(collectionId);
|
|
51
|
+
if (!collection) {
|
|
52
|
+
throw new Error(`Collection not found: ${collectionId}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Apply each action (tagged with stampId)
|
|
56
|
+
for (const action of collectionActions) {
|
|
57
|
+
const taggedAction = { ...(action as any), transaction: stampId };
|
|
58
|
+
await collection.act(taggedAction);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Commit a transaction (actions already applied, orchestrate PEND/COMMIT).
|
|
65
|
+
*
|
|
66
|
+
* This is called by TransactionSession.commit() after all statements have been executed.
|
|
67
|
+
* Actions have already been applied to collections via applyActions(), so this method
|
|
68
|
+
* just orchestrates the distributed consensus.
|
|
69
|
+
*
|
|
70
|
+
* @param transaction - The transaction to commit
|
|
71
|
+
*/
|
|
72
|
+
async commit(transaction: Transaction): Promise<void> {
|
|
73
|
+
// Collect transforms and determine critical blocks for each affected collection
|
|
74
|
+
const collectionData = Array.from(this.collections.entries())
|
|
75
|
+
.map(([collectionId, collection]) => ({
|
|
76
|
+
collectionId,
|
|
77
|
+
collection,
|
|
78
|
+
transforms: collection.tracker.transforms
|
|
79
|
+
}))
|
|
80
|
+
.filter(({ transforms }) =>
|
|
81
|
+
Object.keys(transforms.inserts).length +
|
|
82
|
+
Object.keys(transforms.updates).length +
|
|
83
|
+
transforms.deletes.length > 0
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (collectionData.length === 0) {
|
|
87
|
+
return; // Nothing to commit
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get critical block IDs (log tail) for each affected collection
|
|
91
|
+
// The critical block is the current log tail that must participate in consensus
|
|
92
|
+
const collectionTransforms = new Map<CollectionId, Transforms>();
|
|
93
|
+
const criticalBlocks = new Map<CollectionId, BlockId>();
|
|
94
|
+
|
|
95
|
+
for (const { collectionId, collection, transforms } of collectionData) {
|
|
96
|
+
collectionTransforms.set(collectionId, transforms);
|
|
97
|
+
|
|
98
|
+
// Get the current log tail block ID (critical block)
|
|
99
|
+
const log = await Log.open(collection.tracker, collectionId);
|
|
100
|
+
if (!log) {
|
|
101
|
+
throw new Error(`Log not found for collection ${collectionId}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const tailPath = await (log as unknown as { chain: { getTail: () => Promise<{ block: { header: { id: BlockId } } } | undefined> } }).chain.getTail();
|
|
105
|
+
if (tailPath) {
|
|
106
|
+
criticalBlocks.set(collectionId, tailPath.block.header.id);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Compute hash of ALL operations across ALL collections
|
|
111
|
+
// This hash is used for validation - validators re-execute the transaction
|
|
112
|
+
// and compare their computed operations hash with this one
|
|
113
|
+
const allOperations = collectionData.flatMap(({ collectionId, transforms }) => [
|
|
114
|
+
...Object.entries(transforms.inserts).map(([blockId, block]) =>
|
|
115
|
+
({ type: 'insert' as const, collectionId, blockId, block })
|
|
116
|
+
),
|
|
117
|
+
...Object.entries(transforms.updates).map(([blockId, operations]) =>
|
|
118
|
+
({ type: 'update' as const, collectionId, blockId, operations })
|
|
119
|
+
),
|
|
120
|
+
...transforms.deletes.map(blockId =>
|
|
121
|
+
({ type: 'delete' as const, collectionId, blockId })
|
|
122
|
+
)
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
const operationsHash = this.hashOperations(allOperations);
|
|
126
|
+
|
|
127
|
+
// Execute consensus phases (GATHER, PEND, COMMIT)
|
|
128
|
+
const coordResult = await this.coordinateTransaction(
|
|
129
|
+
transaction,
|
|
130
|
+
operationsHash,
|
|
131
|
+
collectionTransforms,
|
|
132
|
+
criticalBlocks
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (!coordResult.success) {
|
|
136
|
+
throw new Error(`Transaction commit failed: ${coordResult.error}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Rollback a transaction (undo applied actions).
|
|
142
|
+
*
|
|
143
|
+
* This is called by TransactionSession.rollback() to undo all actions
|
|
144
|
+
* that were applied via applyActions().
|
|
145
|
+
*
|
|
146
|
+
* @param _stampId - The transaction stamp ID to rollback (currently unused - we clear all trackers)
|
|
147
|
+
*/
|
|
148
|
+
async rollback(_stampId: string): Promise<void> {
|
|
149
|
+
// Clear trackers for all collections
|
|
150
|
+
// This discards all pending changes that were applied via applyActions()
|
|
151
|
+
// TODO: In the future, we may want to track which collections were affected by
|
|
152
|
+
// a specific stampId and only reset those trackers
|
|
153
|
+
for (const collection of this.collections.values()) {
|
|
154
|
+
// Reset the tracker to discard all pending transforms
|
|
155
|
+
collection.tracker.reset();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Compute hash of all operations in a transaction.
|
|
161
|
+
* This hash is used for validation - validators re-execute the transaction
|
|
162
|
+
* and compare their computed operations hash with this one.
|
|
163
|
+
*/
|
|
164
|
+
private hashOperations(operations: readonly Operation[]): string {
|
|
165
|
+
const operationsData = JSON.stringify(operations);
|
|
166
|
+
const hash = Array.from(operationsData).reduce((acc, char) => {
|
|
167
|
+
const charCode = char.charCodeAt(0);
|
|
168
|
+
return ((acc << 5) - acc + charCode) & acc;
|
|
169
|
+
}, 0);
|
|
170
|
+
return `ops:${Math.abs(hash).toString(36)}`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Commit a transaction context.
|
|
175
|
+
*
|
|
176
|
+
* @deprecated Use TransactionSession instead of TransactionContext
|
|
177
|
+
* This is called by TransactionContext.commit().
|
|
178
|
+
*
|
|
179
|
+
* @param context - The transaction context to commit
|
|
180
|
+
* @returns Execution result with actions and results
|
|
181
|
+
*/
|
|
182
|
+
async commitTransaction(context: TransactionContext): Promise<ExecutionResult> {
|
|
183
|
+
const collectionActions = Array.from(context.getCollectionActions().entries()).map(
|
|
184
|
+
([collectionId, actions]) => ({ collectionId, actions })
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
if (collectionActions.length === 0) {
|
|
188
|
+
return { success: true }; // Nothing to commit
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Create transaction statements
|
|
192
|
+
const statements = createActionsStatements(collectionActions);
|
|
193
|
+
const reads = context.getReads();
|
|
194
|
+
|
|
195
|
+
// Create stamp from context
|
|
196
|
+
const stamp = createTransactionStamp(
|
|
197
|
+
'local', // TODO: Get from context or coordinator
|
|
198
|
+
Date.now(),
|
|
199
|
+
'', // TODO: Get from engine
|
|
200
|
+
context.engine
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const transaction: Transaction = {
|
|
204
|
+
stamp,
|
|
205
|
+
statements,
|
|
206
|
+
reads,
|
|
207
|
+
id: createTransactionId(stamp.id, statements, reads)
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// Create ActionsEngine for execution (TransactionContext only supports actions)
|
|
211
|
+
const { ActionsEngine } = await import('./actions-engine.js');
|
|
212
|
+
const engine = new ActionsEngine(this);
|
|
213
|
+
|
|
214
|
+
// Execute through standard path
|
|
215
|
+
return await this.execute(transaction, engine);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Execute a fully-formed transaction.
|
|
220
|
+
*
|
|
221
|
+
* This can be called directly with a complete transaction (e.g., from Quereus),
|
|
222
|
+
* or indirectly via commitTransaction().
|
|
223
|
+
*
|
|
224
|
+
* @param transaction - The transaction to execute
|
|
225
|
+
* @param engine - The engine to use for executing the transaction
|
|
226
|
+
* @returns Execution result with actions and results
|
|
227
|
+
*/
|
|
228
|
+
async execute(transaction: Transaction, engine: ITransactionEngine): Promise<ExecutionResult> {
|
|
229
|
+
// 1. Validate engine matches transaction
|
|
230
|
+
// Note: We don't enforce this strictly since the engine is passed in explicitly
|
|
231
|
+
// The caller is responsible for ensuring the correct engine is used
|
|
232
|
+
|
|
233
|
+
const result = await engine.execute(transaction);
|
|
234
|
+
if (!result.success) {
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (!result.actions || result.actions.length === 0) {
|
|
239
|
+
return { success: true }; // Nothing to do
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 2. Apply actions to collections and collect transforms
|
|
243
|
+
const collectionTransforms = new Map<CollectionId, Transforms>();
|
|
244
|
+
const criticalBlocks = new Map<CollectionId, BlockId>();
|
|
245
|
+
const actionResults = new Map<CollectionId, any[]>();
|
|
246
|
+
const allCollectionIds = result.actions.map(ca => ca.collectionId);
|
|
247
|
+
|
|
248
|
+
for (const collectionActions of result.actions) {
|
|
249
|
+
const applyResult = await this.applyActionsToCollection(
|
|
250
|
+
collectionActions,
|
|
251
|
+
transaction,
|
|
252
|
+
allCollectionIds
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
if (!applyResult.success) {
|
|
256
|
+
return { success: false, error: applyResult.error };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
collectionTransforms.set(collectionActions.collectionId, applyResult.transforms!);
|
|
260
|
+
criticalBlocks.set(collectionActions.collectionId, applyResult.logTailBlockId!);
|
|
261
|
+
actionResults.set(collectionActions.collectionId, applyResult.results!);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 3. Compute operations hash for validation
|
|
265
|
+
const allOperations = Array.from(collectionTransforms.entries()).flatMap(([collectionId, transforms]) => [
|
|
266
|
+
...Object.entries(transforms.inserts).map(([blockId, block]) =>
|
|
267
|
+
({ type: 'insert' as const, collectionId, blockId, block })
|
|
268
|
+
),
|
|
269
|
+
...Object.entries(transforms.updates).map(([blockId, operations]) =>
|
|
270
|
+
({ type: 'update' as const, collectionId, blockId, operations })
|
|
271
|
+
),
|
|
272
|
+
...transforms.deletes.map(blockId =>
|
|
273
|
+
({ type: 'delete' as const, collectionId, blockId })
|
|
274
|
+
)
|
|
275
|
+
]);
|
|
276
|
+
const operationsHash = this.hashOperations(allOperations);
|
|
277
|
+
|
|
278
|
+
// 4. Coordinate (GATHER if multi-collection)
|
|
279
|
+
const coordResult = await this.coordinateTransaction(
|
|
280
|
+
transaction,
|
|
281
|
+
operationsHash,
|
|
282
|
+
collectionTransforms,
|
|
283
|
+
criticalBlocks
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
if (!coordResult.success) {
|
|
287
|
+
return coordResult;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 4. Return results from actions
|
|
291
|
+
return {
|
|
292
|
+
success: true,
|
|
293
|
+
actions: result.actions,
|
|
294
|
+
results: actionResults
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Apply actions to a collection.
|
|
300
|
+
*
|
|
301
|
+
* This runs the action handlers, writes to the log, and collects transforms.
|
|
302
|
+
*/
|
|
303
|
+
private async applyActionsToCollection(
|
|
304
|
+
collectionActions: CollectionActions,
|
|
305
|
+
transaction: Transaction,
|
|
306
|
+
allCollectionIds: CollectionId[]
|
|
307
|
+
): Promise<{
|
|
308
|
+
success: boolean;
|
|
309
|
+
transforms?: Transforms;
|
|
310
|
+
logTailBlockId?: BlockId;
|
|
311
|
+
results?: any[];
|
|
312
|
+
error?: string;
|
|
313
|
+
}> {
|
|
314
|
+
const collection = this.collections.get(collectionActions.collectionId);
|
|
315
|
+
if (!collection) {
|
|
316
|
+
return {
|
|
317
|
+
success: false,
|
|
318
|
+
error: `Collection not found: ${collectionActions.collectionId}`
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// At this point, actions have already been executed through collection.act()
|
|
323
|
+
// when they were added to the TransactionContext. The collection's tracker
|
|
324
|
+
// already has the transforms, and the actions are in the pending buffer.
|
|
325
|
+
|
|
326
|
+
// Get transforms from the collection's tracker
|
|
327
|
+
const transforms = collection.tracker.transforms;
|
|
328
|
+
|
|
329
|
+
// Write actions to the collection's log to get the log tail block ID
|
|
330
|
+
const log = await Log.open(collection.tracker, collectionActions.collectionId);
|
|
331
|
+
if (!log) {
|
|
332
|
+
return {
|
|
333
|
+
success: false,
|
|
334
|
+
error: `Log not found for collection ${collectionActions.collectionId}`
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Generate action ID from transaction ID
|
|
339
|
+
const actionId = transaction.id;
|
|
340
|
+
const newRev = (collection['source'].actionContext?.rev ?? 0) + 1;
|
|
341
|
+
|
|
342
|
+
// Add actions to log (this updates the tracker with log block changes)
|
|
343
|
+
const addResult = await log.addActions(
|
|
344
|
+
collectionActions.actions,
|
|
345
|
+
actionId,
|
|
346
|
+
newRev,
|
|
347
|
+
() => blockIdsForTransforms(transforms),
|
|
348
|
+
allCollectionIds
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
// Return the transforms and log tail block ID
|
|
352
|
+
return {
|
|
353
|
+
success: true,
|
|
354
|
+
transforms,
|
|
355
|
+
logTailBlockId: addResult.tailPath.block.header.id,
|
|
356
|
+
results: [] // TODO: Collect results from action handlers when we support read operations
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Coordinate a transaction across multiple collections.
|
|
362
|
+
*
|
|
363
|
+
* @param transaction - The transaction to coordinate
|
|
364
|
+
* @param operationsHash - Hash of all operations for validation
|
|
365
|
+
* @param collectionTransforms - Map of collectionId to its transforms
|
|
366
|
+
* @param criticalBlocks - Map of collectionId to its log tail blockId
|
|
367
|
+
*/
|
|
368
|
+
private async coordinateTransaction(
|
|
369
|
+
transaction: Transaction,
|
|
370
|
+
operationsHash: string,
|
|
371
|
+
collectionTransforms: Map<CollectionId, Transforms>,
|
|
372
|
+
criticalBlocks: Map<CollectionId, BlockId>
|
|
373
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
374
|
+
// 1. GATHER phase: collect critical cluster nominees (skip if single collection)
|
|
375
|
+
const criticalBlockIds = Array.from(criticalBlocks.values());
|
|
376
|
+
const superclusterNominees = await this.gatherPhase(criticalBlockIds);
|
|
377
|
+
|
|
378
|
+
// 2. PEND phase: distribute to all block clusters
|
|
379
|
+
const pendResult = await this.pendPhase(
|
|
380
|
+
transaction,
|
|
381
|
+
operationsHash,
|
|
382
|
+
collectionTransforms,
|
|
383
|
+
superclusterNominees
|
|
384
|
+
);
|
|
385
|
+
if (!pendResult.success) {
|
|
386
|
+
return pendResult;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// 3. COMMIT phase: commit to all critical blocks
|
|
390
|
+
const commitResult = await this.commitPhase(
|
|
391
|
+
transaction.id as ActionId,
|
|
392
|
+
criticalBlockIds,
|
|
393
|
+
pendResult.pendedBlockIds!
|
|
394
|
+
);
|
|
395
|
+
if (!commitResult.success) {
|
|
396
|
+
// Cancel pending actions on failure
|
|
397
|
+
await this.cancelPhase(transaction.id as ActionId, collectionTransforms);
|
|
398
|
+
return commitResult;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// 4. PROPAGATE and CHECKPOINT phases are handled by clusters automatically
|
|
402
|
+
// (as per user's note: "managed by each cluster, the client doesn't have to worry about them")
|
|
403
|
+
|
|
404
|
+
return { success: true };
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* GATHER phase: Collect nominees from critical clusters.
|
|
409
|
+
*
|
|
410
|
+
* Skip if only one collection affected (single-collection consensus).
|
|
411
|
+
*
|
|
412
|
+
* @param criticalBlockIds - Block IDs of all log tails
|
|
413
|
+
* @returns Set of peer IDs to use for consensus, or null for single-collection
|
|
414
|
+
*/
|
|
415
|
+
private async gatherPhase(
|
|
416
|
+
criticalBlockIds: readonly BlockId[]
|
|
417
|
+
): Promise<ReadonlySet<PeerId> | null> {
|
|
418
|
+
// Skip GATHER if only one collection affected
|
|
419
|
+
if (criticalBlockIds.length === 1) {
|
|
420
|
+
return null; // Use normal single-collection consensus
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Check if transactor supports cluster queries (optional method)
|
|
424
|
+
if (!this.transactor.queryClusterNominees) {
|
|
425
|
+
// Transactor doesn't support cluster queries - proceed without supercluster
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Query each critical cluster for their nominees and merge into supercluster
|
|
430
|
+
const nomineePromises = criticalBlockIds.map(blockId =>
|
|
431
|
+
this.transactor.queryClusterNominees!(blockId)
|
|
432
|
+
);
|
|
433
|
+
const results = await Promise.all(nomineePromises);
|
|
434
|
+
|
|
435
|
+
// Merge all nominees into a single set
|
|
436
|
+
const supercluster = results.reduce(
|
|
437
|
+
(acc, result) => {
|
|
438
|
+
result.nominees.forEach(nominee => acc.add(nominee));
|
|
439
|
+
return acc;
|
|
440
|
+
},
|
|
441
|
+
new Set<PeerId>()
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
return supercluster;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* PEND phase: Distribute transaction to all affected block clusters.
|
|
449
|
+
*
|
|
450
|
+
* @param transaction - The full transaction for replay/validation
|
|
451
|
+
* @param operationsHash - Hash of all operations for validation
|
|
452
|
+
* @param collectionTransforms - Map of collectionId to its transforms
|
|
453
|
+
* @param superclusterNominees - Nominees for multi-collection consensus (null for single-collection)
|
|
454
|
+
*/
|
|
455
|
+
private async pendPhase(
|
|
456
|
+
transaction: Transaction,
|
|
457
|
+
operationsHash: string,
|
|
458
|
+
collectionTransforms: ReadonlyMap<CollectionId, Transforms>,
|
|
459
|
+
superclusterNominees: ReadonlySet<PeerId> | null
|
|
460
|
+
): Promise<{ success: boolean; error?: string; pendedBlockIds?: Map<CollectionId, BlockId[]> }> {
|
|
461
|
+
if (collectionTransforms.size === 0) {
|
|
462
|
+
return { success: false, error: 'No transforms to pend' };
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const pendedBlockIds = new Map<CollectionId, BlockId[]>();
|
|
466
|
+
const actionId = transaction.id as ActionId;
|
|
467
|
+
const nominees = superclusterNominees ? Array.from(superclusterNominees) : undefined;
|
|
468
|
+
|
|
469
|
+
// Pend each collection's transforms
|
|
470
|
+
for (const [collectionId, transforms] of collectionTransforms.entries()) {
|
|
471
|
+
const collection = this.collections.get(collectionId);
|
|
472
|
+
if (!collection) {
|
|
473
|
+
return { success: false, error: `Collection not found: ${collectionId}` };
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Get revision from the collection's source
|
|
477
|
+
const rev = (collection['source'].actionContext?.rev ?? 0) + 1;
|
|
478
|
+
|
|
479
|
+
// Create pend request with transaction and operations hash for validation
|
|
480
|
+
const pendRequest: PendRequest = {
|
|
481
|
+
actionId,
|
|
482
|
+
rev,
|
|
483
|
+
transforms,
|
|
484
|
+
policy: 'r', // Return policy: fail but return pending actions
|
|
485
|
+
transaction,
|
|
486
|
+
operationsHash,
|
|
487
|
+
superclusterNominees: nominees
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// Pend the transaction
|
|
491
|
+
const pendResult = await this.transactor.pend(pendRequest);
|
|
492
|
+
if (!pendResult.success) {
|
|
493
|
+
return {
|
|
494
|
+
success: false,
|
|
495
|
+
error: `Pend failed for collection ${collectionId}: ${pendResult.reason}`
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Store the pended block IDs for commit phase
|
|
500
|
+
pendedBlockIds.set(collectionId, pendResult.blockIds);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return { success: true, pendedBlockIds };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* COMMIT phase: Commit to all critical blocks.
|
|
508
|
+
*/
|
|
509
|
+
private async commitPhase(
|
|
510
|
+
actionId: ActionId,
|
|
511
|
+
criticalBlockIds: BlockId[],
|
|
512
|
+
pendedBlockIds: Map<CollectionId, BlockId[]>
|
|
513
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
514
|
+
// Commit each collection's transaction
|
|
515
|
+
for (const [collectionId, blockIds] of pendedBlockIds.entries()) {
|
|
516
|
+
const collection = this.collections.get(collectionId);
|
|
517
|
+
if (!collection) {
|
|
518
|
+
return { success: false, error: `Collection not found: ${collectionId}` };
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Get revision
|
|
522
|
+
const rev = (collection['source'].actionContext?.rev ?? 0) + 1;
|
|
523
|
+
|
|
524
|
+
// Find the critical block (log tail) for this collection
|
|
525
|
+
const logTailBlockId = criticalBlockIds.find(blockId =>
|
|
526
|
+
blockIds.includes(blockId)
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
if (!logTailBlockId) {
|
|
530
|
+
return {
|
|
531
|
+
success: false,
|
|
532
|
+
error: `Log tail block not found for collection ${collectionId}`
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Create commit request
|
|
537
|
+
const commitRequest: CommitRequest = {
|
|
538
|
+
actionId,
|
|
539
|
+
blockIds,
|
|
540
|
+
tailId: logTailBlockId,
|
|
541
|
+
rev
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// Commit the transaction
|
|
545
|
+
const commitResult = await this.transactor.commit(commitRequest);
|
|
546
|
+
if (!commitResult.success) {
|
|
547
|
+
return {
|
|
548
|
+
success: false,
|
|
549
|
+
error: `Commit failed for collection ${collectionId}`
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return { success: true };
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* CANCEL phase: Cancel pending actions on all affected blocks.
|
|
559
|
+
*/
|
|
560
|
+
private async cancelPhase(
|
|
561
|
+
actionId: ActionId,
|
|
562
|
+
collectionTransforms: Map<CollectionId, Transforms>
|
|
563
|
+
): Promise<void> {
|
|
564
|
+
// Cancel each collection's pending transaction
|
|
565
|
+
for (const [collectionId, transforms] of collectionTransforms.entries()) {
|
|
566
|
+
const collection = this.collections.get(collectionId);
|
|
567
|
+
if (!collection) {
|
|
568
|
+
continue; // Skip if collection not found
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Get the block IDs from transforms
|
|
572
|
+
const blockIds = blockIdsForTransforms(transforms);
|
|
573
|
+
|
|
574
|
+
// Cancel the transaction
|
|
575
|
+
await this.transactor.cancel({
|
|
576
|
+
actionId,
|
|
577
|
+
blockIds
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
}
|
|
583
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
Transaction,
|
|
3
|
+
TransactionStamp,
|
|
4
|
+
ReadDependency,
|
|
5
|
+
TransactionRef,
|
|
6
|
+
ITransactionEngine,
|
|
7
|
+
ExecutionResult,
|
|
8
|
+
CollectionActions,
|
|
9
|
+
ValidationResult,
|
|
10
|
+
ITransactionValidator
|
|
11
|
+
} from './transaction.js';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
createTransactionStamp,
|
|
15
|
+
createTransactionId
|
|
16
|
+
} from './transaction.js';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
ActionsEngine,
|
|
20
|
+
ACTIONS_ENGINE_ID,
|
|
21
|
+
createActionsStatements
|
|
22
|
+
} from './actions-engine.js';
|
|
23
|
+
|
|
24
|
+
export type { ActionsStatement } from './actions-engine.js';
|
|
25
|
+
|
|
26
|
+
export { TransactionCoordinator } from './coordinator.js';
|
|
27
|
+
export { TransactionContext } from './context.js';
|
|
28
|
+
export { TransactionSession } from './session.js';
|
|
29
|
+
export { TransactionValidator } from './validator.js';
|
|
30
|
+
export type { EngineRegistration, ValidationCoordinatorFactory } from './validator.js';
|