swarm-mail 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 +28 -0
- package/dist/adapter.d.ts +36 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23131 -0
- package/{src/pglite.ts → dist/pglite.d.ts} +7 -93
- package/dist/pglite.d.ts.map +1 -0
- package/dist/streams/agent-mail.d.ts +139 -0
- package/dist/streams/agent-mail.d.ts.map +1 -0
- package/dist/streams/debug.d.ts +173 -0
- package/dist/streams/debug.d.ts.map +1 -0
- package/dist/streams/effect/ask.d.ts +124 -0
- package/dist/streams/effect/ask.d.ts.map +1 -0
- package/dist/streams/effect/cursor.d.ts +87 -0
- package/dist/streams/effect/cursor.d.ts.map +1 -0
- package/dist/streams/effect/deferred.d.ts +108 -0
- package/dist/streams/effect/deferred.d.ts.map +1 -0
- package/{src/streams/effect/index.ts → dist/streams/effect/index.d.ts} +1 -0
- package/dist/streams/effect/index.d.ts.map +1 -0
- package/{src/streams/effect/layers.ts → dist/streams/effect/layers.d.ts} +8 -33
- package/dist/streams/effect/layers.d.ts.map +1 -0
- package/dist/streams/effect/lock.d.ts +137 -0
- package/dist/streams/effect/lock.d.ts.map +1 -0
- package/dist/streams/effect/mailbox.d.ts +98 -0
- package/dist/streams/effect/mailbox.d.ts.map +1 -0
- package/dist/streams/events.d.ts +487 -0
- package/dist/streams/events.d.ts.map +1 -0
- package/dist/streams/index.d.ts +106 -0
- package/dist/streams/index.d.ts.map +1 -0
- package/dist/streams/migrations.d.ts +102 -0
- package/dist/streams/migrations.d.ts.map +1 -0
- package/dist/streams/projections.d.ts +173 -0
- package/dist/streams/projections.d.ts.map +1 -0
- package/dist/streams/store.d.ts +171 -0
- package/dist/streams/store.d.ts.map +1 -0
- package/dist/streams/swarm-mail.d.ts +153 -0
- package/dist/streams/swarm-mail.d.ts.map +1 -0
- package/dist/types/adapter.d.ts +267 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/database.d.ts +117 -0
- package/dist/types/database.d.ts.map +1 -0
- package/{src/types/index.ts → dist/types/index.d.ts} +2 -15
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +20 -4
- package/src/adapter.ts +0 -306
- package/src/index.ts +0 -57
- package/src/streams/agent-mail.test.ts +0 -777
- package/src/streams/agent-mail.ts +0 -535
- package/src/streams/debug.test.ts +0 -500
- package/src/streams/debug.ts +0 -727
- package/src/streams/effect/ask.integration.test.ts +0 -314
- package/src/streams/effect/ask.ts +0 -202
- package/src/streams/effect/cursor.integration.test.ts +0 -418
- package/src/streams/effect/cursor.ts +0 -288
- package/src/streams/effect/deferred.test.ts +0 -357
- package/src/streams/effect/deferred.ts +0 -445
- package/src/streams/effect/lock.test.ts +0 -385
- package/src/streams/effect/lock.ts +0 -399
- package/src/streams/effect/mailbox.test.ts +0 -260
- package/src/streams/effect/mailbox.ts +0 -318
- package/src/streams/events.test.ts +0 -924
- package/src/streams/events.ts +0 -329
- package/src/streams/index.test.ts +0 -229
- package/src/streams/index.ts +0 -578
- package/src/streams/migrations.test.ts +0 -359
- package/src/streams/migrations.ts +0 -362
- package/src/streams/projections.test.ts +0 -611
- package/src/streams/projections.ts +0 -564
- package/src/streams/store.integration.test.ts +0 -658
- package/src/streams/store.ts +0 -1129
- package/src/streams/swarm-mail.ts +0 -552
- package/src/types/adapter.ts +0 -392
- package/src/types/database.ts +0 -127
- package/tsconfig.json +0 -22
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DurableDeferred Service - Distributed Promises
|
|
3
|
+
*
|
|
4
|
+
* Creates a "distributed promise" that can be resolved from anywhere.
|
|
5
|
+
* Useful for request/response patterns over streams.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const response = await DurableDeferred.create<Response>({ ttlSeconds: 60 })
|
|
10
|
+
* await actor.append({ payload: message, replyTo: response.url })
|
|
11
|
+
* return response.value // blocks until resolved or timeout
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Implementation:
|
|
15
|
+
* - Uses Effect.Deferred internally for blocking await
|
|
16
|
+
* - Stores pending promises in 'deferred' table with TTL
|
|
17
|
+
* - Polls database for resolution (could be upgraded to NOTIFY/LISTEN)
|
|
18
|
+
* - Cleans up expired entries automatically
|
|
19
|
+
*/
|
|
20
|
+
import { Context, Effect, Layer } from "effect";
|
|
21
|
+
/**
|
|
22
|
+
* Timeout error when deferred expires before resolution
|
|
23
|
+
*/
|
|
24
|
+
export declare class TimeoutError extends Error {
|
|
25
|
+
readonly url: string;
|
|
26
|
+
readonly ttlSeconds: number;
|
|
27
|
+
readonly _tag = "TimeoutError";
|
|
28
|
+
constructor(url: string, ttlSeconds: number);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Not found error when deferred URL doesn't exist
|
|
32
|
+
*/
|
|
33
|
+
export declare class NotFoundError extends Error {
|
|
34
|
+
readonly url: string;
|
|
35
|
+
readonly _tag = "NotFoundError";
|
|
36
|
+
constructor(url: string);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Handle for a pending deferred promise
|
|
40
|
+
*/
|
|
41
|
+
export interface DeferredHandle<T> {
|
|
42
|
+
/** Unique URL/identifier for this deferred */
|
|
43
|
+
readonly url: string;
|
|
44
|
+
/** Blocks until resolved/rejected or timeout */
|
|
45
|
+
readonly value: Effect.Effect<T, TimeoutError | NotFoundError>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Configuration for creating a deferred
|
|
49
|
+
*/
|
|
50
|
+
export interface DeferredConfig {
|
|
51
|
+
/** Time-to-live in seconds before timeout */
|
|
52
|
+
readonly ttlSeconds: number;
|
|
53
|
+
/** Optional project path for database isolation */
|
|
54
|
+
readonly projectPath?: string;
|
|
55
|
+
}
|
|
56
|
+
declare const DurableDeferred_base: Context.TagClass<DurableDeferred, "DurableDeferred", {
|
|
57
|
+
/**
|
|
58
|
+
* Create a new deferred promise
|
|
59
|
+
*
|
|
60
|
+
* @returns Handle with URL and value getter
|
|
61
|
+
*/
|
|
62
|
+
readonly create: <T>(config: DeferredConfig) => Effect.Effect<DeferredHandle<T>>;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a deferred with a value
|
|
65
|
+
*
|
|
66
|
+
* @param url - Deferred identifier
|
|
67
|
+
* @param value - Resolution value
|
|
68
|
+
*/
|
|
69
|
+
readonly resolve: <T>(url: string, value: T, projectPath?: string) => Effect.Effect<void, NotFoundError>;
|
|
70
|
+
/**
|
|
71
|
+
* Reject a deferred with an error
|
|
72
|
+
*
|
|
73
|
+
* @param url - Deferred identifier
|
|
74
|
+
* @param error - Error to reject with
|
|
75
|
+
*/
|
|
76
|
+
readonly reject: (url: string, error: Error, projectPath?: string) => Effect.Effect<void, NotFoundError>;
|
|
77
|
+
/**
|
|
78
|
+
* Await a deferred's resolution (internal - use handle.value instead)
|
|
79
|
+
*/
|
|
80
|
+
readonly await: <T>(url: string, ttlSeconds: number, projectPath?: string) => Effect.Effect<T, TimeoutError | NotFoundError>;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* DurableDeferred service for distributed promises
|
|
84
|
+
*/
|
|
85
|
+
export declare class DurableDeferred extends DurableDeferred_base {
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Live implementation of DurableDeferred service
|
|
89
|
+
*/
|
|
90
|
+
export declare const DurableDeferredLive: Layer.Layer<DurableDeferred, never, never>;
|
|
91
|
+
/**
|
|
92
|
+
* Create a deferred promise
|
|
93
|
+
*/
|
|
94
|
+
export declare function createDeferred<T>(config: DeferredConfig): Effect.Effect<DeferredHandle<T>, never, DurableDeferred>;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve a deferred
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveDeferred<T>(url: string, value: T, projectPath?: string): Effect.Effect<void, NotFoundError, DurableDeferred>;
|
|
99
|
+
/**
|
|
100
|
+
* Reject a deferred
|
|
101
|
+
*/
|
|
102
|
+
export declare function rejectDeferred(url: string, error: Error, projectPath?: string): Effect.Effect<void, NotFoundError, DurableDeferred>;
|
|
103
|
+
/**
|
|
104
|
+
* Cleanup expired deferred entries (call periodically)
|
|
105
|
+
*/
|
|
106
|
+
export declare function cleanupDeferreds(projectPath?: string): Effect.Effect<number>;
|
|
107
|
+
export {};
|
|
108
|
+
//# sourceMappingURL=deferred.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../../src/streams/effect/deferred.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,OAAO,EAAsB,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAQpE;;GAEG;AACH,qBAAa,YAAa,SAAQ,KAAK;aAGnB,GAAG,EAAE,MAAM;aACX,UAAU,EAAE,MAAM;IAHpC,QAAQ,CAAC,IAAI,kBAAkB;gBAEb,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM;CAIrC;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAEV,GAAG,EAAE,MAAM;IADvC,QAAQ,CAAC,IAAI,mBAAmB;gBACJ,GAAG,EAAE,MAAM;CAGxC;AAMD;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC,CAAC;CAChE;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;;IAYG;;;;OAIG;qBACc,CAAC,CAAC,EACjB,MAAM,EAAE,cAAc,KACnB,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAErC;;;;;OAKG;sBACe,CAAC,CAAC,EAClB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,WAAW,CAAC,EAAE,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAEvC;;;;;OAKG;qBACc,CACf,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAEvC;;OAEG;oBACa,CAAC,CAAC,EAChB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC;;AA9CvD;;GAEG;AACH,qBAAa,eAAgB,SAAQ,oBA6ClC;CAAG;AAkQN;;GAEG;AACH,eAAO,MAAM,mBAAmB,4CAK9B,CAAC;AAMH;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,cAAc,GACrB,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,CAAC,CAK1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,CAAC,EACR,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,eAAe,CAAC,CAKrD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,eAAe,CAAC,CAKrD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAE5E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/streams/effect/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC"}
|
|
@@ -19,44 +19,23 @@
|
|
|
19
19
|
* }).pipe(Effect.provide(DurableCursorDeferredLive));
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
22
|
import { Layer } from "effect";
|
|
24
|
-
import { DurableCursor
|
|
25
|
-
import { DurableDeferred
|
|
26
|
-
import { DurableLock
|
|
27
|
-
import { DurableMailbox
|
|
28
|
-
|
|
29
|
-
// ============================================================================
|
|
30
|
-
// Layer Wrappers (convert Context.make to Layer.succeed)
|
|
31
|
-
// ============================================================================
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Cursor service as Layer
|
|
35
|
-
*/
|
|
36
|
-
const CursorLayer = Layer.succeed(DurableCursor, DurableCursorLive);
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Mailbox service as Layer (with cursor dependency)
|
|
40
|
-
*/
|
|
41
|
-
const MailboxLayer = Layer.mergeAll(CursorLayer, DurableMailboxLive);
|
|
42
|
-
|
|
23
|
+
import { DurableCursor } from "./cursor";
|
|
24
|
+
import { DurableDeferred } from "./deferred";
|
|
25
|
+
import { DurableLock } from "./lock";
|
|
26
|
+
import { DurableMailbox } from "./mailbox";
|
|
43
27
|
/**
|
|
44
28
|
* Minimal layer with just Cursor and Deferred
|
|
45
29
|
*
|
|
46
30
|
* Use when you only need event consumption and distributed promises.
|
|
47
31
|
*/
|
|
48
|
-
export const DurableCursorDeferredLive
|
|
49
|
-
CursorLayer,
|
|
50
|
-
DurableDeferredLive,
|
|
51
|
-
);
|
|
52
|
-
|
|
32
|
+
export declare const DurableCursorDeferredLive: Layer.Layer<DurableCursor | DurableDeferred, never, never>;
|
|
53
33
|
/**
|
|
54
34
|
* Mailbox layer with dependencies
|
|
55
35
|
*
|
|
56
36
|
* Provides DurableMailbox + DurableCursor (required dependency).
|
|
57
37
|
*/
|
|
58
|
-
export const DurableMailboxWithDepsLive
|
|
59
|
-
|
|
38
|
+
export declare const DurableMailboxWithDepsLive: Layer.Layer<DurableCursor | DurableMailbox, never, never>;
|
|
60
39
|
/**
|
|
61
40
|
* Ask pattern layer (Mailbox + Deferred)
|
|
62
41
|
*
|
|
@@ -64,10 +43,6 @@ export const DurableMailboxWithDepsLive = MailboxLayer;
|
|
|
64
43
|
* - DurableMailbox (with DurableCursor dependency)
|
|
65
44
|
* - DurableDeferred
|
|
66
45
|
*/
|
|
67
|
-
export const DurableAskLive
|
|
68
|
-
|
|
69
|
-
// ============================================================================
|
|
70
|
-
// Re-exports for convenience
|
|
71
|
-
// ============================================================================
|
|
72
|
-
|
|
46
|
+
export declare const DurableAskLive: Layer.Layer<DurableCursor | DurableMailbox | DurableDeferred, never, never>;
|
|
73
47
|
export { DurableCursor, DurableDeferred, DurableLock, DurableMailbox };
|
|
48
|
+
//# sourceMappingURL=layers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../../src/streams/effect/layers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAqB,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAuB,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,WAAW,EAAmB,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,cAAc,EAAsB,MAAM,WAAW,CAAC;AAgB/D;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,4DAGrC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,2DAAe,CAAC;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,6EAAoD,CAAC;AAMhF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DurableLock - Distributed Mutual Exclusion via CAS
|
|
3
|
+
*
|
|
4
|
+
* Uses seq=0 CAS (Compare-And-Swap) pattern for distributed locking.
|
|
5
|
+
* Provides acquire/release/withLock methods with TTL expiry and contention handling.
|
|
6
|
+
*
|
|
7
|
+
* Based on Kyle Matthews' pattern from Agent Mail.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // Using Effect API
|
|
12
|
+
* const program = Effect.gen(function* (_) {
|
|
13
|
+
* const lock = yield* _(acquireLock("my-resource", { ttlSeconds: 30 }))
|
|
14
|
+
* try {
|
|
15
|
+
* // Critical section
|
|
16
|
+
* } finally {
|
|
17
|
+
* yield* _(lock.release())
|
|
18
|
+
* }
|
|
19
|
+
* }).pipe(Effect.provide(DurableLockLive))
|
|
20
|
+
*
|
|
21
|
+
* // Or use withLock helper
|
|
22
|
+
* const program = Effect.gen(function* (_) {
|
|
23
|
+
* const lock = yield* _(DurableLock)
|
|
24
|
+
* yield* _(lock.withLock("my-resource", Effect.succeed(42)))
|
|
25
|
+
* }).pipe(Effect.provide(DurableLockLive))
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
import { Context, Effect, Layer } from "effect";
|
|
29
|
+
/**
|
|
30
|
+
* Configuration for lock acquisition
|
|
31
|
+
*/
|
|
32
|
+
export interface LockConfig {
|
|
33
|
+
/**
|
|
34
|
+
* Time-to-live in seconds before lock auto-expires
|
|
35
|
+
* @default 30
|
|
36
|
+
*/
|
|
37
|
+
ttlSeconds?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Maximum retry attempts when lock is contended
|
|
40
|
+
* @default 10
|
|
41
|
+
*/
|
|
42
|
+
maxRetries?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Base delay in milliseconds for exponential backoff
|
|
45
|
+
* @default 50
|
|
46
|
+
*/
|
|
47
|
+
baseDelayMs?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Project path for database instance
|
|
50
|
+
*/
|
|
51
|
+
projectPath?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Custom holder ID (defaults to generated UUID)
|
|
54
|
+
*/
|
|
55
|
+
holderId?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle representing an acquired lock
|
|
59
|
+
*/
|
|
60
|
+
export interface LockHandle {
|
|
61
|
+
/** Resource being locked */
|
|
62
|
+
readonly resource: string;
|
|
63
|
+
/** Holder ID who owns the lock */
|
|
64
|
+
readonly holder: string;
|
|
65
|
+
/** Sequence number when acquired */
|
|
66
|
+
readonly seq: number;
|
|
67
|
+
/** Timestamp when lock was acquired */
|
|
68
|
+
readonly acquiredAt: number;
|
|
69
|
+
/** Timestamp when lock expires */
|
|
70
|
+
readonly expiresAt: number;
|
|
71
|
+
/** Release the lock */
|
|
72
|
+
readonly release: () => Effect.Effect<void, LockError>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Lock errors
|
|
76
|
+
*/
|
|
77
|
+
export type LockError = {
|
|
78
|
+
readonly _tag: "LockTimeout";
|
|
79
|
+
readonly resource: string;
|
|
80
|
+
} | {
|
|
81
|
+
readonly _tag: "LockContention";
|
|
82
|
+
readonly resource: string;
|
|
83
|
+
} | {
|
|
84
|
+
readonly _tag: "LockNotHeld";
|
|
85
|
+
readonly resource: string;
|
|
86
|
+
readonly holder: string;
|
|
87
|
+
} | {
|
|
88
|
+
readonly _tag: "DatabaseError";
|
|
89
|
+
readonly error: Error;
|
|
90
|
+
};
|
|
91
|
+
declare const DurableLock_base: Context.TagClass<DurableLock, "DurableLock", {
|
|
92
|
+
/**
|
|
93
|
+
* Acquire a lock on a resource
|
|
94
|
+
*
|
|
95
|
+
* Uses CAS (seq=0) pattern:
|
|
96
|
+
* - INSERT if no lock exists
|
|
97
|
+
* - UPDATE if expired or we already hold it
|
|
98
|
+
*
|
|
99
|
+
* Retries with exponential backoff on contention.
|
|
100
|
+
*/
|
|
101
|
+
readonly acquire: (resource: string, config?: LockConfig) => Effect.Effect<LockHandle, LockError>;
|
|
102
|
+
/**
|
|
103
|
+
* Release a lock
|
|
104
|
+
*
|
|
105
|
+
* Only succeeds if the holder matches.
|
|
106
|
+
*/
|
|
107
|
+
readonly release: (resource: string, holder: string, projectPath?: string) => Effect.Effect<void, LockError>;
|
|
108
|
+
/**
|
|
109
|
+
* Execute an effect with automatic lock acquisition and release
|
|
110
|
+
*
|
|
111
|
+
* Guarantees lock release even on error (Effect.ensuring).
|
|
112
|
+
*/
|
|
113
|
+
readonly withLock: <A, E, R>(resource: string, effect: Effect.Effect<A, E, R>, config?: LockConfig) => Effect.Effect<A, E | LockError, R | DurableLock>;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* DurableLock service for distributed mutual exclusion
|
|
117
|
+
*/
|
|
118
|
+
export declare class DurableLock extends DurableLock_base {
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Live implementation of DurableLock service
|
|
122
|
+
*/
|
|
123
|
+
export declare const DurableLockLive: Layer.Layer<DurableLock, never, never>;
|
|
124
|
+
/**
|
|
125
|
+
* Acquire a lock (convenience Effect wrapper)
|
|
126
|
+
*/
|
|
127
|
+
export declare function acquireLock(resource: string, config?: LockConfig): Effect.Effect<LockHandle, LockError, DurableLock>;
|
|
128
|
+
/**
|
|
129
|
+
* Release a lock (convenience Effect wrapper)
|
|
130
|
+
*/
|
|
131
|
+
export declare function releaseLock(resource: string, holder: string, projectPath?: string): Effect.Effect<void, LockError, DurableLock>;
|
|
132
|
+
/**
|
|
133
|
+
* Execute with lock (convenience Effect wrapper)
|
|
134
|
+
*/
|
|
135
|
+
export declare function withLock<A, E, R>(resource: string, effect: Effect.Effect<A, E, R>, config?: LockConfig): Effect.Effect<A, E | LockError, R | DurableLock>;
|
|
136
|
+
export {};
|
|
137
|
+
//# sourceMappingURL=lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../../src/streams/effect/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAY,MAAM,QAAQ,CAAC;AAQ1D;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kCAAkC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uBAAuB;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;CACxD;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9D;IACE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;;IAY1D;;;;;;;;OAQG;sBACe,CAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,UAAU,KAChB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC;IAEzC;;;;OAIG;sBACe,CAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC;IAEnC;;;;OAIG;uBACgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EACzB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,MAAM,CAAC,EAAE,UAAU,KAChB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,GAAG,WAAW,CAAC;;AAxCzD;;GAEG;AACH,qBAAa,WAAY,SAAQ,gBAuC9B;CAAG;AAwMN;;GAEG;AACH,eAAO,MAAM,eAAe,wCAI1B,CAAC;AAMH;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAKnD;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAK7C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC9B,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,GAAG,WAAW,CAAC,CAKlD"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DurableMailbox - Actor-style messaging with envelope pattern
|
|
3
|
+
*
|
|
4
|
+
* Combines DurableCursor (positioned consumption) with Envelope pattern for
|
|
5
|
+
* request/response messaging between agents.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const program = Effect.gen(function* () {
|
|
10
|
+
* const mailbox = yield* DurableMailbox;
|
|
11
|
+
* const myMailbox = yield* mailbox.create({ agent: "worker-1" });
|
|
12
|
+
*
|
|
13
|
+
* // Send message with optional reply channel
|
|
14
|
+
* yield* myMailbox.send("worker-2", {
|
|
15
|
+
* payload: { task: "process-data" },
|
|
16
|
+
* replyTo: "deferred:xyz"
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* // Receive messages
|
|
20
|
+
* for await (const envelope of myMailbox.receive()) {
|
|
21
|
+
* yield* handleMessage(envelope.payload);
|
|
22
|
+
* if (envelope.replyTo) {
|
|
23
|
+
* yield* DurableDeferred.resolve(envelope.replyTo, result);
|
|
24
|
+
* }
|
|
25
|
+
* yield* envelope.commit();
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import { Context, Effect, Layer } from "effect";
|
|
31
|
+
import { DurableCursor } from "./cursor";
|
|
32
|
+
/**
|
|
33
|
+
* Envelope wrapping a message with metadata
|
|
34
|
+
*/
|
|
35
|
+
export interface Envelope<T = unknown> {
|
|
36
|
+
/** Message payload */
|
|
37
|
+
readonly payload: T;
|
|
38
|
+
/** Optional URL of DurableDeferred for response */
|
|
39
|
+
readonly replyTo?: string;
|
|
40
|
+
/** Agent who sent the message */
|
|
41
|
+
readonly sender: string;
|
|
42
|
+
/** Original message ID */
|
|
43
|
+
readonly messageId: number;
|
|
44
|
+
/** Thread ID for conversation tracking */
|
|
45
|
+
readonly threadId?: string;
|
|
46
|
+
/** Commit this message position */
|
|
47
|
+
readonly commit: () => Effect.Effect<void>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Configuration for creating a mailbox
|
|
51
|
+
*/
|
|
52
|
+
export interface MailboxConfig {
|
|
53
|
+
/** Agent name (mailbox owner) */
|
|
54
|
+
readonly agent: string;
|
|
55
|
+
/** Project key for scoping messages */
|
|
56
|
+
readonly projectKey: string;
|
|
57
|
+
/** Optional project path for database location */
|
|
58
|
+
readonly projectPath?: string;
|
|
59
|
+
/** Batch size for reading messages (default: 100) */
|
|
60
|
+
readonly batchSize?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Mailbox instance for an agent
|
|
64
|
+
*/
|
|
65
|
+
export interface Mailbox {
|
|
66
|
+
/** Agent name */
|
|
67
|
+
readonly agent: string;
|
|
68
|
+
/** Send a message to another agent */
|
|
69
|
+
readonly send: <T>(to: string | string[], envelope: {
|
|
70
|
+
payload: T;
|
|
71
|
+
replyTo?: string;
|
|
72
|
+
threadId?: string;
|
|
73
|
+
importance?: "low" | "normal" | "high" | "urgent";
|
|
74
|
+
}) => Effect.Effect<void>;
|
|
75
|
+
/** Receive messages as async iterable */
|
|
76
|
+
readonly receive: <T = unknown>() => AsyncIterable<Envelope<T>>;
|
|
77
|
+
/** Peek at next message without consuming */
|
|
78
|
+
readonly peek: <T = unknown>() => Effect.Effect<Envelope<T> | null>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* DurableMailbox service interface
|
|
82
|
+
*/
|
|
83
|
+
export interface DurableMailboxService {
|
|
84
|
+
/** Create a new mailbox instance */
|
|
85
|
+
readonly create: (config: MailboxConfig) => Effect.Effect<Mailbox, never, DurableCursor>;
|
|
86
|
+
}
|
|
87
|
+
declare const DurableMailbox_base: Context.TagClass<DurableMailbox, "DurableMailbox", DurableMailboxService>;
|
|
88
|
+
/**
|
|
89
|
+
* DurableMailbox Context.Tag
|
|
90
|
+
*/
|
|
91
|
+
export declare class DurableMailbox extends DurableMailbox_base {
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Live implementation of DurableMailbox service
|
|
95
|
+
*/
|
|
96
|
+
export declare const DurableMailboxLive: Layer.Layer<DurableMailbox, never, never>;
|
|
97
|
+
export {};
|
|
98
|
+
//# sourceMappingURL=mailbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox.d.ts","sourceRoot":"","sources":["../../../src/streams/effect/mailbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,aAAa,EAAe,MAAM,UAAU,CAAC;AAQtD;;GAEG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO;IACnC,sBAAsB;IACtB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kDAAkD;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,iBAAiB;IACjB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EACf,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EACrB,QAAQ,EAAE;QACR,OAAO,EAAE,CAAC,CAAC;QACX,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;KACnD,KACE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,OAAO,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,CACf,MAAM,EAAE,aAAa,KAClB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;CACnD;;AAMD;;GAEG;AACH,qBAAa,cAAe,SAAQ,mBAGjC;CAAG;AAwMN;;GAEG;AACH,eAAO,MAAM,kBAAkB,2CAE7B,CAAC"}
|