@v3finance/core-sdk 0.0.0-stage → 0.1.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 +44 -0
- package/LICENSE +21 -0
- package/README.md +189 -2
- package/dist/cjs/client.d.ts +117 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +83 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/core/errors.d.ts +72 -0
- package/dist/cjs/core/errors.d.ts.map +1 -0
- package/dist/cjs/core/errors.js +180 -0
- package/dist/cjs/core/errors.js.map +1 -0
- package/dist/cjs/core/gated.d.ts +54 -0
- package/dist/cjs/core/gated.d.ts.map +1 -0
- package/dist/cjs/core/gated.js +57 -0
- package/dist/cjs/core/gated.js.map +1 -0
- package/dist/cjs/core/http.d.ts +98 -0
- package/dist/cjs/core/http.d.ts.map +1 -0
- package/dist/cjs/core/http.js +193 -0
- package/dist/cjs/core/http.js.map +1 -0
- package/dist/cjs/core/pagination.d.ts +37 -0
- package/dist/cjs/core/pagination.d.ts.map +1 -0
- package/dist/cjs/core/pagination.js +50 -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 +3810 -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 +44 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +86 -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 +44 -0
- package/dist/cjs/resources/addresses.d.ts.map +1 -0
- package/dist/cjs/resources/addresses.js +39 -0
- package/dist/cjs/resources/addresses.js.map +1 -0
- package/dist/cjs/resources/admin.d.ts +120 -0
- package/dist/cjs/resources/admin.d.ts.map +1 -0
- package/dist/cjs/resources/admin.js +139 -0
- package/dist/cjs/resources/admin.js.map +1 -0
- package/dist/cjs/resources/approvals.d.ts +47 -0
- package/dist/cjs/resources/approvals.d.ts.map +1 -0
- package/dist/cjs/resources/approvals.js +52 -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 +47 -0
- package/dist/cjs/resources/balances.d.ts.map +1 -0
- package/dist/cjs/resources/balances.js +35 -0
- package/dist/cjs/resources/balances.js.map +1 -0
- package/dist/cjs/resources/categories.d.ts +87 -0
- package/dist/cjs/resources/categories.d.ts.map +1 -0
- package/dist/cjs/resources/categories.js +135 -0
- package/dist/cjs/resources/categories.js.map +1 -0
- package/dist/cjs/resources/counterparties.d.ts +67 -0
- package/dist/cjs/resources/counterparties.d.ts.map +1 -0
- package/dist/cjs/resources/counterparties.js +107 -0
- package/dist/cjs/resources/counterparties.js.map +1 -0
- package/dist/cjs/resources/folders.d.ts +46 -0
- package/dist/cjs/resources/folders.d.ts.map +1 -0
- package/dist/cjs/resources/folders.js +81 -0
- package/dist/cjs/resources/folders.js.map +1 -0
- package/dist/cjs/resources/history.d.ts +41 -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 +37 -0
- package/dist/cjs/resources/me.d.ts.map +1 -0
- package/dist/cjs/resources/me.js +54 -0
- package/dist/cjs/resources/me.js.map +1 -0
- package/dist/cjs/resources/members.d.ts +38 -0
- package/dist/cjs/resources/members.d.ts.map +1 -0
- package/dist/cjs/resources/members.js +58 -0
- package/dist/cjs/resources/members.js.map +1 -0
- package/dist/cjs/resources/operations.d.ts +49 -0
- package/dist/cjs/resources/operations.d.ts.map +1 -0
- package/dist/cjs/resources/operations.js +70 -0
- package/dist/cjs/resources/operations.js.map +1 -0
- package/dist/cjs/resources/registries.d.ts +68 -0
- package/dist/cjs/resources/registries.d.ts.map +1 -0
- package/dist/cjs/resources/registries.js +91 -0
- package/dist/cjs/resources/registries.js.map +1 -0
- package/dist/cjs/resources/reports.d.ts +201 -0
- package/dist/cjs/resources/reports.d.ts.map +1 -0
- package/dist/cjs/resources/reports.js +113 -0
- package/dist/cjs/resources/reports.js.map +1 -0
- package/dist/cjs/resources/sharing.d.ts +52 -0
- package/dist/cjs/resources/sharing.d.ts.map +1 -0
- package/dist/cjs/resources/sharing.js +78 -0
- package/dist/cjs/resources/sharing.js.map +1 -0
- package/dist/cjs/resources/transfers.d.ts +65 -0
- package/dist/cjs/resources/transfers.d.ts.map +1 -0
- package/dist/cjs/resources/transfers.js +83 -0
- package/dist/cjs/resources/transfers.js.map +1 -0
- package/dist/cjs/resources/types.d.ts +40 -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 +129 -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 +117 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +79 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/core/errors.d.ts +72 -0
- package/dist/esm/core/errors.d.ts.map +1 -0
- package/dist/esm/core/errors.js +168 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/gated.d.ts +54 -0
- package/dist/esm/core/gated.d.ts.map +1 -0
- package/dist/esm/core/gated.js +52 -0
- package/dist/esm/core/gated.js.map +1 -0
- package/dist/esm/core/http.d.ts +98 -0
- package/dist/esm/core/http.d.ts.map +1 -0
- package/dist/esm/core/http.js +187 -0
- package/dist/esm/core/http.js.map +1 -0
- package/dist/esm/core/pagination.d.ts +37 -0
- package/dist/esm/core/pagination.d.ts.map +1 -0
- package/dist/esm/core/pagination.js +46 -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 +3810 -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 +44 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +38 -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 +44 -0
- package/dist/esm/resources/addresses.d.ts.map +1 -0
- package/dist/esm/resources/addresses.js +35 -0
- package/dist/esm/resources/addresses.js.map +1 -0
- package/dist/esm/resources/admin.d.ts +120 -0
- package/dist/esm/resources/admin.d.ts.map +1 -0
- package/dist/esm/resources/admin.js +135 -0
- package/dist/esm/resources/admin.js.map +1 -0
- package/dist/esm/resources/approvals.d.ts +47 -0
- package/dist/esm/resources/approvals.d.ts.map +1 -0
- package/dist/esm/resources/approvals.js +48 -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 +47 -0
- package/dist/esm/resources/balances.d.ts.map +1 -0
- package/dist/esm/resources/balances.js +31 -0
- package/dist/esm/resources/balances.js.map +1 -0
- package/dist/esm/resources/categories.d.ts +87 -0
- package/dist/esm/resources/categories.d.ts.map +1 -0
- package/dist/esm/resources/categories.js +131 -0
- package/dist/esm/resources/categories.js.map +1 -0
- package/dist/esm/resources/counterparties.d.ts +67 -0
- package/dist/esm/resources/counterparties.d.ts.map +1 -0
- package/dist/esm/resources/counterparties.js +102 -0
- package/dist/esm/resources/counterparties.js.map +1 -0
- package/dist/esm/resources/folders.d.ts +46 -0
- package/dist/esm/resources/folders.d.ts.map +1 -0
- package/dist/esm/resources/folders.js +77 -0
- package/dist/esm/resources/folders.js.map +1 -0
- package/dist/esm/resources/history.d.ts +41 -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 +37 -0
- package/dist/esm/resources/me.d.ts.map +1 -0
- package/dist/esm/resources/me.js +50 -0
- package/dist/esm/resources/me.js.map +1 -0
- package/dist/esm/resources/members.d.ts +38 -0
- package/dist/esm/resources/members.d.ts.map +1 -0
- package/dist/esm/resources/members.js +54 -0
- package/dist/esm/resources/members.js.map +1 -0
- package/dist/esm/resources/operations.d.ts +49 -0
- package/dist/esm/resources/operations.d.ts.map +1 -0
- package/dist/esm/resources/operations.js +66 -0
- package/dist/esm/resources/operations.js.map +1 -0
- package/dist/esm/resources/registries.d.ts +68 -0
- package/dist/esm/resources/registries.d.ts.map +1 -0
- package/dist/esm/resources/registries.js +87 -0
- package/dist/esm/resources/registries.js.map +1 -0
- package/dist/esm/resources/reports.d.ts +201 -0
- package/dist/esm/resources/reports.d.ts.map +1 -0
- package/dist/esm/resources/reports.js +109 -0
- package/dist/esm/resources/reports.js.map +1 -0
- package/dist/esm/resources/sharing.d.ts +52 -0
- package/dist/esm/resources/sharing.d.ts.map +1 -0
- package/dist/esm/resources/sharing.js +74 -0
- package/dist/esm/resources/sharing.js.map +1 -0
- package/dist/esm/resources/transfers.d.ts +65 -0
- package/dist/esm/resources/transfers.d.ts.map +1 -0
- package/dist/esm/resources/transfers.js +79 -0
- package/dist/esm/resources/transfers.js.map +1 -0
- package/dist/esm/resources/types.d.ts +40 -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 +116 -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/package.json +76 -4
- package/src/client.ts +167 -0
- package/src/core/errors.ts +219 -0
- package/src/core/gated.ts +71 -0
- package/src/core/http.ts +288 -0
- package/src/core/pagination.ts +69 -0
- package/src/generated/operations.ts +1402 -0
- package/src/generated/types.ts +4039 -0
- package/src/index.ts +112 -0
- package/src/query-keys.ts +18 -0
- package/src/resources/addresses.ts +68 -0
- package/src/resources/admin.ts +218 -0
- package/src/resources/approvals.ts +82 -0
- package/src/resources/auth.ts +36 -0
- package/src/resources/balances.ts +68 -0
- package/src/resources/categories.ts +228 -0
- package/src/resources/counterparties.ts +196 -0
- package/src/resources/folders.ts +107 -0
- package/src/resources/history.ts +51 -0
- package/src/resources/me.ts +66 -0
- package/src/resources/members.ts +77 -0
- package/src/resources/operations.ts +114 -0
- package/src/resources/registries.ts +109 -0
- package/src/resources/reports.ts +315 -0
- package/src/resources/sharing.ts +114 -0
- package/src/resources/transfers.ts +107 -0
- package/src/resources/types.ts +59 -0
- package/src/units.ts +140 -0
- package/src/version.ts +5 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
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.1.0 — 2026-11-10
|
|
7
|
+
|
|
8
|
+
First release. The whole API is covered — 171 operations grouped into resources, with the
|
|
9
|
+
administrative surface marked — and a test asserts that every endpoint is reachable, so one added
|
|
10
|
+
to the API shows up as a failure rather than as a gap nobody noticed.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `CoreClient` with vault scoping: `core.vault(code).addresses.list()`. A scope is an expression,
|
|
15
|
+
not state, so two vaults can be used side by side and switching the active one cannot leave a
|
|
16
|
+
stale scope pointing at the wrong place.
|
|
17
|
+
- Injected authentication: `getAuthHeaders`, `onTokenRotated`, `onUnauthorized`. Works with a
|
|
18
|
+
browser cookie, a native cookie jar or a bearer token; the package stores no credentials.
|
|
19
|
+
- `CoreError` with a `code` that is always present and a `kind` separating HTTP, network, timeout,
|
|
20
|
+
aborted and parse failures. Three real response shapes are parsed, including the validation
|
|
21
|
+
failure that arrives as a plain string.
|
|
22
|
+
- Money as smallest-unit strings with BigInt arithmetic (`amount`, `parseDecimal`, `format`, `add`,
|
|
23
|
+
`sub`, `compare`). There is no `toNumber`, on purpose: it would be a convenient door into the
|
|
24
|
+
precision loss the module exists to prevent.
|
|
25
|
+
- `Gated` results for the fifteen operations that can finish in more than one way, telling applied,
|
|
26
|
+
pending and replayed apart by HTTP status — the response bodies are identical, so a client
|
|
27
|
+
reading only the body reports "done" where the truth is "awaiting signatures".
|
|
28
|
+
- Keyset pagination helpers `paginate` and `collectAll`.
|
|
29
|
+
- Resources: addresses, transfers, history, balances, approvals, counterparties and their groups,
|
|
30
|
+
shared access, folders, members, operation labelling, operation metadata and relations, reports
|
|
31
|
+
with templates, snapshots and exports, registries, policy preflight, AML, sign-in, and the
|
|
32
|
+
administrative surface.
|
|
33
|
+
- Per-report-type parameters, so the compiler requires `from`/`to` and the target each report needs
|
|
34
|
+
rather than letting the call fail at runtime.
|
|
35
|
+
- `OPERATIONS`, a generated catalogue of all 171 API operations with the access level each requires.
|
|
36
|
+
- Cache keys for TanStack Query at `@v3finance/core-sdk/query-keys`.
|
|
37
|
+
|
|
38
|
+
### Known limitations
|
|
39
|
+
|
|
40
|
+
- The `assets` filter on reports is accepted by the API and silently ignored by it, so it is marked
|
|
41
|
+
deprecated here. Use `tokenIds`.
|
|
42
|
+
- `runTemplate` cannot override a template's stored filters: the endpoint accepts no body.
|
|
43
|
+
- `/welcome` and `/webhooks/wallet` are not exposed — a browser landing page and the wallet
|
|
44
|
+
service's inbound channel respectively.
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,190 @@
|
|
|
1
|
-
#
|
|
1
|
+
# V3 Finance Core SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@v3finance/core-sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@v3finance/core-sdk)
|
|
5
|
+
[](https://www.npmjs.com/package/@v3finance/core-sdk)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
The official TypeScript SDK for the V3 Finance Core API.
|
|
9
|
+
Custodial addresses, transfers under policy control, approvals and shared access.
|
|
10
|
+
|
|
11
|
+
- **Vault scoping** that carries no state: `core.vault(code)` is an expression, so two vaults work side by side.
|
|
12
|
+
- **Policy-aware results**: a transfer either executes, waits for signatures or replays — told apart by status, not guesswork.
|
|
13
|
+
- **Money that cannot silently lose precision**: smallest-unit strings and BigInt arithmetic, with no `toNumber`.
|
|
14
|
+
- **Pluggable authentication**: browser cookie, native cookie jar or bearer token — you supply headers, the SDK hands events back.
|
|
15
|
+
- **Complete**: every endpoint of the API, grouped into resources, with the administrative surface marked.
|
|
16
|
+
- **Fully typed**, zero dependencies, ESM and CommonJS. Runs on Node.js, Bun, Deno, Cloudflare Workers and React Native.
|
|
17
|
+
|
|
18
|
+
The whole API is covered: addresses and transfers, approvals, counterparties, shared access and
|
|
19
|
+
folders, operation labelling, reports, and the administrative surface. A test asserts that every
|
|
20
|
+
endpoint is reachable through some resource, so an endpoint added to the API shows up as a failure
|
|
21
|
+
rather than as a gap nobody noticed.
|
|
22
|
+
|
|
23
|
+
Two endpoints are deliberately absent: `/welcome` is a browser landing page the API redirects to,
|
|
24
|
+
and `/webhooks/wallet` is the inbound channel for the wallet service.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @v3finance/core-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { CoreClient } from '@v3finance/core-sdk'
|
|
36
|
+
|
|
37
|
+
const core = new CoreClient({
|
|
38
|
+
getAuthHeaders: () => ({ Authorization: `Bearer ${sessionToken}` }),
|
|
39
|
+
onTokenRotated: (token) => storage.save(token),
|
|
40
|
+
onUnauthorized: () => router.push('/login'),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const page = await core.vault('my-vault').addresses.list({ limit: 20 })
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Three things to know before the first call
|
|
47
|
+
|
|
48
|
+
### 1. `vault(code)` is an expression, not state
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
core.vault('alpha').addresses.list()
|
|
52
|
+
core.vault('beta').addresses.list()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
There is deliberately no "current vault". The code is visible on every call site, an administrator can
|
|
56
|
+
work with several vaults at once, and switching the active vault at runtime cannot leave a stale scope
|
|
57
|
+
pointing at the wrong one. Build a scope where you use it; do not store it.
|
|
58
|
+
|
|
59
|
+
### 2. An operation may not execute — it may go for approval
|
|
60
|
+
|
|
61
|
+
Transfers and address creation run through the policy engine. The result is `Gated`, and the three
|
|
62
|
+
branches **must** be distinguished: the response body is identical, only the status differs.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
const result = await core.vault(code).transfers.send({
|
|
66
|
+
fromAddressId,
|
|
67
|
+
toAddress,
|
|
68
|
+
amount: '1.5',
|
|
69
|
+
asset: 'usdt',
|
|
70
|
+
idempotencyKey: crypto.randomUUID(),
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
switch (result.outcome) {
|
|
74
|
+
case 'applied':
|
|
75
|
+
return toast('Transfer sent')
|
|
76
|
+
case 'pending':
|
|
77
|
+
return toast('Awaiting signatures — the funds are reserved')
|
|
78
|
+
case 'replayed':
|
|
79
|
+
return toast('This transfer was already sent')
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Reporting "sent" on `pending` tells a person their money has gone when it is frozen.
|
|
84
|
+
|
|
85
|
+
**Always pass `idempotencyKey`** and keep it until you have an answer: after a timeout it is the only
|
|
86
|
+
way to retry without sending money twice.
|
|
87
|
+
|
|
88
|
+
### 3. Amounts are strings, never numbers
|
|
89
|
+
|
|
90
|
+
Balances arrive in smallest units. `float64` loses precision above 2⁵³, and production balances go higher.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { amount, parseDecimal, format, add } from '@v3finance/core-sdk'
|
|
94
|
+
|
|
95
|
+
const balance = amount(address.balance ?? '0', 6, 'usdt')
|
|
96
|
+
format(balance, { withAsset: true }) // "1,500.00 USDT"
|
|
97
|
+
add(balance, parseDecimal('2.5', 6))
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
There is no `toNumber`, on purpose — it would be a convenient door into the bug this layer prevents.
|
|
101
|
+
|
|
102
|
+
**`balance: null` is not zero.** It means the address has no ledger account yet: nothing has ever
|
|
103
|
+
arrived. "No account" and "empty account" deserve different wording in an interface.
|
|
104
|
+
|
|
105
|
+
## Errors
|
|
106
|
+
|
|
107
|
+
Every failure is a `CoreError` and always carries a `code` — sent by the server or derived from the
|
|
108
|
+
HTTP status. Branch on `code`, display `message`.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { hasCode, isCoreError } from '@v3finance/core-sdk'
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
await core.vault(code).transfers.send(input)
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (hasCode(error, 'INSUFFICIENT_BALANCE')) return showTopUp()
|
|
117
|
+
if (hasCode(error, 'APPROVAL_UNSATISFIABLE')) return showNoApprovers()
|
|
118
|
+
if (isCoreError(error) && error.kind === 'timeout') return retryWithSameKey()
|
|
119
|
+
throw error
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`kind` separates `http` (the server answered), `network` (the request never left), `timeout`,
|
|
124
|
+
`aborted` and `parse`.
|
|
125
|
+
|
|
126
|
+
## Authentication
|
|
127
|
+
|
|
128
|
+
The SDK does not store credentials: you provide headers, it reports two events back.
|
|
129
|
+
|
|
130
|
+
| Runtime | How |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| Browser | `credentials: 'include'`, the cookie is set by the server |
|
|
133
|
+
| React Native | your own cookie jar, returned from `getAuthHeaders` |
|
|
134
|
+
| Anywhere | `Authorization: Bearer <session-token>` |
|
|
135
|
+
|
|
136
|
+
In bearer mode **`onTokenRotated` is required**: the server extends a session through the
|
|
137
|
+
`set-auth-token` header, and a client that does not store the new token is signed out at the next
|
|
138
|
+
rotation.
|
|
139
|
+
|
|
140
|
+
Sign-in is a magic link sent by email. Signing up is possible only on an administrator's invitation.
|
|
141
|
+
|
|
142
|
+
## Pagination
|
|
143
|
+
|
|
144
|
+
Lists return `{ items, nextCursor }`. The cursor is opaque — do not parse it.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import { paginate } from '@v3finance/core-sdk'
|
|
148
|
+
|
|
149
|
+
for await (const address of paginate((p) => core.vault(code).addresses.list(p))) {
|
|
150
|
+
console.log(address.address)
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Admin operations
|
|
155
|
+
|
|
156
|
+
The package covers the whole API, administrative endpoints included. Access level is available
|
|
157
|
+
programmatically:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { OPERATIONS, isAdminOperation } from '@v3finance/core-sdk'
|
|
161
|
+
|
|
162
|
+
isAdminOperation('POST /api/v1/policies') // true
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
A method existing in the package grants nothing: the server decides, based on your session.
|
|
166
|
+
|
|
167
|
+
## Staying in sync with the API
|
|
168
|
+
|
|
169
|
+
The repository holds a snapshot of the OpenAPI document (`openapi/spec.json`). Every model is
|
|
170
|
+
generated from it into `src/generated/types.ts` — one exported type per schema, descriptions
|
|
171
|
+
included — by a small purpose-built generator rather than `openapi-typescript`, which is built on
|
|
172
|
+
the TypeScript 5 compiler API that TypeScript 7 no longer ships.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm run spec:update # refresh the snapshot from the live API
|
|
176
|
+
npm run generate # regenerate types and the operation catalogue
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
CI fails when the generated files drift from the snapshot, and when the API gains an operation that
|
|
180
|
+
has not been classified by access level.
|
|
181
|
+
|
|
182
|
+
A test keeps the generated files in step with the snapshot, so a drift shows up in a pull request
|
|
183
|
+
rather than in a consumer at runtime.
|
|
184
|
+
|
|
185
|
+
Development requires Node.js 24 (the build scripts are TypeScript run directly). The published
|
|
186
|
+
package supports Node.js 20 and above.
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { HttpClient, type ClientOptions } from './core/http.js';
|
|
2
|
+
import type { CreateVaultBody, Health, VaultDetail } from './generated/types.js';
|
|
3
|
+
import { AddressesResource } from './resources/addresses.js';
|
|
4
|
+
import { ApprovalsResource } from './resources/approvals.js';
|
|
5
|
+
import { BalancesResource } from './resources/balances.js';
|
|
6
|
+
import { CounterpartiesResource, CounterpartyGroupsResource } from './resources/counterparties.js';
|
|
7
|
+
import { AdminResource } from './resources/admin.js';
|
|
8
|
+
import { AuthResource } from './resources/auth.js';
|
|
9
|
+
import { CategoriesResource } from './resources/categories.js';
|
|
10
|
+
import { FoldersResource } from './resources/folders.js';
|
|
11
|
+
import { HistoryResource } from './resources/history.js';
|
|
12
|
+
import { MembersResource } from './resources/members.js';
|
|
13
|
+
import { OperationsResource } from './resources/operations.js';
|
|
14
|
+
import { RegistriesResource } from './resources/registries.js';
|
|
15
|
+
import { ReportsResource } from './resources/reports.js';
|
|
16
|
+
import { SharingResource } from './resources/sharing.js';
|
|
17
|
+
import { MeResource } from './resources/me.js';
|
|
18
|
+
import { TransfersResource } from './resources/transfers.js';
|
|
19
|
+
/**
|
|
20
|
+
* Client for the V3 Finance Core API.
|
|
21
|
+
*
|
|
22
|
+
* CALL SHAPE: `core.vault(code).addresses.list()`.
|
|
23
|
+
*
|
|
24
|
+
* `vault(code)` is an EXPRESSION, not state. There is deliberately no
|
|
25
|
+
* "current vault" that you set once and forget:
|
|
26
|
+
*
|
|
27
|
+
* • the vault code is visible on every call site, so reading the code does
|
|
28
|
+
* not require scrolling up to find which vault is in effect;
|
|
29
|
+
* • an administrator works with several vaults at once, and two scopes side
|
|
30
|
+
* by side cannot interfere — there is no shared mutable field;
|
|
31
|
+
* • in the mobile app and on the web the active vault changes at runtime,
|
|
32
|
+
* and a remembered scope would mean requests to the wrong vault after a
|
|
33
|
+
* switch.
|
|
34
|
+
*
|
|
35
|
+
* A scope is cheap: it is a pair of small objects over the shared HTTP
|
|
36
|
+
* client, so creating one per call is fine.
|
|
37
|
+
*
|
|
38
|
+
* Cross-vault and registry endpoints live at the root: `core.vaults`, `core.me`.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { CoreClient } from '@v3finance/core-sdk'
|
|
43
|
+
*
|
|
44
|
+
* const core = new CoreClient({
|
|
45
|
+
* getAuthHeaders: () => ({ Authorization: `Bearer ${sessionToken}` }),
|
|
46
|
+
* onTokenRotated: (token) => save(token),
|
|
47
|
+
* onUnauthorized: () => signOut(),
|
|
48
|
+
* })
|
|
49
|
+
*
|
|
50
|
+
* const page = await core.vault('my-vault').addresses.list({ limit: 20 })
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export interface VaultScope {
|
|
54
|
+
readonly code: string;
|
|
55
|
+
readonly addresses: AddressesResource;
|
|
56
|
+
readonly transfers: TransfersResource;
|
|
57
|
+
readonly history: HistoryResource;
|
|
58
|
+
readonly balances: BalancesResource;
|
|
59
|
+
readonly approvals: ApprovalsResource;
|
|
60
|
+
readonly counterparties: CounterpartiesResource;
|
|
61
|
+
readonly counterpartyGroups: CounterpartyGroupsResource;
|
|
62
|
+
readonly sharing: SharingResource;
|
|
63
|
+
readonly folders: FoldersResource;
|
|
64
|
+
readonly members: MembersResource;
|
|
65
|
+
readonly categories: CategoriesResource;
|
|
66
|
+
readonly reports: ReportsResource;
|
|
67
|
+
readonly operations: OperationsResource;
|
|
68
|
+
}
|
|
69
|
+
export interface VaultSummary {
|
|
70
|
+
id: string;
|
|
71
|
+
code: string;
|
|
72
|
+
name: string;
|
|
73
|
+
[extra: string]: unknown;
|
|
74
|
+
}
|
|
75
|
+
export interface Profile {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string | null;
|
|
78
|
+
username: string | null;
|
|
79
|
+
email: string | null;
|
|
80
|
+
/** The account came from an invitation link and has no real email yet. */
|
|
81
|
+
needsEmail: boolean;
|
|
82
|
+
[extra: string]: unknown;
|
|
83
|
+
}
|
|
84
|
+
export declare class CoreClient {
|
|
85
|
+
/** Low-level access for endpoints the resources do not cover yet. */
|
|
86
|
+
readonly http: HttpClient;
|
|
87
|
+
constructor(options?: ClientOptions);
|
|
88
|
+
/** Scope of one vault. Build it at the call site; do not store it. */
|
|
89
|
+
vault(code: string): VaultScope;
|
|
90
|
+
readonly vaults: {
|
|
91
|
+
/** Administrators only: a plain member sees their own vault through `me.vault()`. */
|
|
92
|
+
list: () => Promise<VaultSummary[]>;
|
|
93
|
+
get: (code: string) => Promise<VaultSummary>;
|
|
94
|
+
/** Administrators only. */
|
|
95
|
+
create: (input: CreateVaultBody) => Promise<VaultDetail>;
|
|
96
|
+
/**
|
|
97
|
+
* Assembles a derivation path from segment values, and takes one apart.
|
|
98
|
+
*
|
|
99
|
+
* Use these rather than building the string yourself: the path is written
|
|
100
|
+
* WITHOUT apostrophes (`m/44/195/…`, not `m/44'/…`), and the segment
|
|
101
|
+
* order comes from the vault's own configuration, not from a convention.
|
|
102
|
+
*/
|
|
103
|
+
buildDerivationPath: (code: string, body: unknown) => Promise<unknown>;
|
|
104
|
+
parseDerivationPath: (code: string, body: unknown) => Promise<unknown>;
|
|
105
|
+
};
|
|
106
|
+
/** Liveness probe. Needs no authentication. */
|
|
107
|
+
health(): Promise<Health>;
|
|
108
|
+
/** The caller's own profile, devices and permissions. */
|
|
109
|
+
readonly me: MeResource;
|
|
110
|
+
/** Networks, tokens, rates, policy preflight and AML. Not vault-scoped. */
|
|
111
|
+
readonly registries: RegistriesResource;
|
|
112
|
+
/** Administrative endpoints. Having one here grants nothing — the server decides. */
|
|
113
|
+
readonly admin: AdminResource;
|
|
114
|
+
/** Signing in. One way only: a magic link, and only by invitation. */
|
|
115
|
+
readonly auth: AuthResource;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CoreClient = void 0;
|
|
4
|
+
const http_js_1 = require("./core/http.js");
|
|
5
|
+
const addresses_js_1 = require("./resources/addresses.js");
|
|
6
|
+
const approvals_js_1 = require("./resources/approvals.js");
|
|
7
|
+
const balances_js_1 = require("./resources/balances.js");
|
|
8
|
+
const counterparties_js_1 = require("./resources/counterparties.js");
|
|
9
|
+
const admin_js_1 = require("./resources/admin.js");
|
|
10
|
+
const auth_js_1 = require("./resources/auth.js");
|
|
11
|
+
const categories_js_1 = require("./resources/categories.js");
|
|
12
|
+
const folders_js_1 = require("./resources/folders.js");
|
|
13
|
+
const history_js_1 = require("./resources/history.js");
|
|
14
|
+
const members_js_1 = require("./resources/members.js");
|
|
15
|
+
const operations_js_1 = require("./resources/operations.js");
|
|
16
|
+
const registries_js_1 = require("./resources/registries.js");
|
|
17
|
+
const reports_js_1 = require("./resources/reports.js");
|
|
18
|
+
const sharing_js_1 = require("./resources/sharing.js");
|
|
19
|
+
const me_js_1 = require("./resources/me.js");
|
|
20
|
+
const transfers_js_1 = require("./resources/transfers.js");
|
|
21
|
+
const version_js_1 = require("./version.js");
|
|
22
|
+
class CoreClient {
|
|
23
|
+
/** Low-level access for endpoints the resources do not cover yet. */
|
|
24
|
+
http;
|
|
25
|
+
constructor(options = {}) {
|
|
26
|
+
this.http = new http_js_1.HttpClient({ ...options, baseUrl: options.baseUrl ?? version_js_1.DEFAULT_BASE_URL });
|
|
27
|
+
this.me = new me_js_1.MeResource(this.http);
|
|
28
|
+
this.registries = new registries_js_1.RegistriesResource(this.http);
|
|
29
|
+
this.admin = new admin_js_1.AdminResource(this.http);
|
|
30
|
+
this.auth = new auth_js_1.AuthResource(this.http);
|
|
31
|
+
}
|
|
32
|
+
/** Scope of one vault. Build it at the call site; do not store it. */
|
|
33
|
+
vault(code) {
|
|
34
|
+
if (!code)
|
|
35
|
+
throw new Error('@v3finance/core-sdk: a vault code is required.');
|
|
36
|
+
return {
|
|
37
|
+
code,
|
|
38
|
+
addresses: new addresses_js_1.AddressesResource(this.http, code),
|
|
39
|
+
transfers: new transfers_js_1.TransfersResource(this.http, code),
|
|
40
|
+
history: new history_js_1.HistoryResource(this.http, code),
|
|
41
|
+
balances: new balances_js_1.BalancesResource(this.http, code),
|
|
42
|
+
approvals: new approvals_js_1.ApprovalsResource(this.http, code),
|
|
43
|
+
counterparties: new counterparties_js_1.CounterpartiesResource(this.http, code),
|
|
44
|
+
counterpartyGroups: new counterparties_js_1.CounterpartyGroupsResource(this.http, code),
|
|
45
|
+
sharing: new sharing_js_1.SharingResource(this.http, code),
|
|
46
|
+
folders: new folders_js_1.FoldersResource(this.http, code),
|
|
47
|
+
members: new members_js_1.MembersResource(this.http, code),
|
|
48
|
+
categories: new categories_js_1.CategoriesResource(this.http, code),
|
|
49
|
+
reports: new reports_js_1.ReportsResource(this.http, code),
|
|
50
|
+
operations: new operations_js_1.OperationsResource(this.http, code),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
vaults = {
|
|
54
|
+
/** Administrators only: a plain member sees their own vault through `me.vault()`. */
|
|
55
|
+
list: () => this.http.request('GET', '/api/v1/vaults'),
|
|
56
|
+
get: (code) => this.http.request('GET', `/api/v1/vaults/${(0, http_js_1.seg)(code)}`),
|
|
57
|
+
/** Administrators only. */
|
|
58
|
+
create: (input) => this.http.request('POST', '/api/v1/vaults', { body: input }),
|
|
59
|
+
/**
|
|
60
|
+
* Assembles a derivation path from segment values, and takes one apart.
|
|
61
|
+
*
|
|
62
|
+
* Use these rather than building the string yourself: the path is written
|
|
63
|
+
* WITHOUT apostrophes (`m/44/195/…`, not `m/44'/…`), and the segment
|
|
64
|
+
* order comes from the vault's own configuration, not from a convention.
|
|
65
|
+
*/
|
|
66
|
+
buildDerivationPath: (code, body) => this.http.request('POST', `/api/v1/vaults/${(0, http_js_1.seg)(code)}/derivation-path/build`, { body }),
|
|
67
|
+
parseDerivationPath: (code, body) => this.http.request('POST', `/api/v1/vaults/${(0, http_js_1.seg)(code)}/derivation-path/parse`, { body }),
|
|
68
|
+
};
|
|
69
|
+
/** Liveness probe. Needs no authentication. */
|
|
70
|
+
health() {
|
|
71
|
+
return this.http.request('GET', '/');
|
|
72
|
+
}
|
|
73
|
+
/** The caller's own profile, devices and permissions. */
|
|
74
|
+
me;
|
|
75
|
+
/** Networks, tokens, rates, policy preflight and AML. Not vault-scoped. */
|
|
76
|
+
registries;
|
|
77
|
+
/** Administrative endpoints. Having one here grants nothing — the server decides. */
|
|
78
|
+
admin;
|
|
79
|
+
/** Signing in. One way only: a magic link, and only by invitation. */
|
|
80
|
+
auth;
|
|
81
|
+
}
|
|
82
|
+
exports.CoreClient = CoreClient;
|
|
83
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every failure from the SDK is a `CoreError`.
|
|
3
|
+
*
|
|
4
|
+
* The API wraps errors into `{error:{code,message,details?}}`, but that
|
|
5
|
+
* wrapper has three gaps the client has to close itself — otherwise a precise
|
|
6
|
+
* error turns into "something went wrong":
|
|
7
|
+
*
|
|
8
|
+
* 1. Bodies without an `error` key pass through untouched. Batch sharing
|
|
9
|
+
* endpoints answer 400 with `{results:[…]}`, which is not a failure of
|
|
10
|
+
* the whole call but "some subjects were rejected", and has to be read
|
|
11
|
+
* item by item.
|
|
12
|
+
* 2. Validation failures arrive as a plain string — `{error: "path: msg"}`
|
|
13
|
+
* — with no code and no details.
|
|
14
|
+
* 3. Inside a batch result `message` equals the code (`{code:"X",
|
|
15
|
+
* message:"X"}`), so it must never be shown to a person as-is.
|
|
16
|
+
*
|
|
17
|
+
* Because of that `code` is always present here: either the server sent one,
|
|
18
|
+
* or it is derived from the HTTP status. Branch on `code`, display `message`.
|
|
19
|
+
*/
|
|
20
|
+
/** Where the failure came from. Each kind calls for a different reaction. */
|
|
21
|
+
export type CoreErrorKind =
|
|
22
|
+
/** The server answered with a status >= 400. `status` and `code` are meaningful. */
|
|
23
|
+
'http'
|
|
24
|
+
/** The request never left: no connection, DNS, socket closed. Retrying makes sense. */
|
|
25
|
+
| 'network'
|
|
26
|
+
/** The request timed out. On money paths retry only with the same idempotency key. */
|
|
27
|
+
| 'timeout'
|
|
28
|
+
/** The caller aborted it. Not a failure — do not surface it. */
|
|
29
|
+
| 'aborted'
|
|
30
|
+
/** A response arrived but could not be read as the contract promises. */
|
|
31
|
+
| 'parse';
|
|
32
|
+
export interface CoreErrorInit {
|
|
33
|
+
kind: CoreErrorKind;
|
|
34
|
+
message: string;
|
|
35
|
+
code: string;
|
|
36
|
+
status?: number | null;
|
|
37
|
+
details?: unknown;
|
|
38
|
+
/** `METHOD /path`, for logs. Never part of the user-facing message. */
|
|
39
|
+
endpoint?: string;
|
|
40
|
+
cause?: unknown;
|
|
41
|
+
}
|
|
42
|
+
export declare class CoreError extends Error {
|
|
43
|
+
readonly kind: CoreErrorKind;
|
|
44
|
+
/** Machine-readable code. Never empty: sent by the server or derived from the status. */
|
|
45
|
+
readonly code: string;
|
|
46
|
+
/** HTTP status, or `null` for network, timeout and aborted failures. */
|
|
47
|
+
readonly status: number | null;
|
|
48
|
+
/** Structured details when the handler provided them. The shape depends on `code`. */
|
|
49
|
+
readonly details: unknown;
|
|
50
|
+
readonly endpoint: string | undefined;
|
|
51
|
+
constructor(init: CoreErrorInit);
|
|
52
|
+
}
|
|
53
|
+
export declare function isCoreError(e: unknown): e is CoreError;
|
|
54
|
+
/** Convenience for `catch`: `if (hasCode(e, 'INSUFFICIENT_BALANCE'))`. */
|
|
55
|
+
export declare function hasCode(e: unknown, ...codes: readonly string[]): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Status to code, mirroring the mapping the API uses, so that both sides call
|
|
58
|
+
* the same thing by the same name.
|
|
59
|
+
*/
|
|
60
|
+
export declare function codeFromStatus(status: number): string;
|
|
61
|
+
/**
|
|
62
|
+
* Turns an error response body into a `CoreError`.
|
|
63
|
+
*
|
|
64
|
+
* Reads both places a code can live: the nested `error.code` and a flat `code`
|
|
65
|
+
* next to `error`. The API populates either one depending on the path.
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseErrorBody(status: number, body: unknown, endpoint?: string): CoreError;
|
|
68
|
+
export declare const networkError: (cause: unknown, endpoint?: string) => CoreError;
|
|
69
|
+
export declare const timeoutError: (ms: number, endpoint?: string) => CoreError;
|
|
70
|
+
export declare const abortedError: (endpoint?: string) => CoreError;
|
|
71
|
+
export declare const parseError: (cause: unknown, endpoint?: string) => CoreError;
|
|
72
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,6EAA6E;AAC7E,MAAM,MAAM,aAAa;AACvB,oFAAoF;AAClF,MAAM;AACR,uFAAuF;GACrF,SAAS;AACX,sFAAsF;GACpF,SAAS;AACX,gEAAgE;GAC9D,SAAS;AACX,yEAAyE;GACvE,OAAO,CAAA;AAEX,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,aAAa,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,sFAAsF;IACtF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAErC,YAAY,IAAI,EAAE,aAAa,EAQ9B;CACF;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,SAAS,CAEtD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAExE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAyBrD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAiD1F;AAsBD,eAAO,MAAM,YAAY,UAAW,OAAO,aAAa,MAAM,KAAG,SAQ7D,CAAA;AAEJ,eAAO,MAAM,YAAY,OAAQ,MAAM,aAAa,MAAM,KAAG,SAOzD,CAAA;AAEJ,eAAO,MAAM,YAAY,cAAe,MAAM,KAAG,SAO7C,CAAA;AAEJ,eAAO,MAAM,UAAU,UAAW,OAAO,aAAa,MAAM,KAAG,SAQ3D,CAAA"}
|