@requence/event-sourcing 0.0.1 → 1.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/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/chunk-24xjphpk.js +51 -0
- package/dist/chunk-24xjphpk.js.map +10 -0
- package/dist/chunk-3t1vzbab.js +88 -0
- package/dist/chunk-3t1vzbab.js.map +10 -0
- package/dist/chunk-6q8mr1sg.js +13 -0
- package/dist/chunk-6q8mr1sg.js.map +10 -0
- package/dist/chunk-9psg50cb.js +22 -0
- package/dist/chunk-9psg50cb.js.map +10 -0
- package/dist/chunk-dgzw1nj9.js +50 -0
- package/dist/chunk-dgzw1nj9.js.map +10 -0
- package/dist/chunk-gq80tgvf.js +70 -0
- package/dist/chunk-gq80tgvf.js.map +10 -0
- package/dist/chunk-jd4q8fcf.js +11 -0
- package/dist/chunk-jd4q8fcf.js.map +10 -0
- package/dist/chunk-m07vf8q9.js +210 -0
- package/dist/chunk-m07vf8q9.js.map +10 -0
- package/dist/chunk-ncpk70p4.js +313 -0
- package/dist/chunk-ncpk70p4.js.map +10 -0
- package/dist/chunk-pmfzjavb.js +49 -0
- package/dist/chunk-pmfzjavb.js.map +10 -0
- package/dist/chunk-qdczt68t.js +84 -0
- package/dist/chunk-qdczt68t.js.map +10 -0
- package/dist/chunk-tfy01fah.js +34 -0
- package/dist/chunk-tfy01fah.js.map +10 -0
- package/dist/chunk-tkvj6x8k.js +389 -0
- package/dist/chunk-tkvj6x8k.js.map +10 -0
- package/dist/chunk-ty9bhdvx.js +53 -0
- package/dist/chunk-ty9bhdvx.js.map +10 -0
- package/dist/chunk-wmz6a1jk.js +233 -0
- package/dist/chunk-wmz6a1jk.js.map +10 -0
- package/dist/chunk-x90g388y.js +22 -0
- package/dist/chunk-x90g388y.js.map +10 -0
- package/dist/chunk-z388cd25.js +91 -0
- package/dist/chunk-z388cd25.js.map +10 -0
- package/dist/chunk-zf3x573k.js +65 -0
- package/dist/chunk-zf3x573k.js.map +10 -0
- package/dist/createAggregateRoot.d.ts +191 -0
- package/dist/createAggregateRoot.d.ts.map +1 -0
- package/dist/createAggregateRoot.js +18 -0
- package/dist/createAggregateRoot.js.map +9 -0
- package/dist/createCheckpointApi.d.ts +38 -0
- package/dist/createCheckpointApi.d.ts.map +1 -0
- package/dist/createCheckpointApi.js +9 -0
- package/dist/createCheckpointApi.js.map +9 -0
- package/dist/createEventListener.d.ts +46 -0
- package/dist/createEventListener.d.ts.map +1 -0
- package/dist/createEventListener.js +12 -0
- package/dist/createEventListener.js.map +9 -0
- package/dist/createEventStore.d.ts +57 -0
- package/dist/createEventStore.d.ts.map +1 -0
- package/dist/createEventStore.js +20 -0
- package/dist/createEventStore.js.map +9 -0
- package/dist/createProcessManager.d.ts +70 -0
- package/dist/createProcessManager.d.ts.map +1 -0
- package/dist/createProcessManager.js +16 -0
- package/dist/createProcessManager.js.map +9 -0
- package/dist/createProjection.d.ts +120 -0
- package/dist/createProjection.d.ts.map +1 -0
- package/dist/createProjection.js +16 -0
- package/dist/createProjection.js.map +9 -0
- package/dist/drizzle/index.d.ts +449 -0
- package/dist/drizzle/index.d.ts.map +1 -0
- package/dist/drizzle/index.js +325 -0
- package/dist/drizzle/index.js.map +10 -0
- package/dist/drizzle/postgres.d.ts +686 -0
- package/dist/drizzle/postgres.d.ts.map +1 -0
- package/dist/drizzle/postgres.js +18 -0
- package/dist/drizzle/postgres.js.map +9 -0
- package/dist/errors.d.ts +53 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +26 -0
- package/dist/errors.js.map +9 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +9 -0
- package/dist/lock.d.ts +6 -0
- package/dist/lock.d.ts.map +1 -0
- package/dist/lock.js +8 -0
- package/dist/lock.js.map +9 -0
- package/dist/memory/index.d.ts +15 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +178 -0
- package/dist/memory/index.js.map +10 -0
- package/dist/redis/index.d.ts +2 -0
- package/dist/redis/index.d.ts.map +1 -0
- package/dist/redis/index.js +8 -0
- package/dist/redis/index.js.map +9 -0
- package/dist/redis/redisLock.d.ts +4 -0
- package/dist/redis/redisLock.d.ts.map +1 -0
- package/dist/redis/redisLock.js +8 -0
- package/dist/redis/redisLock.js.map +9 -0
- package/dist/refresh.d.ts +4 -0
- package/dist/refresh.d.ts.map +1 -0
- package/dist/refresh.js +13 -0
- package/dist/refresh.js.map +9 -0
- package/dist/replay.d.ts +4 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +13 -0
- package/dist/replay.js.map +9 -0
- package/dist/snapshotGenerator.d.ts +79 -0
- package/dist/snapshotGenerator.d.ts.map +1 -0
- package/dist/snapshotGenerator.js +9 -0
- package/dist/snapshotGenerator.js.map +9 -0
- package/dist/superjson.d.ts +5 -0
- package/dist/superjson.d.ts.map +1 -0
- package/dist/superjson.js +12 -0
- package/dist/superjson.js.map +9 -0
- package/dist/transaction.d.ts +13 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +8 -0
- package/dist/transaction.js.map +9 -0
- package/dist/utilityTypes.d.js +2 -0
- package/dist/utilityTypes.d.js.map +9 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +10 -0
- package/dist/utils.js.map +9 -0
- package/dist/wrappedEventBuilder.d.ts +37 -0
- package/dist/wrappedEventBuilder.d.ts.map +1 -0
- package/dist/wrappedEventBuilder.js +12 -0
- package/dist/wrappedEventBuilder.js.map +9 -0
- package/package.json +87 -1
- package/src/createAggregateRoot.ts +902 -0
- package/src/createCheckpointApi.ts +106 -0
- package/src/createEventListener.ts +118 -0
- package/src/createEventStore.ts +446 -0
- package/src/createProcessManager.ts +363 -0
- package/src/createProjection.ts +577 -0
- package/src/drizzle/index.ts +449 -0
- package/src/drizzle/postgres.ts +120 -0
- package/src/errors.ts +85 -0
- package/src/index.ts +45 -0
- package/src/lock.ts +58 -0
- package/src/memory/index.ts +224 -0
- package/src/redis/index.ts +1 -0
- package/src/redis/redisLock.ts +61 -0
- package/src/refresh.ts +19 -0
- package/src/replay.ts +19 -0
- package/src/snapshotGenerator.ts +190 -0
- package/src/superjson.ts +11 -0
- package/src/tests/aggregateRoot.spec.ts +532 -0
- package/src/tests/eventListener.spec.ts +57 -0
- package/src/tests/eventStore.spec.ts +86 -0
- package/src/tests/processManager.spec.ts +185 -0
- package/src/tests/projection.spec.ts +511 -0
- package/src/tests/projectionProcessManager.spec.ts +203 -0
- package/src/tests/setup.ts +230 -0
- package/src/tests/transaction.spec.ts +185 -0
- package/src/transaction.ts +93 -0
- package/src/utilityTypes.d.ts +110 -0
- package/src/utils.ts +43 -0
- package/src/wrappedEventBuilder.ts +181 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 requence
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @requence/event-sourcing
|
|
2
|
+
|
|
3
|
+
A high-performance, type-safe event sourcing library for TypeScript.
|
|
4
|
+
|
|
5
|
+
Build resilient, auditable systems by storing every state change as an immutable event — then derive your current state by replaying them.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Aggregate Roots** — define your domain model with events, business rules, and commands using a fluent builder API.
|
|
10
|
+
- **Automatic Concurrency Control** — aggregate root streams are automatically locked to prevent simultaneous edits and event stream version collisions.
|
|
11
|
+
- **Distributed Locking** — use `redisLock` for multi-instance deployments to coordinate locks across processes via Redis.
|
|
12
|
+
- **Projections** — build query-optimized read models from events, with full replay support.
|
|
13
|
+
- **Process Managers** — coordinate workflows across multiple aggregates.
|
|
14
|
+
- **Event Listeners** — react to events with lightweight, stateless side effects.
|
|
15
|
+
- **Storage Adapters** — swap between an in-memory store (great for testing), PostgreSQL via Drizzle, or Redis.
|
|
16
|
+
- **Type-Safe Events** — leverage Zod schemas and TypeScript for compile-time and runtime guarantees on every event shape.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @requence/event-sourcing zod
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { createAggregateRoot } from '@requence/event-sourcing'
|
|
28
|
+
import { createEventStore } from '@requence/event-sourcing/memory'
|
|
29
|
+
|
|
30
|
+
// 1. Define an aggregate root
|
|
31
|
+
const counter = createAggregateRoot('counter')
|
|
32
|
+
.withInitialState({ count: 0 })
|
|
33
|
+
.withEvents(({ z }) => ({
|
|
34
|
+
Incremented: z.object({ amount: z.number() }),
|
|
35
|
+
}))
|
|
36
|
+
.withEventHandlers((state) => ({
|
|
37
|
+
onIncremented({ payload }) {
|
|
38
|
+
state.count += payload.amount
|
|
39
|
+
},
|
|
40
|
+
}))
|
|
41
|
+
.withCommands((state, event) => ({
|
|
42
|
+
increment(amount: number) {
|
|
43
|
+
return event('Incremented', { amount })
|
|
44
|
+
},
|
|
45
|
+
}))
|
|
46
|
+
|
|
47
|
+
// 2. Create an event store with the aggregate root
|
|
48
|
+
const eventStore = createEventStore({
|
|
49
|
+
aggregateRoots: [counter],
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// 3. Build a read model with a projection
|
|
53
|
+
const totals = new Map<string, number>()
|
|
54
|
+
|
|
55
|
+
eventStore.createProjection('counter-totals').withEventHandlers({
|
|
56
|
+
onIncremented({ streamId, payload }) {
|
|
57
|
+
totals.set(streamId, (totals.get(streamId) ?? 0) + payload.amount)
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// 4. Execute commands on a new stream
|
|
62
|
+
const stream = await counter.newStream().increment(1).increment(5).settled()
|
|
63
|
+
console.log(totals.get(stream.streamId)) // 6
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Storage Adapters
|
|
67
|
+
|
|
68
|
+
| Adapter | Import Path | Use Case |
|
|
69
|
+
|---------|------------|----------|
|
|
70
|
+
| In-Memory | `@requence/event-sourcing/memory` | Testing & prototyping |
|
|
71
|
+
| PostgreSQL (Drizzle) | `@requence/event-sourcing/drizzle/postgres` | Production |
|
|
72
|
+
|
|
73
|
+
## Documentation
|
|
74
|
+
|
|
75
|
+
Full documentation — including concept guides, a step-by-step tutorial, and API reference — is available at:
|
|
76
|
+
|
|
77
|
+
**[https://event-sourcing.docs.requence.cloud](https://event-sourcing.docs.requence.cloud)**
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/createEventListener.ts
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
var eventListenerInfoStore = new AsyncLocalStorage;
|
|
4
|
+
function withEventListenerInfo(info, handler) {
|
|
5
|
+
return eventListenerInfoStore.run(info, handler);
|
|
6
|
+
}
|
|
7
|
+
function getEventListenerInfo() {
|
|
8
|
+
return eventListenerInfoStore.getStore();
|
|
9
|
+
}
|
|
10
|
+
function isInsideEventListener() {
|
|
11
|
+
return Boolean(getEventListenerInfo());
|
|
12
|
+
}
|
|
13
|
+
function createEventListener(name = null) {
|
|
14
|
+
let eventHandlers = {};
|
|
15
|
+
let afterEffectHandlers = {};
|
|
16
|
+
let globalEventHandler;
|
|
17
|
+
let globalAfterEffect;
|
|
18
|
+
const api = {
|
|
19
|
+
async apply(event) {
|
|
20
|
+
withEventListenerInfo({ name, event }, async () => {
|
|
21
|
+
await eventHandlers[`on${event.type}`]?.(event);
|
|
22
|
+
await globalEventHandler?.(event);
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
async applyAfter(event) {
|
|
26
|
+
await afterEffectHandlers[`after${event.type}`]?.(event);
|
|
27
|
+
await globalAfterEffect?.(event);
|
|
28
|
+
},
|
|
29
|
+
withEventHandlers(handlers) {
|
|
30
|
+
eventHandlers = handlers;
|
|
31
|
+
return api;
|
|
32
|
+
},
|
|
33
|
+
withGlobalEventHandler(handler) {
|
|
34
|
+
globalEventHandler = handler;
|
|
35
|
+
return api;
|
|
36
|
+
},
|
|
37
|
+
withAfterEffects(handlers) {
|
|
38
|
+
afterEffectHandlers = handlers;
|
|
39
|
+
return api;
|
|
40
|
+
},
|
|
41
|
+
withGlobalAfterEffect(handler) {
|
|
42
|
+
globalAfterEffect = handler;
|
|
43
|
+
return api;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return api;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { getEventListenerInfo, isInsideEventListener, createEventListener };
|
|
50
|
+
|
|
51
|
+
//# debugId=BA79940C1474466C64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/createEventListener.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { AsyncLocalStorage } from 'node:async_hooks'\n\nimport type {\n AfterEffectHandlers,\n AllEvents,\n BaseOutputEvent,\n EventHandlers,\n EventTemplate,\n Keys,\n MaybePromise,\n Merge,\n} from './utilityTypes.js'\n\nexport type InternalEventListener = {\n apply: (event: BaseOutputEvent) => Promise<void>\n applyAfter: (event: BaseOutputEvent) => Promise<void>\n}\n\ntype EventListenerInfo = {\n name: string | null\n event: BaseOutputEvent\n}\nconst eventListenerInfoStore = new AsyncLocalStorage<EventListenerInfo>()\n\nfunction withEventListenerInfo(\n info: EventListenerInfo,\n handler: () => Promise<void>,\n) {\n return eventListenerInfoStore.run(info, handler)\n}\n\nexport function getEventListenerInfo() {\n return eventListenerInfoStore.getStore()\n}\n\nexport function isInsideEventListener() {\n return Boolean(getEventListenerInfo())\n}\n\nexport type EventListenerApi<\n Events extends EventTemplate = never,\n Flags extends {\n withEventHandlers: boolean\n withGlobalEventHandler: boolean\n withAfterEffects: boolean\n withGlobalAfterEffect: boolean\n } = {\n withEventHandlers: false\n withGlobalEventHandler: false\n withAfterEffects: false\n withGlobalAfterEffect: false\n },\n> = {\n withEventHandlers: (\n handlers: EventHandlers<Events>,\n ) => Omit<\n EventListenerApi<Events, Merge<Flags, { withEventHandlers: true }>>,\n Keys<Merge<Flags, { withEventHandlers: true }>>\n >\n withGlobalEventHandler: (\n handler: (event: AllEvents<Events>) => MaybePromise<void>,\n ) => Omit<\n EventListenerApi<Events, Merge<Flags, { withGlobalEventHandler: true }>>,\n Keys<Merge<Flags, { withGlobalEventHandler: true }>>\n >\n withAfterEffects: (\n handlers: AfterEffectHandlers<Events>,\n ) => Omit<\n EventListenerApi<Events, Merge<Flags, { withAfterEffects: true }>>,\n Keys<Merge<Flags, { withAfterEffects: true }>>\n >\n withGlobalAfterEffect: (\n handler: (event: AllEvents<Events>) => MaybePromise<void>,\n ) => Omit<\n EventListenerApi<Events, Merge<Flags, { withGlobalAfterEffect: true }>>,\n Keys<Merge<Flags, { withGlobalAfterEffect: true }>>\n >\n}\n\nexport function createEventListener(\n name: string | null = null,\n): EventListenerApi {\n let eventHandlers: EventHandlers<any> = {}\n let afterEffectHandlers: AfterEffectHandlers<any> = {}\n let globalEventHandler: (event: BaseOutputEvent) => MaybePromise<void>\n let globalAfterEffect: (event: BaseOutputEvent) => MaybePromise<void>\n const api = {\n async apply(event) {\n withEventListenerInfo({ name, event }, async () => {\n await eventHandlers[`on${event.type}`]?.(event)\n await globalEventHandler?.(event)\n })\n },\n\n async applyAfter(event) {\n await afterEffectHandlers[`after${event.type}`]?.(event)\n await globalAfterEffect?.(event)\n },\n withEventHandlers(handlers) {\n eventHandlers = handlers\n return api\n },\n withGlobalEventHandler(handler) {\n globalEventHandler = handler as any\n return api\n },\n withAfterEffects(handlers) {\n afterEffectHandlers = handlers\n return api\n },\n withGlobalAfterEffect(handler) {\n globalAfterEffect = handler as any\n return api\n },\n } as EventListenerApi & InternalEventListener\n\n return api\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAAA;AAsBA,IAAM,yBAAyB,IAAI;AAEnC,SAAS,qBAAqB,CAC5B,MACA,SACA;AAAA,EACA,OAAO,uBAAuB,IAAI,MAAM,OAAO;AAAA;AAG1C,SAAS,oBAAoB,GAAG;AAAA,EACrC,OAAO,uBAAuB,SAAS;AAAA;AAGlC,SAAS,qBAAqB,GAAG;AAAA,EACtC,OAAO,QAAQ,qBAAqB,CAAC;AAAA;AA2ChC,SAAS,mBAAmB,CACjC,OAAsB,MACJ;AAAA,EAClB,IAAI,gBAAoC,CAAC;AAAA,EACzC,IAAI,sBAAgD,CAAC;AAAA,EACrD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,MAAM,MAAM;AAAA,SACJ,MAAK,CAAC,OAAO;AAAA,MACjB,sBAAsB,EAAE,MAAM,MAAM,GAAG,YAAY;AAAA,QACjD,MAAM,cAAc,KAAK,MAAM,UAAU,KAAK;AAAA,QAC9C,MAAM,qBAAqB,KAAK;AAAA,OACjC;AAAA;AAAA,SAGG,WAAU,CAAC,OAAO;AAAA,MACtB,MAAM,oBAAoB,QAAQ,MAAM,UAAU,KAAK;AAAA,MACvD,MAAM,oBAAoB,KAAK;AAAA;AAAA,IAEjC,iBAAiB,CAAC,UAAU;AAAA,MAC1B,gBAAgB;AAAA,MAChB,OAAO;AAAA;AAAA,IAET,sBAAsB,CAAC,SAAS;AAAA,MAC9B,qBAAqB;AAAA,MACrB,OAAO;AAAA;AAAA,IAET,gBAAgB,CAAC,UAAU;AAAA,MACzB,sBAAsB;AAAA,MACtB,OAAO;AAAA;AAAA,IAET,qBAAqB,CAAC,SAAS;AAAA,MAC7B,oBAAoB;AAAA,MACpB,OAAO;AAAA;AAAA,EAEX;AAAA,EAEA,OAAO;AAAA;",
|
|
8
|
+
"debugId": "BA79940C1474466C64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// src/drizzle/postgres.ts
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
3
|
+
import {
|
|
4
|
+
bigint,
|
|
5
|
+
index,
|
|
6
|
+
integer,
|
|
7
|
+
jsonb,
|
|
8
|
+
pgPolicy,
|
|
9
|
+
pgSchema,
|
|
10
|
+
text,
|
|
11
|
+
timestamp,
|
|
12
|
+
unique,
|
|
13
|
+
uuid
|
|
14
|
+
} from "drizzle-orm/pg-core";
|
|
15
|
+
var eventSourcing = pgSchema("event_sourcing");
|
|
16
|
+
var events = eventSourcing.table("events", {
|
|
17
|
+
position: bigint({ mode: "number" }).generatedByDefaultAsIdentity().primaryKey(),
|
|
18
|
+
id: uuid().unique().notNull().defaultRandom(),
|
|
19
|
+
streamId: text().notNull(),
|
|
20
|
+
streamType: text().notNull(),
|
|
21
|
+
streamVersion: bigint({ mode: "number" }).notNull(),
|
|
22
|
+
type: text().notNull(),
|
|
23
|
+
createdAt: timestamp().defaultNow().notNull(),
|
|
24
|
+
payload: text().notNull(),
|
|
25
|
+
metadata: jsonb().$type().notNull(),
|
|
26
|
+
causationId: uuid(),
|
|
27
|
+
correlationId: uuid(),
|
|
28
|
+
actorId: text(),
|
|
29
|
+
schemaVersion: integer().notNull()
|
|
30
|
+
}, (table) => [
|
|
31
|
+
unique().on(table.streamId, table.streamVersion, table.streamType),
|
|
32
|
+
index().on(table.streamId, table.streamVersion.desc()),
|
|
33
|
+
index("metadata").using("gin", sql`${table.metadata} jsonb_path_ops`),
|
|
34
|
+
pgPolicy("insert only", {
|
|
35
|
+
for: "insert",
|
|
36
|
+
to: "public",
|
|
37
|
+
withCheck: sql`true`
|
|
38
|
+
})
|
|
39
|
+
]);
|
|
40
|
+
var aggregateRootSnapshots = eventSourcing.table("aggregate_root_snapshots", {
|
|
41
|
+
id: uuid().primaryKey().defaultRandom(),
|
|
42
|
+
streamId: text().notNull(),
|
|
43
|
+
streamType: text().notNull(),
|
|
44
|
+
streamVersion: bigint({ mode: "number" }).notNull(),
|
|
45
|
+
state: text().notNull(),
|
|
46
|
+
metadata: text().notNull(),
|
|
47
|
+
createdAt: timestamp().defaultNow().notNull(),
|
|
48
|
+
lastEventPosition: bigint({ mode: "number" }).notNull(),
|
|
49
|
+
schemaVersion: integer().notNull()
|
|
50
|
+
}, (table) => [
|
|
51
|
+
unique().on(table.streamType, table.streamId, table.streamVersion),
|
|
52
|
+
index().on(table.streamType, table.streamId, table.streamVersion.desc())
|
|
53
|
+
]);
|
|
54
|
+
var projectionSnapshots = eventSourcing.table("projection_snapshots", {
|
|
55
|
+
id: uuid().primaryKey().defaultRandom(),
|
|
56
|
+
projectionId: text().notNull(),
|
|
57
|
+
projectionType: text().notNull(),
|
|
58
|
+
state: text().notNull(),
|
|
59
|
+
metadata: text().notNull(),
|
|
60
|
+
createdAt: timestamp().defaultNow().notNull(),
|
|
61
|
+
lastEventPosition: bigint({ mode: "number" }).notNull(),
|
|
62
|
+
schemaVersion: integer().notNull()
|
|
63
|
+
}, (table) => [
|
|
64
|
+
unique().on(table.projectionId, table.projectionType, table.lastEventPosition),
|
|
65
|
+
index().on(table.projectionId, table.projectionType, table.lastEventPosition.desc())
|
|
66
|
+
]);
|
|
67
|
+
var checkpoints = eventSourcing.table("checkpoints", {
|
|
68
|
+
id: uuid().defaultRandom().primaryKey(),
|
|
69
|
+
type: text({ enum: ["projection", "processManager"] }).notNull(),
|
|
70
|
+
name: text().notNull(),
|
|
71
|
+
lastEventPosition: bigint({ mode: "number" }).notNull(),
|
|
72
|
+
metadata: text().notNull()
|
|
73
|
+
}, (table) => [
|
|
74
|
+
unique().on(table.type, table.name),
|
|
75
|
+
index().on(table.type, table.name)
|
|
76
|
+
]);
|
|
77
|
+
var projectionAppliedEvents = eventSourcing.table("projection_applied_events", {
|
|
78
|
+
projectionId: uuid().notNull(),
|
|
79
|
+
projectionType: text().notNull(),
|
|
80
|
+
appliedEvents: integer().notNull()
|
|
81
|
+
}, (table) => [
|
|
82
|
+
unique().on(table.projectionId, table.projectionType),
|
|
83
|
+
index().on(table.projectionId, table.projectionType)
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
export { eventSourcing, events, aggregateRootSnapshots, projectionSnapshots, checkpoints, projectionAppliedEvents };
|
|
87
|
+
|
|
88
|
+
//# debugId=336C30BF93DC04EF64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/drizzle/postgres.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { sql } from 'drizzle-orm'\nimport {\n bigint,\n index,\n integer,\n jsonb,\n pgPolicy,\n pgSchema,\n text,\n timestamp,\n unique,\n uuid,\n} from 'drizzle-orm/pg-core'\nimport type { SuperJSONResult } from 'superjson'\n\nexport const eventSourcing = pgSchema('event_sourcing')\n\nexport const events = eventSourcing.table(\n 'events',\n {\n position: bigint({ mode: 'number' })\n .generatedByDefaultAsIdentity()\n .primaryKey(),\n id: uuid().unique().notNull().defaultRandom(),\n streamId: text().notNull(),\n streamType: text().notNull(),\n streamVersion: bigint({ mode: 'number' }).notNull(),\n type: text().notNull(),\n createdAt: timestamp().defaultNow().notNull(),\n payload: text().notNull(),\n metadata: jsonb().$type<SuperJSONResult>().notNull(),\n causationId: uuid(),\n correlationId: uuid(),\n actorId: text(),\n schemaVersion: integer().notNull(),\n },\n (table) => [\n unique().on(table.streamId, table.streamVersion, table.streamType),\n index().on(table.streamId, table.streamVersion.desc()),\n index('metadata').using('gin', sql`${table.metadata} jsonb_path_ops`),\n pgPolicy('insert only', {\n for: 'insert',\n to: 'public',\n withCheck: sql`true`,\n }),\n ],\n)\n\nexport const aggregateRootSnapshots = eventSourcing.table(\n 'aggregate_root_snapshots',\n {\n id: uuid().primaryKey().defaultRandom(),\n streamId: text().notNull(),\n streamType: text().notNull(),\n streamVersion: bigint({ mode: 'number' }).notNull(),\n state: text().notNull(),\n metadata: text().notNull(),\n createdAt: timestamp().defaultNow().notNull(),\n lastEventPosition: bigint({ mode: 'number' }).notNull(),\n schemaVersion: integer().notNull(),\n },\n (table) => [\n unique().on(table.streamType, table.streamId, table.streamVersion),\n index().on(table.streamType, table.streamId, table.streamVersion.desc()),\n ],\n)\n\nexport const projectionSnapshots = eventSourcing.table(\n 'projection_snapshots',\n {\n id: uuid().primaryKey().defaultRandom(),\n projectionId: text().notNull(),\n projectionType: text().notNull(),\n state: text().notNull(),\n metadata: text().notNull(),\n createdAt: timestamp().defaultNow().notNull(),\n lastEventPosition: bigint({ mode: 'number' }).notNull(),\n schemaVersion: integer().notNull(),\n },\n (table) => [\n unique().on(\n table.projectionId,\n table.projectionType,\n table.lastEventPosition,\n ),\n index().on(\n table.projectionId,\n table.projectionType,\n table.lastEventPosition.desc(),\n ),\n ],\n)\n\nexport const checkpoints = eventSourcing.table(\n 'checkpoints',\n {\n id: uuid().defaultRandom().primaryKey(),\n type: text({ enum: ['projection', 'processManager'] }).notNull(),\n name: text().notNull(),\n lastEventPosition: bigint({ mode: 'number' }).notNull(),\n metadata: text().notNull(),\n },\n (table) => [\n unique().on(table.type, table.name),\n index().on(table.type, table.name),\n ],\n)\n\nexport const projectionAppliedEvents = eventSourcing.table(\n 'projection_applied_events',\n {\n projectionId: uuid().notNull(),\n projectionType: text().notNull(),\n appliedEvents: integer().notNull(),\n },\n (table) => [\n unique().on(table.projectionId, table.projectionType),\n index().on(table.projectionId, table.projectionType),\n ],\n)\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "336C30BF93DC04EF64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/superjson.ts
|
|
2
|
+
import SuperJSON from "superjson";
|
|
3
|
+
var superjson = new SuperJSON;
|
|
4
|
+
function extendTypes(handler) {
|
|
5
|
+
handler(superjson);
|
|
6
|
+
}
|
|
7
|
+
function clone(obj) {
|
|
8
|
+
return superjson.deserialize(superjson.serialize(obj));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { superjson, extendTypes, clone };
|
|
12
|
+
|
|
13
|
+
//# debugId=97ED416FCC5782E564756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/superjson.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import SuperJSON from 'superjson'\n\nexport const superjson = new SuperJSON()\n\nexport function extendTypes(handler: (superjson: SuperJSON) => void) {\n handler(superjson)\n}\n\nexport function clone<T>(obj: T): T {\n return superjson.deserialize(superjson.serialize(obj))\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAAA;AAEO,IAAM,YAAY,IAAI;AAEtB,SAAS,WAAW,CAAC,SAAyC;AAAA,EACnE,QAAQ,SAAS;AAAA;AAGZ,SAAS,KAAQ,CAAC,KAAW;AAAA,EAClC,OAAO,UAAU,YAAY,UAAU,UAAU,GAAG,CAAC;AAAA;",
|
|
8
|
+
"debugId": "97ED416FCC5782E564756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RefreshingSkipError
|
|
3
|
+
} from "./chunk-qdczt68t.js";
|
|
4
|
+
|
|
5
|
+
// src/refresh.ts
|
|
6
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
var refreshStore = new AsyncLocalStorage;
|
|
8
|
+
function isRefreshing() {
|
|
9
|
+
return refreshStore.getStore() ?? false;
|
|
10
|
+
}
|
|
11
|
+
function withRefreshing(handler) {
|
|
12
|
+
return refreshStore.run(true, handler);
|
|
13
|
+
}
|
|
14
|
+
function skipRefreshing() {
|
|
15
|
+
if (isRefreshing()) {
|
|
16
|
+
throw new RefreshingSkipError;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { isRefreshing, withRefreshing, skipRefreshing };
|
|
21
|
+
|
|
22
|
+
//# debugId=662B9CB5FCF319E264756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/refresh.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { AsyncLocalStorage } from 'node:async_hooks'\n\nimport { RefreshingSkipError } from './errors.ts'\n\nconst refreshStore = new AsyncLocalStorage<boolean>()\n\nexport function isRefreshing() {\n return refreshStore.getStore() ?? false\n}\n\nexport function withRefreshing<T extends () => any>(handler: T) {\n return refreshStore.run(true, handler)\n}\n\nexport function skipRefreshing() {\n if (isRefreshing()) {\n throw new RefreshingSkipError()\n }\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;;AAAA;AAIA,IAAM,eAAe,IAAI;AAElB,SAAS,YAAY,GAAG;AAAA,EAC7B,OAAO,aAAa,SAAS,KAAK;AAAA;AAG7B,SAAS,cAAmC,CAAC,SAAY;AAAA,EAC9D,OAAO,aAAa,IAAI,MAAM,OAAO;AAAA;AAGhC,SAAS,cAAc,GAAG;AAAA,EAC/B,IAAI,aAAa,GAAG;AAAA,IAClB,MAAM,IAAI;AAAA,EACZ;AAAA;",
|
|
8
|
+
"debugId": "662B9CB5FCF319E264756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/redis/redisLock.ts
|
|
2
|
+
var extendScript = `
|
|
3
|
+
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
4
|
+
return redis.call("pexpire", KEYS[1], ARGV[2])
|
|
5
|
+
else
|
|
6
|
+
return 0
|
|
7
|
+
end
|
|
8
|
+
`;
|
|
9
|
+
var deleteScript = `
|
|
10
|
+
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
11
|
+
return redis.call("del", KEYS[1])
|
|
12
|
+
else
|
|
13
|
+
return 0
|
|
14
|
+
end
|
|
15
|
+
`;
|
|
16
|
+
function redisLock(client, defaultTtl = 5000) {
|
|
17
|
+
return async (rawKey) => {
|
|
18
|
+
const key = Array.isArray(rawKey) ? rawKey.join(":") : rawKey;
|
|
19
|
+
const token = crypto.randomUUID();
|
|
20
|
+
while (true) {
|
|
21
|
+
const acquired = await client.set(key, token, "PX", defaultTtl, "NX");
|
|
22
|
+
if (acquired !== "OK") {
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
let isReleased = false;
|
|
27
|
+
return {
|
|
28
|
+
async extend(ttl) {
|
|
29
|
+
const extended = await client.eval(extendScript, 1, key, token, ttl ?? defaultTtl / 2);
|
|
30
|
+
if (extended === 0) {
|
|
31
|
+
isReleased = true;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
},
|
|
36
|
+
async release() {
|
|
37
|
+
if (isReleased) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
isReleased = true;
|
|
41
|
+
await client.eval(deleteScript, 1, key, token);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { redisLock };
|
|
49
|
+
|
|
50
|
+
//# debugId=09C372830E540B2B64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/redis/redisLock.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { Redis } from 'ioredis'\n\nimport type { LockCreator } from '../lock.ts'\n\nconst extendScript = `\n if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"pexpire\", KEYS[1], ARGV[2])\n else\n return 0\n end\n`\n\nconst deleteScript = `\n if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n return redis.call(\"del\", KEYS[1])\n else\n return 0\n end\n`\n\nexport function redisLock(client: Redis, defaultTtl = 5000): LockCreator {\n return async (rawKey) => {\n const key = Array.isArray(rawKey) ? rawKey.join(':') : rawKey\n const token = crypto.randomUUID()\n\n while (true) {\n const acquired = await client.set(key, token, 'PX', defaultTtl, 'NX')\n\n if (acquired !== 'OK') {\n await new Promise((resolve) => setTimeout(resolve, 100))\n continue\n }\n\n let isReleased = false\n return {\n async extend(ttl) {\n const extended = await client.eval(\n extendScript,\n 1,\n key,\n token,\n ttl ?? defaultTtl / 2,\n )\n if (extended === 0) {\n isReleased = true\n return false\n }\n return true\n },\n async release() {\n if (isReleased) {\n return\n }\n\n isReleased = true\n await client.eval(deleteScript, 1, key, token)\n },\n }\n }\n }\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAIA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQrB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQd,SAAS,SAAS,CAAC,QAAe,aAAa,MAAmB;AAAA,EACvE,OAAO,OAAO,WAAW;AAAA,IACvB,MAAM,MAAM,MAAM,QAAQ,MAAM,IAAI,OAAO,KAAK,GAAG,IAAI;AAAA,IACvD,MAAM,QAAQ,OAAO,WAAW;AAAA,IAEhC,OAAO,MAAM;AAAA,MACX,MAAM,WAAW,MAAM,OAAO,IAAI,KAAK,OAAO,MAAM,YAAY,IAAI;AAAA,MAEpE,IAAI,aAAa,MAAM;AAAA,QACrB,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,QACvD;AAAA,MACF;AAAA,MAEA,IAAI,aAAa;AAAA,MACjB,OAAO;AAAA,aACC,OAAM,CAAC,KAAK;AAAA,UAChB,MAAM,WAAW,MAAM,OAAO,KAC5B,cACA,GACA,KACA,OACA,OAAO,aAAa,CACtB;AAAA,UACA,IAAI,aAAa,GAAG;AAAA,YAClB,aAAa;AAAA,YACb,OAAO;AAAA,UACT;AAAA,UACA,OAAO;AAAA;AAAA,aAEH,QAAO,GAAG;AAAA,UACd,IAAI,YAAY;AAAA,YACd;AAAA,UACF;AAAA,UAEA,aAAa;AAAA,UACb,MAAM,OAAO,KAAK,cAAc,GAAG,KAAK,KAAK;AAAA;AAAA,MAEjD;AAAA,IACF;AAAA;AAAA;",
|
|
8
|
+
"debugId": "09C372830E540B2B64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// src/transaction.ts
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
async function awaitAll(getPromises) {
|
|
4
|
+
let promises = getPromises();
|
|
5
|
+
while (true) {
|
|
6
|
+
await Promise.all(promises);
|
|
7
|
+
const nextPromises = getPromises();
|
|
8
|
+
if (nextPromises.length > promises.length) {
|
|
9
|
+
promises = nextPromises;
|
|
10
|
+
} else {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function createTransaction() {
|
|
16
|
+
const transactionStore = new AsyncLocalStorage;
|
|
17
|
+
return {
|
|
18
|
+
get active() {
|
|
19
|
+
return Boolean(transactionStore.getStore());
|
|
20
|
+
},
|
|
21
|
+
delay() {
|
|
22
|
+
const store = transactionStore.getStore();
|
|
23
|
+
if (!store) {
|
|
24
|
+
return {
|
|
25
|
+
resolve: () => {},
|
|
26
|
+
reject: () => {},
|
|
27
|
+
commit: () => Promise.resolve()
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const idx = store.commitPromises.length;
|
|
31
|
+
const { resolve, reject, promise } = Promise.withResolvers();
|
|
32
|
+
store.delayPromises.push(promise);
|
|
33
|
+
const { promise: commitPromise, resolve: resolveCommitPromise } = Promise.withResolvers();
|
|
34
|
+
store.commitPromises.push(commitPromise);
|
|
35
|
+
return {
|
|
36
|
+
resolve,
|
|
37
|
+
reject,
|
|
38
|
+
async commit() {
|
|
39
|
+
if (idx > 0) {
|
|
40
|
+
await store.commitPromises.at(idx - 1);
|
|
41
|
+
}
|
|
42
|
+
resolveCommitPromise();
|
|
43
|
+
await awaitAll(() => store.delayPromises);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
after(onAfter) {
|
|
48
|
+
transactionStore.getStore()?.afterHandlers.push(onAfter);
|
|
49
|
+
},
|
|
50
|
+
async run(handler) {
|
|
51
|
+
const { resolve, reject, promise } = Promise.withResolvers();
|
|
52
|
+
const delayPromises = [promise];
|
|
53
|
+
const afterHandlers = [];
|
|
54
|
+
let result;
|
|
55
|
+
try {
|
|
56
|
+
result = await transactionStore.run({ delayPromises, afterHandlers, commitPromises: [] }, handler);
|
|
57
|
+
resolve();
|
|
58
|
+
} catch (error) {
|
|
59
|
+
reject(error);
|
|
60
|
+
}
|
|
61
|
+
await awaitAll(() => delayPromises);
|
|
62
|
+
await Promise.all(afterHandlers.map((handler2) => handler2()));
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { createTransaction };
|
|
69
|
+
|
|
70
|
+
//# debugId=75143A00A85F441C64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/transaction.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { AsyncLocalStorage } from 'node:async_hooks'\n\nasync function awaitAll(getPromises: () => Promise<any>[]) {\n let promises = getPromises()\n\n while (true) {\n await Promise.all(promises)\n const nextPromises = getPromises()\n if (nextPromises.length > promises.length) {\n promises = nextPromises\n } else {\n break\n }\n }\n}\n\nexport type TransactionDelay = {\n resolve: () => void\n reject: (error: Error) => void\n commit: () => Promise<void>\n}\n\nexport default function createTransaction() {\n const transactionStore = new AsyncLocalStorage<{\n delayPromises: Promise<void>[]\n commitPromises: Promise<void>[]\n afterHandlers: Array<() => Promise<any>>\n }>()\n\n return {\n get active() {\n return Boolean(transactionStore.getStore())\n },\n\n delay(): TransactionDelay {\n const store = transactionStore.getStore()\n if (!store) {\n return {\n resolve: () => {},\n reject: () => {},\n commit: () => Promise.resolve(),\n }\n }\n\n const idx = store.commitPromises.length\n const { resolve, reject, promise } = Promise.withResolvers<void>()\n store.delayPromises.push(promise)\n\n const { promise: commitPromise, resolve: resolveCommitPromise } =\n Promise.withResolvers<void>()\n store.commitPromises.push(commitPromise)\n\n return {\n resolve,\n reject,\n async commit() {\n if (idx > 0) {\n await store.commitPromises.at(idx - 1)\n }\n\n resolveCommitPromise()\n await awaitAll(() => store.delayPromises)\n },\n }\n },\n\n after(onAfter: () => Promise<any>) {\n transactionStore.getStore()?.afterHandlers.push(onAfter)\n },\n\n async run<T extends () => any>(handler: T) {\n const { resolve, reject, promise } = Promise.withResolvers<void>()\n const delayPromises = [promise]\n const afterHandlers: Array<() => Promise<any>> = []\n let result\n try {\n result = await transactionStore.run(\n { delayPromises, afterHandlers, commitPromises: [] },\n handler,\n )\n resolve()\n } catch (error) {\n reject(error)\n }\n await awaitAll(() => delayPromises)\n await Promise.all(afterHandlers.map((handler) => handler()))\n\n return result\n },\n }\n}\n\nexport type Transaction = ReturnType<typeof createTransaction>\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAAA;AAEA,eAAe,QAAQ,CAAC,aAAmC;AAAA,EACzD,IAAI,WAAW,YAAY;AAAA,EAE3B,OAAO,MAAM;AAAA,IACX,MAAM,QAAQ,IAAI,QAAQ;AAAA,IAC1B,MAAM,eAAe,YAAY;AAAA,IACjC,IAAI,aAAa,SAAS,SAAS,QAAQ;AAAA,MACzC,WAAW;AAAA,IACb,EAAO;AAAA,MACL;AAAA;AAAA,EAEJ;AAAA;AASF,SAAwB,iBAAiB,GAAG;AAAA,EAC1C,MAAM,mBAAmB,IAAI;AAAA,EAM7B,OAAO;AAAA,QACD,MAAM,GAAG;AAAA,MACX,OAAO,QAAQ,iBAAiB,SAAS,CAAC;AAAA;AAAA,IAG5C,KAAK,GAAqB;AAAA,MACxB,MAAM,QAAQ,iBAAiB,SAAS;AAAA,MACxC,IAAI,CAAC,OAAO;AAAA,QACV,OAAO;AAAA,UACL,SAAS,MAAM;AAAA,UACf,QAAQ,MAAM;AAAA,UACd,QAAQ,MAAM,QAAQ,QAAQ;AAAA,QAChC;AAAA,MACF;AAAA,MAEA,MAAM,MAAM,MAAM,eAAe;AAAA,MACjC,QAAQ,SAAS,QAAQ,YAAY,QAAQ,cAAoB;AAAA,MACjE,MAAM,cAAc,KAAK,OAAO;AAAA,MAEhC,QAAQ,SAAS,eAAe,SAAS,yBACvC,QAAQ,cAAoB;AAAA,MAC9B,MAAM,eAAe,KAAK,aAAa;AAAA,MAEvC,OAAO;AAAA,QACL;AAAA,QACA;AAAA,aACM,OAAM,GAAG;AAAA,UACb,IAAI,MAAM,GAAG;AAAA,YACX,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAAA,UACvC;AAAA,UAEA,qBAAqB;AAAA,UACrB,MAAM,SAAS,MAAM,MAAM,aAAa;AAAA;AAAA,MAE5C;AAAA;AAAA,IAGF,KAAK,CAAC,SAA6B;AAAA,MACjC,iBAAiB,SAAS,GAAG,cAAc,KAAK,OAAO;AAAA;AAAA,SAGnD,IAAwB,CAAC,SAAY;AAAA,MACzC,QAAQ,SAAS,QAAQ,YAAY,QAAQ,cAAoB;AAAA,MACjE,MAAM,gBAAgB,CAAC,OAAO;AAAA,MAC9B,MAAM,gBAA2C,CAAC;AAAA,MAClD,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,SAAS,MAAM,iBAAiB,IAC9B,EAAE,eAAe,eAAe,gBAAgB,CAAC,EAAE,GACnD,OACF;AAAA,QACA,QAAQ;AAAA,QACR,OAAO,OAAO;AAAA,QACd,OAAO,KAAK;AAAA;AAAA,MAEd,MAAM,SAAS,MAAM,aAAa;AAAA,MAClC,MAAM,QAAQ,IAAI,cAAc,IAAI,CAAC,aAAY,SAAQ,CAAC,CAAC;AAAA,MAE3D,OAAO;AAAA;AAAA,EAEX;AAAA;",
|
|
8
|
+
"debugId": "75143A00A85F441C64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function isStreamId(stream) {
|
|
3
|
+
return "id" in stream;
|
|
4
|
+
}
|
|
5
|
+
function isStreamEvents(stream) {
|
|
6
|
+
return "events" in stream && Array.isArray(stream.events);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { isStreamId, isStreamEvents };
|
|
10
|
+
|
|
11
|
+
//# debugId=EF89CA439C05547264756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type {\n Stream,\n StreamEvents,\n StreamId,\n StreamIdEvents,\n} from './utilityTypes.d.ts'\n\nexport { createEventStore } from './createEventStore.ts'\nexport type { BaseOutputEvent as Event } from './utilityTypes.d.ts'\nexport {\n type Snapshot as ProjectionSnapshot,\n isInsideProjection,\n getProjectionInfo,\n} from './createProjection.ts'\nexport type { Checkpoint } from './createCheckpointApi.ts'\nexport {\n isInsideProcessManager,\n getProcessManagerInfo,\n} from './createProcessManager.ts'\nexport {\n isInsideEventListener,\n getEventListenerInfo,\n} from './createEventListener.ts'\nexport * from './errors.ts'\nexport {\n type Snapshot as AggregateRootSnapshot,\n type AnyAggregateRoot,\n type AnyStream,\n createAggregateRoot,\n} from './createAggregateRoot.ts'\n\nexport { skipRefreshing } from './refresh.ts'\nexport { skipReplay } from './replay.ts'\n\nexport function isStreamId(\n stream: Stream,\n): stream is StreamId | StreamIdEvents {\n return 'id' in stream\n}\nexport function isStreamEvents(\n stream: Stream,\n): stream is StreamEvents | StreamIdEvents {\n return 'events' in stream && Array.isArray(stream.events)\n}\nexport type { WrappedEvent } from './wrappedEventBuilder.ts'\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAkCO,SAAS,UAAU,CACxB,QACqC;AAAA,EACrC,OAAO,QAAQ;AAAA;AAEV,SAAS,cAAc,CAC5B,QACyC;AAAA,EACzC,OAAO,YAAY,UAAU,MAAM,QAAQ,OAAO,MAAM;AAAA;",
|
|
8
|
+
"debugId": "EF89CA439C05547264756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|