@fungi.computer/bird-dog 0.0.0-stage → 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.
@@ -0,0 +1,116 @@
1
+ import type * as Schema from "effect/Schema";
2
+ import type { WatchdogQueuedJob, WatchdogSettledJob, WatchdogStoredJob } from "@fungi.computer/watchdog";
3
+ /** An ordinary agent Session address. Relationships between agents live elsewhere. */
4
+ export type BirdDogAgentReference = Readonly<{
5
+ kind: "agent";
6
+ agentId: string;
7
+ sessionId: string;
8
+ }>;
9
+ /** Addressed agent correspondence carried with durable work when a reply is owed. */
10
+ export type BirdDogMail = Readonly<{
11
+ key: string;
12
+ to: BirdDogAgentReference;
13
+ from: BirdDogAgentReference;
14
+ replyTo: readonly BirdDogAgentReference[];
15
+ content: string;
16
+ createdAt: number;
17
+ /** The sender's opaque host metadata; BirdDog never reads it. */
18
+ meta?: BirdDogMeta;
19
+ /** Settlement facts, present only on a reply BirdDog built. */
20
+ reply?: BirdDogReply;
21
+ }>;
22
+ /**
23
+ * What a reply reports about the settled work beside its content. The
24
+ * recipient's host trusts these facts only after it authenticates the reply
25
+ * against the mail it sent.
26
+ */
27
+ export type BirdDogReply = Readonly<{
28
+ /** The replying Session's accepted command: the sender's receipt `commandId`. */
29
+ commandId: string;
30
+ /** The exact Watchdog outcome; failures are never collapsed. */
31
+ outcome: "completed" | "failed" | "interrupted" | "cancelled" | "outcome_unknown";
32
+ /** Bounded terminal diagnostic for work that did not complete or cancel. */
33
+ diagnostic?: string;
34
+ }>;
35
+ /** Opaque JSON a host attached to the work; BirdDog only carries it. */
36
+ export type BirdDogMeta = typeof Schema.Json.Type;
37
+ /** The accepted Session work BirdDog points at from an opaque Watchdog job. */
38
+ export type BirdDogAgentWork = Readonly<{
39
+ jobId: string;
40
+ sessionId: string;
41
+ commandFactId: string;
42
+ recovery?: Readonly<{
43
+ maxRecoveries: number;
44
+ }> | undefined;
45
+ }>;
46
+ /** Typed payload whose meaning belongs to BirdDog, never Watchdog. */
47
+ export type BirdDogAgentJobPayload = Readonly<{
48
+ work: Readonly<{
49
+ sessionId: string;
50
+ commandFactId: string;
51
+ }>;
52
+ mail?: BirdDogMail | undefined;
53
+ }>;
54
+ /** Input for projecting accepted agent work into Watchdog's generic grammar. */
55
+ export type BirdDogAgentJobInput = Readonly<{
56
+ work: BirdDogAgentWork;
57
+ mail?: BirdDogMail | undefined;
58
+ }>;
59
+ /** String-backed durable outbox owned by the BirdDog host. */
60
+ export type BirdDogOutbox = Readonly<{
61
+ /** Store one encoded mail row under its durable key. */
62
+ put: (key: string, value: string) => Promise<void>;
63
+ /** Read one encoded mail row, if it exists. */
64
+ read: (key: string) => Promise<string | undefined>;
65
+ /** Read an ordered page of encoded mail rows. */
66
+ list: (limit: number, afterKey?: string) => Promise<readonly Readonly<{
67
+ key: string;
68
+ value: string;
69
+ }>[]>;
70
+ /** Remove an invalid encoded row; completed deliveries retain receipts. */
71
+ delete: (key: string) => Promise<void>;
72
+ }>;
73
+ /** Host ports for BirdDog's durable mail delivery. */
74
+ export type BirdDogOptions = Readonly<{
75
+ /** Durable store for pending reply mail. */
76
+ outbox: BirdDogOutbox;
77
+ /** Deliver one reply mail and report whether it was accepted. */
78
+ post: (mail: BirdDogMail) => Promise<boolean>;
79
+ /** Arrange a future wake for pending delivery work. */
80
+ scheduleWake: (at: number) => Promise<void>;
81
+ /** Return the host's current wall-clock time in milliseconds. */
82
+ now: () => number;
83
+ }>;
84
+ /** Completed generic work plus the content owed to its correspondents. */
85
+ export type BirdDogSettlement = Readonly<{
86
+ job: WatchdogSettledJob;
87
+ content: string;
88
+ /**
89
+ * The Session's recorded terminal diagnostic. Replies carry it, bounded by
90
+ * `boundedDiagnostic`, only for failed, interrupted and outcome_unknown work.
91
+ */
92
+ diagnostic?: string;
93
+ /**
94
+ * The settled work's host metadata, for the host's own fan-out wrapper (for
95
+ * example, naming who cancelled). Replies never carry it.
96
+ */
97
+ meta?: BirdDogMeta;
98
+ }>;
99
+ /** Durable reply delivery behind the mail-room interface. */
100
+ export type BirdDogRuntime = Readonly<{
101
+ /** Queue replies owed by a settled agent job. */
102
+ fanOut: (settlement: BirdDogSettlement) => Promise<void>;
103
+ /** Deliver due replies and schedule any required retry wake. */
104
+ drainOutbox: () => Promise<void>;
105
+ }>;
106
+ /** BirdDog's small synchronous translation interface for owner transactions. */
107
+ export type BirdDogApi = Readonly<{
108
+ /** Validate and translate accepted agent work into one opaque Watchdog job. */
109
+ agentJob: (input: BirdDogAgentJobInput) => WatchdogQueuedJob;
110
+ /** Decode one generic Watchdog job into BirdDog-owned agent work. */
111
+ decodeAgentJob: (job: WatchdogStoredJob) => BirdDogAgentJobPayload;
112
+ /** Construct the durable reply mail room. */
113
+ make: (options: BirdDogOptions) => Promise<BirdDogRuntime>;
114
+ }>;
115
+ /** Agent-aware mail translation over Watchdog's payload-blind job grammar. */
116
+ export declare const BirdDog: BirdDogApi;
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { agentJobFromInput, decodeAgentJob } from "./effect.js";
2
+ import { createPromiseBirdDog } from "./internal/promise-mail-room.js";
3
+ /** Agent-aware mail translation over Watchdog's payload-blind job grammar. */
4
+ export const BirdDog = Object.freeze({
5
+ agentJob: agentJobFromInput,
6
+ decodeAgentJob,
7
+ make: createPromiseBirdDog,
8
+ });
@@ -0,0 +1,3 @@
1
+ import type { BirdDogApi } from "../index.js";
2
+ /** Lift Promise host ports once into BirdDog's Effect-owned mail room. */
3
+ export declare const createPromiseBirdDog: BirdDogApi["make"];
@@ -0,0 +1,51 @@
1
+ import * as Cause from "effect/Cause";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Exit from "effect/Exit";
4
+ import * as Option from "effect/Option";
5
+ import { BirdDogError, make } from "../effect.js";
6
+ const runPromise = (effect) => Effect.runPromiseExit(effect).then((exit) => {
7
+ if (Exit.isSuccess(exit))
8
+ return exit.value;
9
+ const failure = Option.getOrUndefined(Cause.findErrorOption(exit.cause));
10
+ return Promise.reject(failure instanceof Error ? failure : new BirdDogError("mail room failed"));
11
+ });
12
+ /** Lift Promise host ports once into BirdDog's Effect-owned mail room. */
13
+ export const createPromiseBirdDog = async (options) => {
14
+ const readOutbox = options.outbox.read;
15
+ const readPort = {
16
+ read: (key) => Effect.tryPromise({
17
+ try: () => readOutbox(key),
18
+ catch: (cause) => new BirdDogError("outbox read failed", { cause }),
19
+ }),
20
+ };
21
+ const runtime = await Effect.runPromise(make({
22
+ outbox: {
23
+ ...readPort,
24
+ put: (key, value) => Effect.tryPromise({
25
+ try: () => options.outbox.put(key, value),
26
+ catch: (cause) => new BirdDogError("outbox write failed", { cause }),
27
+ }),
28
+ list: (limit, afterKey) => Effect.tryPromise({
29
+ try: () => options.outbox.list(limit, afterKey),
30
+ catch: (cause) => new BirdDogError("outbox read failed", { cause }),
31
+ }),
32
+ delete: (key) => Effect.tryPromise({
33
+ try: () => options.outbox.delete(key),
34
+ catch: (cause) => new BirdDogError("outbox delete failed", { cause }),
35
+ }),
36
+ },
37
+ post: (mail) => Effect.tryPromise({
38
+ try: () => options.post(mail),
39
+ catch: (cause) => new BirdDogError("mail transport failed", { cause }),
40
+ }),
41
+ scheduleWake: (at) => Effect.tryPromise({
42
+ try: () => options.scheduleWake(at),
43
+ catch: (cause) => new BirdDogError("wake scheduling failed", { cause }),
44
+ }),
45
+ now: options.now,
46
+ }));
47
+ return Object.freeze({
48
+ fanOut: (settlement) => runPromise(runtime.fanOut(settlement)),
49
+ drainOutbox: () => runPromise(runtime.drainOutbox()),
50
+ });
51
+ };
@@ -0,0 +1,14 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ **@fungi.computer/bird-dog**
4
+
5
+ ---
6
+
7
+ # @fungi.computer/bird-dog
8
+
9
+ ## Modules
10
+
11
+ | Module | Description |
12
+ | ------------------- | ----------- |
13
+ | [effect](effect.md) | - |
14
+ | [index](index.md) | - |
@@ -0,0 +1,481 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/bird-dog**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/bird-dog](README.md) / effect
8
+
9
+ # effect
10
+
11
+ ## Classes
12
+
13
+ ### BirdDogError
14
+
15
+ BirdDog could not complete one owned store or transport operation.
16
+
17
+ #### Extends
18
+
19
+ - `Error`
20
+
21
+ #### Constructors
22
+
23
+ ##### Constructor
24
+
25
+ ```ts
26
+ new BirdDogError(message, options?): BirdDogError;
27
+ ```
28
+
29
+ ###### Parameters
30
+
31
+ | Parameter | Type |
32
+ | ---------- | -------------- |
33
+ | `message` | `string` |
34
+ | `options?` | `ErrorOptions` |
35
+
36
+ ###### Returns
37
+
38
+ [`BirdDogError`](#birddogerror)
39
+
40
+ ###### Overrides
41
+
42
+ ```ts
43
+ Error.constructor;
44
+ ```
45
+
46
+ #### Properties
47
+
48
+ ##### \_tag
49
+
50
+ ```ts
51
+ readonly _tag: "BirdDogError";
52
+ ```
53
+
54
+ Stable discriminator for BirdDog-owned effect failures.
55
+
56
+ ## Type Aliases
57
+
58
+ ### EffectBirdDogOptions
59
+
60
+ ```ts
61
+ type EffectBirdDogOptions = Readonly<{
62
+ outbox: Readonly<{
63
+ put: (key, value) => Effect.Effect<void, BirdDogError>;
64
+ read: (key) => Effect.Effect<string | undefined, BirdDogError>;
65
+ list: (
66
+ limit,
67
+ afterKey?,
68
+ ) => Effect.Effect<
69
+ readonly Readonly<{
70
+ key: string;
71
+ value: string;
72
+ }>[],
73
+ BirdDogError
74
+ >;
75
+ delete: (key) => Effect.Effect<void, BirdDogError>;
76
+ }>;
77
+ post: (mail) => Effect.Effect<boolean, BirdDogError>;
78
+ scheduleWake: (at) => Effect.Effect<void, BirdDogError>;
79
+ now: () => number;
80
+ }>;
81
+ ```
82
+
83
+ Effect host ports for the durable mail room.
84
+
85
+ ---
86
+
87
+ ### BirdDogEffect
88
+
89
+ ```ts
90
+ type BirdDogEffect = Readonly<{
91
+ fanOut: (settlement) => Effect.Effect<void, BirdDogError>;
92
+ drainOutbox: () => Effect.Effect<void, BirdDogError>;
93
+ }>;
94
+ ```
95
+
96
+ Effect-native durable reply delivery.
97
+
98
+ ## Variables
99
+
100
+ ### BirdDogAgentReferenceSchema
101
+
102
+ ```ts
103
+ const BirdDogAgentReferenceSchema: Struct<{
104
+ kind: Literal<"agent">;
105
+ agentId: String;
106
+ sessionId: String;
107
+ }>;
108
+ ```
109
+
110
+ Parser for an ordinary agent Session address.
111
+
112
+ ---
113
+
114
+ ### BIRD\_DOG\_DIAGNOSTIC\_MAX\_LENGTH
115
+
116
+ ```ts
117
+ const BIRD_DOG_DIAGNOSTIC_MAX_LENGTH: 200 = 200;
118
+ ```
119
+
120
+ The most characters a reply's failure diagnostic may carry.
121
+
122
+ ---
123
+
124
+ ### BirdDogReplySchema
125
+
126
+ ```ts
127
+ const BirdDogReplySchema: Struct<{
128
+ commandId: String;
129
+ outcome: Literals<
130
+ readonly [
131
+ "completed",
132
+ "failed",
133
+ "interrupted",
134
+ "cancelled",
135
+ "outcome_unknown",
136
+ ]
137
+ >;
138
+ diagnostic: optionalKey<String>;
139
+ }>;
140
+ ```
141
+
142
+ Parser for the settlement facts a reply carries beside its content: the replying
143
+ Session's command, its exact Watchdog outcome and, for work that did not
144
+ complete, the Session's bounded terminal diagnostic.
145
+
146
+ ---
147
+
148
+ ### BirdDogMailSchema
149
+
150
+ ```ts
151
+ const BirdDogMailSchema: Struct<{
152
+ key: String;
153
+ to: Struct<{
154
+ kind: Literal<"agent">;
155
+ agentId: String;
156
+ sessionId: String;
157
+ }>;
158
+ from: Struct<{
159
+ kind: Literal<"agent">;
160
+ agentId: String;
161
+ sessionId: String;
162
+ }>;
163
+ replyTo: $Array<
164
+ Struct<{
165
+ kind: Literal<"agent">;
166
+ agentId: String;
167
+ sessionId: String;
168
+ }>
169
+ >;
170
+ content: String;
171
+ createdAt: Number;
172
+ meta: optionalKey<Codec<Json, Json, never, never>>;
173
+ reply: optionalKey<
174
+ Struct<{
175
+ commandId: String;
176
+ outcome: Literals<
177
+ readonly [
178
+ "completed",
179
+ "failed",
180
+ "interrupted",
181
+ "cancelled",
182
+ "outcome_unknown",
183
+ ]
184
+ >;
185
+ diagnostic: optionalKey<String>;
186
+ }>
187
+ >;
188
+ }>;
189
+ ```
190
+
191
+ Parser for addressed agent correspondence.
192
+
193
+ ---
194
+
195
+ ### BirdDogAgentWorkSchema
196
+
197
+ ```ts
198
+ const BirdDogAgentWorkSchema: Struct<{
199
+ jobId: String;
200
+ sessionId: String;
201
+ commandFactId: String;
202
+ recovery: optional<
203
+ Struct<{
204
+ maxRecoveries: Int;
205
+ }>
206
+ >;
207
+ }>;
208
+ ```
209
+
210
+ Parser for accepted Session work.
211
+
212
+ ---
213
+
214
+ ### BirdDogAgentJobPayloadSchema
215
+
216
+ ```ts
217
+ const BirdDogAgentJobPayloadSchema: Struct<{
218
+ work: Struct<{
219
+ sessionId: String;
220
+ commandFactId: String;
221
+ }>;
222
+ mail: optional<
223
+ Struct<{
224
+ key: String;
225
+ to: Struct<{
226
+ kind: Literal<"agent">;
227
+ agentId: String;
228
+ sessionId: String;
229
+ }>;
230
+ from: Struct<{
231
+ kind: Literal<"agent">;
232
+ agentId: String;
233
+ sessionId: String;
234
+ }>;
235
+ replyTo: $Array<
236
+ Struct<{
237
+ kind: Literal<"agent">;
238
+ agentId: String;
239
+ sessionId: String;
240
+ }>
241
+ >;
242
+ content: String;
243
+ createdAt: Number;
244
+ meta: optionalKey<Codec<Json, Json, never, never>>;
245
+ reply: optionalKey<
246
+ Struct<{
247
+ commandId: String;
248
+ outcome: Literals<
249
+ readonly [
250
+ "completed",
251
+ "failed",
252
+ "interrupted",
253
+ "cancelled",
254
+ "outcome_unknown",
255
+ ]
256
+ >;
257
+ diagnostic: optionalKey<String>;
258
+ }>
259
+ >;
260
+ }>
261
+ >;
262
+ }>;
263
+ ```
264
+
265
+ Parser for the payload that Watchdog stores without interpretation.
266
+
267
+ ---
268
+
269
+ ### BirdDogAgentJobInputSchema
270
+
271
+ ```ts
272
+ const BirdDogAgentJobInputSchema: Struct<{
273
+ work: Struct<{
274
+ jobId: String;
275
+ sessionId: String;
276
+ commandFactId: String;
277
+ recovery: optional<
278
+ Struct<{
279
+ maxRecoveries: Int;
280
+ }>
281
+ >;
282
+ }>;
283
+ mail: optional<
284
+ Struct<{
285
+ key: String;
286
+ to: Struct<{
287
+ kind: Literal<"agent">;
288
+ agentId: String;
289
+ sessionId: String;
290
+ }>;
291
+ from: Struct<{
292
+ kind: Literal<"agent">;
293
+ agentId: String;
294
+ sessionId: String;
295
+ }>;
296
+ replyTo: $Array<
297
+ Struct<{
298
+ kind: Literal<"agent">;
299
+ agentId: String;
300
+ sessionId: String;
301
+ }>
302
+ >;
303
+ content: String;
304
+ createdAt: Number;
305
+ meta: optionalKey<Codec<Json, Json, never, never>>;
306
+ reply: optionalKey<
307
+ Struct<{
308
+ commandId: String;
309
+ outcome: Literals<
310
+ readonly [
311
+ "completed",
312
+ "failed",
313
+ "interrupted",
314
+ "cancelled",
315
+ "outcome_unknown",
316
+ ]
317
+ >;
318
+ diagnostic: optionalKey<String>;
319
+ }>
320
+ >;
321
+ }>
322
+ >;
323
+ }>;
324
+ ```
325
+
326
+ Parser for accepted work entering BirdDog's transactional projection.
327
+
328
+ ## Functions
329
+
330
+ ### boundedDiagnostic()
331
+
332
+ ```ts
333
+ function boundedDiagnostic(text): string | undefined;
334
+ ```
335
+
336
+ One secret-safe line of at most `BIRD_DOG_DIAGNOSTIC_MAX_LENGTH` characters from
337
+ a Session's terminal diagnostic, or nothing when it is blank. Control characters
338
+ and line breaks become single spaces, so the text cannot shape the reply around
339
+ it, and credential-shaped values are masked before the line is cut, so a cut
340
+ never exposes part of one.
341
+
342
+ #### Parameters
343
+
344
+ | Parameter | Type |
345
+ | --------- | -------- |
346
+ | `text` | `string` |
347
+
348
+ #### Returns
349
+
350
+ `string` \| `undefined`
351
+
352
+ ---
353
+
354
+ ### agentJobFromInput()
355
+
356
+ ```ts
357
+ function agentJobFromInput(input): object;
358
+ ```
359
+
360
+ Validate and translate agent work into Watchdog's opaque job grammar.
361
+
362
+ #### Parameters
363
+
364
+ | Parameter | Type |
365
+ | --------- | ------------------------------------------------------- |
366
+ | `input` | [`BirdDogAgentJobInput`](index.md#birddogagentjobinput) |
367
+
368
+ #### Returns
369
+
370
+ `object`
371
+
372
+ | Name | Type |
373
+ | ------------------------ | ---------- |
374
+ | `state` | `"queued"` |
375
+ | `jobId` | `string` |
376
+ | `queue` | `string` |
377
+ | `lane` | `string` |
378
+ | `priority` | `number` |
379
+ | `payload` | `unknown` |
380
+ | `recovery?` | `object` |
381
+ | `recovery.maxRecoveries` | `number` |
382
+
383
+ ---
384
+
385
+ ### decodeAgentJob()
386
+
387
+ ```ts
388
+ function decodeAgentJob(job): BirdDogAgentJobPayload;
389
+ ```
390
+
391
+ Decode the opaque payload at BirdDog's side of the Watchdog seam.
392
+
393
+ #### Parameters
394
+
395
+ | Parameter | Type |
396
+ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
397
+ | `job` | \| \{ `state`: `"queued"`; `jobId`: `string`; `queue`: `string`; `lane`: `string`; `priority`: `number`; `payload`: `unknown`; `recovery?`: \{ `maxRecoveries`: `number`; \}; \} \| \{ `state`: `"running"`; `jobId`: `string`; `queue`: `string`; `lane`: `string`; `priority`: `number`; `payload`: `unknown`; `recovery?`: \{ `maxRecoveries`: `number`; \}; \} \| \{ `state`: `"settled"`; `outcome`: `"failed"` \| `"completed"` \| `"interrupted"` \| `"cancelled"` \| `"outcome_unknown"`; `failureReason?`: `string`; `jobId`: `string`; `queue`: `string`; `lane`: `string`; `priority`: `number`; `payload`: `unknown`; `recovery?`: \{ `maxRecoveries`: `number`; \}; \} |
398
+
399
+ #### Returns
400
+
401
+ [`BirdDogAgentJobPayload`](index.md#birddogagentjobpayload)
402
+
403
+ ---
404
+
405
+ ### settlementReplies()
406
+
407
+ ```ts
408
+ function settlementReplies(
409
+ settlement,
410
+ createdAt,
411
+ ): readonly Readonly<{
412
+ key: string;
413
+ to: BirdDogAgentReference;
414
+ from: BirdDogAgentReference;
415
+ replyTo: readonly Readonly<{
416
+ kind: "agent";
417
+ agentId: string;
418
+ sessionId: string;
419
+ }>[];
420
+ content: string;
421
+ createdAt: number;
422
+ meta?: Json;
423
+ reply?: Readonly<{
424
+ commandId: string;
425
+ outcome:
426
+ "failed" | "completed" | "interrupted" | "cancelled" | "outcome_unknown";
427
+ diagnostic?: string;
428
+ }>;
429
+ }>[];
430
+ ```
431
+
432
+ Build the replies owed by one settlement for a host-owned Post transport. Each
433
+ reply carries the settled content verbatim (or, when there is none, one sentence
434
+ naming the outcome, so the reply is always admissible text) and its settlement
435
+ facts as typed fields; the recipient's host authenticates them and decides how
436
+ they are presented. A reply never carries the settled work's host metadata.
437
+
438
+ #### Parameters
439
+
440
+ | Parameter | Type |
441
+ | ------------ | ------------------------------------------------- |
442
+ | `settlement` | [`BirdDogSettlement`](index.md#birddogsettlement) |
443
+ | `createdAt` | `number` |
444
+
445
+ #### Returns
446
+
447
+ readonly `Readonly`\<\{ `key`: `string`; `to`:
448
+ [`BirdDogAgentReference`](index.md#birddogagentreference); `from`:
449
+ [`BirdDogAgentReference`](index.md#birddogagentreference); `replyTo`: readonly
450
+ `Readonly`\<\{ `kind`: `"agent"`; `agentId`: `string`; `sessionId`: `string`;
451
+ \}\>[]; `content`: `string`; `createdAt`: `number`; `meta?`: `Json`; `reply?`:
452
+ `Readonly`\<\{ `commandId`: `string`; `outcome`: `"failed"` \| `"completed"` \|
453
+ `"interrupted"` \| `"cancelled"` \| `"outcome_unknown"`; `diagnostic?`:
454
+ `string`; \}\>; \}\>[]
455
+
456
+ ---
457
+
458
+ ### make()
459
+
460
+ ```ts
461
+ function make(options): Effect<
462
+ Readonly<{
463
+ fanOut: (settlement) => Effect<void, BirdDogError>;
464
+ drainOutbox: () => Effect<void, BirdDogError>;
465
+ }>
466
+ >;
467
+ ```
468
+
469
+ Construct BirdDog's Effect-native mail room over Post's shared outbox.
470
+
471
+ #### Parameters
472
+
473
+ | Parameter | Type |
474
+ | --------- | ----------------------------------------------- |
475
+ | `options` | [`EffectBirdDogOptions`](#effectbirddogoptions) |
476
+
477
+ #### Returns
478
+
479
+ `Effect`\<`Readonly`\<\{ `fanOut`: (`settlement`) => `Effect`\<`void`,
480
+ [`BirdDogError`](#birddogerror)\>; `drainOutbox`: () => `Effect`\<`void`,
481
+ [`BirdDogError`](#birddogerror)\>; \}\>\>