@calimero-network/mero-js 26.11.0 → 27.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 -12772
  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 -12772
  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 -688
  62. package/dist/admin-api/admin-client.js +0 -1230
  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 -2046
  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,163 +0,0 @@
1
- /**
2
- * Mint a creation warrant: the author's consent for one relay to create one
3
- * context in one group, once.
4
- *
5
- * The intent warrant in `warrant.ts` lets an account with no node *write* to a
6
- * context; this lets it *create* one. The relay executes the warrant and
7
- * publishes `GroupOp::ContextRegisteredOnBehalf` carrying it, and every peer
8
- * checks the **author's** `CAN_CREATE_CONTEXT` (or admin) — the relay needs no
9
- * create rights of its own, only standing to act for members. The app's `init`
10
- * runs as the author's account.
11
- *
12
- * Same primitives and the same two-widths trap as `warrant.ts`: counts **inside
13
- * the encoding** are borsh `u32`, counts the **signing preimage** hashes are
14
- * `u64`. The two `Option<String>` labels add a third shape: on the wire an
15
- * option is a one-byte tag followed (when present) by a `u32`-prefixed string,
16
- * while the preimage hashes the tag and the bytes as two separate parts, the
17
- * bytes empty when absent. That is what keeps `None` and `Some("")` distinct in
18
- * both.
19
- *
20
- * **The byte contract is pinned in core**, at
21
- * `crates/account/src/tests/creation_wire_fixture.rs`, and this module's test
22
- * asserts the same vectors. A drift would surface at a relay as a 403.
23
- */
24
- import { type Signer } from '../signer/signer.js';
25
- /** What a creation warrant authorises. */
26
- export interface CreationWarrantInput {
27
- /** The group the context is created in, hex (32 bytes). */
28
- group: string;
29
- /**
30
- * The seed the node derives the new context's id from, hex (32 bytes).
31
- *
32
- * Optional: when absent, 32 random bytes are drawn and returned alongside the
33
- * warrant. Pass one only to make the id predictable — reusing a seed asks for
34
- * a context that already exists.
35
- */
36
- seed?: string;
37
- /** The author's account, hex — whose consent this is, and who runs `init`. */
38
- authorAccount: string;
39
- /** The relay's account, hex: the subject its authorship grant is held by. */
40
- executor: string;
41
- /** The one signing key of `executor` that may carry it out, hex: discovery's `executorKey`. */
42
- executorKey: string;
43
- /** The application the context is created with, hex (32 bytes). */
44
- applicationId: string;
45
- /**
46
- * Which service of a multi-service bundle, or absent for the default.
47
- *
48
- * Absent and `""` are different values and sign differently. At most 256
49
- * UTF-8 bytes.
50
- */
51
- serviceName?: string;
52
- /** A display name for the context, or absent. At most 256 UTF-8 bytes. */
53
- name?: string;
54
- /**
55
- * The JSON the app's `init()` will receive.
56
- *
57
- * Committed to rather than carried: the relay is sent the same value
58
- * separately and the node checks it hashes to what was signed, so pass the
59
- * exact value you will send. See {@link creationInitHash}.
60
- */
61
- initArgs: unknown;
62
- /**
63
- * Monotonic per author **device**. Spent in the *new* context's warrant
64
- * ledger, so the same per-device nonce source `RelayClient` uses is correct.
65
- */
66
- nonce: number | bigint;
67
- /** Unix seconds after which the relay must refuse it. */
68
- notAfter: number | bigint;
69
- /** Account-log heads the author saw, each hex (32 bytes). At most 64. */
70
- accountHeads?: string[];
71
- /**
72
- * Governance heads the author's view descended from, each hex (32 bytes). At
73
- * most 64. The same caveat as the intent warrant's floor applies: one the
74
- * relay supplied is one the relay chose.
75
- */
76
- governanceFloor?: string[];
77
- /**
78
- * The author device's ed25519 signing secret, hex (32 bytes). Never sent.
79
- *
80
- * Mutually exclusive with {@link CreationWarrantInput.signer}: exactly one is required.
81
- * Prefer `signer` in a browser, since a secret held as a string is readable
82
- * by anything on the origin.
83
- */
84
- deviceSecret?: string;
85
- /**
86
- * The author device's signer, in place of {@link CreationWarrantInput.deviceSecret}: for a
87
- * key that cannot be exported to hex (a non-extractable WebCrypto key, a
88
- * passkey, a hardware or remote signer). Its `publicKey` becomes the
89
- * warrant's `author_device_key`, and it signs the 32-byte preimage as is.
90
- */
91
- signer?: Signer;
92
- }
93
- /** A signed creation warrant and the seed it commits to. */
94
- export interface SignedCreationWarrant {
95
- /** Hex borsh `ContextCreationWarrant`, ready for the relay. */
96
- warrant: string;
97
- /** The seed, hex — the one passed in, or the one drawn when none was. */
98
- seed: string;
99
- }
100
- /** A creation warrant's fields, decoded from the wire encoding. */
101
- export interface CreationWarrantFields {
102
- group: string;
103
- seed: string;
104
- authorAccount: string;
105
- /** The author device key: the signer's public key. */
106
- deviceKey: string;
107
- executor: string;
108
- executorKey: string;
109
- applicationId: string;
110
- /** `null` when absent — distinct from `""`. */
111
- serviceName: string | null;
112
- /** `null` when absent — distinct from `""`. */
113
- name: string | null;
114
- initHash: string;
115
- accountHeads: string[];
116
- governanceFloor: string[];
117
- nonce: bigint;
118
- notAfter: bigint;
119
- signature: string;
120
- }
121
- /**
122
- * The commitment a creation warrant carries in place of the init arguments.
123
- *
124
- * Hashes `JSON.stringify(initArgs)`, the same bytes `RelayClient.createContext`
125
- * sends, under its own domain.
126
- */
127
- export declare function creationInitHash(initArgs: unknown): Promise<Uint8Array>;
128
- /** The already-decoded fields the signature covers. Internal. */
129
- export interface CreationPreimageParts {
130
- group: Uint8Array;
131
- seed: Uint8Array;
132
- authorAccount: Uint8Array;
133
- deviceKey: Uint8Array;
134
- executor: Uint8Array;
135
- executorKey: Uint8Array;
136
- applicationId: Uint8Array;
137
- serviceName: Uint8Array | null;
138
- name: Uint8Array | null;
139
- initHash: Uint8Array;
140
- accountHeads: Uint8Array[];
141
- governanceFloor: Uint8Array[];
142
- nonce: number | bigint;
143
- notAfter: number | bigint;
144
- }
145
- /**
146
- * The bytes the device key signs. Exported for the conformance test only — not
147
- * from the package root.
148
- */
149
- export declare function creationWarrantPreimage(p: CreationPreimageParts): Promise<Uint8Array>;
150
- /**
151
- * Sign a creation warrant and return it hex-encoded, with its seed.
152
- *
153
- * Returns the encoding rather than an object for the reason `signWarrant`
154
- * does: the signature covers exactly these bytes.
155
- */
156
- export declare function signCreationWarrant(input: CreationWarrantInput): Promise<SignedCreationWarrant>;
157
- /**
158
- * Decode a hex creation warrant back into its fields.
159
- *
160
- * Refuses truncated or trailing bytes rather than reading a neighbouring field.
161
- * Does not verify the signature.
162
- */
163
- export declare function parseCreationWarrant(warrant: string): CreationWarrantFields;
@@ -1,194 +0,0 @@
1
- /**
2
- * Mint a creation warrant: the author's consent for one relay to create one
3
- * context in one group, once.
4
- *
5
- * The intent warrant in `warrant.ts` lets an account with no node *write* to a
6
- * context; this lets it *create* one. The relay executes the warrant and
7
- * publishes `GroupOp::ContextRegisteredOnBehalf` carrying it, and every peer
8
- * checks the **author's** `CAN_CREATE_CONTEXT` (or admin) — the relay needs no
9
- * create rights of its own, only standing to act for members. The app's `init`
10
- * runs as the author's account.
11
- *
12
- * Same primitives and the same two-widths trap as `warrant.ts`: counts **inside
13
- * the encoding** are borsh `u32`, counts the **signing preimage** hashes are
14
- * `u64`. The two `Option<String>` labels add a third shape: on the wire an
15
- * option is a one-byte tag followed (when present) by a `u32`-prefixed string,
16
- * while the preimage hashes the tag and the bytes as two separate parts, the
17
- * bytes empty when absent. That is what keeps `None` and `Some("")` distinct in
18
- * both.
19
- *
20
- * **The byte contract is pinned in core**, at
21
- * `crates/account/src/tests/creation_wire_fixture.rs`, and this module's test
22
- * asserts the same vectors. A drift would surface at a relay as a 403.
23
- */
24
- import { concat, domainHash, fromHex, hex, u32le, u64le } from '../crypto/internal.js';
25
- import { resolveSigner } from '../signer/signer.js';
26
- import { checkedSignature, citedHeads } from './warrant.js';
27
- const SIGN_DOMAIN = new TextEncoder().encode('calimero.context-creation-warrant.v1');
28
- const INIT_DOMAIN = new TextEncoder().encode('calimero.context-creation.init.v1');
29
- /** core's cap on `service_name` and `name`, in UTF-8 bytes. */
30
- const MAX_LABEL_BYTES = 256;
31
- /**
32
- * The commitment a creation warrant carries in place of the init arguments.
33
- *
34
- * Hashes `JSON.stringify(initArgs)`, the same bytes `RelayClient.createContext`
35
- * sends, under its own domain.
36
- */
37
- export async function creationInitHash(initArgs) {
38
- const bytes = new TextEncoder().encode(JSON.stringify(initArgs));
39
- return domainHash(INIT_DOMAIN, [bytes]);
40
- }
41
- /**
42
- * The bytes the device key signs. Exported for the conformance test only — not
43
- * from the package root.
44
- */
45
- export async function creationWarrantPreimage(p) {
46
- // An option is two parts here — its tag, then its bytes (empty when absent) —
47
- // so `None` and `Some("")` hash differently. u64 counts HERE; u32 on the wire.
48
- return domainHash(SIGN_DOMAIN, [
49
- p.group,
50
- p.seed,
51
- p.authorAccount,
52
- p.deviceKey,
53
- p.executor,
54
- p.executorKey,
55
- p.applicationId,
56
- new Uint8Array([p.serviceName === null ? 0 : 1]),
57
- p.serviceName ?? new Uint8Array(0),
58
- new Uint8Array([p.name === null ? 0 : 1]),
59
- p.name ?? new Uint8Array(0),
60
- p.initHash,
61
- u64le(p.accountHeads.length),
62
- ...p.accountHeads,
63
- u64le(p.governanceFloor.length),
64
- ...p.governanceFloor,
65
- u64le(p.nonce),
66
- u64le(p.notAfter),
67
- ]);
68
- }
69
- /**
70
- * Sign a creation warrant and return it hex-encoded, with its seed.
71
- *
72
- * Returns the encoding rather than an object for the reason `signWarrant`
73
- * does: the signature covers exactly these bytes.
74
- */
75
- export async function signCreationWarrant(input) {
76
- const group = fromHex(input.group, 'group', 32);
77
- const seed = input.seed === undefined
78
- ? crypto.getRandomValues(new Uint8Array(32))
79
- : fromHex(input.seed, 'seed', 32);
80
- const authorAccount = fromHex(input.authorAccount, 'authorAccount', 32);
81
- const executor = fromHex(input.executor, 'executor', 32);
82
- const executorKey = fromHex(input.executorKey, 'executorKey', 32);
83
- const applicationId = fromHex(input.applicationId, 'applicationId', 32);
84
- const serviceName = label(input.serviceName, 'serviceName');
85
- const name = label(input.name, 'name');
86
- const accountHeads = citedHeads(input.accountHeads, 'accountHeads');
87
- const governanceFloor = citedHeads(input.governanceFloor, 'governanceFloor');
88
- const signer = await resolveSigner(input.deviceSecret, input.signer, 'deviceSecret');
89
- const deviceKey = fromHex(signer.publicKey, 'signer.publicKey', 32);
90
- const initHash = await creationInitHash(input.initArgs);
91
- const preimage = await creationWarrantPreimage({
92
- group,
93
- seed,
94
- authorAccount,
95
- deviceKey,
96
- executor,
97
- executorKey,
98
- applicationId,
99
- serviceName,
100
- name,
101
- initHash,
102
- accountHeads,
103
- governanceFloor,
104
- nonce: input.nonce,
105
- notAfter: input.notAfter,
106
- });
107
- const signature = checkedSignature(await signer.sign(preimage));
108
- const warrant = hex(concat(group, seed, authorAccount, deviceKey, executor, executorKey, applicationId, borshOption(serviceName), borshOption(name), initHash, u32le(accountHeads.length), ...accountHeads, u32le(governanceFloor.length), ...governanceFloor, u64le(input.nonce), u64le(input.notAfter), signature));
109
- return { warrant, seed: hex(seed) };
110
- }
111
- /**
112
- * Decode a hex creation warrant back into its fields.
113
- *
114
- * Refuses truncated or trailing bytes rather than reading a neighbouring field.
115
- * Does not verify the signature.
116
- */
117
- export function parseCreationWarrant(warrant) {
118
- const clean = warrant.trim();
119
- if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
120
- throw new Error('creation warrant must be an even number of hex characters');
121
- }
122
- const bytes = new Uint8Array(clean.length / 2);
123
- for (let i = 0; i < bytes.length; i += 1) {
124
- bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
125
- }
126
- const view = new DataView(bytes.buffer);
127
- let o = 0;
128
- const take = (n, what) => {
129
- if (o + n > bytes.length) {
130
- throw new Error(`creation warrant ends inside ${what} (${bytes.length} bytes)`);
131
- }
132
- const out = bytes.subarray(o, o + n);
133
- o += n;
134
- return out;
135
- };
136
- const u32 = (what) => view.getUint32(take(4, what).byteOffset, true);
137
- const u64 = (what) => view.getBigUint64(take(8, what).byteOffset, true);
138
- const option = (what) => {
139
- const tag = take(1, what)[0];
140
- if (tag === 0)
141
- return null;
142
- if (tag !== 1)
143
- throw new Error(`${what} has option tag ${tag}, expected 0 or 1`);
144
- const len = u32(what);
145
- if (len > MAX_LABEL_BYTES) {
146
- throw new Error(`${what} is ${len} bytes, over the ${MAX_LABEL_BYTES} a node accepts`);
147
- }
148
- return new TextDecoder('utf-8', { fatal: true }).decode(take(len, what));
149
- };
150
- const heads = (what) => {
151
- const count = u32(what);
152
- if (count > 64) {
153
- throw new Error(`${what} cites ${count} heads, over the 64 a node accepts`);
154
- }
155
- return Array.from({ length: count }, () => hex(take(32, what)));
156
- };
157
- const fields = {
158
- group: hex(take(32, 'group')),
159
- seed: hex(take(32, 'seed')),
160
- authorAccount: hex(take(32, 'authorAccount')),
161
- deviceKey: hex(take(32, 'deviceKey')),
162
- executor: hex(take(32, 'executor')),
163
- executorKey: hex(take(32, 'executorKey')),
164
- applicationId: hex(take(32, 'applicationId')),
165
- serviceName: option('serviceName'),
166
- name: option('name'),
167
- initHash: hex(take(32, 'initHash')),
168
- accountHeads: heads('accountHeads'),
169
- governanceFloor: heads('governanceFloor'),
170
- nonce: u64('nonce'),
171
- notAfter: u64('notAfter'),
172
- signature: hex(take(64, 'signature')),
173
- };
174
- if (o !== bytes.length) {
175
- throw new Error(`creation warrant is ${bytes.length} bytes but its fields account for ${o}`);
176
- }
177
- return fields;
178
- }
179
- /** UTF-8 encode an optional label, refusing one longer than a node accepts. */
180
- function label(value, what) {
181
- if (value === undefined)
182
- return null;
183
- const bytes = new TextEncoder().encode(value);
184
- if (bytes.length > MAX_LABEL_BYTES) {
185
- throw new Error(`${what} is ${bytes.length} UTF-8 bytes, over the ${MAX_LABEL_BYTES} a node accepts`);
186
- }
187
- return bytes;
188
- }
189
- /** Borsh `Option<String>`: `0x00`, or `0x01` then a u32 length and the bytes. */
190
- function borshOption(bytes) {
191
- if (bytes === null)
192
- return new Uint8Array([0]);
193
- return concat(new Uint8Array([1]), u32le(bytes.length), bytes);
194
- }
@@ -1,202 +0,0 @@
1
- /**
2
- * Encode the governance ops a member may have a relay publish for them.
3
- *
4
- * A governance warrant commits to an op's **borsh bytes**, not to a description
5
- * of it, so the client has to produce exactly the bytes the node decodes. These
6
- * encoders cover the delegable ops (core's `GroupOp::delegable_form` and
7
- * `RootOp::delegable_form`) that a keyholder app is likely to need. Every
8
- * discriminant is a variant's position in core's enum, which is how borsh
9
- * encodes a Rust enum; they are pinned against core's own vectors in the test.
10
- *
11
- * **Delegable form.** A removal, a leave and a cascade delete carry fields only
12
- * the publisher can compute (post-state hashes, the enumerated subtree). The
13
- * member signs them cleared, and these encoders only ever produce the cleared
14
- * form, which is the one a relay accepts. The relay fills them in afterwards.
15
- *
16
- * Sources in core, for the next person to check a discriminant:
17
- * `crates/governance-types/src/lib.rs` (`GroupOp`, `RootOp`),
18
- * `crates/primitives/src/context.rs` (`GroupMemberRole`),
19
- * `crates/account/src/namespace_id.rs` (`founded_namespace_id`), and the vectors in
20
- * `crates/governance-types/src/tests.rs` (`delegated_governance_op_vectors_are_stable`).
21
- */
22
- /**
23
- * Which plane an op is published on: `group` is a `GroupOp` on the group's own
24
- * log, `root` a `RootOp` on the namespace log. The kind is signed over, so
25
- * consent to one can never be presented as the other.
26
- */
27
- export type GovernanceOpKind = 'group' | 'root';
28
- /** An encoded governance op and the plane it belongs to. */
29
- export interface GovernanceOp {
30
- kind: GovernanceOpKind;
31
- /** The op's borsh bytes in delegable form: what the warrant commits to. */
32
- bytes: Uint8Array;
33
- }
34
- /** A group member's role. Borsh discriminants follow core's `GroupMemberRole`. */
35
- export type GovernanceMemberRole = 'Admin' | 'Member' | 'ReadOnly';
36
- /**
37
- * Add `member` (an account, hex) to the group with `role`.
38
- *
39
- * Applied as the author: adding a `Member` needs `MANAGE_MEMBERS` or admin,
40
- * adding an `Admin` needs admin.
41
- */
42
- export declare function memberAddedOp(member: string, memberRole: GovernanceMemberRole): GovernanceOp;
43
- /**
44
- * Remove `member` (an account, hex) from the group, in delegable form: both
45
- * post-state claims cleared, for the relay to compute from its own view.
46
- */
47
- export declare function memberRemovedOp(member: string): GovernanceOp;
48
- /**
49
- * The author leaves the group, in delegable form. The node applies it only when
50
- * `member` is the author's own account.
51
- */
52
- export declare function memberLeftOp(member: string): GovernanceOp;
53
- /** Set `member`'s role (an account, hex). */
54
- export declare function memberRoleSetOp(member: string, memberRole: GovernanceMemberRole): GovernanceOp;
55
- /**
56
- * The id `admin` derives for a subgroup under `parentId` with birth visibility
57
- * `restricted` and `salt` (all hex), as core's `created_subgroup_id` does:
58
- * `domain_hash("calimero.subgroup.id.v1", [admin, parentId, [restricted], salt])`.
59
- *
60
- * A subgroup's id is bound to its create, so nobody but its creator can name
61
- * it: a node refuses a `GroupCreated` whose fields do not reproduce its id.
62
- * That is what stops a second member racing a concurrent create for an id it
63
- * saw gossiped.
64
- */
65
- export declare function createdSubgroupId(admin: string, parentId: string, restricted: boolean, salt: string): Promise<string>;
66
- /**
67
- * Choose the application a group runs (`GroupOp::TargetApplicationSet`), in
68
- * its delegable form: `bytecode_id` is left for the relay to fill (32 zero
69
- * bytes), resolved from `package@version` in the registry. The member signs
70
- * the application id, package and version, so the relay can pick no other
71
- * build; the application id binds package and signer, and every node checks
72
- * the bundle's signature.
73
- *
74
- * Through a relay this is accepted only as a group's FIRST application, on a
75
- * group that targets none yet (a namespace an account founded). Moving an
76
- * existing target is an upgrade, which never goes through a relay.
77
- */
78
- export declare function targetApplicationSetOp(input: {
79
- applicationId: string;
80
- package: string;
81
- version: string;
82
- }): GovernanceOp;
83
- export declare function defaultCapabilitiesSetOp(capabilities: number): GovernanceOp;
84
- /** What a subgroup is created with. */
85
- export interface GroupCreatedInput {
86
- /**
87
- * The new subgroup's id, hex (32 bytes). It must be
88
- * `createdSubgroupId(admin, parentId, restricted, salt)`; a node refuses any
89
- * other. {@link subgroupCreation} draws the salt and derives it for you.
90
- */
91
- groupId: string;
92
- /** The group it is nested under, hex: the namespace root or an existing subgroup. */
93
- parentId: string;
94
- /** `true` for a Restricted subgroup, `false` for born-Open (the default). */
95
- restricted: boolean;
96
- /**
97
- * The subgroup's founding admin, hex: the **author's** account. The node
98
- * refuses any other, since the op is applied as the author.
99
- */
100
- admin: string;
101
- /** The salt `groupId` was derived with, hex (32 bytes). Random; need not be kept. */
102
- salt: string;
103
- }
104
- /**
105
- * Create a subgroup under `parentId`, a root op published on the namespace.
106
- *
107
- * Needs `CAN_CREATE_SUBGROUP` or admin on the parent; the author, not the
108
- * relay, becomes the new subgroup's admin.
109
- */
110
- export declare function groupCreatedOp(input: GroupCreatedInput): GovernanceOp;
111
- /** A new subgroup's create: its derived id, the salt it was derived with, and the op. */
112
- export interface SubgroupCreation {
113
- groupId: string;
114
- salt: string;
115
- op: GovernanceOp;
116
- }
117
- /**
118
- * Create a subgroup under `parentId`: draws a fresh salt (unless one is given),
119
- * derives the id with {@link createdSubgroupId}, and encodes the op.
120
- */
121
- export declare function subgroupCreation(input: Omit<GroupCreatedInput, 'groupId' | 'salt'> & {
122
- salt?: string;
123
- }): Promise<SubgroupCreation>;
124
- /** Move `childGroupId` under `newParentId`, a root op. */
125
- export declare function groupReparentedOp(childGroupId: string, newParentId: string): GovernanceOp;
126
- /**
127
- * Delete `rootGroupId` and its subtree, in delegable form: both cascade lists
128
- * empty, for the relay to enumerate.
129
- */
130
- export declare function groupDeletedOp(rootGroupId: string): GovernanceOp;
131
- /**
132
- * The id of the namespace `founder` founds with `salt`: core's
133
- * `founded_namespace_id`, `domain_hash("calimero.namespace.id.v1", [founder, salt])`.
134
- *
135
- * Anyone holding the pair can recompute it, and only the founder's account
136
- * hashes to it, which is why a relay founding a namespace for a member cannot
137
- * choose the id: the member computes it and signs it.
138
- */
139
- export declare function foundedNamespaceId(founder: string, salt: string): Promise<string>;
140
- /** What a namespace is founded with. */
141
- export interface NamespaceCreatedInput {
142
- /** The founding account, hex: the **author's**. It becomes founder, owner and admin. */
143
- founder: string;
144
- /**
145
- * The founder's `AccountProof<DeviceCert>`, hex: the credential the author
146
- * already presents as `authorProof`. Its account must be `founder` and its
147
- * device key the one that signs the warrant; the genesis apply checks both
148
- * and binds the founder's device from it.
149
- */
150
- credential: string;
151
- /**
152
- * The salt the namespace id is derived with, hex (32 bytes). Choose it at
153
- * random; {@link foundedNamespaceId} gives the id it yields.
154
- */
155
- salt: string;
156
- }
157
- /**
158
- * Found a namespace: core's `RootOp::NamespaceCreatedV2` genesis, a root op
159
- * published on the new namespace's own log.
160
- *
161
- * Its delegable form is the op itself, nothing cleared, so the author signs the
162
- * exact genesis. Borsh is `[9] || founder || credential || salt`: the credential
163
- * is a nested struct, not a length-prefixed byte string, so it is written
164
- * inline. The warrant's scope must be {@link foundedNamespaceId}`(founder, salt)`.
165
- */
166
- export declare function namespaceCreatedOp(input: NamespaceCreatedInput): GovernanceOp;
167
- /** Set `member`'s capabilities in the group (`GroupOp::MemberCapabilitySet`). Bit 9 is refused. */
168
- export declare function memberCapabilitySetOp(member: string, capabilities: number): GovernanceOp;
169
- /** Detach a context from the group (`GroupOp::ContextDetached`). */
170
- export declare function contextDetachedOp(contextId: string): GovernanceOp;
171
- /** Make a subgroup open (members of the parent may join it themselves) or restricted. */
172
- export declare function subgroupVisibilitySetOp(mode: 'open' | 'restricted'): GovernanceOp;
173
- /** Name the group, with optional key/value data (`GroupOp::GroupMetadataSet`). */
174
- export declare function groupMetadataSetOp(input?: {
175
- name?: string;
176
- data?: Record<string, string>;
177
- }): GovernanceOp;
178
- /** Name a member in the group (`GroupOp::MemberMetadataSet`). */
179
- export declare function memberMetadataSetOp(member: string, input?: {
180
- name?: string;
181
- data?: Record<string, string>;
182
- }): GovernanceOp;
183
- /** Name a context in the group (`GroupOp::ContextMetadataSet`). */
184
- export declare function contextMetadataSetOp(contextId: string, input?: {
185
- name?: string;
186
- data?: Record<string, string>;
187
- }): GovernanceOp;
188
- /** Grant `member` a per-context capability (`GroupOp::ContextCapabilityGranted`). */
189
- export declare function contextCapabilityGrantedOp(contextId: string, member: string, capability: number): GovernanceOp;
190
- /** Revoke a per-context capability from `member` (`GroupOp::ContextCapabilityRevoked`). */
191
- export declare function contextCapabilityRevokedOp(contextId: string, member: string, capability: number): GovernanceOp;
192
- /**
193
- * Join an open subgroup yourself (`RootOp::MemberJoinedOpen`), a root op posted
194
- * to the namespace. `member` must be the author; `credential` is the author's
195
- * own `AccountProof<DeviceCert>`, hex, carried as-is. The author's
196
- * `CAN_JOIN_OPEN_SUBGROUPS` and the open inheritance path are checked as usual.
197
- */
198
- export declare function memberJoinedOpenOp(input: {
199
- member: string;
200
- groupId: string;
201
- credential: string;
202
- }): GovernanceOp;