@invisible-labs/sdk 0.6.0-devnet.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 (54) hide show
  1. package/README.md +210 -0
  2. package/dist/chunk-7DSVN3MV.js +1145 -0
  3. package/dist/chunk-7DSVN3MV.js.map +1 -0
  4. package/dist/chunk-JNNVPZEU.js +599 -0
  5. package/dist/chunk-JNNVPZEU.js.map +1 -0
  6. package/dist/chunk-JRMKCE3S.js +50 -0
  7. package/dist/chunk-JRMKCE3S.js.map +1 -0
  8. package/dist/chunk-LBC7ALYO.js +3783 -0
  9. package/dist/chunk-LBC7ALYO.js.map +1 -0
  10. package/dist/chunk-NCY4FCYU.js +1911 -0
  11. package/dist/chunk-NCY4FCYU.js.map +1 -0
  12. package/dist/chunk-OHIM2YWU.js +126 -0
  13. package/dist/chunk-OHIM2YWU.js.map +1 -0
  14. package/dist/chunk-SZAYO2L5.js +123 -0
  15. package/dist/chunk-SZAYO2L5.js.map +1 -0
  16. package/dist/chunk-TQNNTV5F.js +17 -0
  17. package/dist/chunk-TQNNTV5F.js.map +1 -0
  18. package/dist/chunk-VR6T6OJS.js +24 -0
  19. package/dist/chunk-VR6T6OJS.js.map +1 -0
  20. package/dist/chunk-XUWBGET5.js +221 -0
  21. package/dist/chunk-XUWBGET5.js.map +1 -0
  22. package/dist/coordinator-7Y45MCCZ.js +4 -0
  23. package/dist/coordinator-7Y45MCCZ.js.map +1 -0
  24. package/dist/createSession-D3ym-Ira.d.ts +177 -0
  25. package/dist/dkgWorker.d.ts +2 -0
  26. package/dist/dkgWorker.js +61 -0
  27. package/dist/dkgWorker.js.map +1 -0
  28. package/dist/events.d.ts +54 -0
  29. package/dist/events.js +143 -0
  30. package/dist/events.js.map +1 -0
  31. package/dist/frostRuntime-JESDHN6O.js +4 -0
  32. package/dist/frostRuntime-JESDHN6O.js.map +1 -0
  33. package/dist/index.d.ts +499 -0
  34. package/dist/index.js +132 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/lp.d.ts +388 -0
  37. package/dist/lp.js +1711 -0
  38. package/dist/lp.js.map +1 -0
  39. package/dist/presets.d.ts +43 -0
  40. package/dist/presets.js +70 -0
  41. package/dist/presets.js.map +1 -0
  42. package/dist/session-DFuy54C-.d.ts +31 -0
  43. package/dist/stats.d.ts +47 -0
  44. package/dist/stats.js +21 -0
  45. package/dist/stats.js.map +1 -0
  46. package/dist/storage.d.ts +82 -0
  47. package/dist/storage.js +246 -0
  48. package/dist/storage.js.map +1 -0
  49. package/dist/types-ZhV7TIQY.d.ts +76 -0
  50. package/dist/types.generated-CHGSbmLp.d.ts +67 -0
  51. package/dist/user.d.ts +377 -0
  52. package/dist/user.js +1225 -0
  53. package/dist/user.js.map +1 -0
  54. package/package.json +82 -0
@@ -0,0 +1,499 @@
1
+ import { S as Session } from './session-DFuy54C-.js';
2
+ export { i as isAttested } from './session-DFuy54C-.js';
3
+ export { A as AttestationError, a as AttestationErrorCode, b as CommandError, c as CommandErrorCode, d as CommandErrorOptions, e as CoordinatorWireErrorCode, C as CreateSessionOptions, I as InvalidDepositAmountError, f as InvisibleError, g as InvisibleErrorCode, h as InvisibleErrorOptions, L as LpLifecycleError, i as LpLifecycleErrorCode, N as NotImplementedError, j as NotImplementedErrorCode, P as PolicyValidationError, k as PolicyValidationErrorCode, R as RoutingError, l as RoutingErrorCode, S as StorageError, m as StorageErrorCode, T as TransportError, n as TransportErrorCode, W as WalletError, o as WalletErrorCode, p as closeSession, q as createSession, r as isInvisibleError, s as normalizeError } from './createSession-D3ym-Ira.js';
4
+ import { T as Transport, N as NoiseWebSocketTransportOptions, U as Unsubscribe } from './types-ZhV7TIQY.js';
5
+ export { C as ConnectionState, W as WebSocketFactory, a as WebSocketLike } from './types-ZhV7TIQY.js';
6
+ import { C as CoordinatorEndpoint, b as CoordinatorReleasePin } from './types.generated-CHGSbmLp.js';
7
+ export { A as AzureMaaPin, a as CoordinatorPoolConfig, L as LpPositionView, c as PayoutDestination, P as PayoutPolicy, S as StorageEnvelope } from './types.generated-CHGSbmLp.js';
8
+
9
+ /**
10
+ * The API surface version this build implements. Bumped only on a breaking
11
+ * surface change. See docs/sdk-specification.md section 12.
12
+ */
13
+ declare const apiVersion: "v0";
14
+ /** Literal type of {@link apiVersion}. */
15
+ type ApiVersion = typeof apiVersion;
16
+
17
+ /**
18
+ * Branded scalar types.
19
+ *
20
+ * Branding makes structurally-identical primitives (a lamport amount, a base58
21
+ * address, a correlation id) non-interchangeable at the type level, so the
22
+ * compiler catches "passed a request id where an address was expected" before
23
+ * it reaches the wire. The brand exists only at compile time; at runtime these
24
+ * are plain `number` / `string`.
25
+ *
26
+ * Construct branded values through the smart constructors here. These
27
+ * constructors enforce scalar-level invariants; payout-policy semantics stay in
28
+ * the validation module.
29
+ */
30
+ /** Attach a compile-time-only brand `B` to base type `T`. */
31
+ type Brand<T, B extends string> = T & {
32
+ readonly __brand: B;
33
+ };
34
+ /** A non-negative integer amount of lamports (1 SOL = 1_000_000_000 lamports). */
35
+ type Lamports = Brand<number, "Lamports">;
36
+ /** A Solana account address as base58 text. */
37
+ type PublicKey = Brand<string, "PublicKey">;
38
+ /** A client-generated correlation id for one logical command. */
39
+ type RequestId = Brand<string, "RequestId">;
40
+ /** Lowercase hexadecimal text (no `0x` prefix). */
41
+ type Hex = Brand<string, "Hex">;
42
+ /**
43
+ * Brand a number as {@link Lamports}.
44
+ *
45
+ * @throws PolicyValidationError `INVALID_AMOUNT` if not a non-negative safe integer.
46
+ */
47
+ declare function lamports(value: number): Lamports;
48
+ /**
49
+ * Brand a string as a {@link PublicKey}.
50
+ *
51
+ * Enforces canonical base58 encoding of a 32-byte Solana public key.
52
+ *
53
+ * @throws PolicyValidationError `INVALID_DESTINATION_ADDRESS` if obviously malformed.
54
+ */
55
+ declare function publicKey(value: string): PublicKey;
56
+ /**
57
+ * Brand a non-empty string as a {@link RequestId}.
58
+ *
59
+ * @throws PolicyValidationError `INVALID_AMOUNT` is not appropriate here; an empty
60
+ * id is a programming error, so this throws a plain `Error`.
61
+ */
62
+ declare function requestId(value: string): RequestId;
63
+ /**
64
+ * Brand a string as lowercase {@link Hex}.
65
+ *
66
+ * @throws Error if the string contains non-hex characters.
67
+ */
68
+ declare function hex(value: string): Hex;
69
+
70
+ interface ExponentialBackoffOptions {
71
+ readonly initialDelayMs: number;
72
+ readonly maxDelayMs: number;
73
+ readonly multiplier?: number;
74
+ readonly jitterRatio?: number;
75
+ readonly random?: () => number;
76
+ }
77
+ interface ExponentialBackoff {
78
+ nextDelayMs(): number;
79
+ reset(): void;
80
+ }
81
+ /**
82
+ * Stateful exponential backoff shared by reconnecting SDK consumers.
83
+ * Jitter avoids synchronized reconnect storms while reset makes a healthy
84
+ * connection return to the normal cadence.
85
+ */
86
+ declare function createExponentialBackoff(options: ExponentialBackoffOptions): ExponentialBackoff;
87
+
88
+ /**
89
+ * In-memory transport.
90
+ *
91
+ * A zero-network channel used by unit tests. It transitions straight to `open`
92
+ * on connect. `send` delivers the raw frame bytes to an optional peer sink: the
93
+ * WebSocket message boundary is the frame boundary, so there is no extra length
94
+ * prefix (matching the production transport). Noise lives above this pure byte
95
+ * channel, never inside it.
96
+ *
97
+ * With no peer wired in, `send` is a silent no-op (legacy stub behaviour for
98
+ * tests that never exchange frames). A paired loopback coordinator supplies a
99
+ * `peer` sink so a real Noise XX handshake can run in-process (see the
100
+ * `testLoopback` fixture).
101
+ */
102
+
103
+ /** Options for {@link inMemoryTransport}. Test-only paired-loopback wiring. */
104
+ interface InMemoryTransportOptions {
105
+ /**
106
+ * Sink for frames written via `send()`. A paired in-process coordinator sets
107
+ * this so the client's raw bytes reach the responder. When omitted, `send`
108
+ * is a no-op so legacy stub-only tests keep working.
109
+ */
110
+ readonly peer?: (frame: Uint8Array) => void;
111
+ }
112
+ /** In-memory transport with a hook to feed inbound frames into `onMessage`. */
113
+ interface InMemoryTransportHandle extends Transport {
114
+ /** Deliver a frame to this transport's `onMessage` listeners (peer -> client). */
115
+ readonly deliver: (frame: Uint8Array) => void;
116
+ }
117
+ declare function inMemoryTransport(options?: InMemoryTransportOptions): InMemoryTransportHandle;
118
+
119
+ /**
120
+ * WebSocket transport - the one genuinely functional piece of the skeleton.
121
+ *
122
+ * `connect()` opens a real WebSocket and drives the lifecycle
123
+ * (`connecting -> open`, `-> closed` on close/error/abort). It is a pure byte
124
+ * channel: the Noise XX handshake and TDX attestation are session-level steps
125
+ * layered on top (see ./handshake), not part of opening the socket. `send`
126
+ * writes one raw frame to the socket; the WebSocket message boundary is the
127
+ * frame boundary, so there is no extra length prefix (Noise lives above).
128
+ *
129
+ * The WebSocket implementation is injected (default: the platform global
130
+ * `WebSocket`, present in browsers and Node 22+), so tests connect to a local
131
+ * mock server with no external network.
132
+ */
133
+
134
+ declare function noiseWebSocketTransport(options: NoiseWebSocketTransportOptions): Transport;
135
+
136
+ /**
137
+ * TDX DCAP attestation verifier (SDK port of
138
+ * `web/src/lib/coordinator/tdx-attestation.ts`).
139
+ *
140
+ * Verifies a TDX DCAP quote on three paths, using Web Crypto (`crypto.subtle`,
141
+ * a Node 22 / browser global) and `@peculiar/x509`:
142
+ *
143
+ * - GCP (spec section 5.1): cert chain to the pinned Intel SGX Root CA, TCB
144
+ * validity, freshness nonce == REPORT_DATA[0:32], Noise binding ==
145
+ * REPORT_DATA[32:64], debug bit clear, MRTD pin.
146
+ * - Azure (spec section 5.2): MAA JWT issuer / JWKS / policy-hash / compliance
147
+ * / debug, MAA<->DCAP REPORTDATA binding, hcl_keys hash binding, HCL AK pub
148
+ * extraction, raw DCAP measurement binding, TPM AK quote signature, TPM
149
+ * qualifying data binding.
150
+ * - Local (loopback dev fallback): checks nonce and Noise pubkey consistency
151
+ * only; no hardware attestation.
152
+ *
153
+ * Throws the SDK {@link AttestationError} (from `../core/errors.js`) with a
154
+ * closed `code` on any failure. Callers fail-closed: tear down the Noise
155
+ * transport rather than surface an unverified channel.
156
+ *
157
+ * Never log secrets, nonces, or raw decrypted payloads (spec section 9).
158
+ *
159
+ * @module JW-145 / JW-431
160
+ */
161
+ type AttestationMode = "dev" | "prod";
162
+ type AzureMaaPolicy = {
163
+ /** Expected MAA token issuer for the approved Azure Attestation provider. */
164
+ expectedIssuer: string;
165
+ /** Expected JWKS endpoint for that provider. Token headers must not choose it. */
166
+ expectedJwksUrl: string;
167
+ /** Expected Azure Attestation evaluation policy hash from the signed token. */
168
+ expectedPolicyHash: string;
169
+ };
170
+ type AttestationPolicy = {
171
+ /**
172
+ * Expected MRTD for the published production coordinator build.
173
+ * Dev mode ignores this pin entirely.
174
+ */
175
+ expectedMrtd?: string;
176
+ /**
177
+ * SHA-256 hash of the approved coordinator binary. Azure production
178
+ * attestation requires this pin because binary_hash is otherwise only
179
+ * response metadata, even though the TPM quote binds it cryptographically.
180
+ */
181
+ expectedBinaryHash?: string;
182
+ /**
183
+ * Runtime mode the client expects for this coordinator route. Production
184
+ * builds set this to "prod" so a prod hostname cannot silently accept an
185
+ * unpinned dev coordinator after DNS or load-balancer misrouting.
186
+ */
187
+ requiredMode?: AttestationMode;
188
+ /**
189
+ * Release tooling only: verify a prod quote before the new MRTD has been
190
+ * published. Runtime policy must leave this unset so prod stays fail-closed
191
+ * when the pin is missing.
192
+ */
193
+ allowUnpinnedProdMrtdForRelease?: boolean;
194
+ /**
195
+ * SHA-256 fingerprint (lowercase hex) of the DER-encoded Intel SGX Root CA.
196
+ * Defaults to {@link INTEL_SGX_ROOT_CA_FINGERPRINT_SHA256}. Override only in tests.
197
+ */
198
+ intelRootFingerprint?: string;
199
+ /**
200
+ * Temporary non-prod rollout escape hatch for legacy coordinators that have
201
+ * not rolled out `dcap_collateral`. When collateral is present, it is always
202
+ * verified. Production mode never honors this flag.
203
+ */
204
+ allowMissingDcapCollateral?: boolean;
205
+ /**
206
+ * Development-only escape hatch for a local coordinator running on a non-TDX
207
+ * machine. The transport only honors this for loopback coordinator URLs.
208
+ */
209
+ allowLocalAttestation?: boolean;
210
+ /**
211
+ * Azure-specific trust policy. Required for platform="azure-tdx-dcap" because
212
+ * MAA providers and policies are customer-configurable Azure resources.
213
+ */
214
+ azureMaa?: AzureMaaPolicy;
215
+ };
216
+ type SignedDcapJson = {
217
+ /**
218
+ * JSON string returned by Intel PCS. May be either the inner body
219
+ * (`tcbInfo` / `enclaveIdentity`) or the full PCS wrapper.
220
+ */
221
+ body: string;
222
+ /** Hex signature over the exact signed body bytes. */
223
+ signature: string;
224
+ /** PEM chain whose first certificate verifies `signature`, ending at Intel root. */
225
+ issuerChainPem: string;
226
+ };
227
+ type DcapCollateral = {
228
+ /** PEM X.509 CRL for the PCK certificate issuer. */
229
+ pckCrlPem: string;
230
+ /** PEM chain for the PCK CRL issuer, ending at Intel root. */
231
+ pckCrlIssuerChainPem: string;
232
+ /** PEM X.509 CRL issued by Intel root, covering collateral signing certs. */
233
+ rootCaCrlPem: string;
234
+ /** Signed Intel TDX TCB Info V3. */
235
+ tcbInfo: SignedDcapJson;
236
+ /** Signed Intel TD QE Identity V2. */
237
+ qeIdentity: SignedDcapJson;
238
+ };
239
+ type AttestedMetadata = {
240
+ mode: AttestationMode;
241
+ binaryHash: string;
242
+ mrtd: string;
243
+ rtmr0: string;
244
+ rtmr1: string;
245
+ rtmr2: string;
246
+ rtmr3: string;
247
+ pubkeyHex: string;
248
+ localAttestation: boolean;
249
+ };
250
+ type AttestResponse = {
251
+ quote: string;
252
+ /**
253
+ * Nonce echoed back by the coordinator. Informational only: freshness is
254
+ * enforced cryptographically via REPORT_DATA[0:32] inside the TDX quote, not
255
+ * by trusting this JSON field.
256
+ */
257
+ nonce: string;
258
+ pubkey: string;
259
+ binary_hash: string;
260
+ mode: AttestationMode;
261
+ /**
262
+ * Platform identifier set by the coordinator. Absent on GCP (tdx-dcap).
263
+ * Azure returns "azure-tdx-dcap".
264
+ */
265
+ platform?: string;
266
+ /**
267
+ * Azure only: MAA JWT from /attest/TdxVm, RS256-signed by MAA. Contains
268
+ * tdx_mrtd, tdx_td_attributes_debug, and x-ms-compliance-status.
269
+ */
270
+ maa_token?: string;
271
+ /**
272
+ * Azure only: TPM PCR quote packed as
273
+ * [4-byte msg_len LE][TPM2B_ATTEST][TPMT_SIGNATURE].
274
+ * qualifying_data = SHA-256(nonce || noise_pubkey || binary_hash). Base64-encoded.
275
+ */
276
+ tpm_quote?: string;
277
+ /**
278
+ * Azure only: raw bytes (base64) of the JSON key-blob from HCL report NV
279
+ * 0x1400001 [1056:]. SHA-256(hcl_keys_json_bytes) == DCAP REPORTDATA[0:32].
280
+ * Contains the AK public key as kid="HCLAkPub".
281
+ */
282
+ hcl_keys_json?: string;
283
+ /**
284
+ * Intel DCAP verification collateral. When present, the verifier evaluates
285
+ * PCK revocation, TCB Info, and TD QE Identity. Policies can require it.
286
+ */
287
+ dcap_collateral?: DcapCollateral;
288
+ local_attestation?: boolean;
289
+ };
290
+ /**
291
+ * Assert that an unknown JSON value has the shape of {@link AttestResponse}.
292
+ * Throws {@link AttestationError} ("NOT_ATTESTED") on any missing or wrong-typed
293
+ * field. Replaces an unsafe cast so missing fields produce a typed error rather
294
+ * than silently reaching downstream checks as `undefined`.
295
+ */
296
+ declare function assertAttestResponse(value: unknown): asserts value is AttestResponse;
297
+ declare function verifyAttestation(params: {
298
+ response: AttestResponse;
299
+ expectedNonce: Uint8Array;
300
+ expectedNoiseStaticPub: Uint8Array;
301
+ policy: AttestationPolicy;
302
+ timeoutMs?: number;
303
+ }): Promise<AttestedMetadata>;
304
+
305
+ /**
306
+ * Secure channel: Noise XX handshake + TDX attestation over a raw transport.
307
+ *
308
+ * Free functions, no class (SDK conformance). Given an open {@link Transport}
309
+ * and a {@link CoordinatorEndpoint}, {@link establishSecureChannel} drives:
310
+ *
311
+ * 1. the Noise XX handshake (initiator role) over the raw byte channel:
312
+ * -> msg1 (e) send raw
313
+ * <- msg2 (e, ee, s, es) read raw, reveals the responder static pubkey
314
+ * -> msg3 (s, se) send raw, yields the split NoiseTransport
315
+ * 2. the attestation exchange over the freshly-split (but not-yet-promoted)
316
+ * Noise transport:
317
+ * -> encrypt(encodeAttestationRequest(nonceHex))
318
+ * <- decodeAttestationResponse(decrypt(frame)) -> verifyAttestation
319
+ *
320
+ * On success the pending Noise transport is promoted to the live cipher and an
321
+ * attested channel handle is returned: `send`/`onMessage` transparently
322
+ * Noise-encrypt/decrypt application frames over the raw transport.
323
+ *
324
+ * The release pin (mrtd, intelRootFingerprint, azureMaa) and the endpoint's
325
+ * requiredMode map to the verifier's {@link AttestationPolicy}. The loopback
326
+ * local-attestation fallback (ADR-0037) is only enabled when the endpoint host
327
+ * is a loopback address - it must never be honored for a remote coordinator.
328
+ *
329
+ * Never log secrets, nonces, shares, or decrypted payloads (spec section 9).
330
+ *
331
+ * @module JW-428
332
+ */
333
+
334
+ /** An established, attested Noise channel over a raw transport. */
335
+ interface SecureChannel {
336
+ /** Verified attestation metadata for the coordinator this channel reached. */
337
+ readonly attestation: AttestedMetadata;
338
+ /** The coordinator's Noise static public key, pinned for this channel. */
339
+ readonly remoteStaticPublicKey: Uint8Array;
340
+ /** Request re-attestation without consuming application frames as responses. */
341
+ requestAttestation(nonceHex: string, timeoutMs: number): Promise<AttestResponse>;
342
+ /** Encrypt and send one application frame over the raw transport. */
343
+ send(plaintext: Uint8Array): void;
344
+ /** Subscribe to decrypted inbound application frames. */
345
+ onMessage(handler: (plaintext: Uint8Array) => void): Unsubscribe;
346
+ /** Subscribe to fatal channel failures such as Noise decrypt desync. */
347
+ onFatal(handler: (error: Error) => void): Unsubscribe;
348
+ /** Tear down the channel: detach listeners and stop accepting frames. */
349
+ close(): void;
350
+ }
351
+
352
+ /**
353
+ * Session-establishment seams layered on top of an open {@link Transport}.
354
+ *
355
+ * Once a socket is open, a session runs the Noise XX handshake and then TDX
356
+ * attestation before any sensitive command is allowed. The real logic lives in
357
+ * the secure-channel module (`../session/secureChannel`); these functions are
358
+ * the stable, transport-level entrypoints the root index re-exports.
359
+ *
360
+ * Both halves are driven from one underlying {@link establishSecureChannel}
361
+ * run, because attestation is requested over the same Noise cipher the
362
+ * handshake split. {@link performNoiseHandshake} runs that establishment and
363
+ * caches the resulting channel keyed on the transport; {@link performAttestation}
364
+ * reads the attestation evidence from it. Callers that want the whole flow in
365
+ * one step should use {@link establishAttestedChannel}.
366
+ */
367
+
368
+ /** Result of a completed Noise XX handshake. */
369
+ interface NoiseHandshakeResult {
370
+ /** The coordinator's Noise static public key, pinned for this session. */
371
+ readonly noiseStaticPublicKey: Uint8Array;
372
+ /**
373
+ * The attested secure channel produced by this handshake. Carried so a
374
+ * subsequent {@link performAttestation} can read attestation evidence without
375
+ * re-running the exchange. Internal: not part of the structural contract.
376
+ */
377
+ readonly channel: SecureChannel;
378
+ }
379
+ /** Result of a completed TDX attestation. */
380
+ interface AttestationResult {
381
+ /** The verified release MRTD. */
382
+ readonly mrtd: string;
383
+ /** Attestation mode the coordinator reported. */
384
+ readonly mode: "prod" | "dev";
385
+ /** Coordinator binary hash reported by the verified attestation response. */
386
+ readonly binaryHash: string;
387
+ /** Noise static public key bound into the attestation quote. */
388
+ readonly pubkeyHex: string;
389
+ /** True only for explicit loopback local development attestation. */
390
+ readonly localAttestation: boolean;
391
+ readonly rtmr0?: string;
392
+ readonly rtmr1?: string;
393
+ readonly rtmr2?: string;
394
+ readonly rtmr3?: string;
395
+ /** When verification completed (epoch ms), stamped by the caller. */
396
+ readonly verifiedAtMs: number;
397
+ }
398
+ /**
399
+ * Run the Noise XX handshake over an open transport and pin the coordinator's
400
+ * static key. Drives a full attested-channel establishment (attestation is
401
+ * bound to the same Noise cipher) and returns the handshake half; read the
402
+ * attestation half from {@link performAttestation} with the returned result.
403
+ *
404
+ * @throws TransportError if the channel fails or the handshake is malformed.
405
+ * @throws AttestationError if attestation verification fails.
406
+ */
407
+ declare function performNoiseHandshake(transport: Transport, endpoint: CoordinatorEndpoint, nonce?: Uint8Array): Promise<NoiseHandshakeResult>;
408
+ /**
409
+ * Verify the coordinator's TDX attestation, bound to the handshake's Noise
410
+ * static key. Reads the evidence captured by {@link performNoiseHandshake}.
411
+ *
412
+ * @throws TransportError if the handshake result carries no channel.
413
+ */
414
+ declare function performAttestation(_transport: Transport, handshake: NoiseHandshakeResult): Promise<AttestationResult>;
415
+
416
+ /**
417
+ * Session guards used by mutating commands.
418
+ */
419
+
420
+ /**
421
+ * Assert the session has passed attestation. Every mutating actor command calls
422
+ * this before touching the wire, so an unattested session can never sign or
423
+ * send sensitive material.
424
+ *
425
+ * @throws AttestationError `NOT_ATTESTED` when the session is not attested.
426
+ */
427
+ declare function assertAttested(session: Session): void;
428
+
429
+ /**
430
+ * `attestation` - read controls and verification triggers (spec section 4.1).
431
+ *
432
+ * Grouped as a small object of free functions over the opaque `Session`. The
433
+ * read accessors (`current`, `policy`) report the last verified result and the
434
+ * active pin; `assertValid` re-runs attestation over the live channel and
435
+ * `onPolicyViolation` subscribes to out-of-band re-attestation failures.
436
+ */
437
+
438
+ declare const attestation: {
439
+ /**
440
+ * Force-verify the current session against the active policy by re-running
441
+ * attestation over the live channel. Updates the stored result on success.
442
+ *
443
+ * @throws AttestationError if verification fails.
444
+ * @throws TransportError if the session has no live attested channel.
445
+ */
446
+ assertValid(session: Session): Promise<AttestationResult>;
447
+ /** The last verified attestation result, or `null` before first attestation. */
448
+ current(session: Session): AttestationResult | null;
449
+ /** The release pin the active leader endpoint is verified against. Read-only. */
450
+ policy(session: Session): CoordinatorReleasePin;
451
+ /**
452
+ * Subscribe to out-of-band attestation failures (e.g. during periodic
453
+ * re-attestation). The handler fires with the verification error; returns an
454
+ * unsubscribe function.
455
+ */
456
+ onPolicyViolation(session: Session, handler: (error: Error) => void): Unsubscribe;
457
+ };
458
+
459
+ /**
460
+ * `coordinator` - endpoint pool inspection and failover (spec section 4.2).
461
+ *
462
+ * `endpoints` is a read accessor that works today. Leader discovery, version
463
+ * reporting, and failover depend on the coordinator network surface and are
464
+ * deferred (marked 🟡 V0-target in the spec).
465
+ */
466
+
467
+ /** Coordinator-reported version and role snapshot. */
468
+ interface CoordinatorVersion {
469
+ readonly mode: "prod" | "dev";
470
+ readonly protocolVersion: string;
471
+ readonly schemaVersion: string;
472
+ readonly hostname: string;
473
+ readonly leaderEpoch: number;
474
+ }
475
+ declare const coordinator: {
476
+ /** All configured endpoints, in the order supplied. Read-only. */
477
+ endpoints(session: Session): readonly CoordinatorEndpoint[];
478
+ /**
479
+ * The endpoint currently accepting mutating commands.
480
+ *
481
+ * @throws NotImplementedError - deferred (coordinator-pending).
482
+ */
483
+ currentLeader(_session: Session): Promise<CoordinatorEndpoint | null>;
484
+ /**
485
+ * The coordinator-reported version snapshot.
486
+ *
487
+ * @throws NotImplementedError - deferred (coordinator-pending).
488
+ */
489
+ version(_session: Session): Promise<CoordinatorVersion>;
490
+ /**
491
+ * Tear down the active session and reconnect through the next healthy
492
+ * endpoint, forcing a fresh attestation.
493
+ *
494
+ * @throws NotImplementedError - deferred (coordinator-pending).
495
+ */
496
+ forceFailover(_session: Session): Promise<void>;
497
+ };
498
+
499
+ export { type ApiVersion, type AttestResponse, type AttestationMode, type AttestationPolicy, type AttestationResult, type AzureMaaPolicy, type Brand, CoordinatorEndpoint, CoordinatorReleasePin, type CoordinatorVersion, type ExponentialBackoff, type ExponentialBackoffOptions, type Hex, type Lamports, type NoiseHandshakeResult, NoiseWebSocketTransportOptions, type PublicKey, type RequestId, Session, Transport, Unsubscribe, apiVersion, assertAttestResponse, assertAttested, attestation, coordinator, createExponentialBackoff, hex, inMemoryTransport, lamports, noiseWebSocketTransport, performAttestation, performNoiseHandshake, publicKey, requestId, verifyAttestation };
package/dist/index.js ADDED
@@ -0,0 +1,132 @@
1
+ import { createStateController, reattestSerialized } from './chunk-7DSVN3MV.js';
2
+ export { closeSession, createExponentialBackoff, createSession, noiseWebSocketTransport, performAttestation, performNoiseHandshake } from './chunk-7DSVN3MV.js';
3
+ export { assertAttested, hex, lamports, publicKey, requestId } from './chunk-SZAYO2L5.js';
4
+ import { getSessionState, failSessionClosed } from './chunk-JRMKCE3S.js';
5
+ export { assertAttestResponse, verifyAttestation } from './chunk-NCY4FCYU.js';
6
+ import { TransportError, NotImplementedError } from './chunk-OHIM2YWU.js';
7
+ export { AttestationError, CommandError, InvalidDepositAmountError, InvisibleError, LpLifecycleError, NotImplementedError, PolicyValidationError, RoutingError, StorageError, TransportError, WalletError, isInvisibleError, normalizeError } from './chunk-OHIM2YWU.js';
8
+ import './chunk-VR6T6OJS.js';
9
+
10
+ // src/core/version.ts
11
+ var apiVersion = "v0";
12
+
13
+ // src/core/session.ts
14
+ function isAttested(session) {
15
+ return session.attested;
16
+ }
17
+
18
+ // src/transport/inMemoryTransport.ts
19
+ function inMemoryTransport(options = {}) {
20
+ const sc = createStateController("idle");
21
+ const messageListeners = /* @__PURE__ */ new Set();
22
+ return {
23
+ state: () => sc.get(),
24
+ onStateChange: (listener) => sc.onChange(listener),
25
+ onMessage(listener) {
26
+ messageListeners.add(listener);
27
+ return () => messageListeners.delete(listener);
28
+ },
29
+ deliver(frame) {
30
+ for (const listener of messageListeners) listener(frame);
31
+ },
32
+ async connect(signal) {
33
+ if (signal?.aborted) {
34
+ throw new TransportError("CONNECTION_LOST", "connect aborted before it started");
35
+ }
36
+ if (sc.get() === "open") return;
37
+ sc.set("connecting");
38
+ sc.set("open");
39
+ },
40
+ send(frame) {
41
+ if (sc.get() !== "open") {
42
+ throw new TransportError("CONNECTION_LOST", "cannot send on a non-open transport");
43
+ }
44
+ options.peer?.(frame);
45
+ },
46
+ close() {
47
+ if (sc.get() === "closed") return;
48
+ sc.set("closing");
49
+ sc.set("closed");
50
+ }
51
+ };
52
+ }
53
+
54
+ // src/attestation/index.ts
55
+ var attestation = {
56
+ /**
57
+ * Force-verify the current session against the active policy by re-running
58
+ * attestation over the live channel. Updates the stored result on success.
59
+ *
60
+ * @throws AttestationError if verification fails.
61
+ * @throws TransportError if the session has no live attested channel.
62
+ */
63
+ async assertValid(session) {
64
+ const state = getSessionState(session);
65
+ const endpoint = state.pool.endpoints[0];
66
+ try {
67
+ const result = await reattestSerialized(state, endpoint, state.pool.noiseTransportTimeoutMs);
68
+ state.attestation = result;
69
+ state.attested = true;
70
+ return result;
71
+ } catch (err) {
72
+ const error = err instanceof Error ? err : new Error(String(err));
73
+ failSessionClosed(state, error);
74
+ throw error;
75
+ }
76
+ },
77
+ /** The last verified attestation result, or `null` before first attestation. */
78
+ current(session) {
79
+ return getSessionState(session).attestation;
80
+ },
81
+ /** The release pin the active leader endpoint is verified against. Read-only. */
82
+ policy(session) {
83
+ return getSessionState(session).pool.endpoints[0].releasePin;
84
+ },
85
+ /**
86
+ * Subscribe to out-of-band attestation failures (e.g. during periodic
87
+ * re-attestation). The handler fires with the verification error; returns an
88
+ * unsubscribe function.
89
+ */
90
+ onPolicyViolation(session, handler) {
91
+ const handlers = getSessionState(session).policyViolationHandlers;
92
+ handlers.add(handler);
93
+ return () => handlers.delete(handler);
94
+ }
95
+ };
96
+
97
+ // src/coordinator/index.ts
98
+ var coordinator = {
99
+ /** All configured endpoints, in the order supplied. Read-only. */
100
+ endpoints(session) {
101
+ return getSessionState(session).pool.endpoints;
102
+ },
103
+ /**
104
+ * The endpoint currently accepting mutating commands.
105
+ *
106
+ * @throws NotImplementedError - deferred (coordinator-pending).
107
+ */
108
+ currentLeader(_session) {
109
+ return Promise.reject(new NotImplementedError("coordinator.currentLeader"));
110
+ },
111
+ /**
112
+ * The coordinator-reported version snapshot.
113
+ *
114
+ * @throws NotImplementedError - deferred (coordinator-pending).
115
+ */
116
+ version(_session) {
117
+ return Promise.reject(new NotImplementedError("coordinator.version"));
118
+ },
119
+ /**
120
+ * Tear down the active session and reconnect through the next healthy
121
+ * endpoint, forcing a fresh attestation.
122
+ *
123
+ * @throws NotImplementedError - deferred (coordinator-pending).
124
+ */
125
+ forceFailover(_session) {
126
+ return Promise.reject(new NotImplementedError("coordinator.forceFailover"));
127
+ }
128
+ };
129
+
130
+ export { apiVersion, attestation, coordinator, inMemoryTransport, isAttested };
131
+ //# sourceMappingURL=index.js.map
132
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/version.ts","../src/core/session.ts","../src/transport/inMemoryTransport.ts","../src/attestation/index.ts","../src/coordinator/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The API surface version this build implements. Bumped only on a breaking\n * surface change. See docs/sdk-specification.md section 12.\n */\nexport const apiVersion = \"v0\" as const;\n\n/** Literal type of {@link apiVersion}. */\nexport type ApiVersion = typeof apiVersion;\n","/**\n * The opaque session handle.\n *\n * A `Session` is the single stateful object the functional surface threads\n * through every call: `fn(session, args)`. It owns the transport, the\n * attestation state, and (later) the leader-epoch bookkeeping. Consumers treat\n * it as opaque - they read `session.attested` and pass it back to SDK\n * functions, but never reach inside. The internal state map and constructor\n * live alongside `createSession` (added in a later ticket); this module only\n * fixes the public shape so the rest of the surface can type against it.\n */\n\ndeclare const sessionBrand: unique symbol;\n\n/**\n * Opaque, attested session handle. Obtain one from `createSession`; pass it as\n * the first argument to every actor command. The only field consumers read is\n * {@link Session.attested}.\n */\nexport interface Session {\n /**\n * Whether the current Noise session has passed full TDX attestation. Sensitive\n * commands refuse to run until this is `true`. Re-handshake or failover resets\n * it to `false` until a fresh attestation completes.\n */\n readonly attested: boolean;\n /** @internal Opacity brand; not constructable by consumers. */\n readonly [sessionBrand]: true;\n}\n\n/** Convenience predicate mirroring {@link Session.attested}. */\nexport function isAttested(session: Session): boolean {\n return session.attested;\n}\n","/**\n * In-memory transport.\n *\n * A zero-network channel used by unit tests. It transitions straight to `open`\n * on connect. `send` delivers the raw frame bytes to an optional peer sink: the\n * WebSocket message boundary is the frame boundary, so there is no extra length\n * prefix (matching the production transport). Noise lives above this pure byte\n * channel, never inside it.\n *\n * With no peer wired in, `send` is a silent no-op (legacy stub behaviour for\n * tests that never exchange frames). A paired loopback coordinator supplies a\n * `peer` sink so a real Noise XX handshake can run in-process (see the\n * `testLoopback` fixture).\n */\n\nimport { TransportError } from \"../core/errors.js\";\nimport { createStateController } from \"./stateController.js\";\nimport type { Transport, Unsubscribe } from \"./types.js\";\n\n/** Options for {@link inMemoryTransport}. Test-only paired-loopback wiring. */\nexport interface InMemoryTransportOptions {\n /**\n * Sink for frames written via `send()`. A paired in-process coordinator sets\n * this so the client's raw bytes reach the responder. When omitted, `send`\n * is a no-op so legacy stub-only tests keep working.\n */\n readonly peer?: (frame: Uint8Array) => void;\n}\n\n/** In-memory transport with a hook to feed inbound frames into `onMessage`. */\nexport interface InMemoryTransportHandle extends Transport {\n /** Deliver a frame to this transport's `onMessage` listeners (peer -> client). */\n readonly deliver: (frame: Uint8Array) => void;\n}\n\nexport function inMemoryTransport(options: InMemoryTransportOptions = {}): InMemoryTransportHandle {\n const sc = createStateController(\"idle\");\n const messageListeners = new Set<(frame: Uint8Array) => void>();\n\n return {\n state: () => sc.get(),\n onStateChange: (listener) => sc.onChange(listener),\n onMessage(listener): Unsubscribe {\n messageListeners.add(listener);\n return () => messageListeners.delete(listener);\n },\n deliver(frame: Uint8Array): void {\n for (const listener of messageListeners) listener(frame);\n },\n async connect(signal) {\n if (signal?.aborted) {\n throw new TransportError(\"CONNECTION_LOST\", \"connect aborted before it started\");\n }\n if (sc.get() === \"open\") return;\n sc.set(\"connecting\");\n sc.set(\"open\");\n },\n send(frame: Uint8Array): void {\n if (sc.get() !== \"open\") {\n throw new TransportError(\"CONNECTION_LOST\", \"cannot send on a non-open transport\");\n }\n options.peer?.(frame);\n },\n close() {\n if (sc.get() === \"closed\") return;\n sc.set(\"closing\");\n sc.set(\"closed\");\n },\n };\n}\n","/**\n * `attestation` - read controls and verification triggers (spec section 4.1).\n *\n * Grouped as a small object of free functions over the opaque `Session`. The\n * read accessors (`current`, `policy`) report the last verified result and the\n * active pin; `assertValid` re-runs attestation over the live channel and\n * `onPolicyViolation` subscribes to out-of-band re-attestation failures.\n */\n\nimport type { Session } from \"../core/session.js\";\nimport type { Unsubscribe } from \"../transport/types.js\";\nimport type { AttestationResult } from \"../transport/handshake.js\";\nimport type { CoordinatorReleasePin } from \"../schemas/types.generated.js\";\nimport { failSessionClosed, getSessionState } from \"../session/state.js\";\nimport { reattestSerialized } from \"./reattest.js\";\n\nexport const attestation = {\n /**\n * Force-verify the current session against the active policy by re-running\n * attestation over the live channel. Updates the stored result on success.\n *\n * @throws AttestationError if verification fails.\n * @throws TransportError if the session has no live attested channel.\n */\n async assertValid(session: Session): Promise<AttestationResult> {\n const state = getSessionState(session);\n const endpoint = state.pool.endpoints[0]!;\n try {\n const result = await reattestSerialized(state, endpoint, state.pool.noiseTransportTimeoutMs);\n state.attestation = result;\n state.attested = true;\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n failSessionClosed(state, error);\n throw error;\n }\n },\n\n /** The last verified attestation result, or `null` before first attestation. */\n current(session: Session): AttestationResult | null {\n return getSessionState(session).attestation;\n },\n\n /** The release pin the active leader endpoint is verified against. Read-only. */\n policy(session: Session): CoordinatorReleasePin {\n return getSessionState(session).pool.endpoints[0]!.releasePin;\n },\n\n /**\n * Subscribe to out-of-band attestation failures (e.g. during periodic\n * re-attestation). The handler fires with the verification error; returns an\n * unsubscribe function.\n */\n onPolicyViolation(session: Session, handler: (error: Error) => void): Unsubscribe {\n const handlers = getSessionState(session).policyViolationHandlers;\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n};\n","/**\n * `coordinator` - endpoint pool inspection and failover (spec section 4.2).\n *\n * `endpoints` is a read accessor that works today. Leader discovery, version\n * reporting, and failover depend on the coordinator network surface and are\n * deferred (marked 🟡 V0-target in the spec).\n */\n\nimport { NotImplementedError } from \"../core/errors.js\";\nimport type { Session } from \"../core/session.js\";\nimport type { CoordinatorEndpoint } from \"../schemas/types.generated.js\";\nimport { getSessionState } from \"../session/state.js\";\n\n/** Coordinator-reported version and role snapshot. */\nexport interface CoordinatorVersion {\n readonly mode: \"prod\" | \"dev\";\n readonly protocolVersion: string;\n readonly schemaVersion: string;\n readonly hostname: string;\n readonly leaderEpoch: number;\n}\n\nexport const coordinator = {\n /** All configured endpoints, in the order supplied. Read-only. */\n endpoints(session: Session): readonly CoordinatorEndpoint[] {\n return getSessionState(session).pool.endpoints;\n },\n\n /**\n * The endpoint currently accepting mutating commands.\n *\n * @throws NotImplementedError - deferred (coordinator-pending).\n */\n currentLeader(_session: Session): Promise<CoordinatorEndpoint | null> {\n return Promise.reject(new NotImplementedError(\"coordinator.currentLeader\"));\n },\n\n /**\n * The coordinator-reported version snapshot.\n *\n * @throws NotImplementedError - deferred (coordinator-pending).\n */\n version(_session: Session): Promise<CoordinatorVersion> {\n return Promise.reject(new NotImplementedError(\"coordinator.version\"));\n },\n\n /**\n * Tear down the active session and reconnect through the next healthy\n * endpoint, forcing a fresh attestation.\n *\n * @throws NotImplementedError - deferred (coordinator-pending).\n */\n forceFailover(_session: Session): Promise<void> {\n return Promise.reject(new NotImplementedError(\"coordinator.forceFailover\"));\n },\n};\n"]}