@calimero-network/mero-js 25.3.3 → 26.0.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.
@@ -77,12 +77,9 @@ export declare function clearDelegatedCredential(): void;
77
77
  * replay a spent nonce and be refused. Keyed by relay and context because the
78
78
  * ledger the node keeps is per `(context, author device)`.
79
79
  *
80
- * This is the client-side half of core #4018. The node can answer "where does
81
- * my sequence stand" — `POST /contexts/{id}/warrant-nonce` with the caller's own
82
- * `authorProof` — but that route is mounted on the protected router, so a
83
- * delegated client on a relay cannot reach it. Until it moves, holding the
84
- * counter locally is the only option, and losing storage means burning refusals
85
- * until the counter catches up.
80
+ * No node serves a "where does my sequence stand" lookup (core #4018), so
81
+ * holding the counter locally is the only option, and losing storage means
82
+ * burning refusals until the counter catches up.
86
83
  */
87
84
  export declare function persistedNonces(relayUrl: string): {
88
85
  next: () => Promise<bigint>;
@@ -116,12 +116,9 @@ export function clearDelegatedCredential() {
116
116
  * replay a spent nonce and be refused. Keyed by relay and context because the
117
117
  * ledger the node keeps is per `(context, author device)`.
118
118
  *
119
- * This is the client-side half of core #4018. The node can answer "where does
120
- * my sequence stand" — `POST /contexts/{id}/warrant-nonce` with the caller's own
121
- * `authorProof` — but that route is mounted on the protected router, so a
122
- * delegated client on a relay cannot reach it. Until it moves, holding the
123
- * counter locally is the only option, and losing storage means burning refusals
124
- * until the counter catches up.
119
+ * No node serves a "where does my sequence stand" lookup (core #4018), so
120
+ * holding the counter locally is the only option, and losing storage means
121
+ * burning refusals until the counter catches up.
125
122
  */
126
123
  export function persistedNonces(relayUrl) {
127
124
  // ONE sequence per relay, not one per context. A client is rebuilt whenever
@@ -1,37 +1,6 @@
1
- import { HttpClient, HTTPError } from '../http-client/index.js';
2
- import type { HealthStatus, ReadinessStatus, 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, BlobReadOptions, CreateContextAliasRequest, CreateApplicationAliasRequest, CreateDeviceAliasRequest, CreateAliasResponseData, LookupAliasResponseData, DeleteAliasResponseData, ListAliasesResponseData, ListNamespacesResponseData, CreateNamespaceRequest, CreateNamespaceResponseData, DeleteNamespaceResponseData, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, JoinNamespaceRequest, JoinNamespaceResponseData, CreateGroupInNamespaceRequest, CreateGroupInNamespaceResponseData, SubgroupEntry, Namespace, NamespaceIdentity, NodeIdentity, AccountPairInitRequest, AccountPairInitResponseData, AccountPairCompleteRequest, AccountPairCompleteResponseData, AccountSignWithRootRequest, AccountSignWithRootResponseData, RelinkDeviceRequest, RelinkDeviceResponseData, RescopeDeviceRequest, RescopeDeviceResponseData, LabelDeviceRequest, LabelDeviceResponseData, AccountDeviceEntry, AccountApplicationEntry, RevokeAccountDeviceRequest, LinkAccountDeviceRequest, LinkAccountDeviceResponseData, RevokeAccountDeviceResponseData, MemberDevicesEntry, ListMemberDevicesOptions, GroupInfoResponseData, CreateGroupRequest, CreateGroupResponseData, DeleteGroupResponseData, ListGroupMembersResponseData, ListGroupContextsResponseData, AddGroupMembersRequest, RemoveGroupMembersRequest, UpdateMemberRoleRequest, MemberCapabilities, SetMemberCapabilitiesRequest, SetDefaultCapabilitiesRequest, SetMemberAutoFollowRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, GetTeeAdmissionPolicyResponseData, SetTeeAuthoringPolicyRequest, TransferOwnershipRequest, ChangeNamespaceAdminRequest, OwnerDeleteGroupRequest, RootGuardedOpRequest, SetGroupMetadataRequest, SetMemberMetadataRequest, SetContextMetadataRequest, MetadataRecord, SyncGroupResponseData, UpgradeGroupRequest, UpgradeGroupResponseData, GroupUpgradeStatusResponseData, MigrationStatus, NamespaceRevokedDevices, CascadeStatusEntry, RetryGroupUpgradeResponseData, ReparentGroupRequest, ReparentGroupResponseData, IssueOwnershipProofRequest, IssueNamespaceOwnershipProofRequest, IssueOwnershipProofResponseData, CreateGroupInvitationRequest, CreateGroupInvitationResponseData, CreateRecursiveGroupInvitationResponseData, JoinGroupRequest, JoinGroupResponseData, TeeInfoResponseData, TeeAttestRequest, TeeAttestResponseData, TeeVerifyQuoteRequest, TeeVerifyQuoteResponseData, PerformIntentRequest, PerformIntentResponseData, IntentRelayInfo, QueryContextRequest, QueryContextResponseData, ListMemberDevicesResponseData, SealToAccountRequest, SealedEnvelope, AdmitJoinRequest, AdmitJoinResponseData, WarrantNonceState } from './admin-types.js';
1
+ import { HttpClient } from '../http-client/index.js';
2
+ import type { HealthStatus, ReadinessStatus, AdminAuthStatus, InstallApplicationRequest, InstallApplicationResponseData, InstallDevApplicationRequest, UninstallApplicationResponseData, ListApplicationsResponseData, GetApplicationResponseData, ApplicationVersionEntry, GetApplicationAbiResponseData, GetLatestVersionResponseData, ListPackagesResponseData, ListVersionsResponseData, CreateContextRequest, CreateContextResponseData, DeleteContextResponseData, GetContextsResponseData, Context, GenerateContextIdentityResponseData, GetContextIdentitiesResponseData, JoinContextResponseData, JoinSubgroupInheritanceResponseData, ContextGroupResponseData, ContextStorageResponseData, UpdateContextApplicationRequest, ResyncContextRequest, ResyncContextResponseData, ContextsWithExecutorsResponseData, UploadBlobRequest, UploadBlobResponseData, DeleteBlobResponseData, ListBlobsResponseData, GetBlobInfoResponseData, BlobReadOptions, CreateContextAliasRequest, CreateApplicationAliasRequest, CreateDeviceAliasRequest, CreateAliasResponseData, LookupAliasResponseData, DeleteAliasResponseData, ListAliasesResponseData, ListNamespacesResponseData, CreateNamespaceRequest, CreateNamespaceResponseData, DeleteNamespaceResponseData, CreateNamespaceInvitationRequest, CreateNamespaceInvitationResponseData, CreateRecursiveInvitationResponseData, JoinNamespaceRequest, JoinNamespaceResponseData, CreateGroupInNamespaceRequest, CreateGroupInNamespaceResponseData, SubgroupEntry, Namespace, NodeIdentity, AccountPairInitRequest, AccountPairInitResponseData, AccountPairCompleteRequest, AccountPairCompleteResponseData, AccountSignWithRootRequest, AccountSignWithRootResponseData, RelinkDeviceRequest, RelinkDeviceResponseData, RescopeDeviceRequest, RescopeDeviceResponseData, LabelDeviceRequest, LabelDeviceResponseData, AccountDeviceEntry, AccountApplicationEntry, RevokeAccountDeviceRequest, LinkAccountDeviceRequest, LinkAccountDeviceResponseData, RevokeAccountDeviceResponseData, MemberDevicesEntry, ListMemberDevicesOptions, GroupInfoResponseData, CreateGroupRequest, CreateGroupResponseData, DeleteGroupResponseData, ListGroupMembersResponseData, ListGroupContextsResponseData, AddGroupMembersRequest, RemoveGroupMembersRequest, UpdateMemberRoleRequest, MemberCapabilities, SetMemberCapabilitiesRequest, SetDefaultCapabilitiesRequest, SetMemberAutoFollowRequest, SetSubgroupVisibilityRequest, SetTeeAdmissionPolicyRequest, GetTeeAdmissionPolicyResponseData, SetTeeAuthoringPolicyRequest, TransferOwnershipRequest, ChangeNamespaceAdminRequest, OwnerDeleteGroupRequest, RootGuardedOpRequest, SetGroupMetadataRequest, SetMemberMetadataRequest, SetContextMetadataRequest, MetadataRecord, SyncGroupResponseData, UpgradeGroupRequest, UpgradeGroupResponseData, GroupUpgradeStatusResponseData, MigrationStatus, NamespaceRevokedDevices, CascadeStatusEntry, RetryGroupUpgradeResponseData, ReparentGroupRequest, ReparentGroupResponseData, IssueOwnershipProofRequest, IssueNamespaceOwnershipProofRequest, IssueOwnershipProofResponseData, CreateGroupInvitationRequest, CreateGroupInvitationResponseData, CreateRecursiveGroupInvitationResponseData, JoinGroupRequest, JoinGroupResponseData, TeeInfoResponseData, TeeAttestRequest, TeeAttestResponseData, PerformIntentRequest, PerformIntentResponseData, IntentRelayInfo, QueryContextRequest, QueryContextResponseData, ListMemberDevicesResponseData, SealToAccountRequest, SealedEnvelope, AdmitJoinRequest, AdmitJoinResponseData } from './admin-types.js';
3
3
  import { type RedeemOutcome } from './redeem-invitation.js';
4
- /**
5
- * Thrown when a node answers the warrant-nonce route with a 404.
6
- *
7
- * Its own type because the meaning is unambiguous and not "not found": the
8
- * handler never 404s — an unknown device is a `200` with `seen: false`, a
9
- * malformed id is a `400` — so a 404 says the route is not mounted on this
10
- * node. It is new on core and absent from `master` builds. A caller that sees
11
- * this should fall back to its own counter (or refuse to write) rather than
12
- * retry, because no amount of retrying adds a route to a running node.
13
- */
14
- export declare class WarrantNonceRouteUnavailableError extends Error {
15
- /** The path that answered 404. */
16
- readonly path: string;
17
- /** The underlying HTTP failure, kept for logs. */
18
- readonly cause: HTTPError;
19
- name: string;
20
- constructor(
21
- /** The path that answered 404. */
22
- path: string,
23
- /** The underlying HTTP failure, kept for logs. */
24
- cause: HTTPError);
25
- }
26
- /**
27
- * Shape the node's answer into the union, which is where the exhausted case
28
- * stops being a missing field and starts being something the compiler asks
29
- * about.
30
- *
31
- * Exported for tests: it is the whole client-side contract of the route, and
32
- * testing it needs no transport.
33
- */
34
- export declare function parseWarrantNonce(body: string): WarrantNonceState;
35
4
  /**
36
5
  * Compare two version strings by SemVer 2.0 precedence, ascending: negative if
37
6
  * `a < b`, positive if `a > b`, `0` if equal. Build metadata (`+...`) is stripped
@@ -108,7 +77,6 @@ export declare class AdminApiClient {
108
77
  * context as stranded.
109
78
  */
110
79
  resyncContext(contextId: string, request?: ResyncContextRequest): Promise<ResyncContextResponseData>;
111
- inviteSpecializedNode(request: InviteSpecializedNodeRequest): Promise<InviteSpecializedNodeResponseData>;
112
80
  updateContextApplication(contextId: string, request: UpdateContextApplicationRequest): Promise<void>;
113
81
  getContextsWithExecutorsForApplication(applicationId: string): Promise<ContextsWithExecutorsResponseData>;
114
82
  uploadBlob(request: UploadBlobRequest): Promise<UploadBlobResponseData>;
@@ -169,26 +137,6 @@ export declare class AdminApiClient {
169
137
  * namespace.
170
138
  */
171
139
  getNodeIdentity(): Promise<NodeIdentity>;
172
- /**
173
- * @deprecated Use {@link getNodeIdentity} instead. Every field this returns is
174
- * node-level, so the namespace was only ever decoration — it now delegates to
175
- * the node-level route and reshapes the answer.
176
- *
177
- * Three consequences of that delegation, all visible to a caller who relied on
178
- * the old route's behaviour:
179
- *
180
- * - **No participation gate.** The namespace route answered 404 when this node
181
- * had never joined the namespace; this answers whatever the node's identity
182
- * is, regardless. If you were using it to ask "am I in this namespace?", ask
183
- * {@link listNamespaces} instead — that is the question you were really
184
- * asking.
185
- * - **`namespaceId` is echoed verbatim.** The old route resolved a subgroup id
186
- * to its root namespace and returned that; passing a subgroup id here gives
187
- * the subgroup id back.
188
- * - **404 means something else.** Previously "not my namespace", now "this node
189
- * holds no account root yet".
190
- */
191
- getNamespaceIdentity(namespaceId: string): Promise<NamespaceIdentity>;
192
140
  /**
193
141
  * Ask this node to run one method on a member's behalf, under a warrant that
194
142
  * member signed.
@@ -486,80 +434,6 @@ export declare class AdminApiClient {
486
434
  * same reason {@link listAccountDevices} unwraps `devices`.
487
435
  */
488
436
  listGroupMemberDevices(groupId: string, options?: ListMemberDevicesOptions): Promise<MemberDevicesEntry[]>;
489
- /**
490
- * Where `authorDeviceKey` stands in its warrant-nonce sequence in `contextId`.
491
- *
492
- * # What this is for
493
- *
494
- * The nonce is the one input to a warrant that is stateful on the *client*.
495
- * Everything else an author needs it either holds (its keys, the method, the
496
- * args) or can read from the relay ({@link RelayClient.describe} gives the
497
- * executor account and the grant). So an author that has lost its counter —
498
- * a browser keyholder in partitioned or periodically cleared storage, which
499
- * is its normal lifecycle rather than a fault — otherwise has exactly one
500
- * strategy: guess upward and burn a refused round trip per wrong guess, with
501
- * each refusal indistinguishable at the API from a genuinely spent nonce.
502
- *
503
- * Read {@link WarrantNonceOpen.nextNonce} and mint there. If you still hold
504
- * your own counter, mint at `max(ownNext, nextNonce)`: nonce state folds per
505
- * peer, so a node can only be BEHIND a client whose warrants it has not
506
- * applied — never ahead of the truth. An author spread across several relays
507
- * asks each and takes the highest answer. {@link createRecoveringNonceSource}
508
- * does all of that.
509
- *
510
- * Purely a read. It spends nothing and advances nothing, so it may be called
511
- * as often as you like.
512
- *
513
- * # Forward compatibility — this route is NEW
514
- *
515
- * It is not on core `master` yet, so a current node answers **404**, which
516
- * this method surfaces as {@link WarrantNonceRouteUnavailableError} rather
517
- * than as an opaque {@link HTTPError}. That distinction matters because the
518
- * handler itself never 404s: a device with no row is a `200` with
519
- * `seen: false`, and a malformed id is a `400`. So a 404 here means the node
520
- * does not serve the route at all — an older build, or a deployment that has
521
- * not re-mounted it — and the answer is to fall back to a local counter, not
522
- * to retry.
523
- *
524
- * # Authentication
525
- *
526
- * On the PROTECTED admin router, unlike the two delegated-execution routes it
527
- * sits beside: it takes another principal's device key as input and reports
528
- * that principal's activity. A `--public-intents` deployment does not serve
529
- * this anonymously, so an admin credential is required.
530
- *
531
- * @param authorDeviceKey the device's signing key, base58 (43-44 chars) or
532
- * hex (exactly 64). The node accepts either; the two never collide.
533
- */
534
- getWarrantNonce(contextId: string, authorDeviceKey: string): Promise<WarrantNonceState>;
535
- /**
536
- * The same answer, asked for the way a delegated client has to ask.
537
- *
538
- * {@link getWarrantNonce} is on the protected admin router, so a keyholder
539
- * writing through a relay — the client this whole facility exists for — is
540
- * refused it: measured `403` for a session carrying exactly
541
- * `context:intent`, `context:query`, `context:subscribe`. That client has no
542
- * admin credential and cannot be given one without defeating the point of the
543
- * delegated surface.
544
- *
545
- * What it does have is the credential proving the device is its own, which it
546
- * already sends on every write. Presenting it here makes the request
547
- * self-scoped: you learn a device's position only by proving, at call time,
548
- * that the device is yours. So there is no oracle to protect against, and no
549
- * reason for an admin gate.
550
- *
551
- * The device key is NOT a parameter. It is read from the verified
552
- * certificate server-side, which is the only reading that cannot disagree
553
- * with the signature — a key supplied alongside would be a second spelling of
554
- * the same fact, and two spellings can differ.
555
- *
556
- * Returns the identical shape {@link getWarrantNonce} returns, so a caller can
557
- * swap one for the other without touching what it does with the answer.
558
- *
559
- * @param authorProof hex-encoded borsh `AccountProof<DeviceCert>` — the same
560
- * value passed as `authorProof` to the relay client.
561
- */
562
- getWarrantNonceAsAuthor(contextId: string, authorProof: string): Promise<WarrantNonceState>;
563
437
  /**
564
438
  * Member accounts in the group and the devices bound to each. An admin node
565
439
  * sees every account; a plain member only its own. `403` if this node is not a
@@ -734,11 +608,6 @@ export declare class AdminApiClient {
734
608
  joinSubgroupInheritance(groupId: string): Promise<JoinSubgroupInheritanceResponseData>;
735
609
  getTeeInfo(): Promise<TeeInfoResponseData>;
736
610
  teeAttest(request: TeeAttestRequest): Promise<TeeAttestResponseData>;
737
- /**
738
- * @deprecated Nodes no longer serve `/admin-api/tee/verify-quote` (removed in
739
- * core#3262), so this fails. Verify quotes with `createQuoteVerifier`.
740
- */
741
- teeVerifyQuote(request: TeeVerifyQuoteRequest): Promise<TeeVerifyQuoteResponseData>;
742
611
  getPeersCount(): Promise<{
743
612
  count: number;
744
613
  }>;
@@ -1,92 +1,7 @@
1
- import { HTTPError, withRetry } from '../http-client/index.js';
1
+ import { withRetry } from '../http-client/index.js';
2
2
  import { pathSegment } from '../http-client/path-segment.js';
3
3
  import { CAPABILITIES, hasCap, withCap } from '../capabilities.js';
4
4
  import { redeemInvitation } from './redeem-invitation.js';
5
- /**
6
- * Thrown when a node answers the warrant-nonce route with a 404.
7
- *
8
- * Its own type because the meaning is unambiguous and not "not found": the
9
- * handler never 404s — an unknown device is a `200` with `seen: false`, a
10
- * malformed id is a `400` — so a 404 says the route is not mounted on this
11
- * node. It is new on core and absent from `master` builds. A caller that sees
12
- * this should fall back to its own counter (or refuse to write) rather than
13
- * retry, because no amount of retrying adds a route to a running node.
14
- */
15
- export class WarrantNonceRouteUnavailableError extends Error {
16
- constructor(
17
- /** The path that answered 404. */
18
- path,
19
- /** The underlying HTTP failure, kept for logs. */
20
- cause) {
21
- super(`this node does not serve warrant-nonce discovery (404 on ${path}); it predates the route, so a client must fall back to its own nonce counter`);
22
- this.path = path;
23
- this.cause = cause;
24
- this.name = 'WarrantNonceRouteUnavailableError';
25
- }
26
- }
27
- /**
28
- * Recover a `u64` from the response bytes rather than from a parsed `number`.
29
- *
30
- * `JSON.parse` has already rounded anything past 2^53 by the time a value is
31
- * handed over, and it rounds without complaint — so the digits are read back
32
- * out of the source text and turned straight into a `bigint`.
33
- *
34
- * Matching on the quoted key is safe for exactly this response: its only two
35
- * string fields are a context id and a device key, both of which are hex or
36
- * base58 and so cannot contain a quote, a colon, or these field names. The
37
- * parsed object still decides whether a field is *present*; the text is
38
- * consulted only for its digits.
39
- */
40
- function u64FromBody(body, parsed, field) {
41
- const value = parsed[field];
42
- if (value === undefined || value === null)
43
- return undefined;
44
- const digits = new RegExp(`"${field}"\\s*:\\s*(\\d+)`).exec(body);
45
- if (digits)
46
- return BigInt(digits[1]);
47
- // The field is present but not a bare integer literal in the body — a node
48
- // that started sending it as a string, say. Accept a decimal string, and
49
- // refuse anything else loudly instead of coercing a nonce into existence.
50
- if (typeof value === 'string' && /^\d+$/.test(value))
51
- return BigInt(value);
52
- throw new Error(`warrant-nonce response field \`${field}\` is not a u64: ${JSON.stringify(value)}`);
53
- }
54
- /**
55
- * Shape the node's answer into the union, which is where the exhausted case
56
- * stops being a missing field and starts being something the compiler asks
57
- * about.
58
- *
59
- * Exported for tests: it is the whole client-side contract of the route, and
60
- * testing it needs no transport.
61
- */
62
- export function parseWarrantNonce(body) {
63
- const parsed = JSON.parse(body);
64
- const data = parsed?.data;
65
- if (!data || typeof data !== 'object') {
66
- throw new Error(`warrant-nonce response had no \`data\`: ${body.slice(0, 200)}`);
67
- }
68
- const common = {
69
- contextId: String(data.contextId ?? ''),
70
- authorDeviceKey: String(data.authorDeviceKey ?? ''),
71
- seen: data.seen === true,
72
- highWaterNonce: u64FromBody(body, data, 'highWaterNonce'),
73
- // Not defaulted: a node that stopped sending it is a node whose window this
74
- // client would be guessing at, and the window is not a nonce input anyway.
75
- windowWidth: u64FromBody(body, data, 'windowWidth') ?? 0n,
76
- };
77
- const nextNonce = u64FromBody(body, data, 'nextNonce');
78
- if (nextNonce === undefined) {
79
- // The one absence with a meaning: `u64::MAX` is spent. The node omits the
80
- // field rather than wrapping to `0`, and a client must not fill the gap.
81
- return {
82
- ...common,
83
- kind: 'exhausted',
84
- seen: true,
85
- highWaterNonce: common.highWaterNonce ?? 0xffffffffffffffffn,
86
- };
87
- }
88
- return { ...common, kind: 'open', nextNonce };
89
- }
90
5
  /**
91
6
  * Helper: server wraps most responses in `{ data: T }`.
92
7
  * This extracts `.data` so callers get the inner payload directly. Null-safe so an
@@ -334,9 +249,6 @@ export class AdminApiClient {
334
249
  // callers always get a typed value instead of null.
335
250
  return r ?? { contextId, resyncStarted: true };
336
251
  }
337
- async inviteSpecializedNode(request) {
338
- return unwrap(await this.httpClient.post('/admin-api/contexts/invite-specialized-node', request));
339
- }
340
252
  async updateContextApplication(contextId, request) {
341
253
  await this.httpClient.post(`/admin-api/contexts/${pathSegment(contextId)}/application`, request);
342
254
  }
@@ -495,29 +407,6 @@ export class AdminApiClient {
495
407
  async getNodeIdentity() {
496
408
  return unwrap(await this.httpClient.get('/admin-api/identity'));
497
409
  }
498
- /**
499
- * @deprecated Use {@link getNodeIdentity} instead. Every field this returns is
500
- * node-level, so the namespace was only ever decoration — it now delegates to
501
- * the node-level route and reshapes the answer.
502
- *
503
- * Three consequences of that delegation, all visible to a caller who relied on
504
- * the old route's behaviour:
505
- *
506
- * - **No participation gate.** The namespace route answered 404 when this node
507
- * had never joined the namespace; this answers whatever the node's identity
508
- * is, regardless. If you were using it to ask "am I in this namespace?", ask
509
- * {@link listNamespaces} instead — that is the question you were really
510
- * asking.
511
- * - **`namespaceId` is echoed verbatim.** The old route resolved a subgroup id
512
- * to its root namespace and returned that; passing a subgroup id here gives
513
- * the subgroup id back.
514
- * - **404 means something else.** Previously "not my namespace", now "this node
515
- * holds no account root yet".
516
- */
517
- async getNamespaceIdentity(namespaceId) {
518
- const node = await this.getNodeIdentity();
519
- return { namespaceId, publicKey: node.publicKey, account: node.accountId };
520
- }
521
410
  /**
522
411
  * Ask this node to run one method on a member's behalf, under a warrant that
523
412
  * member signed.
@@ -924,113 +813,6 @@ export class AdminApiClient {
924
813
  const response = await this.httpClient.get(query ? `${base}?${query}` : base);
925
814
  return response.members;
926
815
  }
927
- /**
928
- * Where `authorDeviceKey` stands in its warrant-nonce sequence in `contextId`.
929
- *
930
- * # What this is for
931
- *
932
- * The nonce is the one input to a warrant that is stateful on the *client*.
933
- * Everything else an author needs it either holds (its keys, the method, the
934
- * args) or can read from the relay ({@link RelayClient.describe} gives the
935
- * executor account and the grant). So an author that has lost its counter —
936
- * a browser keyholder in partitioned or periodically cleared storage, which
937
- * is its normal lifecycle rather than a fault — otherwise has exactly one
938
- * strategy: guess upward and burn a refused round trip per wrong guess, with
939
- * each refusal indistinguishable at the API from a genuinely spent nonce.
940
- *
941
- * Read {@link WarrantNonceOpen.nextNonce} and mint there. If you still hold
942
- * your own counter, mint at `max(ownNext, nextNonce)`: nonce state folds per
943
- * peer, so a node can only be BEHIND a client whose warrants it has not
944
- * applied — never ahead of the truth. An author spread across several relays
945
- * asks each and takes the highest answer. {@link createRecoveringNonceSource}
946
- * does all of that.
947
- *
948
- * Purely a read. It spends nothing and advances nothing, so it may be called
949
- * as often as you like.
950
- *
951
- * # Forward compatibility — this route is NEW
952
- *
953
- * It is not on core `master` yet, so a current node answers **404**, which
954
- * this method surfaces as {@link WarrantNonceRouteUnavailableError} rather
955
- * than as an opaque {@link HTTPError}. That distinction matters because the
956
- * handler itself never 404s: a device with no row is a `200` with
957
- * `seen: false`, and a malformed id is a `400`. So a 404 here means the node
958
- * does not serve the route at all — an older build, or a deployment that has
959
- * not re-mounted it — and the answer is to fall back to a local counter, not
960
- * to retry.
961
- *
962
- * # Authentication
963
- *
964
- * On the PROTECTED admin router, unlike the two delegated-execution routes it
965
- * sits beside: it takes another principal's device key as input and reports
966
- * that principal's activity. A `--public-intents` deployment does not serve
967
- * this anonymously, so an admin credential is required.
968
- *
969
- * @param authorDeviceKey the device's signing key, base58 (43-44 chars) or
970
- * hex (exactly 64). The node accepts either; the two never collide.
971
- */
972
- async getWarrantNonce(contextId, authorDeviceKey) {
973
- const path = `/admin-api/contexts/${pathSegment(contextId)}/warrant-nonce/${pathSegment(authorDeviceKey)}`;
974
- // Read as TEXT, not JSON. `JSON.parse` would turn the `u64` nonces into
975
- // doubles before this code ever sees them, rounding anything past 2^53 into
976
- // a value that looks ordinary and is refused forever. The digits have to be
977
- // taken from the bytes.
978
- let raw;
979
- try {
980
- raw = await this.httpClient.get(path, { parse: 'text' });
981
- }
982
- catch (error) {
983
- if (error instanceof HTTPError && error.status === 404) {
984
- throw new WarrantNonceRouteUnavailableError(path, error);
985
- }
986
- throw error;
987
- }
988
- return parseWarrantNonce(raw);
989
- }
990
- /**
991
- * The same answer, asked for the way a delegated client has to ask.
992
- *
993
- * {@link getWarrantNonce} is on the protected admin router, so a keyholder
994
- * writing through a relay — the client this whole facility exists for — is
995
- * refused it: measured `403` for a session carrying exactly
996
- * `context:intent`, `context:query`, `context:subscribe`. That client has no
997
- * admin credential and cannot be given one without defeating the point of the
998
- * delegated surface.
999
- *
1000
- * What it does have is the credential proving the device is its own, which it
1001
- * already sends on every write. Presenting it here makes the request
1002
- * self-scoped: you learn a device's position only by proving, at call time,
1003
- * that the device is yours. So there is no oracle to protect against, and no
1004
- * reason for an admin gate.
1005
- *
1006
- * The device key is NOT a parameter. It is read from the verified
1007
- * certificate server-side, which is the only reading that cannot disagree
1008
- * with the signature — a key supplied alongside would be a second spelling of
1009
- * the same fact, and two spellings can differ.
1010
- *
1011
- * Returns the identical shape {@link getWarrantNonce} returns, so a caller can
1012
- * swap one for the other without touching what it does with the answer.
1013
- *
1014
- * @param authorProof hex-encoded borsh `AccountProof<DeviceCert>` — the same
1015
- * value passed as `authorProof` to the relay client.
1016
- */
1017
- async getWarrantNonceAsAuthor(contextId, authorProof) {
1018
- const path = `/admin-api/contexts/${pathSegment(contextId)}/warrant-nonce`;
1019
- // Text, not JSON, for the reason given in `getWarrantNonce`: `JSON.parse`
1020
- // rounds a u64 past 2^53 into a nonce that looks ordinary and is refused
1021
- // for ever.
1022
- let raw;
1023
- try {
1024
- raw = await this.httpClient.post(path, { authorProof }, { parse: 'text' });
1025
- }
1026
- catch (error) {
1027
- if (error instanceof HTTPError && error.status === 404) {
1028
- throw new WarrantNonceRouteUnavailableError(path, error);
1029
- }
1030
- throw error;
1031
- }
1032
- return parseWarrantNonce(raw);
1033
- }
1034
816
  /**
1035
817
  * Member accounts in the group and the devices bound to each. An admin node
1036
818
  * sees every account; a plain member only its own. `403` if this node is not a
@@ -1326,13 +1108,6 @@ export class AdminApiClient {
1326
1108
  async teeAttest(request) {
1327
1109
  return unwrap(await this.httpClient.post('/admin-api/tee/attest', request));
1328
1110
  }
1329
- /**
1330
- * @deprecated Nodes no longer serve `/admin-api/tee/verify-quote` (removed in
1331
- * core#3262), so this fails. Verify quotes with `createQuoteVerifier`.
1332
- */
1333
- async teeVerifyQuote(request) {
1334
- return unwrap(await this.httpClient.post('/admin-api/tee/verify-quote', request));
1335
- }
1336
1111
  // ---- Network ----
1337
1112
  async getPeersCount() {
1338
1113
  return this.httpClient.get('/admin-api/peers');
@@ -164,13 +164,6 @@ export interface ContextStorageResponseData {
164
164
  sizeInBytes: number;
165
165
  }
166
166
  export type SyncContextResponseData = null;
167
- export interface InviteSpecializedNodeRequest {
168
- contextId: string;
169
- inviterId?: string;
170
- }
171
- export interface InviteSpecializedNodeResponseData {
172
- nonce: string;
173
- }
174
167
  export interface UpdateContextApplicationRequest {
175
168
  applicationId: string;
176
169
  executorPublicKey: string;
@@ -617,23 +610,6 @@ export interface RevokedFromEntry {
617
610
  /** The device that was withdrawn, 64 hex characters. */
618
611
  deviceId: string;
619
612
  }
620
- /**
621
- * @deprecated Use {@link AdminApiClient.getNodeIdentity} instead. Nothing here
622
- * varies by namespace, so the parameter could only ever be decoration.
623
- */
624
- export interface NamespaceIdentity {
625
- /** Echoed back from the argument; it does not describe the identity. */
626
- namespaceId: string;
627
- /** The key this node signs with, 64 hex. */
628
- publicKey: string;
629
- /**
630
- * The account this node writes as, 64 hex characters. This — not
631
- * `publicKey` — is what member-addressing endpoints take, and what
632
- * `listGroupMembers` entries are keyed by, so it is how a caller locates
633
- * itself in a member list.
634
- */
635
- account: string;
636
- }
637
613
  export interface CreateNamespaceRequest {
638
614
  applicationId: string;
639
615
  name?: string;
@@ -1889,23 +1865,6 @@ export interface TeeAttestResponseData {
1889
1865
  */
1890
1866
  collateral?: DcapCollateral;
1891
1867
  }
1892
- /**
1893
- * @deprecated Nodes no longer serve `/admin-api/tee/verify-quote` (removed in
1894
- * core#3262), so a request for it fails. Verify quotes with
1895
- * `createQuoteVerifier`.
1896
- */
1897
- export interface TeeVerifyQuoteRequest {
1898
- quoteB64: string;
1899
- nonce: string;
1900
- expectedApplicationHash?: string;
1901
- }
1902
- /** @deprecated See {@link TeeVerifyQuoteRequest}. */
1903
- export interface TeeVerifyQuoteResponseData {
1904
- quoteVerified: boolean;
1905
- nonceVerified: boolean;
1906
- applicationHashVerified?: boolean;
1907
- quote: Quote;
1908
- }
1909
1868
  export interface AdminApiClientConfig {
1910
1869
  baseUrl: string;
1911
1870
  getAuthToken?: () => Promise<string | undefined>;
@@ -1936,108 +1895,3 @@ export interface AdmitJoinResponseData {
1936
1895
  */
1937
1896
  readonly published: boolean;
1938
1897
  }
1939
- /**
1940
- * Where one author device stands in its warrant-nonce sequence on one node.
1941
- *
1942
- * # Why `bigint` and not `number`
1943
- *
1944
- * A nonce is a `u64` on the node. `JSON.parse` turns every number into an IEEE
1945
- * double, so any value past 2^53 arrives already rounded - and it rounds
1946
- * silently, producing a nonce that looks ordinary and is refused forever. The
1947
- * exhaustion rule this endpoint exists to report (`u64::MAX` spent -> no next
1948
- * nonce) lives precisely in the range a `number` cannot hold, so representing it
1949
- * as one would lose the very case the type is meant to make visible.
1950
- *
1951
- * `bigint` over a decimal `string` because callers do arithmetic with these:
1952
- * the documented recovery rule is `max(ownNext, nextNonce)`, and
1953
- * {@link NonceSource} already emits `bigint`. A string would make every caller
1954
- * convert first, and the ones that forget would compare `"10" < "9"`.
1955
- *
1956
- * The digits are recovered from the raw response text rather than from a parsed
1957
- * `number`, so nothing is routed through a double on the way in.
1958
- *
1959
- * # Why a union on `kind`
1960
- *
1961
- * `nextNonce` is absent in exactly one case, and a client that reads it as
1962
- * `undefined` and falls back to a guess burns nonces for real. Splitting the two
1963
- * cases makes the compiler ask which one this is before `nextNonce` can be read
1964
- * at all.
1965
- *
1966
- * The discriminant is a string rather than an `exhausted: boolean` because this
1967
- * package compiles with `strictNullChecks` off, and TypeScript declines to
1968
- * narrow a union on a boolean-literal discriminant in that mode. A flag that
1969
- * silently fails to narrow would be worse than no flag: it would read as a
1970
- * guard and admit `nextNonce` on both arms.
1971
- */
1972
- export type WarrantNonceState = WarrantNonceOpen | WarrantNonceExhausted;
1973
- /** Fields both arms carry, whatever the sequence's state. */
1974
- interface WarrantNonceCommon {
1975
- /** The context asked about, echoed - read it to reject a cached answer. */
1976
- readonly contextId: string;
1977
- /**
1978
- * The author device asked about, echoed. This is the device's SIGNING KEY,
1979
- * not its `deviceId` and not the account: two devices of one account hold two
1980
- * independent sequences, and a re-keyed device starts a fresh one.
1981
- *
1982
- * Echoed as the node spelled it, which is the spelling that was asked for -
1983
- * the route accepts base58 or hex and does not normalise between them.
1984
- */
1985
- readonly authorDeviceKey: string;
1986
- /**
1987
- * Whether this node has admitted any warrant from this device here.
1988
- *
1989
- * `false` is the ordinary state of a device that has not written yet - a fresh
1990
- * sequence, not an error and not a row worth retrying for.
1991
- */
1992
- readonly seen: boolean;
1993
- /**
1994
- * The highest nonce this node has accepted from this device here, absent when
1995
- * `seen` is `false`.
1996
- *
1997
- * Reported for auditability. Do NOT compute a nonce from it: the `+ 1` is the
1998
- * node's arithmetic, already done in {@link WarrantNonceOpen.nextNonce}, and
1999
- * doing it again here is how a client reintroduces the overflow this endpoint
2000
- * avoids.
2001
- */
2002
- readonly highWaterNonce?: bigint;
2003
- /**
2004
- * How far below `highWaterNonce` a late warrant may still be accepted.
2005
- *
2006
- * Constant (64 today), and useful for sizing an in-flight window: a warrant
2007
- * minted but not yet executed is refused once this many later ones have landed
2008
- * ahead of it. It is NOT an input to a nonce - which parts of the window below
2009
- * the mark are already spent is deliberately not reported.
2010
- */
2011
- readonly windowWidth: bigint;
2012
- }
2013
- /** The sequence has room: {@link nextNonce} is the number to mint at. */
2014
- export interface WarrantNonceOpen extends WarrantNonceCommon {
2015
- readonly kind: 'open';
2016
- /**
2017
- * The smallest nonce this node is guaranteed to accept. **The only actionable
2018
- * value here.**
2019
- *
2020
- * `0` on a fresh sequence (`seen: false`), which is a real answer, not a
2021
- * missing one.
2022
- *
2023
- * A client that still holds its own counter must mint at
2024
- * `max(ownNext, nextNonce)`, never at `nextNonce` alone: nonce state folds per
2025
- * peer, so this node can be BEHIND a client whose warrants it has not applied
2026
- * yet, and never ahead of the truth. An author spread across relays asks each
2027
- * and takes the highest answer.
2028
- */
2029
- readonly nextNonce: bigint;
2030
- }
2031
- /**
2032
- * `u64::MAX` is spent here: there is no next nonce and this device cannot write
2033
- * to this context again. It must re-key - a new signing key starts a fresh
2034
- * sequence.
2035
- *
2036
- * The node reports this by omitting `nextNonce` rather than by wrapping to `0`,
2037
- * because a wrapped `0` would look like a valid answer and be refused forever.
2038
- */
2039
- export interface WarrantNonceExhausted extends WarrantNonceCommon {
2040
- readonly kind: 'exhausted';
2041
- readonly seen: true;
2042
- readonly highWaterNonce: bigint;
2043
- }