@fungi.computer/carrier 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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +457 -2
  3. package/dist/cloudflare.d.ts +32 -0
  4. package/dist/cloudflare.js +80 -0
  5. package/dist/email.d.ts +2 -0
  6. package/dist/email.js +2 -0
  7. package/dist/index.d.ts +21 -0
  8. package/dist/index.js +28 -0
  9. package/dist/inspection.d.ts +108 -0
  10. package/dist/inspection.js +188 -0
  11. package/dist/internal/cloudflare-send.d.ts +9 -0
  12. package/dist/internal/cloudflare-send.js +79 -0
  13. package/dist/internal/contracts.d.ts +94 -0
  14. package/dist/internal/contracts.js +7 -0
  15. package/dist/internal/owner.d.ts +24 -0
  16. package/dist/internal/owner.js +419 -0
  17. package/dist/internal/policy.d.ts +25 -0
  18. package/dist/internal/policy.js +18 -0
  19. package/dist/internal/post-contract.d.ts +27 -0
  20. package/dist/internal/post-contract.js +22 -0
  21. package/dist/internal/post-execution.d.ts +45 -0
  22. package/dist/internal/post-execution.js +73 -0
  23. package/dist/internal/post-sql.d.ts +51 -0
  24. package/dist/internal/post-sql.js +255 -0
  25. package/dist/internal/receipt-schema.d.ts +3 -0
  26. package/dist/internal/receipt-schema.js +12 -0
  27. package/dist/post-d1.d.ts +36 -0
  28. package/dist/post-d1.js +55 -0
  29. package/dist/post-outbox.d.ts +40 -0
  30. package/dist/post-outbox.js +99 -0
  31. package/dist/post-postgres.d.ts +25 -0
  32. package/dist/post-postgres.js +79 -0
  33. package/dist/post.d.ts +189 -0
  34. package/dist/post.js +436 -0
  35. package/dist/testing.d.ts +16 -0
  36. package/dist/testing.js +20 -0
  37. package/docs/api/README.md +20 -0
  38. package/docs/api/cloudflare.md +100 -0
  39. package/docs/api/email.md +87 -0
  40. package/docs/api/index.md +343 -0
  41. package/docs/api/inspection.md +281 -0
  42. package/docs/api/post-d1.md +184 -0
  43. package/docs/api/post-postgres.md +108 -0
  44. package/docs/api/post.md +620 -0
  45. package/docs/api/testing.md +46 -0
  46. package/package.json +94 -3
@@ -0,0 +1,100 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/carrier**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/carrier](README.md) / cloudflare
8
+
9
+ # cloudflare
10
+
11
+ ## Type Aliases
12
+
13
+ ### CloudflareCarrierStorage
14
+
15
+ ```ts
16
+ type CloudflareCarrierStorage = WatchdogSqliteOwner &
17
+ Pick<
18
+ DurableObjectStorage,
19
+ "transaction" | "getAlarm" | "setAlarm" | "deleteAlarm"
20
+ >;
21
+ ```
22
+
23
+ Native SQLite and alarms; the Cloudflare adapter owns their atomic composition.
24
+
25
+ ---
26
+
27
+ ### CloudflareCarrierOptions
28
+
29
+ ```ts
30
+ type CloudflareCarrierOptions = Readonly<{
31
+ storage: CloudflareCarrierStorage;
32
+ canSend?: (emailId) => Promise<boolean>;
33
+ }> &
34
+ | Readonly<{
35
+ email: SendEmail;
36
+ transport?: never;
37
+ }>
38
+ | Readonly<{
39
+ transport: Options["transport"];
40
+ email?: never;
41
+ }>;
42
+ ```
43
+
44
+ Native storage/wake composition with exactly one provider capability.
45
+
46
+ ---
47
+
48
+ ### CloudflareCarrier
49
+
50
+ ```ts
51
+ type CloudflareCarrier = Pick<Carrier, "send" | "get"> &
52
+ Readonly<{
53
+ alarm: () => Promise<void>;
54
+ }>;
55
+ ```
56
+
57
+ Ordinary submission operations and the native Durable Object alarm door.
58
+
59
+ ## Functions
60
+
61
+ ### createCloudflareCarrier()
62
+
63
+ ```ts
64
+ function createCloudflareCarrier(options): Promise<CloudflareCarrier>;
65
+ ```
66
+
67
+ Construct one owner per Durable Object. Forward its native alarm to `alarm`.
68
+ Acceptance commits the Email, recipient Messages, Watchdog job and wake
69
+ together.
70
+
71
+ #### Parameters
72
+
73
+ | Parameter | Type |
74
+ | --------- | ------------------------------------------------------- |
75
+ | `options` | [`CloudflareCarrierOptions`](#cloudflarecarrieroptions) |
76
+
77
+ #### Returns
78
+
79
+ `Promise`\<[`CloudflareCarrier`](#cloudflarecarrier)\>
80
+
81
+ ---
82
+
83
+ ### cloudflareEmailTransport()
84
+
85
+ ```ts
86
+ function cloudflareEmailTransport(binding): (email) => Promise<SendEvidence>;
87
+ ```
88
+
89
+ The native binding as a Carrier transport. Exported so a host that holds the
90
+ binding elsewhere (the Hub's Cloudflare edge) classifies sends identically.
91
+
92
+ #### Parameters
93
+
94
+ | Parameter | Type |
95
+ | --------- | ----------- |
96
+ | `binding` | `SendEmail` |
97
+
98
+ #### Returns
99
+
100
+ (`email`) => `Promise`\<[`SendEvidence`](index.md#sendevidence)\>
@@ -0,0 +1,87 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/carrier**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/carrier](README.md) / email
8
+
9
+ # email
10
+
11
+ ## References
12
+
13
+ ### CarrierError
14
+
15
+ Re-exports [CarrierError](index.md#carriererror)
16
+
17
+ ---
18
+
19
+ ### CarrierStatusSchema
20
+
21
+ Re-exports [CarrierStatusSchema](index.md#carrierstatusschema)
22
+
23
+ ---
24
+
25
+ ### Address
26
+
27
+ Re-exports [Address](index.md#address)
28
+
29
+ ---
30
+
31
+ ### Email
32
+
33
+ Re-exports [Email](index.md#email)
34
+
35
+ ---
36
+
37
+ ### Host
38
+
39
+ Re-exports [Host](index.md#host)
40
+
41
+ ---
42
+
43
+ ### Message
44
+
45
+ Re-exports [Message](index.md#message)
46
+
47
+ ---
48
+
49
+ ### Options
50
+
51
+ Re-exports [Options](index.md#options)
52
+
53
+ ---
54
+
55
+ ### ProviderRejection
56
+
57
+ Re-exports [ProviderRejection](index.md#providerrejection)
58
+
59
+ ---
60
+
61
+ ### Receipt
62
+
63
+ Re-exports [Receipt](index.md#receipt)
64
+
65
+ ---
66
+
67
+ ### SendEvidence
68
+
69
+ Re-exports [SendEvidence](index.md#sendevidence)
70
+
71
+ ---
72
+
73
+ ### Submission
74
+
75
+ Re-exports [Submission](index.md#submission)
76
+
77
+ ---
78
+
79
+ ### Carrier
80
+
81
+ Re-exports [Carrier](index.md#carrier)
82
+
83
+ ---
84
+
85
+ ### createCarrier
86
+
87
+ Re-exports [createCarrier](index.md#createcarrier)
@@ -0,0 +1,343 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/carrier**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/carrier](README.md) / index
8
+
9
+ # index
10
+
11
+ ## Classes
12
+
13
+ ### CarrierError
14
+
15
+ Stable failures omit email bodies, tokens and raw provider errors.
16
+
17
+ #### Extends
18
+
19
+ - `YieldableError`\<`this`\> & `object` & `Readonly`\<\{ `code`: `"conflict"` \|
20
+ `"invalid_input"` \| `"unavailable"`; `message`: `string`; \}\>
21
+
22
+ #### Constructors
23
+
24
+ ##### Constructor
25
+
26
+ ```ts
27
+ new CarrierError(code): CarrierError;
28
+ ```
29
+
30
+ ###### Parameters
31
+
32
+ | Parameter | Type |
33
+ | --------- | ---------------------------------------------------- |
34
+ | `code` | `"conflict"` \| `"invalid_input"` \| `"unavailable"` |
35
+
36
+ ###### Returns
37
+
38
+ [`CarrierError`](#carriererror)
39
+
40
+ ###### Overrides
41
+
42
+ ```ts
43
+ Data.TaggedError("CarrierError")<{
44
+ readonly code: "invalid_input" | "conflict" | "unavailable";
45
+ readonly message: string;
46
+ }>.constructor
47
+ ```
48
+
49
+ #### Properties
50
+
51
+ ##### code
52
+
53
+ ```ts
54
+ readonly code: "conflict" | "invalid_input" | "unavailable";
55
+ ```
56
+
57
+ ###### Inherited from
58
+
59
+ ```ts
60
+ Data.TaggedError("CarrierError").code;
61
+ ```
62
+
63
+ ##### message
64
+
65
+ ```ts
66
+ message: string;
67
+ ```
68
+
69
+ ###### Inherited from
70
+
71
+ ```ts
72
+ Data.TaggedError("CarrierError").message;
73
+ ```
74
+
75
+ ## Type Aliases
76
+
77
+ ### Carrier
78
+
79
+ ```ts
80
+ type Carrier = Readonly<{
81
+ send: (submission) => Promise<Receipt>;
82
+ get: (id) => Promise<Receipt | undefined>;
83
+ tick: () => Promise<void>;
84
+ hasPendingWork: () => Promise<boolean>;
85
+ }>;
86
+ ```
87
+
88
+ Durable email submission and its host-driven recovery door.
89
+
90
+ ---
91
+
92
+ ### Address
93
+
94
+ ```ts
95
+ type Address =
96
+ | string
97
+ | Readonly<{
98
+ email: string;
99
+ name: string;
100
+ }>;
101
+ ```
102
+
103
+ One recipient address; display names remain part of the requested envelope.
104
+
105
+ ---
106
+
107
+ ### Email
108
+
109
+ ```ts
110
+ type Email = Readonly<{
111
+ from: Address;
112
+ to?: readonly Address[];
113
+ cc?: readonly Address[];
114
+ bcc?: readonly Address[];
115
+ subject: string;
116
+ html?: string;
117
+ text?: string;
118
+ headers?: Readonly<Record<string, string>>;
119
+ }>;
120
+ ```
121
+
122
+ Common content and envelope for one Email.
123
+
124
+ ---
125
+
126
+ ### Submission
127
+
128
+ ```ts
129
+ type Submission = Email &
130
+ Readonly<{
131
+ id: string;
132
+ sendBefore?: number;
133
+ }>;
134
+ ```
135
+
136
+ Source identity and expiry belong to the notification's producer.
137
+
138
+ ---
139
+
140
+ ### Message
141
+
142
+ ```ts
143
+ type Message = Readonly<{
144
+ id: string;
145
+ recipient: string;
146
+ roles: readonly ("to" | "cc" | "bcc")[];
147
+ status: "unconfirmed";
148
+ }>;
149
+ ```
150
+
151
+ A recipient Message is distinct from its Email and provider request.
152
+
153
+ ---
154
+
155
+ ### ProviderRejection
156
+
157
+ ```ts
158
+ type ProviderRejection = Readonly<{
159
+ code: string;
160
+ class: "permanent" | "temporary";
161
+ }>;
162
+ ```
163
+
164
+ A provider's definite refusal of a whole request: retryable or final.
165
+
166
+ ---
167
+
168
+ ### Receipt
169
+
170
+ ```ts
171
+ type Receipt = Readonly<{
172
+ id: string;
173
+ status: Schema.Schema.Type<typeof CarrierStatusSchema>;
174
+ providerMessageId?: string;
175
+ providerRejection?: ProviderRejection;
176
+ messages: readonly Message[];
177
+ }>;
178
+ ```
179
+
180
+ Durable submission and aggregate dispatch evidence, without credential content.
181
+ `refused` means Carrier's per-recipient cap declined the submission before any
182
+ provider attempt; `rejected` means the provider definitely refused it (a
183
+ permanent rejection, or temporary rejections until retries ran out).
184
+ `providerRejection` is the last provider refusal, also while a temporary
185
+ rejection waits `queued` for its retry.
186
+
187
+ ---
188
+
189
+ ### SendEvidence
190
+
191
+ ```ts
192
+ type SendEvidence =
193
+ | Readonly<{
194
+ kind: "provider_accepted";
195
+ providerMessageId: string;
196
+ }>
197
+ | (Readonly<{
198
+ kind: "provider_rejected";
199
+ }> &
200
+ ProviderRejection)
201
+ | Readonly<{
202
+ kind: "outcome_unknown";
203
+ cause?: string;
204
+ }>;
205
+ ```
206
+
207
+ One transport invocation reports only the evidence it obtained. Report
208
+ `provider_rejected` only for a documented refusal of the whole request before
209
+ acceptance; `cause` is an optional sanitized provider code for logs.
210
+
211
+ ---
212
+
213
+ ### Host
214
+
215
+ ```ts
216
+ type Host = Readonly<{
217
+ commit: <A>(mutation) => Promise<A>;
218
+ requestWake: () => Promise<void>;
219
+ }>;
220
+ ```
221
+
222
+ Mechanical host capabilities; commit must durably arm a wake with its mutation.
223
+
224
+ ---
225
+
226
+ ### Options
227
+
228
+ ```ts
229
+ type Options = Readonly<{
230
+ storage: WatchdogSqliteOwner;
231
+ host: Host;
232
+ now: () => number;
233
+ canSend?: (emailId) => Promise<boolean>;
234
+ transport: (email) => Promise<SendEvidence>;
235
+ }>;
236
+ ```
237
+
238
+ Configure a durable owner; business validity remains with the source.
239
+
240
+ ## Variables
241
+
242
+ ### CarrierStatusSchema
243
+
244
+ ```ts
245
+ const CarrierStatusSchema: Literals<
246
+ readonly [
247
+ "queued",
248
+ "dispatching",
249
+ "provider_accepted",
250
+ "outcome_unknown",
251
+ "rejected",
252
+ "refused",
253
+ "expired",
254
+ "superseded",
255
+ ]
256
+ >;
257
+ ```
258
+
259
+ Carrier's aggregate dispatch states at both storage and read boundaries.
260
+
261
+ ## Functions
262
+
263
+ ### createCarrier()
264
+
265
+ ```ts
266
+ function createCarrier(options): Promise<Readonly<{
267
+ send: (submission) => Promise<Readonly<{
268
+ id: string;
269
+ status: | "expired"
270
+ | "rejected"
271
+ | "queued"
272
+ | "outcome_unknown"
273
+ | "dispatching"
274
+ | "provider_accepted"
275
+ | "refused"
276
+ | "superseded";
277
+ providerMessageId?: string;
278
+ providerRejection?: Readonly<{
279
+ code: string;
280
+ class: ... | ...;
281
+ }>;
282
+ messages: readonly Readonly<{
283
+ id: string;
284
+ recipient: string;
285
+ roles: readonly ...[];
286
+ status: "unconfirmed";
287
+ }>[];
288
+ }>>;
289
+ get: (id) => Promise<
290
+ | Readonly<{
291
+ id: string;
292
+ status: | "expired"
293
+ | "rejected"
294
+ | "queued"
295
+ | "outcome_unknown"
296
+ | "dispatching"
297
+ | "provider_accepted"
298
+ | "refused"
299
+ | "superseded";
300
+ providerMessageId?: string;
301
+ providerRejection?: Readonly<{
302
+ code: ...;
303
+ class: ...;
304
+ }>;
305
+ messages: readonly Readonly<{
306
+ id: ...;
307
+ recipient: ...;
308
+ roles: ...;
309
+ status: ...;
310
+ }>[];
311
+ }>
312
+ | undefined>;
313
+ tick: () => Promise<void>;
314
+ hasPendingWork: () => Promise<boolean>;
315
+ }>>;
316
+ ```
317
+
318
+ Construct exactly one owner per store/runtime lifetime. A replacement may be
319
+ opened only after its predecessor has stopped; simultaneous owners of the same
320
+ store are unsupported. Native adapters supply their runtime ownership.
321
+
322
+ #### Parameters
323
+
324
+ | Parameter | Type |
325
+ | --------- | --------------------- |
326
+ | `options` | [`Options`](#options) |
327
+
328
+ #### Returns
329
+
330
+ `Promise`\<`Readonly`\<\{ `send`: (`submission`) => `Promise`\<`Readonly`\<\{
331
+ `id`: `string`; `status`: \| `"expired"` \| `"rejected"` \| `"queued"` \|
332
+ `"outcome_unknown"` \| `"dispatching"` \| `"provider_accepted"` \| `"refused"`
333
+ \| `"superseded"`; `providerMessageId?`: `string`; `providerRejection?`:
334
+ `Readonly`\<\{ `code`: `string`; `class`: ... \| ...; \}\>; `messages`: readonly
335
+ `Readonly`\<\{ `id`: `string`; `recipient`: `string`; `roles`: readonly ...[];
336
+ `status`: `"unconfirmed"`; \}\>[]; \}\>\>; `get`: (`id`) => `Promise`\< \|
337
+ `Readonly`\<\{ `id`: `string`; `status`: \| `"expired"` \| `"rejected"` \|
338
+ `"queued"` \| `"outcome_unknown"` \| `"dispatching"` \| `"provider_accepted"` \|
339
+ `"refused"` \| `"superseded"`; `providerMessageId?`: `string`;
340
+ `providerRejection?`: `Readonly`\<\{ `code`: ...; `class`: ...; \}\>;
341
+ `messages`: readonly `Readonly`\<\{ `id`: ...; `recipient`: ...; `roles`: ...;
342
+ `status`: ...; \}\>[]; \}\> \| `undefined`\>; `tick`: () => `Promise`\<`void`\>;
343
+ `hasPendingWork`: () => `Promise`\<`boolean`\>; \}\>\>