@v3finance/core-sdk 0.0.0-stage → 0.2.0
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 +434 -0
- package/LICENSE +21 -0
- package/README.md +332 -2
- package/dist/cjs/client.d.ts +162 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +119 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/core/errors.d.ts +92 -0
- package/dist/cjs/core/errors.d.ts.map +1 -0
- package/dist/cjs/core/errors.js +212 -0
- package/dist/cjs/core/errors.js.map +1 -0
- package/dist/cjs/core/gated.d.ts +72 -0
- package/dist/cjs/core/gated.d.ts.map +1 -0
- package/dist/cjs/core/gated.js +66 -0
- package/dist/cjs/core/gated.js.map +1 -0
- package/dist/cjs/core/http.d.ts +102 -0
- package/dist/cjs/core/http.d.ts.map +1 -0
- package/dist/cjs/core/http.js +283 -0
- package/dist/cjs/core/http.js.map +1 -0
- package/dist/cjs/core/pagination.d.ts +64 -0
- package/dist/cjs/core/pagination.d.ts.map +1 -0
- package/dist/cjs/core/pagination.js +85 -0
- package/dist/cjs/core/pagination.js.map +1 -0
- package/dist/cjs/generated/operations.d.ts +1384 -0
- package/dist/cjs/generated/operations.d.ts.map +1 -0
- package/dist/cjs/generated/operations.js +1391 -0
- package/dist/cjs/generated/operations.js.map +1 -0
- package/dist/cjs/generated/types.d.ts +4586 -0
- package/dist/cjs/generated/types.d.ts.map +1 -0
- package/dist/cjs/generated/types.js +5 -0
- package/dist/cjs/generated/types.js.map +1 -0
- package/dist/cjs/index.d.ts +68 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +98 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/query-keys.d.ts +17 -0
- package/dist/cjs/query-keys.d.ts.map +1 -0
- package/dist/cjs/query-keys.js +20 -0
- package/dist/cjs/query-keys.js.map +1 -0
- package/dist/cjs/resources/addresses.d.ts +58 -0
- package/dist/cjs/resources/addresses.d.ts.map +1 -0
- package/dist/cjs/resources/addresses.js +45 -0
- package/dist/cjs/resources/addresses.js.map +1 -0
- package/dist/cjs/resources/admin.d.ts +245 -0
- package/dist/cjs/resources/admin.d.ts.map +1 -0
- package/dist/cjs/resources/admin.js +210 -0
- package/dist/cjs/resources/admin.js.map +1 -0
- package/dist/cjs/resources/approvals.d.ts +88 -0
- package/dist/cjs/resources/approvals.d.ts.map +1 -0
- package/dist/cjs/resources/approvals.js +75 -0
- package/dist/cjs/resources/approvals.js.map +1 -0
- package/dist/cjs/resources/auth.d.ts +30 -0
- package/dist/cjs/resources/auth.d.ts.map +1 -0
- package/dist/cjs/resources/auth.js +36 -0
- package/dist/cjs/resources/auth.js.map +1 -0
- package/dist/cjs/resources/balances.d.ts +183 -0
- package/dist/cjs/resources/balances.d.ts.map +1 -0
- package/dist/cjs/resources/balances.js +39 -0
- package/dist/cjs/resources/balances.js.map +1 -0
- package/dist/cjs/resources/categories.d.ts +159 -0
- package/dist/cjs/resources/categories.d.ts.map +1 -0
- package/dist/cjs/resources/categories.js +182 -0
- package/dist/cjs/resources/categories.js.map +1 -0
- package/dist/cjs/resources/counterparties.d.ts +90 -0
- package/dist/cjs/resources/counterparties.d.ts.map +1 -0
- package/dist/cjs/resources/counterparties.js +124 -0
- package/dist/cjs/resources/counterparties.js.map +1 -0
- package/dist/cjs/resources/folders.d.ts +87 -0
- package/dist/cjs/resources/folders.d.ts.map +1 -0
- package/dist/cjs/resources/folders.js +112 -0
- package/dist/cjs/resources/folders.js.map +1 -0
- package/dist/cjs/resources/history.d.ts +59 -0
- package/dist/cjs/resources/history.d.ts.map +1 -0
- package/dist/cjs/resources/history.js +17 -0
- package/dist/cjs/resources/history.js.map +1 -0
- package/dist/cjs/resources/me.d.ts +60 -0
- package/dist/cjs/resources/me.d.ts.map +1 -0
- package/dist/cjs/resources/me.js +75 -0
- package/dist/cjs/resources/me.js.map +1 -0
- package/dist/cjs/resources/members.d.ts +53 -0
- package/dist/cjs/resources/members.d.ts.map +1 -0
- package/dist/cjs/resources/members.js +67 -0
- package/dist/cjs/resources/members.js.map +1 -0
- package/dist/cjs/resources/operations.d.ts +105 -0
- package/dist/cjs/resources/operations.d.ts.map +1 -0
- package/dist/cjs/resources/operations.js +94 -0
- package/dist/cjs/resources/operations.js.map +1 -0
- package/dist/cjs/resources/registries.d.ts +146 -0
- package/dist/cjs/resources/registries.d.ts.map +1 -0
- package/dist/cjs/resources/registries.js +134 -0
- package/dist/cjs/resources/registries.js.map +1 -0
- package/dist/cjs/resources/reports.d.ts +460 -0
- package/dist/cjs/resources/reports.d.ts.map +1 -0
- package/dist/cjs/resources/reports.js +241 -0
- package/dist/cjs/resources/reports.js.map +1 -0
- package/dist/cjs/resources/sharing.d.ts +103 -0
- package/dist/cjs/resources/sharing.d.ts.map +1 -0
- package/dist/cjs/resources/sharing.js +125 -0
- package/dist/cjs/resources/sharing.js.map +1 -0
- package/dist/cjs/resources/transfers.d.ts +87 -0
- package/dist/cjs/resources/transfers.d.ts.map +1 -0
- package/dist/cjs/resources/transfers.js +105 -0
- package/dist/cjs/resources/transfers.js.map +1 -0
- package/dist/cjs/resources/types.d.ts +60 -0
- package/dist/cjs/resources/types.d.ts.map +1 -0
- package/dist/cjs/resources/types.js +14 -0
- package/dist/cjs/resources/types.js.map +1 -0
- package/dist/cjs/units.d.ts +59 -0
- package/dist/cjs/units.d.ts.map +1 -0
- package/dist/cjs/units.js +145 -0
- package/dist/cjs/units.js.map +1 -0
- package/dist/cjs/version.d.ts +5 -0
- package/dist/cjs/version.d.ts.map +1 -0
- package/dist/cjs/version.js +8 -0
- package/dist/cjs/version.js.map +1 -0
- package/dist/esm/client.d.ts +162 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +115 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/core/errors.d.ts +92 -0
- package/dist/esm/core/errors.d.ts.map +1 -0
- package/dist/esm/core/errors.js +200 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/gated.d.ts +72 -0
- package/dist/esm/core/gated.d.ts.map +1 -0
- package/dist/esm/core/gated.js +61 -0
- package/dist/esm/core/gated.js.map +1 -0
- package/dist/esm/core/http.d.ts +102 -0
- package/dist/esm/core/http.d.ts.map +1 -0
- package/dist/esm/core/http.js +277 -0
- package/dist/esm/core/http.js.map +1 -0
- package/dist/esm/core/pagination.d.ts +64 -0
- package/dist/esm/core/pagination.d.ts.map +1 -0
- package/dist/esm/core/pagination.js +81 -0
- package/dist/esm/core/pagination.js.map +1 -0
- package/dist/esm/generated/operations.d.ts +1384 -0
- package/dist/esm/generated/operations.d.ts.map +1 -0
- package/dist/esm/generated/operations.js +1387 -0
- package/dist/esm/generated/operations.js.map +1 -0
- package/dist/esm/generated/types.d.ts +4586 -0
- package/dist/esm/generated/types.d.ts.map +1 -0
- package/dist/esm/generated/types.js +4 -0
- package/dist/esm/generated/types.js.map +1 -0
- package/dist/esm/index.d.ts +68 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/query-keys.d.ts +17 -0
- package/dist/esm/query-keys.d.ts.map +1 -0
- package/dist/esm/query-keys.js +17 -0
- package/dist/esm/query-keys.js.map +1 -0
- package/dist/esm/resources/addresses.d.ts +58 -0
- package/dist/esm/resources/addresses.d.ts.map +1 -0
- package/dist/esm/resources/addresses.js +41 -0
- package/dist/esm/resources/addresses.js.map +1 -0
- package/dist/esm/resources/admin.d.ts +245 -0
- package/dist/esm/resources/admin.d.ts.map +1 -0
- package/dist/esm/resources/admin.js +206 -0
- package/dist/esm/resources/admin.js.map +1 -0
- package/dist/esm/resources/approvals.d.ts +88 -0
- package/dist/esm/resources/approvals.d.ts.map +1 -0
- package/dist/esm/resources/approvals.js +71 -0
- package/dist/esm/resources/approvals.js.map +1 -0
- package/dist/esm/resources/auth.d.ts +30 -0
- package/dist/esm/resources/auth.d.ts.map +1 -0
- package/dist/esm/resources/auth.js +32 -0
- package/dist/esm/resources/auth.js.map +1 -0
- package/dist/esm/resources/balances.d.ts +183 -0
- package/dist/esm/resources/balances.d.ts.map +1 -0
- package/dist/esm/resources/balances.js +35 -0
- package/dist/esm/resources/balances.js.map +1 -0
- package/dist/esm/resources/categories.d.ts +159 -0
- package/dist/esm/resources/categories.d.ts.map +1 -0
- package/dist/esm/resources/categories.js +178 -0
- package/dist/esm/resources/categories.js.map +1 -0
- package/dist/esm/resources/counterparties.d.ts +90 -0
- package/dist/esm/resources/counterparties.d.ts.map +1 -0
- package/dist/esm/resources/counterparties.js +119 -0
- package/dist/esm/resources/counterparties.js.map +1 -0
- package/dist/esm/resources/folders.d.ts +87 -0
- package/dist/esm/resources/folders.d.ts.map +1 -0
- package/dist/esm/resources/folders.js +108 -0
- package/dist/esm/resources/folders.js.map +1 -0
- package/dist/esm/resources/history.d.ts +59 -0
- package/dist/esm/resources/history.d.ts.map +1 -0
- package/dist/esm/resources/history.js +13 -0
- package/dist/esm/resources/history.js.map +1 -0
- package/dist/esm/resources/me.d.ts +60 -0
- package/dist/esm/resources/me.d.ts.map +1 -0
- package/dist/esm/resources/me.js +71 -0
- package/dist/esm/resources/me.js.map +1 -0
- package/dist/esm/resources/members.d.ts +53 -0
- package/dist/esm/resources/members.d.ts.map +1 -0
- package/dist/esm/resources/members.js +63 -0
- package/dist/esm/resources/members.js.map +1 -0
- package/dist/esm/resources/operations.d.ts +105 -0
- package/dist/esm/resources/operations.d.ts.map +1 -0
- package/dist/esm/resources/operations.js +90 -0
- package/dist/esm/resources/operations.js.map +1 -0
- package/dist/esm/resources/registries.d.ts +146 -0
- package/dist/esm/resources/registries.d.ts.map +1 -0
- package/dist/esm/resources/registries.js +130 -0
- package/dist/esm/resources/registries.js.map +1 -0
- package/dist/esm/resources/reports.d.ts +460 -0
- package/dist/esm/resources/reports.d.ts.map +1 -0
- package/dist/esm/resources/reports.js +237 -0
- package/dist/esm/resources/reports.js.map +1 -0
- package/dist/esm/resources/sharing.d.ts +103 -0
- package/dist/esm/resources/sharing.d.ts.map +1 -0
- package/dist/esm/resources/sharing.js +121 -0
- package/dist/esm/resources/sharing.js.map +1 -0
- package/dist/esm/resources/transfers.d.ts +87 -0
- package/dist/esm/resources/transfers.d.ts.map +1 -0
- package/dist/esm/resources/transfers.js +101 -0
- package/dist/esm/resources/transfers.js.map +1 -0
- package/dist/esm/resources/types.d.ts +60 -0
- package/dist/esm/resources/types.d.ts.map +1 -0
- package/dist/esm/resources/types.js +13 -0
- package/dist/esm/resources/types.js.map +1 -0
- package/dist/esm/units.d.ts +59 -0
- package/dist/esm/units.d.ts.map +1 -0
- package/dist/esm/units.js +132 -0
- package/dist/esm/units.js.map +1 -0
- package/dist/esm/version.d.ts +5 -0
- package/dist/esm/version.d.ts.map +1 -0
- package/dist/esm/version.js +5 -0
- package/dist/esm/version.js.map +1 -0
- package/docs/concepts.md +191 -0
- package/docs/errors.md +471 -0
- package/package.json +77 -4
- package/src/client.ts +231 -0
- package/src/core/errors.ts +253 -0
- package/src/core/gated.ts +89 -0
- package/src/core/http.ts +398 -0
- package/src/core/pagination.ts +106 -0
- package/src/generated/operations.ts +1402 -0
- package/src/generated/types.ts +4849 -0
- package/src/index.ts +169 -0
- package/src/query-keys.ts +18 -0
- package/src/resources/addresses.ts +83 -0
- package/src/resources/admin.ts +371 -0
- package/src/resources/approvals.ts +128 -0
- package/src/resources/auth.ts +36 -0
- package/src/resources/balances.ts +240 -0
- package/src/resources/categories.ts +323 -0
- package/src/resources/counterparties.ts +213 -0
- package/src/resources/folders.ts +163 -0
- package/src/resources/history.ts +76 -0
- package/src/resources/me.ts +91 -0
- package/src/resources/members.ts +96 -0
- package/src/resources/operations.ts +179 -0
- package/src/resources/registries.ts +188 -0
- package/src/resources/reports.ts +596 -0
- package/src/resources/sharing.ts +167 -0
- package/src/resources/transfers.ts +135 -0
- package/src/resources/types.ts +79 -0
- package/src/units.ts +157 -0
- package/src/version.ts +5 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this package are documented in this file. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
|
|
5
|
+
|
|
6
|
+
## 0.2.0 — 2026-11-11
|
|
7
|
+
|
|
8
|
+
The API corrected its own document between 0.1.0 and this release:
|
|
9
|
+
[v3-finance/policy-engine#13](https://github.com/v3-finance/policy-engine/pull/13) brought the
|
|
10
|
+
response schemas in line with what the handlers send and tied the two together with tests on the
|
|
11
|
+
API's side. Every answer this package had been describing by hand, because the document was wrong
|
|
12
|
+
about it, is generated again — and a number of generated shapes moved as a result. Those moves are
|
|
13
|
+
listed under **Breaking** below; read that part before upgrading.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `docs/errors.md` — every error code the API can return, grouped by domain, with what causes it
|
|
18
|
+
and what a client should do about it, plus the codes that are easy to mishandle and the ones
|
|
19
|
+
declared in the server's types but never actually returned.
|
|
20
|
+
- `registries.evaluate(input, { explain: true })` — the per-policy trace of a decision: for every
|
|
21
|
+
enabled policy the person has for the action, whether it applied and, if not, which selector it
|
|
22
|
+
failed on. The API already read `?explain=true` but did not declare it, and a typed client
|
|
23
|
+
should not invent parameters; it is declared now. All four decisions carry `trace[]` then, a
|
|
24
|
+
bare `deny` included. Without the flag the field is absent, which is why `EvaluationResult`
|
|
25
|
+
keeps it optional.
|
|
26
|
+
- One schema per report type — `TransactionActivityReport`, `CounterpartyActivityReport`,
|
|
27
|
+
`CounterpartyGroupActivityReport`, `AssetMovementReport`, `AddressActivityReport`,
|
|
28
|
+
`AccountStatementReport`, `OperationsExceptionsReport`, `ApprovalActivityReport`,
|
|
29
|
+
`BalancePositionReport`, next to the existing `CategoryAnalytics` — and `AnyReport`, the union of
|
|
30
|
+
the ten. With them come the row types they are built from (`ByCounterpartyAddressRow`,
|
|
31
|
+
`ByGroupCounterpartyRow`, `ByCounterpartyBriefRow`, `StatementTokenRow`, `ReportAccountBalance`).
|
|
32
|
+
- Named request bodies for the reporting resource: `CreateReportTemplateBody`,
|
|
33
|
+
`PatchReportTemplateBody`, `CreateReportSnapshotBody`, `CreateReportExportBody` and
|
|
34
|
+
`ReportDrilldownBody`.
|
|
35
|
+
- Three snapshot schemas instead of one: `ReportSnapshot` (what creating one answers, figures under
|
|
36
|
+
`result`), `ReportSnapshotDetail` (one snapshot, figures under `resultJson`) and
|
|
37
|
+
`ReportSnapshotListItem`, plus `ReportSnapshotList` for the listing.
|
|
38
|
+
- Ledger and balances: `LedgerPosting`, `LedgerEntryToken`, `LedgerEntriesPage`,
|
|
39
|
+
`BalancesAsOfTotal`, `BalancesAsOfAccount`, and `BalancesAsOfWithAccounts` — what
|
|
40
|
+
`balances.asOf()` answers when no summary was asked for.
|
|
41
|
+
- Sharing: `ParticipantVia` (where a person's access comes from, as a union discriminated by
|
|
42
|
+
`kind`), `ShareBatchItem` (`ShareBatchGrantedItem | ShareBatchRejectedItem`, discriminated by
|
|
43
|
+
`ok`), `ShareBatchAllRejected` (the body of the all-refused 400) and `ShareGrantCreated`.
|
|
44
|
+
- Fields the API has been sending and now declares, so they are reachable through the types:
|
|
45
|
+
`usdValue`, `decisionPolicyVersionId`, `decisionCounterpartyGroupsJson`, `counterpartyId` and
|
|
46
|
+
`idempotencyKey` on `TransactionDetail`; `currentVersionId` on `Policy`, `PolicyDetail`,
|
|
47
|
+
`PolicyWithRules` and the rows of `VaultPoliciesPage`; `policyVersionId` on `PolicyTrace`;
|
|
48
|
+
`policyId` on `PolicyApprover`; `revokedAt` and `revokedById` on `AddressAccessGrant` and
|
|
49
|
+
`VisibilityGrant` (which also gains `updatedAt`); `groupId` on the rows of `VaultPoliciesPage`;
|
|
50
|
+
and `_count` on `AddressGroup` and `AddressGroupDetail` — an ORM counter that equals
|
|
51
|
+
`memberCount`, declared only because it arrives; read `memberCount`.
|
|
52
|
+
One of these changed behaviour as well as type: `POST /policies` used to answer
|
|
53
|
+
`currentVersionId: null` although the first version had already been taken, and now answers its
|
|
54
|
+
id.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- Spec snapshot refreshed from the live API twice since 0.1.0.
|
|
59
|
+
|
|
60
|
+
The first refresh (API commit `ebd03eb`) moved no type. The envelope no longer drops the
|
|
61
|
+
machine-readable keys a handler sets beside `error`: it carries them inside `details`, so
|
|
62
|
+
`error.details.field` names the category field that failed validation (it is an explicit `null`
|
|
63
|
+
when the error is not about one field) and `error.details.stepIndex` the composite step that was
|
|
64
|
+
denied, counted from 0. Against the 0.1.0 snapshot that was 306 changed descriptions in
|
|
65
|
+
`openapi/spec.json` and 6 changed examples — the invitation token example stopped looking like a
|
|
66
|
+
live secret — and two lines in `src/generated/`.
|
|
67
|
+
|
|
68
|
+
The second (API commit `165504b`, v3-finance/policy-engine#13) is the one this release is about.
|
|
69
|
+
The document now names 262 schemas, up from 228: 34 added, none removed, and 30 of the existing
|
|
70
|
+
ones changed shape. 72 operations under `/vaults/{code}` now declare a 403 or a 404 they did not
|
|
71
|
+
before; that changes no type — it documents refusals those endpoints already gave, the
|
|
72
|
+
vault-membership gate first among them.
|
|
73
|
+
- `docs/errors.md` told callers those two keys were stripped and had to be parsed out of `message`.
|
|
74
|
+
That was accurate when it was written and is not any more. Corrected with it:
|
|
75
|
+
- an unmatched path and an unhandled exception now answer with the envelope as JSON, so a
|
|
76
|
+
non-JSON error body usually means the edge or a proxy answered rather than the API. Not always,
|
|
77
|
+
and the document now says so: a malformed or empty body sent under a JSON content type is
|
|
78
|
+
refused by the framework's validator with a 400 `text/plain`, which is raised as an exception
|
|
79
|
+
carrying its own finished response and so never passes through the envelope layer. No resource
|
|
80
|
+
method of this package can produce one;
|
|
81
|
+
- a validation failure does not reach a client as the flat `{error: "…"}` string the document
|
|
82
|
+
showed. The handler builds that shape, the envelope layer repackages it, and what arrives is
|
|
83
|
+
the ordinary envelope with a status-derived `BAD_REQUEST`;
|
|
84
|
+
- there is nothing diagnostic left in `message` to forward on a signing-service failure or a
|
|
85
|
+
failed report — but only the report one is a constant (`Report generation failed`). The
|
|
86
|
+
signing-service message is a template carrying the upstream status (`Wallet Service returned
|
|
87
|
+
400`), on address creation as well as on transfers; what is withheld is the service's own
|
|
88
|
+
response body, which goes to the worker log.
|
|
89
|
+
- `reports.run(type, …)` answers with the schema of THAT report. `ReportResult` used to map nine of
|
|
90
|
+
the ten types to one loose `ActivityReport` in which every block was optional, so
|
|
91
|
+
`run('balance_position', …)` offered a `summary` that report never has and no `totalsByAsset`,
|
|
92
|
+
which is all it has. Each type now maps to its own schema; `runUnified(type, …)` narrows the same
|
|
93
|
+
way, and `runTemplate()` answers `AnyReport`, because a template's type is not known to the
|
|
94
|
+
compiler.
|
|
95
|
+
- Every request body of the reporting resource is typed. `createTemplate`, `updateTemplate`,
|
|
96
|
+
`createSnapshot` and `createExport` took `unknown` because the document declared those bodies
|
|
97
|
+
inline and there was nothing to import; it names them now. `queryOperations` takes
|
|
98
|
+
`DrilldownQuery`, which is `ReportDrilldownBody` with its two free-form bags (`filters`,
|
|
99
|
+
`drilldown`) replaced by the keys the endpoint actually reads — the generated type alone would
|
|
100
|
+
let a misspelled filter compile and make a figure disagree with its own breakdown — and answers
|
|
101
|
+
`DrilldownResponse`.
|
|
102
|
+
- `me.updateProfile()` is typed `UserProfile`, as it was, and the type is now TRUE. The PATCH
|
|
103
|
+
handler used to return the database row without `needsEmail`, so the answer read `undefined`
|
|
104
|
+
where a `boolean` was promised — on the flag that gates the "add your real email" prompt. The
|
|
105
|
+
API sends it on both paths now.
|
|
106
|
+
- Names this package exports that the document also has — `LedgerPosting`, `ReportSnapshotDetail`,
|
|
107
|
+
`ReportSnapshotListItem` — are strict aliases of the generated schemas, as are `LedgerEntryItem`
|
|
108
|
+
(of `LedgerEntry`) and `PolicyRow` (of `PolicyTableItem`). Only `ReportSnapshotListItem` existed
|
|
109
|
+
in 0.1.0, as a hand-written `Pick` of the same eleven fields.
|
|
110
|
+
- `ReportType` is taken from the document's own enum rather than spelled out. Same ten values.
|
|
111
|
+
- `AssignCategoryBody.values` is optional, as it is to the API, which defaults it to `{}`. A
|
|
112
|
+
category with required fields still needs them filled.
|
|
113
|
+
- `sharing.share()` and `folders.grant()` are typed with `ShareGrantCreated`. It is the same union
|
|
114
|
+
as before, `AddressAccessGrant | ShareBatchResult`, under the name the document gives it.
|
|
115
|
+
- `balances.entries({ addressId })` narrows for a non-administrator too. The API used to ignore
|
|
116
|
+
the filter for members and answer with entries across all of their addresses; it now applies it
|
|
117
|
+
within the member's own addresses, and somebody else's address answers an empty page rather than
|
|
118
|
+
a 403. Nothing changed on this side — the same call returns less.
|
|
119
|
+
- `balances.entries({ entryType })` is typed with `LedgerEntryType`: the six kinds the journal
|
|
120
|
+
reports — `genesis` among them, the opening correction written when the ledger was first
|
|
121
|
+
backfilled — or the stored spelling of the three that are renamed on the way out. That is the
|
|
122
|
+
FILTER; an entry itself still carries a `string`, as the document declares.
|
|
123
|
+
|
|
124
|
+
#### Breaking
|
|
125
|
+
|
|
126
|
+
Type-level only: no method was renamed or removed, no exported name was dropped, and an existing
|
|
127
|
+
call sends the same request. What changed is what the compiler believes about answers, so an
|
|
128
|
+
upgrade can surface compile errors in code that reads them — in nearly every case at a spot that
|
|
129
|
+
was already wrong at runtime: a field that read `undefined`, a string treated as a number.
|
|
130
|
+
|
|
131
|
+
**A field changed type**
|
|
132
|
+
|
|
133
|
+
- `Comparison.incomingUsdChangePercent`, `outgoingUsdChangePercent`,
|
|
134
|
+
`grossTurnoverUsdChangePercent`, `operationsCountChangePercent` and
|
|
135
|
+
`averageOperationUsdChangePercent` — `number | null` → `string | null`.
|
|
136
|
+
- `Observation.changePercent` — `number | null` → `string | null`.
|
|
137
|
+
|
|
138
|
+
These six are decimal STRINGS on the wire (`"12.5"`, `"-40"`) and always were; the document said
|
|
139
|
+
`number`. Arithmetic or `toFixed()` on them compiled and operated on a string. Put them through
|
|
140
|
+
`parseDecimal`, or `Number()` if a float is acceptable for display.
|
|
141
|
+
- `ReportMeta.dataCutoff` — `string | null` → `{ timestamp: string, blockNumber: number | null }`.
|
|
142
|
+
- `ReportMeta.schemaVersion` — `string | number | null` → `string`.
|
|
143
|
+
- `CategoryAnalytics.report` — no longer `ReportMeta` but the five fields that report really
|
|
144
|
+
carries (`type`, `generatedAt`, `from`, `to`, `timezone`).
|
|
145
|
+
- `ActivityReport` — an interface whose twelve blocks were all optional → a deprecated UNION of
|
|
146
|
+
the nine per-type schemas. Reading `report.summary` off it no longer compiles, because not every
|
|
147
|
+
member has one. Use the schema of the report you asked for, or `AnyReport`. Narrow a union by a
|
|
148
|
+
block only that report has (`'totalsByAsset' in report`): `report.type` will not do it, since
|
|
149
|
+
the document types that field as the same ten-value enum on every member.
|
|
150
|
+
- `reports.runTemplate()` — `ActivityReport` → `AnyReport`, which adds `CategoryAnalytics`.
|
|
151
|
+
- `reports.run()` and `reports.runUnified()` — `ActivityReport` → the schema of the report asked
|
|
152
|
+
for. Reading a block that report does not have stops compiling: `.approvals` on anything but
|
|
153
|
+
`approval_activity`, `.summary` on `account_statement`. Those reads returned `undefined` before.
|
|
154
|
+
|
|
155
|
+
**A parameter stopped accepting any string**
|
|
156
|
+
|
|
157
|
+
- `ReportFilters`: `dateBasis`, `groupBy`, `comparison`, `counterpartyClassification`,
|
|
158
|
+
`folderClassification`, `breakdownBy` and `agg` are the enums the document declares. `groupBy:
|
|
159
|
+
'quarter'` used to compile and answer 400.
|
|
160
|
+
- `reports.run('address_activity', …)` requires exactly one of `addressId` and `folderId`. Neither,
|
|
161
|
+
or both, was a 400 — delivered as `REPORT_INVALID_PERIOD`, which points at the dates.
|
|
162
|
+
- `balances.entries({ entryType })` — `string` → the union of entry types.
|
|
163
|
+
- `reports.snapshot()` — `ReportSnapshot` → `ReportSnapshotDetail`. There is no `result` on it: the
|
|
164
|
+
figures are under `resultJson`, where the detail endpoint has always put them. `result` exists
|
|
165
|
+
only on what `createSnapshot()` answers.
|
|
166
|
+
- `BalancesAsOf.totals` and `.accounts` — arrays of untyped records → `BalancesAsOfTotal[]` and
|
|
167
|
+
`BalancesAsOfAccount[]`. `accounts` is also OPTIONAL in the schema now (absent under
|
|
168
|
+
`summary: true`); the three overloads of `balances.asOf()` still tell the two cases apart, so
|
|
169
|
+
`(await balances.asOf(at)).accounts` needs no check.
|
|
170
|
+
- `LedgerEntry.postings[]` — the fields the document used to promise beyond the two ids (`amount`,
|
|
171
|
+
`amountDecimal`, `direction`, `token`, `account`) are gone, replaced by what arrives:
|
|
172
|
+
`LedgerPosting`, with the figure in `amountRawSigned`/`amountDecimalSigned`.
|
|
173
|
+
`LedgerEntry.token` is `LedgerEntryToken | null` instead of an untyped record, and
|
|
174
|
+
`operationType` is `'transfer' | 'deposit' | null`.
|
|
175
|
+
- `Participant.via` — an array of untyped records → `ParticipantVia[]`.
|
|
176
|
+
- `CategoryAccessScope` — `unknown` → `'owner_only' | 'vault_members'`, which is what
|
|
177
|
+
`viewScope`, `assignScope` and `editScope` take on `categories.create()`/`update()` and what a
|
|
178
|
+
category carries. The API still ACCEPTS `restricted` on input as an alias of `owner_only`, stores
|
|
179
|
+
it as `owner_only` and never answers with it; the type leaves it out on purpose, so a caller
|
|
180
|
+
that sends it stops compiling. Send `owner_only`.
|
|
181
|
+
|
|
182
|
+
**A field was removed from a type — it never arrived**
|
|
183
|
+
|
|
184
|
+
- `ReportTemplate.createdById` → the field is `ownerId`. `description` is declared, and
|
|
185
|
+
`parametersJson` is never `null`.
|
|
186
|
+
- `ByAddressOwnerRow.ownerId` and `.owner` → the field is `userId`, and the row also carries
|
|
187
|
+
`addressesCount`, `incomingByAsset` and `outgoingByAsset`.
|
|
188
|
+
- `AssetAmount.contractAddress`. It is on `ByAssetRow`, not on an amount.
|
|
189
|
+
- `PolicyTableItem.conditionJson` and `.approvalJson` — neither policy listing selects them
|
|
190
|
+
(`admin.policies.list`, `admin.policyGroups.policies`), so a row cannot tell you whether a policy
|
|
191
|
+
is conditional. Load the policy itself for that.
|
|
192
|
+
- `_count.limits` on the rows of `VaultPoliciesPage`.
|
|
193
|
+
|
|
194
|
+
**A field became required or lost `null`**
|
|
195
|
+
|
|
196
|
+
Harmless when reading, a compile error when BUILDING one of these — a fixture or a mock: the six
|
|
197
|
+
status counters, `activeDays`, `firstOperationAt` and `lastOperationAt` on `ReportSummary`; every
|
|
198
|
+
field of `ReportMeta` (all are required now, `from`, `to`, `timezone` and `generatedById` are never
|
|
199
|
+
`null`, and `type`, `dateBasis`, `baseCurrency` and `classificationMode` are enums); `tokenId`,
|
|
200
|
+
`assetCode` and `network` on `AssetAmount` and `ByAssetRow`; `severity` (`'info' | 'warning'`) and
|
|
201
|
+
`drilldownFilters` on `Observation`; most of `ReportSnapshot`, `result` included; `vaultId`,
|
|
202
|
+
`requestedAt`, `storageKey`, `errorCode` and `errorMessage` on `ReportExport`; `updatedAt` on
|
|
203
|
+
`ReportTemplate`; `metric.agg` on `CategoryAnalytics`; `LedgerEntry.reference`; and the fields
|
|
204
|
+
listed under Added. `ShareBatchResult.results[]` is a discriminated union now, so an item must be
|
|
205
|
+
consistent with its `ok`.
|
|
206
|
+
|
|
207
|
+
**A request body that was `unknown` is checked**
|
|
208
|
+
|
|
209
|
+
`createTemplate`, `updateTemplate`, `createSnapshot` and `createExport`, as above; and
|
|
210
|
+
`queryOperations`, whose body went from `unknown` to `DrilldownQuery` and whose answer from
|
|
211
|
+
`unknown` to `DrilldownResponse`. A body the API would have refused with a 400 no longer compiles.
|
|
212
|
+
|
|
213
|
+
`parameters` on the first three is typed as a free-form record, and it is NOT a query string — the
|
|
214
|
+
API hands it to the report builder as it is, parsing nothing and defaulting nothing. So the
|
|
215
|
+
obvious move, spreading the filters of a live report into it, is safe only with two conditions:
|
|
216
|
+
|
|
217
|
+
- **`categoryField` is ignored there.** A live report parses `'ticker:EUR'` into a filter; a
|
|
218
|
+
template or snapshot does not, and answers 200 with figures for EVERY value — a frozen report
|
|
219
|
+
that silently is not the one on screen. Send the parsed form instead:
|
|
220
|
+
`categoryFieldValues: { ticker: ['EUR'] }`. This is a defect of the API, reported there; the
|
|
221
|
+
package documents it rather than hides it.
|
|
222
|
+
- **`timezone` has no default there.** The live endpoints fall back to `UTC`; pass it explicitly.
|
|
223
|
+
|
|
224
|
+
Multi-value filters must be arrays (a comma-separated string is not split), and because the type
|
|
225
|
+
is an index signature a value typed as the `ReportFilters` interface needs a spread
|
|
226
|
+
(`parameters: { ...filters }`).
|
|
227
|
+
|
|
228
|
+
**Unchanged in type, corrected in meaning**
|
|
229
|
+
|
|
230
|
+
- `AssetAmount.amount` is still a `string`, and its description no longer says "raw smallest
|
|
231
|
+
units". It is a DECIMAL string in units of the asset (`"1.5"`), signed only in the `netFlow*`
|
|
232
|
+
blocks. Code that passed it to `amount()` was already failing at runtime on the first fractional
|
|
233
|
+
value; use `parseDecimal`. The same holds for the `byAsset` rows and the balances of
|
|
234
|
+
`asset_movement`, `account_statement` and `balance_position`. The one raw figure in a report is
|
|
235
|
+
`balanceRaw` in the opening and closing balances of `address_activity`.
|
|
236
|
+
- `BalancesAsOfTotal.available` and `.reserved` are DECIMAL too — duplicates of
|
|
237
|
+
`availableDecimal`/`reservedDecimal` — while the fields of the same names on `balances.list()`
|
|
238
|
+
are raw. Raw figures of a replay exist only per account, in `accounts[].balance`.
|
|
239
|
+
- The percentage fields that are new to the document with the per-type schemas —
|
|
240
|
+
`turnoverShareUsd`, `shareOfGroupTurnoverUsd`, `shareOfUserActivityUsd`, the `…RatePercent`
|
|
241
|
+
fields of `approval_activity`, the two shares in `balance_position.concentration` — are decimal
|
|
242
|
+
strings as well.
|
|
243
|
+
|
|
244
|
+
### Fixed
|
|
245
|
+
|
|
246
|
+
Nineteen of the fixes below NARROW a type that used to be `string`, `unknown` or a loose
|
|
247
|
+
`Record`. Code that passed a value the API rejects now fails to compile instead of failing at
|
|
248
|
+
runtime with a 400 — which is the point, but it means an upgrade can surface new compile errors.
|
|
249
|
+
None of them renames or removes an exported name.
|
|
250
|
+
|
|
251
|
+
**Calls that could not be made at all**
|
|
252
|
+
|
|
253
|
+
- `reports.run('balance_position', …)` accepted no parameters. Its entry declared
|
|
254
|
+
`Record<string, never>`, and that index signature applies to the fields of `ReportFilters` too
|
|
255
|
+
once the two are intersected, collapsing every one of them to `never`. The only argument that
|
|
256
|
+
compiled was `{}` — so the report could not be asked for a date, which is the whole point of a
|
|
257
|
+
position report. All six parameters the handler reads now compile.
|
|
258
|
+
- The `idempotency-key` header is no longer sent. The server has never read it, which by itself
|
|
259
|
+
bought nothing; in a browser it cost the entire request, because the API's CORS preflight allows
|
|
260
|
+
exactly `Content-Type` and `Authorization`, so a money call carrying the header was never sent
|
|
261
|
+
and surfaced as a network error no retry explained. The `idempotencyKey` option stays, accepted
|
|
262
|
+
and deprecated: the body field is what protects a transfer.
|
|
263
|
+
- `units.format()` threw `RangeError` for any token with 0 or 1 decimals (`minimumFractionDigits`
|
|
264
|
+
defaulted to 2 above a `maximumFractionDigits` of `decimals`). The decimals ceiling was also 36
|
|
265
|
+
while the API and the package's own generated type allow 38, so `registries.createToken` could
|
|
266
|
+
register a token that `amount()` then refused.
|
|
267
|
+
|
|
268
|
+
**Answers that were read from the wrong place**
|
|
269
|
+
|
|
270
|
+
- `balances.entries()` typed postings from the document, which declared `amount`,
|
|
271
|
+
`amountDecimal`, `direction`, `token` and `account`. The handler sends none of them — the money
|
|
272
|
+
field is `amountRawSigned` — so `BigInt(posting.amount)` threw on the only endpoint that exposes
|
|
273
|
+
the ledger. The document has been corrected, and the type is the generated `LedgerPosting`.
|
|
274
|
+
- `reports.snapshot()` promised `result`; the detail handler returns the stored row, so the field
|
|
275
|
+
is `resultJson`. The numbers were unreachable through the type and `result` read `undefined`
|
|
276
|
+
every time. The document now has a schema for each answer: `snapshot()` is typed with
|
|
277
|
+
`ReportSnapshotDetail`, and `createSnapshot()` keeps `ReportSnapshot` with `result` — that
|
|
278
|
+
handler does map it.
|
|
279
|
+
- `balances.asOf()` exposed 2 of its 8 parameters. Opening the rest meant opening `summary`, and
|
|
280
|
+
with `summary` the handler omits `accounts` altogether. Three overloads tell the cases apart —
|
|
281
|
+
`BalancesAsOfWithAccounts` without a summary, `BalancesAsOfSummary` with one, the union when the
|
|
282
|
+
flag is decided at runtime — so the type never promises an array that will not be there. The
|
|
283
|
+
document agrees now: `accounts` is optional on `BalancesAsOf`.
|
|
284
|
+
|
|
285
|
+
**Values the API rejects no longer compile**
|
|
286
|
+
|
|
287
|
+
- `approvals.list({status})` took any string, but approval statuses are UPPERCASE while transfer
|
|
288
|
+
statuses are lowercase and both appear on one screen; `'pending'` compiled and got a 400.
|
|
289
|
+
- `history.list({status})` took any string, and the package's own exported `TransactionStatus`
|
|
290
|
+
includes `submitted`, which that filter does not accept — the SDK was suggesting a value that
|
|
291
|
+
returns 400.
|
|
292
|
+
- `balances.list({purpose})` knew 2 of the 4 ledger purposes.
|
|
293
|
+
- `OperationType`, `OperationKind` and `PendingApproval` were hand-written aliases widened to
|
|
294
|
+
`string`, and an explicit re-export shadows the generated schema of the same name — so
|
|
295
|
+
`OperationType` reached consumers as `string` rather than `'deposit' | 'transfer'`, and a typo
|
|
296
|
+
in an operation type was caught only by the API. All three are strict aliases now, and
|
|
297
|
+
`test/nameShadowing.test.ts` fails if one widens again.
|
|
298
|
+
- Request bodies that were `unknown` on `categories.addField`/`updateField`/`addApprover`/
|
|
299
|
+
`addGrant`, `admin.invitations.acceptDebug`, `vaults.buildDerivationPath`/`parseDerivationPath`
|
|
300
|
+
now carry their schemas. Response types were filled in only where the handler was read and
|
|
301
|
+
matched.
|
|
302
|
+
|
|
303
|
+
**Transport**
|
|
304
|
+
|
|
305
|
+
- `timeoutMs` and `signal` stopped applying once the response headers arrived: the timer was
|
|
306
|
+
cleared around `fetch`, and the body streamed after. A server that answered and then stalled
|
|
307
|
+
mid-body left a request hanging with nothing to end it. Both now stay armed until the body is in
|
|
308
|
+
hand, and a body read that fails is no longer swallowed into `data: undefined` typed as the
|
|
309
|
+
shape the caller asked for.
|
|
310
|
+
- A non-JSON error body put the proxy's whole HTML page into `message` (measured at 2.3 KB), and
|
|
311
|
+
`request()` and `fetchRaw()` disagreed about the same 502. They now answer alike, HTML is
|
|
312
|
+
suppressed and a short text body is kept.
|
|
313
|
+
- `Gated.status` reported 201 when the server had answered 200.
|
|
314
|
+
- A sub-second timeout rendered as "within 0s".
|
|
315
|
+
|
|
316
|
+
**Documentation that no longer matched the API**: the shape of a validation error, the claim that
|
|
317
|
+
a non-JSON error body can no longer come from the API, `CATEGORY_NOT_FOUND`'s actual paths,
|
|
318
|
+
`REPORT_VAULT_NOT_FOUND` (unreachable — all seven in-handler vault 404s in the reports router are
|
|
319
|
+
dead code), `details.param` on `REPORT_INVALID_PARAMS`, `SUBJECT_REQUIRED` across its three
|
|
320
|
+
different answers, four of nine observation codes, the missing `OPERATION_RELATION_INVALID`, the
|
|
321
|
+
transport codes (`NETWORK_ERROR`, `TIMEOUT`, `ABORTED`, `PARSE_ERROR`) that were named nowhere,
|
|
322
|
+
the count of endpoints left out, the `replayed` branch that only `transfers.send` can reach, and
|
|
323
|
+
the keyset-pagination claim (11 list endpoints are cursored, 18 return `items` alone, 8 a bare
|
|
324
|
+
array).
|
|
325
|
+
|
|
326
|
+
- `admin.users.setRole` took any string for the platform role. The spec declares
|
|
327
|
+
`enum: ["admin", "user"]`, so this is a narrowing the contract already backed — and worth the
|
|
328
|
+
compile error on a privilege path, where `string` meant finding out from a 400 after sending a
|
|
329
|
+
role change. The response keeps `role: string`: the spec declares it bare, and narrowing an
|
|
330
|
+
answer we do not control would be a guess. The type is exported as `PlatformRole`.
|
|
331
|
+
|
|
332
|
+
- `approvals.vote` returned `unknown`. It is typed from `RequestVoteResult`, which the spec
|
|
333
|
+
declares as a component but never `$ref`s — the operation inlines its 200 instead. The two were
|
|
334
|
+
compared property by property and are the same schema, down to identical `required` sets; the
|
|
335
|
+
only difference is an `additionalProperties: false` that does not reach the TypeScript shape.
|
|
336
|
+
Worth checking rather than assuming, because a component nothing references usually means the
|
|
337
|
+
opposite — an orphan left behind, which is what the `Address` schema turned out to be.
|
|
338
|
+
- `deleteSnapshot` and `deleteTemplate` returned `unknown` for a body the spec pins as
|
|
339
|
+
`{deleted: true}`.
|
|
340
|
+
|
|
341
|
+
**Guards added**, because none of the above was caught by a green CI: `generate:check` compares
|
|
342
|
+
only the generated files against the snapshot, and the surface test only checks that paths are
|
|
343
|
+
reachable. New metatests cover name shadowing, query parameters missing from a method's type,
|
|
344
|
+
request bodies left as `unknown`, and the completeness of `docs/errors.md`.
|
|
345
|
+
|
|
346
|
+
Two more came with the corrected document. `test/reportResults.test.ts` holds every method of the
|
|
347
|
+
reporting resource to the schema the API declares for the operation it calls — the check that
|
|
348
|
+
would have caught nine report types sharing one catch-all. And the body test now has a second
|
|
349
|
+
list beside the untyped one: bodies typed by hand OVER a named schema, each held to that schema's
|
|
350
|
+
fields. It has one entry, `queryOperations`; the list of untyped bodies is empty.
|
|
351
|
+
|
|
352
|
+
`test/transport.test.ts` pins the transport fixes by BEHAVIOUR, which none of the metatests can
|
|
353
|
+
reach: they are all about *when* something happens — when the timer is cleared, when the body is
|
|
354
|
+
read, which status is reported — and no type describes that. Its stub aborts its body stream when
|
|
355
|
+
the signal fires, the way a real `fetch` does, and that detail is the whole test: a stub that
|
|
356
|
+
ignores the signal passes even against the broken client, because nothing can interrupt a body
|
|
357
|
+
nobody wired up. Each case was checked by reverting the fix — restoring the old timer placement
|
|
358
|
+
turns four of them red with "test timed out", which is the production symptom exactly.
|
|
359
|
+
|
|
360
|
+
**Seven places where the API's document disagreed with its own handlers** turned up while this
|
|
361
|
+
release was being prepared. hono-openapi does not validate answers against the document, so
|
|
362
|
+
nothing here could fix them — only describe the answer by hand and say why.
|
|
363
|
+
v3-finance/policy-engine#13 fixed all seven at the source, and the hand-written descriptions have
|
|
364
|
+
been dropped in favour of the generated types:
|
|
365
|
+
|
|
366
|
+
| What was wrong | What it meant in 0.1.0 | Now |
|
|
367
|
+
|---|---|---|
|
|
368
|
+
| Ledger postings declared five fields that never arrive and none of the six that do | `posting.amount` was `undefined`; `BigInt(posting.amount)` threw | generated `LedgerPosting`, figure in `amountRawSigned` |
|
|
369
|
+
| One schema for a snapshot, though creating one answers `result` and reading one `resultJson` | `snapshot(id).result` read `undefined`; the figures were unreachable through the type | three schemas; `snapshot()` answers `ReportSnapshotDetail` |
|
|
370
|
+
| `accounts` required on `BalancesAsOf`, though absent under `summary=true` | nothing yet — `asOf()` did not offer `summary` | optional in the schema; the overloads of `asOf()` say which call gets it |
|
|
371
|
+
| `AssetAmount.amount` described as raw smallest units | `amount(x.amount, decimals)` threw on the first fractional value | described as the decimal string it is |
|
|
372
|
+
| The all-refused batch grant answers 400 with `{results}`, declared as an error envelope | the per-subject reasons were in `error.details`, which nothing described | declared as a second form of that 400, `ShareBatchAllRejected`. The SDK still throws on it, body in `details` |
|
|
373
|
+
| `usdValue`, `decisionPolicyVersionId`, `currentVersionId` sent but not declared | unreachable through the types | declared; see Added |
|
|
374
|
+
| `PATCH /me/profile` declared `needsEmail` and did not send it | `updateProfile()` answered `needsEmail: undefined` | the HANDLER was fixed, not the document: the flag is sent |
|
|
375
|
+
|
|
376
|
+
What remains hand-written is hand-written because the document has nothing to offer, not because
|
|
377
|
+
it is wrong: query parameters (the generator emits schemas only, never `parameters`), the few
|
|
378
|
+
answers the API still declares inline without a name (`AmlScore`, the status-history row), and the
|
|
379
|
+
unions it carries only as a bare `string` — `TransactionStatus`, `ApprovalRequestStatus`,
|
|
380
|
+
`LedgerEntryType`. One answer stays untyped for the first of those reasons: the group access
|
|
381
|
+
summary of `admin.policyGroups.access`.
|
|
382
|
+
|
|
383
|
+
- `codeFromStatus` now uses the API's own name for every status the API names: 401 is
|
|
384
|
+
`UNAUTHENTICATED` (was `UNAUTHORIZED`), 422 is `UNPROCESSABLE_ENTITY` (was `UNPROCESSABLE`), 503
|
|
385
|
+
is `SERVICE_UNAVAILABLE` (was `UNAVAILABLE`), and 413/501 are now named at all. Previously a
|
|
386
|
+
non-JSON response gave a code the server never uses for that condition, so a client branching on
|
|
387
|
+
the server's name missed it. 502 and 504 keep the SDK's own names, because the API has no
|
|
388
|
+
envelope for them — they arrive from the edge.
|
|
389
|
+
The test covering this mapping asserted only the statuses that already agreed; it now covers all
|
|
390
|
+
of them.
|
|
391
|
+
|
|
392
|
+
## 0.1.0 — 2026-11-10
|
|
393
|
+
|
|
394
|
+
First release. Every endpoint a client calls is covered — 157 of the API's 171 operations, grouped
|
|
395
|
+
into resources, with the administrative surface marked; the fourteen exceptions are listed under
|
|
396
|
+
Known limitations. A test asserts that each of the rest is reachable, so one added to the API shows
|
|
397
|
+
up as a failure rather than as a gap nobody noticed.
|
|
398
|
+
|
|
399
|
+
### Added
|
|
400
|
+
|
|
401
|
+
- `CoreClient` with vault scoping: `core.vault(code).addresses.list()`. A scope is an expression,
|
|
402
|
+
not state, so two vaults can be used side by side and switching the active one cannot leave a
|
|
403
|
+
stale scope pointing at the wrong place.
|
|
404
|
+
- Injected authentication: `getAuthHeaders`, `onTokenRotated`, `onUnauthorized`. Works with a
|
|
405
|
+
browser cookie, a native cookie jar or a bearer token; the package stores no credentials.
|
|
406
|
+
- `CoreError` with a `code` that is always present and a `kind` separating HTTP, network, timeout,
|
|
407
|
+
aborted and parse failures. Three real response shapes are parsed, including a flat
|
|
408
|
+
`{error: "…"}` string — which is what a non-JSON error body is read as.
|
|
409
|
+
- Money as smallest-unit strings with BigInt arithmetic (`amount`, `parseDecimal`, `format`, `add`,
|
|
410
|
+
`sub`, `compare`). There is no `toNumber`, on purpose: it would be a convenient door into the
|
|
411
|
+
precision loss the module exists to prevent.
|
|
412
|
+
- `Gated` results for the fifteen operations that can finish in more than one way, telling applied,
|
|
413
|
+
pending and replayed apart by HTTP status — the response bodies are identical, so a client
|
|
414
|
+
reading only the body reports "done" where the truth is "awaiting signatures".
|
|
415
|
+
- Keyset pagination helpers `paginate` and `collectAll`.
|
|
416
|
+
- Resources: addresses, transfers, history, balances, approvals, counterparties and their groups,
|
|
417
|
+
shared access, folders, members, operation labelling, operation metadata and relations, reports
|
|
418
|
+
with templates, snapshots and exports, registries, policy preflight, AML, sign-in, and the
|
|
419
|
+
administrative surface.
|
|
420
|
+
- Per-report-type parameters, so the compiler requires `from`/`to` and the target each report needs
|
|
421
|
+
rather than letting the call fail at runtime.
|
|
422
|
+
- `OPERATIONS`, a generated catalogue of all 171 API operations with the access level each requires.
|
|
423
|
+
- Cache keys for TanStack Query at `@v3finance/core-sdk/query-keys`.
|
|
424
|
+
|
|
425
|
+
### Known limitations
|
|
426
|
+
|
|
427
|
+
- The `assets` filter on reports is accepted by the API and silently ignored by it, so it is marked
|
|
428
|
+
deprecated here. Use `tokenIds`.
|
|
429
|
+
- `runTemplate` cannot override a template's stored filters: the endpoint accepts no body.
|
|
430
|
+
- 14 of the 171 operations are not exposed. `/welcome` and `/webhooks/wallet` are a browser landing
|
|
431
|
+
page and the wallet service's inbound channel; the other 12 are the `/address-groups/*` paths,
|
|
432
|
+
which are the older prefix of the same endpoints the folders resource serves under
|
|
433
|
+
`/address-folders` — one entity, two prefixes, and exposing both would only raise the question of
|
|
434
|
+
which to call.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 V3 Finance
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|