@cef-ai/vault-sdk 3.3.0 → 4.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/dist/client.d.ts +26 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +40 -3
- package/dist/client.js.map +1 -1
- package/dist/core/canonical.d.ts +17 -1
- package/dist/core/canonical.d.ts.map +1 -1
- package/dist/core/canonical.js +26 -1
- package/dist/core/canonical.js.map +1 -1
- package/dist/core/endpoints.d.ts +5 -4
- package/dist/core/endpoints.d.ts.map +1 -1
- package/dist/core/endpoints.js +13 -4
- package/dist/core/endpoints.js.map +1 -1
- package/dist/core/grant-doc.d.ts +477 -0
- package/dist/core/grant-doc.d.ts.map +1 -0
- package/dist/core/grant-doc.js +768 -0
- package/dist/core/grant-doc.js.map +1 -0
- package/dist/core/types.d.ts +181 -49
- package/dist/core/types.d.ts.map +1 -1
- package/dist/fluent/vault.d.ts +6 -0
- package/dist/fluent/vault.d.ts.map +1 -1
- package/dist/fluent/vault.js +7 -0
- package/dist/fluent/vault.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/memberships.d.ts +360 -0
- package/dist/internal/memberships.d.ts.map +1 -0
- package/dist/internal/memberships.js +403 -0
- package/dist/internal/memberships.js.map +1 -0
- package/dist/internal/vaults.d.ts +22 -0
- package/dist/internal/vaults.d.ts.map +1 -1
- package/dist/internal/vaults.js +11 -0
- package/dist/internal/vaults.js.map +1 -1
- package/dist/internal-exports.d.ts +2 -1
- package/dist/internal-exports.d.ts.map +1 -1
- package/dist/internal-exports.js +1 -1
- package/dist/internal-exports.js.map +1 -1
- package/package.json +2 -2
- package/dist/internal/orgs.d.ts +0 -59
- package/dist/internal/orgs.d.ts.map +0 -1
- package/dist/internal/orgs.js +0 -80
- package/dist/internal/orgs.js.map +0 -1
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { endpoints } from "../core/endpoints.js";
|
|
2
|
+
import { bytesToHex } from "../core/canonical.js";
|
|
3
|
+
import { GRANT_SIGNATURE_HEADER, GRANT_ISSUED_AT_HEADER, NO_GRANT_EXPIRY, canonicalGrantBytes, canonicalPubkeyHex, grantExpiry, } from "../core/grant-doc.js";
|
|
4
|
+
import { VaultRequestError, VaultSignerRequiredError } from "../core/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Who belongs to a vault, in what role, holding which scope grants — and,
|
|
7
|
+
* from the other direction, which vaults the caller belongs to.
|
|
8
|
+
*
|
|
9
|
+
* ## THERE IS NO ORG ENTITY (D1)
|
|
10
|
+
*
|
|
11
|
+
* This class replaces `sdk.orgs`, which addressed an `orgId`. The `orgs`
|
|
12
|
+
* table and every `/api/v1/orgs…` route were removed, not aliased: a vault
|
|
13
|
+
* IS the organization, and **a vault BECOMES one by acquiring a second
|
|
14
|
+
* member**, which is `put()` below. There is deliberately no `create` — the
|
|
15
|
+
* removed `POST /api/v1/orgs` needed only half a replacement, the naming
|
|
16
|
+
* half, and that is `sdk.vault.rename()` (`PATCH /api/v1/vaults/:vaultId`),
|
|
17
|
+
* because a name is a property of the vault and a single-member vault must
|
|
18
|
+
* be nameable too.
|
|
19
|
+
*
|
|
20
|
+
* ## The one thing a consumer porting from `sdk.orgs` gets wrong
|
|
21
|
+
*
|
|
22
|
+
* `mine()` does NOT include the caller's own vault. `sdk.orgs.list()` folded
|
|
23
|
+
* the two together by synthesising an owner entry; the owner is never a
|
|
24
|
+
* membership row under D1, and `sdk.vault.current()` already answers "my own
|
|
25
|
+
* vault" keyed by wallet. **A switcher shows both by calling both** — and
|
|
26
|
+
* folding them here would double-count for anyone who did:
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* const [own, joined] = await Promise.all([
|
|
30
|
+
* sdk.vault.current(), // the vault this wallet owns
|
|
31
|
+
* sdk.memberships.mine(), // the vaults this wallet was invited into
|
|
32
|
+
* ]);
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* ## THE TWO WRITES CARRY A SECOND SIGNATURE, AND IT IS THE OWNER'S
|
|
36
|
+
*
|
|
37
|
+
* `put()` and `putScopes()` send `X-Grant-Signature`: the VAULT OWNER's
|
|
38
|
+
* ed25519 signature over the grant's canonical document
|
|
39
|
+
* (`canonicalGrantBytes`). ddc-node #1136 made it mandatory on both, so
|
|
40
|
+
* without it neither method can succeed at all — a 400 `grant sig: missing
|
|
41
|
+
* X-Grant-Signature`. They send `X-Grant-Issued-At` alongside it, carrying the
|
|
42
|
+
* moment the document was minted: it is inside the signed bytes, and the
|
|
43
|
+
* server rebuilds those bytes rather than receiving them, so it has no way to
|
|
44
|
+
* supply that field itself. It is a header of its own rather than the wallet auth's
|
|
45
|
+
* `X-Signature` because the two cover different bytes: `X-Signature` covers
|
|
46
|
+
* the request BODY and authenticates the caller, while this covers a document
|
|
47
|
+
* that names the vault, the member, the role and the scopes, so one signature
|
|
48
|
+
* cannot be replayed onto another member or another vault.
|
|
49
|
+
*
|
|
50
|
+
* `remove()` sends NO grant signature, and that is not an omission —
|
|
51
|
+
* `DeleteMember` has no such check. Read the handler before assuming
|
|
52
|
+
* symmetry: revocation deletes the row (and, by FK, its grants), so there is
|
|
53
|
+
* no post-write standing left for a document to describe.
|
|
54
|
+
*
|
|
55
|
+
* ### The document describes the membership AFTER the write, and each route
|
|
56
|
+
* ### knows only half of it
|
|
57
|
+
*
|
|
58
|
+
* `PutMember` builds its document from the role in the body and the scopes
|
|
59
|
+
* ALREADY IN THE STORE; `PutScopes` builds its own from the scopes in the
|
|
60
|
+
* body and the role already in the store. So each method reads the other half
|
|
61
|
+
* back before signing — one extra GET — unless the caller supplies it
|
|
62
|
+
* (`PutMemberOptions.scopes` / `PutScopesOptions.role`). Signing the same
|
|
63
|
+
* bytes for both calls is refused by the second.
|
|
64
|
+
*
|
|
65
|
+
* ### AN ADMIN WHO IS NOT THE OWNER CANNOT SIGN
|
|
66
|
+
*
|
|
67
|
+
* The route's gate admits the vault owner OR a live `role: "admin"` member,
|
|
68
|
+
* but `verifyGrantDocument` checks the signature against the VAULT's wallet
|
|
69
|
+
* key and nothing else. So an admin can be authorised to make this request
|
|
70
|
+
* and unable to produce the document it must carry. The SDK signs with the
|
|
71
|
+
* configured `signer`, which is the owner in the ordinary case of an owner
|
|
72
|
+
* administering their own vault; a non-owner admin gets a 400 naming the
|
|
73
|
+
* document, and needs one their owner signed out of band — pass it by calling
|
|
74
|
+
* the route through `VaultHttpClient` directly with the header set. There is
|
|
75
|
+
* no in-band way to obtain it today.
|
|
76
|
+
*
|
|
77
|
+
* ## Every mutation body carries a `timestamp`
|
|
78
|
+
*
|
|
79
|
+
* The wallet-signature middleware (`pkg/shared/auth/signature.go`) rejects
|
|
80
|
+
* ANY mutation body with no top-level RFC3339 `timestamp` as 401
|
|
81
|
+
* `INVALID_SIGNATURE "body missing timestamp"`, before the request reaches
|
|
82
|
+
* a handler. `WalletAuthProvider` supplies one during canonicalisation;
|
|
83
|
+
* `DelegationAuthProvider` (which never passes through that middleware)
|
|
84
|
+
* supplies nothing — so each method below sends its own, keeping the body
|
|
85
|
+
* correct on both paths. It is NOT a replay guard: ddc-node parses the field
|
|
86
|
+
* and no membership handler reads it.
|
|
87
|
+
*/
|
|
88
|
+
export class Memberships {
|
|
89
|
+
http;
|
|
90
|
+
signer;
|
|
91
|
+
/**
|
|
92
|
+
* `signer` is the VAULT OWNER's key, and it is required by `put` and
|
|
93
|
+
* `putScopes` only — every read here, and `remove`, work without one.
|
|
94
|
+
* Optional so that constructing this class from
|
|
95
|
+
* `@cef-ai/vault-sdk/internal` for reads alone keeps working unchanged;
|
|
96
|
+
* a write without it throws `VaultSignerRequiredError` rather than
|
|
97
|
+
* sending a request the server will refuse.
|
|
98
|
+
*/
|
|
99
|
+
constructor(http, signer) {
|
|
100
|
+
this.http = http;
|
|
101
|
+
this.signer = signer;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The vaults the caller is a MEMBER of, with their own grants on each —
|
|
105
|
+
* the employee's vault switcher. `GET /api/v1/memberships`.
|
|
106
|
+
*
|
|
107
|
+
* Excludes the caller's own vault; see this class's doc comment, which is
|
|
108
|
+
* the single most likely thing to get wrong when porting from
|
|
109
|
+
* `sdk.orgs.list()`.
|
|
110
|
+
*
|
|
111
|
+
* LIVE memberships only: a membership that is suspended or past its
|
|
112
|
+
* `expiresAt` is absent, not present-with-a-state. `scopes` is always
|
|
113
|
+
* present on every entry (these are the caller's OWN grants, so there is
|
|
114
|
+
* no disclosure question) and is `{}` — never `null` — when they hold
|
|
115
|
+
* none.
|
|
116
|
+
*/
|
|
117
|
+
mine() {
|
|
118
|
+
return this.http.send("GET", endpoints.memberships());
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The vault's roster. `GET /api/v1/vaults/:vaultId/members`.
|
|
122
|
+
*
|
|
123
|
+
* Readable by the vault owner or any of its own LIVE members, whatever
|
|
124
|
+
* their role; 403 (uniformly, so an outsider cannot enumerate) otherwise,
|
|
125
|
+
* and 404 if the vault was never claimed.
|
|
126
|
+
*
|
|
127
|
+
* THE OWNER ROW IS FIRST, is synthesised (`isOwner: true`, `role:
|
|
128
|
+
* "admin"`, `state: "active"`), and carries NO `scopes` — see `Member`.
|
|
129
|
+
* Every other row's `scopes` is present only when disclosed to the caller.
|
|
130
|
+
* `Member.scopes` being absent is NOT the same as `{}`; do not default it.
|
|
131
|
+
*/
|
|
132
|
+
list(vaultId) {
|
|
133
|
+
return this.http.send("GET", endpoints.vaultMembers(vaultId));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The same roster as SIGNED EVIDENCE.
|
|
137
|
+
* `GET /api/v1/vaults/:vaultId/roster/signed`.
|
|
138
|
+
*
|
|
139
|
+
* Each entry carries the canonical grant document the vault owner signed
|
|
140
|
+
* and that signature, so a party that does NOT trust this vault-api can
|
|
141
|
+
* decide what a member may do. That is the entire point of the route, and
|
|
142
|
+
* it only holds if the consumer checks the documents AGAINST SOMETHING
|
|
143
|
+
* THIS RESPONSE DID NOT SUPPLY:
|
|
144
|
+
*
|
|
145
|
+
* ```ts
|
|
146
|
+
* import { verifySignedRoster } from "@cef-ai/vault-sdk";
|
|
147
|
+
*
|
|
148
|
+
* const roster = await sdk.memberships.signedRoster(vaultId);
|
|
149
|
+
* const grants = await verifySignedRoster(roster, vaultId); // throws on any entry
|
|
150
|
+
* // act on `grants` — never on roster.grants[i].role / .scopes
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* **Pass the SAME `vaultId` you asked for.** `verifySignedRoster` requires
|
|
154
|
+
* it and will not verify without it, because the alternative is not a
|
|
155
|
+
* weaker check but a meaningless one: `orgWalletPubkey` arrives inside the
|
|
156
|
+
* response, so a roster checked only against itself proves that whoever
|
|
157
|
+
* answered can sign — never that they are the vault's owner. The id is the
|
|
158
|
+
* one value the responder does not get to choose; `vaultIdFor` makes the
|
|
159
|
+
* owner key answer to it. A caller holding the owner key instead of the id
|
|
160
|
+
* gets the id from `vaultIdFor(ownerKey)`.
|
|
161
|
+
*
|
|
162
|
+
* What this does NOT establish: that the vault id is the one you meant. It
|
|
163
|
+
* anchors the roster to a vault, so anchor the vault to something you knew
|
|
164
|
+
* beforehand rather than to a value the same untrusted party handed you.
|
|
165
|
+
*
|
|
166
|
+
* The raw shape is returned rather than the verified one so evidence can be
|
|
167
|
+
* forwarded to a third party intact; `verifySignedRoster` is the step that
|
|
168
|
+
* turns it into values worth acting on. `SignedGrant.role` and
|
|
169
|
+
* `.scopes` are vault-api's own decoding of `doc`, provided for display —
|
|
170
|
+
* enforcing on them verifies one thing and enforces another.
|
|
171
|
+
*
|
|
172
|
+
* Same gate and same disclosure rule as `list()`: readable by the owner or
|
|
173
|
+
* any LIVE member (404 for an unclaimed vault, a uniform 403 otherwise),
|
|
174
|
+
* owner and live admin see every grant, a plain member only their own. Two
|
|
175
|
+
* differences from `list()`, both deliberate: the owner is NOT an entry
|
|
176
|
+
* here (they hold no signed document — `orgWalletPubkey` is where they
|
|
177
|
+
* appear), and only LIVE memberships are served, so there is no `state`
|
|
178
|
+
* field to check.
|
|
179
|
+
*/
|
|
180
|
+
signedRoster(vaultId) {
|
|
181
|
+
return this.http.send("GET", endpoints.vaultSignedRoster(vaultId));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Adds or updates a member. `PUT /api/v1/vaults/:vaultId/members/:memberPubkey`.
|
|
185
|
+
*
|
|
186
|
+
* **This is how a vault becomes an organization** — there is no
|
|
187
|
+
* registration step; the first successful call is the whole ceremony.
|
|
188
|
+
*
|
|
189
|
+
* Requires the vault owner or a live `role: "admin"` member. 400 if
|
|
190
|
+
* `memberPubkey` is the vault's own owner — the owner is never a
|
|
191
|
+
* membership row (D1) — and 404 if the vault is unclaimed.
|
|
192
|
+
*
|
|
193
|
+
* `memberPubkey` should already be in the server's canonical
|
|
194
|
+
* 0x-lowercase-hex spelling (`auth.CanonicalPubKeyHex`), which is the one
|
|
195
|
+
* spelling every authorization read looks members up by.
|
|
196
|
+
*
|
|
197
|
+
* `expiresAt` MUST BE RFC 3339 — vault-api parses it for the timestamptz
|
|
198
|
+
* column and 400s anything else, naming the field. It is also INSIDE THE
|
|
199
|
+
* SIGNED DOCUMENT now, and the server rebuilds the document from the string
|
|
200
|
+
* this method sends: the exact spelling passed here is what is signed and
|
|
201
|
+
* what is sent, never re-derived from a `Date` on either side. Formatting it
|
|
202
|
+
* twice is how the two copies drift by a trimmed fractional zero and the
|
|
203
|
+
* signature fails as though the key were wrong.
|
|
204
|
+
*
|
|
205
|
+
* The returned `Member` carries neither `scopes` nor `isOwner`: it is the
|
|
206
|
+
* row just written, and grants are a separate call (`putScopes`).
|
|
207
|
+
*
|
|
208
|
+
* CARRIES THE OWNER'S `X-Grant-Signature` over
|
|
209
|
+
* `{vaultId, memberPubkey, role, scopes, issuedAt, expiresAt}` — see the
|
|
210
|
+
* class doc comment. The scopes in that document are the ones the member
|
|
211
|
+
* ALREADY HOLDS, because this route sets the role only, so re-roling a
|
|
212
|
+
* member with grants signs those grants too. They are read back with `scopes()` (a 404 — the new
|
|
213
|
+
* member case — is `{}`); pass `{ scopes }` to skip that GET when they are
|
|
214
|
+
* already in hand.
|
|
215
|
+
*/
|
|
216
|
+
async put(vaultId, memberPubkey, role, expiresAt, opts = {}) {
|
|
217
|
+
const scopes = opts.scopes ?? (await this.heldScopes(vaultId, memberPubkey));
|
|
218
|
+
// ONE STRING, SENT AND SIGNED. `expiresAt` goes into the body and into the
|
|
219
|
+
// signed bytes unchanged; absent is NO_GRANT_EXPIRY, which is the empty
|
|
220
|
+
// string and NOT an omitted field — see `NO_GRANT_EXPIRY` for why "no
|
|
221
|
+
// expiry" has a spelling of its own rather than being a missing key.
|
|
222
|
+
const expiry = expiresAt === undefined ? NO_GRANT_EXPIRY : grantExpiry(expiresAt);
|
|
223
|
+
return this.http.send("PUT", endpoints.vaultMember(vaultId, memberPubkey), {
|
|
224
|
+
body: { role, expiresAt, timestamp: new Date().toISOString() },
|
|
225
|
+
headers: await this.grantHeader(vaultId, memberPubkey, role, scopes, expiry),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Removes a member row. `DELETE /api/v1/vaults/:vaultId/members/:memberPubkey`.
|
|
230
|
+
*
|
|
231
|
+
* 409 — not 404 — for the vault's own owner: they cannot be removed at
|
|
232
|
+
* all, and 404 would read as "already gone, nothing left to do" to an
|
|
233
|
+
* admin who believed they had locked the founder out.
|
|
234
|
+
*
|
|
235
|
+
* ddc-node's handler never reads the body, but the wallet-signature
|
|
236
|
+
* middleware still requires a top-level `timestamp` on every mutation
|
|
237
|
+
* regardless of what the handler does with it — so this body is
|
|
238
|
+
* `{timestamp}` and nothing else.
|
|
239
|
+
*
|
|
240
|
+
* NO `X-Grant-Signature`, deliberately and after reading `DeleteMember`:
|
|
241
|
+
* the grant check lives in `verifyGrantDocument`, which only `PutMember`
|
|
242
|
+
* and `PutScopes` call. Adding one here on the assumption that the three
|
|
243
|
+
* writes are symmetrical would send a header the server ignores and would
|
|
244
|
+
* make this method need a signer it has no use for.
|
|
245
|
+
*/
|
|
246
|
+
remove(vaultId, memberPubkey) {
|
|
247
|
+
return this.http.send("DELETE", endpoints.vaultMember(vaultId, memberPubkey), {
|
|
248
|
+
body: { timestamp: new Date().toISOString() },
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* A member's scope grants.
|
|
253
|
+
* `GET /api/v1/vaults/:vaultId/members/:memberPubkey/scopes`.
|
|
254
|
+
*
|
|
255
|
+
* Readable by the vault owner, a live admin, or the member themselves.
|
|
256
|
+
* 404 when the membership does not exist — INCLUDING when the vault OWNER
|
|
257
|
+
* asks for their own grants, which is the read-side face of "the owner is
|
|
258
|
+
* never a row": their authority is key math and there is no grant row.
|
|
259
|
+
*
|
|
260
|
+
* `list()` already carries `scopes` inline on every disclosed row, so a
|
|
261
|
+
* console rendering a roster should NOT call this per member — that is an
|
|
262
|
+
* N+1. This is for reading one membership's grants directly.
|
|
263
|
+
*/
|
|
264
|
+
scopes(vaultId, memberPubkey) {
|
|
265
|
+
return this.http.send("GET", endpoints.vaultMemberScopes(vaultId, memberPubkey));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Replaces a member's FULL scope-grant set.
|
|
269
|
+
* `PUT /api/v1/vaults/:vaultId/members/:memberPubkey/scopes`.
|
|
270
|
+
*
|
|
271
|
+
* The server deletes then reinserts, so this is never a merge or a diff
|
|
272
|
+
* against the existing grants — send the complete intended set. 404 if the
|
|
273
|
+
* membership row does not exist, INCLUDING for an empty `scopes` map: the
|
|
274
|
+
* check is EXISTENCE, not liveness, so an admin may prepare the grants of
|
|
275
|
+
* a currently-suspended membership.
|
|
276
|
+
*
|
|
277
|
+
* CARRIES THE OWNER'S `X-Grant-Signature` over
|
|
278
|
+
* `{vaultId, memberPubkey, role, scopes, issuedAt, expiresAt}` — see the
|
|
279
|
+
* class doc comment. The role AND the expiry in that document are the ones
|
|
280
|
+
* the member ALREADY HOLDS, because this route sets the scopes only; both
|
|
281
|
+
* are read off the roster (`list()`) in one GET, which is why a
|
|
282
|
+
* `memberPubkey` with no row fails here rather than as the server's 404.
|
|
283
|
+
* Pass `{ standing: { role, expiresAt } }` to skip it.
|
|
284
|
+
*
|
|
285
|
+
* THE EXPIRY IS ALSO SENT IN THE BODY, and that is the one place this route
|
|
286
|
+
* differs from `put`. vault-api holds the expiry as a timestamp and the
|
|
287
|
+
* document carries the signer's STRING, which a timestamp cannot be
|
|
288
|
+
* rendered back into — so the server cannot supply this field the way it
|
|
289
|
+
* supplies the role. It checks what is sent against the stored instant, so
|
|
290
|
+
* stating it cannot widen the membership: a different moment is a 400.
|
|
291
|
+
*/
|
|
292
|
+
async putScopes(vaultId, memberPubkey, scopes, opts = {}) {
|
|
293
|
+
const standing = opts.standing ?? (await this.heldStanding(vaultId, memberPubkey));
|
|
294
|
+
const expiry = standing.expiresAt === undefined ? NO_GRANT_EXPIRY : grantExpiry(standing.expiresAt);
|
|
295
|
+
return this.http.send("PUT", endpoints.vaultMemberScopes(vaultId, memberPubkey), {
|
|
296
|
+
body: { scopes, expiresAt: standing.expiresAt, timestamp: new Date().toISOString() },
|
|
297
|
+
headers: await this.grantHeader(vaultId, memberPubkey, standing.role, scopes, expiry),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The vault owner's signature over this grant's canonical document, as the
|
|
302
|
+
* `X-Grant-Signature` header — see the class doc comment for why a write
|
|
303
|
+
* cannot land without it.
|
|
304
|
+
*
|
|
305
|
+
* `memberPubkey` is canonicalised FIRST. The server canonicalises the URL
|
|
306
|
+
* parameter before it derives the bytes (`memberPubkeyParam`), so signing
|
|
307
|
+
* the caller's own spelling of a bare or upper-case key produces a valid
|
|
308
|
+
* signature over a document the server never builds — a 400 that reads as
|
|
309
|
+
* a key problem. `vaultId` is NOT canonicalised, because the server does
|
|
310
|
+
* not touch it either.
|
|
311
|
+
*
|
|
312
|
+
* ED25519 ONLY, and checked here. `authz.VerifyGrantSig` hard-codes
|
|
313
|
+
* `SchemeEd25519` (unlike the request-auth middleware, which also takes
|
|
314
|
+
* sr25519), so an sr25519 owner can authenticate the request and still
|
|
315
|
+
* never produce a document the server will accept. Named up front rather
|
|
316
|
+
* than left to surface as an opaque signature refusal.
|
|
317
|
+
*/
|
|
318
|
+
async grantHeader(vaultId, memberPubkey, role, scopes, expiresAt) {
|
|
319
|
+
const signer = this.signer;
|
|
320
|
+
if (signer === undefined || typeof signer.sign !== "function") {
|
|
321
|
+
throw new VaultSignerRequiredError(`A membership write must carry the VAULT OWNER's signature over the grant's ` +
|
|
322
|
+
`canonical document, in the ${GRANT_SIGNATURE_HEADER} header. Construct the ` +
|
|
323
|
+
`SDK with \`signer\` set to the vault owner's key (\`new VaultSDK({ endpoint, ` +
|
|
324
|
+
`signer })\`); a custom \`auth\` provider authenticates the request but cannot ` +
|
|
325
|
+
`sign the grant, because the two cover different bytes.`);
|
|
326
|
+
}
|
|
327
|
+
if (signer.type !== "ed25519") {
|
|
328
|
+
throw new VaultSignerRequiredError(`A grant signature must be ed25519 — vault-api verifies it with SchemeEd25519 ` +
|
|
329
|
+
`and nothing else — but this signer is "${signer.type}". An sr25519 key can ` +
|
|
330
|
+
`authenticate the request and still never authorise the grant.`);
|
|
331
|
+
}
|
|
332
|
+
// The mint time is chosen HERE, by the signer, and sent beside the
|
|
333
|
+
// signature — vault-api rebuilds the document rather than receiving it,
|
|
334
|
+
// so it cannot supply a mint time of its own without guaranteeing the
|
|
335
|
+
// signature never verifies. `toISOString()` is RFC3339 UTC, the spelling
|
|
336
|
+
// the rest of this API's signed bytes already use.
|
|
337
|
+
//
|
|
338
|
+
// The exact STRING is what gets signed and what gets sent; it is never
|
|
339
|
+
// re-derived from a Date on either side. Formatting it twice is how the
|
|
340
|
+
// two copies drift by a trimmed fractional zero and the signature fails
|
|
341
|
+
// as though the key were wrong.
|
|
342
|
+
const issuedAt = new Date().toISOString();
|
|
343
|
+
const doc = canonicalGrantBytes(vaultId, canonicalPubkeyHex(memberPubkey), role, scopes, issuedAt, expiresAt);
|
|
344
|
+
return {
|
|
345
|
+
[GRANT_SIGNATURE_HEADER]: bytesToHex(await signer.sign(doc, "data")),
|
|
346
|
+
[GRANT_ISSUED_AT_HEADER]: issuedAt,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* The scope grants this member holds RIGHT NOW — the half of `put`'s
|
|
351
|
+
* document that route reads from the store rather than from its body.
|
|
352
|
+
*
|
|
353
|
+
* A 404 is `{}`, not a failure: it is what `GET .../scopes` answers for a
|
|
354
|
+
* membership row that does not exist yet, which is the ordinary case of
|
|
355
|
+
* adding a NEW member, and it is exactly what the server's own
|
|
356
|
+
* `ListScopeGrantsForMember` yields there (it tolerates `ErrNotFound`).
|
|
357
|
+
* Every other error propagates — a 403 means this caller may not administer
|
|
358
|
+
* the vault at all, and guessing `{}` would turn it into a puzzling 400
|
|
359
|
+
* from the write instead.
|
|
360
|
+
*/
|
|
361
|
+
async heldScopes(vaultId, memberPubkey) {
|
|
362
|
+
try {
|
|
363
|
+
return (await this.scopes(vaultId, memberPubkey)).scopes;
|
|
364
|
+
}
|
|
365
|
+
catch (err) {
|
|
366
|
+
if (err instanceof VaultRequestError && err.status === 404)
|
|
367
|
+
return {};
|
|
368
|
+
throw err;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* The role AND expiry this member holds RIGHT NOW — the two halves of
|
|
373
|
+
* `putScopes`'s document that route reads from the store rather than from
|
|
374
|
+
* its body.
|
|
375
|
+
*
|
|
376
|
+
* BOTH OUT OF ONE ROW, deliberately. They used to be one value read here
|
|
377
|
+
* and one value the document did not carry at all; now that the expiry is
|
|
378
|
+
* signed, fetching them separately would be two chances for them to
|
|
379
|
+
* describe different moments of the same membership.
|
|
380
|
+
*
|
|
381
|
+
* From the roster rather than from a route of its own, because there is no
|
|
382
|
+
* single-membership read that carries a role: `GET .../scopes` returns only
|
|
383
|
+
* grants. The synthesised OWNER row is skipped explicitly — the owner is
|
|
384
|
+
* never a membership row (D1), so a `memberPubkey` matching it is the
|
|
385
|
+
* server's 400, not a standing to sign.
|
|
386
|
+
*
|
|
387
|
+
* `expiresAt` absent on the row means the membership does not expire; the
|
|
388
|
+
* roster omits the key rather than sending null (Go `omitempty`), which is
|
|
389
|
+
* the same three-state distinction `Member.scopes` documents.
|
|
390
|
+
*/
|
|
391
|
+
async heldStanding(vaultId, memberPubkey) {
|
|
392
|
+
const canonical = canonicalPubkeyHex(memberPubkey);
|
|
393
|
+
const row = (await this.list(vaultId)).find((r) => r.isOwner !== true && canonicalPubkeyHex(r.memberPubkey) === canonical);
|
|
394
|
+
if (row === undefined) {
|
|
395
|
+
throw new Error(`putScopes: ${canonical} has no membership row on ${vaultId}, so there is no role ` +
|
|
396
|
+
`or expiry to put in the grant document. Add the member first ` +
|
|
397
|
+
`(\`memberships.put\`), or pass \`{ standing: { role, expiresAt } }\` if you ` +
|
|
398
|
+
`already know them.`);
|
|
399
|
+
}
|
|
400
|
+
return { role: row.role, expiresAt: row.expiresAt };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
//# sourceMappingURL=memberships.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memberships.js","sourceRoot":"","sources":["../../src/internal/memberships.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,21 @@ export interface ClaimVaultRequest {
|
|
|
15
15
|
export interface RotateCredentialRequest {
|
|
16
16
|
delegation_token: string;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Body of `PATCH /api/v1/vaults/:vaultId` — the user-editable vault fields.
|
|
20
|
+
*
|
|
21
|
+
* `displayName` is OPTIONAL as a pointer is on the server: absent means
|
|
22
|
+
* "leave as is", and `""` CLEARS the name (a real request — "this vault
|
|
23
|
+
* should go back to being unnamed"). The two are only distinguishable
|
|
24
|
+
* because the field can be absent, so do not normalise `undefined` to `""`.
|
|
25
|
+
*
|
|
26
|
+
* `timestamp` is required by the wallet-signature middleware on every
|
|
27
|
+
* mutation body, as everywhere else on this API.
|
|
28
|
+
*/
|
|
29
|
+
export interface PatchVaultRequest {
|
|
30
|
+
displayName?: string;
|
|
31
|
+
timestamp: string;
|
|
32
|
+
}
|
|
18
33
|
export declare class Vaults {
|
|
19
34
|
private readonly http;
|
|
20
35
|
constructor(http: VaultHttpClient);
|
|
@@ -22,6 +37,13 @@ export declare class Vaults {
|
|
|
22
37
|
current(): Promise<VaultRecord>;
|
|
23
38
|
/** A vault by explicit id. `current()` stays the caller's own vault. */
|
|
24
39
|
byId(vaultId: string): Promise<VaultRecord>;
|
|
40
|
+
/**
|
|
41
|
+
* Patches the vault's editable fields — today `displayName` and nothing
|
|
42
|
+
* else. OWNER-ONLY: the credential, bucket and status columns each have
|
|
43
|
+
* their own path because each carries a lifecycle rule a generic field
|
|
44
|
+
* patch would skip.
|
|
45
|
+
*/
|
|
46
|
+
patch(vaultId: string, req: PatchVaultRequest): Promise<VaultRecord>;
|
|
25
47
|
rotateCredentials(vaultId: string, req: RotateCredentialRequest): Promise<VaultRecord>;
|
|
26
48
|
}
|
|
27
49
|
//# sourceMappingURL=vaults.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vaults.d.ts","sourceRoot":"","sources":["../../src/internal/vaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAAG,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAC9F,MAAM,WAAW,uBAAuB;IAAG,gBAAgB,EAAE,MAAM,CAAA;CAAE;AAErE,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,eAAe;IAElD,KAAK,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAGnD,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;IAG/B,wEAAwE;IACxE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"vaults.d.ts","sourceRoot":"","sources":["../../src/internal/vaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAAG,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;AAC9F,MAAM,WAAW,uBAAuB;IAAG,gBAAgB,EAAE,MAAM,CAAA;CAAE;AAErE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAAG,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAE9E,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,eAAe;IAElD,KAAK,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAGnD,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;IAG/B,wEAAwE;IACxE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAG3C;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAUpE,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC;CAKvF"}
|
package/dist/internal/vaults.js
CHANGED
|
@@ -14,6 +14,17 @@ export class Vaults {
|
|
|
14
14
|
byId(vaultId) {
|
|
15
15
|
return this.http.send("GET", endpoints.vault(vaultId));
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Patches the vault's editable fields — today `displayName` and nothing
|
|
19
|
+
* else. OWNER-ONLY: the credential, bucket and status columns each have
|
|
20
|
+
* their own path because each carries a lifecycle rule a generic field
|
|
21
|
+
* patch would skip.
|
|
22
|
+
*/
|
|
23
|
+
patch(vaultId, req) {
|
|
24
|
+
return this.http.send("PATCH", endpoints.vault(vaultId), {
|
|
25
|
+
body: req,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
17
28
|
// NOTE (multi-credential gateway): the gateway's PUT /auth/credentials
|
|
18
29
|
// never returns a secret, so this rotation path cannot hand back fresh S3
|
|
19
30
|
// credentials against the real gateway. vault-api is being reworked to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vaults.js","sourceRoot":"","sources":["../../src/internal/vaults.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"vaults.js","sourceRoot":"","sources":["../../src/internal/vaults.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AA0BjD,MAAM,OAAO,MAAM;IACY;IAA7B,YAA6B,IAAqB;QAArB,SAAI,GAAJ,IAAI,CAAiB;IAAG,CAAC;IAEtD,KAAK,CAAC,GAAsB;QAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAyC,EAAE,CAAC,CAAC;IACzG,CAAC;IACD,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,wEAAwE;IACxE,IAAI,CAAC,OAAe;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,CAAC;IACD;;;;;OAKG;IACH,KAAK,CAAC,OAAe,EAAE,GAAsB;QAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;YACvD,IAAI,EAAE,GAAyC;SAChD,CAAC,CAAC;IACL,CAAC;IACD,uEAAuE;IACvE,0EAA0E;IAC1E,uEAAuE;IACvE,sEAAsE;IACtE,wEAAwE;IACxE,iBAAiB,CAAC,OAAe,EAAE,GAA4B;QAC7D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE;YAChE,IAAI,EAAE,GAAyC;SAChD,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -6,7 +6,8 @@ export { Browse } from "./internal/browse.js";
|
|
|
6
6
|
export { Cubbies } from "./internal/cubbies.js";
|
|
7
7
|
export { Health } from "./internal/health.js";
|
|
8
8
|
export { Marketplace } from "./internal/marketplace.js";
|
|
9
|
-
export {
|
|
9
|
+
export { Memberships } from "./internal/memberships.js";
|
|
10
|
+
export type { PutMemberOptions, PutScopesOptions } from "./internal/memberships.js";
|
|
10
11
|
export { VaultHttpClient } from "./core/http.js";
|
|
11
12
|
export { endpoints } from "./core/endpoints.js";
|
|
12
13
|
//# sourceMappingURL=internal-exports.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-exports.d.ts","sourceRoot":"","sources":["../src/internal-exports.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"internal-exports.d.ts","sourceRoot":"","sources":["../src/internal-exports.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/internal-exports.js
CHANGED
|
@@ -8,7 +8,7 @@ export { Browse } from "./internal/browse.js";
|
|
|
8
8
|
export { Cubbies } from "./internal/cubbies.js";
|
|
9
9
|
export { Health } from "./internal/health.js";
|
|
10
10
|
export { Marketplace } from "./internal/marketplace.js";
|
|
11
|
-
export {
|
|
11
|
+
export { Memberships } from "./internal/memberships.js";
|
|
12
12
|
export { VaultHttpClient } from "./core/http.js";
|
|
13
13
|
export { endpoints } from "./core/endpoints.js";
|
|
14
14
|
//# sourceMappingURL=internal-exports.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-exports.js","sourceRoot":"","sources":["../src/internal-exports.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,yEAAyE;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"internal-exports.js","sourceRoot":"","sources":["../src/internal-exports.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,yEAAyE;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cef-ai/vault-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"@polkadot/keyring": "^14.0.3",
|
|
26
26
|
"@polkadot/util": "^14.0.3",
|
|
27
27
|
"@polkadot/util-crypto": "^14.0.3",
|
|
28
|
-
"@cef-ai/signer": "1.0.0",
|
|
29
28
|
"@cef-ai/account": "1.3.1",
|
|
29
|
+
"@cef-ai/signer": "1.0.0",
|
|
30
30
|
"@cef-ai/transport": "1.1.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
package/dist/internal/orgs.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { VaultHttpClient } from "../core/http.js";
|
|
2
|
-
import type { Membership, OrgRecord, OrgRole, OrgScopeLevel, OrgSummary } from "../core/types.js";
|
|
3
|
-
export declare class Orgs {
|
|
4
|
-
private readonly http;
|
|
5
|
-
constructor(http: VaultHttpClient);
|
|
6
|
-
/** Orgs the caller owns or is a member of, with the scopes granted to them. */
|
|
7
|
-
list(): Promise<OrgSummary[]>;
|
|
8
|
-
/**
|
|
9
|
-
* Registers `orgId` under the caller's vault. The vault is DERIVED
|
|
10
|
-
* server-side from the caller's key — there is no `vaultId` parameter, and
|
|
11
|
-
* none should be added. Idempotent (upsert) when the org is already
|
|
12
|
-
* registered to the SAME wallet; 409 if it's registered to a different
|
|
13
|
-
* wallet; 403 if the caller isn't that vault's owner.
|
|
14
|
-
*
|
|
15
|
-
* The wallet-signature middleware (`pkg/shared/auth/signature.go`) rejects
|
|
16
|
-
* ANY mutation body with no top-level RFC3339 `timestamp` as 401
|
|
17
|
-
* `CodeInvalidSignature "body missing timestamp"` — this applies before
|
|
18
|
-
* the request ever reaches `org.go`, which itself does not validate the
|
|
19
|
-
* field. `WalletAuthProvider` supplies one during canonicalisation;
|
|
20
|
-
* `DelegationAuthProvider` (which never passes through that middleware)
|
|
21
|
-
* supplies nothing. Sending it explicitly here keeps the body correct on
|
|
22
|
-
* both paths and matches the `Timestamp` field this wire struct declares.
|
|
23
|
-
*/
|
|
24
|
-
register(orgId: string, name: string): Promise<OrgRecord>;
|
|
25
|
-
/**
|
|
26
|
-
* Member rows for `orgId`. 403 unless the caller is the org wallet itself
|
|
27
|
-
* or holds a LIVE membership; 404 if the org doesn't exist.
|
|
28
|
-
*/
|
|
29
|
-
members(orgId: string): Promise<Membership[]>;
|
|
30
|
-
/**
|
|
31
|
-
* Upserts a member's role (and optional expiry). 400 if `memberPubkey` is
|
|
32
|
-
* the org wallet itself — the org wallet owns the org and is never a
|
|
33
|
-
* member row. `memberPubkey` should already be in the server's canonical
|
|
34
|
-
* 0x-lowercase-hex spelling (`auth.CanonicalPubKeyHex`). `expiresAt` must
|
|
35
|
-
* be RFC3339 — Go unmarshals it into `*time.Time`, and e.g. `"2031-01-01"`
|
|
36
|
-
* 400s as "put member: bad body".
|
|
37
|
-
*
|
|
38
|
-
* See `register`'s doc comment: the timestamp is explicit here for the
|
|
39
|
-
* same reason (the wallet-signature middleware, not org.go, requires it).
|
|
40
|
-
*/
|
|
41
|
-
putMember(orgId: string, memberPubkey: string, role: OrgRole, expiresAt?: string): Promise<Membership>;
|
|
42
|
-
/**
|
|
43
|
-
* Removes a member row. `org.go`'s DeleteMember handler never reads the
|
|
44
|
-
* body at all, but the wallet-signature middleware still requires a
|
|
45
|
-
* top-level `timestamp` on every mutation body regardless of what the
|
|
46
|
-
* handler does with it (see `register`'s doc comment) — so this body is
|
|
47
|
-
* `{timestamp}` and nothing else.
|
|
48
|
-
*/
|
|
49
|
-
deleteMember(orgId: string, memberPubkey: string): Promise<void>;
|
|
50
|
-
/**
|
|
51
|
-
* Replaces a member's FULL scope-grant set — the server deletes then
|
|
52
|
-
* reinserts, so this is never a merge/diff against the existing grants.
|
|
53
|
-
* 404 if the membership row doesn't exist, INCLUDING for an empty
|
|
54
|
-
* `scopes` map: the check is existence, not liveness, so an admin may
|
|
55
|
-
* prepare grants for a currently-suspended membership.
|
|
56
|
-
*/
|
|
57
|
-
putScopes(orgId: string, memberPubkey: string, scopes: Record<string, OrgScopeLevel>): Promise<void>;
|
|
58
|
-
}
|
|
59
|
-
//# sourceMappingURL=orgs.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../src/internal/orgs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAElG,qBAAa,IAAI;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,eAAe;IAElD,+EAA+E;IAC/E,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAI7B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAMzD;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAI7C;;;;;;;;;;OAUG;IACH,SAAS,CACP,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,OAAO,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC;IAMtB;;;;;;OAMG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhE;;;;;;OAMG;IACH,SAAS,CACP,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC;CAKjB"}
|