@requence/event-sourcing 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-z2yp4rve.js → chunk-57b88rt5.js} +7 -7
- package/dist/chunk-57b88rt5.js.map +10 -0
- package/dist/chunk-jd4q8fcf.js.map +2 -2
- package/dist/{chunk-gq80tgvf.js → chunk-pc1q4se9.js} +14 -3
- package/dist/chunk-pc1q4se9.js.map +10 -0
- package/dist/{chunk-wzw95hzk.js → chunk-vep2byx4.js} +10 -8
- package/dist/chunk-vep2byx4.js.map +10 -0
- package/dist/{chunk-fkzd741s.js → chunk-vvv14qxy.js} +4 -3
- package/dist/chunk-vvv14qxy.js.map +10 -0
- package/dist/createAggregateRoot.d.ts.map +1 -1
- package/dist/createAggregateRoot.js +2 -2
- package/dist/createEventStore.d.ts +4 -3
- package/dist/createEventStore.d.ts.map +1 -1
- package/dist/createEventStore.js +3 -3
- package/dist/createProcessManager.d.ts +13 -1
- package/dist/createProcessManager.d.ts.map +1 -1
- package/dist/createProcessManager.js +1 -1
- package/dist/drizzle/index.js +4 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/memory/index.js +4 -4
- package/dist/transaction.d.ts +19 -1
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +1 -1
- package/package.json +1 -1
- package/src/createAggregateRoot.ts +37 -10
- package/src/createEventStore.ts +14 -7
- package/src/createProcessManager.ts +15 -1
- package/src/index.ts +2 -0
- package/src/tests/processManager.spec.ts +70 -0
- package/src/tests/transaction.spec.ts +53 -0
- package/src/transaction.ts +34 -2
- package/dist/chunk-fkzd741s.js.map +0 -10
- package/dist/chunk-gq80tgvf.js.map +0 -10
- package/dist/chunk-wzw95hzk.js.map +0 -10
- package/dist/chunk-z2yp4rve.js.map +0 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createProcessManager.d.ts","sourceRoot":"","sources":["../src/createProcessManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAQnE,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,aAAa,EACb,IAAI,EACJ,KAAK,EACL,YAAY,EACb,MAAM,mBAAmB,CAAA;AAE1B,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"createProcessManager.d.ts","sourceRoot":"","sources":["../src/createProcessManager.ts"],"names":[],"mappings":"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"}
|
package/dist/drizzle/index.js
CHANGED
|
@@ -11,18 +11,18 @@ import {
|
|
|
11
11
|
} from "../chunk-jd4q8fcf.js";
|
|
12
12
|
import {
|
|
13
13
|
createEventStore
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-57b88rt5.js";
|
|
15
15
|
import"../chunk-24xjphpk.js";
|
|
16
16
|
import {
|
|
17
17
|
createAggregateRoot
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-vep2byx4.js";
|
|
19
19
|
import"../chunk-ty9bhdvx.js";
|
|
20
|
-
import"../chunk-
|
|
20
|
+
import"../chunk-vvv14qxy.js";
|
|
21
21
|
import {
|
|
22
22
|
extendTypes,
|
|
23
23
|
superjson
|
|
24
24
|
} from "../chunk-6q8mr1sg.js";
|
|
25
|
-
import"../chunk-
|
|
25
|
+
import"../chunk-pc1q4se9.js";
|
|
26
26
|
import"../chunk-z388cd25.js";
|
|
27
27
|
import"../chunk-3ejt4h7x.js";
|
|
28
28
|
import"../chunk-8qn1nqnh.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,11 @@ export { createEventStore } from './createEventStore.ts';
|
|
|
3
3
|
export type { BaseOutputEvent as Event } from './utilityTypes.d.ts';
|
|
4
4
|
export { type Snapshot as ProjectionSnapshot, isInsideProjection, getProjectionInfo, } from './createProjection.ts';
|
|
5
5
|
export type { Checkpoint } from './createCheckpointApi.ts';
|
|
6
|
-
export { isInsideProcessManager, getProcessManagerInfo, } from './createProcessManager.ts';
|
|
6
|
+
export { type ProcessManagerOptions, isInsideProcessManager, getProcessManagerInfo, } from './createProcessManager.ts';
|
|
7
7
|
export { isInsideEventListener, getEventListenerInfo, } from './createEventListener.ts';
|
|
8
8
|
export * from './errors.ts';
|
|
9
9
|
export { type Snapshot as AggregateRootSnapshot, type AnyAggregateRoot, type AnyStream, type SettledOptions, createAggregateRoot, } from './createAggregateRoot.ts';
|
|
10
|
+
export type { TransactionOptions } from './transaction.ts';
|
|
10
11
|
export { skipRefreshing } from './refresh.ts';
|
|
11
12
|
export { skipReplay } from './replay.ts';
|
|
12
13
|
export declare function isStreamId(stream: Stream): stream is StreamId | StreamIdEvents;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,cAAc,EACf,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,YAAY,EAAE,eAAe,IAAI,KAAK,EAAE,MAAM,qBAAqB,CAAA;AACnE,OAAO,EACL,KAAK,QAAQ,IAAI,kBAAkB,EACnC,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,0BAA0B,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,OAAO,EACL,KAAK,QAAQ,IAAI,qBAAqB,EACtC,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,GACb,MAAM,IAAI,QAAQ,GAAG,cAAc,CAErC;AACD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GACb,MAAM,IAAI,YAAY,GAAG,cAAc,CAEzC;AACD,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,cAAc,EACf,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,YAAY,EAAE,eAAe,IAAI,KAAK,EAAE,MAAM,qBAAqB,CAAA;AACnE,OAAO,EACL,KAAK,QAAQ,IAAI,kBAAkB,EACnC,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EACL,KAAK,qBAAqB,EAC1B,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,0BAA0B,CAAA;AACjC,cAAc,aAAa,CAAA;AAC3B,OAAO,EACL,KAAK,QAAQ,IAAI,qBAAqB,EACtC,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,mBAAmB,GACpB,MAAM,0BAA0B,CAAA;AAEjC,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,GACb,MAAM,IAAI,QAAQ,GAAG,cAAc,CAErC;AACD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GACb,MAAM,IAAI,YAAY,GAAG,cAAc,CAEzC;AACD,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -4,21 +4,21 @@ import {
|
|
|
4
4
|
} from "./chunk-jd4q8fcf.js";
|
|
5
5
|
import {
|
|
6
6
|
createEventStore
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-57b88rt5.js";
|
|
8
8
|
import {
|
|
9
9
|
getEventListenerInfo,
|
|
10
10
|
isInsideEventListener
|
|
11
11
|
} from "./chunk-24xjphpk.js";
|
|
12
12
|
import {
|
|
13
13
|
createAggregateRoot
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-vep2byx4.js";
|
|
15
15
|
import"./chunk-ty9bhdvx.js";
|
|
16
16
|
import {
|
|
17
17
|
getProcessManagerInfo,
|
|
18
18
|
isInsideProcessManager
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-vvv14qxy.js";
|
|
20
20
|
import"./chunk-6q8mr1sg.js";
|
|
21
|
-
import"./chunk-
|
|
21
|
+
import"./chunk-pc1q4se9.js";
|
|
22
22
|
import"./chunk-z388cd25.js";
|
|
23
23
|
import {
|
|
24
24
|
getProjectionInfo,
|
package/dist/memory/index.js
CHANGED
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
} from "../chunk-jd4q8fcf.js";
|
|
5
5
|
import {
|
|
6
6
|
createEventStore
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-57b88rt5.js";
|
|
8
8
|
import"../chunk-24xjphpk.js";
|
|
9
9
|
import {
|
|
10
10
|
createAggregateRoot
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-vep2byx4.js";
|
|
12
12
|
import"../chunk-ty9bhdvx.js";
|
|
13
|
-
import"../chunk-
|
|
13
|
+
import"../chunk-vvv14qxy.js";
|
|
14
14
|
import"../chunk-6q8mr1sg.js";
|
|
15
|
-
import"../chunk-
|
|
15
|
+
import"../chunk-pc1q4se9.js";
|
|
16
16
|
import"../chunk-z388cd25.js";
|
|
17
17
|
import"../chunk-3ejt4h7x.js";
|
|
18
18
|
import"../chunk-8qn1nqnh.js";
|
package/dist/transaction.d.ts
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
|
+
import type { SettledOptions } from './createAggregateRoot.ts';
|
|
1
2
|
export type TransactionDelay = {
|
|
2
3
|
resolve: () => void;
|
|
3
4
|
reject: (error: Error) => void;
|
|
4
5
|
commit: () => Promise<void>;
|
|
5
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Options for a transaction run.
|
|
9
|
+
*
|
|
10
|
+
* `settled` — default {@link SettledOptions} applied when the transaction
|
|
11
|
+
* auto-settles the streams whose commands were dispatched inside the handler
|
|
12
|
+
* (explicit `settled()` calls are not allowed there).
|
|
13
|
+
*/
|
|
14
|
+
export type TransactionOptions = {
|
|
15
|
+
settled?: SettledOptions;
|
|
16
|
+
};
|
|
6
17
|
export default function createTransaction(): {
|
|
7
18
|
readonly active: boolean;
|
|
19
|
+
readonly settledDefaults: SettledOptions | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Runs the handler outside the transaction scope. Used by the settle
|
|
22
|
+
* retry: a retried append already passed the transaction gate on its
|
|
23
|
+
* first attempt and must not re-enter the (committed) transaction.
|
|
24
|
+
*/
|
|
25
|
+
exit<T>(handler: () => T): T;
|
|
8
26
|
delay(): TransactionDelay;
|
|
9
27
|
after(onAfter: () => Promise<any>): void;
|
|
10
|
-
run<T extends () => any>(handler: T): Promise<any>;
|
|
28
|
+
run<T extends () => any>(handler: T, options?: TransactionOptions): Promise<any>;
|
|
11
29
|
};
|
|
12
30
|
export type Transaction = ReturnType<typeof createTransaction>;
|
|
13
31
|
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAgB9D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC9B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB;;;IAiBrC;;;;OAIG;SACE,CAAC,WAAW,MAAM,CAAC,GAAG,CAAC;aAInB,gBAAgB;mBAgCV,MAAM,OAAO,CAAC,GAAG,CAAC;QAIvB,CAAC,SAAS,MAAM,GAAG,WAAW,CAAC,YAAY,kBAAkB;EAyB1E;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
|
package/dist/transaction.js
CHANGED
package/package.json
CHANGED
|
@@ -512,6 +512,10 @@ export function createAggregateRoot<Name extends string>(type: Name) {
|
|
|
512
512
|
streamId: string,
|
|
513
513
|
config: CreateStreamConfig = {},
|
|
514
514
|
) => {
|
|
515
|
+
// Captured at the dispatch site so a settle() retry can re-apply the
|
|
516
|
+
// commands within the same AsyncLocalStorage state (user metadata scopes,
|
|
517
|
+
// process-manager info, …) that the original attempt observed.
|
|
518
|
+
const dispatchContext = AsyncLocalStorage.snapshot()
|
|
515
519
|
let version = 0
|
|
516
520
|
const snapshotApi = createSnapshotApi?.(
|
|
517
521
|
state,
|
|
@@ -791,7 +795,7 @@ export function createAggregateRoot<Name extends string>(type: Name) {
|
|
|
791
795
|
const parentProcessManager = getProcessManagerInfo()
|
|
792
796
|
if (parentProcessManager) {
|
|
793
797
|
const error = new Error(
|
|
794
|
-
`aggregateRoot.settled() cannot be called inside a process manager. Attempted on aggregate stream "${type}" within Process Manager ${parentProcessManager.name}.`,
|
|
798
|
+
`aggregateRoot.settled() cannot be called inside a process manager. Attempted on aggregate stream "${type}" within Process Manager ${parentProcessManager.name}. To configure how dispatched streams settle, pass options to createProcessManager(name, { settled }).`,
|
|
795
799
|
)
|
|
796
800
|
commandChain = commandChain.then(() => error)
|
|
797
801
|
throw error
|
|
@@ -799,7 +803,7 @@ export function createAggregateRoot<Name extends string>(type: Name) {
|
|
|
799
803
|
|
|
800
804
|
if (transaction.active) {
|
|
801
805
|
const error = new Error(
|
|
802
|
-
`aggregateRoot.settled() cannot be called inside a transaction. Attempted on aggregate stream "${type}".`,
|
|
806
|
+
`aggregateRoot.settled() cannot be called inside a transaction. Attempted on aggregate stream "${type}". To configure how dispatched streams settle, pass options to transaction(handler, { settled }).`,
|
|
803
807
|
)
|
|
804
808
|
commandChain = commandChain.then(() => error)
|
|
805
809
|
throw error
|
|
@@ -819,12 +823,27 @@ export function createAggregateRoot<Name extends string>(type: Name) {
|
|
|
819
823
|
if (maxRetries > 0 && error instanceof ConcurrencyError) {
|
|
820
824
|
await releaseLock?.()
|
|
821
825
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
826
|
+
// Re-create the stream within the async context captured at the
|
|
827
|
+
// dispatch site, so the replayed commands and event
|
|
828
|
+
// post-processing observe the same AsyncLocalStorage state as
|
|
829
|
+
// the original attempt. Two scopes are explicitly exited: the
|
|
830
|
+
// transaction (the first attempt already passed its commit gate;
|
|
831
|
+
// re-entering the committed store would swallow errors and
|
|
832
|
+
// register dead delays) and the upstream collection (this retry
|
|
833
|
+
// is settled right here, not through another auto-settle
|
|
834
|
+
// registration).
|
|
835
|
+
const retryStream = dispatchContext(() =>
|
|
836
|
+
transaction.exit(() =>
|
|
837
|
+
downstreamRootsPromiseStore.exit(() =>
|
|
838
|
+
createStream(clone(initialState), streamId, {
|
|
839
|
+
load: true,
|
|
840
|
+
filter: config.filter,
|
|
841
|
+
replayCommands: dispatchedCommands,
|
|
842
|
+
errorHandlerEntries: Array.from(errorHandlers),
|
|
843
|
+
}),
|
|
844
|
+
),
|
|
845
|
+
),
|
|
846
|
+
)
|
|
828
847
|
|
|
829
848
|
return retryStream.commands.settled({
|
|
830
849
|
...options,
|
|
@@ -849,8 +868,16 @@ export function createAggregateRoot<Name extends string>(type: Name) {
|
|
|
849
868
|
},
|
|
850
869
|
}
|
|
851
870
|
|
|
852
|
-
|
|
853
|
-
|
|
871
|
+
// Streams dispatched inside a process manager or a transaction cannot
|
|
872
|
+
// call settled() themselves — the surrounding scope settles them when it
|
|
873
|
+
// completes. Capture the defaults declared on that scope
|
|
874
|
+
// (createProcessManager / transaction options) so the auto-settle
|
|
875
|
+
// inherits them.
|
|
876
|
+
const autoSettleOptions =
|
|
877
|
+
getProcessManagerInfo()?.settledDefaults ?? transaction.settledDefaults
|
|
878
|
+
|
|
879
|
+
registerRootPromiseToUpstream(() => api.commands.settled(autoSettleOptions))
|
|
880
|
+
transaction.after(() => api.commands.settled(autoSettleOptions))
|
|
854
881
|
|
|
855
882
|
// Fold existing events before commands run (loadStream, and every retry).
|
|
856
883
|
if (config.load) {
|
package/src/createEventStore.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
type InternalProcessManager,
|
|
15
15
|
type ProcessManagerApi,
|
|
16
|
+
type ProcessManagerOptions,
|
|
16
17
|
buildProcessManagerCreator,
|
|
17
18
|
} from './createProcessManager.ts'
|
|
18
19
|
import {
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
} from './createProjection.ts'
|
|
25
26
|
import lock, { type LockCreator } from './lock.ts'
|
|
26
27
|
import { withRefreshing } from './refresh.ts'
|
|
27
|
-
import createTransaction from './transaction.ts'
|
|
28
|
+
import createTransaction, { type TransactionOptions } from './transaction.ts'
|
|
28
29
|
import type {
|
|
29
30
|
BaseInputEvent,
|
|
30
31
|
BaseOutputEvent,
|
|
@@ -126,7 +127,10 @@ export type EventStore<
|
|
|
126
127
|
): SupportsProjectionSnapshots extends true
|
|
127
128
|
? ProjectionApiWithSnapshots<Event>
|
|
128
129
|
: ProjectionApi<Event>
|
|
129
|
-
createProcessManager(
|
|
130
|
+
createProcessManager(
|
|
131
|
+
name: string,
|
|
132
|
+
options?: ProcessManagerOptions,
|
|
133
|
+
): ProcessManagerApi<never, Event>
|
|
130
134
|
createEventListener(name: string): EventListenerApi<Event>
|
|
131
135
|
rebuild: () => Promise<void>
|
|
132
136
|
isReady: () => Promise<void>
|
|
@@ -134,7 +138,10 @@ export type EventStore<
|
|
|
134
138
|
getAggregateRoot<S extends Root['type']>(
|
|
135
139
|
type: S,
|
|
136
140
|
): Root extends { type: S } ? Root : never
|
|
137
|
-
transaction<T extends () => any>(
|
|
141
|
+
transaction<T extends () => any>(
|
|
142
|
+
handler: T,
|
|
143
|
+
options?: TransactionOptions,
|
|
144
|
+
): Promise<Awaited<ReturnType<T>>>
|
|
138
145
|
}
|
|
139
146
|
|
|
140
147
|
export function createEventStore<const Root extends AnyAggregateRoot>(
|
|
@@ -357,11 +364,11 @@ export function createEventStore<const Root extends AnyAggregateRoot>(
|
|
|
357
364
|
}
|
|
358
365
|
return api
|
|
359
366
|
},
|
|
360
|
-
createProcessManager(name) {
|
|
367
|
+
createProcessManager(name, options) {
|
|
361
368
|
if (processManagers.has(name)) {
|
|
362
369
|
throw new Error(`Process Manager ${name} is already registered`)
|
|
363
370
|
}
|
|
364
|
-
const api = baseCreateProcessManager(name)
|
|
371
|
+
const api = baseCreateProcessManager(name, options)
|
|
365
372
|
|
|
366
373
|
const internalApi = api as unknown as InternalProcessManager
|
|
367
374
|
internalApi.setRelatedStreamEvents((handlers) =>
|
|
@@ -464,8 +471,8 @@ export function createEventStore<const Root extends AnyAggregateRoot>(
|
|
|
464
471
|
(aggregateRoot) => aggregateRoot.type === type,
|
|
465
472
|
) as any
|
|
466
473
|
},
|
|
467
|
-
async transaction(handler) {
|
|
468
|
-
return transaction.run(handler)
|
|
474
|
+
async transaction(handler, options) {
|
|
475
|
+
return transaction.run(handler, options)
|
|
469
476
|
},
|
|
470
477
|
} as EventStore<any, Root>
|
|
471
478
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
2
|
|
|
3
|
+
import type { SettledOptions } from './createAggregateRoot.ts'
|
|
3
4
|
import {
|
|
4
5
|
type CheckpointApi,
|
|
5
6
|
type CheckpointMethods,
|
|
@@ -23,9 +24,21 @@ import type {
|
|
|
23
24
|
StreamEvents,
|
|
24
25
|
} from './utilityTypes.js'
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Options for `createProcessManager`.
|
|
29
|
+
*
|
|
30
|
+
* `settled` — default {@link SettledOptions} applied when the process manager
|
|
31
|
+
* auto-settles the streams its handlers dispatched commands on (explicit
|
|
32
|
+
* `settled()` calls are not allowed inside a process manager).
|
|
33
|
+
*/
|
|
34
|
+
export type ProcessManagerOptions = {
|
|
35
|
+
settled?: SettledOptions
|
|
36
|
+
}
|
|
37
|
+
|
|
26
38
|
type ProcessManagerInfo = {
|
|
27
39
|
name: string
|
|
28
40
|
event: BaseOutputEvent
|
|
41
|
+
settledDefaults?: SettledOptions
|
|
29
42
|
}
|
|
30
43
|
const processManagerInfoStore = new AsyncLocalStorage<ProcessManagerInfo>()
|
|
31
44
|
|
|
@@ -129,7 +142,7 @@ export function buildProcessManagerCreator(params: {
|
|
|
129
142
|
checkpoint: CheckpointMethods
|
|
130
143
|
onRefresh?: OnProgress
|
|
131
144
|
}) {
|
|
132
|
-
return (name: string): ProcessManagerApi => {
|
|
145
|
+
return (name: string, options?: ProcessManagerOptions): ProcessManagerApi => {
|
|
133
146
|
let idle = true
|
|
134
147
|
let createEventHandlers: (
|
|
135
148
|
state: any,
|
|
@@ -196,6 +209,7 @@ export function buildProcessManagerCreator(params: {
|
|
|
196
209
|
{
|
|
197
210
|
name,
|
|
198
211
|
event,
|
|
212
|
+
settledDefaults: options?.settled,
|
|
199
213
|
},
|
|
200
214
|
async () => {
|
|
201
215
|
try {
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export {
|
|
|
14
14
|
} from './createProjection.ts'
|
|
15
15
|
export type { Checkpoint } from './createCheckpointApi.ts'
|
|
16
16
|
export {
|
|
17
|
+
type ProcessManagerOptions,
|
|
17
18
|
isInsideProcessManager,
|
|
18
19
|
getProcessManagerInfo,
|
|
19
20
|
} from './createProcessManager.ts'
|
|
@@ -30,6 +31,7 @@ export {
|
|
|
30
31
|
createAggregateRoot,
|
|
31
32
|
} from './createAggregateRoot.ts'
|
|
32
33
|
|
|
34
|
+
export type { TransactionOptions } from './transaction.ts'
|
|
33
35
|
export { skipRefreshing } from './refresh.ts'
|
|
34
36
|
export { skipReplay } from './replay.ts'
|
|
35
37
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
|
+
import { setTimeout } from 'node:timers/promises'
|
|
3
|
+
|
|
1
4
|
import { describe, expect, it } from 'bun:test'
|
|
2
5
|
|
|
6
|
+
import { createAggregateRoot } from '../createAggregateRoot.ts'
|
|
3
7
|
import { createUserAggregate, setupEventStore } from './setup.ts'
|
|
8
|
+
import lock from '../lock.ts'
|
|
4
9
|
import { skipRefreshing } from '../refresh.ts'
|
|
5
10
|
|
|
6
11
|
describe('ProcessManager', () => {
|
|
@@ -182,4 +187,69 @@ describe('ProcessManager', () => {
|
|
|
182
187
|
await eventStore.rebuild()
|
|
183
188
|
expect(called).toBe(1)
|
|
184
189
|
})
|
|
190
|
+
|
|
191
|
+
it('applies settled defaults from options to dispatched streams', async () => {
|
|
192
|
+
const context = new AsyncLocalStorage<string>()
|
|
193
|
+
|
|
194
|
+
const sourceAggregate = createAggregateRoot('sources')
|
|
195
|
+
.withEvents(({ z }) => ({
|
|
196
|
+
SourceCreated: z.string(),
|
|
197
|
+
}))
|
|
198
|
+
.withCommands((event) => ({
|
|
199
|
+
create(name: string) {
|
|
200
|
+
return event('SourceCreated', name)
|
|
201
|
+
},
|
|
202
|
+
}))
|
|
203
|
+
|
|
204
|
+
const targetAggregate = createAggregateRoot('targets')
|
|
205
|
+
.withEvents(({ z }) => ({
|
|
206
|
+
Written: z.string(),
|
|
207
|
+
}))
|
|
208
|
+
.withCommands((event) => ({
|
|
209
|
+
async write(delay: number, name: string) {
|
|
210
|
+
await setTimeout(delay)
|
|
211
|
+
return event('Written', `${name}:${context.getStore() ?? 'none'}`)
|
|
212
|
+
},
|
|
213
|
+
}))
|
|
214
|
+
|
|
215
|
+
const { eventStore, pseudoEventStore } = setupEventStore(
|
|
216
|
+
[sourceAggregate, targetAggregate],
|
|
217
|
+
{ lock: lock(40) }, // 40ms
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
eventStore
|
|
221
|
+
.createProcessManager('cascade', { settled: { maxRetries: 3 } })
|
|
222
|
+
.withEventHandlers({
|
|
223
|
+
onSourceCreated() {
|
|
224
|
+
context.run('pm', () => {
|
|
225
|
+
targetAggregate.loadStream('t').write(100, 'PM')
|
|
226
|
+
})
|
|
227
|
+
},
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// The process manager's write holds the lock on targets:t, but its 100ms
|
|
231
|
+
// command outlives the 40ms lock TTL, so the direct write slips in and
|
|
232
|
+
// advances the stream to v1. The process manager's append then loses the
|
|
233
|
+
// race — without the settled defaults declared above the ConcurrencyError
|
|
234
|
+
// would surface through the source stream's settled(); with them the
|
|
235
|
+
// auto-settle reloads and re-applies the command.
|
|
236
|
+
await Promise.all([
|
|
237
|
+
sourceAggregate.newStream().create('s').settled(),
|
|
238
|
+
(async () => {
|
|
239
|
+
await setTimeout(30)
|
|
240
|
+
await targetAggregate.loadStream('t').write(5, 'direct').settled()
|
|
241
|
+
})(),
|
|
242
|
+
])
|
|
243
|
+
|
|
244
|
+
const persisted = pseudoEventStore.filter(
|
|
245
|
+
(event) => event.streamType === 'targets',
|
|
246
|
+
)
|
|
247
|
+
// 'PM:pm' also proves the retry re-ran the command inside the dispatch
|
|
248
|
+
// site's async context — the AsyncLocalStorage value survived the retry.
|
|
249
|
+
expect(persisted.map((event) => event.payload)).toEqual([
|
|
250
|
+
'direct:none',
|
|
251
|
+
'PM:pm',
|
|
252
|
+
])
|
|
253
|
+
expect(persisted.map((event) => event.streamVersion)).toEqual([1, 2])
|
|
254
|
+
})
|
|
185
255
|
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
1
2
|
import { setTimeout } from 'node:timers/promises'
|
|
2
3
|
|
|
3
4
|
import { describe, expect, it } from 'bun:test'
|
|
@@ -6,6 +7,7 @@ import { z } from 'zod/v4'
|
|
|
6
7
|
import { createAggregateRoot } from '../createAggregateRoot.ts'
|
|
7
8
|
import { createUserAggregate, setupEventStore } from './setup.ts'
|
|
8
9
|
import { CommandError } from '../errors.ts'
|
|
10
|
+
import lock from '../lock.ts'
|
|
9
11
|
|
|
10
12
|
describe('transaction', () => {
|
|
11
13
|
const createAggregateRoots = () => {
|
|
@@ -182,4 +184,55 @@ describe('transaction', () => {
|
|
|
182
184
|
expect(state.created).toBeTrue()
|
|
183
185
|
})
|
|
184
186
|
})
|
|
187
|
+
|
|
188
|
+
it('applies settled defaults from options to dispatched streams', async () => {
|
|
189
|
+
const context = new AsyncLocalStorage<string>()
|
|
190
|
+
|
|
191
|
+
const slowAggregate = createAggregateRoot('slow')
|
|
192
|
+
.withEvents({
|
|
193
|
+
Written: z.string(),
|
|
194
|
+
})
|
|
195
|
+
.withCommands((event) => ({
|
|
196
|
+
async write(delay: number, name: string) {
|
|
197
|
+
await setTimeout(delay)
|
|
198
|
+
return event('Written', `${name}:${context.getStore() ?? 'none'}`)
|
|
199
|
+
},
|
|
200
|
+
}))
|
|
201
|
+
|
|
202
|
+
const { eventStore, pseudoEventStore } = setupEventStore(slowAggregate, {
|
|
203
|
+
lock: lock(40), // 40ms
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
// The transaction's write holds the lock on slow:a, but its 100ms command
|
|
207
|
+
// outlives the 40ms lock TTL, so the direct write slips in and advances
|
|
208
|
+
// the stream to v1. The transaction's append then loses the race — without
|
|
209
|
+
// the settled defaults declared below the ConcurrencyError would surface
|
|
210
|
+
// from the transaction; with them the auto-settle reloads and re-applies
|
|
211
|
+
// the command.
|
|
212
|
+
await Promise.all([
|
|
213
|
+
eventStore.transaction(
|
|
214
|
+
async () => {
|
|
215
|
+
context.run('tx', () => {
|
|
216
|
+
slowAggregate.loadStream('a').write(100, 'TX')
|
|
217
|
+
})
|
|
218
|
+
},
|
|
219
|
+
{ settled: { maxRetries: 3 } },
|
|
220
|
+
),
|
|
221
|
+
(async () => {
|
|
222
|
+
await setTimeout(30)
|
|
223
|
+
await slowAggregate.loadStream('a').write(5, 'direct').settled()
|
|
224
|
+
})(),
|
|
225
|
+
])
|
|
226
|
+
|
|
227
|
+
const persisted = pseudoEventStore.filter(
|
|
228
|
+
(event) => event.streamType === 'slow',
|
|
229
|
+
)
|
|
230
|
+
// 'TX:tx' also proves the retry re-ran the command inside the dispatch
|
|
231
|
+
// site's async context — the AsyncLocalStorage value survived the retry.
|
|
232
|
+
expect(persisted.map((event) => event.payload)).toEqual([
|
|
233
|
+
'direct:none',
|
|
234
|
+
'TX:tx',
|
|
235
|
+
])
|
|
236
|
+
expect(persisted.map((event) => event.streamVersion)).toEqual([1, 2])
|
|
237
|
+
})
|
|
185
238
|
})
|
package/src/transaction.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
2
|
|
|
3
|
+
import type { SettledOptions } from './createAggregateRoot.ts'
|
|
4
|
+
|
|
3
5
|
async function awaitAll(getPromises: () => Promise<any>[]) {
|
|
4
6
|
let promises = getPromises()
|
|
5
7
|
|
|
@@ -20,11 +22,23 @@ export type TransactionDelay = {
|
|
|
20
22
|
commit: () => Promise<void>
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Options for a transaction run.
|
|
27
|
+
*
|
|
28
|
+
* `settled` — default {@link SettledOptions} applied when the transaction
|
|
29
|
+
* auto-settles the streams whose commands were dispatched inside the handler
|
|
30
|
+
* (explicit `settled()` calls are not allowed there).
|
|
31
|
+
*/
|
|
32
|
+
export type TransactionOptions = {
|
|
33
|
+
settled?: SettledOptions
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
export default function createTransaction() {
|
|
24
37
|
const transactionStore = new AsyncLocalStorage<{
|
|
25
38
|
delayPromises: Promise<void>[]
|
|
26
39
|
commitPromises: Promise<void>[]
|
|
27
40
|
afterHandlers: Array<() => Promise<any>>
|
|
41
|
+
settledDefaults?: SettledOptions
|
|
28
42
|
}>()
|
|
29
43
|
|
|
30
44
|
return {
|
|
@@ -32,6 +46,19 @@ export default function createTransaction() {
|
|
|
32
46
|
return Boolean(transactionStore.getStore())
|
|
33
47
|
},
|
|
34
48
|
|
|
49
|
+
get settledDefaults() {
|
|
50
|
+
return transactionStore.getStore()?.settledDefaults
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Runs the handler outside the transaction scope. Used by the settle
|
|
55
|
+
* retry: a retried append already passed the transaction gate on its
|
|
56
|
+
* first attempt and must not re-enter the (committed) transaction.
|
|
57
|
+
*/
|
|
58
|
+
exit<T>(handler: () => T): T {
|
|
59
|
+
return transactionStore.exit(handler)
|
|
60
|
+
},
|
|
61
|
+
|
|
35
62
|
delay(): TransactionDelay {
|
|
36
63
|
const store = transactionStore.getStore()
|
|
37
64
|
if (!store) {
|
|
@@ -68,14 +95,19 @@ export default function createTransaction() {
|
|
|
68
95
|
transactionStore.getStore()?.afterHandlers.push(onAfter)
|
|
69
96
|
},
|
|
70
97
|
|
|
71
|
-
async run<T extends () => any>(handler: T) {
|
|
98
|
+
async run<T extends () => any>(handler: T, options?: TransactionOptions) {
|
|
72
99
|
const { resolve, reject, promise } = Promise.withResolvers<void>()
|
|
73
100
|
const delayPromises = [promise]
|
|
74
101
|
const afterHandlers: Array<() => Promise<any>> = []
|
|
75
102
|
let result
|
|
76
103
|
try {
|
|
77
104
|
result = await transactionStore.run(
|
|
78
|
-
{
|
|
105
|
+
{
|
|
106
|
+
delayPromises,
|
|
107
|
+
afterHandlers,
|
|
108
|
+
commitPromises: [],
|
|
109
|
+
settledDefaults: options?.settled,
|
|
110
|
+
},
|
|
79
111
|
handler,
|
|
80
112
|
)
|
|
81
113
|
resolve()
|