@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,70 @@
1
+ import { Effect, Exit } from 'effect';
2
+ /**
3
+ * The path that answers whether this process is alive at all, without checking
4
+ * a single dependency.
5
+ */
6
+ export declare const LIVEZ_PATH = "/livez";
7
+ /**
8
+ * The path that answers whether this service can take traffic, after every
9
+ * mounted dependency has been asked.
10
+ */
11
+ export declare const READYZ_PATH = "/readyz";
12
+ /**
13
+ * Same check as READYZ_PATH, under a second name. Orchestrators expect
14
+ * different words for the same question: can you send traffic here.
15
+ */
16
+ export declare const HEALTHZ_PATH = "/healthz";
17
+ /**
18
+ * How one dependency came back: it answered, or it is down.
19
+ */
20
+ export type HealthCheckStatus = 'ok' | 'down';
21
+ /**
22
+ * One dependency to check, under the name the answer reports it by.
23
+ */
24
+ export interface NamedHealthCheck<R> {
25
+ readonly name: string;
26
+ readonly verify: Effect.Effect<void, unknown, R>;
27
+ }
28
+ /**
29
+ * What the readiness endpoint answers: whether the service is ready, and how
30
+ * each dependency came back.
31
+ */
32
+ export interface ReadinessOutcome {
33
+ readonly ready: boolean;
34
+ readonly checks: Readonly<Record<string, HealthCheckStatus>>;
35
+ }
36
+ /**
37
+ * Runs a readiness check and returns its Exit. A resolver borrows the same
38
+ * shape from the runtime as the GraphQL context does, so both sides of the
39
+ * machinery talk to the runtime through one interface.
40
+ */
41
+ export type RunHealthCheck<R> = <A, E>(program: Effect.Effect<A, E, R>) => Promise<Exit.Exit<A, E>>;
42
+ /**
43
+ * How long one check gets before it counts as down. Without a deadline a
44
+ * check that hangs, rather than failing outright, keeps /readyz open
45
+ * indefinitely instead of returning in time.
46
+ */
47
+ export declare const DEFAULT_HEALTH_CHECK_DEADLINE_MILLIS = 3000;
48
+ /**
49
+ * What the readiness routes need: the runtime that runs a check, the checks
50
+ * themselves, and the deadline one check gets.
51
+ */
52
+ export interface HealthRoutesOptions<R> {
53
+ readonly runCheck: RunHealthCheck<R>;
54
+ readonly checks: readonly NamedHealthCheck<R>[];
55
+ readonly checkDeadlineMillis?: number;
56
+ }
57
+ /**
58
+ * Runs every check independently, in parallel, under its own deadline. One
59
+ * dependency that fails or hangs does not hide the others' results and does
60
+ * not hold /readyz open past checkDeadlineMillis. An empty checks list
61
+ * reports ready: true — an app with no mounted dependencies is ready by
62
+ * itself.
63
+ */
64
+ export declare const checkReadiness: <R>(options: HealthRoutesOptions<R>) => Effect.Effect<ReadinessOutcome>;
65
+ /**
66
+ * Handles the three readiness endpoints. Returns null on any other path, so
67
+ * the caller passes the request on down its own chain — one Bun.serve
68
+ * handler can then serve both readiness probes and GraphQL.
69
+ */
70
+ export declare const healthRoutesFetch: <R>(options: HealthRoutesOptions<R>) => ((request: Request) => Promise<Response | null>);
@@ -0,0 +1,60 @@
1
+ import { Duration, Effect, Exit } from 'effect';
2
+ /**
3
+ * The path that answers whether this process is alive at all, without checking
4
+ * a single dependency.
5
+ */
6
+ export const LIVEZ_PATH = '/livez';
7
+ /**
8
+ * The path that answers whether this service can take traffic, after every
9
+ * mounted dependency has been asked.
10
+ */
11
+ export const READYZ_PATH = '/readyz';
12
+ /**
13
+ * Same check as READYZ_PATH, under a second name. Orchestrators expect
14
+ * different words for the same question: can you send traffic here.
15
+ */
16
+ export const HEALTHZ_PATH = '/healthz';
17
+ /**
18
+ * How long one check gets before it counts as down. Without a deadline a
19
+ * check that hangs, rather than failing outright, keeps /readyz open
20
+ * indefinitely instead of returning in time.
21
+ */
22
+ export const DEFAULT_HEALTH_CHECK_DEADLINE_MILLIS = 3_000;
23
+ const oneCheckOutcome = (runCheck, check, deadlineMillis) => Effect.promise(() => runCheck(check.verify.pipe(Effect.timeout(Duration.millis(deadlineMillis))))).pipe(Effect.map((exit) => [check.name, Exit.isSuccess(exit) ? 'ok' : 'down']));
24
+ /**
25
+ * Runs every check independently, in parallel, under its own deadline. One
26
+ * dependency that fails or hangs does not hide the others' results and does
27
+ * not hold /readyz open past checkDeadlineMillis. An empty checks list
28
+ * reports ready: true — an app with no mounted dependencies is ready by
29
+ * itself.
30
+ */
31
+ export const checkReadiness = (options) => {
32
+ const deadlineMillis = options.checkDeadlineMillis ?? DEFAULT_HEALTH_CHECK_DEADLINE_MILLIS;
33
+ return Effect.forEach(options.checks, (check) => oneCheckOutcome(options.runCheck, check, deadlineMillis), { concurrency: 'unbounded' }).pipe(Effect.map((pairs) => {
34
+ const checks = Object.fromEntries(pairs);
35
+ const ready = pairs.every(([, status]) => status === 'ok');
36
+ return { ready, checks };
37
+ }));
38
+ };
39
+ const jsonResponse = (status, body) => new Response(JSON.stringify(body), {
40
+ status,
41
+ headers: { 'content-type': 'application/json' },
42
+ });
43
+ /**
44
+ * Handles the three readiness endpoints. Returns null on any other path, so
45
+ * the caller passes the request on down its own chain — one Bun.serve
46
+ * handler can then serve both readiness probes and GraphQL.
47
+ */
48
+ export const healthRoutesFetch = (options) => {
49
+ return async (request) => {
50
+ const url = new URL(request.url);
51
+ if (url.pathname === LIVEZ_PATH) {
52
+ return jsonResponse(200, { status: 'ok' });
53
+ }
54
+ if (url.pathname === READYZ_PATH || url.pathname === HEALTHZ_PATH) {
55
+ const outcome = await Effect.runPromise(checkReadiness(options));
56
+ return jsonResponse(outcome.ready ? 200 : 503, outcome);
57
+ }
58
+ return null;
59
+ };
60
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Public entry to the http mechanism: readiness probes mounted on the same port
3
+ * as GraphQL. See machinery/graphql/server.ts for where they attach.
4
+ */
5
+ export { checkReadiness, DEFAULT_HEALTH_CHECK_DEADLINE_MILLIS, HEALTHZ_PATH, type HealthCheckStatus, type HealthRoutesOptions, healthRoutesFetch, LIVEZ_PATH, type NamedHealthCheck, READYZ_PATH, type ReadinessOutcome, type RunHealthCheck, } from './health.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Public entry to the http mechanism: readiness probes mounted on the same port
3
+ * as GraphQL. See machinery/graphql/server.ts for where they attach.
4
+ */
5
+ export { checkReadiness, DEFAULT_HEALTH_CHECK_DEADLINE_MILLIS, HEALTHZ_PATH, healthRoutesFetch, LIVEZ_PATH, READYZ_PATH, } from './health.js';
@@ -0,0 +1,37 @@
1
+ import { Effect, Either } from 'effect';
2
+ import { NotAClientCodeError } from './failures.js';
3
+ declare const clientCodeBrand: unique symbol;
4
+ /**
5
+ * The number a client quotes back to you: eight digits, the last of which
6
+ * checks the other seven. It is a label and never an identity — the
7
+ * identity of an account is its own identifier — and it is never a key of
8
+ * anything either, so knowing one opens nothing.
9
+ */
10
+ export type ClientCode = string & {
11
+ readonly [clientCodeBrand]: 'ClientCode';
12
+ };
13
+ /**
14
+ * A fresh client code, drawn from the randomness the service already
15
+ * shares. The seven drawn digits never start with a zero, so the code
16
+ * reads back the same whether a person writes it or a spreadsheet does,
17
+ * and the eighth digit is the check the whole code stands on. Nothing
18
+ * here counts: two codes issued one after the other say nothing about
19
+ * how many clients came between them.
20
+ */
21
+ export declare const newClientCode: Effect.Effect<ClientCode>;
22
+ /**
23
+ * Reads a client code somebody typed, forgiving the spaces and hyphens a
24
+ * person puts between the groups. A code whose check digit does not hold
25
+ * comes back as a refusal, and the refusal names no character.
26
+ */
27
+ export declare const clientCodeFrom: (text: string) => Either.Either<ClientCode, NotAClientCodeError>;
28
+ /**
29
+ * The eight digits with nothing between them, which is the form a
30
+ * document number and a payment reference are built from.
31
+ */
32
+ export declare const digitsOfClientCode: (code: ClientCode) => string;
33
+ /**
34
+ * The form a person reads off a document: two groups of four.
35
+ */
36
+ export declare const clientCodeInGroupedForm: (code: ClientCode) => string;
37
+ export {};
@@ -0,0 +1,41 @@
1
+ import { Effect, Either, Random } from 'effect';
2
+ import { dammHolds, withDammCheckDigit } from './damm.js';
3
+ import { NotAClientCodeError } from './failures.js';
4
+ const DRAWN_DIGITS = 7;
5
+ const EIGHT_DIGITS_WITHOUT_A_LEADING_ZERO = /^[1-9]\d{7}$/;
6
+ const NOT_A_DIGIT = /[\s-]+/g;
7
+ const GROUP = 4;
8
+ /**
9
+ * A fresh client code, drawn from the randomness the service already
10
+ * shares. The seven drawn digits never start with a zero, so the code
11
+ * reads back the same whether a person writes it or a spreadsheet does,
12
+ * and the eighth digit is the check the whole code stands on. Nothing
13
+ * here counts: two codes issued one after the other say nothing about
14
+ * how many clients came between them.
15
+ */
16
+ export const newClientCode = Effect.gen(function* () {
17
+ const first = yield* Random.nextIntBetween(1, 10);
18
+ const rest = yield* Effect.replicateEffect(Random.nextIntBetween(0, 10), DRAWN_DIGITS - 1);
19
+ const drawn = `${first}${rest.join('')}`;
20
+ return (withDammCheckDigit(drawn) ?? drawn);
21
+ });
22
+ /**
23
+ * Reads a client code somebody typed, forgiving the spaces and hyphens a
24
+ * person puts between the groups. A code whose check digit does not hold
25
+ * comes back as a refusal, and the refusal names no character.
26
+ */
27
+ export const clientCodeFrom = (text) => {
28
+ const digits = text.replace(NOT_A_DIGIT, '');
29
+ return EIGHT_DIGITS_WITHOUT_A_LEADING_ZERO.test(digits) && dammHolds(digits)
30
+ ? Either.right(digits)
31
+ : Either.left(new NotAClientCodeError({ text }));
32
+ };
33
+ /**
34
+ * The eight digits with nothing between them, which is the form a
35
+ * document number and a payment reference are built from.
36
+ */
37
+ export const digitsOfClientCode = (code) => code;
38
+ /**
39
+ * The form a person reads off a document: two groups of four.
40
+ */
41
+ export const clientCodeInGroupedForm = (code) => `${code.slice(0, GROUP)}-${code.slice(GROUP)}`;
@@ -0,0 +1,38 @@
1
+ import { Either } from 'effect';
2
+ import type { DocumentNumber } from './document-number.js';
3
+ import { NotACreditorReferenceError } from './failures.js';
4
+ declare const creditorReferenceBrand: unique symbol;
5
+ /**
6
+ * The reference a payer copies into a bank transfer, with its own check
7
+ * digits.
8
+ *
9
+ * The reference a payer copies into their bank transfer: the letters `RF`, two
10
+ * check digits over everything after them, and the digits of the document
11
+ * number. It follows ISO 11649, so a bank anywhere reads it and a typo in it
12
+ * does not reach anybody's ledger.
13
+ */
14
+ export type CreditorReference = string & {
15
+ readonly [creditorReferenceBrand]: 'CreditorReference';
16
+ };
17
+ /**
18
+ * The payment reference for a document that somebody has to pay.
19
+ */
20
+ export declare const creditorReferenceOf: (number: DocumentNumber) => CreditorReference;
21
+ /**
22
+ * Reads a reference somebody typed, forgiving case, spaces and the
23
+ * hyphens a person copies along with it. A reference whose check digits
24
+ * do not hold comes back as a refusal that names no character: the
25
+ * payer retypes the whole reference, and nobody guessing at references
26
+ * learns which part they got closest on.
27
+ */
28
+ export declare const creditorReferenceFrom: (text: string) => Either.Either<CreditorReference, NotACreditorReferenceError>;
29
+ /**
30
+ * The digits of the document number this reference points at.
31
+ */
32
+ export declare const digitsOfCreditorReference: (reference: CreditorReference) => string;
33
+ /**
34
+ * The form a person reads off a document and types into a bank: groups
35
+ * of four, the way ISO 11649 prints one.
36
+ */
37
+ export declare const creditorReferenceInGroupedForm: (reference: CreditorReference) => string;
38
+ export {};
@@ -0,0 +1,32 @@
1
+ import { Either } from 'effect';
2
+ import { generate, parse } from 'node-iso11649';
3
+ import { digitsOfDocumentNumber } from './document-number.js';
4
+ import { NotACreditorReferenceError } from './failures.js';
5
+ const NOT_A_REFERENCE_CHARACTER = /[\s-]+/g;
6
+ const GROUP = 4;
7
+ /**
8
+ * The payment reference for a document that somebody has to pay.
9
+ */
10
+ export const creditorReferenceOf = (number) => generate(digitsOfDocumentNumber(number));
11
+ /**
12
+ * Reads a reference somebody typed, forgiving case, spaces and the
13
+ * hyphens a person copies along with it. A reference whose check digits
14
+ * do not hold comes back as a refusal that names no character: the
15
+ * payer retypes the whole reference, and nobody guessing at references
16
+ * learns which part they got closest on.
17
+ */
18
+ export const creditorReferenceFrom = (text) => {
19
+ const written = text.replace(NOT_A_REFERENCE_CHARACTER, '').toUpperCase();
20
+ return parse(written) === null
21
+ ? Either.left(new NotACreditorReferenceError({ text }))
22
+ : Either.right(written);
23
+ };
24
+ /**
25
+ * The digits of the document number this reference points at.
26
+ */
27
+ export const digitsOfCreditorReference = (reference) => reference.slice(GROUP);
28
+ /**
29
+ * The form a person reads off a document and types into a bank: groups
30
+ * of four, the way ISO 11649 prints one.
31
+ */
32
+ export const creditorReferenceInGroupedForm = (reference) => (reference.match(/.{1,4}/g) ?? [reference]).join(' ');
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The check digit that makes a run of digits self-checking, by Damm's
3
+ * algorithm. The table above is the order-ten totally anti-symmetric
4
+ * quasigroup of the 2004 paper *Total anti-symmetrische Quasigruppen*
5
+ * (Philipps-Universitat Marburg), which is what makes the digit catch
6
+ * every single wrong digit and every swap of two neighbours. A text
7
+ * holding anything but digits gets `null` — the caller turns that into
8
+ * its own refusal.
9
+ *
10
+ * No package on the registry carries this algorithm at a version a
11
+ * service should depend on, so it stands here as one pure function with
12
+ * its source named, rather than as an unmaintained peer dependency.
13
+ */
14
+ export declare const dammCheckDigit: (digits: string) => string | null;
15
+ /**
16
+ * The same digits with their check digit written on the end.
17
+ */
18
+ export declare const withDammCheckDigit: (digits: string) => string | null;
19
+ /**
20
+ * Whether a run of digits already carries a check digit that holds.
21
+ */
22
+ export declare const dammHolds: (digits: string) => boolean;
@@ -0,0 +1,50 @@
1
+ const OPERATION_TABLE = [
2
+ [0, 3, 1, 7, 5, 9, 8, 6, 4, 2],
3
+ [7, 0, 9, 2, 1, 5, 4, 8, 6, 3],
4
+ [4, 2, 0, 6, 8, 7, 1, 3, 5, 9],
5
+ [1, 7, 5, 0, 9, 8, 3, 4, 2, 6],
6
+ [6, 1, 2, 3, 0, 4, 5, 9, 7, 8],
7
+ [3, 6, 7, 4, 2, 0, 9, 5, 8, 1],
8
+ [5, 8, 6, 9, 7, 2, 0, 1, 3, 4],
9
+ [8, 9, 4, 5, 3, 6, 2, 0, 1, 7],
10
+ [9, 4, 3, 8, 6, 1, 7, 2, 0, 5],
11
+ [2, 5, 8, 1, 4, 3, 6, 7, 9, 0],
12
+ ];
13
+ const ONLY_DIGITS = /^\d+$/;
14
+ const interimOf = (digits) => {
15
+ if (!ONLY_DIGITS.test(digits))
16
+ return null;
17
+ let row = 0;
18
+ for (const digit of digits) {
19
+ row = OPERATION_TABLE[row]?.[Number(digit)] ?? 0;
20
+ }
21
+ return row;
22
+ };
23
+ /**
24
+ * The check digit that makes a run of digits self-checking, by Damm's
25
+ * algorithm. The table above is the order-ten totally anti-symmetric
26
+ * quasigroup of the 2004 paper *Total anti-symmetrische Quasigruppen*
27
+ * (Philipps-Universitat Marburg), which is what makes the digit catch
28
+ * every single wrong digit and every swap of two neighbours. A text
29
+ * holding anything but digits gets `null` — the caller turns that into
30
+ * its own refusal.
31
+ *
32
+ * No package on the registry carries this algorithm at a version a
33
+ * service should depend on, so it stands here as one pure function with
34
+ * its source named, rather than as an unmaintained peer dependency.
35
+ */
36
+ export const dammCheckDigit = (digits) => {
37
+ const interim = interimOf(digits);
38
+ return interim === null ? null : String(interim);
39
+ };
40
+ /**
41
+ * The same digits with their check digit written on the end.
42
+ */
43
+ export const withDammCheckDigit = (digits) => {
44
+ const check = dammCheckDigit(digits);
45
+ return check === null ? null : `${digits}${check}`;
46
+ };
47
+ /**
48
+ * Whether a run of digits already carries a check digit that holds.
49
+ */
50
+ export const dammHolds = (digits) => interimOf(digits) === 0;
@@ -0,0 +1,68 @@
1
+ import type { ClosedSet } from '@satorio/machinery/core';
2
+ import { type CalendarDay } from '@satorio/machinery/time';
3
+ import { Either } from 'effect';
4
+ import { type ClientCode } from './client-code.js';
5
+ import { NotADocumentNumberError } from './failures.js';
6
+ declare const documentNumberBrand: unique symbol;
7
+ /**
8
+ * The number printed on a document, in the form a person reads it.
9
+ *
10
+ * The number printed on a document: its series, the client code, the reporting
11
+ * month as two digits of year and two of month, and the count of documents
12
+ * that client has been sent that month.
13
+ */
14
+ export type DocumentNumber = string & {
15
+ readonly [documentNumberBrand]: 'DocumentNumber';
16
+ };
17
+ /**
18
+ * What a document number is made of. The count is shared across every
19
+ * series, so a client never meets two documents carrying the same digits
20
+ * in one month.
21
+ */
22
+ export interface DocumentNumberParts<Series extends string = string> {
23
+ readonly series: Series;
24
+ readonly clientCode: ClientCode;
25
+ readonly reportingMonth: CalendarDay;
26
+ readonly count: number;
27
+ }
28
+ /**
29
+ * The two digits of year and two of month a reporting period is written
30
+ * as: March 2026 reads `2603`.
31
+ */
32
+ export declare const reportingMonthOf: (day: CalendarDay) => string;
33
+ /**
34
+ * Builds a document number out of its parts. A count below one, or one
35
+ * that is no whole number, comes back as a refusal: a document nobody
36
+ * counted has no number.
37
+ *
38
+ * @internal
39
+ */
40
+ export declare const documentNumberOf: (parts: DocumentNumberParts) => Either.Either<DocumentNumber, NotADocumentNumberError>;
41
+ /**
42
+ * Reads a document number somebody typed against the series a service
43
+ * issues. The series has to stand in that set, and the client code
44
+ * inside the number has to pass its own check digit, so a number
45
+ * invented by hand does not read back.
46
+ *
47
+ * @internal
48
+ */
49
+ export declare const documentNumberReadFrom: (text: string, series: ClosedSet<readonly string[]>) => Either.Either<DocumentNumber, NotADocumentNumberError>;
50
+ /**
51
+ * The series this document belongs to, as the number itself spells it.
52
+ *
53
+ * @internal
54
+ */
55
+ export declare const seriesOfDocumentNumber: (number: DocumentNumber) => string;
56
+ /**
57
+ * The digits of a document number with the series and the hyphens taken
58
+ * off, which is what a payment reference is built over.
59
+ */
60
+ export declare const digitsOfDocumentNumber: (number: DocumentNumber) => string;
61
+ /**
62
+ * The client code printed inside a document number. Every document
63
+ * number that exists was either built from a client code or read back
64
+ * through that code's own check digit, so the eight digits at the front
65
+ * of one are always a code that holds.
66
+ */
67
+ export declare const clientCodeOfDocumentNumber: (number: DocumentNumber) => ClientCode;
68
+ export {};
@@ -0,0 +1,73 @@
1
+ import { dayInIsoForm } from '@satorio/machinery/time';
2
+ import { Either } from 'effect';
3
+ import { clientCodeFrom, clientCodeInGroupedForm, } from './client-code.js';
4
+ import { NotADocumentNumberError } from './failures.js';
5
+ const SMALLEST_COUNT = 1;
6
+ const COUNT_DIGITS = 2;
7
+ const CLIENT_CODE_DIGITS = 8;
8
+ const WRITTEN_FORM = /^([A-Z]{2,3})-(\d{4})-(\d{4})-(\d{4})-(\d{2,})$/;
9
+ const YEAR_IN_MONTH = 4;
10
+ const NOT_A_DIGIT = /[\s-]+/g;
11
+ /**
12
+ * The two digits of year and two of month a reporting period is written
13
+ * as: March 2026 reads `2603`.
14
+ */
15
+ export const reportingMonthOf = (day) => {
16
+ const iso = dayInIsoForm(day);
17
+ return `${iso.slice(2, YEAR_IN_MONTH)}${iso.slice(5, 7)}`;
18
+ };
19
+ /**
20
+ * Builds a document number out of its parts. A count below one, or one
21
+ * that is no whole number, comes back as a refusal: a document nobody
22
+ * counted has no number.
23
+ *
24
+ * @internal
25
+ */
26
+ export const documentNumberOf = (parts) => {
27
+ const counted = Number.isInteger(parts.count) && parts.count >= SMALLEST_COUNT;
28
+ const count = String(parts.count).padStart(COUNT_DIGITS, '0');
29
+ const written = `${parts.series}-${clientCodeInGroupedForm(parts.clientCode)}` +
30
+ `-${reportingMonthOf(parts.reportingMonth)}-${count}`;
31
+ return counted
32
+ ? Either.right(written)
33
+ : Either.left(new NotADocumentNumberError({ text: written }));
34
+ };
35
+ /**
36
+ * Reads a document number somebody typed against the series a service
37
+ * issues. The series has to stand in that set, and the client code
38
+ * inside the number has to pass its own check digit, so a number
39
+ * invented by hand does not read back.
40
+ *
41
+ * @internal
42
+ */
43
+ export const documentNumberReadFrom = (text, series) => {
44
+ const written = text.trim().toUpperCase();
45
+ const parts = WRITTEN_FORM.exec(written);
46
+ const refused = Either.left(new NotADocumentNumberError({ text }));
47
+ if (parts === null)
48
+ return refused;
49
+ const [, written_series = '', first = '', second = ''] = parts;
50
+ if (!series.is(written_series))
51
+ return refused;
52
+ return Either.isRight(clientCodeFrom(`${first}${second}`))
53
+ ? Either.right(written)
54
+ : refused;
55
+ };
56
+ /**
57
+ * The series this document belongs to, as the number itself spells it.
58
+ *
59
+ * @internal
60
+ */
61
+ export const seriesOfDocumentNumber = (number) => number.slice(0, number.indexOf('-'));
62
+ /**
63
+ * The digits of a document number with the series and the hyphens taken
64
+ * off, which is what a payment reference is built over.
65
+ */
66
+ export const digitsOfDocumentNumber = (number) => number.slice(number.indexOf('-') + 1).replace(NOT_A_DIGIT, '');
67
+ /**
68
+ * The client code printed inside a document number. Every document
69
+ * number that exists was either built from a client code or read back
70
+ * through that code's own check digit, so the eight digits at the front
71
+ * of one are always a code that holds.
72
+ */
73
+ export const clientCodeOfDocumentNumber = (number) => digitsOfDocumentNumber(number).slice(0, CLIENT_CODE_DIGITS);
@@ -0,0 +1,27 @@
1
+ import type { ClosedSet } from '@satorio/machinery/core';
2
+ import type { DocumentNumberCounter, DocumentNumberCounterUnavailableError } from '@satorio/machinery/ports';
3
+ import type { Effect, Either } from 'effect';
4
+ import { type DocumentNumber, type DocumentNumberParts } from './document-number.js';
5
+ import type { NotADocumentNumberError } from './failures.js';
6
+ import { type NextDocumentNumberInput } from './next-document-number.js';
7
+ /**
8
+ * The document numbers of one closed set of series: minting bound to
9
+ * that set, reading that refuses any series outside it, and the set
10
+ * itself, so a caller lists its own series in one place and reads them
11
+ * back from the same one.
12
+ */
13
+ export interface DocumentNumbers<Series extends readonly string[]> {
14
+ readonly series: ClosedSet<Series>;
15
+ readonly of: (parts: DocumentNumberParts<Series[number]>) => Either.Either<DocumentNumber, NotADocumentNumberError>;
16
+ readonly from: (text: string) => Either.Either<DocumentNumber, NotADocumentNumberError>;
17
+ readonly seriesOf: (number: DocumentNumber) => Series[number];
18
+ readonly next: (input: NextDocumentNumberInput<Series[number]>) => Effect.Effect<DocumentNumber, DocumentNumberCounterUnavailableError, DocumentNumberCounter>;
19
+ }
20
+ /**
21
+ * Binds document numbers to the series one service issues. Which kinds
22
+ * of document exist is that service's own canon, never this package's:
23
+ * a proforma, a monthly invoice and a credit note belong to whoever
24
+ * sends them, and a package that hard-codes those four sends every
25
+ * other business back to writing its own numbering.
26
+ */
27
+ export declare const makeDocumentNumbers: <const Series extends readonly string[]>(series: ClosedSet<Series>) => DocumentNumbers<Series>;
@@ -0,0 +1,16 @@
1
+ import { documentNumberOf, documentNumberReadFrom, seriesOfDocumentNumber, } from './document-number.js';
2
+ import { nextDocumentNumber, } from './next-document-number.js';
3
+ /**
4
+ * Binds document numbers to the series one service issues. Which kinds
5
+ * of document exist is that service's own canon, never this package's:
6
+ * a proforma, a monthly invoice and a credit note belong to whoever
7
+ * sends them, and a package that hard-codes those four sends every
8
+ * other business back to writing its own numbering.
9
+ */
10
+ export const makeDocumentNumbers = (series) => ({
11
+ series,
12
+ of: (parts) => documentNumberOf(parts),
13
+ from: (text) => documentNumberReadFrom(text, series),
14
+ seriesOf: (number) => seriesOfDocumentNumber(number),
15
+ next: (input) => nextDocumentNumber(input),
16
+ });
@@ -0,0 +1,46 @@
1
+ import type { Refusal } from '@satorio/machinery/core';
2
+ declare const NotAClientCodeError_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: "NotAClientCodeError";
4
+ } & Readonly<A>;
5
+ /**
6
+ * The text handed in is not a client code. The refusal never says which
7
+ * character failed: a client code is a public label, and a message that
8
+ * narrows the search helps whoever is guessing at codes more than it
9
+ * helps the person who typed one wrong.
10
+ */
11
+ export declare class NotAClientCodeError extends NotAClientCodeError_base<{
12
+ readonly text: string;
13
+ }> {
14
+ get refusal(): Refusal;
15
+ }
16
+ declare const NotADocumentNumberError_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 & {
17
+ readonly _tag: "NotADocumentNumberError";
18
+ } & Readonly<A>;
19
+ /**
20
+ * The parts handed in cannot make a document number, or the text handed
21
+ * in does not read as one.
22
+ */
23
+ export declare class NotADocumentNumberError extends NotADocumentNumberError_base<{
24
+ readonly text: string;
25
+ }> {
26
+ get refusal(): Refusal;
27
+ }
28
+ declare const NotACreditorReferenceError_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: "NotACreditorReferenceError";
30
+ } & Readonly<A>;
31
+ /**
32
+ * The text handed in is not a payment reference this mechanism issued.
33
+ * Like a client code, the refusal names no character: whoever typed one
34
+ * wrong retypes the whole reference, and whoever is guessing learns
35
+ * nothing.
36
+ */
37
+ export declare class NotACreditorReferenceError extends NotACreditorReferenceError_base<{
38
+ readonly text: string;
39
+ }> {
40
+ get refusal(): Refusal;
41
+ }
42
+ /**
43
+ * Every way this mechanism refuses a value.
44
+ */
45
+ export type IdentifierFailure = NotAClientCodeError | NotADocumentNumberError | NotACreditorReferenceError;
46
+ export {};
@@ -0,0 +1,48 @@
1
+ import { Data } from 'effect';
2
+ /**
3
+ * The text handed in is not a client code. The refusal never says which
4
+ * character failed: a client code is a public label, and a message that
5
+ * narrows the search helps whoever is guessing at codes more than it
6
+ * helps the person who typed one wrong.
7
+ */
8
+ export class NotAClientCodeError extends Data.TaggedError('NotAClientCodeError') {
9
+ get refusal() {
10
+ return {
11
+ what: `${JSON.stringify(this.text)} is not a client code.`,
12
+ why: 'A client code is eight digits, the last of which checks the other ' +
13
+ 'seven, and this text does not pass that check.',
14
+ whatToDo: 'Read the code off the document again, keeping all eight digits, ' +
15
+ 'then hand it back.',
16
+ };
17
+ }
18
+ }
19
+ /**
20
+ * The parts handed in cannot make a document number, or the text handed
21
+ * in does not read as one.
22
+ */
23
+ export class NotADocumentNumberError extends Data.TaggedError('NotADocumentNumberError') {
24
+ get refusal() {
25
+ return {
26
+ what: `${JSON.stringify(this.text)} is not a document number.`,
27
+ why: 'A document number is a series, a client code, the reporting month ' +
28
+ 'as four digits, and a count, joined by hyphens.',
29
+ whatToDo: 'Write it as INV-4173-8297-2609-02, then hand it back.',
30
+ };
31
+ }
32
+ }
33
+ /**
34
+ * The text handed in is not a payment reference this mechanism issued.
35
+ * Like a client code, the refusal names no character: whoever typed one
36
+ * wrong retypes the whole reference, and whoever is guessing learns
37
+ * nothing.
38
+ */
39
+ export class NotACreditorReferenceError extends Data.TaggedError('NotACreditorReferenceError') {
40
+ get refusal() {
41
+ return {
42
+ what: `${JSON.stringify(this.text)} is not a payment reference that exists.`,
43
+ why: 'A payment reference carries its own two check digits, and this ' +
44
+ 'text does not pass them.',
45
+ whatToDo: 'Copy the reference from the document again, then hand it back.',
46
+ };
47
+ }
48
+ }