@v3finance/core-sdk 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +441 -7
- package/README.md +219 -73
- package/dist/cjs/client.d.ts +67 -22
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +38 -2
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/core/errors.d.ts +30 -10
- package/dist/cjs/core/errors.d.ts.map +1 -1
- package/dist/cjs/core/errors.js +47 -15
- package/dist/cjs/core/errors.js.map +1 -1
- package/dist/cjs/core/gated.d.ts +30 -6
- package/dist/cjs/core/gated.d.ts.map +1 -1
- package/dist/cjs/core/gated.js +21 -6
- package/dist/cjs/core/gated.js.map +1 -1
- package/dist/cjs/core/http.d.ts +12 -8
- package/dist/cjs/core/http.d.ts.map +1 -1
- package/dist/cjs/core/http.js +147 -43
- package/dist/cjs/core/http.js.map +1 -1
- package/dist/cjs/core/pagination.d.ts +28 -1
- package/dist/cjs/core/pagination.d.ts.map +1 -1
- package/dist/cjs/core/pagination.js +36 -1
- package/dist/cjs/core/pagination.js.map +1 -1
- package/dist/cjs/generated/operations.js +1 -1
- package/dist/cjs/generated/types.d.ts +965 -179
- package/dist/cjs/generated/types.d.ts.map +1 -1
- package/dist/cjs/index.d.ts +32 -8
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/resources/addresses.d.ts +23 -8
- package/dist/cjs/resources/addresses.d.ts.map +1 -1
- package/dist/cjs/resources/addresses.js +8 -1
- package/dist/cjs/resources/addresses.js.map +1 -1
- package/dist/cjs/resources/admin.d.ts +150 -25
- package/dist/cjs/resources/admin.d.ts.map +1 -1
- package/dist/cjs/resources/admin.js +94 -23
- package/dist/cjs/resources/admin.js.map +1 -1
- package/dist/cjs/resources/approvals.d.ts +46 -5
- package/dist/cjs/resources/approvals.d.ts.map +1 -1
- package/dist/cjs/resources/approvals.js +27 -4
- package/dist/cjs/resources/approvals.js.map +1 -1
- package/dist/cjs/resources/balances.d.ts +152 -16
- package/dist/cjs/resources/balances.d.ts.map +1 -1
- package/dist/cjs/resources/balances.js +9 -5
- package/dist/cjs/resources/balances.js.map +1 -1
- package/dist/cjs/resources/categories.d.ts +93 -21
- package/dist/cjs/resources/categories.d.ts.map +1 -1
- package/dist/cjs/resources/categories.js +65 -18
- package/dist/cjs/resources/categories.js.map +1 -1
- package/dist/cjs/resources/counterparties.d.ts +26 -3
- package/dist/cjs/resources/counterparties.d.ts.map +1 -1
- package/dist/cjs/resources/counterparties.js +17 -0
- package/dist/cjs/resources/counterparties.js.map +1 -1
- package/dist/cjs/resources/folders.d.ts +51 -10
- package/dist/cjs/resources/folders.d.ts.map +1 -1
- package/dist/cjs/resources/folders.js +36 -5
- package/dist/cjs/resources/folders.js.map +1 -1
- package/dist/cjs/resources/history.d.ts +20 -2
- package/dist/cjs/resources/history.d.ts.map +1 -1
- package/dist/cjs/resources/history.js.map +1 -1
- package/dist/cjs/resources/me.d.ts +27 -4
- package/dist/cjs/resources/me.d.ts.map +1 -1
- package/dist/cjs/resources/me.js +22 -1
- package/dist/cjs/resources/me.js.map +1 -1
- package/dist/cjs/resources/members.d.ts +19 -4
- package/dist/cjs/resources/members.d.ts.map +1 -1
- package/dist/cjs/resources/members.js +15 -6
- package/dist/cjs/resources/members.js.map +1 -1
- package/dist/cjs/resources/operations.d.ts +64 -8
- package/dist/cjs/resources/operations.d.ts.map +1 -1
- package/dist/cjs/resources/operations.js +26 -2
- package/dist/cjs/resources/operations.js.map +1 -1
- package/dist/cjs/resources/registries.d.ts +87 -9
- package/dist/cjs/resources/registries.d.ts.map +1 -1
- package/dist/cjs/resources/registries.js +54 -11
- package/dist/cjs/resources/registries.js.map +1 -1
- package/dist/cjs/resources/reports.d.ts +300 -41
- package/dist/cjs/resources/reports.d.ts.map +1 -1
- package/dist/cjs/resources/reports.js +135 -7
- package/dist/cjs/resources/reports.js.map +1 -1
- package/dist/cjs/resources/sharing.d.ts +61 -10
- package/dist/cjs/resources/sharing.d.ts.map +1 -1
- package/dist/cjs/resources/sharing.js +51 -4
- package/dist/cjs/resources/sharing.js.map +1 -1
- package/dist/cjs/resources/transfers.d.ts +44 -6
- package/dist/cjs/resources/transfers.d.ts.map +1 -1
- package/dist/cjs/resources/transfers.js +41 -3
- package/dist/cjs/resources/transfers.js.map +1 -1
- package/dist/cjs/resources/types.d.ts +16 -0
- package/dist/cjs/resources/types.d.ts.map +1 -1
- package/dist/cjs/units.d.ts.map +1 -1
- package/dist/cjs/units.js +18 -2
- package/dist/cjs/units.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client.d.ts +67 -22
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +38 -2
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/core/errors.d.ts +30 -10
- package/dist/esm/core/errors.d.ts.map +1 -1
- package/dist/esm/core/errors.js +47 -15
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/gated.d.ts +30 -6
- package/dist/esm/core/gated.d.ts.map +1 -1
- package/dist/esm/core/gated.js +21 -6
- package/dist/esm/core/gated.js.map +1 -1
- package/dist/esm/core/http.d.ts +12 -8
- package/dist/esm/core/http.d.ts.map +1 -1
- package/dist/esm/core/http.js +148 -44
- package/dist/esm/core/http.js.map +1 -1
- package/dist/esm/core/pagination.d.ts +28 -1
- package/dist/esm/core/pagination.d.ts.map +1 -1
- package/dist/esm/core/pagination.js +36 -1
- package/dist/esm/core/pagination.js.map +1 -1
- package/dist/esm/generated/operations.js +1 -1
- package/dist/esm/generated/types.d.ts +965 -179
- package/dist/esm/generated/types.d.ts.map +1 -1
- package/dist/esm/index.d.ts +32 -8
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +17 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resources/addresses.d.ts +23 -8
- package/dist/esm/resources/addresses.d.ts.map +1 -1
- package/dist/esm/resources/addresses.js +8 -1
- package/dist/esm/resources/addresses.js.map +1 -1
- package/dist/esm/resources/admin.d.ts +150 -25
- package/dist/esm/resources/admin.d.ts.map +1 -1
- package/dist/esm/resources/admin.js +94 -23
- package/dist/esm/resources/admin.js.map +1 -1
- package/dist/esm/resources/approvals.d.ts +46 -5
- package/dist/esm/resources/approvals.d.ts.map +1 -1
- package/dist/esm/resources/approvals.js +27 -4
- package/dist/esm/resources/approvals.js.map +1 -1
- package/dist/esm/resources/balances.d.ts +152 -16
- package/dist/esm/resources/balances.d.ts.map +1 -1
- package/dist/esm/resources/balances.js +9 -5
- package/dist/esm/resources/balances.js.map +1 -1
- package/dist/esm/resources/categories.d.ts +93 -21
- package/dist/esm/resources/categories.d.ts.map +1 -1
- package/dist/esm/resources/categories.js +65 -18
- package/dist/esm/resources/categories.js.map +1 -1
- package/dist/esm/resources/counterparties.d.ts +26 -3
- package/dist/esm/resources/counterparties.d.ts.map +1 -1
- package/dist/esm/resources/counterparties.js +17 -0
- package/dist/esm/resources/counterparties.js.map +1 -1
- package/dist/esm/resources/folders.d.ts +51 -10
- package/dist/esm/resources/folders.d.ts.map +1 -1
- package/dist/esm/resources/folders.js +36 -5
- package/dist/esm/resources/folders.js.map +1 -1
- package/dist/esm/resources/history.d.ts +20 -2
- package/dist/esm/resources/history.d.ts.map +1 -1
- package/dist/esm/resources/history.js.map +1 -1
- package/dist/esm/resources/me.d.ts +27 -4
- package/dist/esm/resources/me.d.ts.map +1 -1
- package/dist/esm/resources/me.js +22 -1
- package/dist/esm/resources/me.js.map +1 -1
- package/dist/esm/resources/members.d.ts +19 -4
- package/dist/esm/resources/members.d.ts.map +1 -1
- package/dist/esm/resources/members.js +15 -6
- package/dist/esm/resources/members.js.map +1 -1
- package/dist/esm/resources/operations.d.ts +64 -8
- package/dist/esm/resources/operations.d.ts.map +1 -1
- package/dist/esm/resources/operations.js +26 -2
- package/dist/esm/resources/operations.js.map +1 -1
- package/dist/esm/resources/registries.d.ts +87 -9
- package/dist/esm/resources/registries.d.ts.map +1 -1
- package/dist/esm/resources/registries.js +54 -11
- package/dist/esm/resources/registries.js.map +1 -1
- package/dist/esm/resources/reports.d.ts +300 -41
- package/dist/esm/resources/reports.d.ts.map +1 -1
- package/dist/esm/resources/reports.js +135 -7
- package/dist/esm/resources/reports.js.map +1 -1
- package/dist/esm/resources/sharing.d.ts +61 -10
- package/dist/esm/resources/sharing.d.ts.map +1 -1
- package/dist/esm/resources/sharing.js +51 -4
- package/dist/esm/resources/sharing.js.map +1 -1
- package/dist/esm/resources/transfers.d.ts +44 -6
- package/dist/esm/resources/transfers.d.ts.map +1 -1
- package/dist/esm/resources/transfers.js +41 -3
- package/dist/esm/resources/transfers.js.map +1 -1
- package/dist/esm/resources/types.d.ts +16 -0
- package/dist/esm/resources/types.d.ts.map +1 -1
- package/dist/esm/units.d.ts.map +1 -1
- package/dist/esm/units.js +18 -2
- package/dist/esm/units.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/concepts.md +193 -0
- package/docs/errors.md +491 -0
- package/package.json +7 -6
- package/src/client.ts +89 -25
- package/src/core/errors.ts +49 -15
- package/src/core/gated.ts +31 -7
- package/src/core/http.ts +173 -49
- package/src/core/pagination.ts +38 -1
- package/src/generated/operations.ts +1 -1
- package/src/generated/types.ts +1001 -180
- package/src/index.ts +64 -7
- package/src/resources/addresses.ts +24 -8
- package/src/resources/admin.ts +186 -33
- package/src/resources/approvals.ts +55 -9
- package/src/resources/balances.ts +186 -14
- package/src/resources/categories.ts +125 -30
- package/src/resources/counterparties.ts +23 -6
- package/src/resources/folders.ts +74 -18
- package/src/resources/history.ts +27 -2
- package/src/resources/me.ts +30 -5
- package/src/resources/members.ts +26 -7
- package/src/resources/operations.ts +73 -8
- package/src/resources/registries.ts +90 -11
- package/src/resources/reports.ts +348 -67
- package/src/resources/sharing.ts +71 -18
- package/src/resources/transfers.ts +51 -7
- package/src/resources/types.ts +16 -0
- package/src/units.ts +19 -2
- package/src/version.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -11,7 +11,20 @@
|
|
|
11
11
|
* Signing up is possible only on an administrator's invitation.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
export { CoreClient, type VaultScope
|
|
14
|
+
export { CoreClient, type VaultScope } from './client.js'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Kept so that existing imports keep resolving. Both are now strict aliases
|
|
18
|
+
* of generated schemas — `VaultSummary` of `VaultListItem`, `Profile` of
|
|
19
|
+
* `UserProfile` — and new code should name those instead.
|
|
20
|
+
*
|
|
21
|
+
* They are listed apart from `CoreClient` on purpose: an explicit re-export
|
|
22
|
+
* SHADOWS the same name coming from `export type * from './generated/types'`
|
|
23
|
+
* below, so a hand-written type parked in this list quietly becomes the one
|
|
24
|
+
* consumers get. Anything added here has to be identical to the schema it
|
|
25
|
+
* covers, or carry a name the schemas do not use.
|
|
26
|
+
*/
|
|
27
|
+
export type { VaultSummary, Profile } from './client.js'
|
|
15
28
|
|
|
16
29
|
export {
|
|
17
30
|
HttpClient,
|
|
@@ -76,13 +89,29 @@ export {
|
|
|
76
89
|
} from './resources/addresses.js'
|
|
77
90
|
|
|
78
91
|
export { TransfersResource, type VoteInput } from './resources/transfers.js'
|
|
79
|
-
export {
|
|
92
|
+
export {
|
|
93
|
+
HistoryResource,
|
|
94
|
+
type HistoryParams,
|
|
95
|
+
type HistoryStatusFilter,
|
|
96
|
+
} from './resources/history.js'
|
|
80
97
|
export { MeResource } from './resources/me.js'
|
|
81
98
|
export { SharingResource } from './resources/sharing.js'
|
|
82
99
|
export { FoldersResource } from './resources/folders.js'
|
|
83
100
|
export { MembersResource } from './resources/members.js'
|
|
84
|
-
export { RegistriesResource } from './resources/registries.js'
|
|
101
|
+
export { RegistriesResource, type AmlScore } from './resources/registries.js'
|
|
85
102
|
export { CategoriesResource, type OperationType } from './resources/categories.js'
|
|
103
|
+
/**
|
|
104
|
+
* `ReportSnapshotListItem` and `ReportSnapshotDetail` are also the names of
|
|
105
|
+
* generated schemas, and listing them here shadows those. That is safe only
|
|
106
|
+
* because both are strict aliases (`export type X = GeneratedX`) — see the
|
|
107
|
+
* note on `VaultSummary` above, and `test/nameShadowing.test.ts`, which fails
|
|
108
|
+
* the moment one of them stops being identical. The same goes for
|
|
109
|
+
* `LedgerPosting` in the balances block below.
|
|
110
|
+
*
|
|
111
|
+
* The report schemas themselves — `TransactionActivityReport`,
|
|
112
|
+
* `BalancePositionReport`, `AnyReport` and the rest of what `ReportResult`
|
|
113
|
+
* maps to — are not listed: they reach consumers through `export type *`.
|
|
114
|
+
*/
|
|
86
115
|
export {
|
|
87
116
|
ReportsResource,
|
|
88
117
|
type ReportType,
|
|
@@ -90,12 +119,40 @@ export {
|
|
|
90
119
|
type ReportParams,
|
|
91
120
|
type ReportResult,
|
|
92
121
|
type ReportSnapshotListItem,
|
|
122
|
+
type ReportSnapshotDetail,
|
|
123
|
+
type DrilldownQuery,
|
|
124
|
+
type DrilldownFilters,
|
|
125
|
+
type DrilldownSelection,
|
|
93
126
|
} from './resources/reports.js'
|
|
94
|
-
export {
|
|
127
|
+
export {
|
|
128
|
+
AdminResource,
|
|
129
|
+
type PlatformRole,
|
|
130
|
+
type PolicyRow,
|
|
131
|
+
type PolicyRowWithGroup,
|
|
132
|
+
type VaultPoliciesParams,
|
|
133
|
+
} from './resources/admin.js'
|
|
95
134
|
export { AuthResource } from './resources/auth.js'
|
|
96
|
-
export {
|
|
97
|
-
|
|
98
|
-
|
|
135
|
+
export {
|
|
136
|
+
OperationsResource,
|
|
137
|
+
type OperationKind,
|
|
138
|
+
type ListRelationsParams,
|
|
139
|
+
} from './resources/operations.js'
|
|
140
|
+
export {
|
|
141
|
+
ApprovalsResource,
|
|
142
|
+
type ListApprovalsParams,
|
|
143
|
+
type ApprovalRequestStatus,
|
|
144
|
+
} from './resources/approvals.js'
|
|
145
|
+
export {
|
|
146
|
+
BalancesResource,
|
|
147
|
+
type BalancesParams,
|
|
148
|
+
type BalancesAsOfParams,
|
|
149
|
+
type BalancesAsOfSummary,
|
|
150
|
+
type BalancesAsOfWithAccounts,
|
|
151
|
+
type LedgerEntryItem,
|
|
152
|
+
type LedgerEntryType,
|
|
153
|
+
type LedgerPosting,
|
|
154
|
+
type LedgerPurpose,
|
|
155
|
+
} from './resources/balances.js'
|
|
99
156
|
export {
|
|
100
157
|
CounterpartiesResource,
|
|
101
158
|
CounterpartyGroupsResource,
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import { seg, type HttpClient } from '../core/http.js'
|
|
2
2
|
import type { Page, PageParams } from '../core/pagination.js'
|
|
3
3
|
import { toGated, type Gated } from '../core/gated.js'
|
|
4
|
-
|
|
5
|
-
/** Returned when creating an address required approval instead of running. */
|
|
6
|
-
export interface PendingApproval {
|
|
7
|
-
status: string
|
|
8
|
-
approvalRequestId: string
|
|
9
|
-
approvalThreshold: number
|
|
10
|
-
}
|
|
11
4
|
import type { Address, AddressDetail } from './types.js'
|
|
12
5
|
import type {
|
|
13
6
|
CreateAddressBody,
|
|
14
7
|
CreateAddressResult,
|
|
15
8
|
PatchAddressBody,
|
|
9
|
+
PendingApproval as GeneratedPendingApproval,
|
|
16
10
|
} from '../generated/types.js'
|
|
17
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Returned when creating an address required approval instead of running.
|
|
14
|
+
*
|
|
15
|
+
* A strict alias, not a hand-written copy. The copy declared `status: string`
|
|
16
|
+
* and, because `src/index.ts` re-exports this name explicitly, it won the
|
|
17
|
+
* contest against `export type *` and became what consumers saw — a wider
|
|
18
|
+
* type than the API can produce, where the only value is the literal
|
|
19
|
+
* `"awaiting_approval"`.
|
|
20
|
+
*
|
|
21
|
+
* Do not reach for `status` to tell the two outcomes apart: `Gated` already
|
|
22
|
+
* distinguishes them by `outcome`, and this branch is only ever reached when
|
|
23
|
+
* nothing was created.
|
|
24
|
+
*/
|
|
25
|
+
export type PendingApproval = GeneratedPendingApproval
|
|
26
|
+
|
|
18
27
|
export interface ListAddressesParams extends PageParams {
|
|
19
28
|
/** Token code: `usdt`, `a7a5`. */
|
|
20
29
|
token?: string | undefined
|
|
@@ -61,7 +70,14 @@ export class AddressesResource {
|
|
|
61
70
|
return toGated<CreateAddressResult, PendingApproval>(res.status, res.data)
|
|
62
71
|
}
|
|
63
72
|
|
|
64
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Metadata only: this touches neither money nor the derivation path.
|
|
75
|
+
*
|
|
76
|
+
* Answers with the same row as the listing — `owner`, `access` and
|
|
77
|
+
* `sharing` included — so it can replace the address in a list without a
|
|
78
|
+
* refetch. Recent operations and `shares`, which `get()` carries, are not
|
|
79
|
+
* in it.
|
|
80
|
+
*/
|
|
65
81
|
update(addressId: string, input: PatchAddressBody): Promise<Address> {
|
|
66
82
|
return this.#http.request<Address>('PATCH', `${this.#base}/${seg(addressId)}`, { body: input })
|
|
67
83
|
}
|
package/src/resources/admin.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { seg, type HttpClient } from '../core/http.js'
|
|
2
2
|
import type { PageParams } from '../core/pagination.js'
|
|
3
3
|
import type {
|
|
4
|
+
AcceptDebugBody,
|
|
5
|
+
AcceptResult,
|
|
6
|
+
ActionType,
|
|
4
7
|
CreateInvitationBody,
|
|
8
|
+
Effect,
|
|
9
|
+
Invitation,
|
|
10
|
+
InvitationListItem,
|
|
11
|
+
InvitationPublic,
|
|
12
|
+
Membership,
|
|
5
13
|
PolicyGroup,
|
|
14
|
+
PolicyGroupWithCounts,
|
|
6
15
|
PolicyTableItem,
|
|
7
16
|
PolicyWithRules,
|
|
8
17
|
CreateSeatBody,
|
|
@@ -17,10 +26,49 @@ import type {
|
|
|
17
26
|
PolicyDetail,
|
|
18
27
|
PolicyGroupDetail,
|
|
19
28
|
PolicyVersionList,
|
|
29
|
+
UserGroupItem,
|
|
20
30
|
VaultPoliciesPage,
|
|
21
31
|
VisibilityGrant,
|
|
22
32
|
} from '../generated/types.js'
|
|
23
33
|
|
|
34
|
+
/**
|
|
35
|
+
* A policy as the two LISTING endpoints return it. A strict alias of the
|
|
36
|
+
* generated `PolicyTableItem`, kept under its earlier name.
|
|
37
|
+
*
|
|
38
|
+
* There is NO `conditionJson` and no `approvalJson` here: neither listing
|
|
39
|
+
* selects them, so a row cannot tell you whether a policy is conditional —
|
|
40
|
+
* and treating the absence as "applies always" is the opposite of what a
|
|
41
|
+
* condition usually says. Load one policy (`policies.get`) when you need the
|
|
42
|
+
* rule itself; the vault-scoped page (`vault().policies`) does carry both
|
|
43
|
+
* fields.
|
|
44
|
+
*/
|
|
45
|
+
export type PolicyRow = PolicyTableItem
|
|
46
|
+
|
|
47
|
+
/** Filters of the vault-scoped policy page (`vault().policies`). */
|
|
48
|
+
export interface VaultPoliciesParams extends PageParams {
|
|
49
|
+
actionType?: ActionType | undefined
|
|
50
|
+
/**
|
|
51
|
+
* `requireApproval` is accepted here and nowhere else. A policy's own
|
|
52
|
+
* effect has been `allow | block` only since approval became a property of
|
|
53
|
+
* an allowing policy rather than an effect of its own, so this third value
|
|
54
|
+
* exists for rows written before that change — not for new ones.
|
|
55
|
+
*/
|
|
56
|
+
effect?: Effect | 'requireApproval' | undefined
|
|
57
|
+
enabled?: boolean | undefined
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A policy from the flat vault listing, which also names its owner group. */
|
|
61
|
+
export interface PolicyRowWithGroup extends PolicyRow {
|
|
62
|
+
groupId: string
|
|
63
|
+
group: {
|
|
64
|
+
id: string
|
|
65
|
+
code: string
|
|
66
|
+
name: string
|
|
67
|
+
color: string | null
|
|
68
|
+
emoji: string | null
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
24
72
|
/**
|
|
25
73
|
* Administrative endpoints.
|
|
26
74
|
*
|
|
@@ -33,6 +81,12 @@ import type {
|
|
|
33
81
|
* this OBJECT" — grants — lives with the resources it belongs to
|
|
34
82
|
* (`sharing`, `folders`, `categories`).
|
|
35
83
|
*/
|
|
84
|
+
/**
|
|
85
|
+
* The PLATFORM role, from the spec's own enum. Not a role inside a vault —
|
|
86
|
+
* a platform `admin` sees every vault while belonging to none.
|
|
87
|
+
*/
|
|
88
|
+
export type PlatformRole = 'admin' | 'user'
|
|
89
|
+
|
|
36
90
|
export class AdminResource {
|
|
37
91
|
readonly #http: HttpClient
|
|
38
92
|
|
|
@@ -63,15 +117,26 @@ export class AdminResource {
|
|
|
63
117
|
/**
|
|
64
118
|
* `vaultId` is REQUIRED — the endpoint lists policies of one vault and
|
|
65
119
|
* answers 400 without it. It is also NOT paginated: everything comes
|
|
66
|
-
* back in one array.
|
|
120
|
+
* back in one array, sorted group then code.
|
|
121
|
+
*
|
|
122
|
+
* `actionType` is spelled out rather than left as a string because the
|
|
123
|
+
* API does not validate it here: an unrecognised value is passed to the
|
|
124
|
+
* query as-is and comes back as an EMPTY list, which reads like "this
|
|
125
|
+
* vault has no transfer policies" instead of "you misspelled it". The
|
|
126
|
+
* vault-scoped twin (`vault().policies`) declares the same ten values as
|
|
127
|
+
* an enum, so one spelling serves both.
|
|
128
|
+
*
|
|
129
|
+
* `effect` is `allow | block` only. Approval stopped being an effect when
|
|
130
|
+
* it became a property of an allowing policy; the vault-scoped twin still
|
|
131
|
+
* accepts the historical third value, this one does not and answers 400.
|
|
67
132
|
*/
|
|
68
133
|
list: (params: {
|
|
69
134
|
vaultId: string
|
|
70
|
-
groupId?: string
|
|
71
|
-
actionType?:
|
|
72
|
-
effect?:
|
|
73
|
-
enabled?: boolean
|
|
74
|
-
}) => this.#http.request<{ items:
|
|
135
|
+
groupId?: string | undefined
|
|
136
|
+
actionType?: ActionType | undefined
|
|
137
|
+
effect?: Effect | undefined
|
|
138
|
+
enabled?: boolean | undefined
|
|
139
|
+
}) => this.#http.request<{ items: PolicyRowWithGroup[] }>('GET', '/api/v1/policies', {
|
|
75
140
|
query: { ...params },
|
|
76
141
|
}),
|
|
77
142
|
|
|
@@ -109,10 +174,23 @@ export class AdminResource {
|
|
|
109
174
|
get: (groupId: string) =>
|
|
110
175
|
this.#http.request<PolicyGroupDetail>('GET', `/api/v1/policy-groups/${seg(groupId)}`),
|
|
111
176
|
|
|
112
|
-
policies
|
|
113
|
-
|
|
177
|
+
/** This group's policies for a table view: every field but the rules. */
|
|
178
|
+
policies: (groupId: string, params: { actionType?: ActionType | undefined } = {}) =>
|
|
179
|
+
this.#http.request<PolicyRow[]>('GET', `/api/v1/policy-groups/${seg(groupId)}/policies`, {
|
|
180
|
+
query: { ...params },
|
|
181
|
+
}),
|
|
114
182
|
|
|
115
|
-
/**
|
|
183
|
+
/**
|
|
184
|
+
* What this group's members can reach: the group, its member count, its
|
|
185
|
+
* policies and the three kinds of grant held by the group as a subject
|
|
186
|
+
* (addresses, member visibility, operation categories).
|
|
187
|
+
*
|
|
188
|
+
* Left untyped. The API declares this body inline, so there is no
|
|
189
|
+
* generated name to import, and it nests four different resources —
|
|
190
|
+
* hand-writing them here would add exactly the kind of duplicated shape
|
|
191
|
+
* that drifts from the API with nothing to notice it. Narrow it at the
|
|
192
|
+
* call site, or read the single-purpose endpoints.
|
|
193
|
+
*/
|
|
116
194
|
access: (groupId: string) =>
|
|
117
195
|
this.#http.request('GET', `/api/v1/policy-groups/${seg(groupId)}/access`),
|
|
118
196
|
|
|
@@ -129,13 +207,21 @@ export class AdminResource {
|
|
|
129
207
|
* used to drift apart, leaving people with policies but no membership.
|
|
130
208
|
*/
|
|
131
209
|
addMember: (groupId: string, userId: string) =>
|
|
132
|
-
this.#http.request('POST', `/api/v1/policy-groups/${seg(groupId)}/members`, {
|
|
210
|
+
this.#http.request<Membership>('POST', `/api/v1/policy-groups/${seg(groupId)}/members`, {
|
|
133
211
|
body: { userId },
|
|
134
212
|
}),
|
|
135
213
|
|
|
136
|
-
/**
|
|
214
|
+
/**
|
|
215
|
+
* Takes the MEMBERSHIP id, not the user id — a user id answers 404. The
|
|
216
|
+
* id comes from `users.policyGroups`, which returns it as `membershipId`
|
|
217
|
+
* for this purpose.
|
|
218
|
+
*
|
|
219
|
+
* Removing somebody from their last group does NOT remove them from the
|
|
220
|
+
* vault: membership is its own record, so they stay in the directory with
|
|
221
|
+
* no policies — able to be granted access, refused every action.
|
|
222
|
+
*/
|
|
137
223
|
removeMember: (groupId: string, membershipId: string) =>
|
|
138
|
-
this.#http.request(
|
|
224
|
+
this.#http.request<{ deleted: true }>(
|
|
139
225
|
'DELETE',
|
|
140
226
|
`/api/v1/policy-groups/${seg(groupId)}/members/${seg(membershipId)}`,
|
|
141
227
|
),
|
|
@@ -144,27 +230,60 @@ export class AdminResource {
|
|
|
144
230
|
// --- people -------------------------------------------------------------
|
|
145
231
|
|
|
146
232
|
readonly users = {
|
|
147
|
-
|
|
148
|
-
|
|
233
|
+
/**
|
|
234
|
+
* Every group this person is in, each with the `membershipId` that
|
|
235
|
+
* `policyGroups.removeMember` needs. Without `vaultId` it spans ALL
|
|
236
|
+
* vaults, so filter when you are rendering one vault's screen.
|
|
237
|
+
*/
|
|
238
|
+
policyGroups: (userId: string, params: { vaultId?: string | undefined } = {}) =>
|
|
239
|
+
this.#http.request<UserGroupItem[]>('GET', `/api/v1/users/${seg(userId)}/policy-groups`, {
|
|
240
|
+
query: { ...params },
|
|
241
|
+
}),
|
|
149
242
|
|
|
150
|
-
/**
|
|
151
|
-
|
|
152
|
-
|
|
243
|
+
/**
|
|
244
|
+
* The PLATFORM role, not a role within a vault. The two are different:
|
|
245
|
+
* a platform `admin` sees every vault while belonging to none, whereas a
|
|
246
|
+
* vault membership carries its own role.
|
|
247
|
+
*
|
|
248
|
+
* The parameter is narrowed to the two values the spec declares, which is
|
|
249
|
+
* worth the compile error on a privilege path: `string` here let a caller
|
|
250
|
+
* pass anything and find out from a 400 — after sending a role change.
|
|
251
|
+
* The RESPONSE keeps `role: string`, because the spec declares it bare and
|
|
252
|
+
* narrowing an answer we do not control would be a guess.
|
|
253
|
+
*/
|
|
254
|
+
setRole: (userId: string, role: PlatformRole) =>
|
|
255
|
+
this.#http.request<{ id: string; email: string; role: string }>(
|
|
256
|
+
'PATCH',
|
|
257
|
+
`/api/v1/users/${seg(userId)}/role`,
|
|
258
|
+
{ body: { role } },
|
|
259
|
+
),
|
|
153
260
|
}
|
|
154
261
|
|
|
155
262
|
/** Vault-scoped administrative listings and creation. */
|
|
156
263
|
vault(vaultCode: string): {
|
|
157
|
-
invitations: (
|
|
158
|
-
|
|
159
|
-
|
|
264
|
+
invitations: (params?: {
|
|
265
|
+
status?: 'pending' | 'accepted' | 'revoked' | undefined
|
|
266
|
+
}) => Promise<InvitationListItem[]>
|
|
267
|
+
policies: (params?: VaultPoliciesParams) => Promise<VaultPoliciesPage>
|
|
268
|
+
policyGroups: () => Promise<PolicyGroupWithCounts[]>
|
|
160
269
|
createSeat: (input: CreateSeatBody) => Promise<SeatCreated>
|
|
161
270
|
} {
|
|
162
271
|
const base = `/api/v1/vaults/${seg(vaultCode)}`
|
|
163
272
|
return {
|
|
164
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Every invitation of the vault, newest first. The magic-link TOKEN is
|
|
275
|
+
* not in the listing — only `invitations.get` returns it, so that it
|
|
276
|
+
* cannot leak through a screenshot or a log of a list view.
|
|
277
|
+
*/
|
|
278
|
+
invitations: (params = {}) =>
|
|
279
|
+
this.#http.request<InvitationListItem[]>('GET', `${base}/invitations`, {
|
|
280
|
+
query: { ...params },
|
|
281
|
+
}),
|
|
165
282
|
policies: (params = {}) =>
|
|
166
|
-
this.#http.request<VaultPoliciesPage>('GET', `${base}/policies`, { query: params }),
|
|
167
|
-
|
|
283
|
+
this.#http.request<VaultPoliciesPage>('GET', `${base}/policies`, { query: { ...params } }),
|
|
284
|
+
/** Groups with `_count` of their policies and members. No cursor. */
|
|
285
|
+
policyGroups: () =>
|
|
286
|
+
this.#http.request<PolicyGroupWithCounts[]>('GET', `${base}/policy-groups`),
|
|
168
287
|
/**
|
|
169
288
|
* Creates a "seat": an account prepared in advance, before the person's
|
|
170
289
|
* email is known, handed over as a link or a QR code. The link is
|
|
@@ -177,22 +296,44 @@ export class AdminResource {
|
|
|
177
296
|
}
|
|
178
297
|
|
|
179
298
|
readonly invitations = {
|
|
180
|
-
/**
|
|
299
|
+
/**
|
|
300
|
+
* Public: lets an invited person see what they were invited to — the
|
|
301
|
+
* vault and the groups, no token echoed back. The only endpoint here
|
|
302
|
+
* that needs no session, because it is what the /accept page calls.
|
|
303
|
+
*
|
|
304
|
+
* A revoked or already-accepted invitation answers 410, not 404: the
|
|
305
|
+
* difference is worth showing, since "this link was withdrawn" and "this
|
|
306
|
+
* link never existed" lead somewhere different.
|
|
307
|
+
*/
|
|
181
308
|
byToken: (token: string) =>
|
|
182
|
-
this.#http.request(
|
|
309
|
+
this.#http.request<InvitationPublic>(
|
|
310
|
+
'GET',
|
|
311
|
+
`/api/v1/invitations/by-token/${seg(token)}`,
|
|
312
|
+
),
|
|
183
313
|
|
|
314
|
+
/** The one place the magic-link token is returned. */
|
|
184
315
|
get: (invitationId: string) =>
|
|
185
316
|
this.#http.request<InvitationDetail>('GET', `/api/v1/invitations/${seg(invitationId)}`),
|
|
186
317
|
|
|
187
318
|
create: (input: CreateInvitationBody) =>
|
|
188
319
|
this.#http.request<InvitationCreated>('POST', '/api/v1/invitations', { body: input }),
|
|
189
320
|
|
|
321
|
+
/** Answers the invitation itself, now `revoked`. Already revoked → 400. */
|
|
190
322
|
revoke: (invitationId: string) =>
|
|
191
|
-
this.#http.request('POST', `/api/v1/invitations/${seg(invitationId)}/revoke`),
|
|
323
|
+
this.#http.request<Invitation>('POST', `/api/v1/invitations/${seg(invitationId)}/revoke`),
|
|
192
324
|
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Accepts an invitation without the email round-trip, for an account that
|
|
327
|
+
* already exists. For debugging and curl tests: in the real flow this
|
|
328
|
+
* happens inside the sign-up hook.
|
|
329
|
+
*
|
|
330
|
+
* Matches on the EMAIL in the body, not on a token — it finds the pending
|
|
331
|
+
* invitation for that address. No pending invitation → 404; the user
|
|
332
|
+
* already attached to another invitation → 400, so a repeat is refused
|
|
333
|
+
* rather than duplicating memberships.
|
|
334
|
+
*/
|
|
335
|
+
acceptDebug: (body: AcceptDebugBody) =>
|
|
336
|
+
this.#http.request<AcceptResult>('POST', '/api/v1/invitations/accept-debug', { body }),
|
|
196
337
|
}
|
|
197
338
|
|
|
198
339
|
/**
|
|
@@ -204,15 +345,27 @@ export class AdminResource {
|
|
|
204
345
|
* here.
|
|
205
346
|
*/
|
|
206
347
|
visibilityGrants(vaultCode: string): {
|
|
207
|
-
list: (
|
|
348
|
+
list: (params?: {
|
|
349
|
+
subjectUserId?: string | undefined
|
|
350
|
+
subjectGroupId?: string | undefined
|
|
351
|
+
includeRevoked?: boolean | undefined
|
|
352
|
+
}) => Promise<{ items: VisibilityGrant[] }>
|
|
208
353
|
create: (input: CreateVisibilityGrantBody) => Promise<VisibilityGrant>
|
|
209
|
-
revoke: (grantId: string) => Promise<
|
|
354
|
+
revoke: (grantId: string) => Promise<{ revoked: true }>
|
|
210
355
|
} {
|
|
211
356
|
const base = `/api/v1/vaults/${seg(vaultCode)}/visibility-grants`
|
|
212
357
|
return {
|
|
213
|
-
|
|
358
|
+
/**
|
|
359
|
+
* Active grants with the cards of subject and target group. The subject
|
|
360
|
+
* filters answer "what is open to this person or group", which is what
|
|
361
|
+
* their detail screen needs; `includeRevoked` adds the soft-deleted
|
|
362
|
+
* rows, the only way to see what access was withdrawn and when.
|
|
363
|
+
*/
|
|
364
|
+
list: (params = {}) =>
|
|
365
|
+
this.#http.request<{ items: VisibilityGrant[] }>('GET', base, { query: { ...params } }),
|
|
214
366
|
create: (input) => this.#http.request<VisibilityGrant>('POST', base, { body: input }),
|
|
215
|
-
|
|
367
|
+
/** Soft: the row stays as `revoked`. Effective immediately. */
|
|
368
|
+
revoke: (grantId) => this.#http.request<{ revoked: true }>('DELETE', `${base}/${seg(grantId)}`),
|
|
216
369
|
}
|
|
217
370
|
}
|
|
218
371
|
}
|
|
@@ -4,14 +4,30 @@ import { toGated, type Gated } from '../core/gated.js'
|
|
|
4
4
|
import type {
|
|
5
5
|
ApprovalRequestCreated,
|
|
6
6
|
ApprovalRequestDetail,
|
|
7
|
-
CompositeApplied,
|
|
8
7
|
ApprovalRequestsPage,
|
|
8
|
+
CompositeApplied,
|
|
9
9
|
CreateCompositeBody,
|
|
10
|
+
RequestVoteResult,
|
|
10
11
|
VoteBody,
|
|
11
12
|
} from '../generated/types.js'
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Status of an approval REQUEST — and in UPPER CASE.
|
|
16
|
+
*
|
|
17
|
+
* That is the trap this type exists for: a transfer's status is lowercase
|
|
18
|
+
* (`awaiting_approval`, `confirmed`), a request's is not, and the two live
|
|
19
|
+
* side by side on the same screen. `status: 'pending'` used to compile and
|
|
20
|
+
* answer 400.
|
|
21
|
+
*
|
|
22
|
+
* `APPROVED` is about the VOTES, not about the outcome. "Approved but it
|
|
23
|
+
* failed to apply" is still `APPROVED`, and the difference shows up in
|
|
24
|
+
* `applyError` and `resolvedResultId` on the vote's answer — so a listing
|
|
25
|
+
* filtered to `APPROVED` is not a listing of things that happened.
|
|
26
|
+
*/
|
|
27
|
+
export type ApprovalRequestStatus = 'PENDING' | 'APPROVED' | 'REJECTED' | 'CANCELLED'
|
|
28
|
+
|
|
13
29
|
export interface ListApprovalsParams extends PageParams {
|
|
14
|
-
status?:
|
|
30
|
+
status?: ApprovalRequestStatus | undefined
|
|
15
31
|
action?: string | undefined
|
|
16
32
|
/** Requests I STARTED. Not the same as the ones waiting for me. */
|
|
17
33
|
mine?: boolean | undefined
|
|
@@ -52,15 +68,45 @@ export class ApprovalsResource {
|
|
|
52
68
|
return this.#http.request<ApprovalRequestDetail>('GET', `${this.#base}/${seg(requestId)}`)
|
|
53
69
|
}
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Typed from `RequestVoteResult`, which the spec declares as a component but
|
|
73
|
+
* never `$ref`s — the operation inlines its 200 instead. The two were
|
|
74
|
+
* compared key by key and type by type and are the same schema; the only
|
|
75
|
+
* difference is an `additionalProperties: false` that does not reach the
|
|
76
|
+
* TypeScript shape. Worth saying, because a component nothing references
|
|
77
|
+
* usually means the opposite: an orphan left behind, which is what the
|
|
78
|
+
* `Address` schema turned out to be.
|
|
79
|
+
*
|
|
80
|
+
* Read `finalized` with `applyError`: a vote can finalize a request AND
|
|
81
|
+
* fail to apply it, and then the money has not moved.
|
|
82
|
+
*/
|
|
83
|
+
vote(requestId: string, input: VoteBody): Promise<RequestVoteResult> {
|
|
84
|
+
return this.#http.request<RequestVoteResult>(
|
|
85
|
+
'POST',
|
|
86
|
+
`${this.#base}/${seg(requestId)}/approvals`,
|
|
87
|
+
{ body: input },
|
|
88
|
+
)
|
|
57
89
|
}
|
|
58
90
|
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Cancels your own request and releases whatever it reserved.
|
|
93
|
+
*
|
|
94
|
+
* Only while the request is `PENDING`, and only as its initiator or as an
|
|
95
|
+
* admin — the admin case exists so a request whose initiator is gone can
|
|
96
|
+
* still be cleared instead of holding the reserve forever.
|
|
97
|
+
*
|
|
98
|
+
* @param reason IGNORED BY THE SERVER, and no longer sent. The endpoint
|
|
99
|
+
* declares no request body and the handler never reads one, so the reason
|
|
100
|
+
* reached nothing: not the cancellation event, not the audit trail. It
|
|
101
|
+
* stays in the signature only so that existing callers keep compiling —
|
|
102
|
+
* drop it from your call, and record the reason wherever you need it to
|
|
103
|
+
* actually survive.
|
|
104
|
+
*/
|
|
105
|
+
cancel(requestId: string, reason?: string): Promise<{ status: 'CANCELLED' }> {
|
|
106
|
+
return this.#http.request<{ status: 'CANCELLED' }>(
|
|
107
|
+
'POST',
|
|
108
|
+
`${this.#base}/${seg(requestId)}/cancel`,
|
|
109
|
+
)
|
|
64
110
|
}
|
|
65
111
|
|
|
66
112
|
/**
|