@anabranch/eventlog 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -5
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,17 +1,130 @@
|
|
|
1
1
|
# @anabranch/eventlog
|
|
2
2
|
|
|
3
|
-
Event log with Task/Stream semantics
|
|
4
|
-
|
|
3
|
+
Event log with **Task/Stream** semantics for event-sourced systems. Built for
|
|
4
|
+
reliable, cursor-based consumption and functional error handling.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Description
|
|
7
|
+
|
|
8
|
+
A high-level event log abstraction that integrates with `@anabranch/task`. By
|
|
9
|
+
representing log operations as **Tasks**, you get first-class support for
|
|
10
|
+
retries, timeouts, and `AbortSignal` propagation out of the box.
|
|
11
|
+
|
|
12
|
+
This library provides a unified interface for appending and consuming events
|
|
13
|
+
across different storage backends while maintaining strict type safety and lazy
|
|
14
|
+
execution patterns.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Lazy Execution**: Operations return a `Task`. Nothing happens until you
|
|
19
|
+
`.run()`.
|
|
20
|
+
- **First-Class Cancellation**: Built-in `AbortSignal` merging across all
|
|
21
|
+
operations.
|
|
22
|
+
- **Cursor-Based**: Resume processing from any position with consumer groups.
|
|
23
|
+
- **At-Least-Once Delivery**: Manual acknowledgement gives you full control.
|
|
24
|
+
- **Pluggable Architecture**: Standardized adapter interface for any storage
|
|
25
|
+
backend.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# JSR
|
|
31
|
+
jsr add @anabranch/eventlog
|
|
32
|
+
|
|
33
|
+
# Deno
|
|
34
|
+
deno add @anabranch/eventlog
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
7
38
|
|
|
8
39
|
```ts
|
|
9
|
-
import {} from "@anabranch/eventlog";
|
|
40
|
+
import { createInMemory, EventLog } from "@anabranch/eventlog";
|
|
41
|
+
|
|
42
|
+
const connector = createInMemory();
|
|
43
|
+
|
|
44
|
+
// Compose your logic as a Task chain
|
|
45
|
+
const program = EventLog.connect(connector).flatMap((log) => {
|
|
46
|
+
return log
|
|
47
|
+
.append("users", { type: "signup", email: "alice@example.com" })
|
|
48
|
+
.tap(() => console.log("Event appended!"))
|
|
49
|
+
.flatMap(() => log.get("users", 0));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Execute the task at the edge of your application
|
|
53
|
+
const result = await program.result();
|
|
54
|
+
|
|
55
|
+
if (result.type === "success") {
|
|
56
|
+
console.log("User at sequence 0:", result.value);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Reliable Consumption
|
|
61
|
+
|
|
62
|
+
The `.consume()` method returns a Stream of batches. To guarantee at-least-once
|
|
63
|
+
delivery, you manually commit the cursor after successful processing.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const log = await EventLog.connect(connector).run();
|
|
67
|
+
|
|
68
|
+
const consumer = log
|
|
69
|
+
.consume("users", "email-service", { batchSize: 10 })
|
|
70
|
+
.map(async (batch) => {
|
|
71
|
+
// 1. Process your events
|
|
72
|
+
for (const event of batch.events) {
|
|
73
|
+
await sendWelcomeEmail(event.data);
|
|
74
|
+
}
|
|
75
|
+
// 2. Commit the cursor only after success
|
|
76
|
+
await log.commit(batch.topic, batch.consumerGroup, batch.cursor).run();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Run the consumer
|
|
80
|
+
await consumer.run();
|
|
10
81
|
```
|
|
11
82
|
|
|
12
83
|
## API
|
|
13
84
|
|
|
14
|
-
###
|
|
85
|
+
### `EventLog.connect(adapter)`
|
|
86
|
+
|
|
87
|
+
Initializes the connection. Returns a
|
|
88
|
+
`Task<EventLog, EventLogConnectionFailed>`.
|
|
89
|
+
|
|
90
|
+
### `log.append(topic, data, options?)`
|
|
91
|
+
|
|
92
|
+
Appends an event. Options include `partitionKey` and `metadata`.\
|
|
93
|
+
Returns `Task<string, EventLogAppendFailed>`.
|
|
94
|
+
|
|
95
|
+
### `log.consume(topic, consumerGroup, options?)`
|
|
96
|
+
|
|
97
|
+
Returns a Stream of event batches. If a cursor is found for the group, it
|
|
98
|
+
resumes automatically.
|
|
99
|
+
|
|
100
|
+
### `log.commit(topic, consumerGroup, cursor)`
|
|
101
|
+
|
|
102
|
+
Persists the progress for a specific consumer group.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Error Handling
|
|
107
|
+
|
|
108
|
+
Because operations are Tasks, you can handle failures declaratively:
|
|
15
109
|
|
|
16
110
|
```ts
|
|
111
|
+
const task = log.append("orders", data)
|
|
112
|
+
.retry({
|
|
113
|
+
attempts: 3,
|
|
114
|
+
delay: (n) => Math.pow(2, n) * 1000, // Exponential backoff
|
|
115
|
+
when: (err) => err instanceof EventLogAppendFailed,
|
|
116
|
+
})
|
|
117
|
+
.timeout(5000)
|
|
118
|
+
.recover((err) => {
|
|
119
|
+
console.error("Critical failure:", err);
|
|
120
|
+
return "FALLBACK_ID";
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const eventId = await task.run();
|
|
17
124
|
```
|
|
125
|
+
|
|
126
|
+
## Related
|
|
127
|
+
|
|
128
|
+
- [@anabranch/task](https://jsr.io/@anabranch/task) - Core Task primitives
|
|
129
|
+
- [@anabranch/stream](https://jsr.io/@anabranch/stream) - Reactive stream
|
|
130
|
+
processing
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anabranch/eventlog",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Event log with Task/Stream semantics. In-memory adapter for event-sourced systems with cursor-based consumption.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -20,5 +20,8 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"anabranch": "^0"
|
|
22
22
|
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^24"
|
|
25
|
+
},
|
|
23
26
|
"_generatedBy": "dnt@dev"
|
|
24
27
|
}
|