@hyperscale0/adl 1.0.0-alpha.2 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from 1.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.0.0-beta.2] - 2026-09-10
10
+
11
+ - Republished against UDL 2.0.0. No package behavior changes from
12
+ 1.0.0-beta.1.
13
+
14
+ ## [1.0.0-beta.1] - 2026-08-29
15
+
16
+ - This is the first beta and has no package behavior changes from
17
+ 1.0.0-alpha.2.
18
+
9
19
  ## [1.0.0-alpha.2] - 2026-08-26
10
20
 
11
21
  ### Removed
@@ -54,6 +64,7 @@ write an adapter in; an adapter is still what you write.
54
64
  the exported types derived from them, so the published schema cannot drift
55
65
  from the type checker. No exported type changed shape.
56
66
 
57
- [Unreleased]: https://github.com/hyperscale0/hyperscale-adl/compare/v1.0.0-alpha.2...HEAD
67
+ [Unreleased]: https://github.com/hyperscale0/hyperscale-adl/compare/v1.0.0-beta.1...HEAD
68
+ [1.0.0-beta.1]: https://github.com/hyperscale0/hyperscale-adl/compare/v1.0.0-alpha.2...v1.0.0-beta.1
58
69
  [1.0.0-alpha.2]: https://github.com/hyperscale0/hyperscale-adl/compare/v1.0.0-alpha.1...v1.0.0-alpha.2
59
70
  [1.0.0-alpha.1]: https://github.com/hyperscale0/hyperscale-adl/releases/tag/v1.0.0-alpha.1
package/README.md CHANGED
@@ -1,37 +1,18 @@
1
- # ADL
1
+ ![ADL: Declare how a bank or provider behaves.](docs/assets/adl.svg)
2
2
 
3
- ADL, the Adapter Declaration Language: the format for describing a bank or
4
- provider to Hyperscale, the validator that refuses a declaration the runtime
5
- could not operate, and the conformance suite that says when one is ready to
6
- serve live money.
3
+ # ADL
7
4
 
8
- It is the third of three. UDL describes the product, HSX scripts the money
9
- movement, ADL declares the provider the money moves through.
5
+ ADL is the Adapter Declaration Language: the public format for declaring how a bank or provider behaves at the control-plane boundary. Its validator and conformance suite refuse incomplete interface facts before a generic runtime can poll, classify, reconcile, or deduplicate provider results. The three language boundaries stay separate: HSX authors settlement behavior, UDL defines the canonical product contract, and ADL declares how an external provider performs or confirms work behind that contract.
10
6
 
11
- **Status: alpha.** `1.0.0-alpha.1`. The surface can still change on a minor
12
- version until 1.0.0.
7
+ **Status: beta.** Current release is 1.0.0-beta.1. Pre-1.0 releases can change on minor versions until 1.0.0.
13
8
 
14
9
  ## Adapter symmetry
15
10
 
16
- Hyperscale's own bank adapters are written against this package and nothing
17
- more. There is no private adapter API and no second interface for first-party
18
- code. When one of our adapters needs a seam ADL lacks, the seam is added here,
19
- in public, or it is not added.
20
-
21
- So the guide below is not a simplified account of how we do it. It is how we
22
- do it.
11
+ Hyperscale first-party bank adapters are written against this package and nothing more. There is no private adapter API and no second interface for first-party code. When an adapter needs a seam ADL lacks, the seam is added here, in public, or not at all.
23
12
 
24
- ## What an adapter is
13
+ An adapter is a declaration, not a client. It is a plain object stating what the provider does: which commands exist, how responses classify, what bank status tokens mean, when statements can be fetched, and which reference returns on a debit. The generic execution runtime ships with the platform. An adapter opens no sockets, holds no credentials, and decides nothing about what a payment means.
25
14
 
26
- A declaration, not a client. A plain object saying what the provider does:
27
- which commands exist, how each response classifies, what the bank's status
28
- tokens mean, when statements can be fetched, which reference comes back on a
29
- debit. The runtime that executes it is generic and ships with the platform.
30
-
31
- Your adapter opens no sockets, holds no credentials, and decides nothing about
32
- what a payment means. It states facts, and the checks in this package prove
33
- those facts are complete enough for a generic runtime to poll, classify,
34
- reconcile, and dedupe without guessing.
15
+ Conformance checks a declaration. It does not contact a bank, verify a credential, certify regulatory readiness, or make a Product live.
35
16
 
36
17
  ## Install
37
18
 
@@ -39,13 +20,11 @@ reconcile, and dedupe without guessing.
39
20
  npm install @hyperscale0/adl
40
21
  ```
41
22
 
42
- Every release before 1.0.0 is an alpha, and `latest` follows the newest one, so
43
- a bare install gets it. Pin an exact version if you need one: until 1.0.0 a
44
- change to the surface ships as a minor bump, not a major.
23
+ Pre-1.0 releases are prerelease versions (alpha and beta). Pin an exact version if needed: until 1.0.0, a change to the surface ships as a minor bump, not a major. The package has no runtime dependencies.
45
24
 
46
- No runtime dependencies, and no proprietary code imported.
25
+ ## Adapter declaration
47
26
 
48
- ## The thirty-second shape
27
+ A provider adapter declaration using verified package exports and the repository example profile:
49
28
 
50
29
  ```ts
51
30
  import {
@@ -53,12 +32,12 @@ import {
53
32
  createProviderAdapterRegistry,
54
33
  type ProviderAdapterVocabulary,
55
34
  } from "@hyperscale0/adl";
35
+ import { meridianProfile } from "./examples/meridian-bank/index.js";
56
36
 
57
37
  interface MyVocabulary extends ProviderAdapterVocabulary {
58
38
  capability: "payout_execution";
59
39
  operation: "payout.submit";
60
40
  resource: "payout";
61
- // ...the rest of your closed unions
62
41
  }
63
42
 
64
43
  const defineAdapters = createProviderAdapterRegistry<MyVocabulary>();
@@ -87,30 +66,18 @@ export const adapters = defineAdapters([
87
66
  config: {
88
67
  credentialRef: { source: "environment", name: "MERIDIAN_CREDENTIALS" },
89
68
  },
90
- profile: myBankProfile,
69
+ profile: meridianProfile,
91
70
  },
92
71
  ]);
93
72
 
94
- for (const adapter of adapters) certifyPartnerBankAdapter(adapter);
73
+ for (const adapter of adapters) {
74
+ certifyPartnerBankAdapter(adapter);
75
+ }
95
76
  ```
96
77
 
97
- `createProviderAdapterRegistry` validates at import and preserves your literal
98
- types. `certifyPartnerBankAdapter` throws with every gap listed at once; an
99
- empty finding list is the certification.
100
-
101
- ## Where to go next
78
+ `createProviderAdapterRegistry` validates at import and preserves literal types. `certifyPartnerBankAdapter` throws with every gap listed at once; an empty finding list is the certification.
102
79
 
103
- - **[docs/authoring-guide.md](docs/authoring-guide.md)** -- the whole job, field
104
- by field, with the rule that enforces each one.
105
- - **[examples/meridian-bank](examples/meridian-bank)** -- a complete certified
106
- adapter for a bank that does not exist, with fixtures and its own tests.
107
- Copy it.
108
- - **[conformance/cases.json](conformance/cases.json)** -- every rule as data:
109
- one broken fact per case, and what each gate says about it.
110
- - **[spec/manifest.schema.json](spec/manifest.schema.json)** -- JSON Schema
111
- 2020-12 for one declaration, for authors who are not writing TypeScript.
112
-
113
- ## Running conformance
80
+ Check an adapter declaration with conformance:
114
81
 
115
82
  ```bash
116
83
  bun run conformance -- ./examples/meridian-bank
@@ -122,43 +89,22 @@ ok meridian_bank:bank_credit
122
89
  2 adapter(s) checked, 0 finding(s) reported
123
90
  ```
124
91
 
125
- Exit 1 when anything reports, so it drops straight into CI.
92
+ The command exits 0 on success and 1 when findings are reported.
126
93
 
127
- ## Development
94
+ ## Documentation
128
95
 
129
- ```bash
130
- bun install
131
- bun run check # spec drift, tests, types
132
- bun run build
133
- ```
96
+ - [Authoring guide](docs/authoring-guide.md)
97
+ - [Meridian Bank example](examples/meridian-bank)
98
+ - [Conformance test cases](conformance/cases.json)
99
+ - [Manifest JSON schema](spec/manifest.schema.json)
100
+ - [Contributing](CONTRIBUTING.md)
134
101
 
135
102
  ## Versioning
136
103
 
137
- Semantic versioning from 1.0.0. Until then, alpha releases may change the
138
- surface on a minor version. Two promises hold now:
139
-
140
- - conformance codes are append-only: a released code is never renamed or
141
- removed, so `switch` statements stay exhaustive;
142
- - removing a value from a vocabulary in `src/vocabulary.ts` is a breaking
143
- change and appears in [CHANGELOG.md](CHANGELOG.md).
144
-
145
- ## Contributing
146
-
147
- Issues only. Hyperscale makes the changes to the format and the package; you
148
- propose them in an issue carrying the provider that needs the seam and the
149
- conformance case it would add. [CONTRIBUTING.md](CONTRIBUTING.md) has that
150
- model in full, plus the loop: what earns a new field, how to regenerate the
151
- schema, and the CLA behind a rare accepted pull request. Participation is under
152
- the [Code of Conduct](CODE_OF_CONDUCT.md).
104
+ Semantic versioning from 1.0.0. Until then, prereleases may change the surface on a minor version. Conformance codes are append-only: a released code is never renamed or removed. Removing a value from a vocabulary in `src/vocabulary.ts` is a breaking change documented in [CHANGELOG.md](CHANGELOG.md).
153
105
 
154
- Vulnerabilities go through GitHub private reporting, never a public issue. See
155
- [SECURITY.md](SECURITY.md).
106
+ ## License and security
156
107
 
157
- ## License
108
+ ADL is licensed under AGPL-3.0-only, with a commercial license available from Hyperscale LLC. See [LICENSE](LICENSE), [LICENSING.md](LICENSING.md), and [TRADEMARKS.md](TRADEMARKS.md).
158
109
 
159
- AGPL-3.0-only, with a commercial license available from Hyperscale LLC for
160
- organisations that cannot accept the AGPL. See [LICENSE](LICENSE) for the text
161
- and [LICENSING.md](LICENSING.md) for which one you want and how to ask for the
162
- commercial one. Neither covers the Hyperscale marks;
163
- [TRADEMARKS.md](TRADEMARKS.md) says what that means and carries the rule for
164
- claiming conformance.
110
+ Vulnerability reports go through private disclosure as described in [SECURITY.md](SECURITY.md).
@@ -1 +1 @@
1
- {"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,yBAAyB,EAG1B,MAAM,YAAY,CAAC;AAGpB;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,kuBAyB9B,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAeD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,SAAS,yBAAyB,EAE5C,OAAO,EAAE,eAAe,CAAC,UAAU,CAAC,GACnC,SAAS,6BAA6B,EAAE,CA2B1C;AAED,+EAA+E;AAC/E,wBAAgB,yBAAyB,CACvC,UAAU,SAAS,yBAAyB,EAC5C,OAAO,EAAE,eAAe,CAAC,UAAU,CAAC,GAAG,IAAI,CAW5C"}
1
+ {"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAEV,eAAe,EACf,yBAAyB,EAG1B,MAAM,YAAY,CAAC;AAGpB;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,YACtC,8BAA8B,EAC9B,qBAAqB,EACrB,4BAA4B,EAC5B,gCAAgC,EAChC,+BAA+B,EAC/B,wBAAwB,EACxB,oCAAoC,EACpC,6BAA6B,EAC7B,gCAAgC,EAChC,0BAA0B,EAC1B,0BAA0B,EAC1B,6BAA6B,EAC7B,6BAA6B,EAC7B,yCAAyC,EACzC,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,uBAAuB,EACvB,gCAAgC,EAChC,6BAA6B,EAC7B,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,EACtB,0BAA0B,CAClB,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAeD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,SAAS,yBAAyB,EAE5C,OAAO,EAAE,eAAe,CAAC,UAAU,CAAC,GACnC,SAAS,6BAA6B,EAAE,CA2B1C;AAED,+EAA+E;AAC/E,wBAAgB,yBAAyB,CACvC,UAAU,SAAS,yBAAyB,EAC5C,OAAO,EAAE,eAAe,CAAC,UAAU,CAAC,GAAG,IAAI,CAW5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"vocabulary.d.ts","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vocabulary.d.ts","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="360" viewBox="0 0 1200 360" role="img" aria-labelledby="title desc">
2
+ <title id="title">ADL</title>
3
+ <desc id="desc">Declare how a bank or provider behaves.</desc>
4
+ <rect width="1200" height="360" fill="#050505"/>
5
+ <path d="M48 48H1152M48 304H1152M944 48V304" fill="none" stroke="#303030"/>
6
+ <rect x="48" y="76" width="10" height="10" fill="#2f7dff"/>
7
+ <g font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">
8
+ <text x="72" y="86" fill="#a3a3a3" font-size="14" letter-spacing="2">HYPERSCALE / DOCUMENTATION</text>
9
+ <text x="44" y="194" fill="#ffffff" font-size="76" letter-spacing="-4">ADL</text>
10
+ <text x="48" y="243" fill="#a3a3a3" font-size="20">Declare how a bank or provider behaves.</text>
11
+ <text x="48" y="334" fill="#a3a3a3" font-size="12" letter-spacing="2">DECLARATION / VALIDATION / CONFORMANCE</text>
12
+ <text x="991" y="279" fill="#a3a3a3" font-size="12">SOURCE → CONTRACT</text>
13
+ </g>
14
+ <g fill="none" stroke="#2f7dff" stroke-width="2">
15
+ <path d="M990 110H1058V178H1126V246H1058V178H990Z"/>
16
+ <path d="M1058 110H1126V178H1058"/>
17
+ </g>
18
+ </svg>
@@ -15,9 +15,9 @@ credential, and never decides what a payment means.
15
15
 
16
16
  That split is why the checks in ADL are declaration-level. Conformance
17
17
  does not call your bank. It proves the facts you declared are complete enough
18
- for a generic runtime to poll, classify, reconcile, and dedupe **without
19
- guessing**, because every guess a runtime makes about money is a bug you find
20
- in production.
18
+ for a generic runtime to poll, classify, reconcile, and dedupe without
19
+ guessing. Every guess a runtime makes about money is a provider-boundary
20
+ defect.
21
21
 
22
22
  Two consequences worth internalizing before you write a line:
23
23
 
@@ -30,7 +30,7 @@ Two consequences worth internalizing before you write a line:
30
30
  fact to post from. `validatePartnerBankProfile` refuses a profile whose
31
31
  `notificationMechanisms` omits `poll`, whatever else it lists.
32
32
 
33
- ### Adapter Symmetry
33
+ ### Adapter symmetry
34
34
 
35
35
  Hyperscale's own bank adapters are written against this package and nothing
36
36
  more. There is no private adapter API, no internal hook, no second interface
@@ -108,18 +108,18 @@ Each `ProviderOperationBinding` carries:
108
108
  | `resourceKind` | The platform resource the provider's answer commits onto. Must appear in `bindings`. |
109
109
  | `resourceIdPath` | Where the resource id is read from. Non-blank, checked at load. |
110
110
  | `meter` | Optional. The usage meter this operation feeds. |
111
- | `envelope` | How **this** operation's response carries its outcome. Required on a live command, see below. |
111
+ | `envelope` | How this operation's response carries its outcome. Required when the runtime sends a provider command, see below. |
112
112
  | `statusEnquiry` | The authoritative read-after-write. Required on a REST command, see below. |
113
113
 
114
114
  ### The envelope class, per operation
115
115
 
116
116
  `ProviderResponseEnvelope` has three inhabitants:
117
117
 
118
- - `http_200_body_status` -- every response is HTTP 200 and the outcome is a
118
+ - `http_200_body_status`: every response is HTTP 200 and the outcome is a
119
119
  status token in the body. A rejection arrives inside a success.
120
- - `http_status_error_body` -- the HTTP status carries the outcome and a failure
120
+ - `http_status_error_body`: the HTTP status carries the outcome and a failure
121
121
  body is prose.
122
- - `unconfirmed_until_live` -- the provider publishes no error sample, so the
122
+ - `unconfirmed_until_live`: the provider publishes no error sample, so the
123
123
  class is honestly unknown.
124
124
 
125
125
  Declare it **per operation**, never per provider. Real providers answer in more
@@ -130,9 +130,10 @@ Conformance requires the class on any binding where the runtime sends a command
130
130
  and reads an answer, meaning `direction: "tenant_initiated"` on an `egress` of
131
131
  `rest` or `sync_clearance`. Missing it is `response_envelope_unclassified`; a
132
132
  declared `unconfirmed_until_live` is `response_envelope_unconfirmed`, because
133
- certification is the licence to serve live and the class must be established
134
- first. A `system_settlement` binding carries no response of its own, so it owes
135
- no envelope, and declaring one there would be a borrowed fact.
133
+ conformance requires the response class to be established first. Passing that
134
+ check does not grant live readiness. A `system_settlement` binding carries no
135
+ response of its own, so it owes no envelope, and declaring one there would be a
136
+ borrowed fact.
136
137
 
137
138
  ### Status enquiry, the read-after-write
138
139
 
@@ -165,10 +166,10 @@ enquiry support from a command URL, so:
165
166
 
166
167
  `ProviderEgressMode` is how this adapter reaches the provider at all:
167
168
 
168
- - `none` -- the capability is learned entirely by observation;
169
- - `rest` -- per-command HTTP;
170
- - `batch_reconcile` -- files, reconciled after the fact;
171
- - `sync_clearance` -- one synchronous exchange that carries its own truth.
169
+ - `none`: the capability is learned entirely by observation;
170
+ - `rest`: per-command HTTP;
171
+ - `batch_reconcile`: files, reconciled after the fact;
172
+ - `sync_clearance`: one synchronous exchange that carries its own truth.
172
173
 
173
174
  A `tenant_initiated` binding on `none` or `batch_reconcile` promises an
174
175
  outbound call the egress mode cannot make: `egress_direction_incoherent`.
@@ -191,11 +192,11 @@ missing: polling is the fact.
191
192
  `bindings` maps each resource kind this adapter settles to a
192
193
  `ProviderResourceBinding`:
193
194
 
194
- - `strict` -- the provider's fact must match the platform's row exactly;
195
- - `claim` -- the provider's fact claims an existing row;
196
- - `confirmation_only` -- the provider only confirms what the platform already
195
+ - `strict`: the provider's fact must match the platform's row exactly;
196
+ - `claim`: the provider's fact claims an existing row;
197
+ - `confirmation_only`: the provider only confirms what the platform already
197
198
  decided;
198
- - `evidence_only` -- the fact is recorded as evidence, and settles nothing.
199
+ - `evidence_only`: the fact is recorded as evidence, and settles nothing.
199
200
 
200
201
  Every `resourceKind` named by an operation binding or a webhook plan needs an
201
202
  entry, or conformance reports `resource_binding_missing`: a provider fact with
@@ -226,8 +227,8 @@ would otherwise guess.
226
227
 
227
228
  `wireCodec` (`rest_json`, `iso20022_xml`, `swift_mt`) and `auth`
228
229
  (`ProviderAuthEnvelope` plus a signing scheme). Declaring a grant the bank will
229
- not accept fails on the first live call, so read the bank's token service, do
230
- not assume client credentials.
230
+ not accept fails on the first provider call. Read the bank's token service and
231
+ do not assume client credentials.
231
232
 
232
233
  ### The idempotency spine
233
234
 
@@ -415,8 +416,8 @@ An adapter is handed over as source, never as a running service:
415
416
 
416
417
  ## Stability
417
418
 
418
- The package is `1.0.0-alpha.1` and the surface can still change on a minor
419
- version until it is `1.0.0`. Two promises hold from now:
419
+ The package is pre-1.0 and the surface can still change on a minor version
420
+ until it is `1.0.0`. Two promises hold now:
420
421
 
421
422
  - conformance codes are append-only;
422
423
  - a value removed from a vocabulary in `src/vocabulary.ts` is a breaking change
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperscale0/adl",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "The Adapter Declaration Language: provider adapter interfaces, registry validation, and the partner-bank conformance suite.",
5
5
  "keywords": [
6
6
  "adl",
@@ -67,13 +67,14 @@
67
67
  "typecheck": "tsc -p tsconfig.json"
68
68
  },
69
69
  "devDependencies": {
70
- "@types/bun": "1.4.0",
71
- "typescript": "6.0.3"
70
+ "bun-types": "1.4.2",
71
+ "typescript": "7.0.2"
72
72
  },
73
73
  "author": "Hyperscale LLC",
74
74
  "contributors": [
75
75
  "Meshael AlBakaawi",
76
76
  "Amir Ayub",
77
77
  "Sara AlBakaawi"
78
- ]
78
+ ],
79
+ "gitHead": "092924e9cf7c89ab2fbff740c5d19e355a74007c"
79
80
  }
@@ -1,162 +0,0 @@
1
- /**
2
- * The example's own test, and the shape yours should take: conformance is
3
- * the gate, and the fixtures keep the declaration honest against the bytes
4
- * the bank actually sends. A declaration that certifies but cannot read its
5
- * own sandbox capture is not finished.
6
- */
7
-
8
- import { readFileSync } from "node:fs";
9
-
10
- import { partnerBankConformanceFindings } from "@hyperscale0/adl";
11
- import { describe, expect, test } from "bun:test";
12
-
13
- import { meridianAdapters, meridianProfile } from "./index.js";
14
-
15
- interface ExchangeFixture {
16
- readonly kind: "command" | "enquiry";
17
- readonly operation: string;
18
- readonly response: {
19
- readonly httpStatus: number;
20
- readonly body: Record<string, unknown>;
21
- };
22
- }
23
-
24
- interface StatementFixture {
25
- readonly format: string;
26
- readonly entries: readonly {
27
- readonly amount: string;
28
- readonly customerReference: string | null;
29
- readonly narrative: string;
30
- }[];
31
- }
32
-
33
- interface NotificationFixture {
34
- readonly eventKind: string;
35
- readonly payload: Record<string, unknown>;
36
- }
37
-
38
- function fixture<T>(name: string): T {
39
- return JSON.parse(
40
- readFileSync(new URL(`./fixtures/${name}.json`, import.meta.url), "utf8"),
41
- ) as T;
42
- }
43
-
44
- const exchanges = [
45
- fixture<ExchangeFixture>("payout-submit-accepted"),
46
- fixture<ExchangeFixture>("payout-submit-declined"),
47
- fixture<ExchangeFixture>("payout-status-settled"),
48
- fixture<ExchangeFixture>("payout-status-replay"),
49
- ];
50
- const statement = fixture<StatementFixture>("statement-camt053");
51
- const notification = fixture<NotificationFixture>("webhook-payout-settled");
52
-
53
- const [payoutAdapter] = meridianAdapters;
54
- if (!payoutAdapter) throw new Error("payout adapter missing");
55
-
56
- /** The same normalization a runtime uses to match a status token. */
57
- function normalize(token: string): string {
58
- return token.trim().toUpperCase();
59
- }
60
-
61
- const canonicalStateFor = new Map(
62
- Object.entries(meridianProfile.lifecycleVocabulary).map(
63
- ([spelling, state]) => [normalize(spelling), state as string],
64
- ),
65
- );
66
-
67
- describe("meridian bank adapter", () => {
68
- test("every capability certifies with zero findings", () => {
69
- for (const adapter of meridianAdapters) {
70
- expect({
71
- capability: adapter.capability,
72
- findings: partnerBankConformanceFindings(adapter),
73
- }).toEqual({ capability: adapter.capability, findings: [] });
74
- }
75
- });
76
-
77
- test("the lifecycle vocabulary spells every token the bank sends", () => {
78
- for (const exchange of exchanges) {
79
- const token = exchange.response.body["status"];
80
- expect(typeof token).toBe("string");
81
- expect(canonicalStateFor.get(normalize(token as string))).toBeDefined();
82
- }
83
- });
84
-
85
- test("the declared envelope class is how the fixtures actually read", () => {
86
- // http_status_error_body: the HTTP status carries the outcome and a
87
- // failure body is prose. Reading the body of a 2xx for a rejection, or
88
- // treating a 4xx as a lost response, would strand the payment.
89
- expect(payoutAdapter.operationMap["payout.submit"]?.envelope).toBe(
90
- "http_status_error_body",
91
- );
92
- for (const exchange of exchanges) {
93
- if (exchange.kind !== "command") continue;
94
- const state = canonicalStateFor.get(
95
- normalize(exchange.response.body["status"] as string),
96
- );
97
- if (state === "failed") {
98
- expect(exchange.response.httpStatus).toBeGreaterThanOrEqual(400);
99
- expect(typeof exchange.response.body["message"]).toBe("string");
100
- continue;
101
- }
102
- expect(exchange.response.httpStatus).toBeLessThan(400);
103
- }
104
- });
105
-
106
- test("the statement format is declared and has a fetch window", () => {
107
- const formats: readonly string[] = meridianProfile.statementFormats;
108
- expect(formats).toContain(statement.format);
109
- const windows: Record<string, unknown> = meridianProfile.windows.statements;
110
- expect(windows[statement.format]).toBeDefined();
111
- });
112
-
113
- test("the charge narratives recognize the bank's own debits", () => {
114
- const startsWithAny = (narrative: string, prefixes: readonly string[]) =>
115
- prefixes.some((prefix) => normalize(narrative).startsWith(prefix));
116
-
117
- const { charge, vat } = meridianProfile.charges.narratives;
118
- const chargeLines = statement.entries.filter((entry) =>
119
- startsWithAny(entry.narrative, charge),
120
- );
121
- const vatLines = statement.entries.filter((entry) =>
122
- startsWithAny(entry.narrative, vat),
123
- );
124
- expect(chargeLines).toHaveLength(1);
125
- expect(vatLines).toHaveLength(1);
126
- });
127
-
128
- test("an instructed payout is attributable on the statement", () => {
129
- // statementDebitReference says which reference comes back. Every debit
130
- // that is not one of the bank's own charge lines must carry it, or the
131
- // ledger cannot prove the debit was ours.
132
- expect(meridianProfile.statementDebitReference).toBe("customer_reference");
133
- const chargePrefixes = [
134
- ...meridianProfile.charges.narratives.charge,
135
- ...meridianProfile.charges.narratives.vat,
136
- ];
137
- const instructedDebits = statement.entries.filter(
138
- (entry) =>
139
- entry.amount.startsWith("-") &&
140
- !chargePrefixes.some((prefix) =>
141
- normalize(entry.narrative).startsWith(prefix),
142
- ),
143
- );
144
- expect(instructedDebits).not.toHaveLength(0);
145
- for (const debit of instructedDebits) {
146
- expect(typeof debit.customerReference).toBe("string");
147
- }
148
- });
149
-
150
- test("the webhook plan describes the callback the bank sends", () => {
151
- const plan = Object.entries(payoutAdapter.webhookMap).find(
152
- ([eventKind]) => eventKind === notification.eventKind,
153
- )?.[1];
154
- expect(plan).toBeDefined();
155
- if (!plan) return;
156
- for (const field of plan.requiredPayloadFields) {
157
- expect(notification.payload[field]).toBeDefined();
158
- }
159
- expect(notification.payload[plan.resourceIdField]).toBeDefined();
160
- expect(notification.payload[plan.timestampField]).toBeDefined();
161
- });
162
- });