@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,7 +1,7 @@
1
- export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createAttestedSealedFetch, createSealedFetch, fetchAttestedTransportKey, transportKeyBinding, } from './sealed.js';
2
- export type { AttestedSealedFetchOptions, SealedFetchOptions, VerifyTransportQuote } from './sealed.js';
1
+ export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createSealedFetch, transportKeyBinding, } from './sealed.js';
2
+ export type { SealedFetchOptions, VerifyTransportQuote } from './sealed.js';
3
3
  export { PRODUCTION_PROFILE, createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
4
4
  export type { DcapCollateral, DcapVerifiedReport, DcapVerify, PublishedMrtds, QuoteVerifier, QuoteVerifierOptions, TrustedMeasurements, TrustedProfileOptions, } from './verify.js';
5
- export { DEFAULT_RELEASE_MIRROR, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseSealedFetch, createSignedReleaseVerifier, fetchNodeRelease, fetchNodeReleaseVersion, nodeReleaseVersionFromImage, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
6
- export type { SignedNodeRelease, SignedReleaseSealedFetchOptions, SignedReleaseVerifierOptions, TrustSignedReleaseOptions, VerifySignedNodeReleaseOptions, } from './release.js';
5
+ export { DEFAULT_RELEASE_MIRROR, GITHUB_RELEASES, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseVerifier, fetchGithubNodeRelease, fetchNodeRelease, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
6
+ export type { SignedNodeRelease, SignedReleaseVerifierOptions, TrustSignedReleaseOptions, VerifySignedNodeReleaseOptions, } from './release.js';
7
7
  export type { SignerIdentity } from './sigstore.js';
@@ -1,3 +1,3 @@
1
- export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createAttestedSealedFetch, createSealedFetch, fetchAttestedTransportKey, transportKeyBinding, } from './sealed.js';
1
+ export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createSealedFetch, transportKeyBinding, } from './sealed.js';
2
2
  export { PRODUCTION_PROFILE, createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
3
- export { DEFAULT_RELEASE_MIRROR, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseSealedFetch, createSignedReleaseVerifier, fetchNodeRelease, fetchNodeReleaseVersion, nodeReleaseVersionFromImage, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
3
+ export { DEFAULT_RELEASE_MIRROR, GITHUB_RELEASES, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseVerifier, fetchGithubNodeRelease, fetchNodeRelease, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
@@ -21,7 +21,7 @@
21
21
  * - the minimum release you pass, below which no release is accepted.
22
22
  *
23
23
  * What is not: the transport, the server that serves the release, and the
24
- * relay's choice of release. A relay can present any genuinely signed release
24
+ * node's choice of release. A node can present any genuinely signed release
25
25
  * at or above the minimum, and no other; its quote must then match that
26
26
  * release's measurements exactly, so it cannot claim one release and run
27
27
  * another.
@@ -86,25 +86,19 @@ export declare function verifySignedNodeRelease(publishedMrtds: string | Uint8Ar
86
86
  export declare function fetchNodeRelease(url: string, options?: {
87
87
  fetch?: typeof fetch;
88
88
  }): Promise<SignedNodeRelease>;
89
+ /** Where mero-tee publishes its releases' assets, as core's `calimero-tee-release` fetches them. */
90
+ export declare const GITHUB_RELEASES = "https://github.com/calimero-network/mero-tee/releases/download";
89
91
  /**
90
- * The release a mero-tee node image was built from, read from its name, e.g.
91
- * `merotee-ubuntu-questing-25-10-locked-read-only-2-3-87` is `2.3.87`. Throws
92
- * for any other name, including the suffixed images of unreleased builds.
92
+ * Node release `version` straight from its GitHub release (`mero-tee-v{version}`):
93
+ * `published-mrtds.json` and its cosign bundle, the files core's Rust client
94
+ * verifies. Only fetched: verify it with {@link trustSignedRelease}. GitHub's
95
+ * downloads send no CORS headers, so in a browser use a mirror
96
+ * ({@link cloudNodeReleaseUrl}) instead.
93
97
  */
94
- export declare function nodeReleaseVersionFromImage(osImage: string): string;
95
- /**
96
- * The release the TEE node at `baseUrl` says it runs, from the image name its
97
- * `GET /admin-api/tee/info` reports. The node's own claim, and not trusted:
98
- * it only picks which signed release to fetch, and the quote must then match
99
- * that release's measurements.
100
- *
101
- * `/tee/info` is read in the clear, before any session exists. A node that
102
- * requires sealing serves it unsealed from core#4196 on; an older one refuses
103
- * it with `403 sealed_required`, and then this throws saying so.
104
- */
105
- export declare function fetchNodeReleaseVersion(baseUrl: string, options?: {
98
+ export declare function fetchGithubNodeRelease(version: string, options?: {
106
99
  fetch?: typeof fetch;
107
- }): Promise<string>;
100
+ base?: string;
101
+ }): Promise<SignedNodeRelease>;
108
102
  /** Where the cloud at `cloudUrl` (e.g. `https://cloud.calimero.network`) mirrors node release `version`. */
109
103
  export declare function cloudNodeReleaseUrl(cloudUrl: string, version: string): string;
110
104
  export interface TrustSignedReleaseOptions extends TrustedProfileOptions {
@@ -112,7 +106,7 @@ export interface TrustSignedReleaseOptions extends TrustedProfileOptions {
112
106
  release: SignedNodeRelease;
113
107
  /**
114
108
  * The oldest release accepted, e.g. `2.3.87`. Required: every release ever
115
- * signed stays validly signed, so without a floor a relay could present an
109
+ * signed stays validly signed, so without a floor a node could present an
116
110
  * old release, with a flaw since fixed, and a quote from that old image
117
111
  * would pass. Raise it when a release must no longer be trusted.
118
112
  */
@@ -129,7 +123,7 @@ export interface TrustSignedReleaseOptions extends TrustedProfileOptions {
129
123
  * file.
130
124
  *
131
125
  * ```ts
132
- * const version = await fetchNodeReleaseVersion(relayUrl);
126
+ * const version = claimedRelease(attestationDoc, '2.3.109'); // the release the node names
133
127
  * const release = await fetchNodeRelease(cloudNodeReleaseUrl(DEFAULT_RELEASE_MIRROR, version));
134
128
  * const verifier = createQuoteVerifier({
135
129
  * dcapVerify,
@@ -160,64 +154,15 @@ export interface SignedReleaseVerifierOptions extends Omit<TrustSignedReleaseOpt
160
154
  *
161
155
  * The node's choice of release is the one thing taken from it, and it is
162
156
  * bounded: only a genuinely signed release at or above `minReleaseVersion`
163
- * passes, and the quote must then be of exactly that release's image. Use it
164
- * as `connectCloud`'s `seal`, or with `createAttestedSealedFetch`;
165
- * {@link createSignedReleaseSealedFetch} does the latter for you.
157
+ * passes, and the quote must then be of exactly that release's image. Pass it
158
+ * as `CloudPolicy.verifyQuote` to choose where the release comes from yourself.
166
159
  */
167
160
  export declare function createSignedReleaseVerifier(options: SignedReleaseVerifierOptions): QuoteVerifier;
168
- export interface SignedReleaseSealedFetchOptions extends Omit<SignedReleaseVerifierOptions, 'release'> {
169
- /** The TEE node's (the relay's) base URL. */
170
- baseUrl: string;
171
- /**
172
- * Where to get the release the node says it runs, the version read from its
173
- * `GET /admin-api/tee/info` each time it is attested. A string is the base
174
- * URL of a mirror serving {@link cloudNodeReleaseUrl}'s path, defaulting to
175
- * {@link DEFAULT_RELEASE_MIRROR}; a function gets the version and returns
176
- * the release, e.g. from a file bundled with the app. Whichever it is, it is
177
- * not trusted: the release is verified. `/tee/info` is read in the clear;
178
- * for a node that refuses that, see `releaseVersion`.
179
- */
180
- releaseSource?: string | ((context: {
181
- baseUrl: string;
182
- version: string;
183
- fetch: typeof fetch;
184
- }) => Promise<SignedNodeRelease>);
185
- /**
186
- * The release to fetch when the node will not name one: a node that
187
- * requires sealing (`[server.sealed] required`) and predates core#4196
188
- * refuses `/tee/info` unsealed. Used only then; a node that answers is
189
- * taken at its word. Either way untrusted: the quote must match the signed
190
- * release, so a wrong version only fails the attestation.
191
- */
192
- releaseVersion?: string;
193
- /** Also require the node to run this application with this bytecode hash. */
194
- applicationId?: string;
195
- applicationHash?: string;
196
- /** Fetch for the release, the attestation and the envelopes. Defaults to global `fetch`. */
197
- fetch?: typeof fetch;
198
- }
161
+ /** `value` if it is a release version (`2.3.87`, `2.3.88-rc.1`); throws otherwise. */
162
+ export declare function releaseVersion(value: unknown, what: string): string;
199
163
  /**
200
- * {@link createAttestedSealedFetch} for a TEE node known only by URL, trusting
201
- * whatever signed release at or above `minReleaseVersion` it runs: it reads
202
- * the release the node names from its `/tee/info` (or takes `releaseVersion`
203
- * when a node too old to serve that unsealed requires sealing), gets that release from
204
- * `releaseSource` (the public mirror unless you say otherwise), verifies its
205
- * signature, builds the quote verifier from its measurements, attests the node
206
- * and seals everything to it.
207
- *
208
- * ```ts
209
- * import { verify as dcapVerify } from '@phala/dcap-qvl';
210
- *
211
- * const relay = new RelayClient({
212
- * relayUrl,
213
- * fetch: createSignedReleaseSealedFetch({
214
- * baseUrl: relayUrl,
215
- * dcapVerify,
216
- * profile: 'locked-read-only',
217
- * minReleaseVersion: '2.3.87',
218
- * }),
219
- * ...
220
- * });
221
- * ```
164
+ * Order two release versions as semver does, and as core's
165
+ * `compare_release_versions`: numerically by `X.Y.Z`, a pre-release before its
166
+ * release, build metadata ignored.
222
167
  */
223
- export declare function createSignedReleaseSealedFetch(options: SignedReleaseSealedFetchOptions): typeof fetch;
168
+ export declare function compareReleaseVersions(a: string, b: string): number;
@@ -21,12 +21,11 @@
21
21
  * - the minimum release you pass, below which no release is accepted.
22
22
  *
23
23
  * What is not: the transport, the server that serves the release, and the
24
- * relay's choice of release. A relay can present any genuinely signed release
24
+ * node's choice of release. A node can present any genuinely signed release
25
25
  * at or above the minimum, and no other; its quote must then match that
26
26
  * release's measurements exactly, so it cannot claim one release and run
27
27
  * another.
28
28
  */
29
- import { createAttestedSealedFetch } from './sealed.js';
30
29
  import { verifyCosignBundle } from './sigstore.js';
31
30
  import { createQuoteVerifier, trustedMeasurementsFromReleases, } from './verify.js';
32
31
  /** The workflow that signs every mero-tee node release, and the issuer of its identity. */
@@ -111,63 +110,26 @@ export async function fetchNodeRelease(url, options = {}) {
111
110
  }
112
111
  return { version: release.version, publishedMrtds: release.publishedMrtds, bundle: release.bundle };
113
112
  }
113
+ /** Where mero-tee publishes its releases' assets, as core's `calimero-tee-release` fetches them. */
114
+ export const GITHUB_RELEASES = 'https://github.com/calimero-network/mero-tee/releases/download';
114
115
  /**
115
- * The release a mero-tee node image was built from, read from its name, e.g.
116
- * `merotee-ubuntu-questing-25-10-locked-read-only-2-3-87` is `2.3.87`. Throws
117
- * for any other name, including the suffixed images of unreleased builds.
116
+ * Node release `version` straight from its GitHub release (`mero-tee-v{version}`):
117
+ * `published-mrtds.json` and its cosign bundle, the files core's Rust client
118
+ * verifies. Only fetched: verify it with {@link trustSignedRelease}. GitHub's
119
+ * downloads send no CORS headers, so in a browser use a mirror
120
+ * ({@link cloudNodeReleaseUrl}) instead.
118
121
  */
119
- export function nodeReleaseVersionFromImage(osImage) {
120
- const match = /^merotee-.+-(\d+)-(\d+)-(\d+)$/.exec(osImage);
121
- if (!match)
122
- throw new Error(`${JSON.stringify(osImage)} is not the image of a mero-tee node release`);
123
- return `${Number(match[1])}.${Number(match[2])}.${Number(match[3])}`;
124
- }
125
- /**
126
- * The release the TEE node at `baseUrl` says it runs, from the image name its
127
- * `GET /admin-api/tee/info` reports. The node's own claim, and not trusted:
128
- * it only picks which signed release to fetch, and the quote must then match
129
- * that release's measurements.
130
- *
131
- * `/tee/info` is read in the clear, before any session exists. A node that
132
- * requires sealing serves it unsealed from core#4196 on; an older one refuses
133
- * it with `403 sealed_required`, and then this throws saying so.
134
- */
135
- export async function fetchNodeReleaseVersion(baseUrl, options = {}) {
136
- const version = await readNodeReleaseVersion(baseUrl, options.fetch ?? fetch);
137
- if (version === undefined) {
138
- throw new Error(`${infoUrl(baseUrl)} was refused unsealed: the node requires sealing and is too old to name its ` +
139
- "release before a session exists. Name the release it runs yourself (createSignedReleaseSealedFetch's " +
140
- '`releaseVersion`), or upgrade the node');
141
- }
142
- return version;
143
- }
144
- function infoUrl(baseUrl) {
145
- return `${baseUrl.replace(/\/+$/, '')}/admin-api/tee/info`;
146
- }
147
- /** As {@link fetchNodeReleaseVersion}, but `undefined` when the node refuses `/tee/info` as `sealed_required`. */
148
- async function readNodeReleaseVersion(baseUrl, givenFetch) {
149
- const url = infoUrl(baseUrl);
150
- const response = await givenFetch(url, { headers: { accept: 'application/json' } });
151
- if (response.status === 403) {
152
- const code = await response
153
- .json()
154
- .then((body) => body?.error?.code)
155
- .catch(() => undefined);
156
- if (code === 'sealed_required')
157
- return undefined;
158
- }
159
- if (!response.ok)
160
- throw new Error(`Fetching ${url} failed: HTTP ${response.status}`);
161
- let osImage;
162
- try {
163
- osImage = (await response.json())?.data?.osImage;
164
- }
165
- catch {
166
- throw new Error(`${url} did not answer with JSON`);
167
- }
168
- if (typeof osImage !== 'string')
169
- throw new Error(`${url} did not name the node's image`);
170
- return nodeReleaseVersionFromImage(osImage);
122
+ export async function fetchGithubNodeRelease(version, options = {}) {
123
+ const tag = `mero-tee-v${releaseVersion(version, 'version')}`;
124
+ const base = `${(options.base ?? GITHUB_RELEASES).replace(/\/+$/, '')}/${tag}/published-mrtds.json`;
125
+ const get = async (url) => {
126
+ const response = await (options.fetch ?? fetch)(url);
127
+ if (!response.ok)
128
+ throw new Error(`Fetching ${url} failed: HTTP ${response.status}`);
129
+ return response.text();
130
+ };
131
+ const [publishedMrtds, bundle] = await Promise.all([get(base), get(`${base}.bundle.json`)]);
132
+ return { version, publishedMrtds, bundle };
171
133
  }
172
134
  /** Where the cloud at `cloudUrl` (e.g. `https://cloud.calimero.network`) mirrors node release `version`. */
173
135
  export function cloudNodeReleaseUrl(cloudUrl, version) {
@@ -181,7 +143,7 @@ export function cloudNodeReleaseUrl(cloudUrl, version) {
181
143
  * file.
182
144
  *
183
145
  * ```ts
184
- * const version = await fetchNodeReleaseVersion(relayUrl);
146
+ * const version = claimedRelease(attestationDoc, '2.3.109'); // the release the node names
185
147
  * const release = await fetchNodeRelease(cloudNodeReleaseUrl(DEFAULT_RELEASE_MIRROR, version));
186
148
  * const verifier = createQuoteVerifier({
187
149
  * dcapVerify,
@@ -213,9 +175,8 @@ export async function trustSignedRelease(options) {
213
175
  *
214
176
  * The node's choice of release is the one thing taken from it, and it is
215
177
  * bounded: only a genuinely signed release at or above `minReleaseVersion`
216
- * passes, and the quote must then be of exactly that release's image. Use it
217
- * as `connectCloud`'s `seal`, or with `createAttestedSealedFetch`;
218
- * {@link createSignedReleaseSealedFetch} does the latter for you.
178
+ * passes, and the quote must then be of exactly that release's image. Pass it
179
+ * as `CloudPolicy.verifyQuote` to choose where the release comes from yourself.
219
180
  */
220
181
  export function createSignedReleaseVerifier(options) {
221
182
  releaseVersion(options.minReleaseVersion, 'minReleaseVersion');
@@ -237,54 +198,9 @@ export function createSignedReleaseVerifier(options) {
237
198
  };
238
199
  return Object.assign(verifier, { includeCollateral: true });
239
200
  }
240
- /**
241
- * {@link createAttestedSealedFetch} for a TEE node known only by URL, trusting
242
- * whatever signed release at or above `minReleaseVersion` it runs: it reads
243
- * the release the node names from its `/tee/info` (or takes `releaseVersion`
244
- * when a node too old to serve that unsealed requires sealing), gets that release from
245
- * `releaseSource` (the public mirror unless you say otherwise), verifies its
246
- * signature, builds the quote verifier from its measurements, attests the node
247
- * and seals everything to it.
248
- *
249
- * ```ts
250
- * import { verify as dcapVerify } from '@phala/dcap-qvl';
251
- *
252
- * const relay = new RelayClient({
253
- * relayUrl,
254
- * fetch: createSignedReleaseSealedFetch({
255
- * baseUrl: relayUrl,
256
- * dcapVerify,
257
- * profile: 'locked-read-only',
258
- * minReleaseVersion: '2.3.87',
259
- * }),
260
- * ...
261
- * });
262
- * ```
263
- */
264
- export function createSignedReleaseSealedFetch(options) {
265
- const { baseUrl, releaseSource, releaseVersion: fallbackVersion, applicationId, applicationHash, fetch: givenFetch, ...verifierOptions } = options;
266
- if (fallbackVersion !== undefined)
267
- releaseVersion(fallbackVersion, 'releaseVersion');
268
- const baseFetch = givenFetch ?? ((input, init) => fetch(input, init));
269
- const release = async () => {
270
- const version = fallbackVersion === undefined
271
- ? await fetchNodeReleaseVersion(baseUrl, { fetch: baseFetch })
272
- : ((await readNodeReleaseVersion(baseUrl, baseFetch)) ?? fallbackVersion);
273
- return typeof releaseSource === 'function'
274
- ? releaseSource({ baseUrl, version, fetch: baseFetch })
275
- : fetchNodeRelease(cloudNodeReleaseUrl(releaseSource ?? DEFAULT_RELEASE_MIRROR, version), { fetch: baseFetch });
276
- };
277
- return createAttestedSealedFetch({
278
- baseUrl,
279
- verify: createSignedReleaseVerifier({ ...verifierOptions, release }),
280
- applicationId,
281
- applicationHash,
282
- fetch: baseFetch,
283
- });
284
- }
285
201
  const RELEASE_VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
286
202
  /** `value` if it is a release version (`2.3.87`, `2.3.88-rc.1`); throws otherwise. */
287
- function releaseVersion(value, what) {
203
+ export function releaseVersion(value, what) {
288
204
  const match = typeof value === 'string' ? RELEASE_VERSION.exec(value) : null;
289
205
  const pre = match?.[4];
290
206
  if (!match || (pre !== undefined && pre.split('.').some((id) => id === ''))) {
@@ -297,7 +213,7 @@ function releaseVersion(value, what) {
297
213
  * `compare_release_versions`: numerically by `X.Y.Z`, a pre-release before its
298
214
  * release, build metadata ignored.
299
215
  */
300
- function compareReleaseVersions(a, b) {
216
+ export function compareReleaseVersions(a, b) {
301
217
  const [aCore, aPre] = splitVersion(a);
302
218
  const [bCore, bPre] = splitVersion(b);
303
219
  for (let i = 0; i < 3; i += 1) {
@@ -8,7 +8,7 @@
8
8
  * produce a response the client accepts.
9
9
  *
10
10
  * The client opens a session with a Noise NK handshake to the X25519 transport
11
- * key the node's quote commits to ({@link fetchAttestedTransportKey}). The
11
+ * key the node's quote commits to (`fetchAttestedKey`, `GET /attestation`). The
12
12
  * transport key only authenticates the node: the session keys come from both
13
13
  * sides' ephemeral keys, so once a session is gone (an hour at most) what was
14
14
  * sent in it cannot be opened, not even with the transport key. Each request
@@ -17,7 +17,7 @@
17
17
  * refuses one inside the envelope with a 501.
18
18
  *
19
19
  * The node's side, and the wire format this implements byte for byte, are in
20
- * core's `crates/server/src/sealed.rs`:
20
+ * core's `crates/sealed` (`calimero-sealed`):
21
21
  *
22
22
  * ```text
23
23
  * handshake Noise_NK_25519_AESGCM_SHA256, prologue "calimero/sealed-http/v2"
@@ -33,9 +33,9 @@
33
33
  * inner u32 BE head length || head (JSON) || body
34
34
  * ```
35
35
  *
36
- * Use it by handing {@link createSealedFetch} to `MeroJsConfig.fetch`.
36
+ * `CalimeroClient` seals every request this way; {@link createSealedFetch} is
37
+ * the same channel as a plain `fetch`.
37
38
  */
38
- import type { TeeAttestRequest, TeeAttestResponseData } from '../admin-api/admin-types.js';
39
39
  import { initiate } from './noise.js';
40
40
  import type { DcapCollateral } from './verify.js';
41
41
  /** Where a session is opened, relative to the node's base URL. */
@@ -83,64 +83,17 @@ export interface VerifyTransportQuote {
83
83
  collateral?: DcapCollateral;
84
84
  }): Promise<boolean>;
85
85
  /**
86
- * Ask the node for the collateral its quote verifies against, and pass it
87
- * in as `collateral`. Off unless set, because a node that predates the field
88
- * refuses the request.
86
+ * Set by the verifiers this package builds. A Calimero 1.0 node sends no
87
+ * collateral with its quote; the verifier fetches it itself.
89
88
  */
90
89
  readonly includeCollateral?: boolean;
91
90
  }
92
- /**
93
- * Ask a node for its transport key and accept it only if a quote you verified
94
- * commits to it.
95
- *
96
- * `applicationHash` (hex), when given, is the bytecode hash you expect the
97
- * attested application to have; the node is asked to bind that application,
98
- * and the quote only verifies if it runs that exact bytecode.
99
- */
100
- export declare function fetchAttestedTransportKey(admin: {
101
- teeAttest(request: TeeAttestRequest): Promise<TeeAttestResponseData>;
102
- }, verify: VerifyTransportQuote, options?: {
103
- applicationId?: string;
104
- applicationHash?: string;
105
- }): Promise<Uint8Array>;
106
- export interface AttestedSealedFetchOptions {
107
- /** The node's base URL. */
108
- baseUrl: string;
109
- /**
110
- * Decides whether the node's quote is one you trust — typically
111
- * {@link createQuoteVerifier}. Asked again whenever the node restarts.
112
- */
113
- verify: VerifyTransportQuote;
114
- /** Also require the node to run this application with this bytecode hash. */
115
- applicationId?: string;
116
- applicationHash?: string;
117
- /** Fetch that carries the attestation and the envelopes. Defaults to global `fetch`. */
118
- fetch?: typeof fetch;
119
- }
120
- /**
121
- * {@link createSealedFetch} for a node you know only by URL: it attests the
122
- * node's transport key with `verify`, over `POST /admin-api/tee/attest` (the
123
- * one call that needs no credential and is never sealed), and seals everything
124
- * else to it. A restarted node is attested again, through the same verifier.
125
- *
126
- * This is what to hand a {@link RelayClient} for a TEE relay, so the warrant
127
- * and the method's arguments reach only the attested TD:
128
- *
129
- * ```ts
130
- * const relay = new RelayClient({
131
- * relayUrl,
132
- * fetch: createAttestedSealedFetch({ baseUrl: relayUrl, verify: createQuoteVerifier(...) }),
133
- * ...
134
- * });
135
- * ```
136
- */
137
- export declare function createAttestedSealedFetch(options: AttestedSealedFetchOptions): typeof fetch;
138
91
  export interface SealedFetchOptions {
139
- /** The node's base URL, as given to `MeroJsConfig.baseUrl`. */
92
+ /** The node's base URL. */
140
93
  baseUrl: string;
141
94
  /**
142
95
  * The node's attested transport key, or a function that attests and returns
143
- * it — typically `() => fetchAttestedTransportKey(admin, verify)`. Given a
96
+ * it — typically `() => fetchAttestedKey(baseUrl, policy)`. Given a
144
97
  * function, a restarted node is handled: the key is attested again, through
145
98
  * your verifier, and the request retried once. Given bytes, a restart
146
99
  * surfaces as {@link StaleTransportKeyError}.
@@ -151,7 +104,6 @@ export interface SealedFetchOptions {
151
104
  }
152
105
  /**
153
106
  * A `fetch` that seals every request to the node's attested transport key.
154
- * Pass it as `MeroJsConfig.fetch`.
155
107
  *
156
108
  * A request for any URL outside `baseUrl` is refused rather than sent in the
157
109
  * clear: falling back to plaintext would silently undo the point of sealing.
@@ -8,7 +8,7 @@
8
8
  * produce a response the client accepts.
9
9
  *
10
10
  * The client opens a session with a Noise NK handshake to the X25519 transport
11
- * key the node's quote commits to ({@link fetchAttestedTransportKey}). The
11
+ * key the node's quote commits to (`fetchAttestedKey`, `GET /attestation`). The
12
12
  * transport key only authenticates the node: the session keys come from both
13
13
  * sides' ephemeral keys, so once a session is gone (an hour at most) what was
14
14
  * sent in it cannot be opened, not even with the transport key. Each request
@@ -17,7 +17,7 @@
17
17
  * refuses one inside the envelope with a 501.
18
18
  *
19
19
  * The node's side, and the wire format this implements byte for byte, are in
20
- * core's `crates/server/src/sealed.rs`:
20
+ * core's `crates/sealed` (`calimero-sealed`):
21
21
  *
22
22
  * ```text
23
23
  * handshake Noise_NK_25519_AESGCM_SHA256, prologue "calimero/sealed-http/v2"
@@ -33,9 +33,10 @@
33
33
  * inner u32 BE head length || head (JSON) || body
34
34
  * ```
35
35
  *
36
- * Use it by handing {@link createSealedFetch} to `MeroJsConfig.fetch`.
36
+ * `CalimeroClient` seals every request this way; {@link createSealedFetch} is
37
+ * the same channel as a plain `fetch`.
37
38
  */
38
- import { concat, fromHex, hex } from '../crypto/internal.js';
39
+ import { concat } from '../crypto/internal.js';
39
40
  import { initiate } from './noise.js';
40
41
  /** Where a session is opened, relative to the node's base URL. */
41
42
  export const HANDSHAKE_PATH = '/sealed/v2/handshake';
@@ -92,92 +93,8 @@ export async function transportKeyBinding(inner, transportKey) {
92
93
  const digest = await crypto.subtle.digest('SHA-256', concat(utf8.encode(TRANSPORT_BINDING_DOMAIN), inner, transportKey));
93
94
  return new Uint8Array(digest);
94
95
  }
95
- /**
96
- * Ask a node for its transport key and accept it only if a quote you verified
97
- * commits to it.
98
- *
99
- * `applicationHash` (hex), when given, is the bytecode hash you expect the
100
- * attested application to have; the node is asked to bind that application,
101
- * and the quote only verifies if it runs that exact bytecode.
102
- */
103
- export async function fetchAttestedTransportKey(admin, verify, options = {}) {
104
- if ((options.applicationId === undefined) !== (options.applicationHash === undefined)) {
105
- throw new Error('applicationId and applicationHash are given together or not at all');
106
- }
107
- const nonce = hex(crypto.getRandomValues(new Uint8Array(32)));
108
- const attested = await admin.teeAttest({
109
- nonce,
110
- applicationId: options.applicationId,
111
- bindTransportKey: true,
112
- ...(verify.includeCollateral ? { includeCollateral: true } : {}),
113
- });
114
- if (!attested.transportPublicKey) {
115
- throw new Error('The node did not report a transport key; it predates sealed transport');
116
- }
117
- const transportKey = fromHex(attested.transportPublicKey, 'transportPublicKey', 32);
118
- const inner = options.applicationHash
119
- ? fromHex(options.applicationHash, 'applicationHash', 32)
120
- : new Uint8Array(32);
121
- const reportDataSuffix = hex(await transportKeyBinding(inner, transportKey));
122
- const verified = await verify({
123
- quoteB64: attested.quoteB64,
124
- nonce,
125
- reportDataSuffix,
126
- collateral: attested.collateral,
127
- });
128
- if (!verified) {
129
- throw new Error('The attestation did not verify, so its transport key is not trusted');
130
- }
131
- return transportKey;
132
- }
133
- /**
134
- * {@link createSealedFetch} for a node you know only by URL: it attests the
135
- * node's transport key with `verify`, over `POST /admin-api/tee/attest` (the
136
- * one call that needs no credential and is never sealed), and seals everything
137
- * else to it. A restarted node is attested again, through the same verifier.
138
- *
139
- * This is what to hand a {@link RelayClient} for a TEE relay, so the warrant
140
- * and the method's arguments reach only the attested TD:
141
- *
142
- * ```ts
143
- * const relay = new RelayClient({
144
- * relayUrl,
145
- * fetch: createAttestedSealedFetch({ baseUrl: relayUrl, verify: createQuoteVerifier(...) }),
146
- * ...
147
- * });
148
- * ```
149
- */
150
- export function createAttestedSealedFetch(options) {
151
- const baseFetch = options.fetch ?? ((input, init) => fetch(input, init));
152
- const attestUrl = `${options.baseUrl.replace(/\/+$/, '')}/admin-api/tee/attest`;
153
- const admin = {
154
- async teeAttest(request) {
155
- const response = await baseFetch(attestUrl, {
156
- method: 'POST',
157
- headers: { 'content-type': 'application/json' },
158
- body: JSON.stringify(request),
159
- });
160
- if (!response.ok) {
161
- throw new Error(`The node refused to attest: HTTP ${response.status}`);
162
- }
163
- const body = (await response.json());
164
- if (!body.data)
165
- throw new Error('The attestation response is malformed');
166
- return body.data;
167
- },
168
- };
169
- return createSealedFetch({
170
- baseUrl: options.baseUrl,
171
- transportPublicKey: () => fetchAttestedTransportKey(admin, options.verify, {
172
- applicationId: options.applicationId,
173
- applicationHash: options.applicationHash,
174
- }),
175
- fetch: baseFetch,
176
- });
177
- }
178
96
  /**
179
97
  * A `fetch` that seals every request to the node's attested transport key.
180
- * Pass it as `MeroJsConfig.fetch`.
181
98
  *
182
99
  * A request for any URL outside `baseUrl` is refused rather than sent in the
183
100
  * clear: falling back to plaintext would silently undo the point of sealing.
@@ -239,13 +156,18 @@ export function createSealedFetch(options) {
239
156
  request.headers.forEach((value, name) => headers.push([name, value]));
240
157
  const head = { method: request.method, path: url.pathname.slice(basePath.length) + url.search, headers };
241
158
  const body = new Uint8Array(await request.arrayBuffer());
159
+ // The caller's own signal, not `request.signal`: a Request's signal follows
160
+ // the one it was built from only through a weak reference (undici), so once
161
+ // the Request is garbage collected (it is, while a stream stays open) an
162
+ // abort no longer reaches the fetch, and an event stream never closes.
163
+ const signal = init?.signal ?? (input instanceof Request ? input.signal : undefined);
242
164
  const send = async (open) => {
243
165
  const { requestId, header, envelope } = await sealRequest(open, head, body);
244
166
  const response = await baseFetch(`${nodeUrl}${SEALED_PATH}`, {
245
167
  method: 'POST',
246
168
  headers: { 'content-type': SEALED_CONTENT_TYPE },
247
169
  body: envelope,
248
- signal: request.signal,
170
+ signal,
249
171
  });
250
172
  if (response.headers.get('content-type') !== SEALED_CONTENT_TYPE) {
251
173
  throw await envelopeRefusal(response);
@@ -5,9 +5,8 @@
5
5
  * signatures against Intel's root, the TCB status of the platform, the
6
6
  * measurements of the image, and that its report data is the nonce and the
7
7
  * binding this client asked for. {@link createQuoteVerifier} does all of that
8
- * here, with nothing but the node: the node hands over the Intel-signed
9
- * collateral with its quote (`includeCollateral`), and a node cannot forge
10
- * collateral, only choose which valid collateral to serve.
8
+ * here. A Calimero 1.0 node sends no collateral: the verifier fetches Intel's
9
+ * (`fetchCollateral`), which the node can neither forge nor choose.
11
10
  *
12
11
  * The DCAP verification itself — parsing the quote, checking its signature
13
12
  * chain and appraising its TCB level against the collateral — comes from a
@@ -20,8 +19,7 @@ import type { VerifyTransportQuote } from './sealed.js';
20
19
  /**
21
20
  * The collateral a quote is verified against — TCB info, QE identity, CRLs and
22
21
  * their chains — in dcap-qvl's form: byte fields are hex strings or byte
23
- * arrays. What `/admin-api/tee/attest` returns with `includeCollateral`, and
24
- * what `@phala/dcap-qvl`'s `getCollateral` fetches.
22
+ * arrays. What `@phala/dcap-qvl`'s `getCollateral` fetches.
25
23
  */
26
24
  export interface DcapCollateral {
27
25
  pck_crl_issuer_chain: string;
@@ -87,16 +85,15 @@ export interface QuoteVerifierOptions {
87
85
  */
88
86
  allowedTcbStatuses?: string[];
89
87
  /**
90
- * Where to get collateral when the node sends none (it predates
91
- * `includeCollateral`): for example
88
+ * Where to get collateral (a Calimero 1.0 node sends none): for example
92
89
  * `(quote) => getCollateral(PHALA_PCCS_URL, quote)` from `@phala/dcap-qvl`.
93
- * Without it, such a node's quote is refused.
90
+ * Without it, a quote that came without collateral is refused.
94
91
  */
95
92
  fetchCollateral?: (quote: Uint8Array) => Promise<DcapCollateral>;
96
93
  /** The current time in milliseconds; defaults to `Date.now`. For tests. */
97
94
  now?: () => number;
98
95
  }
99
- /** A verifier for {@link fetchAttestedTransportKey}, which asks the node for collateral. */
96
+ /** A quote verifier as this package builds one ({@link createQuoteVerifier}). */
100
97
  export type QuoteVerifier = VerifyTransportQuote & {
101
98
  readonly includeCollateral: true;
102
99
  };
@@ -122,10 +119,7 @@ export type QuoteVerifier = VerifyTransportQuote & {
122
119
  * dcapVerify,
123
120
  * ...trustedMeasurementsFromReleases([publishedMrtds], { profile: 'locked-read-only' }),
124
121
  * });
125
- * const fetch = createSealedFetch({
126
- * baseUrl,
127
- * transportPublicKey: () => fetchAttestedTransportKey(admin, verifier),
128
- * });
122
+ * const client = new CalimeroClient({ baseUrl, policy: { verifyQuote: verifier } });
129
123
  * ```
130
124
  */
131
125
  export declare function createQuoteVerifier(options: QuoteVerifierOptions): QuoteVerifier;