@calimero-network/mero-js 18.0.0 → 18.1.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/dist/admin-api/admin-client.d.ts +106 -17
- package/dist/admin-api/admin-client.js +133 -57
- package/dist/admin-api/admin-types.d.ts +371 -32
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +148 -41
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +148 -41
- package/dist/index.mjs.map +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HttpClient } from '../http-client/index.js';
|
|
2
|
-
import type { HealthStatus, AdminAuthStatus, InstallApplicationRequest, InstallApplicationResponseData, InstallDevApplicationRequest, UninstallApplicationResponseData, ListApplicationsResponseData, GetApplicationResponseData, ApplicationVersionEntry, GetApplicationAbiResponseData, GetLatestVersionResponseData, ListPackagesResponseData, ListVersionsResponseData, CreateContextRequest, CreateContextResponseData,
|
|
2
|
+
import type { HealthStatus, AdminAuthStatus, InstallApplicationRequest, InstallApplicationResponseData, InstallDevApplicationRequest, UninstallApplicationResponseData, ListApplicationsResponseData, GetApplicationResponseData, ApplicationVersionEntry, GetApplicationAbiResponseData, GetLatestVersionResponseData, ListPackagesResponseData, ListVersionsResponseData, CreateContextRequest, CreateContextResponseData, DeleteContextResponseData, GetContextsResponseData, Context, GenerateContextIdentityResponseData, GetContextIdentitiesResponseData, JoinContextResponseData, JoinSubgroupInheritanceResponseData, ContextGroupResponseData, ContextStorageResponseData, InviteSpecializedNodeRequest, InviteSpecializedNodeResponseData, UpdateContextApplicationRequest, ResyncContextRequest, ResyncContextResponseData, ContextsWithExecutorsResponseData, UploadBlobRequest, UploadBlobResponseData, DeleteBlobResponseData, ListBlobsResponseData, GetBlobInfoResponseData, CreateContextAliasRequest, CreateApplicationAliasRequest, CreateAliasResponseData, LookupAliasResponseData, DeleteAliasResponseData, ListAliasesResponseData, ListNamespacesResponseData, CreateNamespaceRequest, CreateNamespaceResponseData, DeleteNamespaceResponseData, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, JoinNamespaceRequest, JoinNamespaceResponseData, CreateGroupInNamespaceRequest, CreateGroupInNamespaceResponseData, SubgroupEntry, Namespace, NamespaceIdentity, NodeIdentity, AccountPairInitRequest, AccountPairInitResponseData, AccountPairCompleteRequest, AccountPairCompleteResponseData, RelinkDeviceRequest, RelinkDeviceResponseData, AccountDeviceEntry, AccountApplicationEntry, RevokeAccountDeviceRequest, RevokeAccountDeviceResponseData, GroupInfoResponseData, CreateGroupRequest, CreateGroupResponseData, DeleteGroupResponseData, ListGroupMembersResponseData, ListGroupContextsResponseData, AddGroupMembersRequest, RemoveGroupMembersRequest, UpdateMemberRoleRequest, MemberCapabilities, SetMemberCapabilitiesRequest, SetDefaultCapabilitiesRequest, SetMemberAutoFollowRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, GetTeeAdmissionPolicyResponseData, SetGroupMetadataRequest, SetMemberMetadataRequest, SetContextMetadataRequest, MetadataRecord, SyncGroupResponseData, UpgradeGroupRequest, UpgradeGroupResponseData, GroupUpgradeStatusResponseData, MigrationStatus, CascadeStatusEntry, RetryGroupUpgradeResponseData, ReparentGroupRequest, ReparentGroupResponseData, IssueOwnershipProofRequest, IssueNamespaceOwnershipProofRequest, IssueOwnershipProofResponseData, CreateGroupInvitationRequest, CreateGroupInvitationResponseData, CreateRecursiveGroupInvitationResponseData, JoinGroupRequest, JoinGroupResponseData, TeeInfoResponseData, TeeAttestRequest, TeeAttestResponseData, TeeVerifyQuoteRequest, TeeVerifyQuoteResponseData, PerformIntentRequest, PerformIntentResponseData, AdmitJoinRequest, AdmitJoinResponseData } from './admin-types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Compare two version strings by SemVer 2.0 precedence, ascending: negative if
|
|
5
5
|
* `a < b`, positive if `a > b`, `0` if equal. Build metadata (`+...`) is stripped
|
|
@@ -52,7 +52,7 @@ export declare class AdminApiClient {
|
|
|
52
52
|
listPackageVersions(packageName: string): Promise<ListVersionsResponseData>;
|
|
53
53
|
getLatestPackageVersion(packageName: string): Promise<GetLatestVersionResponseData>;
|
|
54
54
|
createContext(request: CreateContextRequest): Promise<CreateContextResponseData>;
|
|
55
|
-
deleteContext(contextId: string
|
|
55
|
+
deleteContext(contextId: string): Promise<DeleteContextResponseData>;
|
|
56
56
|
getContexts(): Promise<GetContextsResponseData>;
|
|
57
57
|
getContext(contextId: string): Promise<Context>;
|
|
58
58
|
getContextsForApplication(applicationId: string): Promise<GetContextsResponseData>;
|
|
@@ -155,7 +155,7 @@ export declare class AdminApiClient {
|
|
|
155
155
|
performIntent(contextId: string, request: PerformIntentRequest): Promise<PerformIntentResponseData>;
|
|
156
156
|
listNamespacesForApplication(applicationId: string): Promise<ListNamespacesResponseData>;
|
|
157
157
|
createNamespace(request: CreateNamespaceRequest): Promise<CreateNamespaceResponseData>;
|
|
158
|
-
deleteNamespace(namespaceId: string
|
|
158
|
+
deleteNamespace(namespaceId: string): Promise<DeleteNamespaceResponseData>;
|
|
159
159
|
createNamespaceInvitation(namespaceId: string, request?: CreateNamespaceInvitationRequest): Promise<CreateNamespaceInvitationResponseData | CreateRecursiveInvitationResponseData>;
|
|
160
160
|
/**
|
|
161
161
|
* Present a join this caller signed to a node the inviter named as an
|
|
@@ -178,12 +178,103 @@ export declare class AdminApiClient {
|
|
|
178
178
|
joinNamespace(namespaceId: string, request: JoinNamespaceRequest): Promise<JoinNamespaceResponseData>;
|
|
179
179
|
createGroupInNamespace(namespaceId: string, request?: CreateGroupInNamespaceRequest): Promise<CreateGroupInNamespaceResponseData>;
|
|
180
180
|
listNamespaceGroups(namespaceId: string): Promise<SubgroupEntry[]>;
|
|
181
|
+
/**
|
|
182
|
+
* Mint this node a device for an account that already lives somewhere else -
|
|
183
|
+
* the first half of pairing, run on the joining node.
|
|
184
|
+
*
|
|
185
|
+
* Publishes nothing and needs no key: it produces the device id, the two
|
|
186
|
+
* public keys and the signature that the account holder's
|
|
187
|
+
* {@link completeAccountPairing} certifies, plus a code to read out to them
|
|
188
|
+
* over a channel the payload does not travel on. Until that second half runs,
|
|
189
|
+
* the device this mints is inert.
|
|
190
|
+
*
|
|
191
|
+
* Takes a set of namespaces rather than one, and takes it from the caller
|
|
192
|
+
* because this node cannot discover it: a node that is a member of nothing can
|
|
193
|
+
* neither read the account's namespace set off a DAG nor derive it. One device
|
|
194
|
+
* covers however many are named - the certificate is over the account, not a
|
|
195
|
+
* scope - so there is one id and one code to hand over regardless.
|
|
196
|
+
*/
|
|
197
|
+
initAccountPairing(request: AccountPairInitRequest): Promise<AccountPairInitResponseData>;
|
|
198
|
+
/**
|
|
199
|
+
* Certify a device another node minted, link it, and deliver its scope keys -
|
|
200
|
+
* the second half of pairing, run on the node that holds the account root.
|
|
201
|
+
*
|
|
202
|
+
* Every field but `applications` is copied verbatim out of that node's
|
|
203
|
+
* {@link initAccountPairing} answer. Only this side can complete it: the
|
|
204
|
+
* certificate is signed by the account root, which never leaves the node that
|
|
205
|
+
* holds it.
|
|
206
|
+
*
|
|
207
|
+
* The scope is named in applications, not namespaces, because that is the
|
|
208
|
+
* question a person can answer - a namespace is an implementation unit they
|
|
209
|
+
* never chose. Leave it out to grant every application.
|
|
210
|
+
*/
|
|
211
|
+
completeAccountPairing(request: AccountPairCompleteRequest): Promise<AccountPairCompleteResponseData>;
|
|
212
|
+
/**
|
|
213
|
+
* Re-run the pairing fan-out for a device this account already certified,
|
|
214
|
+
* against the namespaces this node takes part in now.
|
|
215
|
+
*
|
|
216
|
+
* Pairing is a snapshot, and this is how it is repeated. A namespace created
|
|
217
|
+
* or joined afterwards holds no binding for a device paired before it, and the
|
|
218
|
+
* symptom is silence - the device simply never sees that namespace. Nothing
|
|
219
|
+
* but the id is needed to repair it: the certificate is already held here,
|
|
220
|
+
* root-signed and naming no namespace, so a fresh endorsement and a key wrap
|
|
221
|
+
* are all a later namespace is missing. The device does not have to be online.
|
|
222
|
+
*
|
|
223
|
+
* Passing `applications` widens the device's stored scope as well as
|
|
224
|
+
* repairing. Passing none - or an empty list - repairs against the scope
|
|
225
|
+
* already stored, which is deliberately NOT the "every application" that an
|
|
226
|
+
* empty list means on {@link completeAccountPairing}: overloading it here
|
|
227
|
+
* would make the accidental request the widest one.
|
|
228
|
+
*/
|
|
229
|
+
relinkAccountDevice(deviceId: string, request?: RelinkDeviceRequest): Promise<RelinkDeviceResponseData>;
|
|
230
|
+
/**
|
|
231
|
+
* Every device of this account, as this node sees them - its own included.
|
|
232
|
+
*
|
|
233
|
+
* Joined from the node-local certificate cache and the live bindings of every
|
|
234
|
+
* namespace this node takes part in, so it is this node's view rather than a
|
|
235
|
+
* global one: a device certified by another holder appears with an empty
|
|
236
|
+
* `applications`, because the certificate that would name its scope is not
|
|
237
|
+
* cached here.
|
|
238
|
+
*
|
|
239
|
+
* The wire wraps this in `devices` rather than the usual `data`; the array is
|
|
240
|
+
* what a caller wants, so that wrapper is not passed on.
|
|
241
|
+
*/
|
|
242
|
+
listAccountDevices(): Promise<AccountDeviceEntry[]>;
|
|
243
|
+
/**
|
|
244
|
+
* Every application this account speaks in, with the namespaces targeting each.
|
|
245
|
+
*
|
|
246
|
+
* What a device-scoping UI lists: {@link completeAccountPairing} and
|
|
247
|
+
* {@link relinkAccountDevice} both take applications, and this is where the
|
|
248
|
+
* ids they take come from. Derived from the namespaces this node takes part
|
|
249
|
+
* in, so an application installed with no namespace yet is absent - it has
|
|
250
|
+
* nothing to scope a device to until one exists.
|
|
251
|
+
*
|
|
252
|
+
* Wrapped in `applications` on the wire rather than `data`, unwrapped here for
|
|
253
|
+
* the same reason {@link listAccountDevices} unwraps `devices`.
|
|
254
|
+
*/
|
|
255
|
+
listAccountApplications(): Promise<AccountApplicationEntry[]>;
|
|
256
|
+
/**
|
|
257
|
+
* Withdraw a device from this account, terminally.
|
|
258
|
+
*
|
|
259
|
+
* Two authorities reach the same endpoint. An admin may revoke any device and
|
|
260
|
+
* rotates the scope key as it goes. The account holder may revoke its own with
|
|
261
|
+
* a root-signed `proof`, which does not rotate - so read
|
|
262
|
+
* {@link RevokeAccountDeviceResponseData.revokedIn} rather than assuming the
|
|
263
|
+
* device lost its access: a namespace reporting `keyRotated: false` has
|
|
264
|
+
* stopped the device writing but leaves it able to read until an admin
|
|
265
|
+
* rotates.
|
|
266
|
+
*
|
|
267
|
+
* `namespaceId` names where to publish from, not the extent of the revocation:
|
|
268
|
+
* a device belongs to the account, so every namespace holding a binding for it
|
|
269
|
+
* is withdrawn from and reported back.
|
|
270
|
+
*/
|
|
271
|
+
revokeAccountDevice(namespaceId: string, request: RevokeAccountDeviceRequest): Promise<RevokeAccountDeviceResponseData>;
|
|
181
272
|
getGroupInfo(groupId: string): Promise<GroupInfoResponseData>;
|
|
182
273
|
/** Thin wrapper over {@link getGroupInfo}: returns the group's `defaultCapabilities` bitmask. */
|
|
183
274
|
getDefaultCapabilities(groupId: string): Promise<number>;
|
|
184
275
|
/** Thin wrapper over {@link getGroupInfo}: returns the group's `subgroupVisibility`. */
|
|
185
276
|
getSubgroupVisibility(groupId: string): Promise<string>;
|
|
186
|
-
deleteGroup(groupId: string
|
|
277
|
+
deleteGroup(groupId: string): Promise<DeleteGroupResponseData>;
|
|
187
278
|
listGroupMembers(groupId: string): Promise<ListGroupMembersResponseData>;
|
|
188
279
|
listGroupContexts(groupId: string): Promise<ListGroupContextsResponseData>;
|
|
189
280
|
addGroupMembers(groupId: string, request: AddGroupMembersRequest): Promise<void>;
|
|
@@ -221,7 +312,7 @@ export declare class AdminApiClient {
|
|
|
221
312
|
getMemberMetadata(groupId: string, identity: string): Promise<MetadataRecord | null>;
|
|
222
313
|
setContextMetadata(groupId: string, contextId: string, request: SetContextMetadataRequest): Promise<void>;
|
|
223
314
|
getContextMetadata(groupId: string, contextId: string): Promise<MetadataRecord | null>;
|
|
224
|
-
syncGroup(groupId: string
|
|
315
|
+
syncGroup(groupId: string): Promise<SyncGroupResponseData>;
|
|
225
316
|
upgradeGroup(groupId: string, request: UpgradeGroupRequest): Promise<UpgradeGroupResponseData>;
|
|
226
317
|
getGroupUpgradeStatus(groupId: string): Promise<GroupUpgradeStatusResponseData>;
|
|
227
318
|
/**
|
|
@@ -232,11 +323,11 @@ export declare class AdminApiClient {
|
|
|
232
323
|
getMigrationStatus(namespaceId: string): Promise<MigrationStatus>;
|
|
233
324
|
/** Per-group cascade-migration snapshots for a namespace. */
|
|
234
325
|
getCascadeStatus(namespaceId: string): Promise<CascadeStatusEntry[]>;
|
|
235
|
-
retryGroupUpgrade(groupId: string
|
|
326
|
+
retryGroupUpgrade(groupId: string): Promise<RetryGroupUpgradeResponseData>;
|
|
236
327
|
/** Move `childGroupId` under `request.newParentId`. */
|
|
237
328
|
reparentGroup(childGroupId: string, request: ReparentGroupRequest): Promise<ReparentGroupResponseData>;
|
|
238
329
|
listSubgroups(groupId: string): Promise<SubgroupEntry[]>;
|
|
239
|
-
detachContextFromGroup(groupId: string, contextId: string
|
|
330
|
+
detachContextFromGroup(groupId: string, contextId: string): Promise<void>;
|
|
240
331
|
createGroupInvitation(groupId: string, request?: CreateGroupInvitationRequest): Promise<CreateGroupInvitationResponseData | CreateRecursiveGroupInvitationResponseData>;
|
|
241
332
|
joinGroup(request: JoinGroupRequest): Promise<JoinGroupResponseData>;
|
|
242
333
|
joinSubgroupInheritance(groupId: string): Promise<JoinSubgroupInheritanceResponseData>;
|
|
@@ -253,19 +344,17 @@ export declare class AdminApiClient {
|
|
|
253
344
|
/** Node TLS certificate, PEM text (GET /admin-api/certificate). */
|
|
254
345
|
getCertificate(): Promise<string>;
|
|
255
346
|
/** Create a standalone group (POST /admin-api/groups). */
|
|
256
|
-
createGroup(request:
|
|
257
|
-
groupId: string;
|
|
258
|
-
}>;
|
|
347
|
+
createGroup(request: CreateGroupRequest): Promise<CreateGroupResponseData>;
|
|
259
348
|
/** Leave a group (POST /admin-api/groups/:group_id/leave). */
|
|
260
|
-
leaveGroup(groupId: string
|
|
349
|
+
leaveGroup(groupId: string): Promise<void>;
|
|
261
350
|
/** Leave a context (POST /admin-api/contexts/:context_id/leave). */
|
|
262
|
-
leaveContext(contextId: string
|
|
351
|
+
leaveContext(contextId: string): Promise<void>;
|
|
263
352
|
/** Leave a namespace (POST /admin-api/namespaces/:namespace_id/leave). */
|
|
264
|
-
leaveNamespace(namespaceId: string
|
|
353
|
+
leaveNamespace(namespaceId: string): Promise<void>;
|
|
265
354
|
/** Issue a group ownership proof (POST /admin-api/groups/:group_id/issue-ownership-proof). */
|
|
266
|
-
issueOwnershipProof(groupId: string, request
|
|
355
|
+
issueOwnershipProof(groupId: string, request: IssueOwnershipProofRequest): Promise<IssueOwnershipProofResponseData>;
|
|
267
356
|
/** Issue a namespace ownership proof (POST /admin-api/groups/:group_id/issue-namespace-ownership-proof). */
|
|
268
|
-
issueNamespaceOwnershipProof(groupId: string, request
|
|
357
|
+
issueNamespaceOwnershipProof(groupId: string, request: IssueNamespaceOwnershipProofRequest): Promise<IssueOwnershipProofResponseData>;
|
|
269
358
|
/**
|
|
270
359
|
* Set a member's auto-follow flag (PUT
|
|
271
360
|
* /admin-api/groups/:group_id/members/:identity/auto-follow).
|
|
@@ -274,7 +363,7 @@ export declare class AdminApiClient {
|
|
|
274
363
|
* {@link listGroupMembers} — not the signing key that added them. Both are
|
|
275
364
|
* 64 hex, so nothing but the source tells them apart.
|
|
276
365
|
*/
|
|
277
|
-
setMemberAutoFollow(groupId: string, identity: string, request:
|
|
366
|
+
setMemberAutoFollow(groupId: string, identity: string, request: SetMemberAutoFollowRequest): Promise<void>;
|
|
278
367
|
/** Abort a namespace migration (POST /admin-api/groups/:namespace_id/migration/abort). */
|
|
279
|
-
abortMigration(namespaceId: string
|
|
368
|
+
abortMigration(namespaceId: string): Promise<unknown>;
|
|
280
369
|
}
|
|
@@ -184,14 +184,7 @@ export class AdminApiClient {
|
|
|
184
184
|
const body = { ...request, initializationParams: request.initializationParams ?? [] };
|
|
185
185
|
return unwrap(await this.httpClient.post('/admin-api/contexts', body));
|
|
186
186
|
}
|
|
187
|
-
async deleteContext(contextId
|
|
188
|
-
if (request) {
|
|
189
|
-
return unwrap(await this.httpClient.request(`/admin-api/contexts/${contextId}`, {
|
|
190
|
-
method: 'DELETE',
|
|
191
|
-
body: JSON.stringify(request),
|
|
192
|
-
headers: { 'Content-Type': 'application/json' },
|
|
193
|
-
}));
|
|
194
|
-
}
|
|
187
|
+
async deleteContext(contextId) {
|
|
195
188
|
return unwrap(await this.httpClient.delete(`/admin-api/contexts/${contextId}`));
|
|
196
189
|
}
|
|
197
190
|
async getContexts() {
|
|
@@ -417,30 +410,14 @@ export class AdminApiClient {
|
|
|
417
410
|
return unwrap(await this.httpClient.get(`/admin-api/namespaces/for-application/${applicationId}`));
|
|
418
411
|
}
|
|
419
412
|
async createNamespace(request) {
|
|
420
|
-
|
|
421
|
-
//
|
|
422
|
-
// The concept was deleted server-side (calimero-network/core#3393), but only
|
|
423
|
-
// on master: every RELEASED node still declares the field required and
|
|
424
|
-
// rejects a body without it — `missing field 'upgradePolicy'`. A node that
|
|
425
|
-
// has dropped it ignores the extra key, so sending it is the one shape that
|
|
426
|
-
// works against both, and this SDK does not get to choose which node a
|
|
427
|
-
// caller points it at.
|
|
428
|
-
//
|
|
429
|
-
// `LazyOnAccess` because it was the default and is the only behaviour that
|
|
430
|
-
// survives the removal, so an old node given it does what a new one does.
|
|
431
|
-
//
|
|
432
|
-
// Remove once no supported release predates that change.
|
|
433
|
-
return unwrap(await this.httpClient.post('/admin-api/namespaces', {
|
|
434
|
-
upgradePolicy: 'LazyOnAccess',
|
|
435
|
-
...request,
|
|
436
|
-
}));
|
|
413
|
+
return unwrap(await this.httpClient.post('/admin-api/namespaces', request));
|
|
437
414
|
}
|
|
438
|
-
async deleteNamespace(namespaceId
|
|
439
|
-
// Core requires `Content-Type: application/json` on this DELETE even
|
|
440
|
-
// body is empty, so
|
|
415
|
+
async deleteNamespace(namespaceId) {
|
|
416
|
+
// Core requires `Content-Type: application/json` on this DELETE even though
|
|
417
|
+
// the body is always empty, so send the header and an empty JSON object.
|
|
441
418
|
return unwrap(await this.httpClient.request(`/admin-api/namespaces/${namespaceId}`, {
|
|
442
419
|
method: 'DELETE',
|
|
443
|
-
body:
|
|
420
|
+
body: '{}',
|
|
444
421
|
headers: { 'Content-Type': 'application/json' },
|
|
445
422
|
}));
|
|
446
423
|
}
|
|
@@ -486,6 +463,112 @@ export class AdminApiClient {
|
|
|
486
463
|
async listNamespaceGroups(namespaceId) {
|
|
487
464
|
return unwrap(await this.httpClient.get(`/admin-api/namespaces/${namespaceId}/groups`));
|
|
488
465
|
}
|
|
466
|
+
// ---- Account Devices & Pairing ----
|
|
467
|
+
/**
|
|
468
|
+
* Mint this node a device for an account that already lives somewhere else -
|
|
469
|
+
* the first half of pairing, run on the joining node.
|
|
470
|
+
*
|
|
471
|
+
* Publishes nothing and needs no key: it produces the device id, the two
|
|
472
|
+
* public keys and the signature that the account holder's
|
|
473
|
+
* {@link completeAccountPairing} certifies, plus a code to read out to them
|
|
474
|
+
* over a channel the payload does not travel on. Until that second half runs,
|
|
475
|
+
* the device this mints is inert.
|
|
476
|
+
*
|
|
477
|
+
* Takes a set of namespaces rather than one, and takes it from the caller
|
|
478
|
+
* because this node cannot discover it: a node that is a member of nothing can
|
|
479
|
+
* neither read the account's namespace set off a DAG nor derive it. One device
|
|
480
|
+
* covers however many are named - the certificate is over the account, not a
|
|
481
|
+
* scope - so there is one id and one code to hand over regardless.
|
|
482
|
+
*/
|
|
483
|
+
async initAccountPairing(request) {
|
|
484
|
+
return unwrap(await this.httpClient.post('/admin-api/account/pair-init', request));
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Certify a device another node minted, link it, and deliver its scope keys -
|
|
488
|
+
* the second half of pairing, run on the node that holds the account root.
|
|
489
|
+
*
|
|
490
|
+
* Every field but `applications` is copied verbatim out of that node's
|
|
491
|
+
* {@link initAccountPairing} answer. Only this side can complete it: the
|
|
492
|
+
* certificate is signed by the account root, which never leaves the node that
|
|
493
|
+
* holds it.
|
|
494
|
+
*
|
|
495
|
+
* The scope is named in applications, not namespaces, because that is the
|
|
496
|
+
* question a person can answer - a namespace is an implementation unit they
|
|
497
|
+
* never chose. Leave it out to grant every application.
|
|
498
|
+
*/
|
|
499
|
+
async completeAccountPairing(request) {
|
|
500
|
+
return unwrap(await this.httpClient.post('/admin-api/account/pair-complete', request));
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Re-run the pairing fan-out for a device this account already certified,
|
|
504
|
+
* against the namespaces this node takes part in now.
|
|
505
|
+
*
|
|
506
|
+
* Pairing is a snapshot, and this is how it is repeated. A namespace created
|
|
507
|
+
* or joined afterwards holds no binding for a device paired before it, and the
|
|
508
|
+
* symptom is silence - the device simply never sees that namespace. Nothing
|
|
509
|
+
* but the id is needed to repair it: the certificate is already held here,
|
|
510
|
+
* root-signed and naming no namespace, so a fresh endorsement and a key wrap
|
|
511
|
+
* are all a later namespace is missing. The device does not have to be online.
|
|
512
|
+
*
|
|
513
|
+
* Passing `applications` widens the device's stored scope as well as
|
|
514
|
+
* repairing. Passing none - or an empty list - repairs against the scope
|
|
515
|
+
* already stored, which is deliberately NOT the "every application" that an
|
|
516
|
+
* empty list means on {@link completeAccountPairing}: overloading it here
|
|
517
|
+
* would make the accidental request the widest one.
|
|
518
|
+
*/
|
|
519
|
+
async relinkAccountDevice(deviceId, request) {
|
|
520
|
+
return unwrap(await this.httpClient.post(`/admin-api/account/devices/${deviceId}/relink`, request ?? {}));
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Every device of this account, as this node sees them - its own included.
|
|
524
|
+
*
|
|
525
|
+
* Joined from the node-local certificate cache and the live bindings of every
|
|
526
|
+
* namespace this node takes part in, so it is this node's view rather than a
|
|
527
|
+
* global one: a device certified by another holder appears with an empty
|
|
528
|
+
* `applications`, because the certificate that would name its scope is not
|
|
529
|
+
* cached here.
|
|
530
|
+
*
|
|
531
|
+
* The wire wraps this in `devices` rather than the usual `data`; the array is
|
|
532
|
+
* what a caller wants, so that wrapper is not passed on.
|
|
533
|
+
*/
|
|
534
|
+
async listAccountDevices() {
|
|
535
|
+
const response = await this.httpClient.get('/admin-api/account/devices');
|
|
536
|
+
return response.devices;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Every application this account speaks in, with the namespaces targeting each.
|
|
540
|
+
*
|
|
541
|
+
* What a device-scoping UI lists: {@link completeAccountPairing} and
|
|
542
|
+
* {@link relinkAccountDevice} both take applications, and this is where the
|
|
543
|
+
* ids they take come from. Derived from the namespaces this node takes part
|
|
544
|
+
* in, so an application installed with no namespace yet is absent - it has
|
|
545
|
+
* nothing to scope a device to until one exists.
|
|
546
|
+
*
|
|
547
|
+
* Wrapped in `applications` on the wire rather than `data`, unwrapped here for
|
|
548
|
+
* the same reason {@link listAccountDevices} unwraps `devices`.
|
|
549
|
+
*/
|
|
550
|
+
async listAccountApplications() {
|
|
551
|
+
const response = await this.httpClient.get('/admin-api/account/applications');
|
|
552
|
+
return response.applications;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Withdraw a device from this account, terminally.
|
|
556
|
+
*
|
|
557
|
+
* Two authorities reach the same endpoint. An admin may revoke any device and
|
|
558
|
+
* rotates the scope key as it goes. The account holder may revoke its own with
|
|
559
|
+
* a root-signed `proof`, which does not rotate - so read
|
|
560
|
+
* {@link RevokeAccountDeviceResponseData.revokedIn} rather than assuming the
|
|
561
|
+
* device lost its access: a namespace reporting `keyRotated: false` has
|
|
562
|
+
* stopped the device writing but leaves it able to read until an admin
|
|
563
|
+
* rotates.
|
|
564
|
+
*
|
|
565
|
+
* `namespaceId` names where to publish from, not the extent of the revocation:
|
|
566
|
+
* a device belongs to the account, so every namespace holding a binding for it
|
|
567
|
+
* is withdrawn from and reported back.
|
|
568
|
+
*/
|
|
569
|
+
async revokeAccountDevice(namespaceId, request) {
|
|
570
|
+
return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/account/revoke`, request));
|
|
571
|
+
}
|
|
489
572
|
// ---- Group Management ----
|
|
490
573
|
async getGroupInfo(groupId) {
|
|
491
574
|
return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}`));
|
|
@@ -498,12 +581,12 @@ export class AdminApiClient {
|
|
|
498
581
|
async getSubgroupVisibility(groupId) {
|
|
499
582
|
return (await this.getGroupInfo(groupId)).subgroupVisibility;
|
|
500
583
|
}
|
|
501
|
-
async deleteGroup(groupId
|
|
502
|
-
// Core requires `Content-Type: application/json` on this DELETE even
|
|
503
|
-
//
|
|
584
|
+
async deleteGroup(groupId) {
|
|
585
|
+
// Core requires `Content-Type: application/json` on this DELETE even though
|
|
586
|
+
// the body is always empty, so send the header and an empty JSON object.
|
|
504
587
|
return unwrap(await this.httpClient.request(`/admin-api/groups/${groupId}`, {
|
|
505
588
|
method: 'DELETE',
|
|
506
|
-
body:
|
|
589
|
+
body: '{}',
|
|
507
590
|
headers: { 'Content-Type': 'application/json' },
|
|
508
591
|
}));
|
|
509
592
|
}
|
|
@@ -604,8 +687,8 @@ export class AdminApiClient {
|
|
|
604
687
|
const response = await this.httpClient.get(`/admin-api/groups/${groupId}/contexts/${contextId}/metadata`);
|
|
605
688
|
return response?.data ?? null;
|
|
606
689
|
}
|
|
607
|
-
async syncGroup(groupId
|
|
608
|
-
return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/sync`,
|
|
690
|
+
async syncGroup(groupId) {
|
|
691
|
+
return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/sync`, {}));
|
|
609
692
|
}
|
|
610
693
|
async upgradeGroup(groupId, request) {
|
|
611
694
|
return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/upgrade`, request));
|
|
@@ -627,8 +710,8 @@ export class AdminApiClient {
|
|
|
627
710
|
const id = encodeURIComponent(namespaceId);
|
|
628
711
|
return unwrap(await this.httpClient.get(`/admin-api/groups/${id}/cascade-status`));
|
|
629
712
|
}
|
|
630
|
-
async retryGroupUpgrade(groupId
|
|
631
|
-
return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/upgrade/retry`,
|
|
713
|
+
async retryGroupUpgrade(groupId) {
|
|
714
|
+
return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/upgrade/retry`, {}));
|
|
632
715
|
}
|
|
633
716
|
/** Move `childGroupId` under `request.newParentId`. */
|
|
634
717
|
async reparentGroup(childGroupId, request) {
|
|
@@ -640,8 +723,8 @@ export class AdminApiClient {
|
|
|
640
723
|
const response = await this.httpClient.get(`/admin-api/groups/${groupId}/subgroups`);
|
|
641
724
|
return response.subgroups ?? response.data ?? [];
|
|
642
725
|
}
|
|
643
|
-
async detachContextFromGroup(groupId, contextId
|
|
644
|
-
await this.httpClient.post(`/admin-api/groups/${groupId}/contexts/${contextId}/remove`,
|
|
726
|
+
async detachContextFromGroup(groupId, contextId) {
|
|
727
|
+
await this.httpClient.post(`/admin-api/groups/${groupId}/contexts/${contextId}/remove`, {});
|
|
645
728
|
}
|
|
646
729
|
// ---- Group Invitation & Join ----
|
|
647
730
|
async createGroupInvitation(groupId, request) {
|
|
@@ -682,34 +765,27 @@ export class AdminApiClient {
|
|
|
682
765
|
// ---- Group / context / namespace membership ----
|
|
683
766
|
/** Create a standalone group (POST /admin-api/groups). */
|
|
684
767
|
async createGroup(request) {
|
|
685
|
-
|
|
686
|
-
// the only two requests a released node still requires it on, and it ignores
|
|
687
|
-
// the extra key once the concept is gone. Spread after the caller's request
|
|
688
|
-
// so an explicit value wins.
|
|
689
|
-
return unwrap(await this.httpClient.post('/admin-api/groups', {
|
|
690
|
-
upgradePolicy: 'LazyOnAccess',
|
|
691
|
-
...request,
|
|
692
|
-
}));
|
|
768
|
+
return unwrap(await this.httpClient.post('/admin-api/groups', request));
|
|
693
769
|
}
|
|
694
770
|
/** Leave a group (POST /admin-api/groups/:group_id/leave). */
|
|
695
|
-
async leaveGroup(groupId
|
|
696
|
-
await this.httpClient.post(`/admin-api/groups/${groupId}/leave`,
|
|
771
|
+
async leaveGroup(groupId) {
|
|
772
|
+
await this.httpClient.post(`/admin-api/groups/${groupId}/leave`, {});
|
|
697
773
|
}
|
|
698
774
|
/** Leave a context (POST /admin-api/contexts/:context_id/leave). */
|
|
699
|
-
async leaveContext(contextId
|
|
700
|
-
await this.httpClient.post(`/admin-api/contexts/${contextId}/leave`,
|
|
775
|
+
async leaveContext(contextId) {
|
|
776
|
+
await this.httpClient.post(`/admin-api/contexts/${contextId}/leave`, {});
|
|
701
777
|
}
|
|
702
778
|
/** Leave a namespace (POST /admin-api/namespaces/:namespace_id/leave). */
|
|
703
|
-
async leaveNamespace(namespaceId
|
|
704
|
-
await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/leave`,
|
|
779
|
+
async leaveNamespace(namespaceId) {
|
|
780
|
+
await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/leave`, {});
|
|
705
781
|
}
|
|
706
782
|
/** Issue a group ownership proof (POST /admin-api/groups/:group_id/issue-ownership-proof). */
|
|
707
783
|
async issueOwnershipProof(groupId, request) {
|
|
708
|
-
return this.httpClient.post(`/admin-api/groups/${groupId}/issue-ownership-proof`, request
|
|
784
|
+
return this.httpClient.post(`/admin-api/groups/${groupId}/issue-ownership-proof`, request);
|
|
709
785
|
}
|
|
710
786
|
/** Issue a namespace ownership proof (POST /admin-api/groups/:group_id/issue-namespace-ownership-proof). */
|
|
711
787
|
async issueNamespaceOwnershipProof(groupId, request) {
|
|
712
|
-
return this.httpClient.post(`/admin-api/groups/${groupId}/issue-namespace-ownership-proof`, request
|
|
788
|
+
return this.httpClient.post(`/admin-api/groups/${groupId}/issue-namespace-ownership-proof`, request);
|
|
713
789
|
}
|
|
714
790
|
/**
|
|
715
791
|
* Set a member's auto-follow flag (PUT
|
|
@@ -723,7 +799,7 @@ export class AdminApiClient {
|
|
|
723
799
|
await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/auto-follow`, request);
|
|
724
800
|
}
|
|
725
801
|
/** Abort a namespace migration (POST /admin-api/groups/:namespace_id/migration/abort). */
|
|
726
|
-
async abortMigration(namespaceId
|
|
727
|
-
return this.httpClient.post(`/admin-api/groups/${namespaceId}/migration/abort`,
|
|
802
|
+
async abortMigration(namespaceId) {
|
|
803
|
+
return this.httpClient.post(`/admin-api/groups/${namespaceId}/migration/abort`, {});
|
|
728
804
|
}
|
|
729
805
|
}
|