@effect-pantry/events 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 effect-pantry contributors
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,362 @@
1
+ # @effect-pantry/events
2
+
3
+ A type-safe, in-memory event bus for Effect-TS v3. Define events with branded tags and inferred payload types, then publish/subscribe — all within the Effect runtime.
4
+
5
+ ## Features
6
+
7
+ - **Fully type-safe** — payload types are inferred from your schemas; the compiler catches mismatches
8
+ - **Schema-agnostic** — accepts `@effect/schema` or any library implementing the `@standard-schema/spec` interface (Zod, Valibot, ArkType)
9
+ - **Runtime payload validation** — input is validated through your schema at publish time; invalid payloads produce a `SchemaParseError`
10
+ - **Pluggable bus** — `EventBus` is a `Context.Tag`; the default implementation uses in-memory `PubSub`, but you can swap in your own
11
+ - **Composable** — build custom buses on top of the default one (e.g., record every event, add transforms, bridge to external systems)
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @effect-pantry/events effect
17
+ ```
18
+
19
+ This package targets **Effect v3**. Not compatible with v4.
20
+
21
+ ---
22
+
23
+ ## Basic Usage
24
+
25
+ Define an event, provide the default `EventBus`, then publish and subscribe.
26
+
27
+ ```ts
28
+ import { Event, EventBus } from "@effect-pantry/events"
29
+ import { Effect, Schema, Stream } from "effect"
30
+
31
+ // 1. Define an event
32
+ const UserCreated = Event.make({
33
+ tag: "UserCreated",
34
+ payload: Schema.Struct({ id: Schema.String, name: Schema.String }),
35
+ })
36
+
37
+ // 2. Provide the default in-memory bus
38
+ const layer = EventBus.layer()
39
+
40
+ // 3. Subscribe and publish
41
+ const program = Effect.gen(function* () {
42
+ const stream = EventBus.subscribe(UserCreated)
43
+ const fiber = yield* Effect.fork(
44
+ Stream.runForEach(stream, (envelope) =>
45
+ Effect.log(`User ${envelope.payload.name} created`),
46
+ ),
47
+ )
48
+ yield* EventBus.publish(UserCreated, { id: "1", name: "Alice" })
49
+ yield* Fiber.join(fiber)
50
+ })
51
+
52
+ Effect.runPromise(Effect.provide(program, layer))
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Events
58
+
59
+ ### Defining Events
60
+
61
+ Call `Event.make` with a `tag` string and an optional `payload` schema. The schema is used **only for type inference**.
62
+
63
+ ```ts
64
+ import { Event } from "@effect-pantry/events"
65
+ import { Schema } from "effect"
66
+
67
+ // With a payload schema
68
+ const OrderPlaced = Event.make({
69
+ tag: "OrderPlaced",
70
+ payload: Schema.Struct({
71
+ orderId: Schema.String,
72
+ amount: Schema.Number,
73
+ }),
74
+ })
75
+
76
+ // Without a payload (defaults to Schema.Void)
77
+ const SystemStarted = Event.make({ tag: "SystemStarted" })
78
+ ```
79
+
80
+ > **The `tag` must be system-wide unique.** It is the primary identifier used to route events between publishers and subscribers. Two events with the same tag will share subscribers.
81
+
82
+ | Option | Type | Description |
83
+ | ------------ | ------------ | --------------------------------------------------------------- |
84
+ | **`tag`** | `string` | **Required.** System-wide unique identifier for the event. |
85
+ | **`payload`** | `AnyPayload` | **Optional.** Schema for type inference. Defaults to `Schema.Void`. |
86
+
87
+ `AnyPayload` accepts `@effect/schema` or any `StandardSchemaV1`-compatible library (Zod, Valibot, ArkType, etc.).
88
+
89
+ ### Type Guards
90
+
91
+ ```ts
92
+ import { Event } from "@effect-pantry/events"
93
+
94
+ Event.isEvent(UserCreated) // true
95
+ Event.isEvent({ tag: "x" }) // false
96
+ ```
97
+
98
+ ---
99
+
100
+ ## The EventBus
101
+
102
+ `EventBus` is a **`Context.Tag`** — a contract, not a concrete implementation. The default implementation ships with the package, but you can swap it out, or build on top of it, just by providing a different service.
103
+
104
+ ### Default Implementation
105
+
106
+ The default bus is backed by Effect's in-memory `PubSub`. Publish pushes an event onto the bus; subscribe returns a `Stream` filtered by event tag.
107
+
108
+ #### Providing the Bus
109
+
110
+ An **unbounded** queue is recommended for most use cases.
111
+
112
+ ```ts
113
+ import { EventBus } from "@effect-pantry/events"
114
+
115
+ const layer = EventBus.layer()
116
+ Effect.provide(myProgram, layer)
117
+ ```
118
+
119
+ > **Bounded queues are not recommended.** When you set a `capacity`, publishers will be suspended if the queue fills up, waiting for subscribers to drain it. This can lead to deadlocks in programs where publishing and subscribing happen within the same fiber, or introduce hard-to-debug backpressure. Prefer the default unbounded queue unless you have a specific need to limit memory usage.
120
+
121
+ If you do need a bounded queue:
122
+
123
+ ```ts
124
+ const boundedLayer = EventBus.layer({ capacity: 256 })
125
+ ```
126
+
127
+ #### Publishing
128
+
129
+ ```ts
130
+ const run = Effect.gen(function* () {
131
+ const ok = yield* EventBus.publish(OrderPlaced, {
132
+ orderId: "ord_001",
133
+ amount: 2999,
134
+ })
135
+ // ok: boolean
136
+ })
137
+ ```
138
+
139
+ If the bus isn't in context, `publish` fails with `EventBusNotFoundError`.
140
+
141
+ #### Subscribing
142
+
143
+ `EventBus.subscribe` returns a `Stream` of `Envelope` objects. Subscriptions filter by event tag — publishing a different event type won't trigger the wrong subscriber.
144
+
145
+ ```ts
146
+ const run = Effect.gen(function* () {
147
+ const stream = EventBus.subscribe(OrderPlaced)
148
+
149
+ yield* Stream.runForEach(stream, (envelope) =>
150
+ Effect.log(`Order ${envelope.payload.orderId} — $${envelope.payload.amount}`),
151
+ )
152
+ })
153
+ ```
154
+
155
+ #### The Envelope
156
+
157
+ Every published event is wrapped in an `Envelope`:
158
+
159
+ | Field | Type | Description |
160
+ | ----------- | -------- | ------------------------------------------------ |
161
+ | **`id`** | `string` | UUID v4 generated at publish time. |
162
+ | **`ts`** | `number` | Unix timestamp in milliseconds. |
163
+ | **`event`** | `Event` | The event definition that was published. |
164
+ | **`payload`** | (inferred) | The type-safe payload data. |
165
+
166
+ #### Error Handling
167
+
168
+ When the `EventBus` service isn't provided, operations fail with `EventBusNotFoundError`:
169
+
170
+ ```ts
171
+ import { EventBus, EventBusNotFoundError } from "@effect-pantry/events"
172
+
173
+ const result = yield* Effect.either(
174
+ EventBus.publish(OrderPlaced, { orderId: "1", amount: 99 }),
175
+ )
176
+ // Left(EventBusNotFoundError): "EventBus service not provided..."
177
+ ```
178
+
179
+ When the payload doesn't match the event schema, `publish()` fails with `SchemaParseError`:
180
+
181
+ ```ts
182
+ import { EventBus, SchemaParseError } from "@effect-pantry/events"
183
+
184
+ const result = yield* Effect.either(
185
+ EventBus.publish(OrderPlaced, { orderId: 1, amount: "not-a-number" }),
186
+ )
187
+ // Left(SchemaParseError): "Expected number, received string"
188
+ ```
189
+
190
+ #### Optional Access
191
+
192
+ When the bus is truly optional, use the `Optional` variants — they return `Option` instead of failing:
193
+
194
+ ```ts
195
+ // Returns Option<boolean> — none if bus isn't provided
196
+ const result = yield* EventBus.publishOptional(OrderPlaced, {
197
+ orderId: "1",
198
+ amount: 99,
199
+ })
200
+
201
+ // Returns Option<Stream>
202
+ const stream = yield* EventBus.subscribeOptional(OrderPlaced)
203
+ ```
204
+
205
+ ### Custom Implementations
206
+
207
+ Because `EventBus` is just a `Context.Tag`, you can implement your own bus and provide it instead. The interface you need to satisfy is:
208
+
209
+ ```ts
210
+ {
211
+ readonly publish: <TEvent extends Event.AnyEvent>(
212
+ event: TEvent,
213
+ input: TEvent[typeof Event.MetaTypeId]['input'],
214
+ ) => Effect.Effect<boolean, Errors.SchemaParseError>
215
+
216
+ readonly subscribe: <TEvent extends Event.AnyEvent>(
217
+ event: TEvent,
218
+ ) => Stream.Stream<Envelope.Envelope<TEvent>, never>
219
+
220
+ readonly unsafePublish: <TEvent extends Event.AnyEvent>(
221
+ event: TEvent,
222
+ input: TEvent[typeof Event.MetaTypeId]['input'],
223
+ ) => boolean
224
+ }
225
+ ```
226
+
227
+ You can build on top of the default bus using `EventBus.make()` and add side effects without changing the shape:
228
+
229
+ ```ts
230
+ import { EventBus, Envelope } from "@effect-pantry/events"
231
+ import { Effect, Layer } from "effect"
232
+
233
+ const makeLoggingBus = Effect.gen(function* () {
234
+ const bus = yield* EventBus.make() // the default in-memory bus
235
+
236
+ return EventBus.of({
237
+ publish: (event, payload) =>
238
+ Effect.gen(function* () {
239
+ yield* Effect.log(`[event] ${event.tag}`, payload)
240
+ return yield* bus.publish(event, payload)
241
+ }),
242
+ subscribe: (event) => bus.subscribe(event),
243
+ unsafePublish: (event, payload) => {
244
+ console.log(`[event] ${event.tag}`)
245
+ return bus.unsafePublish(event, payload)
246
+ },
247
+ })
248
+ })
249
+
250
+ const LoggingBusLayer = Layer.effect(EventBus, makeLoggingBus)
251
+ ```
252
+
253
+ For cross-cutting concerns that need their own interface, define a separate `Context.Tag`. For example, a recorder that stores every published event:
254
+
255
+ ```ts
256
+ import { EventBus, Envelope } from "@effect-pantry/events"
257
+ import { Context, Effect, Layer, Ref } from "effect"
258
+
259
+ class Recorder extends Context.Tag("Recorder")<
260
+ Recorder,
261
+ {
262
+ readonly push: (envelope: Envelope.Envelope<any>) => Effect.Effect<void>
263
+ readonly all: () => Effect.Effect<Array<Envelope.Envelope<any>>>
264
+ }
265
+ >() {}
266
+
267
+ const RecorderLive = Layer.effect(
268
+ Recorder,
269
+ Effect.gen(function* () {
270
+ const ref = yield* Ref.make<Array<Envelope.Envelope<any>>>([])
271
+ return Recorder.of({
272
+ push: (envelope) => Ref.update(ref, (history) => [...history, envelope]),
273
+ all: () => Ref.get(ref),
274
+ })
275
+ }),
276
+ )
277
+
278
+ // Build a bus that records via the Recorder tag
279
+ const makeRecordingBus = Effect.gen(function* () {
280
+ const bus = yield* EventBus.make()
281
+ const recorder = yield* Recorder
282
+
283
+ return EventBus.of({
284
+ publish: (event, payload) =>
285
+ Effect.gen(function* () {
286
+ const envelope = Envelope.make({ event, payload })
287
+ yield* recorder.push(envelope)
288
+ return yield* bus.publish(event, payload)
289
+ }),
290
+ subscribe: (event) => bus.subscribe(event),
291
+ unsafePublish: (event, payload) => bus.unsafePublish(event, payload),
292
+ })
293
+ })
294
+
295
+ const RecordingBusLayer = Layer.effect(EventBus, makeRecordingBus)
296
+
297
+ // Provide all layers
298
+ const program = Effect.provide(myProgram, RecordingBusLayer)
299
+ .pipe(Effect.provide(RecorderLive))
300
+ ```
301
+
302
+ ---
303
+
304
+ ## API Reference
305
+
306
+ ### `Event`
307
+
308
+ | Export | Description |
309
+ | --------------- | ------------------------------------------ |
310
+ | `Event.make(options)` | Create an event definition with `tag` and optional `payload`. |
311
+ | `Event.isEvent(u)` | Runtime type guard. Returns `true` for Event instances. |
312
+ | `Event.MetaTypeId` | Symbol key for accessing system-level event metadata (`EventMeta`). |
313
+ | `Event.EventMeta<Payload>` | Container for system-level type information (e.g. `inferPayload`). |
314
+
315
+ ### `EventBus`
316
+
317
+ | Export | Description |
318
+ | ------------------------- | -------------------------------------------------------- |
319
+ | `EventBus` | `Context.Tag` — the contract. Inject with `yield* EventBus`. |
320
+ | `EventBus.publish(event, payload)` | Publish. Fails with `EventBusNotFoundError` if bus absent. |
321
+ | `EventBus.subscribe(event)` | Subscribe. Returns `Stream<Envelope>`. |
322
+ | `EventBus.publishOptional(event, payload)` | Non-failing publish. Returns `Option<boolean>`. |
323
+ | `EventBus.subscribeOptional(event)` | Non-failing subscribe. Returns `Option<Stream>`. |
324
+ | `EventBus.layer(options?)` | Create a `Layer` providing the default in-memory bus. |
325
+ | `EventBus.make(options?)` | Create the default bus directly (returns `Effect<EventBus>`). |
326
+
327
+ ### `Envelope`
328
+
329
+ | Export | Description |
330
+ | --------------------- | ---------------------------------------- |
331
+ | `Envelope.make({ event, payload })` | Create an envelope (generates UUID + timestamp). |
332
+ | `Envelope.isEnvelope(u)` | Runtime type guard. |
333
+
334
+ ### Errors
335
+
336
+ | Export | Description |
337
+ | ----------------------- | ---------------------------------------------- |
338
+ | `EventBusNotFoundError` | Thrown when EventBus is not in the context. |
339
+ | `SchemaParseError` | Thrown when payload validation fails. |
340
+
341
+ ### Symbols
342
+
343
+ | Export | Description |
344
+ | -------------------- | ----------------------------------------------------- |
345
+ | `Event.TypeId` | Brand symbol for Event instances. |
346
+ | `Event.MetaTypeId` | Symbol key for accessing system-level event metadata. |
347
+ | `Envelope.TypeId` | Brand symbol for Envelope instances. |
348
+
349
+ ### Types
350
+
351
+ | Export | Description |
352
+ | ------------------------- | --------------------------------------------------------- |
353
+ | `Event<Tag, Payload>` | Typed event definition. |
354
+ | `Event.EventMeta<Payload>` | System-level event metadata (inferred payload type, etc.). |
355
+ | `Envelope<TEvent>` | Published event with `id`, `ts`, `event`, and `payload`. |
356
+ | `AnyPayload` | `Schema.Schema.Any \| StandardSchemaV1`. |
357
+ | `InferPayloadOutput<Payload>` | Extracts the output (decoded) type from a payload schema. |
358
+ | `InferPayloadInput<Payload>` | Extracts the input (encoded) type from a payload schema. |
359
+
360
+ ## License
361
+
362
+ MIT
@@ -0,0 +1,44 @@
1
+ import * as Event from './Event.js';
2
+ /**
3
+ * Brand symbol for Envelope instances.
4
+ */
5
+ export declare const TypeId: unique symbol;
6
+ export type TypeId = typeof TypeId;
7
+ /**
8
+ * Runtime type guard: checks whether a value is an {@link Envelope}.
9
+ */
10
+ export declare const isEnvelope: (u: unknown) => u is Envelope<any>;
11
+ /**
12
+ * A published event wrapped with metadata.
13
+ *
14
+ * Carries the original event definition, the payload,
15
+ * a unique id (UUID v4), and a Unix timestamp.
16
+ */
17
+ export interface Envelope<out TEvent extends Event.AnyEvent> {
18
+ readonly [TypeId]: TypeId;
19
+ /** Unique identifier for this event occurrence (UUID v4) */
20
+ readonly id: string;
21
+ /** The event definition that was published */
22
+ readonly event: TEvent;
23
+ /** Unix timestamp (milliseconds) of when the envelope was created */
24
+ readonly ts: number;
25
+ /** The payload matching the event's schema (output/decoded type) */
26
+ readonly payload: TEvent[typeof Event.MetaTypeId]['output'];
27
+ }
28
+ /** Strip the brand symbol from an Envelope type. */
29
+ export type WithoutBrand<T extends Envelope<any>> = Omit<T, TypeId>;
30
+ /**
31
+ * Extract the output payload type from an Event definition.
32
+ * Convenience type for use with {@link Payload.parse} / {@link Payload.parseSync}.
33
+ */
34
+ export type ExtractPayload<T extends Event.AnyEvent> = T[typeof Event.MetaTypeId]['output'];
35
+ /**
36
+ * Create an envelope for a published event.
37
+ *
38
+ * Automatically generates a UUID v4 id and sets the timestamp.
39
+ */
40
+ export declare const make: <TEvent extends Event.AnyEvent>(envelope: {
41
+ readonly event: TEvent;
42
+ readonly payload: TEvent[typeof Event.MetaTypeId]['output'];
43
+ }) => Envelope<TEvent>;
44
+ //# sourceMappingURL=Envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Envelope.d.ts","sourceRoot":"","sources":["../src/Envelope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,OAAO,MAAqD,CAAC;AAElF,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AAEnC;;GAEG;AACH,eAAO,MAAM,UAAU,MAAO,OAAO,KAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAqC,CAAC;AAE/F;;;;;GAKG;AACH,MAAM,WAAW,QAAQ,CAAC,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC,QAAQ;IACzD,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC7D;AAED,oDAAoD;AACpD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;AAI5F;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,MAAM,SAAS,KAAK,CAAC,QAAQ,YAAY;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC7D,KAAG,QAAQ,CAAC,MAAM,CAKlB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { Predicate } from 'effect';
2
+ /**
3
+ * Brand symbol for Envelope instances.
4
+ */
5
+ export const TypeId = Symbol.for('@effect-pantry/events/Envelope');
6
+ /**
7
+ * Runtime type guard: checks whether a value is an {@link Envelope}.
8
+ */
9
+ export const isEnvelope = (u) => Predicate.hasProperty(u, TypeId);
10
+ const Proto = { [TypeId]: TypeId };
11
+ /**
12
+ * Create an envelope for a published event.
13
+ *
14
+ * Automatically generates a UUID v4 id and sets the timestamp.
15
+ */
16
+ export const make = (envelope) => {
17
+ return Object.assign(Object.create(Proto), envelope, {
18
+ id: globalThis.crypto.randomUUID(),
19
+ ts: Date.now(),
20
+ });
21
+ };
22
+ //# sourceMappingURL=Envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Envelope.js","sourceRoot":"","sources":["../src/Envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGnC;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAkB,MAAM,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;AAIlF;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAU,EAAsB,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AA6B/F,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;AAEnC;;;;GAIG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAgC,QAGnD,EAAoB,EAAE;IACrB,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE;QACnD,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE;QAClC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAqB,CAAC;AACzB,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ declare const EventBusNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "EventBusNotFoundError";
3
+ } & Readonly<A>;
4
+ /**
5
+ * The EventBus service was not provided to the Effect runtime.
6
+ */
7
+ export declare class EventBusNotFoundError extends EventBusNotFoundError_base<{
8
+ readonly message: string;
9
+ }> {
10
+ }
11
+ declare const SchemaParseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
12
+ readonly _tag: "SchemaParseError";
13
+ } & Readonly<A>;
14
+ /**
15
+ * Validation of the event payload through the schema failed.
16
+ *
17
+ * The `schema` field holds the schema that produced the error, enabling
18
+ * callers to inspect or recover the schema at runtime.
19
+ */
20
+ export declare class SchemaParseError extends SchemaParseError_base<{
21
+ readonly message: string;
22
+ readonly schema: unknown;
23
+ }> {
24
+ }
25
+ export {};
26
+ //# sourceMappingURL=Errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../src/Errors.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,2BAA0C;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;CAAG;;;;AAEL;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,sBAAqC;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG"}
package/dist/Errors.js ADDED
@@ -0,0 +1,15 @@
1
+ import { Data } from 'effect';
2
+ /**
3
+ * The EventBus service was not provided to the Effect runtime.
4
+ */
5
+ export class EventBusNotFoundError extends Data.TaggedError('EventBusNotFoundError') {
6
+ }
7
+ /**
8
+ * Validation of the event payload through the schema failed.
9
+ *
10
+ * The `schema` field holds the schema that produced the error, enabling
11
+ * callers to inspect or recover the schema at runtime.
12
+ */
13
+ export class SchemaParseError extends Data.TaggedError('SchemaParseError') {
14
+ }
15
+ //# sourceMappingURL=Errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.js","sourceRoot":"","sources":["../src/Errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,IAAI,CAAC,WAAW,CAAC,uBAAuB,CAEjF;CAAG;AAEL;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAGvE;CAAG"}
@@ -0,0 +1,71 @@
1
+ import { Schema } from 'effect';
2
+ import * as Payload from './Payload.js';
3
+ /**
4
+ * Brand symbol for Event instances. Used by {@link isEvent} to
5
+ * distinguish Event objects from plain values at runtime.
6
+ */
7
+ export declare const TypeId: unique symbol;
8
+ export type TypeId = typeof TypeId;
9
+ /**
10
+ * Meta typeid — single access point for system-level event metadata.
11
+ *
12
+ * All internal machinery (payload schema, inferred type, etc.) lives
13
+ * behind this symbol so the `Event` interface stays clean and
14
+ * extensible for future system-level additions.
15
+ */
16
+ export declare const MetaTypeId: unique symbol;
17
+ export type MetaTypeId = typeof MetaTypeId;
18
+ /**
19
+ * System-level metadata attached to every {@link Event}.
20
+ *
21
+ * Holds phantom type information (inferred input/output types) and
22
+ * any future internal fields the framework needs — things *added by the
23
+ * system*, not the user. User-facing properties like {@link Event.payload}
24
+ * live directly on the {@link Event} interface.
25
+ */
26
+ export interface EventMeta<Payload extends Payload.AnyPayload> {
27
+ /** Phantom type for the output (decoded) type — what subscribers receive. */
28
+ readonly output: Payload.InferPayloadOutput<Payload>;
29
+ /** Phantom type for the input (encoded) type — what publishers provide. */
30
+ readonly input: Payload.InferPayloadInput<Payload>;
31
+ }
32
+ /**
33
+ * A typed event definition.
34
+ *
35
+ * Created via {@link Event.make} — carries a string tag and an optional
36
+ * payload schema. System-level metadata (inferred type, etc.) lives
37
+ * behind the {@link MetaTypeId} symbol.
38
+ *
39
+ * @typeParam Tag - Discriminant string tag (e.g. `"user.created"`)
40
+ * @typeParam Payload - Schema used to infer the event payload
41
+ */
42
+ export interface Event<out Tag extends string, in out Payload extends Payload.AnyPayload = typeof Schema.Void> {
43
+ readonly [MetaTypeId]: EventMeta<Payload>;
44
+ readonly [TypeId]: TypeId;
45
+ readonly tag: Tag;
46
+ readonly payload: Payload;
47
+ }
48
+ export type AnyEvent = Event<any, any>;
49
+ /**
50
+ * Runtime type guard: checks whether a value is an {@link Event} instance.
51
+ */
52
+ export declare const isEvent: (u: unknown) => u is AnyEvent;
53
+ /**
54
+ * Create a new event definition.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const UserCreated = Event.make({
59
+ * tag: 'user.created',
60
+ * payload: Schema.Struct({ id: Schema.String, name: Schema.String }),
61
+ * });
62
+ * ```
63
+ *
64
+ * @param options.tag - Unique string identifier for the event
65
+ * @param options.payload - Schema for the event payload (defaults to `Schema.Void`)
66
+ */
67
+ export declare const make: <Tag extends string, Payload extends Payload.AnyPayload = typeof Schema.Void>(options: {
68
+ readonly tag: Tag;
69
+ readonly payload?: Payload;
70
+ }) => Event<Tag, Payload>;
71
+ //# sourceMappingURL=Event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Event.d.ts","sourceRoot":"","sources":["../src/Event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,OAAO,MAAkD,CAAC;AAE/E,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AAEnC;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,MAAuD,CAAC;AAExF,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS,CAAC,OAAO,SAAS,OAAO,CAAC,UAAU;IAC3D,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrD,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,KAAK,CACpB,GAAG,CAAC,GAAG,SAAS,MAAM,EACtB,EAAE,CAAC,GAAG,CAAC,OAAO,SAAS,OAAO,CAAC,UAAU,GAAG,OAAO,MAAM,CAAC,IAAI;IAE9D,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,OAAO,MAAO,OAAO,KAAG,CAAC,IAAI,QAA4C,CAAC;AAIvF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,IAAI,GACf,GAAG,SAAS,MAAM,EAClB,OAAO,SAAS,OAAO,CAAC,UAAU,GAAG,OAAO,MAAM,CAAC,IAAI,WAC9C;IACT,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,KAAG,KAAK,CAAC,GAAG,EAAE,OAAO,CAQrB,CAAC"}
package/dist/Event.js ADDED
@@ -0,0 +1,43 @@
1
+ import { Predicate, Schema } from 'effect';
2
+ /**
3
+ * Brand symbol for Event instances. Used by {@link isEvent} to
4
+ * distinguish Event objects from plain values at runtime.
5
+ */
6
+ export const TypeId = Symbol.for('@effect-pantry/events/Event');
7
+ /**
8
+ * Meta typeid — single access point for system-level event metadata.
9
+ *
10
+ * All internal machinery (payload schema, inferred type, etc.) lives
11
+ * behind this symbol so the `Event` interface stays clean and
12
+ * extensible for future system-level additions.
13
+ */
14
+ export const MetaTypeId = Symbol.for('@effect-pantry/events/Event.Meta');
15
+ /**
16
+ * Runtime type guard: checks whether a value is an {@link Event} instance.
17
+ */
18
+ export const isEvent = (u) => Predicate.hasProperty(u, TypeId);
19
+ const Proto = { [TypeId]: TypeId };
20
+ /**
21
+ * Create a new event definition.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const UserCreated = Event.make({
26
+ * tag: 'user.created',
27
+ * payload: Schema.Struct({ id: Schema.String, name: Schema.String }),
28
+ * });
29
+ * ```
30
+ *
31
+ * @param options.tag - Unique string identifier for the event
32
+ * @param options.payload - Schema for the event payload (defaults to `Schema.Void`)
33
+ */
34
+ export const make = (options) => {
35
+ const payload = (options.payload ?? Schema.Void);
36
+ const self = {
37
+ tag: options.tag,
38
+ payload,
39
+ [MetaTypeId]: {},
40
+ };
41
+ return Object.assign(Object.create(Proto), self);
42
+ };
43
+ //# sourceMappingURL=Event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Event.js","sourceRoot":"","sources":["../src/Event.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG3C;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAkB,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;AAI/E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAkB,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAyCxF;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAU,EAAiB,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAEvF,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;AAEnC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAGlB,OAGD,EAAuB,EAAE;IACxB,MAAM,OAAO,GAAY,CAAC,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAY,CAAC;IACrE,MAAM,IAAI,GAAG;QACX,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO;QACP,CAAC,UAAU,CAAC,EAAE,EAAwB;KACvC,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC,CAAC"}
@@ -0,0 +1,79 @@
1
+ import { Effect, Context, Stream, Layer, Option } from 'effect';
2
+ import * as Errors from './Errors.js';
3
+ import * as Event from './Event.js';
4
+ import * as EnvelopeApi from './Envelope.js';
5
+ declare const EventBus_base: Context.TagClass<EventBus, "@effect-pantry/events/EventBus", {
6
+ readonly publish: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => Effect.Effect<boolean, Errors.SchemaParseError>;
7
+ readonly subscribe: <TEvent extends Event.AnyEvent>(event: TEvent) => Stream.Stream<EnvelopeApi.Envelope<TEvent>>;
8
+ readonly unsafePublish: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => boolean;
9
+ }>;
10
+ /**
11
+ * In-memory typed event bus backed by Effect's {@link PubSub}.
12
+ *
13
+ * Provides publish/subscribe with per-event-tag filtering and both
14
+ * fail-fast and optional access patterns.
15
+ *
16
+ * Provide it via {@link EventBus.layer} or manually.
17
+ */
18
+ export declare class EventBus extends EventBus_base {
19
+ }
20
+ /**
21
+ * Get the EventBus from context as an `Option`, returning `none` when absent.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const maybeBus = yield* EventBus.getOption;
26
+ * ```
27
+ */
28
+ export declare const getOption: Effect.Effect<Option.Option<{
29
+ readonly publish: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => Effect.Effect<boolean, Errors.SchemaParseError>;
30
+ readonly subscribe: <TEvent extends Event.AnyEvent>(event: TEvent) => Stream.Stream<EnvelopeApi.Envelope<TEvent>>;
31
+ readonly unsafePublish: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => boolean;
32
+ }>, never, never>;
33
+ /**
34
+ * Publish an event. Requires the EventBus service in context.
35
+ *
36
+ * Validates the input through the event's payload schema before publishing.
37
+ * Fails with {@link EventBusNotFoundError} if the bus is not provided,
38
+ * or with {@link SchemaParseError} if the input fails schema validation.
39
+ */
40
+ export declare function publish<TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']): Effect.Effect<boolean, Errors.EventBusNotFoundError | Errors.SchemaParseError>;
41
+ export declare function subscribe<TEvent extends Event.AnyEvent>(event: TEvent): Stream.Stream<EnvelopeApi.Envelope<TEvent>, Errors.EventBusNotFoundError>;
42
+ /**
43
+ * Non-failing variant of {@link publish}. Returns `Option.none()`
44
+ * if the EventBus is not in context, or `Option.some(result)` with
45
+ * the publish result if it is.
46
+ */
47
+ export declare const publishOptional: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => Effect.Effect<Option.Option<boolean>, Errors.SchemaParseError>;
48
+ /**
49
+ * Non-failing variant of {@link subscribe}. Returns `Option.none()`
50
+ * if the EventBus is not in context, or `Option.some(stream)` if it is.
51
+ */
52
+ export declare const subscribeOptional: <TEvent extends Event.AnyEvent>(event: TEvent) => Effect.Effect<Option.Option<Stream.Stream<EnvelopeApi.Envelope<TEvent>>>>;
53
+ type MakeOptions = {
54
+ /** Max number of buffered events. Omit for unbounded (recommended). */
55
+ readonly capacity?: number;
56
+ };
57
+ /**
58
+ * Create an EventBus service backed by a bounded or unbounded {@link PubSub}.
59
+ *
60
+ * @param options.capacity - Max number of buffered events. If omitted, an
61
+ * unbounded queue is used (never blocks publishers).
62
+ */
63
+ export declare const make: (options?: MakeOptions) => Effect.Effect<{
64
+ readonly publish: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => Effect.Effect<boolean, Errors.SchemaParseError>;
65
+ readonly subscribe: <TEvent extends Event.AnyEvent>(event: TEvent) => Stream.Stream<EnvelopeApi.Envelope<TEvent>>;
66
+ readonly unsafePublish: <TEvent extends Event.AnyEvent>(event: TEvent, input: TEvent[typeof Event.MetaTypeId]['input']) => boolean;
67
+ }, never, never>;
68
+ /**
69
+ * Create an {@link Effect.Layer} providing the EventBus service.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const layer = EventBus.layer({ capacity: 256 });
74
+ * const program = Effect.provide(program, layer);
75
+ * ```
76
+ */
77
+ export declare const layer: (options?: MakeOptions) => Layer.Layer<EventBus, never, never>;
78
+ export {};
79
+ //# sourceMappingURL=EventBus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventBus.d.ts","sourceRoot":"","sources":["../src/EventBus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { Effect, Context, PubSub, Stream, pipe, Layer, Option } from 'effect';
2
+ import * as Errors from './Errors.js';
3
+ import * as EnvelopeApi from './Envelope.js';
4
+ import * as PayloadApi from './Payload.js';
5
+ /**
6
+ * In-memory typed event bus backed by Effect's {@link PubSub}.
7
+ *
8
+ * Provides publish/subscribe with per-event-tag filtering and both
9
+ * fail-fast and optional access patterns.
10
+ *
11
+ * Provide it via {@link EventBus.layer} or manually.
12
+ */
13
+ export class EventBus extends Context.Tag('@effect-pantry/events/EventBus')() {
14
+ }
15
+ /**
16
+ * Get the EventBus from context as an `Option`, returning `none` when absent.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const maybeBus = yield* EventBus.getOption;
21
+ * ```
22
+ */
23
+ export const getOption = Effect.serviceOption(EventBus);
24
+ /** Get the EventBus from context, failing with {@link EventBusNotFoundError} if absent. */
25
+ const getOrFail = pipe(getOption, Effect.flatMap(Option.match({
26
+ onNone: () => Effect.fail(new Errors.EventBusNotFoundError({
27
+ message: 'EventBus service not provided. Use EventBus.layer or provide it manually.',
28
+ })),
29
+ onSome: (bus) => Effect.succeed(bus),
30
+ })));
31
+ /**
32
+ * Publish an event. Requires the EventBus service in context.
33
+ *
34
+ * Validates the input through the event's payload schema before publishing.
35
+ * Fails with {@link EventBusNotFoundError} if the bus is not provided,
36
+ * or with {@link SchemaParseError} if the input fails schema validation.
37
+ */
38
+ export function publish(event, input) {
39
+ return pipe(getOrFail, Effect.andThen((s) => s.publish(event, input)));
40
+ }
41
+ export function subscribe(event) {
42
+ return pipe(getOrFail, Effect.map((s) => s.subscribe(event)), Stream.unwrap);
43
+ }
44
+ //TODO: publishWith/subscribeWith static function for a pipeable approach (dual fn)
45
+ //https://effect-ts.github.io/effect/effect/Function.ts.html#dual
46
+ /**
47
+ * Non-failing variant of {@link publish}. Returns `Option.none()`
48
+ * if the EventBus is not in context, or `Option.some(result)` with
49
+ * the publish result if it is.
50
+ */
51
+ export const publishOptional = (event, input) => Effect.gen(function* () {
52
+ const eventBus = yield* getOption;
53
+ if (Option.isNone(eventBus))
54
+ return Option.none();
55
+ const result = yield* eventBus.value.publish(event, input);
56
+ return Option.some(result);
57
+ });
58
+ /**
59
+ * Non-failing variant of {@link subscribe}. Returns `Option.none()`
60
+ * if the EventBus is not in context, or `Option.some(stream)` if it is.
61
+ */
62
+ export const subscribeOptional = (event) => Effect.gen(function* () {
63
+ const eventBus = yield* getOption;
64
+ if (Option.isNone(eventBus))
65
+ return Option.none();
66
+ return Option.some(eventBus.value.subscribe(event));
67
+ });
68
+ /**
69
+ * Create an EventBus service backed by a bounded or unbounded {@link PubSub}.
70
+ *
71
+ * @param options.capacity - Max number of buffered events. If omitted, an
72
+ * unbounded queue is used (never blocks publishers).
73
+ */
74
+ export const make = (options = {}) => Effect.gen(function* () {
75
+ const bus = yield* options.capacity !== undefined
76
+ ? PubSub.bounded({ capacity: options.capacity })
77
+ : PubSub.unbounded();
78
+ return EventBus.of({
79
+ publish: (event, input) => Effect.gen(function* () {
80
+ const payload = yield* PayloadApi.parse(event.payload, input);
81
+ const envelope = EnvelopeApi.make({
82
+ event,
83
+ payload,
84
+ });
85
+ return yield* PubSub.publish(bus, envelope);
86
+ }),
87
+ subscribe: (expectedEvent) => pipe(Stream.fromPubSub(bus), Stream.filter((env) => env.event.tag === expectedEvent.tag)),
88
+ unsafePublish(event, input) {
89
+ const payload = PayloadApi.parseSync(event.payload, input);
90
+ const envelope = EnvelopeApi.make({
91
+ event,
92
+ payload,
93
+ });
94
+ return bus.unsafeOffer(envelope);
95
+ },
96
+ });
97
+ });
98
+ /**
99
+ * Create an {@link Effect.Layer} providing the EventBus service.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * const layer = EventBus.layer({ capacity: 256 });
104
+ * const program = Effect.provide(program, layer);
105
+ * ```
106
+ */
107
+ export const layer = (options = {}) => Layer.effect(EventBus, make(options));
108
+ //# sourceMappingURL=EventBus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventBus.js","sourceRoot":"","sources":["../src/EventBus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
+ import { Effect, Schema } from 'effect';
3
+ import * as Errors from './Errors.js';
4
+ /**
5
+ * Union of supported payload schema types. Accepts both Effect
6
+ * {@link Schema.Schema} and framework-agnostic {@link StandardSchemaV1}
7
+ * schemas (Zod, Valibot, ArkType, etc.).
8
+ */
9
+ export type AnyPayload = Schema.Schema.Any | StandardSchemaV1;
10
+ /**
11
+ * Extracts the inferred **output** (decoded) type from a payload schema.
12
+ *
13
+ * This is the type subscribers receive in the {@link Envelope}.
14
+ */
15
+ export type InferPayloadOutput<P extends AnyPayload> = P extends Schema.Schema.Any ? Schema.Schema.Type<P> : P extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<P> : never;
16
+ /**
17
+ * Extracts the inferred **input** (encoded) type from a payload schema.
18
+ *
19
+ * This is the type publishers provide to {@link EventBus.publish}.
20
+ */
21
+ export type InferPayloadInput<P extends AnyPayload> = P extends Schema.Schema.Any ? Schema.Schema.Encoded<P> : P extends StandardSchemaV1 ? StandardSchemaV1.InferInput<P> : never;
22
+ /**
23
+ * Validate and transform an input value through the given payload schema.
24
+ *
25
+ * Handles both Effect {@link Schema.Schema} and framework-agnostic
26
+ * {@link StandardSchemaV1} schemas at runtime.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const payload = yield* Payload.parse(Schema.DateFromString, '2024-01-01');
31
+ * // payload is Date
32
+ * ```
33
+ */
34
+ export declare const parse: <S extends AnyPayload, A extends InferPayloadOutput<S>, I>(schema: S, input: I) => Effect.Effect<A, Errors.SchemaParseError>;
35
+ /**
36
+ * Synchronous variant of {@link parse}. Throws {@link Errors.SchemaParseError}
37
+ * if validation fails.
38
+ *
39
+ * For {@link StandardSchemaV1} schemas that return asynchronous validation
40
+ * results, this throws with an explanatory error.
41
+ */
42
+ export declare const parseSync: <A>(schema: AnyPayload, input: unknown) => A;
43
+ //# sourceMappingURL=Payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Payload.d.ts","sourceRoot":"","sources":["../src/Payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,gBAAgB,CAAC;AAE9D;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,GAAG,GAC9E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GACrB,CAAC,SAAS,gBAAgB,GACxB,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,GAC/B,KAAK,CAAC;AAEZ;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,GAAG,GAC7E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GACxB,CAAC,SAAS,gBAAgB,GACxB,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,GAC9B,KAAK,CAAC;AAaZ;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,UACpE,CAAC,SACF,CAAC,KACP,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,gBAAgB,CA2CvC,CAAC;AAEL;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,UAAU,UAAU,SAAS,OAAO,KAAG,CA+BjE,CAAC"}
@@ -0,0 +1,87 @@
1
+ import { Effect, Schema } from 'effect';
2
+ import * as Errors from './Errors.js';
3
+ // ── Runtime helpers ────────────────────────────────────────────────────
4
+ const isEffectSchema = (u) => (typeof u === 'object' || typeof u === 'function') && u !== null && Schema.TypeId in u;
5
+ const isStandardSchema = (u) => typeof u === 'object' &&
6
+ u !== null &&
7
+ '~standard' in u &&
8
+ typeof u['~standard']?.validate === 'function';
9
+ /**
10
+ * Validate and transform an input value through the given payload schema.
11
+ *
12
+ * Handles both Effect {@link Schema.Schema} and framework-agnostic
13
+ * {@link StandardSchemaV1} schemas at runtime.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const payload = yield* Payload.parse(Schema.DateFromString, '2024-01-01');
18
+ * // payload is Date
19
+ * ```
20
+ */
21
+ export const parse = (schema, input) => Effect.suspend(() => {
22
+ if (isEffectSchema(schema)) {
23
+ return Schema.decodeUnknown(schema)(input).pipe(Effect.mapError((issue) => new Errors.SchemaParseError({
24
+ message: issue.message,
25
+ schema,
26
+ })));
27
+ }
28
+ if (isStandardSchema(schema)) {
29
+ const result = schema['~standard'].validate(input);
30
+ const resolved = result instanceof Promise ? result : Promise.resolve(result);
31
+ return Effect.promise(() => resolved).pipe(Effect.flatMap((r) => 'issues' in r
32
+ ? Effect.fail(new Errors.SchemaParseError({
33
+ message: r.issues?.map((i) => i.message).join(', ') ?? 'Validation failed',
34
+ schema,
35
+ }))
36
+ : Effect.succeed(r.value)));
37
+ }
38
+ const schemaDescription = schema === null
39
+ ? 'null'
40
+ : schema === undefined
41
+ ? 'undefined'
42
+ : `object with constructor ${schema.constructor?.name ?? '<unknown>'}`;
43
+ return Effect.fail(new Errors.SchemaParseError({
44
+ message: `Unrecognized schema: expected an Effect Schema, StandardSchemaV1, or similar — received ${schemaDescription}`,
45
+ schema,
46
+ }));
47
+ });
48
+ /**
49
+ * Synchronous variant of {@link parse}. Throws {@link Errors.SchemaParseError}
50
+ * if validation fails.
51
+ *
52
+ * For {@link StandardSchemaV1} schemas that return asynchronous validation
53
+ * results, this throws with an explanatory error.
54
+ */
55
+ export const parseSync = (schema, input) => {
56
+ if (isEffectSchema(schema)) {
57
+ try {
58
+ return Schema.decodeSync(schema)(input);
59
+ }
60
+ catch (e) {
61
+ throw new Errors.SchemaParseError({
62
+ message: e instanceof Error ? e.message : String(e),
63
+ schema,
64
+ });
65
+ }
66
+ }
67
+ if (isStandardSchema(schema)) {
68
+ const result = schema['~standard'].validate(input);
69
+ if (result instanceof Promise) {
70
+ throw new Errors.SchemaParseError({
71
+ message: 'StandardSchemaV1 validate returned an async result; ' +
72
+ 'use the Effect-based publish() instead of unsafePublish()',
73
+ schema,
74
+ });
75
+ }
76
+ if ('issues' in result) {
77
+ throw new Errors.SchemaParseError({
78
+ message: result.issues?.map((i) => i.message).join(', ') ?? 'Validation failed',
79
+ schema,
80
+ });
81
+ }
82
+ return result.value;
83
+ }
84
+ // Unrecognised schema type — pass through
85
+ return input;
86
+ };
87
+ //# sourceMappingURL=Payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Payload.js","sourceRoot":"","sources":["../src/Payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * as Event from './Event.js';
2
+ export * as EventBus from './EventBus.js';
3
+ export * as Envelope from './Envelope.js';
4
+ export { EventBusNotFoundError, SchemaParseError } from './Errors.js';
5
+ export type { AnyPayload, InferPayloadOutput, InferPayloadInput } from './Payload.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACtE,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * as Event from './Event.js';
2
+ export * as EventBus from './EventBus.js';
3
+ export * as Envelope from './Envelope.js';
4
+ export { EventBusNotFoundError, SchemaParseError } from './Errors.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@effect-pantry/events",
3
+ "version": "0.0.1",
4
+ "description": "Type-safe in-memory event bus for Effect-TS — branded event definitions with PubSub-backed publish/subscribe",
5
+ "keywords": [
6
+ "effect",
7
+ "event-bus",
8
+ "events",
9
+ "pubsub"
10
+ ],
11
+ "homepage": "https://github.com/nipakke/effect-pantry/tree/main/packages/events#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/nipakke/effect-pantry/issues"
14
+ },
15
+ "license": "MIT",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/nipakke/effect-pantry.git",
19
+ "directory": "packages/events"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "dependencies": {
37
+ "@standard-schema/spec": "^1.1.0",
38
+ "effect": "^3.21.2"
39
+ },
40
+ "devDependencies": {
41
+ "@effect/platform": "^0.90.10",
42
+ "@effect/vitest": "^0.29.0",
43
+ "@types/node": "^25.8.0",
44
+ "@typescript/native-preview": "7.0.0-dev.20260515.1",
45
+ "rimraf": "^6.0.1",
46
+ "vite-plus": "^0.1.21",
47
+ "vitest": "^3.2.0",
48
+ "@tooling/tsconfig": "0.0.1"
49
+ },
50
+ "engines": {
51
+ "node": ">=24"
52
+ },
53
+ "scripts": {
54
+ "clean": "rimraf dist",
55
+ "build": "pnpm clean && tsgo",
56
+ "check": "vp check",
57
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
58
+ "test": "vitest run"
59
+ }
60
+ }