@calimero-network/mero-js 25.0.3 → 25.0.5

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.
@@ -1,4 +1,5 @@
1
1
  import { HTTPError, withRetry } from '../http-client/index.js';
2
+ import { pathSegment } from '../http-client/path-segment.js';
2
3
  import { CAPABILITIES, hasCap, withCap } from '../capabilities.js';
3
4
  import { redeemInvitation } from './redeem-invitation.js';
4
5
  /**
@@ -234,13 +235,13 @@ export class AdminApiClient {
234
235
  return unwrap(await this.httpClient.post('/admin-api/install-dev-application', request));
235
236
  }
236
237
  async uninstallApplication(appId) {
237
- return unwrap(await this.httpClient.delete(`/admin-api/applications/${appId}`));
238
+ return unwrap(await this.httpClient.delete(`/admin-api/applications/${pathSegment(appId)}`));
238
239
  }
239
240
  async listApplications() {
240
241
  return unwrap(await this.httpClient.get('/admin-api/applications'));
241
242
  }
242
243
  async getApplication(appId) {
243
- return unwrap(await this.httpClient.get(`/admin-api/applications/${appId}`));
244
+ return unwrap(await this.httpClient.get(`/admin-api/applications/${pathSegment(appId)}`));
244
245
  }
245
246
  /**
246
247
  * Installed-blob inventory for an application — one entry per locally installed
@@ -248,7 +249,7 @@ export class AdminApiClient {
248
249
  * pin" UI); the registry equivalent is `listPackageVersions`.
249
250
  */
250
251
  async listApplicationVersions(applicationId) {
251
- return unwrap(await this.httpClient.get(`/admin-api/applications/${applicationId}/versions`));
252
+ return unwrap(await this.httpClient.get(`/admin-api/applications/${pathSegment(applicationId)}/versions`));
252
253
  }
253
254
  /**
254
255
  * The application's embedded `wasm-abi/1` manifest. Omit `serviceName` for
@@ -256,7 +257,7 @@ export class AdminApiClient {
256
257
  */
257
258
  async getApplicationAbi(applicationId, serviceName) {
258
259
  const query = serviceName ? `?service_name=${encodeURIComponent(serviceName)}` : '';
259
- return unwrap(await this.httpClient.get(`/admin-api/applications/${applicationId}/abi${query}`));
260
+ return unwrap(await this.httpClient.get(`/admin-api/applications/${pathSegment(applicationId)}/abi${query}`));
260
261
  }
261
262
  // ---- Package Management ----
262
263
  async listPackages() {
@@ -266,11 +267,11 @@ export class AdminApiClient {
266
267
  }
267
268
  async listPackageVersions(packageName) {
268
269
  // Core returns this flat ({ versions: [...] }), not under `data`; tolerate both.
269
- const r = await this.httpClient.get(`/admin-api/packages/${encodeURIComponent(packageName)}/versions`);
270
+ const r = await this.httpClient.get(`/admin-api/packages/${pathSegment(packageName)}/versions`);
270
271
  return (r?.data ?? r);
271
272
  }
272
273
  async getLatestPackageVersion(packageName) {
273
- return this.httpClient.get(`/admin-api/packages/${encodeURIComponent(packageName)}/latest`);
274
+ return this.httpClient.get(`/admin-api/packages/${pathSegment(packageName)}/latest`);
274
275
  }
275
276
  // ---- Context Management ----
276
277
  async createContext(request) {
@@ -280,43 +281,43 @@ export class AdminApiClient {
280
281
  return unwrap(await this.httpClient.post('/admin-api/contexts', body));
281
282
  }
282
283
  async deleteContext(contextId) {
283
- return unwrap(await this.httpClient.delete(`/admin-api/contexts/${contextId}`));
284
+ return unwrap(await this.httpClient.delete(`/admin-api/contexts/${pathSegment(contextId)}`));
284
285
  }
285
286
  async getContexts() {
286
287
  return unwrap(await this.httpClient.get('/admin-api/contexts'));
287
288
  }
288
289
  async getContext(contextId) {
289
- return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}`));
290
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/${pathSegment(contextId)}`));
290
291
  }
291
292
  async getContextsForApplication(applicationId) {
292
- return unwrap(await this.httpClient.get(`/admin-api/contexts/for-application/${applicationId}`));
293
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/for-application/${pathSegment(applicationId)}`));
293
294
  }
294
295
  // ---- Context Identity ----
295
296
  async generateContextIdentity() {
296
297
  return unwrap(await this.httpClient.post('/admin-api/identity/context', {}));
297
298
  }
298
299
  async getContextIdentities(contextId) {
299
- return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/identities`));
300
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/${pathSegment(contextId)}/identities`));
300
301
  }
301
302
  async getContextIdentitiesOwned(contextId) {
302
- return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/identities-owned`));
303
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/${pathSegment(contextId)}/identities-owned`));
303
304
  }
304
305
  // ---- Context join (group membership) ----
305
306
  async joinContext(contextId) {
306
- return unwrap(await this.httpClient.post(`/admin-api/contexts/${contextId}/join`, {}));
307
+ return unwrap(await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/join`, {}));
307
308
  }
308
309
  // ---- Context group / storage / sync ----
309
310
  async getContextGroup(contextId) {
310
- return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/group`));
311
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/${pathSegment(contextId)}/group`));
311
312
  }
312
313
  async getContextStorage(contextId) {
313
- return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/storage`));
314
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/${pathSegment(contextId)}/storage`));
314
315
  }
315
316
  /** Sync one context, or every context when `contextId` is omitted. */
316
317
  async syncContext(contextId) {
317
318
  // Sync-all is `/contexts/sync` with no trailing slash - core routes the two
318
319
  // spellings separately and 404s the trailing one.
319
- const path = contextId ? `/admin-api/contexts/sync/${contextId}` : '/admin-api/contexts/sync';
320
+ const path = contextId ? `/admin-api/contexts/sync/${pathSegment(contextId)}` : '/admin-api/contexts/sync';
320
321
  await this.httpClient.post(path, {});
321
322
  }
322
323
  /**
@@ -328,7 +329,7 @@ export class AdminApiClient {
328
329
  // Core's `ResyncContextApiResponse` is a flat payload (no inner `data`
329
330
  // field), so parse the body directly — do NOT `unwrap`, or `resyncStarted`
330
331
  // reads as undefined and the resync silently appears to never start.
331
- const r = await this.httpClient.post(`/admin-api/contexts/${contextId}/resync`, request);
332
+ const r = await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/resync`, request);
332
333
  // An empty 2xx body means the resync was accepted; synthesize the result so
333
334
  // callers always get a typed value instead of null.
334
335
  return r ?? { contextId, resyncStarted: true };
@@ -337,11 +338,11 @@ export class AdminApiClient {
337
338
  return unwrap(await this.httpClient.post('/admin-api/contexts/invite-specialized-node', request));
338
339
  }
339
340
  async updateContextApplication(contextId, request) {
340
- await this.httpClient.post(`/admin-api/contexts/${contextId}/application`, request);
341
+ await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/application`, request);
341
342
  }
342
343
  async getContextsWithExecutorsForApplication(applicationId) {
343
344
  // Core returns this flat as { contexts: [...] } (not a bare array under `data`).
344
- const r = await this.httpClient.get(`/admin-api/contexts/with-executors/for-application/${applicationId}`);
345
+ const r = await this.httpClient.get(`/admin-api/contexts/with-executors/for-application/${pathSegment(applicationId)}`);
345
346
  if (Array.isArray(r))
346
347
  return r;
347
348
  return (r?.contexts ??
@@ -374,7 +375,7 @@ export class AdminApiClient {
374
375
  // Core's `BlobDeleteResponse` is a flat, snake_case payload (`{ blob_id,
375
376
  // deleted }`) — the lone admin DTO without a camelCase rename and without an
376
377
  // inner `data` field. Parse directly (no `unwrap`) and map to camelCase.
377
- const body = await this.httpClient.delete(`/admin-api/blobs/${blobId}`);
378
+ const body = await this.httpClient.delete(`/admin-api/blobs/${pathSegment(blobId)}`);
378
379
  return { blobId: body.blob_id, deleted: body.deleted };
379
380
  }
380
381
  async listBlobs() {
@@ -389,9 +390,9 @@ export class AdminApiClient {
389
390
  */
390
391
  blobPath(blobId, options) {
391
392
  if (!options?.contextId)
392
- return `/admin-api/blobs/${blobId}`;
393
+ return `/admin-api/blobs/${pathSegment(blobId)}`;
393
394
  const params = new URLSearchParams({ context_id: options.contextId });
394
- return `/admin-api/blobs/${blobId}?${params.toString()}`;
395
+ return `/admin-api/blobs/${pathSegment(blobId)}?${params.toString()}`;
395
396
  }
396
397
  /**
397
398
  * Download a blob's raw bytes. `GET /admin-api/blobs/:id` streams the blob
@@ -447,16 +448,16 @@ export class AdminApiClient {
447
448
  return unwrap(await this.httpClient.post('/admin-api/alias/create/application', { alias: request.alias, applicationId: request.applicationId }));
448
449
  }
449
450
  async lookupContextAlias(name) {
450
- return unwrap(await this.httpClient.post(`/admin-api/alias/lookup/context/${encodeURIComponent(name)}`, {}));
451
+ return unwrap(await this.httpClient.post(`/admin-api/alias/lookup/context/${pathSegment(name)}`, {}));
451
452
  }
452
453
  async lookupApplicationAlias(name) {
453
- return unwrap(await this.httpClient.post(`/admin-api/alias/lookup/application/${encodeURIComponent(name)}`, {}));
454
+ return unwrap(await this.httpClient.post(`/admin-api/alias/lookup/application/${pathSegment(name)}`, {}));
454
455
  }
455
456
  async deleteContextAlias(name) {
456
- return unwrap(await this.httpClient.post(`/admin-api/alias/delete/context/${encodeURIComponent(name)}`, {}));
457
+ return unwrap(await this.httpClient.post(`/admin-api/alias/delete/context/${pathSegment(name)}`, {}));
457
458
  }
458
459
  async deleteApplicationAlias(name) {
459
- return unwrap(await this.httpClient.post(`/admin-api/alias/delete/application/${encodeURIComponent(name)}`, {}));
460
+ return unwrap(await this.httpClient.post(`/admin-api/alias/delete/application/${pathSegment(name)}`, {}));
460
461
  }
461
462
  async listContextAliases() {
462
463
  return unwrap(await this.httpClient.get('/admin-api/alias/list/context'));
@@ -468,10 +469,10 @@ export class AdminApiClient {
468
469
  return unwrap(await this.httpClient.post('/admin-api/alias/create/device', { alias: request.alias, deviceId: request.deviceId }));
469
470
  }
470
471
  async lookupDeviceAlias(name) {
471
- return unwrap(await this.httpClient.post(`/admin-api/alias/lookup/device/${encodeURIComponent(name)}`, {}));
472
+ return unwrap(await this.httpClient.post(`/admin-api/alias/lookup/device/${pathSegment(name)}`, {}));
472
473
  }
473
474
  async deleteDeviceAlias(name) {
474
- return unwrap(await this.httpClient.post(`/admin-api/alias/delete/device/${encodeURIComponent(name)}`, {}));
475
+ return unwrap(await this.httpClient.post(`/admin-api/alias/delete/device/${pathSegment(name)}`, {}));
475
476
  }
476
477
  async listDeviceAliases() {
477
478
  return unwrap(await this.httpClient.get('/admin-api/alias/list/device'));
@@ -481,7 +482,7 @@ export class AdminApiClient {
481
482
  return unwrap(await this.httpClient.get('/admin-api/namespaces'));
482
483
  }
483
484
  async getNamespace(namespaceId) {
484
- return unwrap(await this.httpClient.get(`/admin-api/namespaces/${namespaceId}`));
485
+ return unwrap(await this.httpClient.get(`/admin-api/namespaces/${pathSegment(namespaceId)}`));
485
486
  }
486
487
  /**
487
488
  * Who this node is — the account it writes as, the device it is, the key it
@@ -544,7 +545,7 @@ export class AdminApiClient {
544
545
  * {@link PerformIntentRequest.warrant}.
545
546
  */
546
547
  async performIntent(contextId, request) {
547
- return unwrap(await this.httpClient.post(`/admin-api/contexts/${contextId}/intents`, request));
548
+ return unwrap(await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/intents`, request));
548
549
  }
549
550
  /**
550
551
  * Read a context as the session's ACCOUNT, without minting a warrant.
@@ -556,7 +557,7 @@ export class AdminApiClient {
556
557
  * {@link performIntent}).
557
558
  */
558
559
  async queryContext(contextId, request) {
559
- return unwrap(await this.httpClient.post(`/admin-api/contexts/${contextId}/query`, request));
560
+ return unwrap(await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/query`, request));
560
561
  }
561
562
  /**
562
563
  * Ask what this node can do for a member in `contextId`, before they sign
@@ -580,10 +581,10 @@ export class AdminApiClient {
580
581
  * run as a relay.
581
582
  */
582
583
  async getIntentRelay(contextId) {
583
- return unwrap(await this.httpClient.get(`/admin-api/contexts/${contextId}/intents`));
584
+ return unwrap(await this.httpClient.get(`/admin-api/contexts/${pathSegment(contextId)}/intents`));
584
585
  }
585
586
  async listNamespacesForApplication(applicationId) {
586
- return unwrap(await this.httpClient.get(`/admin-api/namespaces/for-application/${applicationId}`));
587
+ return unwrap(await this.httpClient.get(`/admin-api/namespaces/for-application/${pathSegment(applicationId)}`));
587
588
  }
588
589
  async createNamespace(request) {
589
590
  return unwrap(await this.httpClient.post('/admin-api/namespaces', request));
@@ -591,14 +592,14 @@ export class AdminApiClient {
591
592
  async deleteNamespace(namespaceId) {
592
593
  // Core requires `Content-Type: application/json` on this DELETE even though
593
594
  // the body is always empty, so send the header and an empty JSON object.
594
- return unwrap(await this.httpClient.request(`/admin-api/namespaces/${namespaceId}`, {
595
+ return unwrap(await this.httpClient.request(`/admin-api/namespaces/${pathSegment(namespaceId)}`, {
595
596
  method: 'DELETE',
596
597
  body: '{}',
597
598
  headers: { 'Content-Type': 'application/json' },
598
599
  }));
599
600
  }
600
601
  async createNamespaceInvitation(namespaceId, request) {
601
- return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/invite`, request ?? {}));
602
+ return unwrap(await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/invite`, request ?? {}));
602
603
  }
603
604
  /**
604
605
  * Present a join this caller signed to a node the inviter named as an
@@ -618,10 +619,10 @@ export class AdminApiClient {
618
619
  * @param request the invitation and the hex-encoded signed op
619
620
  */
620
621
  async admitJoin(namespaceId, request) {
621
- return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/admit`, request, { timeoutMs: 65000 }));
622
+ return unwrap(await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/admit`, request, { timeoutMs: 65000 }));
622
623
  }
623
624
  async joinNamespace(namespaceId, request) {
624
- const data = unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/join`, request, { timeoutMs: 65000 }));
625
+ const data = unwrap(await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/join`, request, { timeoutMs: 65000 }));
625
626
  // core 0.11.0-rc.25 renamed this response's `groupId` to `namespaceId`
626
627
  // (core#3598). Bind whichever spelling the node actually sent rather than
627
628
  // picking one: the rename lands as `undefined` on the field the client
@@ -662,10 +663,10 @@ export class AdminApiClient {
662
663
  });
663
664
  }
664
665
  async createGroupInNamespace(namespaceId, request) {
665
- return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/groups`, request ?? {}));
666
+ return unwrap(await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/groups`, request ?? {}));
666
667
  }
667
668
  async listNamespaceGroups(namespaceId) {
668
- return unwrap(await this.httpClient.get(`/admin-api/namespaces/${namespaceId}/groups`));
669
+ return unwrap(await this.httpClient.get(`/admin-api/namespaces/${pathSegment(namespaceId)}/groups`));
669
670
  }
670
671
  // ---- Account Devices & Pairing ----
671
672
  /**
@@ -721,7 +722,7 @@ export class AdminApiClient {
721
722
  * would make the accidental request the widest one.
722
723
  */
723
724
  async relinkAccountDevice(deviceId, request) {
724
- return unwrap(await this.httpClient.post(`/admin-api/account/devices/${deviceId}/relink`, request ?? {}));
725
+ return unwrap(await this.httpClient.post(`/admin-api/account/devices/${pathSegment(deviceId)}/relink`, request ?? {}));
725
726
  }
726
727
  /**
727
728
  * Replace a device's scope outright, in one root-signed op.
@@ -731,7 +732,7 @@ export class AdminApiClient {
731
732
  * device need not be online.
732
733
  */
733
734
  async rescopeAccountDevice(deviceId, request) {
734
- return unwrap(await this.httpClient.put(`/admin-api/account/devices/${encodeURIComponent(deviceId)}/scope`, request));
735
+ return unwrap(await this.httpClient.put(`/admin-api/account/devices/${pathSegment(deviceId)}/scope`, request));
735
736
  }
736
737
  /**
737
738
  * Sign a payload an outside verifier specified, with this account's root.
@@ -772,7 +773,7 @@ export class AdminApiClient {
772
773
  * node is accepted only for that device's own id.
773
774
  */
774
775
  async labelAccountDevice(deviceId, request) {
775
- return unwrap(await this.httpClient.put(`/admin-api/account/devices/${encodeURIComponent(deviceId)}/label`, request));
776
+ return unwrap(await this.httpClient.put(`/admin-api/account/devices/${pathSegment(deviceId)}/label`, request));
776
777
  }
777
778
  /**
778
779
  * Every device of this account, as this node sees them - its own included.
@@ -829,7 +830,7 @@ export class AdminApiClient {
829
830
  * that - "this device can no longer act" is the only claim it supports.
830
831
  */
831
832
  async revokeAccountDevice(namespaceId, request) {
832
- return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/account/revoke`, request));
833
+ return unwrap(await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/account/revoke`, request));
833
834
  }
834
835
  /**
835
836
  * Carry the device link of an account **this node does not hold**, so the
@@ -847,11 +848,11 @@ export class AdminApiClient {
847
848
  * account is a member of nothing in the namespace (add it first).
848
849
  */
849
850
  async linkAccountDevice(namespaceId, request) {
850
- return unwrap(await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/account/link-device`, request));
851
+ return unwrap(await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/account/link-device`, request));
851
852
  }
852
853
  // ---- Group Management ----
853
854
  async getGroupInfo(groupId) {
854
- return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}`));
855
+ return unwrap(await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}`));
855
856
  }
856
857
  /** Thin wrapper over {@link getGroupInfo}: returns the group's `defaultCapabilities` bitmask. */
857
858
  async getDefaultCapabilities(groupId) {
@@ -864,14 +865,14 @@ export class AdminApiClient {
864
865
  async deleteGroup(groupId) {
865
866
  // Core requires `Content-Type: application/json` on this DELETE even though
866
867
  // the body is always empty, so send the header and an empty JSON object.
867
- return unwrap(await this.httpClient.request(`/admin-api/groups/${groupId}`, {
868
+ return unwrap(await this.httpClient.request(`/admin-api/groups/${pathSegment(groupId)}`, {
868
869
  method: 'DELETE',
869
870
  body: '{}',
870
871
  headers: { 'Content-Type': 'application/json' },
871
872
  }));
872
873
  }
873
874
  async listGroupMembers(groupId) {
874
- const response = await this.httpClient.get(`/admin-api/groups/${groupId}/members`);
875
+ const response = await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/members`);
875
876
  // Validate the field we declare as non-optional in the type so a
876
877
  // contract-violating response (proxy error body, future API drift,
877
878
  // etc.) surfaces as a clear error rather than silently producing an
@@ -919,7 +920,7 @@ export class AdminApiClient {
919
920
  if (options?.limit !== undefined)
920
921
  params.set('limit', String(options.limit));
921
922
  const query = params.toString();
922
- const base = `/admin-api/groups/${encodeURIComponent(groupId)}/member-devices`;
923
+ const base = `/admin-api/groups/${pathSegment(groupId)}/member-devices`;
923
924
  const response = await this.httpClient.get(query ? `${base}?${query}` : base);
924
925
  return response.members;
925
926
  }
@@ -969,7 +970,7 @@ export class AdminApiClient {
969
970
  * hex (exactly 64). The node accepts either; the two never collide.
970
971
  */
971
972
  async getWarrantNonce(contextId, authorDeviceKey) {
972
- const path = `/admin-api/contexts/${encodeURIComponent(contextId)}/warrant-nonce/${encodeURIComponent(authorDeviceKey)}`;
973
+ const path = `/admin-api/contexts/${pathSegment(contextId)}/warrant-nonce/${pathSegment(authorDeviceKey)}`;
973
974
  // Read as TEXT, not JSON. `JSON.parse` would turn the `u64` nonces into
974
975
  // doubles before this code ever sees them, rounding anything past 2^53 into
975
976
  // a value that looks ordinary and is refused forever. The digits have to be
@@ -1014,7 +1015,7 @@ export class AdminApiClient {
1014
1015
  * value passed as `authorProof` to the relay client.
1015
1016
  */
1016
1017
  async getWarrantNonceAsAuthor(contextId, authorProof) {
1017
- const path = `/admin-api/contexts/${encodeURIComponent(contextId)}/warrant-nonce`;
1018
+ const path = `/admin-api/contexts/${pathSegment(contextId)}/warrant-nonce`;
1018
1019
  // Text, not JSON, for the reason given in `getWarrantNonce`: `JSON.parse`
1019
1020
  // rounds a u64 past 2^53 into a nonce that looks ordinary and is refused
1020
1021
  // for ever.
@@ -1042,7 +1043,7 @@ export class AdminApiClient {
1042
1043
  if (options.limit !== undefined)
1043
1044
  params.set('limit', String(options.limit));
1044
1045
  const query = params.toString();
1045
- const path = `/admin-api/groups/${groupId}/member-devices${query ? `?${query}` : ''}`;
1046
+ const path = `/admin-api/groups/${pathSegment(groupId)}/member-devices${query ? `?${query}` : ''}`;
1046
1047
  return this.httpClient.get(path);
1047
1048
  }
1048
1049
  /**
@@ -1051,16 +1052,16 @@ export class AdminApiClient {
1051
1052
  * the route reaches no further than the caller already does.
1052
1053
  */
1053
1054
  async sealToAccount(groupId, account, request) {
1054
- return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/accounts/${account}/seal`, request));
1055
+ return unwrap(await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/accounts/${pathSegment(account)}/seal`, request));
1055
1056
  }
1056
1057
  async listGroupContexts(groupId) {
1057
- return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}/contexts`));
1058
+ return unwrap(await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/contexts`));
1058
1059
  }
1059
1060
  async addGroupMembers(groupId, request) {
1060
- await this.httpClient.post(`/admin-api/groups/${groupId}/members`, request);
1061
+ await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/members`, request);
1061
1062
  }
1062
1063
  async removeGroupMembers(groupId, request) {
1063
- await this.httpClient.post(`/admin-api/groups/${groupId}/members/remove`, request);
1064
+ await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/members/remove`, request);
1064
1065
  }
1065
1066
  /**
1066
1067
  * `identity` is the member's ACCOUNT (64 hex), as returned by
@@ -1068,7 +1069,7 @@ export class AdminApiClient {
1068
1069
  * 64 hex, so nothing but the source tells them apart.
1069
1070
  */
1070
1071
  async updateMemberRole(groupId, identity, request) {
1071
- await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/role`, request);
1072
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/members/${pathSegment(identity)}/role`, request);
1072
1073
  }
1073
1074
  /**
1074
1075
  * `identity` is the member's ACCOUNT (64 hex), as returned by
@@ -1076,7 +1077,7 @@ export class AdminApiClient {
1076
1077
  * 64 hex, so nothing but the source tells them apart.
1077
1078
  */
1078
1079
  async getMemberCapabilities(groupId, identity) {
1079
- return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}/members/${identity}/capabilities`));
1080
+ return unwrap(await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/members/${pathSegment(identity)}/capabilities`));
1080
1081
  }
1081
1082
  /**
1082
1083
  * `identity` is the member's ACCOUNT (64 hex), as returned by
@@ -1084,10 +1085,10 @@ export class AdminApiClient {
1084
1085
  * 64 hex, so nothing but the source tells them apart.
1085
1086
  */
1086
1087
  async setMemberCapabilities(groupId, identity, request) {
1087
- await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/capabilities`, request);
1088
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/members/${pathSegment(identity)}/capabilities`, request);
1088
1089
  }
1089
1090
  async setDefaultCapabilities(groupId, request) {
1090
- await this.httpClient.put(`/admin-api/groups/${groupId}/settings/default-capabilities`, request);
1091
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/settings/default-capabilities`, request);
1091
1092
  }
1092
1093
  /**
1093
1094
  * Make every member admitted to `groupId` from now on able to relay a
@@ -1169,15 +1170,15 @@ export class AdminApiClient {
1169
1170
  return { changed: true, capabilities: next };
1170
1171
  }
1171
1172
  async setSubgroupVisibility(groupId, request) {
1172
- await this.httpClient.put(`/admin-api/groups/${groupId}/settings/subgroup-visibility`, request);
1173
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/settings/subgroup-visibility`, request);
1173
1174
  }
1174
1175
  async setTeeAdmissionPolicy(groupId, request) {
1175
- await this.httpClient.put(`/admin-api/groups/${groupId}/settings/tee-admission-policy`, request);
1176
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/settings/tee-admission-policy`, request);
1176
1177
  }
1177
1178
  async getTeeAdmissionPolicy(groupId) {
1178
1179
  // Intersection (not union) so the type is unambiguous: `data` is optional, so
1179
1180
  // `?? response` cleanly falls back to a flat (un-enveloped) response.
1180
- const response = await this.httpClient.get(`/admin-api/groups/${groupId}/settings/tee-admission-policy`);
1181
+ const response = await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/settings/tee-admission-policy`);
1181
1182
  return response.data ?? response;
1182
1183
  }
1183
1184
  /**
@@ -1187,7 +1188,7 @@ export class AdminApiClient {
1187
1188
  * route for this policy.
1188
1189
  */
1189
1190
  async setTeeAuthoringPolicy(groupId, request) {
1190
- await this.httpClient.put(`/admin-api/groups/${groupId}/settings/tee-authoring-policy`, request);
1191
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/settings/tee-authoring-policy`, request);
1191
1192
  }
1192
1193
  /**
1193
1194
  * Turns TEE authorship off in the namespace: every TEE loses its authority,
@@ -1199,7 +1200,7 @@ export class AdminApiClient {
1199
1200
  * (`teeAuthoringPolicyOp([])`); omit it on a node that holds that root.
1200
1201
  */
1201
1202
  async disableTeeAuthoringPolicy(groupId, options = {}) {
1202
- const path = `/admin-api/groups/${groupId}/settings/tee-authoring-policy`;
1203
+ const path = `/admin-api/groups/${pathSegment(groupId)}/settings/tee-authoring-policy`;
1203
1204
  if (options.rootProof === undefined) {
1204
1205
  await this.httpClient.delete(path);
1205
1206
  return;
@@ -1217,14 +1218,14 @@ export class AdminApiClient {
1217
1218
  * {@link RootGuardedOpRequest}.
1218
1219
  */
1219
1220
  async transferOwnership(groupId, request) {
1220
- await this.httpClient.post(`/admin-api/groups/${groupId}/transfer-ownership`, request);
1221
+ await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/transfer-ownership`, request);
1221
1222
  }
1222
1223
  /**
1223
1224
  * Repoint the namespace's admin pin at `newAdmin`, a member of its root.
1224
1225
  * Owner-only, with the owner account's root proof; see {@link RootGuardedOpRequest}.
1225
1226
  */
1226
1227
  async changeNamespaceAdmin(namespaceId, request) {
1227
- await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/admin`, request);
1228
+ await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/admin`, request);
1228
1229
  }
1229
1230
  /**
1230
1231
  * Delete a group through the owner-only path: it must hold no contexts, and
@@ -1232,22 +1233,22 @@ export class AdminApiClient {
1232
1233
  * admin-level cascading delete.
1233
1234
  */
1234
1235
  async ownerDeleteGroup(groupId, request = {}) {
1235
- await this.httpClient.post(`/admin-api/groups/${groupId}/owner-delete`, request);
1236
+ await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/owner-delete`, request);
1236
1237
  }
1237
1238
  // ---- Group / member / context metadata ----
1238
1239
  async setGroupMetadata(groupId, request) {
1239
- await this.httpClient.put(`/admin-api/groups/${groupId}/metadata`, request);
1240
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/metadata`, request);
1240
1241
  }
1241
1242
  async getGroupMetadata(groupId) {
1242
1243
  // Core single-envelopes the record: `{ data: MetadataRecord | null }`.
1243
1244
  // "No record yet" is `{ data: null }` (or a bare null body on older nodes),
1244
1245
  // so optional-chain to a clean null. Returns the full record (name + data +
1245
1246
  // updatedAt/updatedBy), not just the data map.
1246
- const response = await this.httpClient.get(`/admin-api/groups/${groupId}/metadata`);
1247
+ const response = await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/metadata`);
1247
1248
  return response?.data ?? null;
1248
1249
  }
1249
1250
  async setMemberMetadata(groupId, identity, request) {
1250
- await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/metadata`, request);
1251
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/members/${pathSegment(identity)}/metadata`, request);
1251
1252
  }
1252
1253
  /**
1253
1254
  * `identity` is the member's ACCOUNT (64 hex), as returned by
@@ -1256,25 +1257,25 @@ export class AdminApiClient {
1256
1257
  */
1257
1258
  async getMemberMetadata(groupId, identity) {
1258
1259
  // Single-enveloped record; see getGroupMetadata.
1259
- const response = await this.httpClient.get(`/admin-api/groups/${groupId}/members/${identity}/metadata`);
1260
+ const response = await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/members/${pathSegment(identity)}/metadata`);
1260
1261
  return response?.data ?? null;
1261
1262
  }
1262
1263
  async setContextMetadata(groupId, contextId, request) {
1263
- await this.httpClient.put(`/admin-api/groups/${groupId}/contexts/${contextId}/metadata`, request);
1264
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/contexts/${pathSegment(contextId)}/metadata`, request);
1264
1265
  }
1265
1266
  async getContextMetadata(groupId, contextId) {
1266
1267
  // Single-enveloped record; see getGroupMetadata.
1267
- const response = await this.httpClient.get(`/admin-api/groups/${groupId}/contexts/${contextId}/metadata`);
1268
+ const response = await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/contexts/${pathSegment(contextId)}/metadata`);
1268
1269
  return response?.data ?? null;
1269
1270
  }
1270
1271
  async syncGroup(groupId) {
1271
- return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/sync`, {}));
1272
+ return unwrap(await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/sync`, {}));
1272
1273
  }
1273
1274
  async upgradeGroup(groupId, request) {
1274
- return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/upgrade`, request));
1275
+ return unwrap(await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/upgrade`, request));
1275
1276
  }
1276
1277
  async getGroupUpgradeStatus(groupId) {
1277
- return unwrap(await this.httpClient.get(`/admin-api/groups/${groupId}/upgrade/status`));
1278
+ return unwrap(await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/upgrade/status`));
1278
1279
  }
1279
1280
  /**
1280
1281
  * The operator-facing "have all peers migrated?" rollup for a namespace.
@@ -1282,39 +1283,37 @@ export class AdminApiClient {
1282
1283
  * envelope to unwrap here (unlike most admin reads).
1283
1284
  */
1284
1285
  async getMigrationStatus(namespaceId) {
1285
- const id = encodeURIComponent(namespaceId);
1286
- return this.httpClient.get(`/admin-api/groups/${id}/migration-status`);
1286
+ return this.httpClient.get(`/admin-api/groups/${pathSegment(namespaceId)}/migration-status`);
1287
1287
  }
1288
1288
  /** Per-group cascade-migration snapshots for a namespace. */
1289
1289
  async getCascadeStatus(namespaceId) {
1290
- const id = encodeURIComponent(namespaceId);
1291
- return unwrap(await this.httpClient.get(`/admin-api/groups/${id}/cascade-status`));
1290
+ return unwrap(await this.httpClient.get(`/admin-api/groups/${pathSegment(namespaceId)}/cascade-status`));
1292
1291
  }
1293
1292
  async retryGroupUpgrade(groupId) {
1294
- return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/upgrade/retry`, {}));
1293
+ return unwrap(await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/upgrade/retry`, {}));
1295
1294
  }
1296
1295
  /** Move `childGroupId` under `request.newParentId`. */
1297
1296
  async reparentGroup(childGroupId, request) {
1298
1297
  // Core returns this flat ({ reparented }); tolerate the { data } envelope too.
1299
- const r = await this.httpClient.post(`/admin-api/groups/${childGroupId}/reparent`, request);
1298
+ const r = await this.httpClient.post(`/admin-api/groups/${pathSegment(childGroupId)}/reparent`, request);
1300
1299
  return (r?.data ?? r);
1301
1300
  }
1302
1301
  async listSubgroups(groupId) {
1303
- const response = await this.httpClient.get(`/admin-api/groups/${groupId}/subgroups`);
1302
+ const response = await this.httpClient.get(`/admin-api/groups/${pathSegment(groupId)}/subgroups`);
1304
1303
  return response.subgroups ?? response.data ?? [];
1305
1304
  }
1306
1305
  async detachContextFromGroup(groupId, contextId) {
1307
- await this.httpClient.post(`/admin-api/groups/${groupId}/contexts/${contextId}/remove`, {});
1306
+ await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/contexts/${pathSegment(contextId)}/remove`, {});
1308
1307
  }
1309
1308
  // ---- Group Invitation & Join ----
1310
1309
  async createGroupInvitation(groupId, request) {
1311
- return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/invite`, request ?? {}));
1310
+ return unwrap(await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/invite`, request ?? {}));
1312
1311
  }
1313
1312
  async joinGroup(request) {
1314
1313
  return unwrap(await this.httpClient.post('/admin-api/groups/join', request));
1315
1314
  }
1316
1315
  async joinSubgroupInheritance(groupId) {
1317
- return unwrap(await this.httpClient.post(`/admin-api/groups/${groupId}/join-via-inheritance`, {}));
1316
+ return unwrap(await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/join-via-inheritance`, {}));
1318
1317
  }
1319
1318
  // ---- TEE ----
1320
1319
  async getTeeInfo() {
@@ -1349,23 +1348,23 @@ export class AdminApiClient {
1349
1348
  }
1350
1349
  /** Leave a group (POST /admin-api/groups/:group_id/leave). */
1351
1350
  async leaveGroup(groupId) {
1352
- await this.httpClient.post(`/admin-api/groups/${groupId}/leave`, {});
1351
+ await this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/leave`, {});
1353
1352
  }
1354
1353
  /** Leave a context (POST /admin-api/contexts/:context_id/leave). */
1355
1354
  async leaveContext(contextId) {
1356
- await this.httpClient.post(`/admin-api/contexts/${contextId}/leave`, {});
1355
+ await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/leave`, {});
1357
1356
  }
1358
1357
  /** Leave a namespace (POST /admin-api/namespaces/:namespace_id/leave). */
1359
1358
  async leaveNamespace(namespaceId) {
1360
- await this.httpClient.post(`/admin-api/namespaces/${namespaceId}/leave`, {});
1359
+ await this.httpClient.post(`/admin-api/namespaces/${pathSegment(namespaceId)}/leave`, {});
1361
1360
  }
1362
1361
  /** Issue a group ownership proof (POST /admin-api/groups/:group_id/issue-ownership-proof). */
1363
1362
  async issueOwnershipProof(groupId, request) {
1364
- return this.httpClient.post(`/admin-api/groups/${groupId}/issue-ownership-proof`, request);
1363
+ return this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/issue-ownership-proof`, request);
1365
1364
  }
1366
1365
  /** Issue a namespace ownership proof (POST /admin-api/groups/:group_id/issue-namespace-ownership-proof). */
1367
1366
  async issueNamespaceOwnershipProof(groupId, request) {
1368
- return this.httpClient.post(`/admin-api/groups/${groupId}/issue-namespace-ownership-proof`, request);
1367
+ return this.httpClient.post(`/admin-api/groups/${pathSegment(groupId)}/issue-namespace-ownership-proof`, request);
1369
1368
  }
1370
1369
  /**
1371
1370
  * Set a member's auto-follow flag (PUT
@@ -1376,10 +1375,10 @@ export class AdminApiClient {
1376
1375
  * 64 hex, so nothing but the source tells them apart.
1377
1376
  */
1378
1377
  async setMemberAutoFollow(groupId, identity, request) {
1379
- await this.httpClient.put(`/admin-api/groups/${groupId}/members/${identity}/auto-follow`, request);
1378
+ await this.httpClient.put(`/admin-api/groups/${pathSegment(groupId)}/members/${pathSegment(identity)}/auto-follow`, request);
1380
1379
  }
1381
1380
  /** Abort a namespace migration (POST /admin-api/groups/:namespace_id/migration/abort). */
1382
1381
  async abortMigration(namespaceId) {
1383
- return this.httpClient.post(`/admin-api/groups/${namespaceId}/migration/abort`, {});
1382
+ return this.httpClient.post(`/admin-api/groups/${pathSegment(namespaceId)}/migration/abort`, {});
1384
1383
  }
1385
1384
  }