@calimero-network/mero-js 26.10.0 → 27.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.
Files changed (220) hide show
  1. package/README.md +73 -288
  2. package/dist/cloud-v2/attestation.d.ts +91 -0
  3. package/dist/cloud-v2/attestation.js +135 -0
  4. package/dist/cloud-v2/capabilities.d.ts +30 -0
  5. package/dist/cloud-v2/capabilities.js +31 -0
  6. package/dist/cloud-v2/client.d.ts +426 -0
  7. package/dist/cloud-v2/client.js +646 -0
  8. package/dist/cloud-v2/errors.d.ts +98 -0
  9. package/dist/cloud-v2/errors.js +165 -0
  10. package/dist/cloud-v2/index.d.ts +10 -0
  11. package/dist/cloud-v2/index.js +5 -0
  12. package/dist/cloud-v2/passkey.d.ts +27 -0
  13. package/dist/cloud-v2/passkey.js +73 -0
  14. package/dist/crypto/internal.d.ts +3 -37
  15. package/dist/crypto/internal.js +3 -72
  16. package/dist/index.browser.mjs +4 -2
  17. package/dist/index.browser.mjs.map +4 -4
  18. package/dist/index.cjs +1750 -12767
  19. package/dist/index.cjs.map +4 -4
  20. package/dist/index.d.ts +3 -56
  21. package/dist/index.js +14 -75
  22. package/dist/index.mjs +1750 -12767
  23. package/dist/index.mjs.map +4 -4
  24. package/dist/sealed/index.d.ts +4 -4
  25. package/dist/sealed/index.js +2 -2
  26. package/dist/sealed/release.d.ts +21 -76
  27. package/dist/sealed/release.js +24 -108
  28. package/dist/sealed/sealed.d.ts +8 -56
  29. package/dist/sealed/sealed.js +11 -89
  30. package/dist/sealed/verify.d.ts +7 -13
  31. package/dist/sealed/verify.js +3 -7
  32. package/package.json +8 -13
  33. package/dist/account/account-admin.d.ts +0 -80
  34. package/dist/account/account-admin.js +0 -346
  35. package/dist/account/account.d.ts +0 -196
  36. package/dist/account/account.js +0 -269
  37. package/dist/account/application-id.d.ts +0 -50
  38. package/dist/account/application-id.js +0 -83
  39. package/dist/account/bootstrap-from-invitation.d.ts +0 -110
  40. package/dist/account/bootstrap-from-invitation.js +0 -80
  41. package/dist/account/create-context.d.ts +0 -103
  42. package/dist/account/create-context.js +0 -267
  43. package/dist/account/govern.d.ts +0 -24
  44. package/dist/account/govern.js +0 -50
  45. package/dist/account/index.d.ts +0 -26
  46. package/dist/account/index.js +0 -15
  47. package/dist/account/join-as-account.d.ts +0 -23
  48. package/dist/account/join-as-account.js +0 -34
  49. package/dist/account/join-with-node.d.ts +0 -115
  50. package/dist/account/join-with-node.js +0 -161
  51. package/dist/account/node-admin.d.ts +0 -20
  52. package/dist/account/node-admin.js +0 -33
  53. package/dist/account/relay-from-invitation.d.ts +0 -137
  54. package/dist/account/relay-from-invitation.js +0 -180
  55. package/dist/account/relay-login-error.d.ts +0 -32
  56. package/dist/account/relay-login-error.js +0 -34
  57. package/dist/account/session.d.ts +0 -266
  58. package/dist/account/session.js +0 -915
  59. package/dist/account/wordlist.d.ts +0 -16
  60. package/dist/account/wordlist.js +0 -273
  61. package/dist/admin-api/admin-client.d.ts +0 -686
  62. package/dist/admin-api/admin-client.js +0 -1225
  63. package/dist/admin-api/admin-factory.d.ts +0 -14
  64. package/dist/admin-api/admin-factory.js +0 -22
  65. package/dist/admin-api/admin-types.d.ts +0 -2041
  66. package/dist/admin-api/admin-types.js +0 -12
  67. package/dist/admin-api/index.d.ts +0 -4
  68. package/dist/admin-api/index.js +0 -5
  69. package/dist/admin-api/redeem-invitation.d.ts +0 -101
  70. package/dist/admin-api/redeem-invitation.js +0 -200
  71. package/dist/auth/index.d.ts +0 -34
  72. package/dist/auth/index.js +0 -67
  73. package/dist/auth-api/auth-client.d.ts +0 -31
  74. package/dist/auth-api/auth-client.js +0 -117
  75. package/dist/auth-api/auth-factory.d.ts +0 -7
  76. package/dist/auth-api/auth-factory.js +0 -41
  77. package/dist/auth-api/auth-types.d.ts +0 -130
  78. package/dist/auth-api/auth-types.js +0 -2
  79. package/dist/auth-api/index.d.ts +0 -3
  80. package/dist/auth-api/index.js +0 -4
  81. package/dist/capabilities.d.ts +0 -84
  82. package/dist/capabilities.js +0 -117
  83. package/dist/cloud/account-ownership.d.ts +0 -63
  84. package/dist/cloud/account-ownership.js +0 -87
  85. package/dist/cloud/cloud-client.d.ts +0 -949
  86. package/dist/cloud/cloud-client.js +0 -1068
  87. package/dist/cloud/connect.d.ts +0 -213
  88. package/dist/cloud/connect.js +0 -260
  89. package/dist/cloud/enrol-redirect.d.ts +0 -181
  90. package/dist/cloud/enrol-redirect.js +0 -244
  91. package/dist/cloud/index.d.ts +0 -12
  92. package/dist/cloud/index.js +0 -10
  93. package/dist/cloud/link-redirect.d.ts +0 -95
  94. package/dist/cloud/link-redirect.js +0 -121
  95. package/dist/cloud/link-state.d.ts +0 -36
  96. package/dist/cloud/link-state.js +0 -104
  97. package/dist/cloud/routing-proof.d.ts +0 -113
  98. package/dist/cloud/routing-proof.js +0 -96
  99. package/dist/device-cert/device-cert.d.ts +0 -189
  100. package/dist/device-cert/device-cert.js +0 -239
  101. package/dist/device-cert/device-scope.d.ts +0 -58
  102. package/dist/device-cert/device-scope.js +0 -76
  103. package/dist/device-cert/index.d.ts +0 -4
  104. package/dist/device-cert/index.js +0 -3
  105. package/dist/ephemeral/codec.d.ts +0 -4
  106. package/dist/ephemeral/codec.js +0 -12
  107. package/dist/ephemeral/index.d.ts +0 -57
  108. package/dist/ephemeral/index.js +0 -101
  109. package/dist/ephemeral/types.d.ts +0 -27
  110. package/dist/ephemeral/types.js +0 -1
  111. package/dist/errors/classify.d.ts +0 -65
  112. package/dist/errors/classify.js +0 -117
  113. package/dist/errors/index.d.ts +0 -2
  114. package/dist/errors/index.js +0 -1
  115. package/dist/events/group.d.ts +0 -95
  116. package/dist/events/group.js +0 -10
  117. package/dist/events/index.d.ts +0 -5
  118. package/dist/events/index.js +0 -2
  119. package/dist/events/sse.d.ts +0 -127
  120. package/dist/events/sse.js +0 -469
  121. package/dist/events/ws.d.ts +0 -57
  122. package/dist/events/ws.js +0 -212
  123. package/dist/http-client/api-response.d.ts +0 -15
  124. package/dist/http-client/api-response.js +0 -1
  125. package/dist/http-client/http-factory.d.ts +0 -71
  126. package/dist/http-client/http-factory.js +0 -68
  127. package/dist/http-client/http-types.d.ts +0 -87
  128. package/dist/http-client/http-types.js +0 -1
  129. package/dist/http-client/index.d.ts +0 -7
  130. package/dist/http-client/index.js +0 -11
  131. package/dist/http-client/path-segment.d.ts +0 -1
  132. package/dist/http-client/path-segment.js +0 -8
  133. package/dist/http-client/retry.d.ts +0 -5
  134. package/dist/http-client/retry.js +0 -82
  135. package/dist/http-client/signal-utils.d.ts +0 -2
  136. package/dist/http-client/signal-utils.js +0 -41
  137. package/dist/http-client/web-client.d.ts +0 -80
  138. package/dist/http-client/web-client.js +0 -557
  139. package/dist/invitation/index.d.ts +0 -2
  140. package/dist/invitation/index.js +0 -2
  141. package/dist/invitation/invitation.d.ts +0 -106
  142. package/dist/invitation/invitation.js +0 -104
  143. package/dist/login/index.d.ts +0 -4
  144. package/dist/login/index.js +0 -3
  145. package/dist/login/login.d.ts +0 -111
  146. package/dist/login/login.js +0 -110
  147. package/dist/login/session.d.ts +0 -124
  148. package/dist/login/session.js +0 -141
  149. package/dist/mero-js.d.ts +0 -231
  150. package/dist/mero-js.js +0 -469
  151. package/dist/namespace-op/index.d.ts +0 -2
  152. package/dist/namespace-op/index.js +0 -3
  153. package/dist/namespace-op/namespace-op.d.ts +0 -150
  154. package/dist/namespace-op/namespace-op.js +0 -191
  155. package/dist/nodeDiscovery.d.ts +0 -47
  156. package/dist/nodeDiscovery.js +0 -101
  157. package/dist/owner-op/index.d.ts +0 -2
  158. package/dist/owner-op/index.js +0 -3
  159. package/dist/owner-op/owner-op.d.ts +0 -119
  160. package/dist/owner-op/owner-op.js +0 -214
  161. package/dist/presence/relay-presence.d.ts +0 -56
  162. package/dist/presence/relay-presence.js +0 -107
  163. package/dist/presence/statement.d.ts +0 -12
  164. package/dist/presence/statement.js +0 -17
  165. package/dist/relay/index.d.ts +0 -4
  166. package/dist/relay/index.js +0 -2
  167. package/dist/relay/nonce-source.d.ts +0 -72
  168. package/dist/relay/nonce-source.js +0 -111
  169. package/dist/relay/relay-client.d.ts +0 -472
  170. package/dist/relay/relay-client.js +0 -518
  171. package/dist/relay-attestation/attest-node-key.d.ts +0 -66
  172. package/dist/relay-attestation/attest-node-key.js +0 -110
  173. package/dist/relay-attestation/index.d.ts +0 -1
  174. package/dist/relay-attestation/index.js +0 -1
  175. package/dist/request/caller-proof.d.ts +0 -43
  176. package/dist/request/caller-proof.js +0 -36
  177. package/dist/request/index.d.ts +0 -3
  178. package/dist/request/index.js +0 -3
  179. package/dist/request/proof-signer.d.ts +0 -49
  180. package/dist/request/proof-signer.js +0 -59
  181. package/dist/request/request-sig.d.ts +0 -99
  182. package/dist/request/request-sig.js +0 -95
  183. package/dist/request-proof/authorizer.d.ts +0 -41
  184. package/dist/request-proof/authorizer.js +0 -60
  185. package/dist/request-proof/index.d.ts +0 -4
  186. package/dist/request-proof/index.js +0 -2
  187. package/dist/request-proof/request-proof.d.ts +0 -53
  188. package/dist/request-proof/request-proof.js +0 -95
  189. package/dist/rpc/index.d.ts +0 -64
  190. package/dist/rpc/index.js +0 -78
  191. package/dist/signer/index.d.ts +0 -2
  192. package/dist/signer/index.js +0 -3
  193. package/dist/signer/signer.d.ts +0 -92
  194. package/dist/signer/signer.js +0 -147
  195. package/dist/token-store/index.d.ts +0 -27
  196. package/dist/token-store/index.js +0 -62
  197. package/dist/transport/index.d.ts +0 -6
  198. package/dist/transport/index.js +0 -3
  199. package/dist/transport/mero-client.d.ts +0 -294
  200. package/dist/transport/mero-client.js +0 -386
  201. package/dist/transport/relay-observer.d.ts +0 -152
  202. package/dist/transport/relay-observer.js +0 -173
  203. package/dist/transport/relay-transport.d.ts +0 -73
  204. package/dist/transport/relay-transport.js +0 -94
  205. package/dist/transport/types.d.ts +0 -100
  206. package/dist/transport/types.js +0 -32
  207. package/dist/types/api-response.d.ts +0 -15
  208. package/dist/types/api-response.js +0 -1
  209. package/dist/types/index.d.ts +0 -1
  210. package/dist/types/index.js +0 -1
  211. package/dist/warrant/creation-warrant.d.ts +0 -163
  212. package/dist/warrant/creation-warrant.js +0 -194
  213. package/dist/warrant/governance-op.d.ts +0 -202
  214. package/dist/warrant/governance-op.js +0 -355
  215. package/dist/warrant/governance-warrant.d.ts +0 -124
  216. package/dist/warrant/governance-warrant.js +0 -164
  217. package/dist/warrant/index.d.ts +0 -8
  218. package/dist/warrant/index.js +0 -5
  219. package/dist/warrant/warrant.d.ts +0 -188
  220. package/dist/warrant/warrant.js +0 -202
@@ -1,191 +0,0 @@
1
- import { encodeGroupInvitation } from '../invitation/invitation.js';
2
- import { concat, fromHex, hex, u32le, u64le } from '../crypto/internal.js';
3
- import { resolveSigner } from '../signer/signer.js';
4
- /**
5
- * Core's `SIGNED_NAMESPACE_OP_SCHEMA_VERSION`. A node refuses any other value.
6
- *
7
- * 15: core went to 13 (TEE rows locked to the TEE roles, a TEE's relay role
8
- * read at its namespace root row, inherited read-only roles read-only in Open
9
- * subgroups), then 14 (`GroupOp::ContextRegisteredOnBehalf`) and 15
10
- * (`GroupOp::OnBehalf` / `RootOp::OnBehalf`) for delegated context creation and
11
- * governance through a relay. None of these changes a layout this module
12
- * signs; the version moves with core's so nodes on different versions never
13
- * share a namespace.
14
- *
15
- * 16: a namespace can be founded through a relay (a delegated
16
- * `NamespaceCreatedV2`), and `GroupOp::FoundingRelayAttested` lets that relay
17
- * admit itself as the namespace's first TEE. Again no layout this module signs.
18
- *
19
- * 17: `RootOp::GroupCreated` carries a `salt`, and its `group_id` must be the
20
- * one `createdSubgroupId(admin, parentId, restricted, salt)` derives
21
- * (calimero-network/core#4244), so two concurrent creates for one id can never
22
- * name different creators. The layout of that variant changed.
23
- *
24
- * 18: owner-level ops need the account ROOT, not only a device of it
25
- * (calimero-network/core, root-guarded owner ops). `GroupOp::RootGuarded` and
26
- * `RootOp::RootGuarded` are appended and carry a root-signed proof, and the bare
27
- * `TransferOwnership`, `AdminChanged`, `GroupDelete` and TEE policy ops are
28
- * refused. No layout this module signs changes; see `../owner-op` for the proof.
29
- *
30
- * 19 is reserved for calimero-network/core#4269.
31
- *
32
- * 20: no layout change. A delegated `GroupCreated` whose executor is a TEE at
33
- * the namespace root now seats that TEE in the new subgroup
34
- * (calimero-network/core#4276), an apply-time rule older peers disagree on.
35
- * Core signs and checks at 20, so every op this module signs must too.
36
- *
37
- * 21: no layout change. An op concurrent with its signer's removal is void
38
- * (calimero-network/core#4275), an apply-time rule older peers disagree on.
39
- * Core signs and checks at 21 from 0.11.0-rc.75. 23.4.0 and 23.4.1 still sign
40
- * at 20, so against rc.75 every namespace op an account signs with them (a
41
- * join, a create, any governance op) is refused "schema version mismatch:
42
- * expected 21, got 20".
43
- *
44
- * 22: `GroupOp::SharedWritersRotated` is appended, a `SharedStorage` cell's
45
- * writer-set step (calimero-network/core#4263), and a capability revoke voids
46
- * the member's concurrent ops that needed a removed bit
47
- * (calimero-network/core#4453). No layout this module signs changes.
48
- *
49
- * 23: a TEE admission op carries the quote it was admitted on and a TEE
50
- * authority evidence op the credential it was made for
51
- * (calimero-network/core#4265). Neither is an op this module signs, so only
52
- * the version byte moves. Core signs and checks at 23 from 0.11.0-rc.81, the
53
- * first release with both 22 and 23.
54
- *
55
- * 24: no layout change. Only a subgroup's creator may open it - flip it to
56
- * `Open` (calimero-network/core#4522) - an apply-time rule older peers
57
- * disagree on, since they let any of its admins open it. A UI that offers
58
- * "make public" should offer it to the creator alone.
59
- *
60
- * 25: no layout change; refused device link/unlink/descope ops are never logged.
61
- *
62
- * 26: no layout change. A device link's scope is judged against every
63
- * application the group may have targeted at the link's cut, not its live
64
- * target (calimero-network/core#4603), so replicas agree on a link that races
65
- * a target change; older peers judge it by fold order.
66
- *
67
- * 27: no layout change. The namespace founder is seated as an admin by the
68
- * genesis op itself, so a founder who transfers ownership stays a member
69
- * (calimero-network/core#4625); older peers seat her from the root's current
70
- * owner and drop her.
71
- */
72
- export const SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 27;
73
- /** Domain prefixed to the signable bytes; core's `NAMESPACE_GOVERNANCE_SIGN_DOMAIN`. */
74
- const NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode('calimero.namespace.v1');
75
- /** `NamespaceOp::Root` is the first variant. */
76
- const NAMESPACE_OP_ROOT = 0;
77
- /**
78
- * `RootOp` discriminants, in declaration order. Only the two join variants are
79
- * emitted here; the rest are listed so the numbering is checkable against core
80
- * rather than inferred from the two in use.
81
- */
82
- const ROOT_OP = {
83
- GroupCreated: 0,
84
- GroupReparented: 1,
85
- GroupDeleted: 2,
86
- AdminChanged: 3,
87
- PolicyUpdated: 4,
88
- MemberJoined: 5,
89
- KeyDelivery: 6,
90
- MemberJoinedOpen: 7,
91
- MemberJoinedAt: 8,
92
- NamespaceCreatedV2: 9,
93
- MemberJoinedViaTeeAttestation: 10,
94
- };
95
- /**
96
- * Borsh `Option<[u8; 32]>` from the byte array JSON carries it as.
97
- *
98
- * `[u8; 32]` crosses JSON as 32 numbers, not as hex — the hex spelling belongs to
99
- * `AccountId`, which has its own representation. Encoding one of these from a hex
100
- * string would silently produce the wrong 32 bytes.
101
- */
102
- function optionalBytes32(value, label) {
103
- if (value === null || value === undefined) {
104
- return new Uint8Array([0]);
105
- }
106
- if (value.length !== 32) {
107
- throw new Error(`${label} must be 32 bytes, got ${value.length}`);
108
- }
109
- return concat(new Uint8Array([1]), new Uint8Array(value));
110
- }
111
- /** Borsh `String`: u32 length then UTF-8 bytes. */
112
- function borshString(value) {
113
- const bytes = new TextEncoder().encode(value);
114
- return concat(u32le(bytes.length), bytes);
115
- }
116
- /**
117
- * Borsh-encode a `SignedGroupOpenInvitation`.
118
- *
119
- * Re-encoded rather than passed through, because it has to go inside the op that
120
- * gets signed. That makes this function version-locked to core: a field added to
121
- * the invitation and omitted here produces an op whose inner invitation no longer
122
- * matches the inviter's signature over it. That exact drift, in client-py, broke
123
- * 93 scenarios — the failure surfaces as `invalid invitation signature` and points
124
- * nowhere near the encoder.
125
- */
126
- export function encodeSignedInvitation(signed) {
127
- const body = signed.invitation;
128
- const admitterAddrs = signed.admitter_addrs ?? [];
129
- return concat(
130
- // GroupInvitationFromAdmin, from the one encoder the SDK's own invitation
131
- // signer uses: the bytes signed and the bytes carried must not drift.
132
- encodeGroupInvitation(body),
133
- // ...then the enclosing SignedGroupOpenInvitation, in declaration order.
134
- // `inviter_account` sits between the signature and the addresses; putting it
135
- // anywhere else still encodes 32 bytes and still verifies as nothing.
136
- borshString(signed.inviter_signature), signed.inviter_account
137
- ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, 'inviter_account', 32))
138
- : new Uint8Array([0]),
139
- // A `Vec<String>`, so each entry is a bare borsh string. This carried an
140
- // enum until core dropped the URL variant, and an enum writes a
141
- // discriminant byte ahead of each entry — encoding one here now would shift
142
- // every following byte and fail as `invalid invitation signature`, pointing
143
- // nowhere near this line.
144
- u32le(admitterAddrs.length), ...admitterAddrs.map(borshString), optionalBytes32(signed.application_id, 'application_id'),
145
- // Borsh order follows core's field order, where this is `bytecode_id`; the
146
- // JSON key is `app_key`, a rename covering both directions that core pins in
147
- // a test. Encoding by the Rust name would read `undefined` and emit a None
148
- // where the inviter signed a Some.
149
- optionalBytes32(signed.app_key, 'app_key'));
150
- }
151
- /**
152
- * Sign a `MemberJoined` (or `MemberJoinedAt`) namespace op and return it
153
- * borsh-encoded and hex — the `signedOp` that `admitJoin` takes.
154
- */
155
- export async function signMemberJoinOp(input) {
156
- const parents = input.parentOpHashes ?? [];
157
- const credential = fromHex(input.credential, 'credential', input.credential.length / 2);
158
- // An invitation that expires must be claimed with `MemberJoinedAt`, which
159
- // carries `joined_at` between the invitation and the credential. Choosing the
160
- // variant from the invitation keeps the two in step: the discriminant and the
161
- // presence of that field are one decision, and splitting them produces bytes
162
- // that decode into the wrong shape rather than failing to decode.
163
- const expires = BigInt(input.invitation.invitation.expiration_timestamp ?? 0) !== 0n;
164
- const joinedAt = input.joinedAt ?? BigInt(Math.floor(Date.now() / 1000));
165
- const rootOp = expires
166
- ? concat(new Uint8Array([ROOT_OP.MemberJoinedAt]), fromHex(input.member, 'member', 32), encodeSignedInvitation(input.invitation), u64le(joinedAt), credential)
167
- : concat(new Uint8Array([ROOT_OP.MemberJoined]), fromHex(input.member, 'member', 32), encodeSignedInvitation(input.invitation), credential);
168
- const op = concat(new Uint8Array([NAMESPACE_OP_ROOT]), rootOp);
169
- const signingKey = await resolveSigner(input.deviceSecret, input.signer, 'deviceSecret');
170
- // Named apart from the signer itself: this is the public half the op carries
171
- // as its `signer` field, which every peer compares with the credential's
172
- // `sign_pk` before applying the join.
173
- const signerPublicKey = fromHex(signingKey.publicKey, 'signer.publicKey', 32);
174
- const signable = concat(new Uint8Array([SIGNED_NAMESPACE_OP_SCHEMA_VERSION]), fromHex(input.namespaceId, 'namespaceId', 32), u32le(parents.length), ...parents.map((p, i) => fromHex(p, `parentOpHashes[${i}]`, 32)), signerPublicKey, u64le(input.nonce), op);
175
- const signature = await signingKey.sign(concat(NAMESPACE_SIGN_DOMAIN, signable));
176
- // The signed struct repeats the signable fields, then the signature, then the
177
- // admitter endorsement. The domain is a signing prefix only and is never part
178
- // of the encoded op.
179
- //
180
- // The endorsement is written as borsh `None` — a single `0x00` — and that is
181
- // the correct value from here, not a placeholder. It authorises the membership
182
- // and can only be signed by an account the invitation named as an admitter,
183
- // which a keyholder is not. The admitter attaches its own as it relays the op
184
- // through `admitJoin`.
185
- //
186
- // It sits outside `signable`, so it is outside this signature and outside the
187
- // op's id. That is what makes attaching it possible: the admitter changes
188
- // neither what was signed here nor which op this is.
189
- const unendorsed = new Uint8Array([0]);
190
- return hex(concat(signable, signature, unendorsed));
191
- }
@@ -1,47 +0,0 @@
1
- /**
2
- * Local-node discovery.
3
- *
4
- * Calimero dev/desktop nodes expose a public, unauthenticated health endpoint
5
- * at `GET {nodeUrl}/admin-api/health` that returns `{ "data": { "status":
6
- * "alive" } }`. The most common local layouts run on a small, well-known set of
7
- * ports, so instead of forcing the user to type a URL we probe those ports and
8
- * offer whatever is actually running.
9
- */
10
- /**
11
- * Default ports probed when discovering local nodes. Covers the two-node dev
12
- * stacks used across the Calimero apps (RPC + alt ports for node1 / node2).
13
- */
14
- export declare const DEFAULT_LOCAL_NODE_PORTS: readonly [2428, 2429, 2528, 2529];
15
- export interface DiscoverLocalNodesOptions {
16
- /** Ports to probe. Defaults to {@link DEFAULT_LOCAL_NODE_PORTS}. */
17
- ports?: readonly number[];
18
- /** Per-probe timeout in ms. Defaults to 2000. */
19
- timeoutMs?: number;
20
- /** Abort the whole discovery (e.g. when the modal closes). */
21
- signal?: AbortSignal;
22
- }
23
- /** Build the canonical base URL for a local node on the given port. */
24
- export declare function localNodeUrl(port: number): string;
25
- /**
26
- * Resolve an API `path` against a node `baseUrl`. Ensures the base ends with a
27
- * slash first, so a base that carries a path prefix (e.g. a `NODE_PATH_PREFIX`
28
- * deployment like `http://host/node1`) keeps that segment instead of having it
29
- * stripped by relative URL resolution.
30
- */
31
- export declare function nodeEndpoint(baseUrl: string, path: string): string;
32
- /**
33
- * Probe a single node's health endpoint. Resolves `true` only when the node
34
- * answers with a 2xx and (when the body is JSON) reports a non-dead status.
35
- * Any network error, timeout, or non-ok response resolves `false` — never
36
- * throws (except on an external abort, which is swallowed as `false`).
37
- */
38
- export declare function probeNodeHealth(baseUrl: string, options?: {
39
- timeoutMs?: number;
40
- signal?: AbortSignal;
41
- }): Promise<boolean>;
42
- /**
43
- * Probe the configured local ports in parallel and return the base URLs that
44
- * responded as healthy, in the same order as the `ports` argument (which
45
- * defaults to ascending). Returns an empty array when nothing local is running.
46
- */
47
- export declare function discoverLocalNodes(options?: DiscoverLocalNodesOptions): Promise<string[]>;
@@ -1,101 +0,0 @@
1
- /**
2
- * Local-node discovery.
3
- *
4
- * Calimero dev/desktop nodes expose a public, unauthenticated health endpoint
5
- * at `GET {nodeUrl}/admin-api/health` that returns `{ "data": { "status":
6
- * "alive" } }`. The most common local layouts run on a small, well-known set of
7
- * ports, so instead of forcing the user to type a URL we probe those ports and
8
- * offer whatever is actually running.
9
- */
10
- /**
11
- * Default ports probed when discovering local nodes. Covers the two-node dev
12
- * stacks used across the Calimero apps (RPC + alt ports for node1 / node2).
13
- */
14
- export const DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529];
15
- /** Host used to build local candidate URLs. */
16
- const LOCAL_HOST = 'localhost';
17
- /** Per-probe timeout. A reachable local node answers almost instantly; a
18
- * closed port rejects fast, but a firewalled/black-holed one can hang, so we
19
- * cap each probe. */
20
- const DEFAULT_PROBE_TIMEOUT_MS = 2000;
21
- /** Build the canonical base URL for a local node on the given port. */
22
- export function localNodeUrl(port) {
23
- return `http://${LOCAL_HOST}:${port}`;
24
- }
25
- /**
26
- * Resolve an API `path` against a node `baseUrl`. Ensures the base ends with a
27
- * slash first, so a base that carries a path prefix (e.g. a `NODE_PATH_PREFIX`
28
- * deployment like `http://host/node1`) keeps that segment instead of having it
29
- * stripped by relative URL resolution.
30
- */
31
- export function nodeEndpoint(baseUrl, path) {
32
- const base = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
33
- return new URL(path, base).toString();
34
- }
35
- /**
36
- * Probe a single node's health endpoint. Resolves `true` only when the node
37
- * answers with a 2xx and (when the body is JSON) reports a non-dead status.
38
- * Any network error, timeout, or non-ok response resolves `false` — never
39
- * throws (except on an external abort, which is swallowed as `false`).
40
- */
41
- export async function probeNodeHealth(baseUrl, options = {}) {
42
- const { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal } = options;
43
- // Already cancelled before we start — don't fetch, and don't register a
44
- // timer or listener that would then need cleanup.
45
- if (signal?.aborted)
46
- return false;
47
- // Per-probe timeout, also linked to the caller's abort signal so closing the
48
- // modal cancels every in-flight probe. Bind the signal to a local so the
49
- // cleanup below stays symmetric with registration without re-narrowing.
50
- const controller = new AbortController();
51
- const onAbort = () => controller.abort();
52
- const abortSignal = signal;
53
- if (abortSignal)
54
- abortSignal.addEventListener('abort', onAbort, { once: true });
55
- const timer = setTimeout(() => controller.abort(), timeoutMs);
56
- try {
57
- const url = nodeEndpoint(baseUrl, 'admin-api/health');
58
- const res = await fetch(url, {
59
- method: 'GET',
60
- signal: controller.signal,
61
- });
62
- if (!res.ok)
63
- return false;
64
- // Health body is `{ data: { status: "alive" } }`, but tolerate plain
65
- // `{ status }` and non-JSON 2xx responses. A *missing* status is treated as
66
- // alive (the 2xx is enough); a status that is present but not "alive"
67
- // (including an explicit `null`) is treated as unhealthy.
68
- try {
69
- const body = (await res.json());
70
- const status = body?.data?.status !== undefined ? body?.data?.status : body?.status;
71
- if (status === undefined)
72
- return true;
73
- return typeof status === 'string' && status.toLowerCase() === 'alive';
74
- }
75
- catch {
76
- return true;
77
- }
78
- }
79
- catch {
80
- return false;
81
- }
82
- finally {
83
- clearTimeout(timer);
84
- if (abortSignal)
85
- abortSignal.removeEventListener('abort', onAbort);
86
- }
87
- }
88
- /**
89
- * Probe the configured local ports in parallel and return the base URLs that
90
- * responded as healthy, in the same order as the `ports` argument (which
91
- * defaults to ascending). Returns an empty array when nothing local is running.
92
- */
93
- export async function discoverLocalNodes(options = {}) {
94
- const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;
95
- const results = await Promise.all(ports.map(async (port) => {
96
- const url = localNodeUrl(port);
97
- const ok = await probeNodeHealth(url, { timeoutMs, signal });
98
- return ok ? url : null;
99
- }));
100
- return results.filter((url) => url !== null);
101
- }
@@ -1,2 +0,0 @@
1
- export { OWNER_OP_KIND, transferOwnershipOp, groupDeleteOp, adminChangedOp, teeAuthoringPolicyOp, teeAdmissionPolicyOp, teeReleaseAdmissionPolicyOp, ownerOpDigest, ownerOpSigningPayload, signOwnerOpProof, rootGuardedOpBytes, } from './owner-op.js';
2
- export type { OwnerOp, OwnerOpKind, OwnerOpPlane, OwnerOpProofInput, TeeAdmissionPolicyOpInput, TeeReleaseAdmissionPolicyOpInput, } from './owner-op.js';
@@ -1,3 +0,0 @@
1
- // Root proofs for owner-level governance ops: what a nodeless or cold-root
2
- // account signs offline so a stolen device alone cannot take a group.
3
- export { OWNER_OP_KIND, transferOwnershipOp, groupDeleteOp, adminChangedOp, teeAuthoringPolicyOp, teeAdmissionPolicyOp, teeReleaseAdmissionPolicyOp, ownerOpDigest, ownerOpSigningPayload, signOwnerOpProof, rootGuardedOpBytes, } from './owner-op.js';
@@ -1,119 +0,0 @@
1
- /**
2
- * Which owner-level op a proof authorises. The value is the byte core signs,
3
- * its `OwnerOpKind` discriminant.
4
- */
5
- export declare const OWNER_OP_KIND: {
6
- readonly transferOwnership: 0;
7
- readonly adminChanged: 1;
8
- readonly groupDelete: 2;
9
- readonly teeAdmissionPolicy: 3;
10
- readonly teeAuthoringPolicy: 4;
11
- readonly teeReleaseAdmissionPolicy: 5;
12
- };
13
- export type OwnerOpKind = keyof typeof OWNER_OP_KIND;
14
- /** Which plane the op is on: a `GroupOp` on a group, or a `RootOp` on the namespace. */
15
- export type OwnerOpPlane = 'group' | 'root';
16
- /** An encoded owner-level op: its borsh bytes, its kind and its plane. */
17
- export interface OwnerOp {
18
- kind: OwnerOpKind;
19
- plane: OwnerOpPlane;
20
- /** The op's borsh bytes: exactly what the node builds, and what the digest covers. */
21
- bytes: Uint8Array;
22
- }
23
- /** Hand the group to `newOwner` (an account, hex), who must already be an admin. */
24
- export declare function transferOwnershipOp(newOwner: string): OwnerOp;
25
- /** The owner-only deletion of a group that holds no contexts. */
26
- export declare function groupDeleteOp(): OwnerOp;
27
- /** Repoint the namespace's admin pin at `newAdmin` (an account, hex). A root op. */
28
- export declare function adminChangedOp(newAdmin: string): OwnerOp;
29
- /** The TEE authoring policy `PUT`/`DELETE …/settings/tee-authoring-policy` publishes. */
30
- export declare function teeAuthoringPolicyOp(allowedMrtd: string[]): OwnerOp;
31
- /** A measurement-list admission policy, as the node publishes it (the V2 form). */
32
- export interface TeeAdmissionPolicyOpInput {
33
- allowedMrtd: string[];
34
- allowedRtmr0: string[];
35
- allowedRtmr1: string[];
36
- allowedRtmr2: string[];
37
- allowedRtmr3: string[];
38
- allowedTcbStatuses: string[];
39
- acceptMock: boolean;
40
- mode?: 'replica' | 'relay';
41
- }
42
- /**
43
- * The measurement-list admission policy `PUT …/settings/tee-admission-policy`
44
- * publishes. Pass the fields exactly as you send them: the node signs over the
45
- * op it builds from them, and any difference is a different op.
46
- */
47
- export declare function teeAdmissionPolicyOp(input: TeeAdmissionPolicyOpInput): OwnerOp;
48
- /** A signed-release admission policy, as the node publishes it (the V2 form). */
49
- export interface TeeReleaseAdmissionPolicyOpInput {
50
- allowedProfiles: string[];
51
- /**
52
- * The oldest release admitted. Give it in the node's normalised form
53
- * (`X.Y.Z`, no tag prefix): the node normalises what it is sent before it
54
- * builds the op, and the proof must be for the op it builds.
55
- */
56
- minReleaseVersion?: string;
57
- allowedTcbStatuses: string[];
58
- acceptMock: boolean;
59
- mode?: 'replica' | 'relay';
60
- }
61
- /** The signed-release admission policy `PUT …/settings/tee-admission-policy` publishes. */
62
- export declare function teeReleaseAdmissionPolicyOp(input: TeeReleaseAdmissionPolicyOpInput): OwnerOp;
63
- /** core's `OwnerOpAuthorization::op_digest`: the op's bytes, hashed under the body domain. */
64
- export declare function ownerOpDigest(opBytes: Uint8Array): Promise<Uint8Array>;
65
- /** What an owner-op proof binds, apart from the op and the key that signs it. */
66
- export interface OwnerOpProofInput {
67
- /** The account root's signing secret, 64 hex. Never sent anywhere. */
68
- rootSecret: string;
69
- /** The namespace the op is published in (`getGroupInfo(...).namespaceId`), hex. */
70
- namespaceId: string;
71
- /**
72
- * The group the op acts on, hex. For `adminChanged` and the TEE policies,
73
- * the namespace root.
74
- */
75
- groupId: string;
76
- /** The op, from one of the encoders here. */
77
- op: OwnerOp;
78
- /** The group's current guarded-op counter (`getGroupInfo(groupId).ownerOpCounter`). */
79
- counter: number | bigint;
80
- /**
81
- * The root epoch that signs, 0 for a root that has never been handed off.
82
- * A later epoch needs `chain`.
83
- */
84
- keyEpoch?: number;
85
- /**
86
- * The account's root-key handoffs, epoch 0 upward, each the hex borsh of a
87
- * `RootKeyHandoff` (account 32, from_epoch u32, new root key 32, signature
88
- * 64). It must reach at least `keyEpoch`, and at least the epoch the group
89
- * has recorded for the account, or the node refuses the proof.
90
- */
91
- chain?: string[];
92
- }
93
- /** core's `OwnerOpTerms::signing_payload`. */
94
- export declare function ownerOpSigningPayload(input: {
95
- account: string;
96
- namespaceId: string;
97
- groupId: string;
98
- kind: OwnerOpKind;
99
- opDigest: Uint8Array;
100
- counter: number | bigint;
101
- keyEpoch: number;
102
- }): Promise<Uint8Array>;
103
- /**
104
- * Sign a root proof for `op` and return it as core's `rootProof`: the hex
105
- * borsh of an `AccountProof<OwnerOpAuthorization>`.
106
- *
107
- * Layout: `AccountGenesis` (version u8 + root pk 32), the handoff chain (u32
108
- * count + 132 bytes each), then `OwnerOpAuthorization` (account 32, namespace
109
- * 32, group 32, kind u8, op digest 32, counter u64, key epoch u32, signature
110
- * 64).
111
- */
112
- export declare function signOwnerOpProof(input: OwnerOpProofInput): Promise<string>;
113
- /**
114
- * The `RootGuarded` wrapper core publishes: the op and its proof, as one
115
- * `GroupOp` or `RootOp`. A client never sends this to a node (the endpoints
116
- * take the proof and build the wrapper); it is here so the whole encoding is
117
- * checkable against core's vector.
118
- */
119
- export declare function rootGuardedOpBytes(op: OwnerOp, rootProof: string): Uint8Array;