@satorio/machinery 0.2.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 (341) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/dictionary/all.json +4656 -0
  4. package/dictionary/all.toon +639 -0
  5. package/dictionary/core.json +221 -0
  6. package/dictionary/core.toon +33 -0
  7. package/dictionary/graphql.json +212 -0
  8. package/dictionary/graphql.toon +32 -0
  9. package/dictionary/http.json +113 -0
  10. package/dictionary/http.toon +21 -0
  11. package/dictionary/identifiers.json +266 -0
  12. package/dictionary/identifiers.toon +38 -0
  13. package/dictionary/index.json +96 -0
  14. package/dictionary/index.toon +18 -0
  15. package/dictionary/integration.json +131 -0
  16. package/dictionary/integration.toon +23 -0
  17. package/dictionary/money.json +383 -0
  18. package/dictionary/money.toon +51 -0
  19. package/dictionary/ports.json +392 -0
  20. package/dictionary/ports.toon +52 -0
  21. package/dictionary/postgres.json +473 -0
  22. package/dictionary/postgres.toon +61 -0
  23. package/dictionary/publishing.json +131 -0
  24. package/dictionary/publishing.toon +23 -0
  25. package/dictionary/queue.json +365 -0
  26. package/dictionary/queue.toon +49 -0
  27. package/dictionary/reference/api.mdx +843 -0
  28. package/dictionary/reference/uk/api.mdx +844 -0
  29. package/dictionary/storage.json +194 -0
  30. package/dictionary/storage.toon +30 -0
  31. package/dictionary/testing.json +707 -0
  32. package/dictionary/testing.toon +87 -0
  33. package/dictionary/time.json +311 -0
  34. package/dictionary/time.toon +43 -0
  35. package/dictionary/vitest.json +356 -0
  36. package/dictionary/vitest.toon +48 -0
  37. package/dictionary/workflow.json +185 -0
  38. package/dictionary/workflow.toon +29 -0
  39. package/dist/bin/command.d.ts +45 -0
  40. package/dist/bin/command.js +113 -0
  41. package/dist/bin.d.ts +2 -0
  42. package/dist/bin.js +11 -0
  43. package/dist/core/bigint-json.d.ts +6 -0
  44. package/dist/core/bigint-json.js +6 -0
  45. package/dist/core/closed-set.d.ts +14 -0
  46. package/dist/core/closed-set.js +8 -0
  47. package/dist/core/domain-error.d.ts +8 -0
  48. package/dist/core/domain-error.js +11 -0
  49. package/dist/core/environment.d.ts +124 -0
  50. package/dist/core/environment.js +115 -0
  51. package/dist/core/index.d.ts +13 -0
  52. package/dist/core/index.js +13 -0
  53. package/dist/core/ulid.d.ts +27 -0
  54. package/dist/core/ulid.js +27 -0
  55. package/dist/graphql/builder.d.ts +36 -0
  56. package/dist/graphql/builder.js +35 -0
  57. package/dist/graphql/context.d.ts +36 -0
  58. package/dist/graphql/context.js +69 -0
  59. package/dist/graphql/failure-classification.d.ts +11 -0
  60. package/dist/graphql/failure-classification.js +1 -0
  61. package/dist/graphql/failures.d.ts +62 -0
  62. package/dist/graphql/failures.js +30 -0
  63. package/dist/graphql/graphiql.d.ts +45 -0
  64. package/dist/graphql/graphiql.js +56 -0
  65. package/dist/graphql/index.d.ts +15 -0
  66. package/dist/graphql/index.js +14 -0
  67. package/dist/graphql/layer.d.ts +15 -0
  68. package/dist/graphql/layer.js +23 -0
  69. package/dist/graphql/request-handler.d.ts +26 -0
  70. package/dist/graphql/request-handler.js +33 -0
  71. package/dist/graphql/server.d.ts +19 -0
  72. package/dist/graphql/server.js +16 -0
  73. package/dist/graphql/settings.d.ts +55 -0
  74. package/dist/graphql/settings.js +82 -0
  75. package/dist/http/health.d.ts +70 -0
  76. package/dist/http/health.js +60 -0
  77. package/dist/http/index.d.ts +5 -0
  78. package/dist/http/index.js +5 -0
  79. package/dist/identifiers/client-code.d.ts +37 -0
  80. package/dist/identifiers/client-code.js +41 -0
  81. package/dist/identifiers/creditor-reference.d.ts +38 -0
  82. package/dist/identifiers/creditor-reference.js +32 -0
  83. package/dist/identifiers/damm.d.ts +22 -0
  84. package/dist/identifiers/damm.js +50 -0
  85. package/dist/identifiers/document-number.d.ts +68 -0
  86. package/dist/identifiers/document-number.js +73 -0
  87. package/dist/identifiers/document-numbers.d.ts +27 -0
  88. package/dist/identifiers/document-numbers.js +16 -0
  89. package/dist/identifiers/failures.d.ts +46 -0
  90. package/dist/identifiers/failures.js +48 -0
  91. package/dist/identifiers/index.d.ts +14 -0
  92. package/dist/identifiers/index.js +13 -0
  93. package/dist/identifiers/next-document-number.d.ts +26 -0
  94. package/dist/identifiers/next-document-number.js +31 -0
  95. package/dist/identifiers/ulid.d.ts +28 -0
  96. package/dist/identifiers/ulid.js +71 -0
  97. package/dist/integration/external-http-client.d.ts +22 -0
  98. package/dist/integration/external-http-client.js +74 -0
  99. package/dist/integration/index.d.ts +12 -0
  100. package/dist/integration/index.js +12 -0
  101. package/dist/integration/layer.d.ts +19 -0
  102. package/dist/integration/layer.js +30 -0
  103. package/dist/integration/retry.d.ts +65 -0
  104. package/dist/integration/retry.js +54 -0
  105. package/dist/integration/settings.d.ts +73 -0
  106. package/dist/integration/settings.js +92 -0
  107. package/dist/money/amount.d.ts +60 -0
  108. package/dist/money/amount.js +67 -0
  109. package/dist/money/arithmetic.d.ts +60 -0
  110. package/dist/money/arithmetic.js +73 -0
  111. package/dist/money/currency.d.ts +25 -0
  112. package/dist/money/currency.js +24 -0
  113. package/dist/money/decimal.d.ts +29 -0
  114. package/dist/money/decimal.js +39 -0
  115. package/dist/money/exchange-rate.d.ts +32 -0
  116. package/dist/money/exchange-rate.js +28 -0
  117. package/dist/money/failures.d.ts +86 -0
  118. package/dist/money/failures.js +97 -0
  119. package/dist/money/index.d.ts +15 -0
  120. package/dist/money/index.js +15 -0
  121. package/dist/money/percent.d.ts +35 -0
  122. package/dist/money/percent.js +50 -0
  123. package/dist/money/schema.d.ts +25 -0
  124. package/dist/money/schema.js +41 -0
  125. package/dist/ports/blob-store.d.ts +42 -0
  126. package/dist/ports/blob-store.js +13 -0
  127. package/dist/ports/document-number-counter.d.ts +36 -0
  128. package/dist/ports/document-number-counter.js +12 -0
  129. package/dist/ports/event-publisher.d.ts +29 -0
  130. package/dist/ports/event-publisher.js +13 -0
  131. package/dist/ports/external-http-client.d.ts +60 -0
  132. package/dist/ports/external-http-client.js +25 -0
  133. package/dist/ports/index.d.ts +17 -0
  134. package/dist/ports/index.js +17 -0
  135. package/dist/ports/integration-event-outbox.d.ts +44 -0
  136. package/dist/ports/integration-event-outbox.js +13 -0
  137. package/dist/ports/port-unavailable.d.ts +21 -0
  138. package/dist/ports/port-unavailable.js +30 -0
  139. package/dist/ports/processed-event-registry.d.ts +57 -0
  140. package/dist/ports/processed-event-registry.js +24 -0
  141. package/dist/ports/queue-message-producer.d.ts +26 -0
  142. package/dist/ports/queue-message-producer.js +12 -0
  143. package/dist/ports/queue-message-source.d.ts +39 -0
  144. package/dist/ports/queue-message-source.js +13 -0
  145. package/dist/ports/readiness-probe.d.ts +27 -0
  146. package/dist/ports/readiness-probe.js +13 -0
  147. package/dist/ports/transaction-boundary.d.ts +28 -0
  148. package/dist/ports/transaction-boundary.js +13 -0
  149. package/dist/postgres/client.d.ts +51 -0
  150. package/dist/postgres/client.js +81 -0
  151. package/dist/postgres/document-number-counter.d.ts +14 -0
  152. package/dist/postgres/document-number-counter.js +27 -0
  153. package/dist/postgres/failures.d.ts +28 -0
  154. package/dist/postgres/failures.js +18 -0
  155. package/dist/postgres/index.d.ts +18 -0
  156. package/dist/postgres/index.js +18 -0
  157. package/dist/postgres/integration-event-outbox.d.ts +15 -0
  158. package/dist/postgres/integration-event-outbox.js +60 -0
  159. package/dist/postgres/jsonb-value.d.ts +10 -0
  160. package/dist/postgres/jsonb-value.js +9 -0
  161. package/dist/postgres/layer.d.ts +57 -0
  162. package/dist/postgres/layer.js +72 -0
  163. package/dist/postgres/migrations/advisory-lock.d.ts +47 -0
  164. package/dist/postgres/migrations/advisory-lock.js +59 -0
  165. package/dist/postgres/migrations/runner.d.ts +56 -0
  166. package/dist/postgres/migrations/runner.js +69 -0
  167. package/dist/postgres/migrations/sql-file-loader.d.ts +59 -0
  168. package/dist/postgres/migrations/sql-file-loader.js +99 -0
  169. package/dist/postgres/processed-event-registry.d.ts +13 -0
  170. package/dist/postgres/processed-event-registry.js +44 -0
  171. package/dist/postgres/readiness-probe.d.ts +27 -0
  172. package/dist/postgres/readiness-probe.js +33 -0
  173. package/dist/postgres/settings.d.ts +134 -0
  174. package/dist/postgres/settings.js +210 -0
  175. package/dist/postgres/sql/0001_processed_event.sql +4 -0
  176. package/dist/postgres/sql/0002_integration_event_outbox.sql +13 -0
  177. package/dist/postgres/sql/0003_document_number_counter.sql +6 -0
  178. package/dist/postgres/sql-failure.d.ts +19 -0
  179. package/dist/postgres/sql-failure.js +22 -0
  180. package/dist/postgres/store-failure.d.ts +17 -0
  181. package/dist/postgres/store-failure.js +16 -0
  182. package/dist/postgres/transaction-boundary.d.ts +13 -0
  183. package/dist/postgres/transaction-boundary.js +21 -0
  184. package/dist/publishing/event-publisher.sns.d.ts +66 -0
  185. package/dist/publishing/event-publisher.sns.js +75 -0
  186. package/dist/publishing/event-publisher.stdout.d.ts +15 -0
  187. package/dist/publishing/event-publisher.stdout.js +24 -0
  188. package/dist/publishing/index.d.ts +10 -0
  189. package/dist/publishing/index.js +10 -0
  190. package/dist/publishing/layer.d.ts +25 -0
  191. package/dist/publishing/layer.js +39 -0
  192. package/dist/publishing/settings.d.ts +60 -0
  193. package/dist/publishing/settings.js +85 -0
  194. package/dist/queue/consumer.d.ts +91 -0
  195. package/dist/queue/consumer.js +92 -0
  196. package/dist/queue/envelope.d.ts +39 -0
  197. package/dist/queue/envelope.js +39 -0
  198. package/dist/queue/failures.d.ts +33 -0
  199. package/dist/queue/failures.js +15 -0
  200. package/dist/queue/index.d.ts +14 -0
  201. package/dist/queue/index.js +14 -0
  202. package/dist/queue/layer.d.ts +33 -0
  203. package/dist/queue/layer.js +58 -0
  204. package/dist/queue/message-codec.d.ts +43 -0
  205. package/dist/queue/message-codec.js +33 -0
  206. package/dist/queue/queue-message-producer.d.ts +61 -0
  207. package/dist/queue/queue-message-producer.js +52 -0
  208. package/dist/queue/queue-message-source.d.ts +93 -0
  209. package/dist/queue/queue-message-source.js +86 -0
  210. package/dist/queue/readiness.d.ts +78 -0
  211. package/dist/queue/readiness.js +86 -0
  212. package/dist/queue/settings.d.ts +106 -0
  213. package/dist/queue/settings.js +160 -0
  214. package/dist/storage/blob-store.d.ts +84 -0
  215. package/dist/storage/blob-store.js +109 -0
  216. package/dist/storage/index.d.ts +9 -0
  217. package/dist/storage/index.js +9 -0
  218. package/dist/storage/layer.d.ts +17 -0
  219. package/dist/storage/layer.js +30 -0
  220. package/dist/storage/settings.d.ts +48 -0
  221. package/dist/storage/settings.js +65 -0
  222. package/dist/testing/blob-store.d.ts +27 -0
  223. package/dist/testing/blob-store.js +45 -0
  224. package/dist/testing/clock.d.ts +29 -0
  225. package/dist/testing/clock.js +41 -0
  226. package/dist/testing/dna-perturbator/attention.d.ts +55 -0
  227. package/dist/testing/dna-perturbator/attention.js +49 -0
  228. package/dist/testing/dna-perturbator/chains.d.ts +31 -0
  229. package/dist/testing/dna-perturbator/chains.js +53 -0
  230. package/dist/testing/dna-perturbator/report.d.ts +12 -0
  231. package/dist/testing/dna-perturbator/report.js +22 -0
  232. package/dist/testing/dna-perturbator/verdict.d.ts +26 -0
  233. package/dist/testing/dna-perturbator/verdict.js +28 -0
  234. package/dist/testing/dna-perturbator.d.ts +48 -0
  235. package/dist/testing/dna-perturbator.js +145 -0
  236. package/dist/testing/document-number-counter.d.ts +29 -0
  237. package/dist/testing/document-number-counter.js +39 -0
  238. package/dist/testing/event-publisher.d.ts +28 -0
  239. package/dist/testing/event-publisher.js +33 -0
  240. package/dist/testing/external-http-client.d.ts +29 -0
  241. package/dist/testing/external-http-client.js +49 -0
  242. package/dist/testing/index.d.ts +24 -0
  243. package/dist/testing/index.js +24 -0
  244. package/dist/testing/integration-event-outbox.d.ts +37 -0
  245. package/dist/testing/integration-event-outbox.js +67 -0
  246. package/dist/testing/mutation-settings.d.ts +71 -0
  247. package/dist/testing/mutation-settings.js +57 -0
  248. package/dist/testing/postgres-rows.d.ts +12 -0
  249. package/dist/testing/postgres-rows.js +19 -0
  250. package/dist/testing/processed-event-registry.d.ts +25 -0
  251. package/dist/testing/processed-event-registry.js +39 -0
  252. package/dist/testing/queue-message-producer.d.ts +27 -0
  253. package/dist/testing/queue-message-producer.js +41 -0
  254. package/dist/testing/queue-message-source.d.ts +54 -0
  255. package/dist/testing/queue-message-source.js +71 -0
  256. package/dist/testing/quiet-reporter.d.ts +86 -0
  257. package/dist/testing/quiet-reporter.js +81 -0
  258. package/dist/testing/readiness-probe.d.ts +27 -0
  259. package/dist/testing/readiness-probe.js +33 -0
  260. package/dist/testing/scenario.d.ts +94 -0
  261. package/dist/testing/scenario.js +81 -0
  262. package/dist/testing/transaction-boundary.d.ts +30 -0
  263. package/dist/testing/transaction-boundary.js +36 -0
  264. package/dist/testing/typed-failure.d.ts +8 -0
  265. package/dist/testing/typed-failure.js +15 -0
  266. package/dist/time/calendar-day.d.ts +83 -0
  267. package/dist/time/calendar-day.js +112 -0
  268. package/dist/time/failures.d.ts +51 -0
  269. package/dist/time/failures.js +56 -0
  270. package/dist/time/index.d.ts +11 -0
  271. package/dist/time/index.js +11 -0
  272. package/dist/time/instant.d.ts +64 -0
  273. package/dist/time/instant.js +67 -0
  274. package/dist/time/period.d.ts +45 -0
  275. package/dist/time/period.js +55 -0
  276. package/dist/vitest/container-reuse.d.ts +14 -0
  277. package/dist/vitest/container-reuse.js +15 -0
  278. package/dist/vitest/dotenv.d.ts +16 -0
  279. package/dist/vitest/dotenv.js +48 -0
  280. package/dist/vitest/effect-single-instance.d.ts +36 -0
  281. package/dist/vitest/effect-single-instance.js +125 -0
  282. package/dist/vitest/fast-check-single-instance.d.ts +11 -0
  283. package/dist/vitest/fast-check-single-instance.js +26 -0
  284. package/dist/vitest/index.d.ts +31 -0
  285. package/dist/vitest/index.js +30 -0
  286. package/dist/vitest/localstack-container.d.ts +32 -0
  287. package/dist/vitest/localstack-container.js +55 -0
  288. package/dist/vitest/port-contract-tester.d.ts +8 -0
  289. package/dist/vitest/port-contract-tester.js +1 -0
  290. package/dist/vitest/port-contracts/blob-store.contract.d.ts +22 -0
  291. package/dist/vitest/port-contracts/blob-store.contract.js +108 -0
  292. package/dist/vitest/port-contracts/document-number-counter.contract.d.ts +18 -0
  293. package/dist/vitest/port-contracts/document-number-counter.contract.js +90 -0
  294. package/dist/vitest/port-contracts/event-publisher.contract.d.ts +35 -0
  295. package/dist/vitest/port-contracts/event-publisher.contract.js +67 -0
  296. package/dist/vitest/port-contracts/external-http-client.contract.d.ts +35 -0
  297. package/dist/vitest/port-contracts/external-http-client.contract.js +52 -0
  298. package/dist/vitest/port-contracts/integration-event-outbox.contract.d.ts +23 -0
  299. package/dist/vitest/port-contracts/integration-event-outbox.contract.js +75 -0
  300. package/dist/vitest/port-contracts/processed-event-registry.contract.d.ts +18 -0
  301. package/dist/vitest/port-contracts/processed-event-registry.contract.js +84 -0
  302. package/dist/vitest/port-contracts/queue-message-producer.contract.d.ts +26 -0
  303. package/dist/vitest/port-contracts/queue-message-producer.contract.js +48 -0
  304. package/dist/vitest/port-contracts/queue-message-source.contract.d.ts +29 -0
  305. package/dist/vitest/port-contracts/queue-message-source.contract.js +71 -0
  306. package/dist/vitest/port-contracts/readiness-probe.contract.d.ts +18 -0
  307. package/dist/vitest/port-contracts/readiness-probe.contract.js +41 -0
  308. package/dist/vitest/port-contracts/transaction-boundary.contract.d.ts +21 -0
  309. package/dist/vitest/port-contracts/transaction-boundary.contract.js +64 -0
  310. package/dist/vitest/postgres-container.d.ts +57 -0
  311. package/dist/vitest/postgres-container.js +118 -0
  312. package/dist/vitest/reader-port-contract.d.ts +41 -0
  313. package/dist/vitest/reader-port-contract.js +43 -0
  314. package/dist/vitest/repo-source-files.d.ts +37 -0
  315. package/dist/vitest/repo-source-files.js +61 -0
  316. package/dist/vitest/reset-tables.d.ts +18 -0
  317. package/dist/vitest/reset-tables.js +30 -0
  318. package/dist/vitest/settings-contract.d.ts +38 -0
  319. package/dist/vitest/settings-contract.js +77 -0
  320. package/dist/vitest/stub-server.d.ts +43 -0
  321. package/dist/vitest/stub-server.js +60 -0
  322. package/dist/vitest/term-registry.json +730 -0
  323. package/dist/vitest/testclock-fork-isolated-files.d.ts +13 -0
  324. package/dist/vitest/testclock-fork-isolated-files.js +18 -0
  325. package/dist/vitest/testclock-fork-isolation.d.ts +77 -0
  326. package/dist/vitest/testclock-fork-isolation.js +188 -0
  327. package/dist/workflow/claim-once.d.ts +16 -0
  328. package/dist/workflow/claim-once.js +9 -0
  329. package/dist/workflow/failures.d.ts +47 -0
  330. package/dist/workflow/failures.js +22 -0
  331. package/dist/workflow/index.d.ts +12 -0
  332. package/dist/workflow/index.js +12 -0
  333. package/dist/workflow/on-claim.d.ts +17 -0
  334. package/dist/workflow/on-claim.js +8 -0
  335. package/dist/workflow/publish-pending-events.d.ts +31 -0
  336. package/dist/workflow/publish-pending-events.js +31 -0
  337. package/dist/workflow/transactionally.d.ts +8 -0
  338. package/dist/workflow/transactionally.js +8 -0
  339. package/dist/workflow/versioned-payload.d.ts +35 -0
  340. package/dist/workflow/versioned-payload.js +43 -0
  341. package/package.json +309 -0
@@ -0,0 +1,35 @@
1
+ import { Either } from 'effect';
2
+ import { NotAPercentError } from './failures.js';
3
+ /**
4
+ * A share of an amount, held exactly. Thirty percent is the ratio three
5
+ * tenths, and this value carries it as a whole number of units and the
6
+ * count of decimals those units are counted in. Two sources write the
7
+ * same share in two forms — a price list writes `30`, a table of rates
8
+ * writes `0.3` — so each form has its own reader and its own writer, and
9
+ * nothing in between guesses which one arrived.
10
+ */
11
+ export interface Percent {
12
+ readonly amount: bigint;
13
+ readonly scale: bigint;
14
+ }
15
+ /**
16
+ * Reads the form a price list writes: `30` means thirty percent.
17
+ */
18
+ export declare const percentFromPercentageForm: (text: string) => Either.Either<Percent, NotAPercentError>;
19
+ /**
20
+ * Reads the form a table of rates writes: `0.3` means thirty percent.
21
+ */
22
+ export declare const percentFromRatioForm: (text: string) => Either.Either<Percent, NotAPercentError>;
23
+ /**
24
+ * Writes the percentage form back, trimmed: thirty percent reads `30`.
25
+ */
26
+ export declare const percentInPercentageForm: (percent: Percent) => string;
27
+ /**
28
+ * Writes the ratio form back, trimmed: thirty percent reads `0.3`.
29
+ */
30
+ export declare const percentInRatioForm: (percent: Percent) => string;
31
+ /**
32
+ * Whether two shares are the same share, whichever form each was read
33
+ * from. `30` and `0.30` are one share, and this says so.
34
+ */
35
+ export declare const samePercent: (left: Percent, right: Percent) => boolean;
@@ -0,0 +1,50 @@
1
+ import { Either } from 'effect';
2
+ import { exactDecimalOf, trimmedDecimalOf } from './decimal.js';
3
+ import { NotAPercentError } from './failures.js';
4
+ const PERCENTAGE_TO_RATIO = 2n;
5
+ /**
6
+ * Reads the form a price list writes: `30` means thirty percent.
7
+ */
8
+ export const percentFromPercentageForm = (text) => {
9
+ const read = exactDecimalOf(text);
10
+ return read === null
11
+ ? Either.left(new NotAPercentError({ text, form: 'percentage' }))
12
+ : Either.right({
13
+ amount: read.units,
14
+ scale: read.scale + PERCENTAGE_TO_RATIO,
15
+ });
16
+ };
17
+ /**
18
+ * Reads the form a table of rates writes: `0.3` means thirty percent.
19
+ */
20
+ export const percentFromRatioForm = (text) => {
21
+ const read = exactDecimalOf(text);
22
+ return read === null
23
+ ? Either.left(new NotAPercentError({ text, form: 'ratio' }))
24
+ : Either.right({ amount: read.units, scale: read.scale });
25
+ };
26
+ const liftedTo = (percent, scale) => percent.scale >= scale
27
+ ? percent
28
+ : { amount: percent.amount * 10n ** (scale - percent.scale), scale };
29
+ /**
30
+ * Writes the percentage form back, trimmed: thirty percent reads `30`.
31
+ */
32
+ export const percentInPercentageForm = (percent) => {
33
+ const lifted = liftedTo(percent, PERCENTAGE_TO_RATIO);
34
+ return trimmedDecimalOf({
35
+ units: lifted.amount,
36
+ scale: lifted.scale - PERCENTAGE_TO_RATIO,
37
+ });
38
+ };
39
+ /**
40
+ * Writes the ratio form back, trimmed: thirty percent reads `0.3`.
41
+ */
42
+ export const percentInRatioForm = (percent) => trimmedDecimalOf({ units: percent.amount, scale: percent.scale });
43
+ /**
44
+ * Whether two shares are the same share, whichever form each was read
45
+ * from. `30` and `0.30` are one share, and this says so.
46
+ */
47
+ export const samePercent = (left, right) => {
48
+ const finest = left.scale > right.scale ? left.scale : right.scale;
49
+ return liftedTo(left, finest).amount === liftedTo(right, finest).amount;
50
+ };
@@ -0,0 +1,25 @@
1
+ import { Schema } from 'effect';
2
+ import { type Money } from './amount.js';
3
+ import type { Currency } from './currency.js';
4
+ import { type Percent } from './percent.js';
5
+ /**
6
+ * Reads and writes an amount on the wire as decimal text, in the currency you
7
+ * name.
8
+ *
9
+ * Reads an amount off the wire as the decimal text a sender wrote, in the
10
+ * currency you name, and writes it back in that same form. A text this schema
11
+ * refuses carries the whole three-part refusal into the parse error, so
12
+ * whoever sent a bad command reads a sentence about their own amount rather
13
+ * than a bare type name.
14
+ */
15
+ export declare const MoneyFromDecimalString: (currency: Currency) => Schema.Schema<Money, string>;
16
+ /**
17
+ * Reads a share off the wire in the form a price list writes: `30` means
18
+ * thirty percent. It writes that same form back.
19
+ */
20
+ export declare const PercentFromPercentageString: Schema.Schema<Percent, string>;
21
+ /**
22
+ * Reads a share off the wire in the form a table of rates writes: `0.3`
23
+ * means thirty percent. It writes that same form back.
24
+ */
25
+ export declare const PercentFromRatioString: Schema.Schema<Percent, string>;
@@ -0,0 +1,41 @@
1
+ import { refusalText } from '@satorio/machinery/core';
2
+ import { Either, ParseResult, Schema } from 'effect';
3
+ import { moneyFromDecimalForm, moneyInDecimalForm } from './amount.js';
4
+ import { percentFromPercentageForm, percentFromRatioForm, percentInPercentageForm, percentInRatioForm, } from './percent.js';
5
+ const MoneyValue = Schema.declare((value) => typeof value === 'object' && value !== null && 'calculator' in value, { identifier: 'Money' });
6
+ const PercentValue = Schema.declare((value) => typeof value === 'object' &&
7
+ value !== null &&
8
+ typeof value.amount === 'bigint', { identifier: 'Percent' });
9
+ /**
10
+ * Reads and writes an amount on the wire as decimal text, in the currency you
11
+ * name.
12
+ *
13
+ * Reads an amount off the wire as the decimal text a sender wrote, in the
14
+ * currency you name, and writes it back in that same form. A text this schema
15
+ * refuses carries the whole three-part refusal into the parse error, so
16
+ * whoever sent a bad command reads a sentence about their own amount rather
17
+ * than a bare type name.
18
+ */
19
+ export const MoneyFromDecimalString = (currency) => Schema.transformOrFail(Schema.String, MoneyValue, {
20
+ strict: true,
21
+ decode: (text, _options, ast) => Either.mapLeft(moneyFromDecimalForm(currency, text), (failure) => new ParseResult.Type(ast, text, refusalText(failure.refusal))),
22
+ encode: (amount) => ParseResult.succeed(moneyInDecimalForm(amount)),
23
+ });
24
+ /**
25
+ * Reads a share off the wire in the form a price list writes: `30` means
26
+ * thirty percent. It writes that same form back.
27
+ */
28
+ export const PercentFromPercentageString = Schema.transformOrFail(Schema.String, PercentValue, {
29
+ strict: true,
30
+ decode: (text, _options, ast) => Either.mapLeft(percentFromPercentageForm(text), (failure) => new ParseResult.Type(ast, text, refusalText(failure.refusal))),
31
+ encode: (percent) => ParseResult.succeed(percentInPercentageForm(percent)),
32
+ });
33
+ /**
34
+ * Reads a share off the wire in the form a table of rates writes: `0.3`
35
+ * means thirty percent. It writes that same form back.
36
+ */
37
+ export const PercentFromRatioString = Schema.transformOrFail(Schema.String, PercentValue, {
38
+ strict: true,
39
+ decode: (text, _options, ast) => Either.mapLeft(percentFromRatioForm(text), (failure) => new ParseResult.Type(ast, text, refusalText(failure.refusal))),
40
+ encode: (percent) => ParseResult.succeed(percentInRatioForm(percent)),
41
+ });
@@ -0,0 +1,42 @@
1
+ import { Context, type Effect, type Option } from 'effect';
2
+ declare const BlobStoreUnavailableError_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 & {
3
+ readonly _tag: "BlobStoreUnavailableError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * The object store did not answer; a key that is not there at all is never
7
+ * this failure.
8
+ */
9
+ export declare class BlobStoreUnavailableError extends BlobStoreUnavailableError_base<{
10
+ readonly operation: string;
11
+ readonly cause: unknown;
12
+ }> {
13
+ }
14
+ /**
15
+ * A stored blob's bytes, content type, and free-form text metadata. The key
16
+ * lives outside this shape, as a separate argument to each operation — a
17
+ * blob does not know its own key.
18
+ */
19
+ export interface StoredBlob {
20
+ readonly body: Uint8Array;
21
+ readonly contentType: string;
22
+ readonly metadata: Readonly<Record<string, string>>;
23
+ }
24
+ /**
25
+ * The blob store's operations. A missing key is not a failure: `get`
26
+ * returns `Option.none` and `exists` returns `false`.
27
+ * `BlobStoreUnavailableError` means only one thing: the store did not answer.
28
+ */
29
+ export interface BlobStoreShape {
30
+ readonly put: (key: string, blob: StoredBlob) => Effect.Effect<void, BlobStoreUnavailableError>;
31
+ readonly get: (key: string) => Effect.Effect<Option.Option<StoredBlob>, BlobStoreUnavailableError>;
32
+ readonly exists: (key: string) => Effect.Effect<boolean, BlobStoreUnavailableError>;
33
+ readonly delete: (key: string) => Effect.Effect<void, BlobStoreUnavailableError>;
34
+ }
35
+ declare const BlobStore_base: Context.TagClass<BlobStore, "BlobStore", BlobStoreShape>;
36
+ /**
37
+ * The port a use case asks for when it stores whole objects under a key and
38
+ * reads them back.
39
+ */
40
+ export declare class BlobStore extends BlobStore_base {
41
+ }
42
+ export {};
@@ -0,0 +1,13 @@
1
+ import { Context, Data } from 'effect';
2
+ /**
3
+ * The object store did not answer; a key that is not there at all is never
4
+ * this failure.
5
+ */
6
+ export class BlobStoreUnavailableError extends Data.TaggedError('BlobStoreUnavailableError') {
7
+ }
8
+ /**
9
+ * The port a use case asks for when it stores whole objects under a key and
10
+ * reads them back.
11
+ */
12
+ export class BlobStore extends Context.Tag('BlobStore')() {
13
+ }
@@ -0,0 +1,36 @@
1
+ import { Context, type Effect } from 'effect';
2
+ declare const DocumentNumberCounterUnavailableError_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 & {
3
+ readonly _tag: "DocumentNumberCounterUnavailableError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * The counter behind a document number did not answer; `operation` names the
7
+ * call and `cause` carries the driver's own error.
8
+ */
9
+ export declare class DocumentNumberCounterUnavailableError extends DocumentNumberCounterUnavailableError_base<{
10
+ readonly operation: string;
11
+ readonly cause: unknown;
12
+ }> {
13
+ }
14
+ /**
15
+ * Which counter to move on: one client, one reporting month. Every series
16
+ * of documents a client is sent in that month shares this counter, so two
17
+ * documents never carry the same digits.
18
+ */
19
+ export interface DocumentNumberCountInput {
20
+ readonly clientCode: string;
21
+ readonly reportingMonth: string;
22
+ }
23
+ /**
24
+ * What the counter offers: one call that moves a client's month on and hands
25
+ * back the count the next document takes.
26
+ */
27
+ export interface DocumentNumberCounterShape {
28
+ readonly nextCount: (input: DocumentNumberCountInput) => Effect.Effect<number, DocumentNumberCounterUnavailableError>;
29
+ }
30
+ declare const DocumentNumberCounter_base: Context.TagClass<DocumentNumberCounter, "DocumentNumberCounter", DocumentNumberCounterShape>;
31
+ /**
32
+ * The port a use case asks for when it numbers a document a person will read.
33
+ */
34
+ export declare class DocumentNumberCounter extends DocumentNumberCounter_base {
35
+ }
36
+ export {};
@@ -0,0 +1,12 @@
1
+ import { Context, Data } from 'effect';
2
+ /**
3
+ * The counter behind a document number did not answer; `operation` names the
4
+ * call and `cause` carries the driver's own error.
5
+ */
6
+ export class DocumentNumberCounterUnavailableError extends Data.TaggedError('DocumentNumberCounterUnavailableError') {
7
+ }
8
+ /**
9
+ * The port a use case asks for when it numbers a document a person will read.
10
+ */
11
+ export class DocumentNumberCounter extends Context.Tag('DocumentNumberCounter')() {
12
+ }
@@ -0,0 +1,29 @@
1
+ import { Context, type Effect } from 'effect';
2
+ import type { OutboxMessage } from './integration-event-outbox.js';
3
+ declare const EventPublisherUnavailableError_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 & {
4
+ readonly _tag: "EventPublisherUnavailableError";
5
+ } & Readonly<A>;
6
+ /**
7
+ * The publisher did not answer, or no topic is configured; `cause` says which
8
+ * of the two it was.
9
+ */
10
+ export declare class EventPublisherUnavailableError extends EventPublisherUnavailableError_base<{
11
+ readonly operation: string;
12
+ readonly cause: unknown;
13
+ }> {
14
+ }
15
+ /**
16
+ * What a publisher offers: one call that sends a batch of outbox messages out
17
+ * of this service.
18
+ */
19
+ export interface EventPublisherShape {
20
+ readonly publish: (messages: readonly OutboxMessage[]) => Effect.Effect<void, EventPublisherUnavailableError>;
21
+ }
22
+ declare const EventPublisher_base: Context.TagClass<EventPublisher, "EventPublisher", EventPublisherShape>;
23
+ /**
24
+ * The port the outbox relay asks for when it announces what has already
25
+ * happened.
26
+ */
27
+ export declare class EventPublisher extends EventPublisher_base {
28
+ }
29
+ export {};
@@ -0,0 +1,13 @@
1
+ import { Context, Data } from 'effect';
2
+ /**
3
+ * The publisher did not answer, or no topic is configured; `cause` says which
4
+ * of the two it was.
5
+ */
6
+ export class EventPublisherUnavailableError extends Data.TaggedError('EventPublisherUnavailableError') {
7
+ }
8
+ /**
9
+ * The port the outbox relay asks for when it announces what has already
10
+ * happened.
11
+ */
12
+ export class EventPublisher extends Context.Tag('EventPublisher')() {
13
+ }
@@ -0,0 +1,60 @@
1
+ import { Context, type Effect, type Schema } from 'effect';
2
+ declare const ExternalServiceUnavailableError_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 & {
3
+ readonly _tag: "ExternalServiceUnavailableError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * A network failure, a timeout, or a server error after the retries ran out;
7
+ * the same request may well succeed later.
8
+ */
9
+ export declare class ExternalServiceUnavailableError extends ExternalServiceUnavailableError_base<{
10
+ readonly service: string;
11
+ readonly operation: string;
12
+ readonly cause: unknown;
13
+ }> {
14
+ }
15
+ declare const ExternalServiceRefusedError_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 & {
16
+ readonly _tag: "ExternalServiceRefusedError";
17
+ } & Readonly<A>;
18
+ /**
19
+ * The external service answered with a refusal of its own, so the same request
20
+ * will fail again until the request changes.
21
+ */
22
+ export declare class ExternalServiceRefusedError extends ExternalServiceRefusedError_base<{
23
+ readonly service: string;
24
+ readonly operation: string;
25
+ readonly status: number;
26
+ }> {
27
+ }
28
+ declare const ExternalServiceResponseMalformedError_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 & {
29
+ readonly _tag: "ExternalServiceResponseMalformedError";
30
+ } & Readonly<A>;
31
+ /**
32
+ * The external service answered, but the body did not fit the schema the
33
+ * caller handed in.
34
+ */
35
+ export declare class ExternalServiceResponseMalformedError extends ExternalServiceResponseMalformedError_base<{
36
+ readonly service: string;
37
+ readonly operation: string;
38
+ readonly cause: unknown;
39
+ }> {
40
+ }
41
+ /**
42
+ * One external HTTP service, read through one operation. `getJson` asks
43
+ * for a path under the service's own address and decodes the answer
44
+ * through the schema you hand it, so a caller reads a value of its own
45
+ * type or one of exactly three failures: the service did not answer
46
+ * (`ExternalServiceUnavailableError`), the service said a specific no
47
+ * (`ExternalServiceRefusedError`), or the body did not fit the schema
48
+ * (`ExternalServiceResponseMalformedError`).
49
+ */
50
+ export interface ExternalHttpClientShape {
51
+ readonly getJson: <A, I>(path: string, schema: Schema.Schema<A, I>) => Effect.Effect<A, ExternalServiceUnavailableError | ExternalServiceRefusedError | ExternalServiceResponseMalformedError>;
52
+ }
53
+ declare const ExternalHttpClient_base: Context.TagClass<ExternalHttpClient, "ExternalHttpClient", ExternalHttpClientShape>;
54
+ /**
55
+ * The port a use case asks for when it reads reference data from a service
56
+ * outside this one.
57
+ */
58
+ export declare class ExternalHttpClient extends ExternalHttpClient_base {
59
+ }
60
+ export {};
@@ -0,0 +1,25 @@
1
+ import { Context, Data } from 'effect';
2
+ /**
3
+ * A network failure, a timeout, or a server error after the retries ran out;
4
+ * the same request may well succeed later.
5
+ */
6
+ export class ExternalServiceUnavailableError extends Data.TaggedError('ExternalServiceUnavailableError') {
7
+ }
8
+ /**
9
+ * The external service answered with a refusal of its own, so the same request
10
+ * will fail again until the request changes.
11
+ */
12
+ export class ExternalServiceRefusedError extends Data.TaggedError('ExternalServiceRefusedError') {
13
+ }
14
+ /**
15
+ * The external service answered, but the body did not fit the schema the
16
+ * caller handed in.
17
+ */
18
+ export class ExternalServiceResponseMalformedError extends Data.TaggedError('ExternalServiceResponseMalformedError') {
19
+ }
20
+ /**
21
+ * The port a use case asks for when it reads reference data from a service
22
+ * outside this one.
23
+ */
24
+ export class ExternalHttpClient extends Context.Tag('ExternalHttpClient')() {
25
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Public entry to the ports mechanism: every boundary a use case may ask for,
3
+ * and the failure each one raises. It gives you every boundary a use case may
4
+ * ask for, each one a `Context.Tag` with a shape, the value types that shape
5
+ * uses, and the failure it raises when the driver behind it does not answer.
6
+ */
7
+ export { BlobStore, type BlobStoreShape, BlobStoreUnavailableError, type StoredBlob, } from './blob-store.js';
8
+ export { DocumentNumberCounter, type DocumentNumberCounterShape, DocumentNumberCounterUnavailableError, type DocumentNumberCountInput, } from './document-number-counter.js';
9
+ export { EventPublisher, type EventPublisherShape, EventPublisherUnavailableError, } from './event-publisher.js';
10
+ export { ExternalHttpClient, type ExternalHttpClientShape, ExternalServiceRefusedError, ExternalServiceResponseMalformedError, ExternalServiceUnavailableError, } from './external-http-client.js';
11
+ export { IntegrationEventOutbox, type IntegrationEventOutboxShape, IntegrationEventOutboxUnavailableError, type OutboxMessage, } from './integration-event-outbox.js';
12
+ export { PORT_FAILURES_IN_THE_EVENTS_LANGUAGE, portUnavailable, } from './port-unavailable.js';
13
+ export { alreadyProcessed, type ClaimProcessedEventInput, claimAccepted, type ProcessedEventClaim, ProcessedEventRegistry, type ProcessedEventRegistryShape, ProcessedEventRegistryUnavailableError, } from './processed-event-registry.js';
14
+ export { QueueMessageProducer, type QueueMessageProducerShape, QueueMessageProducerUnavailableError, } from './queue-message-producer.js';
15
+ export { QueueMessageSource, type QueueMessageSourceShape, QueueMessageSourceUnavailableError, type RawQueueMessage, } from './queue-message-source.js';
16
+ export { DatabaseDidNotAnswerError, ReadinessProbe, type ReadinessProbeShape, } from './readiness-probe.js';
17
+ export { TransactionBoundary, type TransactionBoundaryShape, TransactionBoundaryUnavailableError, } from './transaction-boundary.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Public entry to the ports mechanism: every boundary a use case may ask for,
3
+ * and the failure each one raises. It gives you every boundary a use case may
4
+ * ask for, each one a `Context.Tag` with a shape, the value types that shape
5
+ * uses, and the failure it raises when the driver behind it does not answer.
6
+ */
7
+ export { BlobStore, BlobStoreUnavailableError, } from './blob-store.js';
8
+ export { DocumentNumberCounter, DocumentNumberCounterUnavailableError, } from './document-number-counter.js';
9
+ export { EventPublisher, EventPublisherUnavailableError, } from './event-publisher.js';
10
+ export { ExternalHttpClient, ExternalServiceRefusedError, ExternalServiceResponseMalformedError, ExternalServiceUnavailableError, } from './external-http-client.js';
11
+ export { IntegrationEventOutbox, IntegrationEventOutboxUnavailableError, } from './integration-event-outbox.js';
12
+ export { PORT_FAILURES_IN_THE_EVENTS_LANGUAGE, portUnavailable, } from './port-unavailable.js';
13
+ export { alreadyProcessed, claimAccepted, ProcessedEventRegistry, ProcessedEventRegistryUnavailableError, } from './processed-event-registry.js';
14
+ export { QueueMessageProducer, QueueMessageProducerUnavailableError, } from './queue-message-producer.js';
15
+ export { QueueMessageSource, QueueMessageSourceUnavailableError, } from './queue-message-source.js';
16
+ export { DatabaseDidNotAnswerError, ReadinessProbe, } from './readiness-probe.js';
17
+ export { TransactionBoundary, TransactionBoundaryUnavailableError, } from './transaction-boundary.js';
@@ -0,0 +1,44 @@
1
+ import { Context, type DateTime, type Effect } from 'effect';
2
+ declare const IntegrationEventOutboxUnavailableError_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 & {
3
+ readonly _tag: "IntegrationEventOutboxUnavailableError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * The outbox driver did not answer; `operation` names the call and `cause`
7
+ * carries the driver's own error.
8
+ */
9
+ export declare class IntegrationEventOutboxUnavailableError extends IntegrationEventOutboxUnavailableError_base<{
10
+ readonly operation: string;
11
+ readonly cause: unknown;
12
+ }> {
13
+ }
14
+ /**
15
+ * One message waiting in the outbox: its own id, what it is, which schema
16
+ * shaped it, when it happened, and what it carries.
17
+ */
18
+ export interface OutboxMessage {
19
+ readonly messageId: string;
20
+ readonly eventType: string;
21
+ readonly schemaVersion: number;
22
+ readonly occurredAt: DateTime.Utc;
23
+ readonly payload: {
24
+ readonly [key: string]: unknown;
25
+ };
26
+ }
27
+ /**
28
+ * The outbox holds messages a use case enqueues in the same transaction as
29
+ * its state change. The outbox relay reads and sends them out separately,
30
+ * so "saved" and "announced" never drift apart.
31
+ */
32
+ export interface IntegrationEventOutboxShape {
33
+ readonly enqueue: (messages: readonly OutboxMessage[]) => Effect.Effect<void, IntegrationEventOutboxUnavailableError>;
34
+ readonly pending: (limit: number) => Effect.Effect<readonly OutboxMessage[], IntegrationEventOutboxUnavailableError>;
35
+ readonly markDispatched: (messageIds: readonly string[]) => Effect.Effect<void, IntegrationEventOutboxUnavailableError>;
36
+ }
37
+ declare const IntegrationEventOutbox_base: Context.TagClass<IntegrationEventOutbox, "IntegrationEventOutbox", IntegrationEventOutboxShape>;
38
+ /**
39
+ * The port a use case asks for when it enqueues an event in the same
40
+ * transaction as the state change that caused it.
41
+ */
42
+ export declare class IntegrationEventOutbox extends IntegrationEventOutbox_base {
43
+ }
44
+ export {};
@@ -0,0 +1,13 @@
1
+ import { Context, Data } from 'effect';
2
+ /**
3
+ * The outbox driver did not answer; `operation` names the call and `cause`
4
+ * carries the driver's own error.
5
+ */
6
+ export class IntegrationEventOutboxUnavailableError extends Data.TaggedError('IntegrationEventOutboxUnavailableError') {
7
+ }
8
+ /**
9
+ * The port a use case asks for when it enqueues an event in the same
10
+ * transaction as the state change that caused it.
11
+ */
12
+ export class IntegrationEventOutbox extends Context.Tag('IntegrationEventOutbox')() {
13
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Builds the "did not answer" failure factory around one port's own
3
+ * `<Port>UnavailableError` constructor. An adapter writes
4
+ * `const unavailable = portUnavailable(XUnavailableError)` once, then
5
+ * calls `unavailable('byId')(cause)` on every path that reaches the
6
+ * driver.
7
+ */
8
+ export declare const portUnavailable: <E>(Unavailable: new (fields: {
9
+ readonly operation: string;
10
+ readonly cause: unknown;
11
+ }) => E) => (operation: string) => (cause: unknown) => E;
12
+ /**
13
+ * A port failure named in the event's language rather than as
14
+ * `<Port>UnavailableError`, with the sentence that earns the exception.
15
+ * The list is short on purpose: every member is a place where the
16
+ * uniform name would have told the reader less than the event does.
17
+ * The canon package's mechanism-form rule reads its own copy of this
18
+ * roster, so the two tables are held equal by hand: a name added here
19
+ * has to reach `@satorio/canon` before the guard allows it.
20
+ */
21
+ export declare const PORT_FAILURES_IN_THE_EVENTS_LANGUAGE: Readonly<Record<string, string>>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Builds the "did not answer" failure factory around one port's own
3
+ * `<Port>UnavailableError` constructor. An adapter writes
4
+ * `const unavailable = portUnavailable(XUnavailableError)` once, then
5
+ * calls `unavailable('byId')(cause)` on every path that reaches the
6
+ * driver.
7
+ */
8
+ export const portUnavailable = (Unavailable) => (operation) => (cause) => new Unavailable({ operation, cause });
9
+ /**
10
+ * A port failure named in the event's language rather than as
11
+ * `<Port>UnavailableError`, with the sentence that earns the exception.
12
+ * The list is short on purpose: every member is a place where the
13
+ * uniform name would have told the reader less than the event does.
14
+ * The canon package's mechanism-form rule reads its own copy of this
15
+ * roster, so the two tables are held equal by hand: a name added here
16
+ * has to reach `@satorio/canon` before the guard allows it.
17
+ */
18
+ export const PORT_FAILURES_IN_THE_EVENTS_LANGUAGE = {
19
+ DatabaseDidNotAnswerError: 'the probe has one operation and two named reasons, so `reason` says ' +
20
+ 'more in a log line than `operation` and `cause` ever could.',
21
+ ExternalServiceUnavailableError: 'one process calls several external services through this one port, ' +
22
+ 'so the failure has to say which service went quiet before anybody ' +
23
+ 'can act on it.',
24
+ ExternalServiceRefusedError: 'the service answered, and the status code is the answer: a 404 sends ' +
25
+ 'a caller down a different path than a 403, and `cause` would hide ' +
26
+ 'that behind a word.',
27
+ ExternalServiceResponseMalformedError: 'the service answered and the body did not fit the schema, which is a ' +
28
+ 'different event from silence and asks a different question of ' +
29
+ 'whoever reads it.',
30
+ };
@@ -0,0 +1,57 @@
1
+ import { Context, type DateTime, type Effect } from 'effect';
2
+ declare const ProcessedEventRegistryUnavailableError_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 & {
3
+ readonly _tag: "ProcessedEventRegistryUnavailableError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * The claim-once driver did not answer; `operation` names the call and `cause`
7
+ * carries the driver's own error.
8
+ */
9
+ export declare class ProcessedEventRegistryUnavailableError extends ProcessedEventRegistryUnavailableError_base<{
10
+ readonly operation: string;
11
+ readonly cause: unknown;
12
+ }> {
13
+ }
14
+ /**
15
+ * The two states of the claim-once lock: this run took the event, or somebody
16
+ * already had.
17
+ *
18
+ * The claim-once lock has exactly two states: an event is claimed for the
19
+ * first time, or it was already claimed, and then the timestamp is known.
20
+ */
21
+ export type ProcessedEventClaim = {
22
+ readonly _tag: 'ClaimAccepted';
23
+ } | {
24
+ readonly _tag: 'AlreadyProcessed';
25
+ readonly processedAt: DateTime.Utc;
26
+ };
27
+ /**
28
+ * The claim nobody had taken yet, so this run is the one that does the work.
29
+ */
30
+ export declare const claimAccepted: ProcessedEventClaim;
31
+ /**
32
+ * The claim somebody else already took, with the moment they took it.
33
+ */
34
+ export declare const alreadyProcessed: (processedAt: DateTime.Utc) => ProcessedEventClaim;
35
+ /**
36
+ * What a claim needs: which event is being claimed, and the moment it is
37
+ * claimed at.
38
+ */
39
+ export interface ClaimProcessedEventInput {
40
+ readonly eventId: string;
41
+ readonly processedAt: DateTime.Utc;
42
+ }
43
+ /**
44
+ * What the claim-once lock offers: one call that either takes an event for the
45
+ * first time or says when it was taken before.
46
+ */
47
+ export interface ProcessedEventRegistryShape {
48
+ readonly claim: (input: ClaimProcessedEventInput) => Effect.Effect<ProcessedEventClaim, ProcessedEventRegistryUnavailableError>;
49
+ }
50
+ declare const ProcessedEventRegistry_base: Context.TagClass<ProcessedEventRegistry, "ProcessedEventRegistry", ProcessedEventRegistryShape>;
51
+ /**
52
+ * The port a use case asks for when an event must be acted on exactly once,
53
+ * however many times it arrives.
54
+ */
55
+ export declare class ProcessedEventRegistry extends ProcessedEventRegistry_base {
56
+ }
57
+ export {};
@@ -0,0 +1,24 @@
1
+ import { Context, Data } from 'effect';
2
+ /**
3
+ * The claim-once driver did not answer; `operation` names the call and `cause`
4
+ * carries the driver's own error.
5
+ */
6
+ export class ProcessedEventRegistryUnavailableError extends Data.TaggedError('ProcessedEventRegistryUnavailableError') {
7
+ }
8
+ /**
9
+ * The claim nobody had taken yet, so this run is the one that does the work.
10
+ */
11
+ export const claimAccepted = { _tag: 'ClaimAccepted' };
12
+ /**
13
+ * The claim somebody else already took, with the moment they took it.
14
+ */
15
+ export const alreadyProcessed = (processedAt) => ({
16
+ _tag: 'AlreadyProcessed',
17
+ processedAt,
18
+ });
19
+ /**
20
+ * The port a use case asks for when an event must be acted on exactly once,
21
+ * however many times it arrives.
22
+ */
23
+ export class ProcessedEventRegistry extends Context.Tag('ProcessedEventRegistry')() {
24
+ }