@invisible-labs/sdk 0.6.0-devnet.2 → 0.6.0-devnet.3

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 (41) hide show
  1. package/README.md +131 -72
  2. package/dist/{chunk-TQNNTV5F.js → chunk-4X5OCCQW.js} +3 -3
  3. package/dist/{chunk-TQNNTV5F.js.map → chunk-4X5OCCQW.js.map} +1 -1
  4. package/dist/{chunk-7DSVN3MV.js → chunk-BWCGNTN5.js} +13 -5
  5. package/dist/chunk-BWCGNTN5.js.map +1 -0
  6. package/dist/{chunk-NCY4FCYU.js → chunk-DIA6U2CV.js} +19 -3
  7. package/dist/chunk-DIA6U2CV.js.map +1 -0
  8. package/dist/{chunk-OHIM2YWU.js → chunk-GHBQF3A7.js} +2 -2
  9. package/dist/chunk-GHBQF3A7.js.map +1 -0
  10. package/dist/{chunk-SZAYO2L5.js → chunk-NHEHCUS5.js} +3 -3
  11. package/dist/{chunk-SZAYO2L5.js.map → chunk-NHEHCUS5.js.map} +1 -1
  12. package/dist/{chunk-LBC7ALYO.js → chunk-NKRVQXRP.js} +58 -3
  13. package/dist/chunk-NKRVQXRP.js.map +1 -0
  14. package/dist/{chunk-XUWBGET5.js → chunk-QQSI3ZD7.js} +23 -7
  15. package/dist/chunk-QQSI3ZD7.js.map +1 -0
  16. package/dist/{chunk-JRMKCE3S.js → chunk-V5HXJRBW.js} +3 -3
  17. package/dist/{chunk-JRMKCE3S.js.map → chunk-V5HXJRBW.js.map} +1 -1
  18. package/dist/{coordinator-7Y45MCCZ.js → coordinator-VVJ33WF2.js} +3 -3
  19. package/dist/{coordinator-7Y45MCCZ.js.map → coordinator-VVJ33WF2.js.map} +1 -1
  20. package/dist/{createSession-D3ym-Ira.d.ts → errors-N2touVm4.d.ts} +2 -54
  21. package/dist/events.js +3 -3
  22. package/dist/index.d.ts +60 -4
  23. package/dist/index.js +7 -7
  24. package/dist/lp.d.ts +8 -1
  25. package/dist/lp.js +109 -22
  26. package/dist/lp.js.map +1 -1
  27. package/dist/presets.d.ts +3 -3
  28. package/dist/presets.js +13 -6
  29. package/dist/presets.js.map +1 -1
  30. package/dist/stats.js +1 -1
  31. package/dist/storage.js +1 -1
  32. package/dist/{types.generated-CHGSbmLp.d.ts → types.generated-BSEBz4jR.d.ts} +1 -0
  33. package/dist/user.d.ts +26 -143
  34. package/dist/user.js +42 -30
  35. package/dist/user.js.map +1 -1
  36. package/package.json +7 -4
  37. package/dist/chunk-7DSVN3MV.js.map +0 -1
  38. package/dist/chunk-LBC7ALYO.js.map +0 -1
  39. package/dist/chunk-NCY4FCYU.js.map +0 -1
  40. package/dist/chunk-OHIM2YWU.js.map +0 -1
  41. package/dist/chunk-XUWBGET5.js.map +0 -1
package/README.md CHANGED
@@ -7,8 +7,11 @@ TypeScript SDK for building private SOL transfer integrations with Invisible.
7
7
  [API reference](https://docs.invisible.exchange/docs/sdk/reference/) ·
8
8
  [Trust model](https://docs.invisible.exchange/docs/security/)
9
9
 
10
- > Devnet beta. This release targets Solana devnet. APIs may change before a
11
- > stable release.
10
+ > Devnet beta. This release targets Solana devnet. APIs may change before a stable release.
11
+
12
+ This package is the programmatic entrypoint for user and LP interaction with an attested Invisible
13
+ coordinator. The normal-user surface uses one functional sequence over a caller-owned session:
14
+ `createSession`, `contractRequest`, `sync`, `requestRefund`, then `closeSession`.
12
15
 
13
16
  ## Install
14
17
 
@@ -16,86 +19,134 @@ TypeScript SDK for building private SOL transfer integrations with Invisible.
16
19
  npm install @invisible-labs/sdk@devnet
17
20
  ```
18
21
 
19
- ## What the SDK provides
20
-
21
- - Attested coordinator sessions over WSS and Noise XX.
22
- - Private SOL transfer, status-sync, and refund flows.
23
- - Imports limited to the features an application needs.
24
- - Typed errors and runtime validation at protocol boundaries.
25
-
26
22
  ## Entrypoints
27
23
 
28
- | Import | Purpose |
29
- | ----------------------------- | --------------------------------------------------- |
30
- | `@invisible-labs/sdk` | Session lifecycle, attestation, and shared controls |
31
- | `@invisible-labs/sdk/user` | Private-transfer and refund flows |
32
- | `@invisible-labs/sdk/events` | Sync subscriptions |
33
- | `@invisible-labs/sdk/storage` | Client storage adapters |
24
+ | Import | Covers |
25
+ | ----------------------------- | ------------------------------------------------------ |
26
+ | `@invisible-labs/sdk` | `createSession`, attestation, and coordinator controls |
27
+ | `@invisible-labs/sdk/user` | normal-user commands: private transfer, sync, refund |
28
+ | `@invisible-labs/sdk/lp` | liquidity-provider lifecycle |
29
+ | `@invisible-labs/sdk/stats` | actor-safe read projections |
30
+ | `@invisible-labs/sdk/events` | sync subscriptions |
31
+ | `@invisible-labs/sdk/storage` | storage adapters |
32
+ | `@invisible-labs/sdk/presets` | optional coordinator endpoint presets |
33
+
34
+ Each actor entrypoint is independently importable; pulling one in must not drag the others into a
35
+ consumer bundle. See [ARCHITECTURE.md](./ARCHITECTURE.md) for the layered module map.
34
36
 
35
37
  ## Private transfer
36
38
 
37
- Configure the coordinator from the current approved release information, then
38
- create a user session:
39
+ The canonical normal-user flow uses one attested session and the functional SDK commands:
39
40
 
40
41
  ```ts
41
- import { normalizeError } from "@invisible-labs/sdk";
42
- import { createCoordinatorSession } from "@invisible-labs/sdk/user";
43
-
44
- const transfer = createCoordinatorSession({
45
- coordinator,
46
- });
47
-
42
+ import { closeSession, createSession } from "@invisible-labs/sdk";
43
+ import {
44
+ contractRequest,
45
+ recoveryCodeFromHex,
46
+ requestRefund,
47
+ sync,
48
+ } from "@invisible-labs/sdk/user";
49
+
50
+ const coordinator = {
51
+ endpoints: [
52
+ /* CoordinatorEndpoint[] - supply your own, or use @invisible-labs/sdk/presets */
53
+ ],
54
+ };
55
+ const payoutPolicy = {
56
+ destinations: [{ address: receiverPublicKey, sharePercent: 100 }],
57
+ totalDeadlineMs: 0,
58
+ };
59
+
60
+ const session = await createSession({ coordinator });
48
61
  try {
49
- const result = await transfer.runSwap({
62
+ const contract = await contractRequest(session, {
50
63
  amountLamports: 3_000_000_000,
51
- payoutSpec: {
52
- mode: "instant",
53
- destination_address: destinationAddress,
54
- },
55
- onSyncSecretReady({ secretHex }) {
56
- saveSyncSecret(secretHex);
57
- },
58
- onRecoveryCodeReady({ codeHex }) {
59
- saveRecoveryCode(codeHex);
60
- },
61
- onDepositAddressReady(deposit) {
62
- showDepositInstructions(deposit);
63
- },
64
+ payoutPolicy,
64
65
  });
65
-
66
- console.log(result.swapId);
67
- } catch (error) {
68
- console.error(normalizeError(error));
66
+ const status = await sync(session, contract.swapId, contract.syncSecret);
67
+ console.log(status.state, status.coordinatorTimestampMs);
68
+
69
+ if (status.actor_sync?.snapshot.refundability === "available_now") {
70
+ const receipt = await requestRefund(session, {
71
+ recoveryCode: recoveryCodeFromHex(contract.recoveryCodeHex!),
72
+ });
73
+ console.log(receipt.requestId, receipt.amountLamports);
74
+ }
69
75
  } finally {
70
- transfer.close();
76
+ closeSession(session);
71
77
  }
72
78
  ```
73
79
 
74
- See the
75
- [private-transfer guide](https://docs.invisible.exchange/docs/sdk/private-transfer/)
76
- for funding, settlement events, scheduled receive, sync, and refunds.
80
+ `contractRequest` resolves after durable delegation and before the deposit is observed. Its result
81
+ contains `swapId`, `depositAddress`, `depositExpiresAtMs`, `syncSecret`, and the generated Recovery
82
+ Code. Persist the sync secret and Recovery Code before asking the user to deposit. Send exactly
83
+ `amountLamports` to the deposit address. The `sync` response contains actor-scoped lifecycle truth
84
+ and the coordinator response timestamp; it does not expose an internal payout due timestamp. A
85
+ refund receipt also carries the coordinator-authoritative accepted amount; use that value for
86
+ pending refund accounting and use `sync` for final landing, cancellation, and fee-loss outcomes.
77
87
 
78
- ## Security model
88
+ ## Private-transfer amount limits
89
+
90
+ Use the public user-entry constants for inclusive preflight validation. Values are expressed in
91
+ lamports, matching the `amountLamports` request field. The current V0 bounds are `1.5 SOL`
92
+ (`1_500_000_000` lamports) minimum and `100 SOL` (`100_000_000_000` lamports) maximum.
93
+ The SDK rejects non-safe integers and values outside these bounds before sending a coordinator
94
+ request.
95
+
96
+ ```ts
97
+ import { MAX_ENTRY_AMOUNT_LAMPORTS, MIN_ENTRY_AMOUNT_LAMPORTS } from "@invisible-labs/sdk/user";
98
+
99
+ const isValidEntryAmount = (amountLamports: number) =>
100
+ Number.isSafeInteger(amountLamports) &&
101
+ amountLamports >= MIN_ENTRY_AMOUNT_LAMPORTS &&
102
+ amountLamports <= MAX_ENTRY_AMOUNT_LAMPORTS;
103
+ ```
104
+
105
+ ## Live and deferred surfaces
79
106
 
80
- The SDK establishes an encrypted Noise XX channel and verifies TDX attestation
81
- before sensitive protocol material is sent. Verification failures stop the
82
- session.
107
+ Live today:
83
108
 
84
- Integrators remain responsible for:
109
+ - `createSession` opens a live WebSocket, runs Noise XX, verifies TDX attestation, and returns an
110
+ attested `Session`.
111
+ - `contractRequest`, `sync`, and `requestRefund` are the only normal-user command path over a
112
+ caller-owned attested session. `closeSession` ends the flow.
113
+ - LP lifecycle helpers drive position open/recover, DKG, funding, refill, withdrawal, confirmation,
114
+ and listing.
115
+ - Input validation throws typed `PolicyValidationError`; the closed `InvisibleError` taxonomy and
116
+ `normalizeError` are available to callers.
85
117
 
86
- - loading coordinator measurements from an approved release source;
87
- - protecting Recovery Codes and sync secrets;
88
- - persisting recovery material before asking a user to deposit;
89
- - using fresh payout destinations;
90
- - handling reconnects through sync instead of blindly repeating commands.
118
+ Other target surfaces throw `NotImplementedError` until each is finalized. No command fakes success.
91
119
 
92
- Invisible is trust-minimized, not trustless. Attestation verifies an approved
93
- coordinator build; it does not prove that the code is bug-free. Privacy is not
94
- absolute and can be weakened by low pool depth, timing, amount correlation,
95
- destination reuse, and off-chain metadata.
120
+ ## Recovery material and storage
96
121
 
97
- Read the full
98
- [trust model and security boundaries](https://docs.invisible.exchange/docs/security/).
122
+ The SDK does not persist recovery material automatically. Consumers that need restart or tab-close
123
+ recovery must store the relevant values themselves:
124
+
125
+ | Material | Needed for | Guidance |
126
+ | ----------------------- | ----------------------------------------------- | ------------------------------------------------------- |
127
+ | `swapId` + `syncSecret` | Re-sync a private-transfer status view | Persist before asking the user to deposit. |
128
+ | User Recovery Code | Request an origin-bound private-transfer refund | Treat it like a seed phrase and persist it immediately. |
129
+ | LP Position Code | Recover and operate an LP position | Keep it out of logs and treat it like a seed phrase. |
130
+
131
+ The web app persists private-transfer recovery material locally so users can resume flows. SDK
132
+ consumers can choose `browserStorage`, `extensionStorage`, or their own encrypted storage layer.
133
+
134
+ LP DKG requests are bounded. If a browser worker stops responding, the SDK terminates the local
135
+ workers and attempts the signed position-scoped DKG abort command within a bounded cleanup window
136
+ before returning the original failure. LP recovery sends the same cleanup command for an
137
+ incomplete position, so a reload does not wait for the coordinator's session expiry.
138
+
139
+ ## Security model
140
+
141
+ The SDK establishes an encrypted Noise XX channel and verifies TDX attestation before sensitive
142
+ protocol material is sent. Verification failures stop the session. Integrators remain responsible
143
+ for loading coordinator measurements from an approved release source, protecting Recovery Codes and
144
+ sync secrets, persisting recovery material before deposit, using fresh payout destinations, and
145
+ handling reconnects through `sync` instead of blindly repeating commands.
146
+
147
+ Invisible is trust-minimized, not trustless. Attestation verifies an approved coordinator build; it
148
+ does not prove that the code is bug-free. Privacy can be weakened by low pool depth, timing, amount
149
+ correlation, destination reuse, and off-chain metadata.
99
150
 
100
151
  ## Devnet limitations
101
152
 
@@ -105,15 +156,23 @@ Read the full
105
156
  - Availability and privacy strength depend on current pool conditions.
106
157
  - Some documented target APIs are not yet available in the devnet beta.
107
158
 
108
- Use only APIs marked as live in the
109
- [current reference](https://docs.invisible.exchange/docs/sdk/reference/).
159
+ Use only APIs marked as live in the [current reference](https://docs.invisible.exchange/docs/sdk/reference/).
110
160
 
111
- ## Documentation
161
+ ## Not in this SDK
162
+
163
+ Protocol-fee admin payout is out of scope for the SDK. It lives behind a separate admin surface.
164
+
165
+ ## Packaging
166
+
167
+ The package is bundled with tsup into a self-contained artifact. Workspace-internal packages and the
168
+ FROST WASM are inlined into the published bundle, while published third-party packages remain
169
+ external dependencies.
170
+
171
+ ```bash
172
+ npm run build
173
+ npm run verify:exports
174
+ ```
112
175
 
113
- - [SDK overview](https://docs.invisible.exchange/docs/sdk/)
114
- - [Quickstart](https://docs.invisible.exchange/docs/sdk/quickstart/)
115
- - [Examples](https://docs.invisible.exchange/docs/sdk/examples/)
116
- - [API reference](https://docs.invisible.exchange/docs/sdk/reference/)
117
- - [Compatibility](https://docs.invisible.exchange/docs/sdk/compatibility/)
118
- - [Versioning](https://docs.invisible.exchange/docs/sdk/versioning/)
119
- - [V0 launch scope](https://docs.invisible.exchange/docs/v0-launch/)
176
+ The prod-attestation smoke normally rebuilds the SDK. Its `--prebuilt-sdk`
177
+ option is reserved for an integrity-bound runtime that already contains the
178
+ exact built `dist`; ordinary operator runs must omit it.
@@ -6,12 +6,12 @@ var LP_DEFAULT_TARGET_SHARDS = 200;
6
6
  var LP_MAX_TARGET_SHARDS = 300;
7
7
  var LP_DEFAULT_REFILL_BATCH_SIZE = 50;
8
8
  var LP_MAX_REFILL_BATCH_SIZE = 50;
9
- var PRODUCT_MIN_ENTRY_LAMPORTS = 4e8;
9
+ var PRODUCT_MIN_ENTRY_LAMPORTS = 15e8;
10
10
  var PRODUCT_MAX_ENTRY_LAMPORTS = 1e11;
11
11
  function isValidLpPositionId(lpPositionId) {
12
12
  return lpPositionId.length >= LP_POSITION_ID_MIN_LENGTH && lpPositionId.length <= LP_POSITION_ID_MAX_LENGTH && LP_POSITION_ID_PATTERN.test(lpPositionId);
13
13
  }
14
14
 
15
15
  export { LP_DEFAULT_REFILL_BATCH_SIZE, LP_DEFAULT_TARGET_SHARDS, LP_MAX_REFILL_BATCH_SIZE, LP_MAX_TARGET_SHARDS, PRODUCT_MAX_ENTRY_LAMPORTS, PRODUCT_MIN_ENTRY_LAMPORTS, isValidLpPositionId };
16
- //# sourceMappingURL=chunk-TQNNTV5F.js.map
17
- //# sourceMappingURL=chunk-TQNNTV5F.js.map
16
+ //# sourceMappingURL=chunk-4X5OCCQW.js.map
17
+ //# sourceMappingURL=chunk-4X5OCCQW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../shared/src/index.ts"],"names":[],"mappings":";AAgBO,IAAM,yBAAA,GAA4B,CAAA;AAClC,IAAM,yBAAA,GAA4B,EAAA;AAClC,IAAM,sBAAA,GAAyB,kBAAA;AAC/B,IAAM,wBAAA,GAA2B;AACjC,IAAM,oBAAA,GAAuB;AAC7B,IAAM,4BAAA,GAA+B;AACrC,IAAM,wBAAA,GAA2B;AAKjC,IAAM,0BAAA,GAA6B;AACnC,IAAM,0BAAA,GAA6B;AAGnC,SAAS,oBAAoB,YAAA,EAA+B;AACjE,EAAA,OACE,YAAA,CAAa,UAAU,yBAAA,IACvB,YAAA,CAAa,UAAU,yBAAA,IACvB,sBAAA,CAAuB,KAAK,YAAY,CAAA;AAE5C","file":"chunk-TQNNTV5F.js","sourcesContent":["/**\n * Shared workspace entrypoint.\n *\n * Keep exports here pure and reusable across workspaces. Do not put React,\n * DOM-only, libp2p runtime state, or feature-specific glue in this package.\n */\nexport function sleep(ms: number): Promise<void> {\n if (ms <= 0) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport const LP_POSITION_ID_MIN_LENGTH = 3;\nexport const LP_POSITION_ID_MAX_LENGTH = 96;\nexport const LP_POSITION_ID_PATTERN = /^[A-Za-z0-9_-]+$/;\nexport const LP_DEFAULT_TARGET_SHARDS = 200;\nexport const LP_MAX_TARGET_SHARDS = 300;\nexport const LP_DEFAULT_REFILL_BATCH_SIZE = 50;\nexport const LP_MAX_REFILL_BATCH_SIZE = 50;\n\n// Temporary TypeScript mirrors of the Rust TEE entry limits, plus the distinct\n// mainnet UI default. Keep them guarded by `npm run product-limits:check` until\n// cross-language generated product constants exist.\nexport const PRODUCT_MIN_ENTRY_LAMPORTS = 400_000_000;\nexport const PRODUCT_MAX_ENTRY_LAMPORTS = 100_000_000_000;\nexport const PRODUCT_DEFAULT_MAINNET_ENTRY_LAMPORTS = 3_000_000_000;\n\nexport function isValidLpPositionId(lpPositionId: string): boolean {\n return (\n lpPositionId.length >= LP_POSITION_ID_MIN_LENGTH &&\n lpPositionId.length <= LP_POSITION_ID_MAX_LENGTH &&\n LP_POSITION_ID_PATTERN.test(lpPositionId)\n );\n}\n"]}
1
+ {"version":3,"sources":["../../shared/src/index.ts"],"names":[],"mappings":";AAgBO,IAAM,yBAAA,GAA4B,CAAA;AAClC,IAAM,yBAAA,GAA4B,EAAA;AAClC,IAAM,sBAAA,GAAyB,kBAAA;AAC/B,IAAM,wBAAA,GAA2B;AACjC,IAAM,oBAAA,GAAuB;AAC7B,IAAM,4BAAA,GAA+B;AACrC,IAAM,wBAAA,GAA2B;AAKjC,IAAM,0BAAA,GAA6B;AACnC,IAAM,0BAAA,GAA6B;AAGnC,SAAS,oBAAoB,YAAA,EAA+B;AACjE,EAAA,OACE,YAAA,CAAa,UAAU,yBAAA,IACvB,YAAA,CAAa,UAAU,yBAAA,IACvB,sBAAA,CAAuB,KAAK,YAAY,CAAA;AAE5C","file":"chunk-4X5OCCQW.js","sourcesContent":["/**\n * Shared workspace entrypoint.\n *\n * Keep exports here pure and reusable across workspaces. Do not put React,\n * DOM-only, libp2p runtime state, or feature-specific glue in this package.\n */\nexport function sleep(ms: number): Promise<void> {\n if (ms <= 0) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport const LP_POSITION_ID_MIN_LENGTH = 3;\nexport const LP_POSITION_ID_MAX_LENGTH = 96;\nexport const LP_POSITION_ID_PATTERN = /^[A-Za-z0-9_-]+$/;\nexport const LP_DEFAULT_TARGET_SHARDS = 200;\nexport const LP_MAX_TARGET_SHARDS = 300;\nexport const LP_DEFAULT_REFILL_BATCH_SIZE = 50;\nexport const LP_MAX_REFILL_BATCH_SIZE = 50;\n\n// Temporary TypeScript mirrors of the Rust TEE entry limits, plus the distinct\n// mainnet UI default. Keep them guarded by `npm run product-limits:check` until\n// cross-language generated product constants exist.\nexport const PRODUCT_MIN_ENTRY_LAMPORTS = 1_500_000_000;\nexport const PRODUCT_MAX_ENTRY_LAMPORTS = 100_000_000_000;\nexport const PRODUCT_DEFAULT_MAINNET_ENTRY_LAMPORTS = 1_500_000_000;\n\nexport function isValidLpPositionId(lpPositionId: string): boolean {\n return (\n lpPositionId.length >= LP_POSITION_ID_MIN_LENGTH &&\n lpPositionId.length <= LP_POSITION_ID_MAX_LENGTH &&\n LP_POSITION_ID_PATTERN.test(lpPositionId)\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { failSessionClosed, createSessionHandle, getSessionState, closeSessionState } from './chunk-JRMKCE3S.js';
2
- import { verifyAttestation, assertAttestResponse } from './chunk-NCY4FCYU.js';
3
- import { TransportError, AttestationError } from './chunk-OHIM2YWU.js';
1
+ import { failSessionClosed, createSessionHandle, getSessionState, closeSessionState } from './chunk-V5HXJRBW.js';
2
+ import { verifyAttestation, assertAttestResponse } from './chunk-DIA6U2CV.js';
3
+ import { TransportError, AttestationError } from './chunk-GHBQF3A7.js';
4
4
  import { generateKeyPair, sharedKey } from '@stablelib/x25519';
5
5
  import { ChaCha20Poly1305 } from '@stablelib/chacha20poly1305';
6
6
  import { hash, SHA256 } from '@stablelib/sha256';
@@ -398,6 +398,7 @@ function toAttestationPolicy(endpoint) {
398
398
  // ignore the MRTD pin inside the verifier.
399
399
  expectedMrtd: pin.mrtd,
400
400
  ...pin.binaryHash ? { expectedBinaryHash: pin.binaryHash } : {},
401
+ ...pin.runtimeProfile ? { expectedRuntimeProfile: pin.runtimeProfile } : {},
401
402
  allowMissingDcapCollateral: pin.allowMissingDcapCollateral === true,
402
403
  allowLocalAttestation
403
404
  };
@@ -694,6 +695,7 @@ async function establishAttestedChannel(params) {
694
695
  mrtd: channel.attestation.mrtd,
695
696
  mode: channel.attestation.mode,
696
697
  binaryHash: channel.attestation.binaryHash,
698
+ runtimeProfile: channel.attestation.runtimeProfile,
697
699
  pubkeyHex: channel.attestation.pubkeyHex,
698
700
  localAttestation: channel.attestation.localAttestation,
699
701
  rtmr0: channel.attestation.rtmr0,
@@ -723,6 +725,7 @@ function performAttestation(_transport, handshake) {
723
725
  mrtd: channel.attestation.mrtd,
724
726
  mode: channel.attestation.mode,
725
727
  binaryHash: channel.attestation.binaryHash,
728
+ runtimeProfile: channel.attestation.runtimeProfile,
726
729
  pubkeyHex: channel.attestation.pubkeyHex,
727
730
  localAttestation: channel.attestation.localAttestation,
728
731
  rtmr0: channel.attestation.rtmr0,
@@ -872,6 +875,10 @@ var coordinatorPoolConfig_schema_default = {
872
875
  pattern: "^[0-9a-fA-F]{64}$",
873
876
  description: "Optional SHA-256 hash of the approved coordinator binary; required for production Azure attestation."
874
877
  },
878
+ runtimeProfile: {
879
+ enum: ["prod-hardened", "prod-devnet-simplified"],
880
+ description: "Optional compile-time coordinator runtime profile; production simplified deployments must pin it."
881
+ },
875
882
  intelRootFingerprint: {
876
883
  type: "string",
877
884
  description: "Hex SHA-256 of the Intel root cert."
@@ -1023,6 +1030,7 @@ async function reattest(state, endpoint, timeoutMs = DEFAULT_REATTEST_TIMEOUT_MS
1023
1030
  mrtd: metadata.mrtd,
1024
1031
  mode: metadata.mode,
1025
1032
  binaryHash: metadata.binaryHash,
1033
+ runtimeProfile: metadata.runtimeProfile,
1026
1034
  pubkeyHex: metadata.pubkeyHex,
1027
1035
  localAttestation: metadata.localAttestation,
1028
1036
  rtmr0: metadata.rtmr0,
@@ -1141,5 +1149,5 @@ async function runReattest(state, endpoint) {
1141
1149
  }
1142
1150
 
1143
1151
  export { closeSession, createExponentialBackoff, createSession, createStateController, formatAjvErrors, noiseWebSocketTransport, performAttestation, performNoiseHandshake, reattestSerialized, validatePayoutPolicyShape };
1144
- //# sourceMappingURL=chunk-7DSVN3MV.js.map
1145
- //# sourceMappingURL=chunk-7DSVN3MV.js.map
1152
+ //# sourceMappingURL=chunk-BWCGNTN5.js.map
1153
+ //# sourceMappingURL=chunk-BWCGNTN5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/exponentialBackoff.ts","../src/transport/stateController.ts","../src/transport/noiseWebSocketTransport.ts","../src/transport/noiseXx.ts","../src/session/secureChannel.ts","../src/transport/handshake.ts","../src/schemas/payoutPolicy.schema.json","../src/schemas/coordinatorPoolConfig.schema.json","../src/schemas/lpPositionView.schema.json","../src/schemas/storageEnvelope.schema.json","../src/validation/ajv.ts","../src/attestation/reattest.ts","../src/session/createSession.ts"],"names":["sha256Hash"],"mappings":";;;;;;;;;;AAkBO,SAAS,yBAAyB,OAAA,EAAwD;AAC/F,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,OAAA,CAAQ,cAAc,CAAA,IAAK,OAAA,CAAQ,kBAAkB,CAAA,EAAG;AAC3E,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAC,OAAO,QAAA,CAAS,OAAA,CAAQ,UAAU,CAAA,IAAK,OAAA,CAAQ,UAAA,GAAa,OAAA,CAAQ,cAAA,EAAgB;AACvF,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AACA,EAAA,IACE,OAAA,CAAQ,UAAA,KAAe,MAAA,KACtB,CAAC,MAAA,CAAO,QAAA,CAAS,OAAA,CAAQ,UAAU,CAAA,IAAK,OAAA,CAAQ,UAAA,GAAa,CAAA,CAAA,EAC9D;AACA,IAAA,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAAA,EACtD;AACA,EAAA,IACE,OAAA,CAAQ,WAAA,KAAgB,MAAA,KACvB,CAAC,OAAO,QAAA,CAAS,OAAA,CAAQ,WAAW,CAAA,IAAK,OAAA,CAAQ,WAAA,GAAc,CAAA,IAAK,OAAA,CAAQ,cAAc,CAAA,CAAA,EAC3F;AACA,IAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,EACvD;AAEA,EAAA,MAAM,iBAAiB,OAAA,CAAQ,cAAA;AAC/B,EAAA,MAAM,aAAa,OAAA,CAAQ,UAAA;AAC3B,EAAA,MAAM,UAAA,GAAa,QAAQ,UAAA,IAAc,CAAA;AACzC,EAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,IAAe,CAAA;AAC3C,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,IAAU,IAAA,CAAK,MAAA;AACtC,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,OAAO;AAAA,IACL,WAAA,GAAsB;AACpB,MAAA,MAAM,cAAc,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,cAAA,GAAiB,cAAc,OAAO,CAAA;AAC/E,MAAA,OAAA,IAAW,CAAA;AAEX,MAAA,IAAI,WAAA,KAAgB,CAAA,EAAG,OAAO,IAAA,CAAK,MAAM,WAAW,CAAA;AAEpD,MAAA,MAAM,UAAA,GAAa,eAAe,CAAA,GAAI,WAAA,CAAA;AACtC,MAAA,MAAM,UAAA,GAAa,eAAe,CAAA,GAAI,WAAA,CAAA;AACtC,MAAA,MAAM,aAAA,GAAgB,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,MAAA,EAAO,EAAG,CAAC,CAAA,EAAG,CAAC,CAAA;AACvD,MAAA,OAAO,IAAA,CAAK,GAAA;AAAA,QACV,UAAA;AAAA,QACA,IAAA,CAAK,KAAA,CAAM,UAAA,GAAA,CAAc,UAAA,GAAa,cAAc,aAAa;AAAA,OACnE;AAAA,IACF,CAAA;AAAA,IACA,KAAA,GAAc;AACZ,MAAA,OAAA,GAAU,CAAA;AAAA,IACZ;AAAA,GACF;AACF;;;ACjDO,SAAS,sBAAsB,OAAA,EAA2C;AAC/E,EAAA,IAAI,KAAA,GAAQ,OAAA;AACZ,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAsC;AAC5D,EAAA,OAAO;AAAA,IACL,KAAK,MAAM,KAAA;AAAA,IACX,IAAI,IAAA,EAAM;AACR,MAAA,IAAI,SAAS,KAAA,EAAO;AACpB,MAAA,KAAA,GAAQ,IAAA;AACR,MAAA,KAAA,MAAW,QAAA,IAAY,SAAA,EAAW,QAAA,CAAS,IAAI,CAAA;AAAA,IACjD,CAAA;AAAA,IACA,SAAS,QAAA,EAAU;AACjB,MAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,MAAA,OAAO,MAAM,SAAA,CAAU,MAAA,CAAO,QAAQ,CAAA;AAAA,IACxC;AAAA,GACF;AACF;;;ACLA,IAAM,0BAAA,GAA6B,GAAA;AAEnC,SAAS,wBAAwB,GAAA,EAA4B;AAC3D,EAAA,MAAM,OAAQ,UAAA,CAAkE,SAAA;AAChF,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,IAAI,cAAA;AAAA,MACR,qBAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,IAAI,KAAK,GAAG,CAAA;AACrB;AAEA,SAAS,aAAa,IAAA,EAA2B;AAC/C,EAAA,IAAI,IAAA,YAAgB,YAAY,OAAO,IAAA;AACvC,EAAA,IAAI,IAAA,YAAgB,WAAA,EAAa,OAAO,IAAI,WAAW,IAAI,CAAA;AAC3D,EAAA,IAAI,WAAA,CAAY,MAAA,CAAO,IAAI,CAAA,EAAG;AAC5B,IAAA,OAAO,IAAI,UAAA,CAAW,IAAA,CAAK,QAAQ,IAAA,CAAK,UAAA,EAAY,KAAK,UAAU,CAAA;AAAA,EACrE;AACA,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU,OAAO,IAAI,WAAA,EAAY,CAAE,OAAO,IAAI,CAAA;AAClE,EAAA,MAAM,IAAI,cAAA,CAAe,uBAAA,EAAyB,gCAAgC,CAAA;AACpF;AAEO,SAAS,wBAAwB,OAAA,EAAoD;AAC1F,EAAA,MAAM,OAAA,GAA4B,QAAQ,gBAAA,IAAoB,uBAAA;AAC9D,EAAA,MAAM,gBAAA,GAAmB,QAAQ,gBAAA,IAAoB,0BAAA;AACrD,EAAA,MAAM,EAAA,GAAK,sBAAsB,MAAM,CAAA;AACvC,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAiC;AAC9D,EAAA,IAAI,MAAA,GAA+B,IAAA;AAEnC,EAAA,SAAS,QAAA,GAAW;AAClB,IAAA,IAAI,EAAA,CAAG,GAAA,EAAI,KAAM,QAAA,EAAU;AAC3B,IAAA,EAAA,CAAG,IAAI,SAAS,CAAA;AAChB,IAAA,MAAM,EAAA,GAAK,MAAA;AACX,IAAA,MAAA,GAAS,IAAA;AACT,IAAA,IAAI,EAAA,EAAI;AACN,MAAA,EAAA,CAAG,MAAA,GAAS,IAAA;AACZ,MAAA,EAAA,CAAG,OAAA,GAAU,IAAA;AACb,MAAA,EAAA,CAAG,SAAA,GAAY,IAAA;AACf,MAAA,EAAA,CAAG,OAAA,GAAU,IAAA;AACb,MAAA,IAAI;AACF,QAAA,EAAA,CAAG,KAAA,EAAM;AAAA,MACX,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,EAAA,CAAG,IAAI,QAAQ,CAAA;AAAA,EACjB;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAM,EAAA,CAAG,GAAA,EAAI;AAAA,IACpB,aAAA,EAAe,CAAC,QAAA,KAAa,EAAA,CAAG,SAAS,QAAQ,CAAA;AAAA,IACjD,UAAU,QAAA,EAAuB;AAC/B,MAAA,gBAAA,CAAiB,IAAI,QAAQ,CAAA;AAC7B,MAAA,OAAO,MAAM,gBAAA,CAAiB,MAAA,CAAO,QAAQ,CAAA;AAAA,IAC/C,CAAA;AAAA,IAEA,QAAQ,MAAA,EAAQ;AACd,MAAA,IAAI,GAAG,GAAA,EAAI,KAAM,MAAA,EAAQ,OAAO,QAAQ,OAAA,EAAQ;AAChD,MAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,QAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,UACb,IAAI,cAAA,CAAe,iBAAA,EAAmB,mCAAmC;AAAA,SAC3E;AAAA,MACF;AACA,MAAA,EAAA,CAAG,IAAI,YAAY,CAAA;AAEnB,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC5C,QAAA,IAAI,OAAA,GAAU,KAAA;AACd,QAAA,MAAM,EAAA,GAAK,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AAChC,QAAA,MAAA,GAAS,EAAA;AACT,QAAA,EAAA,CAAG,UAAA,GAAa,aAAA;AAEhB,QAAA,MAAM,iBAAiB,MAAM;AAC3B,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,MAAA,EAAQ,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAAA,QAC9C,CAAA;AACA,QAAA,MAAM,IAAA,GAAO,CAAC,KAAA,KAA0B;AACtC,UAAA,IAAI,OAAA,EAAS;AACb,UAAA,OAAA,GAAU,IAAA;AACV,UAAA,cAAA,EAAe;AACf,UAAA,QAAA,EAAS;AACT,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd,CAAA;AACA,QAAA,MAAM,UAAU,MAAM,IAAA,CAAK,IAAI,cAAA,CAAe,iBAAA,EAAmB,iBAAiB,CAAC,CAAA;AACnF,QAAA,MAAM,KAAA,GAAQ,UAAA;AAAA,UACZ,MACE,IAAA;AAAA,YACE,IAAI,cAAA;AAAA,cACF,qBAAA;AAAA,cACA,2BAA2B,gBAAgB,CAAA,EAAA;AAAA;AAC7C,WACF;AAAA,UACF;AAAA,SACF;AACA,QAAA,MAAA,EAAQ,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAEzD,QAAA,EAAA,CAAG,SAAS,MAAM;AAChB,UAAA,IAAI,OAAA,EAAS;AACb,UAAA,OAAA,GAAU,IAAA;AACV,UAAA,cAAA,EAAe;AAEf,UAAA,EAAA,CAAG,SAAA,GAAY,CAAC,KAAA,KAAU;AACxB,YAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,KAAA,CAAM,IAAI,CAAA;AACrC,YAAA,KAAA,MAAW,QAAA,IAAY,gBAAA,EAAkB,QAAA,CAAS,KAAK,CAAA;AAAA,UACzD,CAAA;AACA,UAAA,EAAA,CAAG,OAAA,GAAU,MAAM,QAAA,EAAS;AAC5B,UAAA,EAAA,CAAG,OAAA,GAAU,MAAM,QAAA,EAAS;AAC5B,UAAA,EAAA,CAAG,IAAI,MAAM,CAAA;AACb,UAAA,OAAA,EAAQ;AAAA,QACV,CAAA;AACA,QAAA,EAAA,CAAG,UAAU,MACX,IAAA,CAAK,IAAI,cAAA,CAAe,qBAAA,EAAuB,6BAA6B,CAAC,CAAA;AAC/E,QAAA,EAAA,CAAG,UAAU,MACX,IAAA,CAAK,IAAI,cAAA,CAAe,iBAAA,EAAmB,8BAA8B,CAAC,CAAA;AAAA,MAC9E,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,KAAK,KAAA,EAAmB;AACtB,MAAA,MAAM,EAAA,GAAK,MAAA;AACX,MAAA,IAAI,EAAA,CAAG,GAAA,EAAI,KAAM,MAAA,IAAU,CAAC,EAAA,EAAI;AAC9B,QAAA,MAAM,IAAI,cAAA,CAAe,iBAAA,EAAmB,qCAAqC,CAAA;AAAA,MACnF;AAGA,MAAA,EAAA,CAAG,KAAK,KAAK,CAAA;AAAA,IACf,CAAA;AAAA,IAEA,KAAA,GAAQ;AACN,MAAA,QAAA,EAAS;AAAA,IACX;AAAA,GACF;AACF;AClIA,IAAM,aAAA,GAAgB,kCAAA;AAqDtB,SAAS,WAAW,CAAA,EAAuB;AACzC,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,EAAE,CAAA;AAE7B,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA;AACpC,EAAA,IAAA,CAAK,SAAA,CAAU,CAAA,EAAG,CAAA,GAAI,UAAA,EAAY,IAAI,CAAA;AACtC,EAAA,IAAA,CAAK,SAAA,CAAU,GAAG,IAAA,CAAK,KAAA,CAAM,IAAI,UAAW,CAAA,GAAI,YAAY,IAAI,CAAA;AAChE,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,KAAA,CAAM,IAAgB,GAAA,EAA2C;AACxE,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,MAAA,EAAQ,EAAE,CAAA;AAChC,EAAA,IAAA,CAAK,OAAO,GAAG,CAAA;AACf,EAAA,MAAM,IAAA,GAAO,KAAK,MAAA,EAAO;AAEzB,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,MAAA,EAAQ,IAAI,CAAA;AAClC,EAAA,IAAA,CAAK,OAAO,IAAI,UAAA,CAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,KAAK,MAAA,EAAO;AAEzB,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,MAAA,EAAQ,IAAI,CAAA;AAClC,EAAA,IAAA,CAAK,OAAO,IAAI,CAAA;AAChB,EAAA,IAAA,CAAK,OAAO,IAAI,UAAA,CAAW,CAAC,CAAC,CAAC,CAAC,CAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,KAAK,MAAA,EAAO;AAEzB,EAAA,OAAO,CAAC,MAAM,IAAI,CAAA;AACpB;AAeA,SAAS,cAAA,GAAgC;AACvC,EAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY,CAAE,OAAO,aAAa,CAAA;AACpD,EAAA,MAAM,EAAA,GAAK,IAAI,UAAA,CAAW,EAAE,CAAA;AAC5B,EAAA,EAAA,CAAG,IAAI,KAAK,CAAA;AACZ,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,EAAE,CAAA;AAC7B,EAAA,GAAA,CAAI,IAAI,EAAE,CAAA;AAEV,EAAA,MAAM,EAAA,GAAoB;AAAA,IACxB,CAAA,EAAG,EAAA;AAAA,IACH,EAAA,EAAI,GAAA;AAAA,IACJ,CAAA,EAAG,IAAA;AAAA,IACH,CAAA,EAAG,CAAA;AAAA,IAEH,QAAQ,IAAA,EAAwB;AAC9B,MAAA,MAAM,WAAW,IAAI,UAAA,CAAW,KAAK,CAAA,CAAE,MAAA,GAAS,KAAK,MAAM,CAAA;AAC3D,MAAA,QAAA,CAAS,GAAA,CAAI,KAAK,CAAC,CAAA;AACnB,MAAA,QAAA,CAAS,GAAA,CAAI,IAAA,EAAM,IAAA,CAAK,CAAA,CAAE,MAAM,CAAA;AAChC,MAAA,IAAA,CAAK,CAAA,GAAIA,KAAW,QAAQ,CAAA;AAAA,IAC9B,CAAA;AAAA,IAEA,OAAO,GAAA,EAAuB;AAC5B,MAAA,MAAM,CAAC,KAAA,EAAO,IAAI,IAAI,KAAA,CAAM,IAAA,CAAK,IAAI,GAAG,CAAA;AACxC,MAAA,IAAA,CAAK,EAAA,GAAK,KAAA;AACV,MAAA,IAAA,CAAK,CAAA,GAAI,IAAA;AACT,MAAA,IAAA,CAAK,CAAA,GAAI,CAAA;AAAA,IACX,CAAA;AAAA,IAEA,eAAe,SAAA,EAAmC;AAChD,MAAA,IAAI,CAAC,KAAK,CAAA,EAAG;AACX,QAAA,IAAA,CAAK,QAAQ,SAAS,CAAA;AACtB,QAAA,OAAO,IAAI,WAAW,SAAS,CAAA;AAAA,MACjC;AACA,MAAA,MAAM,IAAA,GAAO,IAAI,gBAAA,CAAiB,IAAA,CAAK,CAAC,CAAA;AACxC,MAAA,MAAM,EAAA,GAAK,KAAK,IAAA,CAAK,UAAA,CAAW,KAAK,CAAC,CAAA,EAAG,SAAA,EAAW,IAAA,CAAK,CAAC,CAAA;AAC1D,MAAA,IAAA,CAAK,CAAA,EAAA;AACL,MAAA,IAAA,CAAK,QAAQ,EAAE,CAAA;AACf,MAAA,OAAO,EAAA;AAAA,IACT,CAAA;AAAA,IAEA,eAAe,UAAA,EAAoC;AACjD,MAAA,IAAI,CAAC,KAAK,CAAA,EAAG;AACX,QAAA,IAAA,CAAK,QAAQ,UAAU,CAAA;AACvB,QAAA,OAAO,IAAI,WAAW,UAAU,CAAA;AAAA,MAClC;AACA,MAAA,MAAM,IAAA,GAAO,IAAI,gBAAA,CAAiB,IAAA,CAAK,CAAC,CAAA;AACxC,MAAA,MAAM,EAAA,GAAK,KAAK,IAAA,CAAK,UAAA,CAAW,KAAK,CAAC,CAAA,EAAG,UAAA,EAAY,IAAA,CAAK,CAAC,CAAA;AAC3D,MAAA,IAAI,CAAC,EAAA,EAAI,MAAM,IAAI,MAAM,+BAA+B,CAAA;AACxD,MAAA,IAAA,CAAK,CAAA,EAAA;AACL,MAAA,IAAA,CAAK,QAAQ,UAAU,CAAA;AACvB,MAAA,OAAO,EAAA;AAAA,IACT,CAAA;AAAA,IAEA,KAAA,GAAkC;AAChC,MAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,KAAA,CAAM,KAAK,EAAA,EAAI,IAAI,UAAA,CAAW,CAAC,CAAC,CAAA;AAEjD,MAAA,OAAO,CAAC,IAAI,EAAE,CAAA;AAAA,IAChB;AAAA,GACF;AAEA,EAAA,EAAA,CAAG,OAAA,CAAQ,IAAI,UAAA,CAAW,CAAC,CAAC,CAAA;AAC5B,EAAA,OAAO,EAAA;AACT;AASO,SAAS,oBAAA,CAAqB,SAAqB,OAAA,EAAqC;AAC7F,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,OAAO;AAAA,IACL,QAAQ,SAAA,EAAmC;AACzC,MAAA,MAAM,IAAA,GAAO,IAAI,gBAAA,CAAiB,OAAO,CAAA;AACzC,MAAA,MAAM,KAAK,IAAA,CAAK,IAAA,CAAK,WAAW,KAAK,CAAA,EAAG,WAAW,MAAS,CAAA;AAC5D,MAAA,KAAA,EAAA;AACA,MAAA,OAAO,EAAA;AAAA,IACT,CAAA;AAAA,IACA,QAAQ,UAAA,EAAoC;AAC1C,MAAA,MAAM,IAAA,GAAO,IAAI,gBAAA,CAAiB,OAAO,CAAA;AACzC,MAAA,MAAM,KAAK,IAAA,CAAK,IAAA,CAAK,WAAW,KAAK,CAAA,EAAG,YAAY,MAAS,CAAA;AAC7D,MAAA,IAAI,CAAC,EAAA,EAAI,MAAM,IAAI,MAAM,oCAAoC,CAAA;AAC7D,MAAA,KAAA,EAAA;AACA,MAAA,OAAO,EAAA;AAAA,IACT;AAAA,GACF;AACF;AAQO,SAAS,sBAAA,GAA2C;AACzD,EAAA,MAAM,gBAAgB,eAAA,EAAgB;AACtC,EAAA,MAAM,aAAa,eAAA,EAAgB;AACnC,EAAA,MAAM,KAAK,cAAA,EAAe;AAC1B,EAAA,IAAI,YAAA,GAAkC,IAAA;AACtC,EAAA,IAAI,eAAA,GAAqC,IAAA;AAEzC,EAAA,OAAO;AAAA,IACL,IAAI,qBAAA,GAA2C;AAC7C,MAAA,OAAO,eAAA;AAAA,IACT,CAAA;AAAA,IAEA,aAAA,GAA4B;AAC1B,MAAA,EAAA,CAAG,OAAA,CAAQ,WAAW,SAAS,CAAA;AAC/B,MAAA,OAAO,IAAI,UAAA,CAAW,UAAA,CAAW,SAAS,CAAA;AAAA,IAC5C,CAAA;AAAA,IAEA,aAAa,GAAA,EAAuB;AAClC,MAAA,IAAI,GAAA,CAAI,SAAS,EAAA,EAAI;AACnB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qCAAA,EAAwC,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,MACtE;AAGA,MAAA,YAAA,GAAe,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAC9B,MAAA,EAAA,CAAG,QAAQ,YAAY,CAAA;AAGvB,MAAA,MAAM,IAAA,GAAO,SAAA,CAAU,UAAA,CAAW,SAAA,EAAW,YAAY,CAAA;AACzD,MAAA,EAAA,CAAG,OAAO,IAAI,CAAA;AAKd,MAAA,eAAA,GAAkB,GAAG,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,EAAA,EAAI,EAAE,CAAC,CAAA;AAGrD,MAAA,MAAM,IAAA,GAAO,SAAA,CAAU,UAAA,CAAW,SAAA,EAAW,eAAe,CAAA;AAC5D,MAAA,EAAA,CAAG,OAAO,IAAI,CAAA;AAGd,MAAA,IAAI,GAAA,CAAI,SAAS,EAAA,EAAI;AACnB,QAAA,EAAA,CAAG,cAAA,CAAe,GAAA,CAAI,KAAA,CAAM,EAAE,CAAC,CAAA;AAAA,MACjC;AAAA,IACF,CAAA;AAAA,IAEA,aAAA,GAAoE;AAClE,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,MAC5D;AAGA,MAAA,MAAM,IAAA,GAAO,EAAA,CAAG,cAAA,CAAe,aAAA,CAAc,SAAS,CAAA;AAGtD,MAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,SAAA,EAAW,YAAY,CAAA;AAC5D,MAAA,EAAA,CAAG,OAAO,IAAI,CAAA;AAGd,MAAA,MAAM,aAAa,EAAA,CAAG,cAAA,CAAe,IAAI,UAAA,CAAW,CAAC,CAAC,CAAA;AAEtD,MAAA,MAAM,UAAU,IAAI,UAAA,CAAW,IAAA,CAAK,MAAA,GAAS,WAAW,MAAM,CAAA;AAC9D,MAAA,OAAA,CAAQ,IAAI,IAAI,CAAA;AAChB,MAAA,OAAA,CAAQ,GAAA,CAAI,UAAA,EAAY,IAAA,CAAK,MAAM,CAAA;AAEnC,MAAA,MAAM,CAAC,OAAA,EAAS,OAAO,CAAA,GAAI,GAAG,KAAA,EAAM;AAEpC,MAAA,OAAO,EAAE,OAAA,EAAS,SAAA,EAAW,oBAAA,CAAqB,OAAA,EAAS,OAAO,CAAA,EAAE;AAAA,IACtE;AAAA,GACF;AACF;;;AC9OO,IAAM,qBAAA,GAAwB,IAAI,WAAA,EAAY,CAAE,OAAO,uBAAuB,CAAA;AAGrF,IAAM,0BAAA,GAA6B,GAAA;AAuCnC,eAAsB,uBACpB,OAAA,EACwB;AACxB,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,KAAA,EAAM,GAAI,OAAA;AACvC,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,0BAAA;AAEvC,EAAA,IAAI,SAAA,CAAU,KAAA,EAAM,KAAM,MAAA,EAAQ;AAChC,IAAA,MAAM,IAAI,cAAA,CAAe,iBAAA,EAAmB,2CAA2C,CAAA;AAAA,EACzF;AAIA,EAAA,MAAM,OAAA,GAAU,kBAAkB,SAAS,CAAA;AAE3C,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,sBAAA,EAAuB;AAGzC,IAAA,SAAA,CAAU,IAAA,CAAK,SAAA,CAAU,aAAA,EAAe,CAAA;AAGxC,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA;AACzC,IAAA,IAAI;AACF,MAAA,SAAA,CAAU,aAAa,IAAI,CAAA;AAAA,IAC7B,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,cAAA,CAAe,wBAAA,EAA0B,wBAAwB,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA,EAAI;AAAA,QAC1F;AAAA,OACD,CAAA;AAAA,IACH;AAEA,IAAA,MAAM,wBAAwB,SAAA,CAAU,qBAAA;AACxC,IAAA,IAAI,CAAC,qBAAA,EAAuB;AAC1B,MAAA,MAAM,IAAI,cAAA;AAAA,QACR,wBAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAGA,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,UAAU,aAAA,EAAc;AACvC,MAAA,SAAA,CAAU,IAAA,CAAK,OAAO,OAAO,CAAA;AAC7B,MAAA,OAAA,GAAU,MAAA,CAAO,SAAA;AAAA,IACnB,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,cAAA,CAAe,wBAAA,EAA0B,yBAAyB,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA,EAAI;AAAA,QAC3F;AAAA,OACD,CAAA;AAAA,IACH;AAIA,IAAA,MAAM,QAAA,GAAW,WAAW,KAAK,CAAA;AACjC,IAAA,SAAA,CAAU,KAAK,OAAA,CAAQ,OAAA,CAAQ,wBAAA,CAAyB,QAAQ,CAAC,CAAC,CAAA;AAGlE,IAAA,MAAM,aAAA,GAAgB,MAAM,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA;AAClD,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,yBAAA,CAA0B,OAAA,CAAQ,OAAA,CAAQ,aAAa,CAAC,CAAA;AAAA,IACrE,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,KAAA,YAAiB,kBAAkB,MAAM,KAAA;AAC7C,MAAA,MAAM,IAAI,gBAAA;AAAA,QACR,cAAA;AAAA,QACA,CAAA,uCAAA,EAA0C,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA,QACvD,EAAE,KAAA;AAAM,OACV;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,oBAAoB,QAAQ,CAAA;AAC3C,IAAA,MAAM,WAAA,GAAc,MAAM,iBAAA,CAAkB;AAAA,MAC1C,QAAA;AAAA,MACA,aAAA,EAAe,KAAA;AAAA,MACf,sBAAA,EAAwB,qBAAA;AAAA,MACxB,MAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,OAAA,CAAQ,MAAA,EAAO;AACf,IAAA,OAAO,eAAe,EAAE,SAAA,EAAW,QAAQ,OAAA,EAAS,WAAA,EAAa,uBAAuB,CAAA;AAAA,EAC1F,SAAS,GAAA,EAAK;AACZ,IAAA,OAAA,CAAQ,MAAA,EAAO;AACf,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAOO,SAAS,oBAAoB,QAAA,EAAkD;AACpF,EAAA,MAAM,MAAM,QAAA,CAAS,UAAA;AACrB,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,QAAA,CAAS,KAAK,CAAA;AAC7C,EAAA,MAAM,wBACJ,QAAA,CAAS,qBAAA,KAA0B,IAAA,IAAQ,QAAA,IAAY,SAAS,YAAA,KAAiB,MAAA;AAEnF,EAAA,MAAM,MAAA,GAA4B;AAAA,IAChC,GAAI,IAAI,oBAAA,GAAuB,EAAE,sBAAsB,GAAA,CAAI,oBAAA,KAAyB,EAAC;AAAA;AAAA,IAErF,GAAI,SAAS,YAAA,KAAiB,MAAA,GAAS,EAAE,YAAA,EAAc,QAAA,CAAS,YAAA,EAAa,GAAI,EAAC;AAAA;AAAA;AAAA,IAGlF,cAAc,GAAA,CAAI,IAAA;AAAA,IAClB,GAAI,IAAI,UAAA,GAAa,EAAE,oBAAoB,GAAA,CAAI,UAAA,KAAe,EAAC;AAAA,IAC/D,GAAI,IAAI,cAAA,GAAiB,EAAE,wBAAwB,GAAA,CAAI,cAAA,KAAmB,EAAC;AAAA,IAC3E,0BAAA,EAA4B,IAAI,0BAAA,KAA+B,IAAA;AAAA,IAC/D;AAAA,GACF;AAEA,EAAA,IAAI,IAAI,QAAA,EAAU;AAChB,IAAA,MAAA,CAAO,QAAA,GAAW;AAAA,MAChB,cAAA,EAAgB,IAAI,QAAA,CAAS,MAAA;AAAA,MAC7B,eAAA,EAAiB,IAAI,QAAA,CAAS,OAAA;AAAA,MAC9B,kBAAA,EAAoB,IAAI,QAAA,CAAS;AAAA,KACnC;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAIA,SAAS,eAAe,MAAA,EAKN;AAChB,EAAA,MAAM,EAAE,SAAA,EAAW,MAAA,EAAQ,WAAA,EAAa,uBAAsB,GAAI,MAAA;AAClE,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAqC;AAC1D,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAA4B;AACtD,EAAA,IAAI,iBAAA,GAIO,IAAA;AACX,EAAA,IAAI,MAAA,GAAS,KAAA;AAEb,EAAA,MAAM,cAAA,GAAiB,SAAA,CAAU,SAAA,CAAU,CAAC,KAAA,KAAU;AACpD,IAAA,IAAI,MAAA,EAAQ;AACZ,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI;AACF,MAAA,SAAA,GAAY,MAAA,CAAO,QAAQ,KAAK,CAAA;AAAA,IAClC,SAAS,KAAA,EAAO;AAId,MAAA,MAAM,QAAQ,IAAI,cAAA;AAAA,QAChB,wBAAA;AAAA,QACA,CAAA,+BAAA,EAAkC,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA,QAC/C,EAAE,KAAA;AAAM,OACV;AACA,MAAA,IAAA,CAAK,KAAK,CAAA;AACV,MAAA;AAAA,IACF;AACA,IAAA,IAAI,sBAAsB,IAAA,EAAM;AAC9B,MAAA,MAAM,OAAA,GAAU,8BAA8B,SAAS,CAAA;AACvD,MAAA,IAAI,OAAA,CAAQ,SAAS,UAAA,EAAY;AAC/B,QAAA,MAAM,MAAA,GAAS,iBAAA;AACf,QAAA,iBAAA,GAAoB,IAAA;AACpB,QAAA,YAAA,CAAa,OAAO,KAAK,CAAA;AACzB,QAAA,MAAA,CAAO,OAAA,CAAQ,QAAQ,QAAQ,CAAA;AAC/B,QAAA;AAAA,MACF;AACA,MAAA,IAAI,OAAA,CAAQ,SAAS,SAAA,EAAW;AAC9B,QAAA,MAAM,MAAA,GAAS,iBAAA;AACf,QAAA,iBAAA,GAAoB,IAAA;AACpB,QAAA,YAAA,CAAa,OAAO,KAAK,CAAA;AACzB,QAAA,MAAA,CAAO,MAAA,CAAO,QAAQ,KAAK,CAAA;AAC3B,QAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,KAAA,MAAW,OAAA,IAAW,QAAA,EAAU,OAAA,CAAQ,SAAS,CAAA;AAAA,EACnD,CAAC,CAAA;AAED,EAAA,MAAM,gBAAA,GAAmB,SAAA,CAAU,aAAA,CAAc,CAAC,KAAA,KAAU;AAC1D,IAAA,IAAI,MAAA,EAAQ;AACZ,IAAA,IAAI,KAAA,KAAU,SAAA,IAAa,KAAA,KAAU,QAAA,EAAU;AAC7C,MAAA,IAAA,CAAK,IAAI,cAAA,CAAe,iBAAA,EAAmB,iCAAiC,CAAC,CAAA;AAAA,IAC/E;AAAA,EACF,CAAC,CAAA;AAED,EAAA,SAAS,KAAA,GAAc;AACrB,IAAA,IAAI,MAAA,EAAQ;AACZ,IAAA,MAAA,GAAS,IAAA;AACT,IAAA,QAAA,CAAS,KAAA,EAAM;AACf,IAAA,aAAA,CAAc,KAAA,EAAM;AACpB,IAAA,IAAI,sBAAsB,IAAA,EAAM;AAC9B,MAAA,MAAM,MAAA,GAAS,iBAAA;AACf,MAAA,iBAAA,GAAoB,IAAA;AACpB,MAAA,YAAA,CAAa,OAAO,KAAK,CAAA;AACzB,MAAA,MAAA,CAAO,MAAA,CAAO,IAAI,cAAA,CAAe,iBAAA,EAAmB,0BAA0B,CAAC,CAAA;AAAA,IACjF;AACA,IAAA,cAAA,EAAe;AACf,IAAA,gBAAA,EAAiB;AAAA,EACnB;AAEA,EAAA,SAAS,KAAK,KAAA,EAAoB;AAChC,IAAA,IAAI,MAAA,EAAQ;AACZ,IAAA,MAAM,cAAA,GAAiB,CAAC,GAAG,aAAa,CAAA;AACxC,IAAA,KAAA,MAAW,OAAA,IAAW,cAAA,EAAgB,OAAA,CAAQ,KAAK,CAAA;AACnD,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,KAAA,EAAM;AACN,MAAA,SAAA,CAAU,KAAA,EAAM;AAAA,IAClB;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,WAAA;AAAA,IACA,qBAAA;AAAA,IACA,kBAAA,CAAmB,UAAkB,SAAA,EAA4C;AAC/E,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,OAAO,QAAQ,MAAA,CAAO,IAAI,cAAA,CAAe,iBAAA,EAAmB,0BAA0B,CAAC,CAAA;AAAA,MACzF;AACA,MAAA,IAAI,sBAAsB,IAAA,EAAM;AAC9B,QAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,UACb,IAAI,gBAAA,CAAiB,cAAA,EAAgB,qCAAqC;AAAA,SAC5E;AAAA,MACF;AACA,MAAA,OAAO,IAAI,OAAA,CAAwB,CAAC,OAAA,EAAS,MAAA,KAAW;AACtD,QAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,UAAA,IAAI,sBAAsB,IAAA,EAAM;AAChC,UAAA,iBAAA,GAAoB,IAAA;AACpB,UAAA,MAAA;AAAA,YACE,IAAI,gBAAA,CAAiB,cAAA,EAAgB,CAAA,+BAAA,EAAkC,SAAS,CAAA,EAAA,CAAI;AAAA,WACtF;AAAA,QACF,GAAG,SAAS,CAAA;AACZ,QAAA,iBAAA,GAAoB,EAAE,OAAA,EAAS,MAAA,EAAQ,KAAA,EAAM;AAC7C,QAAA,IAAI;AACF,UAAA,SAAA,CAAU,KAAK,MAAA,CAAO,OAAA,CAAQ,wBAAA,CAAyB,QAAQ,CAAC,CAAC,CAAA;AAAA,QACnE,SAAS,KAAA,EAAO;AACd,UAAA,IAAI,sBAAsB,IAAA,EAAM;AAChC,UAAA,iBAAA,GAAoB,IAAA;AACpB,UAAA,YAAA,CAAa,KAAK,CAAA;AAClB,UAAA,MAAA,CAAO,KAAA,YAAiB,QAAQ,KAAA,GAAQ,IAAI,MAAM,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA;AAAA,QAClE;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,KAAK,SAAA,EAA6B;AAChC,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,MAAM,IAAI,cAAA,CAAe,iBAAA,EAAmB,0BAA0B,CAAA;AAAA,MACxE;AACA,MAAA,SAAA,CAAU,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAC,CAAA;AAAA,IAC1C,CAAA;AAAA,IACA,UAAU,OAAA,EAAsB;AAC9B,MAAA,QAAA,CAAS,IAAI,OAAO,CAAA;AACpB,MAAA,OAAO,MAAM,QAAA,CAAS,MAAA,CAAO,OAAO,CAAA;AAAA,IACtC,CAAA;AAAA,IACA,QAAQ,OAAA,EAAsB;AAC5B,MAAA,aAAA,CAAc,IAAI,OAAO,CAAA;AACzB,MAAA,OAAO,MAAM,aAAA,CAAc,MAAA,CAAO,OAAO,CAAA;AAAA,IAC3C,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAWA,SAAS,kBAAkB,SAAA,EAAmC;AAC5D,EAAA,MAAM,QAAsB,EAAC;AAC7B,EAAA,IAAI,MAAA,GAAkF,IAAA;AACtF,EAAA,IAAI,QAAA,GAAW,KAAA;AAEf,EAAA,MAAM,kBAAA,GAAqB,SAAA,CAAU,SAAA,CAAU,CAAC,KAAA,KAAU;AACxD,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,CAAA,GAAI,MAAA;AACV,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,CAAA,CAAE,QAAQ,KAAK,CAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,IAClB;AAAA,EACF,CAAC,CAAA;AAED,EAAA,MAAM,gBAAA,GAAmB,SAAA,CAAU,aAAA,CAAc,CAAC,KAAA,KAAU;AAC1D,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,IAAI,KAAA,KAAU,SAAA,IAAa,KAAA,KAAU,QAAA,EAAU;AAC7C,MAAA,MAAM,CAAA,GAAI,MAAA;AACV,MAAA,MAAA,GAAS,IAAA;AACT,MAAA,CAAA,EAAG,MAAA;AAAA,QACD,IAAI,cAAA,CAAe,iBAAA,EAAmB,+CAA+C;AAAA,OACvF;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AAED,EAAA,SAAS,MAAA,GAAe;AACtB,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,kBAAA,EAAmB;AACnB,IAAA,gBAAA,EAAiB;AACjB,IAAA,KAAA,CAAM,MAAA,GAAS,CAAA;AAAA,EACjB;AAEA,EAAA,OAAO;AAAA,IACL,KAAK,SAAA,EAAwC;AAC3C,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,OAAO,QAAQ,MAAA,CAAO,IAAI,cAAA,CAAe,iBAAA,EAAmB,uBAAuB,CAAC,CAAA;AAAA,MACtF;AACA,MAAA,MAAM,MAAA,GAAS,MAAM,KAAA,EAAM;AAC3B,MAAA,IAAI,MAAA,EAAQ,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AACzC,MAAA,OAAO,IAAI,OAAA,CAAoB,CAAC,OAAA,EAAS,MAAA,KAAW;AAClD,QAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,UAAA,IAAI,MAAA,EAAQ;AACV,YAAA,MAAA,GAAS,IAAA;AACT,YAAA,MAAA;AAAA,cACE,IAAI,cAAA;AAAA,gBACF,wBAAA;AAAA,gBACA,iDAAiD,SAAS,CAAA,EAAA;AAAA;AAC5D,aACF;AAAA,UACF;AAAA,QACF,GAAG,SAAS,CAAA;AACZ,QAAA,MAAA,GAAS;AAAA,UACP,OAAA,EAAS,CAAC,CAAA,KAAM;AACd,YAAA,YAAA,CAAa,KAAK,CAAA;AAClB,YAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,UACX,CAAA;AAAA,UACA,MAAA,EAAQ,CAAC,CAAA,KAAM;AACb,YAAA,YAAA,CAAa,KAAK,CAAA;AAClB,YAAA,MAAA,CAAO,CAAC,CAAA;AAAA,UACV;AAAA,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAOA,SAAS,8BAA8B,SAAA,EAAgD;AACrF,EAAA,MAAM,IAAA,GAAO,IAAI,WAAA,EAAY,CAAE,OAAO,SAAS,CAAA;AAC/C,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,MAAM,KAAA,EAAM;AAAA,EACvB;AAEA,EAAA,IAAI;AACF,IAAA,oBAAA,CAAqB,IAAI,CAAA;AACzB,IAAA,OAAO,EAAE,IAAA,EAAM,UAAA,EAAY,QAAA,EAAU,IAAA,EAAK;AAAA,EAC5C,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,4BAAA,CAA6B,IAAI,CAAA,EAAG;AACtC,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,SAAA;AAAA,QACN,KAAA,EACE,KAAA,YAAiB,gBAAA,GACb,KAAA,GACA,IAAI,gBAAA,CAAiB,cAAA,EAAgB,MAAA,CAAO,KAAK,CAAA,EAAG,EAAE,KAAA,EAAO;AAAA,OACrE;AAAA,IACF;AACA,IAAA,OAAO,EAAE,MAAM,KAAA,EAAM;AAAA,EACvB;AACF;AAEA,SAAS,6BAA6B,KAAA,EAAyB;AAC7D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,KAAA;AACxD,EAAA,MAAM,IAAA,GAAO,KAAA;AACb,EAAA,OACE,OAAA,IAAW,IAAA,IACX,OAAA,IAAW,IAAA,IACX,YAAY,IAAA,IACZ,aAAA,IAAiB,IAAA,IACjB,mBAAA,IAAuB,IAAA,IACvB,WAAA,IAAe,IAAA,IACf,WAAA,IAAe,QACf,eAAA,IAAmB,IAAA;AAEvB;AAKO,SAAS,yBAAyB,QAAA,EAA8B;AACrE,EAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY,CAAE,OAAO,QAAQ,CAAA;AAC/C,EAAA,MAAM,MAAM,IAAI,UAAA,CAAW,qBAAA,CAAsB,MAAA,GAAS,MAAM,MAAM,CAAA;AACtE,EAAA,GAAA,CAAI,IAAI,qBAAqB,CAAA;AAC7B,EAAA,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,qBAAA,CAAsB,MAAM,CAAA;AAC3C,EAAA,OAAO,GAAA;AACT;AAGO,SAAS,0BAA0B,SAAA,EAAuC;AAC/E,EAAA,MAAM,IAAA,GAAO,IAAI,WAAA,EAAY,CAAE,OAAO,SAAS,CAAA;AAC/C,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,gBAAA;AAAA,MACR,cAAA;AAAA,MACA,CAAA,wCAAA,EAA2C,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA,MACxD,EAAE,KAAA;AAAM,KACV;AAAA,EACF;AACA,EAAA,oBAAA,CAAqB,IAAI,CAAA;AACzB,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,cAAc,KAAA,EAAwB;AACpD,EAAA,IAAI;AACF,IAAA,OAAO,kBAAA,CAAmB,IAAI,GAAA,CAAI,KAAK,EAAE,QAAQ,CAAA;AAAA,EACnD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,QAAA,EAA2B;AACrD,EAAA,MAAM,UAAA,GAAa,SAAS,WAAA,EAAY;AACxC,EAAA,IAAI,UAAA,KAAe,WAAA,IAAe,UAAA,KAAe,KAAA,IAAS,eAAe,OAAA,EAAS;AAChF,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,cAAA,CAAe,UAAU,CAAA,EAAG;AAC9B,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,WAAW,UAAA,CAAW,UAAU,KAAK,CAAC,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AACnE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,UAAA,CAAW,KAAA,CAAM,UAAA,CAAW,QAAQ,EAAE,CAAA;AACrD,EAAA,IAAI,cAAA,CAAe,MAAM,CAAA,EAAG;AAC1B,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAC9B,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAO,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAA,IAAK,IAAI,EAAE,CAAA;AAC/C,EAAA,MAAM,MAAM,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAA,IAAK,IAAI,EAAE,CAAA;AAC9C,EAAA,IACE,CAAC,MAAA,CAAO,SAAA,CAAU,IAAI,CAAA,IACtB,CAAC,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,IACrB,OAAO,CAAA,IACP,IAAA,GAAO,SACP,GAAA,GAAM,CAAA,IACN,MAAM,KAAA,EACN;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAA,CAAS,IAAA,IAAQ,EAAA,GAAM,GAAA,MAAS,EAAA,KAAO,GAAA;AACzC;AAEA,SAAS,eAAe,QAAA,EAA2B;AACjD,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA;AAChC,EAAA,OACE,KAAA,CAAM,MAAA,KAAW,CAAA,IACjB,KAAA,CAAM,KAAA,CAAM,CAAC,IAAA,KAAS,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,IACxC,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,KAAM,GAAA,IACrB,KAAA,CAAM,KAAA,CAAM,CAAC,IAAA,KAAS,MAAA,CAAO,IAAI,CAAA,IAAK,CAAA,IAAK,MAAA,CAAO,IAAI,KAAK,GAAG,CAAA;AAElE;AAIA,SAAS,WAAW,CAAA,EAAuB;AACzC,EAAA,IAAI,CAAA,GAAI,EAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK,CAAA,IAAK,CAAA,CAAE,CAAC,EAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACzE,EAAA,OAAO,CAAA;AACT;;;ACreA,eAAsB,yBAAyB,MAAA,EAKlB;AAC3B,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,KAAA,EAAO,WAAU,GAAI,MAAA;AAClD,EAAA,MAAM,OAAA,GAAU,MAAM,sBAAA,CAAuB,EAAE,WAAW,QAAA,EAAU,KAAA,EAAO,WAAW,CAAA;AACtF,EAAA,MAAM,SAAA,GAAkC;AAAA,IACtC,sBAAsB,OAAA,CAAQ,qBAAA;AAAA,IAC9B;AAAA,GACF;AACA,EAAA,MAAM,WAAA,GAAiC;AAAA,IACrC,IAAA,EAAM,QAAQ,WAAA,CAAY,IAAA;AAAA,IAC1B,IAAA,EAAM,QAAQ,WAAA,CAAY,IAAA;AAAA,IAC1B,UAAA,EAAY,QAAQ,WAAA,CAAY,UAAA;AAAA,IAChC,cAAA,EAAgB,QAAQ,WAAA,CAAY,cAAA;AAAA,IACpC,SAAA,EAAW,QAAQ,WAAA,CAAY,SAAA;AAAA,IAC/B,gBAAA,EAAkB,QAAQ,WAAA,CAAY,gBAAA;AAAA,IACtC,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,YAAA,EAAc,KAAK,GAAA;AAAI,GACzB;AAGA,EAAA,KAAK,oBAAoB,QAAQ,CAAA;AACjC,EAAA,OAAO,EAAE,OAAA,EAAS,SAAA,EAAW,WAAA,EAAY;AAC3C;AAWA,eAAsB,qBAAA,CACpB,SAAA,EACA,QAAA,EACA,KAAA,GAAoB,MAAA,CAAO,gBAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAA,EAC9B;AAC/B,EAAA,MAAM,cAAc,MAAM,wBAAA,CAAyB,EAAE,SAAA,EAAW,QAAA,EAAU,OAAO,CAAA;AACjF,EAAA,OAAO,WAAA,CAAY,SAAA;AACrB;AAQO,SAAS,kBAAA,CACd,YACA,SAAA,EAC4B;AAC5B,EAAA,MAAM,UAAU,SAAA,CAAU,OAAA;AAC1B,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,MACb,IAAI,cAAA;AAAA,QACF,wBAAA;AAAA,QACA;AAAA;AACF,KACF;AAAA,EACF;AACA,EAAA,OAAO,QAAQ,OAAA,CAAQ;AAAA,IACrB,IAAA,EAAM,QAAQ,WAAA,CAAY,IAAA;AAAA,IAC1B,IAAA,EAAM,QAAQ,WAAA,CAAY,IAAA;AAAA,IAC1B,UAAA,EAAY,QAAQ,WAAA,CAAY,UAAA;AAAA,IAChC,cAAA,EAAgB,QAAQ,WAAA,CAAY,cAAA;AAAA,IACpC,SAAA,EAAW,QAAQ,WAAA,CAAY,SAAA;AAAA,IAC/B,gBAAA,EAAkB,QAAQ,WAAA,CAAY,gBAAA;AAAA,IACtC,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,KAAA,EAAO,QAAQ,WAAA,CAAY,KAAA;AAAA,IAC3B,YAAA,EAAc,KAAK,GAAA;AAAI,GACxB,CAAA;AACH;;;AC3JA,IAAA,2BAAA,GAAA;AAAA,EACE,OAAA,EAAW,8CAAA;AAAA,EACX,GAAA,EAAO,iEAAA;AAAA,EACP,KAAA,EAAS,cAAA;AAAA,EACT,WAAA,EAAe,6KAAA;AAAA,EACf,IAAA,EAAQ,QAAA;AAAA,EACR,oBAAA,EAAwB,KAAA;AAAA,EACxB,QAAA,EAAY,CAAC,cAAc,CAAA;AAAA,EAC3B,UAAA,EAAc;AAAA,IACZ,YAAA,EAAgB;AAAA,MACd,IAAA,EAAQ,OAAA;AAAA,MACR,QAAA,EAAY,CAAA;AAAA,MACZ,WAAA,EAAe,qGAAA;AAAA,MACf,KAAA,EAAS,EAAE,IAAA,EAAQ,2BAAA;AAA4B,KACjD;AAAA,IACA,eAAA,EAAmB;AAAA,MACjB,IAAA,EAAQ,SAAA;AAAA,MACR,OAAA,EAAW,CAAA;AAAA,MACX,WAAA,EAAe;AAAA,KACjB;AAAA,IACA,gBAAA,EAAoB;AAAA,MAClB,IAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAe;AAAA;AACjB,GACF;AAAA,EACA,KAAA,EAAS;AAAA,IACP,iBAAA,EAAqB;AAAA,MACnB,KAAA,EAAS,mBAAA;AAAA,MACT,IAAA,EAAQ,QAAA;AAAA,MACR,oBAAA,EAAwB,KAAA;AAAA,MACxB,QAAA,EAAY,CAAC,SAAA,EAAW,cAAc,CAAA;AAAA,MACtC,UAAA,EAAc;AAAA,QACZ,OAAA,EAAW;AAAA,UACT,IAAA,EAAQ,QAAA;AAAA,UACR,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,YAAA,EAAgB;AAAA,UACd,IAAA,EAAQ,QAAA;AAAA,UACR,OAAA,EAAW,CAAA;AAAA,UACX,OAAA,EAAW,GAAA;AAAA,UACX,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,UAAA,EAAc;AAAA,UACZ,IAAA,EAAQ,SAAA;AAAA,UACR,OAAA,EAAW,CAAA;AAAA,UACX,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,UAAA,EAAc;AAAA,UACZ,IAAA,EAAQ,SAAA;AAAA,UACR,OAAA,EAAW,CAAA;AAAA,UACX,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,WAAA,EAAe,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA;AAAE;AACnD;AACF;AAEJ,CAAA;;;ACxDA,IAAA,oCAAA,GAAA;AAAA,EACE,OAAA,EAAW,8CAAA;AAAA,EACX,GAAA,EAAO,0EAAA;AAAA,EACP,KAAA,EAAS,uBAAA;AAAA,EACT,WAAA,EAAe,wJAAA;AAAA,EACf,IAAA,EAAQ,QAAA;AAAA,EACR,oBAAA,EAAwB,KAAA;AAAA,EACxB,QAAA,EAAY,CAAC,WAAW,CAAA;AAAA,EACxB,UAAA,EAAc;AAAA,IACZ,SAAA,EAAa;AAAA,MACX,IAAA,EAAQ,OAAA;AAAA,MACR,QAAA,EAAY,CAAA;AAAA,MACZ,KAAA,EAAS,EAAE,IAAA,EAAQ,6BAAA;AAA8B,KACnD;AAAA,IACA,eAAA,EAAmB,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IACrD,kBAAA,EAAsB,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IACxD,oBAAA,EAAwB,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IAC1D,uBAAA,EAA2B,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IAC7D,YAAA,EAAgB,EAAE,IAAA,EAAQ,SAAA,EAAU;AAAA,IACpC,YAAA,EAAgB;AAAA,MACd,IAAA,EAAQ,OAAA;AAAA,MACR,OAAS,EAAE,IAAA,EAAQ,CAAC,QAAA,EAAU,SAAS,CAAA;AAAE;AAC3C,GACF;AAAA,EACA,KAAA,EAAS;AAAA,IACP,mBAAA,EAAuB;AAAA,MACrB,KAAA,EAAS,qBAAA;AAAA,MACT,IAAA,EAAQ,QAAA;AAAA,MACR,oBAAA,EAAwB,KAAA;AAAA,MACxB,QAAA,EAAY,CAAC,OAAA,EAAS,kBAAA,EAAoB,cAAc,cAAc,CAAA;AAAA,MACtE,KAAA,EAAS;AAAA,QACP;AAAA,UACE,EAAA,EAAM;AAAA,YACJ,UAAA,EAAc;AAAA,cACZ,UAAA,EAAc;AAAA,gBACZ,IAAA,EAAQ,QAAA;AAAA,gBACR,QAAA,EAAY,CAAC,4BAA4B,CAAA;AAAA,gBACzC,UAAA,EAAc;AAAA,kBACZ,0BAAA,EAA8B,EAAE,KAAA,EAAS,IAAA;AAAK;AAChD;AACF,aACF;AAAA,YACA,QAAA,EAAY,CAAC,YAAY;AAAA,WAC3B;AAAA,UACA,IAAA,EAAQ;AAAA,YACN,UAAA,EAAc;AAAA,cACZ,YAAA,EAAgB,EAAE,KAAA,EAAS,KAAA;AAAM;AACnC;AACF;AACF,OACF;AAAA,MACA,UAAA,EAAc;AAAA,QACZ,KAAA,EAAS,EAAE,IAAA,EAAQ,QAAA,EAAU,aAAe,uBAAA,EAAwB;AAAA,QACpE,gBAAA,EAAoB;AAAA,UAClB,IAAA,EAAQ,QAAA;AAAA,UACR,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,UAAA,EAAc,EAAE,IAAA,EAAQ,oBAAA,EAAqB;AAAA,QAC7C,cAAgB,EAAE,IAAA,EAAQ,CAAC,MAAA,EAAQ,KAAA,EAAO,MAAM,CAAA,EAAE;AAAA,QAClD,qBAAA,EAAyB;AAAA,UACvB,IAAA,EAAQ,SAAA;AAAA,UACR,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,UAAY,EAAE,IAAA,EAAQ,CAAC,QAAA,EAAU,SAAS,CAAA,EAAE;AAAA,QAC5C,MAAA,EAAU,EAAE,IAAA,EAAQ,QAAA,EAAU,SAAW,CAAA;AAAE;AAC7C,KACF;AAAA,IACA,UAAA,EAAc;AAAA,MACZ,KAAA,EAAS,uBAAA;AAAA,MACT,IAAA,EAAQ,QAAA;AAAA,MACR,oBAAA,EAAwB,KAAA;AAAA,MACxB,QAAA,EAAY,CAAC,MAAM,CAAA;AAAA,MACnB,UAAA,EAAc;AAAA,QACZ,IAAA,EAAQ,EAAE,IAAA,EAAQ,QAAA,EAAU,aAAe,uBAAA,EAAwB;AAAA,QACnE,UAAA,EAAc;AAAA,UACZ,IAAA,EAAQ,QAAA;AAAA,UACR,OAAA,EAAW,mBAAA;AAAA,UACX,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,cAAA,EAAkB;AAAA,UAChB,IAAA,EAAQ,CAAC,eAAA,EAAiB,wBAAwB,CAAA;AAAA,UAClD,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,oBAAA,EAAwB;AAAA,UACtB,IAAA,EAAQ,QAAA;AAAA,UACR,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,0BAAA,EAA8B;AAAA,UAC5B,IAAA,EAAQ,SAAA;AAAA,UACR,WAAA,EAAe;AAAA,SACjB;AAAA,QACA,QAAA,EAAY,EAAE,IAAA,EAAQ,qBAAA;AAAsB;AAC9C,KACF;AAAA,IACA,WAAA,EAAe;AAAA,MACb,KAAA,EAAS,aAAA;AAAA,MACT,IAAA,EAAQ,QAAA;AAAA,MACR,oBAAA,EAAwB,KAAA;AAAA,MACxB,QAAA,EAAY,CAAC,QAAA,EAAU,SAAA,EAAW,YAAY,CAAA;AAAA,MAC9C,UAAA,EAAc;AAAA,QACZ,MAAA,EAAU,EAAE,IAAA,EAAQ,QAAA,EAAS;AAAA,QAC7B,OAAA,EAAW,EAAE,IAAA,EAAQ,QAAA,EAAS;AAAA,QAC9B,UAAA,EAAc,EAAE,IAAA,EAAQ,QAAA;AAAS;AACnC;AACF;AAEJ,CAAA;;;AC1GA,IAAA,6BAAA,GAAA;AAAA,EACE,OAAA,EAAW,8CAAA;AAAA,EACX,GAAA,EAAO,mEAAA;AAAA,EACP,KAAA,EAAS,gBAAA;AAAA,EACT,WAAA,EAAe,sHAAA;AAAA,EACf,IAAA,EAAQ,QAAA;AAAA,EACR,oBAAA,EAAwB,KAAA;AAAA,EACxB,QAAA,EAAY;AAAA,IACV,IAAA;AAAA,IACA,QAAA;AAAA,IACA,kBAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,IACA,sBAAA;AAAA,IACA,mBAAA;AAAA,IACA,gBAAA;AAAA,IACA,iBAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,UAAA,EAAc;AAAA,IACZ,EAAA,EAAM,EAAE,IAAA,EAAQ,QAAA,EAAU,aAAe,gBAAA,EAAiB;AAAA,IAC1D,MAAA,EAAU,EAAE,IAAA,EAAQ,CAAC,eAAe,QAAA,EAAU,aAAA,EAAe,QAAQ,CAAA,EAAE;AAAA,IACvE,kBAAoB,EAAE,IAAA,EAAQ,WAAW,OAAA,EAAW,CAAA,EAAG,SAAW,GAAA,EAAI;AAAA,IACtE,aAAA,EAAiB;AAAA,MACf,IAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAe;AAAA,KACjB;AAAA,IACA,eAAA,EAAmB,EAAE,IAAA,EAAQ,QAAA,EAAU,aAAe,oBAAA,EAAqB;AAAA,IAC3E,oBAAA,EAAwB;AAAA,MACtB,IAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAe;AAAA,KACjB;AAAA,IACA,iBAAA,EAAqB,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IACvD,cAAA,EAAkB,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IACpD,eAAA,EAAmB,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA,EAAE;AAAA,IACrD,MAAA,EAAU;AAAA,MACR,IAAA,EAAQ,OAAA;AAAA,MACR,WAAA,EAAe,2EAAA;AAAA,MACf,KAAA,EAAS,EAAE,IAAA,EAAQ,QAAA;AAAS,KAC9B;AAAA,IACA,SAAA,EAAa,EAAE,IAAA,EAAQ,SAAA,EAAW,SAAW,CAAA;AAAE;AAEnD,CAAA;;;AC3CA,IAAA,8BAAA,GAAA;AAAA,EACE,OAAA,EAAW,8CAAA;AAAA,EACX,GAAA,EAAO,oEAAA;AAAA,EACP,KAAA,EAAS,iBAAA;AAAA,EACT,WAAA,EAAe,yOAAA;AAAA,EACf,IAAA,EAAQ,QAAA;AAAA,EACR,oBAAA,EAAwB,KAAA;AAAA,EACxB,UAAY,CAAC,WAAA,EAAa,KAAA,EAAO,KAAA,EAAO,cAAc,aAAa,CAAA;AAAA,EACnE,UAAA,EAAc;AAAA,IACZ,SAAA,EAAa;AAAA,MACX,IAAA,EAAQ,QAAA;AAAA,MACR,SAAA,EAAa;AAAA,KACf;AAAA,IACA,GAAA,EAAO;AAAA,MACL,IAAA,EAAQ,QAAA;AAAA,MACR,SAAA,EAAa;AAAA,KACf;AAAA,IACA,GAAA,EAAO;AAAA,MACL,IAAA,EAAQ,CAAC,SAAA,EAAW,MAAM,CAAA;AAAA,MAC1B,WAAA,EAAe;AAAA,KACjB;AAAA,IACA,UAAA,EAAc;AAAA,MACZ,IAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAe;AAAA,KACjB;AAAA,IACA,EAAA,EAAM;AAAA,MACJ,IAAA,EAAQ,QAAA;AAAA,MACR,WAAA,EAAe;AAAA,KACjB;AAAA,IACA,WAAA,EAAe;AAAA,MACb,IAAA,EAAQ,SAAA;AAAA,MACR,OAAA,EAAW;AAAA;AACb,GACF;AAAA,EACA,KAAA,EAAS;AAAA,IACP;AAAA,MACE,EAAA,EAAM;AAAA,QACJ,YAAc,EAAE,GAAA,EAAO,EAAE,KAAA,EAAS,WAAU,EAAE;AAAA,QAC9C,QAAA,EAAY,CAAC,KAAK;AAAA,OACpB;AAAA,MACA,IAAA,EAAQ;AAAA,QACN,YAAc,EAAE,EAAA,EAAM,EAAE,IAAA,EAAQ,UAAS,EAAE;AAAA,QAC3C,QAAA,EAAY,CAAC,IAAI;AAAA;AACnB;AACF;AAEJ,CAAA;;;ACnBA,IAAM,GAAA,GAAM,IAAI,OAAA,CAAQ,EAAE,WAAW,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAA;AAElD,IAAM,yBAAA,GACX,GAAA,CAAI,OAAA,CAAsB,2BAAkB;AAEvC,IAAM,kCAAA,GACX,GAAA,CAAI,OAAA,CAA+B,oCAA2B,CAAA;AAG9D,GAAA,CAAI,OAAA,CAAwB,6BAAoB;AAGhD,GAAA,CAAI,OAAA,CAAyB,8BAAqB;AAG7C,SAAS,gBAAgB,MAAA,EAAkD;AAChF,EAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,GAAG,OAAO,0BAAA;AAC3C,EAAA,OAAO,OACJ,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,EAAE,YAAA,IAAgB,QAAQ,CAAA,CAAA,EAAI,CAAA,CAAE,WAAW,YAAY,CAAA,CAAA,CAAG,MAAM,CAAA,CAC9E,KAAK,IAAI,CAAA;AACd;;;ACxBA,IAAM,2BAAA,GAA8B,GAAA;AAOpC,eAAsB,QAAA,CACpB,KAAA,EACA,QAAA,EACA,SAAA,GAAoB,2BAAA,EACQ;AAC5B,EAAA,MAAM,EAAE,OAAA,EAAS,qBAAA,EAAsB,GAAI,KAAA;AAC3C,EAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,qBAAA,KAA0B,IAAA,EAAM;AACtD,IAAA,MAAM,IAAI,cAAA,CAAe,iBAAA,EAAmB,iDAAiD,CAAA;AAAA,EAC/F;AAEA,EAAA,MAAM,QAAQ,MAAA,CAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAA;AACvD,EAAA,MAAM,WAAW,MAAM,OAAA,CAAQ,mBAAmB,KAAA,CAAM,KAAK,GAAG,SAAS,CAAA;AAEzE,EAAA,MAAM,QAAA,GAAW,MAAM,iBAAA,CAAkB;AAAA,IACvC,QAAA;AAAA,IACA,aAAA,EAAe,KAAA;AAAA,IACf,sBAAA,EAAwB,qBAAA;AAAA,IACxB,MAAA,EAAQ,oBAAoB,QAAQ,CAAA;AAAA,IACpC;AAAA,GACD,CAAA;AAED,EAAA,OAAO;AAAA,IACL,MAAM,QAAA,CAAS,IAAA;AAAA,IACf,MAAM,QAAA,CAAS,IAAA;AAAA,IACf,YAAY,QAAA,CAAS,UAAA;AAAA,IACrB,gBAAgB,QAAA,CAAS,cAAA;AAAA,IACzB,WAAW,QAAA,CAAS,SAAA;AAAA,IACpB,kBAAkB,QAAA,CAAS,gBAAA;AAAA,IAC3B,OAAO,QAAA,CAAS,KAAA;AAAA,IAChB,OAAO,QAAA,CAAS,KAAA;AAAA,IAChB,OAAO,QAAA,CAAS,KAAA;AAAA,IAChB,OAAO,QAAA,CAAS,KAAA;AAAA,IAChB,YAAA,EAAc,KAAK,GAAA;AAAI,GACzB;AACF;AAEO,SAAS,kBAAA,CACd,KAAA,EACA,QAAA,EACA,SAAA,GAAoB,2BAAA,EACQ;AAC5B,EAAA,IAAI,KAAA,CAAM,oBAAoB,IAAA,EAAM;AAClC,IAAA,OAAO,KAAA,CAAM,eAAA;AAAA,EACf;AACA,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,EAAQ,CAC7B,IAAA,CAAK,MAAM,QAAA,CAAS,KAAA,EAAO,QAAA,EAAU,SAAS,CAAC,CAAA,CAC/C,QAAQ,MAAM;AACb,IAAA,IAAI,KAAA,CAAM,oBAAoB,OAAA,EAAS;AACrC,MAAA,KAAA,CAAM,eAAA,GAAkB,IAAA;AAAA,IAC1B;AAAA,EACF,CAAC,CAAA;AACH,EAAA,KAAA,CAAM,eAAA,GAAkB,OAAA;AACxB,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,MAAM,CAAA,EAAuB;AACpC,EAAA,IAAI,CAAA,GAAI,EAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK,CAAA,IAAK,CAAA,CAAE,CAAC,EAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACzE,EAAA,OAAO,CAAA;AACT;;;AC1DO,IAAM,iBAAA,GAAoB,GAAA;AAgCjC,eAAsB,cAAc,OAAA,EAAiD;AACnF,EAAA,MAAM,EAAE,aAAY,GAAI,OAAA;AACxB,EAAA,IAAI,CAAC,kCAAA,CAAmC,WAAW,CAAA,EAAG;AACpD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,iCAAA,EAAoC,eAAA,CAAgB,kCAAA,CAAmC,MAAM,CAAC,CAAA;AAAA,KAChG;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAW,WAAA,CAAY,SAAA,CAAU,CAAC,CAAA;AACxC,EAAA,sBAAA,CAAuB,QAAQ,CAAA;AAC/B,EAAA,MAAM,YAAY,WAAA,CAAY,uBAAA;AAC9B,EAAA,MAAM,SAAA,GACJ,OAAA,CAAQ,SAAA,IACR,uBAAA,CAAwB,EAAE,OAAO,QAAA,CAAS,KAAA,EAAO,gBAAA,EAAkB,SAAA,EAAW,CAAA;AAChF,EAAA,MAAM,UAAU,OAAA,EAAQ;AAGxB,EAAA,MAAM,QAAQ,MAAA,CAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAA;AAEvD,EAAA,IAAI,WAAA;AACJ,EAAA,IAAI;AACF,IAAA,WAAA,GAAc,MAAM,wBAAA,CAAyB,EAAE,WAAW,QAAA,EAAU,KAAA,EAAO,WAAW,CAAA;AAAA,EACxF,SAAS,GAAA,EAAK;AAEZ,IAAA,SAAA,CAAU,KAAA,EAAM;AAChB,IAAA,MAAM,GAAA;AAAA,EACR;AAEA,EAAA,MAAM,KAAA,GAAsB;AAAA,IAC1B,QAAA,EAAU,IAAA;AAAA,IACV,SAAA;AAAA,IACA,IAAA,EAAM,WAAA;AAAA,IACN,aAAa,WAAA,CAAY,WAAA;AAAA,IACzB,SAAS,WAAA,CAAY,OAAA;AAAA,IACrB,KAAA;AAAA,IACA,qBAAA,EAAuB,YAAY,SAAA,CAAU,oBAAA;AAAA,IAC7C,aAAA,EAAe,IAAA;AAAA,IACf,eAAA,EAAiB,IAAA;AAAA,IACjB,cAAA,EAAgB,IAAA;AAAA,IAChB,uBAAA,sBAA6B,GAAA,EAAI;AAAA,IACjC,KAAA,GAAc;AACZ,MAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA,IACxB;AAAA,GACF;AAEA,EAAA,WAAA,CAAY,QAAQ,OAAA,CAAQ,CAAC,UAAU,iBAAA,CAAkB,KAAA,EAAO,KAAK,CAAC,CAAA;AACtE,EAAA,gBAAA,CAAiB,OAAO,QAAQ,CAAA;AAEhC,EAAA,OAAO,oBAAoB,KAAK,CAAA;AAClC;AAEA,SAAS,uBAAuB,QAAA,EAA4D;AAC1F,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,IAAI,GAAA,CAAI,QAAA,CAAS,KAAK,CAAA,CAAE,QAAA;AAAA,EACrC,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,QAAQ,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,QAAA,CAAS,KAAK,CAAA,CAAE,CAAA;AACtE,IAAC,MAA8B,KAAA,GAAQ,GAAA;AACvC,IAAA,MAAM,KAAA;AAAA,EACR;AACA,EAAA,IAAI,SAAS,WAAA,EAAY,KAAM,QAAA,CAAS,gBAAA,CAAiB,aAAY,EAAG;AACtE,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,8BAAA,EAAiC,QAAQ,CAAA,iCAAA,EAAoC,QAAA,CAAS,gBAAgB,CAAA;AAAA,KACxG;AAAA,EACF;AACF;AAGO,SAAS,aAAa,OAAA,EAAwB;AACnD,EAAA,eAAA,CAAgB,OAAO,EAAE,KAAA,EAAM;AACjC;AAOA,SAAS,gBAAA,CACP,OACA,QAAA,EACM;AACN,EAAA,IAAI,KAAA,CAAM,YAAY,IAAA,EAAM;AAC5B,EAAA,MAAM,eAAA,GAAkB,KAAA,CAAM,IAAA,CAAK,eAAA,IAAmB,iBAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,IAAA,KAAK,WAAA,CAAY,OAAO,QAAQ,CAAA;AAAA,EAClC,GAAG,eAAe,CAAA;AAElB,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAQ,WAAW,KAAA,EAAO;AACnE,IAAC,MAA4B,KAAA,EAAM;AAAA,EACrC;AACA,EAAA,KAAA,CAAM,aAAA,GAAgB,KAAA;AACxB;AAEA,eAAe,WAAA,CACb,OACA,QAAA,EACe;AACf,EAAA,KAAA,CAAM,aAAA,GAAgB,IAAA;AACtB,EAAA,IAAI,KAAA,CAAM,YAAY,IAAA,IAAQ,KAAA,CAAM,UAAU,IAAA,IAAQ,KAAA,CAAM,0BAA0B,IAAA,EAAM;AAC1F,IAAA;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAA,KAAA,CAAM,cAAc,MAAM,kBAAA;AAAA,MACxB,KAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,KACb;AACA,IAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,IAAA,gBAAA,CAAiB,OAAO,QAAQ,CAAA;AAAA,EAClC,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,KAAA,GAAQ,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AAChE,IAAA,iBAAA,CAAkB,OAAO,KAAK,CAAA;AAAA,EAChC;AACF","file":"chunk-BWCGNTN5.js","sourcesContent":["export interface ExponentialBackoffOptions {\n readonly initialDelayMs: number;\n readonly maxDelayMs: number;\n readonly multiplier?: number;\n readonly jitterRatio?: number;\n readonly random?: () => number;\n}\n\nexport interface ExponentialBackoff {\n nextDelayMs(): number;\n reset(): void;\n}\n\n/**\n * Stateful exponential backoff shared by reconnecting SDK consumers.\n * Jitter avoids synchronized reconnect storms while reset makes a healthy\n * connection return to the normal cadence.\n */\nexport function createExponentialBackoff(options: ExponentialBackoffOptions): ExponentialBackoff {\n if (!Number.isFinite(options.initialDelayMs) || options.initialDelayMs <= 0) {\n throw new Error(\"initialDelayMs must be a positive finite number\");\n }\n if (!Number.isFinite(options.maxDelayMs) || options.maxDelayMs < options.initialDelayMs) {\n throw new Error(\"maxDelayMs must be finite and >= initialDelayMs\");\n }\n if (\n options.multiplier !== undefined &&\n (!Number.isFinite(options.multiplier) || options.multiplier < 1)\n ) {\n throw new Error(\"multiplier must be finite and >= 1\");\n }\n if (\n options.jitterRatio !== undefined &&\n (!Number.isFinite(options.jitterRatio) || options.jitterRatio < 0 || options.jitterRatio > 1)\n ) {\n throw new Error(\"jitterRatio must be between 0 and 1\");\n }\n\n const initialDelayMs = options.initialDelayMs;\n const maxDelayMs = options.maxDelayMs;\n const multiplier = options.multiplier ?? 2;\n const jitterRatio = options.jitterRatio ?? 0;\n const random = options.random ?? Math.random;\n let attempt = 0;\n\n return {\n nextDelayMs(): number {\n const baseDelayMs = Math.min(maxDelayMs, initialDelayMs * multiplier ** attempt);\n attempt += 1;\n\n if (jitterRatio === 0) return Math.round(baseDelayMs);\n\n const lowerBound = baseDelayMs * (1 - jitterRatio);\n const upperBound = baseDelayMs * (1 + jitterRatio);\n const boundedRandom = Math.min(Math.max(random(), 0), 1);\n return Math.min(\n maxDelayMs,\n Math.round(lowerBound + (upperBound - lowerBound) * boundedRandom),\n );\n },\n reset(): void {\n attempt = 0;\n },\n };\n}\n","/**\n * A tiny observable state holder shared by the transports. Keeps the\n * lifecycle-transition plumbing in one place so each transport only decides\n * *when* to transition, not *how* to notify.\n */\n\nimport type { ConnectionState, Unsubscribe } from \"./types.js\";\n\nexport interface StateController {\n get(): ConnectionState;\n /** Set the state; notifies listeners only when the value actually changes. */\n set(next: ConnectionState): void;\n onChange(listener: (state: ConnectionState) => void): Unsubscribe;\n}\n\nexport function createStateController(initial: ConnectionState): StateController {\n let state = initial;\n const listeners = new Set<(state: ConnectionState) => void>();\n return {\n get: () => state,\n set(next) {\n if (next === state) return;\n state = next;\n for (const listener of listeners) listener(next);\n },\n onChange(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n","/**\n * WebSocket transport - the one genuinely functional piece of the skeleton.\n *\n * `connect()` opens a real WebSocket and drives the lifecycle\n * (`connecting -> open`, `-> closed` on close/error/abort). It is a pure byte\n * channel: the Noise XX handshake and TDX attestation are session-level steps\n * layered on top (see ./handshake), not part of opening the socket. `send`\n * writes one raw frame to the socket; the WebSocket message boundary is the\n * frame boundary, so there is no extra length prefix (Noise lives above).\n *\n * The WebSocket implementation is injected (default: the platform global\n * `WebSocket`, present in browsers and Node 22+), so tests connect to a local\n * mock server with no external network.\n */\n\nimport { TransportError } from \"../core/errors.js\";\nimport { createStateController } from \"./stateController.js\";\nimport type {\n NoiseWebSocketTransportOptions,\n Transport,\n Unsubscribe,\n WebSocketFactory,\n WebSocketLike,\n} from \"./types.js\";\n\nconst DEFAULT_CONNECT_TIMEOUT_MS = 30_000;\n\nfunction defaultWebSocketFactory(url: string): WebSocketLike {\n const ctor = (globalThis as { WebSocket?: new (url: string) => WebSocketLike }).WebSocket;\n if (!ctor) {\n throw new TransportError(\n \"WS_HANDSHAKE_FAILED\",\n \"no global WebSocket available; pass options.webSocketFactory\",\n );\n }\n return new ctor(url);\n}\n\nfunction toUint8Array(data: unknown): Uint8Array {\n if (data instanceof Uint8Array) return data;\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n if (ArrayBuffer.isView(data)) {\n return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n }\n if (typeof data === \"string\") return new TextEncoder().encode(data);\n throw new TransportError(\"NOISE_FRAME_TOO_LARGE\", \"unsupported inbound frame type\");\n}\n\nexport function noiseWebSocketTransport(options: NoiseWebSocketTransportOptions): Transport {\n const factory: WebSocketFactory = options.webSocketFactory ?? defaultWebSocketFactory;\n const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;\n const sc = createStateController(\"idle\");\n const messageListeners = new Set<(frame: Uint8Array) => void>();\n let socket: WebSocketLike | null = null;\n\n function teardown() {\n if (sc.get() === \"closed\") return;\n sc.set(\"closing\");\n const ws = socket;\n socket = null;\n if (ws) {\n ws.onopen = null;\n ws.onerror = null;\n ws.onmessage = null;\n ws.onclose = null;\n try {\n ws.close();\n } catch {\n // Closing an already-closing socket is fine.\n }\n }\n sc.set(\"closed\");\n }\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\n connect(signal) {\n if (sc.get() === \"open\") return Promise.resolve();\n if (signal?.aborted) {\n return Promise.reject(\n new TransportError(\"CONNECTION_LOST\", \"connect aborted before it started\"),\n );\n }\n sc.set(\"connecting\");\n\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const ws = factory(options.wsUrl);\n socket = ws;\n ws.binaryType = \"arraybuffer\";\n\n const cleanupConnect = () => {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n };\n const fail = (error: TransportError) => {\n if (settled) return;\n settled = true;\n cleanupConnect();\n teardown();\n reject(error);\n };\n const onAbort = () => fail(new TransportError(\"CONNECTION_LOST\", \"connect aborted\"));\n const timer = setTimeout(\n () =>\n fail(\n new TransportError(\n \"WS_HANDSHAKE_FAILED\",\n `connect timed out after ${connectTimeoutMs}ms`,\n ),\n ),\n connectTimeoutMs,\n );\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n ws.onopen = () => {\n if (settled) return;\n settled = true;\n cleanupConnect();\n // The socket is the live byte channel from here on.\n ws.onmessage = (event) => {\n const frame = toUint8Array(event.data);\n for (const listener of messageListeners) listener(frame);\n };\n ws.onclose = () => teardown();\n ws.onerror = () => teardown();\n sc.set(\"open\");\n resolve();\n };\n ws.onerror = () =>\n fail(new TransportError(\"WS_HANDSHAKE_FAILED\", \"socket error during connect\"));\n ws.onclose = () =>\n fail(new TransportError(\"CONNECTION_LOST\", \"socket closed during connect\"));\n });\n },\n\n send(frame: Uint8Array) {\n const ws = socket;\n if (sc.get() !== \"open\" || !ws) {\n throw new TransportError(\"CONNECTION_LOST\", \"cannot send on a non-open transport\");\n }\n // The WebSocket message boundary is the frame boundary: write the raw\n // bytes with no extra length prefix. Noise framing lives above this.\n ws.send(frame);\n },\n\n close() {\n teardown();\n },\n };\n}\n","/**\n * Noise XX handshake - DH:X25519, Cipher:ChaChaPoly, Hash:SHA256.\n *\n * Port of `web/src/lib/coordinator/noise-xx.ts` into the SDK. Implements the\n * Noise_XX_25519_ChaChaPoly_SHA256 pattern. Mirrors the Rust responder in\n * `tee/coordinator/src/noise_xx.rs` exactly, so it interoperates with the live\n * coordinator.\n *\n * Initiator message flow:\n * Write msg1: -> e (32 bytes)\n * Read msg2: <- e, ee, s, es (96 bytes)\n * Write msg3: -> s, se (64 bytes)\n * => NoiseTransport for encrypted application I/O\n *\n * SDK conventions: no exported `class`. The handshake state and transport are\n * exposed as plain objects with method properties, created by free functions.\n * Never log secrets, nonces, or raw decrypted payloads.\n *\n * @module JW-138 / JW-431\n */\n\nimport { generateKeyPair, sharedKey } from \"@stablelib/x25519\";\nimport { ChaCha20Poly1305 } from \"@stablelib/chacha20poly1305\";\nimport { hash as sha256Hash, SHA256 } from \"@stablelib/sha256\";\nimport { HMAC } from \"@stablelib/hmac\";\n\nconst PROTOCOL_NAME = \"Noise_XX_25519_ChaChaPoly_SHA256\"; // exactly 32 bytes\n\n// ── Public plain-object interfaces ───────────────────────────────────────────\n\n/**\n * Post-handshake encrypted byte channel with split send/recv keys.\n *\n * Returned by {@link NoiseXXInitiator.writeMessage3} (initiator role) and by\n * {@link NoiseXXResponder.readMessage3} (responder role, in-process test peer).\n */\nexport interface NoiseTransport {\n /** Encrypt one application frame with the send key, advancing the send nonce. */\n encrypt(plaintext: Uint8Array): Uint8Array;\n /** Decrypt one application frame with the recv key, advancing the recv nonce. */\n decrypt(ciphertext: Uint8Array): Uint8Array;\n}\n\n/** Noise XX initiator handshake handle. */\nexport interface NoiseXXInitiator {\n /** msg1: -> e (32 bytes). */\n writeMessage1(): Uint8Array;\n /** msg2: <- e, ee, s, es (96 bytes from responder). Reveals the remote static key. */\n readMessage2(msg: Uint8Array): void;\n /** msg3: -> s, se (64 bytes to responder), plus the split transport. */\n writeMessage3(): { message: Uint8Array; transport: NoiseTransport };\n /**\n * Responder's static X25519 public key, decrypted from msg2.\n * `null` until {@link readMessage2} has been called successfully.\n *\n * This is the value attestation verification compares against\n * `REPORT_DATA[32:64]` and the attestation `pubkey` field.\n */\n readonly remoteStaticPublicKey: Uint8Array | null;\n}\n\n/** Noise XX responder handshake handle (in-process test/loopback peer). */\nexport interface NoiseXXResponder {\n /** msg1: <- e (32 bytes from initiator). */\n readMessage1(msg: Uint8Array): void;\n /** msg2: -> e, ee, s, es (96 bytes to initiator). */\n writeMessage2(): Uint8Array;\n /** msg3: <- s, se (64 bytes from initiator), plus the split transport. */\n readMessage3(msg: Uint8Array): NoiseTransport;\n /**\n * This responder's static X25519 public key. The initiator recovers exactly\n * this value from msg2; the loopback attestation response echoes it as the\n * bound `pubkey` field.\n */\n readonly staticPublicKey: Uint8Array;\n}\n\n// ── Symmetric state (internal) ───────────────────────────────────────────────\n\nfunction noiseNonce(n: number): Uint8Array {\n const buf = new Uint8Array(12);\n // 4 zero bytes + 8-byte little-endian counter\n const view = new DataView(buf.buffer);\n view.setUint32(4, n & 0xffffffff, true);\n view.setUint32(8, Math.floor(n / 0x100000000) & 0xffffffff, true);\n return buf;\n}\n\nfunction hkdf2(ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array] {\n const mac1 = new HMAC(SHA256, ck);\n mac1.update(ikm);\n const temp = mac1.digest();\n\n const mac2 = new HMAC(SHA256, temp);\n mac2.update(new Uint8Array([1]));\n const out1 = mac2.digest();\n\n const mac3 = new HMAC(SHA256, temp);\n mac3.update(out1);\n mac3.update(new Uint8Array([2]));\n const out2 = mac3.digest();\n\n return [out1, out2];\n}\n\ninterface NoiseSymState {\n h: Uint8Array; // handshake hash, 32 bytes\n ck: Uint8Array; // chaining key, 32 bytes\n k: Uint8Array | null; // AEAD key, 32 bytes\n n: number; // nonce counter\n mixHash(data: Uint8Array): void;\n mixKey(ikm: Uint8Array): void;\n encryptAndHash(plaintext: Uint8Array): Uint8Array;\n decryptAndHash(ciphertext: Uint8Array): Uint8Array;\n /** Returns [k1, k2] = HKDF(ck, \"\"). k1 = initiator->responder, k2 = responder->initiator. */\n split(): [Uint8Array, Uint8Array];\n}\n\nfunction createSymState(): NoiseSymState {\n const proto = new TextEncoder().encode(PROTOCOL_NAME);\n const h0 = new Uint8Array(32);\n h0.set(proto);\n const ck0 = new Uint8Array(32);\n ck0.set(h0);\n\n const ss: NoiseSymState = {\n h: h0,\n ck: ck0,\n k: null,\n n: 0,\n\n mixHash(data: Uint8Array): void {\n const combined = new Uint8Array(this.h.length + data.length);\n combined.set(this.h);\n combined.set(data, this.h.length);\n this.h = sha256Hash(combined);\n },\n\n mixKey(ikm: Uint8Array): void {\n const [newCk, newK] = hkdf2(this.ck, ikm);\n this.ck = newCk;\n this.k = newK;\n this.n = 0;\n },\n\n encryptAndHash(plaintext: Uint8Array): Uint8Array {\n if (!this.k) {\n this.mixHash(plaintext);\n return new Uint8Array(plaintext);\n }\n const aead = new ChaCha20Poly1305(this.k);\n const ct = aead.seal(noiseNonce(this.n), plaintext, this.h);\n this.n++;\n this.mixHash(ct);\n return ct;\n },\n\n decryptAndHash(ciphertext: Uint8Array): Uint8Array {\n if (!this.k) {\n this.mixHash(ciphertext);\n return new Uint8Array(ciphertext);\n }\n const aead = new ChaCha20Poly1305(this.k);\n const pt = aead.open(noiseNonce(this.n), ciphertext, this.h);\n if (!pt) throw new Error(\"Noise: AEAD decryption failed\");\n this.n++;\n this.mixHash(ciphertext);\n return pt;\n },\n\n split(): [Uint8Array, Uint8Array] {\n const [k1, k2] = hkdf2(this.ck, new Uint8Array(0));\n // k1 = initiator->responder, k2 = responder->initiator\n return [k1, k2];\n },\n };\n\n ss.mixHash(new Uint8Array(0)); // empty prologue\n return ss;\n}\n\n// ── Transport ────────────────────────────────────────────────────────────────\n\n/**\n * Create a transport over a fixed (sendKey, recvKey) pair. Each direction has\n * its own monotonically increasing nonce. AEAD associated data is empty for\n * application frames (matches the Rust responder).\n */\nexport function createNoiseTransport(sendKey: Uint8Array, recvKey: Uint8Array): NoiseTransport {\n let sendN = 0;\n let recvN = 0;\n return {\n encrypt(plaintext: Uint8Array): Uint8Array {\n const aead = new ChaCha20Poly1305(sendKey);\n const ct = aead.seal(noiseNonce(sendN), plaintext, undefined);\n sendN++;\n return ct;\n },\n decrypt(ciphertext: Uint8Array): Uint8Array {\n const aead = new ChaCha20Poly1305(recvKey);\n const pt = aead.open(noiseNonce(recvN), ciphertext, undefined);\n if (!pt) throw new Error(\"Noise: transport decryption failed\");\n recvN++;\n return pt;\n },\n };\n}\n\n// ── Initiator handshake ──────────────────────────────────────────────────────\n\n/**\n * Create a Noise XX initiator. Generates a fresh static and ephemeral X25519\n * key pair. Drive it with writeMessage1 -> readMessage2 -> writeMessage3.\n */\nexport function createNoiseXXInitiator(): NoiseXXInitiator {\n const staticKeyPair = generateKeyPair();\n const ephKeyPair = generateKeyPair();\n const ss = createSymState();\n let remoteEphPub: Uint8Array | null = null;\n let remoteStaticPub: Uint8Array | null = null;\n\n return {\n get remoteStaticPublicKey(): Uint8Array | null {\n return remoteStaticPub;\n },\n\n writeMessage1(): Uint8Array {\n ss.mixHash(ephKeyPair.publicKey);\n return new Uint8Array(ephKeyPair.publicKey);\n },\n\n readMessage2(msg: Uint8Array): void {\n if (msg.length < 96) {\n throw new Error(`noise msg2: expected >=96 bytes, got ${msg.length}`);\n }\n\n // e: responder ephemeral public key (32 bytes)\n remoteEphPub = msg.slice(0, 32);\n ss.mixHash(remoteEphPub);\n\n // ee: DH(our ephemeral, their ephemeral)\n const dhEE = sharedKey(ephKeyPair.secretKey, remoteEphPub);\n ss.mixKey(dhEE);\n\n // s: decrypt responder's static public key (32 + 16 tag = 48 bytes).\n // Stored for JW-145 channel binding (compared against the pubkey bound\n // into the TDX quote's REPORT_DATA[32:64]).\n remoteStaticPub = ss.decryptAndHash(msg.slice(32, 80));\n\n // es (initiator): DH(e=our_ephemeral, rs=responder_static)\n const dhES = sharedKey(ephKeyPair.secretKey, remoteStaticPub);\n ss.mixKey(dhES);\n\n // empty payload (16-byte tag)\n if (msg.length > 80) {\n ss.decryptAndHash(msg.slice(80));\n }\n },\n\n writeMessage3(): { message: Uint8Array; transport: NoiseTransport } {\n if (!remoteEphPub) {\n throw new Error(\"noise msg3: must call readMessage2 first\");\n }\n\n // s: encrypt our static public key (32 + 16 tag = 48 bytes)\n const encS = ss.encryptAndHash(staticKeyPair.publicKey);\n\n // se (initiator): DH(s=our_static, re=responder_ephemeral)\n const dhSE = sharedKey(staticKeyPair.secretKey, remoteEphPub);\n ss.mixKey(dhSE);\n\n // empty payload\n const encPayload = ss.encryptAndHash(new Uint8Array(0));\n\n const message = new Uint8Array(encS.length + encPayload.length);\n message.set(encS);\n message.set(encPayload, encS.length);\n\n const [sendKey, recvKey] = ss.split();\n // Initiator sends with k1, receives with k2.\n return { message, transport: createNoiseTransport(sendKey, recvKey) };\n },\n };\n}\n\n// ── Responder handshake (in-process test/loopback peer) ──────────────────────\n\n/**\n * Create a Noise XX responder. Mirrors the Rust/Go responder so an in-process\n * round-trip test can run without a real coordinator. Drive it with\n * readMessage1 -> writeMessage2 -> readMessage3.\n */\nexport function createNoiseXXResponder(): NoiseXXResponder {\n const staticKeyPair = generateKeyPair();\n const ephKeyPair = generateKeyPair();\n const ss = createSymState();\n let remoteEphPub = new Uint8Array(32);\n\n return {\n get staticPublicKey(): Uint8Array {\n return new Uint8Array(staticKeyPair.publicKey);\n },\n\n readMessage1(msg: Uint8Array): void {\n remoteEphPub = msg.slice(0, 32);\n ss.mixHash(remoteEphPub);\n },\n\n writeMessage2(): Uint8Array {\n ss.mixHash(ephKeyPair.publicKey);\n const dhEE = sharedKey(ephKeyPair.secretKey, remoteEphPub);\n ss.mixKey(dhEE);\n const encS = ss.encryptAndHash(staticKeyPair.publicKey);\n const dhES = sharedKey(staticKeyPair.secretKey, remoteEphPub);\n ss.mixKey(dhES);\n const encPayload = ss.encryptAndHash(new Uint8Array(0));\n const msg = new Uint8Array(32 + encS.length + encPayload.length);\n msg.set(ephKeyPair.publicKey);\n msg.set(encS, 32);\n msg.set(encPayload, 32 + encS.length);\n return msg;\n },\n\n readMessage3(msg: Uint8Array): NoiseTransport {\n const remoteSBytes = ss.decryptAndHash(msg.slice(0, 48));\n const dhSE = sharedKey(ephKeyPair.secretKey, remoteSBytes);\n ss.mixKey(dhSE);\n if (msg.length > 48) {\n ss.decryptAndHash(msg.slice(48));\n }\n const [k1, k2] = ss.split();\n // Responder sends with k2, receives with k1.\n return createNoiseTransport(k2, k1);\n },\n };\n}\n","/**\n * Secure channel: Noise XX handshake + TDX attestation over a raw transport.\n *\n * Free functions, no class (SDK conformance). Given an open {@link Transport}\n * and a {@link CoordinatorEndpoint}, {@link establishSecureChannel} drives:\n *\n * 1. the Noise XX handshake (initiator role) over the raw byte channel:\n * -> msg1 (e) send raw\n * <- msg2 (e, ee, s, es) read raw, reveals the responder static pubkey\n * -> msg3 (s, se) send raw, yields the split NoiseTransport\n * 2. the attestation exchange over the freshly-split (but not-yet-promoted)\n * Noise transport:\n * -> encrypt(encodeAttestationRequest(nonceHex))\n * <- decodeAttestationResponse(decrypt(frame)) -> verifyAttestation\n *\n * On success the pending Noise transport is promoted to the live cipher and an\n * attested channel handle is returned: `send`/`onMessage` transparently\n * Noise-encrypt/decrypt application frames over the raw transport.\n *\n * The release pin (mrtd, intelRootFingerprint, azureMaa) and the endpoint's\n * requiredMode map to the verifier's {@link AttestationPolicy}. The loopback\n * local-attestation fallback (ADR-0037) is only enabled when the endpoint host\n * is a loopback address - it must never be honored for a remote coordinator.\n *\n * Never log secrets, nonces, shares, or decrypted payloads (spec section 9).\n *\n * @module JW-428\n */\n\nimport { AttestationError, TransportError } from \"../core/errors.js\";\nimport {\n verifyAttestation,\n assertAttestResponse,\n type AttestationPolicy,\n type AttestedMetadata,\n type AttestResponse,\n} from \"../attestation/verifier.js\";\nimport { createNoiseXXInitiator, type NoiseTransport } from \"../transport/noiseXx.js\";\nimport type { Transport, Unsubscribe } from \"../transport/types.js\";\nimport type { CoordinatorEndpoint } from \"../schemas/types.generated.js\";\n\n/**\n * Prefix that tags an attestation control frame. Ported verbatim from the\n * canonical client so the SDK and the live coordinator agree on the wire shape.\n */\nexport const ATTEST_REQUEST_PREFIX = new TextEncoder().encode(\"invisible-attest-v1\\0\");\n\n/** Default deadline for the whole handshake + attestation exchange. */\nconst DEFAULT_CHANNEL_TIMEOUT_MS = 30_000;\n\n/** An established, attested Noise channel over a raw transport. */\nexport interface SecureChannel {\n /** Verified attestation metadata for the coordinator this channel reached. */\n readonly attestation: AttestedMetadata;\n /** The coordinator's Noise static public key, pinned for this channel. */\n readonly remoteStaticPublicKey: Uint8Array;\n /** Request re-attestation without consuming application frames as responses. */\n requestAttestation(nonceHex: string, timeoutMs: number): Promise<AttestResponse>;\n /** Encrypt and send one application frame over the raw transport. */\n send(plaintext: Uint8Array): void;\n /** Subscribe to decrypted inbound application frames. */\n onMessage(handler: (plaintext: Uint8Array) => void): Unsubscribe;\n /** Subscribe to fatal channel failures such as Noise decrypt desync. */\n onFatal(handler: (error: Error) => void): Unsubscribe;\n /** Tear down the channel: detach listeners and stop accepting frames. */\n close(): void;\n}\n\n/** Options for {@link establishSecureChannel}. */\nexport interface EstablishSecureChannelOptions {\n /** The open raw byte channel to layer Noise + attestation over. */\n readonly transport: Transport;\n /** The endpoint being attested (release pin, requiredMode, host). */\n readonly endpoint: CoordinatorEndpoint;\n /** Fresh 32-byte CSPRNG nonce, bound into the attestation request. */\n readonly nonce: Uint8Array;\n /** Whole-exchange deadline in ms. Defaults to {@link DEFAULT_CHANNEL_TIMEOUT_MS}. */\n readonly timeoutMs?: number;\n}\n\n/**\n * Run the Noise XX handshake then the attestation exchange over `transport`,\n * returning an attested {@link SecureChannel}.\n *\n * @throws TransportError if the raw channel fails or the handshake is malformed.\n * @throws AttestationError if attestation verification fails.\n */\nexport async function establishSecureChannel(\n options: EstablishSecureChannelOptions,\n): Promise<SecureChannel> {\n const { transport, endpoint, nonce } = options;\n const timeoutMs = options.timeoutMs ?? DEFAULT_CHANNEL_TIMEOUT_MS;\n\n if (transport.state() !== \"open\") {\n throw new TransportError(\"CONNECTION_LOST\", \"secure channel requires an open transport\");\n }\n\n // Inbound raw frames are funneled into a single-slot queue. The handshake is\n // strictly request/response, so at most one frame is awaited at a time.\n const inbound = createFrameReader(transport);\n\n try {\n const initiator = createNoiseXXInitiator();\n\n // msg1: -> e\n transport.send(initiator.writeMessage1());\n\n // msg2: <- e, ee, s, es\n const msg2 = await inbound.next(timeoutMs);\n try {\n initiator.readMessage2(msg2);\n } catch (cause) {\n throw new TransportError(\"NOISE_HANDSHAKE_FAILED\", `readMessage2 failed: ${String(cause)}`, {\n cause,\n });\n }\n\n const remoteStaticPublicKey = initiator.remoteStaticPublicKey;\n if (!remoteStaticPublicKey) {\n throw new TransportError(\n \"NOISE_HANDSHAKE_FAILED\",\n \"missing responder static pubkey after readMessage2\",\n );\n }\n\n // msg3: -> s, se, plus the split (pending) Noise transport.\n let pending: NoiseTransport;\n try {\n const result = initiator.writeMessage3();\n transport.send(result.message);\n pending = result.transport;\n } catch (cause) {\n throw new TransportError(\"NOISE_HANDSHAKE_FAILED\", `writeMessage3 failed: ${String(cause)}`, {\n cause,\n });\n }\n\n // Attestation request over the pending Noise transport. Requesting it over\n // the same channel binds the attestation to this exact Noise session.\n const nonceHex = bytesToHex(nonce);\n transport.send(pending.encrypt(encodeAttestationRequest(nonceHex)));\n\n // Attestation response: decrypt, decode, verify.\n const responseFrame = await inbound.next(timeoutMs);\n let response: AttestResponse;\n try {\n response = decodeAttestationResponse(pending.decrypt(responseFrame));\n } catch (cause) {\n if (cause instanceof AttestationError) throw cause;\n throw new AttestationError(\n \"NOT_ATTESTED\",\n `failed to decode attestation response: ${String(cause)}`,\n { cause },\n );\n }\n\n const policy = toAttestationPolicy(endpoint);\n const attestation = await verifyAttestation({\n response,\n expectedNonce: nonce,\n expectedNoiseStaticPub: remoteStaticPublicKey,\n policy,\n timeoutMs,\n });\n\n inbound.detach();\n return promoteChannel({ transport, cipher: pending, attestation, remoteStaticPublicKey });\n } catch (err) {\n inbound.detach();\n throw err;\n }\n}\n\n/**\n * Map a {@link CoordinatorEndpoint} (release pin + requiredMode + host) to the\n * verifier's {@link AttestationPolicy}. The loopback local-attestation fallback\n * is only enabled for loopback hosts (ADR-0037).\n */\nexport function toAttestationPolicy(endpoint: CoordinatorEndpoint): AttestationPolicy {\n const pin = endpoint.releasePin;\n const loopback = isLoopbackUrl(endpoint.wsUrl);\n const allowLocalAttestation =\n endpoint.allowLocalAttestation === true && loopback && endpoint.requiredMode !== \"prod\";\n\n const policy: AttestationPolicy = {\n ...(pin.intelRootFingerprint ? { intelRootFingerprint: pin.intelRootFingerprint } : {}),\n // \"auto\" leaves the mode unconstrained; \"prod\"/\"dev\" are passed through.\n ...(endpoint.requiredMode !== \"auto\" ? { requiredMode: endpoint.requiredMode } : {}),\n // Keep the release pin active in prod and auto mode. Dev local attestations\n // ignore the MRTD pin inside the verifier.\n expectedMrtd: pin.mrtd,\n ...(pin.binaryHash ? { expectedBinaryHash: pin.binaryHash } : {}),\n ...(pin.runtimeProfile ? { expectedRuntimeProfile: pin.runtimeProfile } : {}),\n allowMissingDcapCollateral: pin.allowMissingDcapCollateral === true,\n allowLocalAttestation,\n };\n\n if (pin.azureMaa) {\n policy.azureMaa = {\n expectedIssuer: pin.azureMaa.issuer,\n expectedJwksUrl: pin.azureMaa.jwksUrl,\n expectedPolicyHash: pin.azureMaa.policyHash,\n };\n }\n\n return policy;\n}\n\n// ── Internal: promote pending cipher to a live attested channel ──────────────\n\nfunction promoteChannel(params: {\n transport: Transport;\n cipher: NoiseTransport;\n attestation: AttestedMetadata;\n remoteStaticPublicKey: Uint8Array;\n}): SecureChannel {\n const { transport, cipher, attestation, remoteStaticPublicKey } = params;\n const handlers = new Set<(plaintext: Uint8Array) => void>();\n const fatalHandlers = new Set<(error: Error) => void>();\n let attestationWaiter: {\n readonly resolve: (response: AttestResponse) => void;\n readonly reject: (error: Error) => void;\n readonly timer: ReturnType<typeof setTimeout>;\n } | null = null;\n let closed = false;\n\n const unsubscribeRaw = transport.onMessage((frame) => {\n if (closed) return;\n let plaintext: Uint8Array;\n try {\n plaintext = cipher.decrypt(frame);\n } catch (cause) {\n // A decrypt failure means the cipher state is irrecoverably desynced\n // (tamper or nonce desync). Drop the channel rather than surface\n // untrusted bytes.\n const error = new TransportError(\n \"NOISE_HANDSHAKE_FAILED\",\n `secure channel decrypt failed: ${String(cause)}`,\n { cause },\n );\n fail(error);\n return;\n }\n if (attestationWaiter !== null) {\n const decoded = decodeAttestationControlFrame(plaintext);\n if (decoded.kind === \"response\") {\n const waiter = attestationWaiter;\n attestationWaiter = null;\n clearTimeout(waiter.timer);\n waiter.resolve(decoded.response);\n return;\n }\n if (decoded.kind === \"invalid\") {\n const waiter = attestationWaiter;\n attestationWaiter = null;\n clearTimeout(waiter.timer);\n waiter.reject(decoded.error);\n return;\n }\n }\n for (const handler of handlers) handler(plaintext);\n });\n\n const unsubscribeState = transport.onStateChange((state) => {\n if (closed) return;\n if (state === \"closing\" || state === \"closed\") {\n fail(new TransportError(\"CONNECTION_LOST\", \"secure channel transport closed\"));\n }\n });\n\n function close(): void {\n if (closed) return;\n closed = true;\n handlers.clear();\n fatalHandlers.clear();\n if (attestationWaiter !== null) {\n const waiter = attestationWaiter;\n attestationWaiter = null;\n clearTimeout(waiter.timer);\n waiter.reject(new TransportError(\"CONNECTION_LOST\", \"secure channel is closed\"));\n }\n unsubscribeRaw();\n unsubscribeState();\n }\n\n function fail(error: Error): void {\n if (closed) return;\n const notifyHandlers = [...fatalHandlers];\n for (const handler of notifyHandlers) handler(error);\n if (!closed) {\n close();\n transport.close();\n }\n }\n\n return {\n attestation,\n remoteStaticPublicKey,\n requestAttestation(nonceHex: string, timeoutMs: number): Promise<AttestResponse> {\n if (closed) {\n return Promise.reject(new TransportError(\"CONNECTION_LOST\", \"secure channel is closed\"));\n }\n if (attestationWaiter !== null) {\n return Promise.reject(\n new AttestationError(\"NOT_ATTESTED\", \"re-attestation is already in flight\"),\n );\n }\n return new Promise<AttestResponse>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (attestationWaiter === null) return;\n attestationWaiter = null;\n reject(\n new AttestationError(\"NOT_ATTESTED\", `re-attestation timed out after ${timeoutMs}ms`),\n );\n }, timeoutMs);\n attestationWaiter = { resolve, reject, timer };\n try {\n transport.send(cipher.encrypt(encodeAttestationRequest(nonceHex)));\n } catch (cause) {\n if (attestationWaiter === null) return;\n attestationWaiter = null;\n clearTimeout(timer);\n reject(cause instanceof Error ? cause : new Error(String(cause)));\n }\n });\n },\n send(plaintext: Uint8Array): void {\n if (closed) {\n throw new TransportError(\"CONNECTION_LOST\", \"secure channel is closed\");\n }\n transport.send(cipher.encrypt(plaintext));\n },\n onMessage(handler): Unsubscribe {\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n onFatal(handler): Unsubscribe {\n fatalHandlers.add(handler);\n return () => fatalHandlers.delete(handler);\n },\n close,\n };\n}\n\n// ── Internal: single-slot inbound frame reader ───────────────────────────────\n\ninterface FrameReader {\n /** Resolve with the next inbound frame, or reject on timeout/close. */\n next(timeoutMs: number): Promise<Uint8Array>;\n /** Stop buffering and detach from the transport. */\n detach(): void;\n}\n\nfunction createFrameReader(transport: Transport): FrameReader {\n const queue: Uint8Array[] = [];\n let waiter: { resolve: (f: Uint8Array) => void; reject: (e: Error) => void } | null = null;\n let detached = false;\n\n const unsubscribeMessage = transport.onMessage((frame) => {\n if (detached) return;\n if (waiter) {\n const w = waiter;\n waiter = null;\n w.resolve(frame);\n } else {\n queue.push(frame);\n }\n });\n\n const unsubscribeState = transport.onStateChange((state) => {\n if (detached) return;\n if (state === \"closing\" || state === \"closed\") {\n const w = waiter;\n waiter = null;\n w?.reject(\n new TransportError(\"CONNECTION_LOST\", \"transport closed during handshake/attestation\"),\n );\n }\n });\n\n function detach(): void {\n if (detached) return;\n detached = true;\n unsubscribeMessage();\n unsubscribeState();\n queue.length = 0;\n }\n\n return {\n next(timeoutMs: number): Promise<Uint8Array> {\n if (detached) {\n return Promise.reject(new TransportError(\"CONNECTION_LOST\", \"frame reader detached\"));\n }\n const queued = queue.shift();\n if (queued) return Promise.resolve(queued);\n return new Promise<Uint8Array>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (waiter) {\n waiter = null;\n reject(\n new TransportError(\n \"NOISE_HANDSHAKE_FAILED\",\n `timed out waiting for a handshake frame after ${timeoutMs}ms`,\n ),\n );\n }\n }, timeoutMs);\n waiter = {\n resolve: (f) => {\n clearTimeout(timer);\n resolve(f);\n },\n reject: (e) => {\n clearTimeout(timer);\n reject(e);\n },\n };\n });\n },\n detach,\n };\n}\n\ntype AttestationControlFrame =\n | { readonly kind: \"response\"; readonly response: AttestResponse }\n | { readonly kind: \"invalid\"; readonly error: AttestationError }\n | { readonly kind: \"app\" };\n\nfunction decodeAttestationControlFrame(plaintext: Uint8Array): AttestationControlFrame {\n const text = new TextDecoder().decode(plaintext);\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n return { kind: \"app\" };\n }\n\n try {\n assertAttestResponse(body);\n return { kind: \"response\", response: body };\n } catch (cause) {\n if (looksLikeAttestationResponse(body)) {\n return {\n kind: \"invalid\",\n error:\n cause instanceof AttestationError\n ? cause\n : new AttestationError(\"NOT_ATTESTED\", String(cause), { cause }),\n };\n }\n return { kind: \"app\" };\n }\n}\n\nfunction looksLikeAttestationResponse(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const body = value as Record<string, unknown>;\n return (\n \"quote\" in body ||\n \"nonce\" in body ||\n \"pubkey\" in body ||\n \"binary_hash\" in body ||\n \"local_attestation\" in body ||\n \"maa_token\" in body ||\n \"tpm_quote\" in body ||\n \"hcl_keys_json\" in body\n );\n}\n\n// ── Internal: attestation control-frame codecs (ported from the WS client) ───\n\n/** Encode an attestation request frame: prefix || ascii(nonceHex). */\nexport function encodeAttestationRequest(nonceHex: string): Uint8Array {\n const nonce = new TextEncoder().encode(nonceHex);\n const out = new Uint8Array(ATTEST_REQUEST_PREFIX.length + nonce.length);\n out.set(ATTEST_REQUEST_PREFIX);\n out.set(nonce, ATTEST_REQUEST_PREFIX.length);\n return out;\n}\n\n/** Decode + structurally validate a decrypted attestation response (JSON). */\nexport function decodeAttestationResponse(plaintext: Uint8Array): AttestResponse {\n const text = new TextDecoder().decode(plaintext);\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch (cause) {\n throw new AttestationError(\n \"NOT_ATTESTED\",\n `attestation response is not valid JSON: ${String(cause)}`,\n { cause },\n );\n }\n assertAttestResponse(body);\n return body;\n}\n\n// ── Internal: loopback detection (ported from the WS client) ─────────────────\n\n/** True when `value` is a ws(s) URL whose host is a loopback address. */\nexport function isLoopbackUrl(value: string): boolean {\n try {\n return isLoopbackHostname(new URL(value).hostname);\n } catch {\n return false;\n }\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase();\n if (normalized === \"localhost\" || normalized === \"::1\" || normalized === \"[::1]\") {\n return true;\n }\n if (isLoopbackIpv4(normalized)) {\n return true;\n }\n if (!normalized.startsWith(\"[::ffff:\") || !normalized.endsWith(\"]\")) {\n return false;\n }\n\n const mapped = normalized.slice(\"[::ffff:\".length, -1);\n if (isLoopbackIpv4(mapped)) {\n return true;\n }\n const parts = mapped.split(\":\");\n if (parts.length !== 2) {\n return false;\n }\n const high = Number.parseInt(parts[0] ?? \"\", 16);\n const low = Number.parseInt(parts[1] ?? \"\", 16);\n if (\n !Number.isInteger(high) ||\n !Number.isInteger(low) ||\n high < 0 ||\n high > 0xffff ||\n low < 0 ||\n low > 0xffff\n ) {\n return false;\n }\n return ((high << 16) | low) >>> 24 === 127;\n}\n\nfunction isLoopbackIpv4(hostname: string): boolean {\n const parts = hostname.split(\".\");\n return (\n parts.length === 4 &&\n parts.every((part) => /^\\d+$/.test(part)) &&\n Number(parts[0]) === 127 &&\n parts.every((part) => Number(part) >= 0 && Number(part) <= 255)\n );\n}\n\n// ── Tiny utilities ───────────────────────────────────────────────────────────\n\nfunction bytesToHex(b: Uint8Array): string {\n let s = \"\";\n for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, \"0\");\n return s;\n}\n","/**\n * Session-establishment seams layered on top of an open {@link Transport}.\n *\n * Once a socket is open, a session runs the Noise XX handshake and then TDX\n * attestation before any sensitive command is allowed. The real logic lives in\n * the secure-channel module (`../session/secureChannel`); these functions are\n * the stable, transport-level entrypoints the root index re-exports.\n *\n * Both halves are driven from one underlying {@link establishSecureChannel}\n * run, because attestation is requested over the same Noise cipher the\n * handshake split. {@link performNoiseHandshake} runs that establishment and\n * caches the resulting channel keyed on the transport; {@link performAttestation}\n * reads the attestation evidence from it. Callers that want the whole flow in\n * one step should use {@link establishAttestedChannel}.\n */\n\nimport { TransportError } from \"../core/errors.js\";\nimport {\n establishSecureChannel,\n toAttestationPolicy,\n type SecureChannel,\n} from \"../session/secureChannel.js\";\nimport type { CoordinatorEndpoint } from \"../schemas/types.generated.js\";\nimport type { Transport } from \"./types.js\";\n\n/** Result of a completed Noise XX handshake. */\nexport interface NoiseHandshakeResult {\n /** The coordinator's Noise static public key, pinned for this session. */\n readonly noiseStaticPublicKey: Uint8Array;\n /**\n * The attested secure channel produced by this handshake. Carried so a\n * subsequent {@link performAttestation} can read attestation evidence without\n * re-running the exchange. Internal: not part of the structural contract.\n */\n readonly channel: SecureChannel;\n}\n\n/** Result of a completed TDX attestation. */\nexport interface AttestationResult {\n /** The verified release MRTD. */\n readonly mrtd: string;\n /** Attestation mode the coordinator reported. */\n readonly mode: \"prod\" | \"dev\";\n /** Coordinator binary hash reported by the verified attestation response. */\n readonly binaryHash: string;\n /** Compile-time runtime profile carried by the attested coordinator artifact. */\n readonly runtimeProfile?: \"prod-hardened\" | \"prod-devnet-simplified\";\n /** Noise static public key bound into the attestation quote. */\n readonly pubkeyHex: string;\n /** True only for explicit loopback local development attestation. */\n readonly localAttestation: boolean;\n readonly rtmr0?: string;\n readonly rtmr1?: string;\n readonly rtmr2?: string;\n readonly rtmr3?: string;\n /** When verification completed (epoch ms), stamped by the caller. */\n readonly verifiedAtMs: number;\n}\n\n/** A fully-established, attested channel plus its derived evidence. */\nexport interface AttestedChannel {\n /** The live attested secure channel. */\n readonly channel: SecureChannel;\n /** The handshake result (pinned Noise static key). */\n readonly handshake: NoiseHandshakeResult;\n /** The attestation result, stamped with the verification time. */\n readonly attestation: AttestationResult;\n}\n\n/**\n * Run the Noise XX handshake then attestation over an open transport, returning\n * the live channel and its derived evidence. This is the single internal entry\n * the session orchestration uses.\n */\nexport async function establishAttestedChannel(params: {\n transport: Transport;\n endpoint: CoordinatorEndpoint;\n nonce: Uint8Array;\n timeoutMs?: number;\n}): Promise<AttestedChannel> {\n const { transport, endpoint, nonce, timeoutMs } = params;\n const channel = await establishSecureChannel({ transport, endpoint, nonce, timeoutMs });\n const handshake: NoiseHandshakeResult = {\n noiseStaticPublicKey: channel.remoteStaticPublicKey,\n channel,\n };\n const attestation: AttestationResult = {\n mrtd: channel.attestation.mrtd,\n mode: channel.attestation.mode,\n binaryHash: channel.attestation.binaryHash,\n runtimeProfile: channel.attestation.runtimeProfile,\n pubkeyHex: channel.attestation.pubkeyHex,\n localAttestation: channel.attestation.localAttestation,\n rtmr0: channel.attestation.rtmr0,\n rtmr1: channel.attestation.rtmr1,\n rtmr2: channel.attestation.rtmr2,\n rtmr3: channel.attestation.rtmr3,\n verifiedAtMs: Date.now(),\n };\n // Touch the policy mapper so its loopback gating stays exercised by the\n // single-step entrypoint as well.\n void toAttestationPolicy(endpoint);\n return { channel, handshake, attestation };\n}\n\n/**\n * Run the Noise XX handshake over an open transport and pin the coordinator's\n * static key. Drives a full attested-channel establishment (attestation is\n * bound to the same Noise cipher) and returns the handshake half; read the\n * attestation half from {@link performAttestation} with the returned result.\n *\n * @throws TransportError if the channel fails or the handshake is malformed.\n * @throws AttestationError if attestation verification fails.\n */\nexport async function performNoiseHandshake(\n transport: Transport,\n endpoint: CoordinatorEndpoint,\n nonce: Uint8Array = crypto.getRandomValues(new Uint8Array(32)),\n): Promise<NoiseHandshakeResult> {\n const established = await establishAttestedChannel({ transport, endpoint, nonce });\n return established.handshake;\n}\n\n/**\n * Verify the coordinator's TDX attestation, bound to the handshake's Noise\n * static key. Reads the evidence captured by {@link performNoiseHandshake}.\n *\n * @throws TransportError if the handshake result carries no channel.\n */\nexport function performAttestation(\n _transport: Transport,\n handshake: NoiseHandshakeResult,\n): Promise<AttestationResult> {\n const channel = handshake.channel as SecureChannel | undefined;\n if (!channel) {\n return Promise.reject(\n new TransportError(\n \"NOISE_HANDSHAKE_FAILED\",\n \"performAttestation requires a handshake result produced by performNoiseHandshake\",\n ),\n );\n }\n return Promise.resolve({\n mrtd: channel.attestation.mrtd,\n mode: channel.attestation.mode,\n binaryHash: channel.attestation.binaryHash,\n runtimeProfile: channel.attestation.runtimeProfile,\n pubkeyHex: channel.attestation.pubkeyHex,\n localAttestation: channel.attestation.localAttestation,\n rtmr0: channel.attestation.rtmr0,\n rtmr1: channel.attestation.rtmr1,\n rtmr2: channel.attestation.rtmr2,\n rtmr3: channel.attestation.rtmr3,\n verifiedAtMs: Date.now(),\n });\n}\n","{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://invisible.exchange/schemas/sdk/payoutPolicy.schema.json\",\n \"title\": \"PayoutPolicy\",\n \"description\": \"Where and how a contract's output is delivered. V0 normal-user requests accept exactly one destination. Validated locally before submission (spec sections 4.3.1 and 10.1).\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"destinations\"],\n \"properties\": {\n \"destinations\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"description\": \"V0 normal-user requests accept exactly one destination. Multi-address receive is not supported yet.\",\n \"items\": { \"$ref\": \"#/$defs/payoutDestination\" }\n },\n \"totalDeadlineMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Payout-window selector in milliseconds: 0 for instant, or a currently supported scheduled window duration.\"\n },\n \"batchExclusionId\": {\n \"type\": \"string\",\n \"description\": \"Not supported in V0 normal-user requests. Reserved for V1 campaign-scoped batch exclusion; never a stable actor identity.\"\n }\n },\n \"$defs\": {\n \"payoutDestination\": {\n \"title\": \"PayoutDestination\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"address\", \"sharePercent\"],\n \"properties\": {\n \"address\": {\n \"type\": \"string\",\n \"description\": \"Base58 Solana account address.\"\n },\n \"sharePercent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"description\": \"Share of the payout. Sums to 100 across destinations.\"\n },\n \"minDelayMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Not supported in V0 normal-user requests; the SDK rejects this field because the current runtime does not honor per-destination delay bounds.\"\n },\n \"maxDelayMs\": {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"description\": \"Not supported in V0 normal-user requests; the SDK rejects this field because the current runtime does not honor per-destination delay bounds.\"\n },\n \"minLamports\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n }\n }\n}\n","{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://invisible.exchange/schemas/sdk/coordinatorPoolConfig.schema.json\",\n \"title\": \"CoordinatorPoolConfig\",\n \"description\": \"The coordinator endpoint pool a session connects through (spec section 6.1). No hostname is baked in; callers supply endpoints (or opt into a preset).\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"endpoints\"],\n \"properties\": {\n \"endpoints\": {\n \"type\": \"array\",\n \"minItems\": 1,\n \"items\": { \"$ref\": \"#/$defs/coordinatorEndpoint\" }\n },\n \"reattestEveryMs\": { \"type\": \"integer\", \"minimum\": 1 },\n \"failoverDebounceMs\": { \"type\": \"integer\", \"minimum\": 0 },\n \"maxReconnectAttempts\": { \"type\": \"integer\", \"minimum\": 0 },\n \"noiseTransportTimeoutMs\": { \"type\": \"integer\", \"minimum\": 1 },\n \"preferLeader\": { \"type\": \"boolean\" },\n \"allowedRoles\": {\n \"type\": \"array\",\n \"items\": { \"enum\": [\"leader\", \"watcher\"] }\n }\n },\n \"$defs\": {\n \"coordinatorEndpoint\": {\n \"title\": \"CoordinatorEndpoint\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"wsUrl\", \"expectedHostname\", \"releasePin\", \"requiredMode\"],\n \"allOf\": [\n {\n \"if\": {\n \"properties\": {\n \"releasePin\": {\n \"type\": \"object\",\n \"required\": [\"allowMissingDcapCollateral\"],\n \"properties\": {\n \"allowMissingDcapCollateral\": { \"const\": true }\n }\n }\n },\n \"required\": [\"releasePin\"]\n },\n \"then\": {\n \"properties\": {\n \"requiredMode\": { \"const\": \"dev\" }\n }\n }\n }\n ],\n \"properties\": {\n \"wsUrl\": { \"type\": \"string\", \"description\": \"wss://<host>/ws-noise\" },\n \"expectedHostname\": {\n \"type\": \"string\",\n \"description\": \"Must match the SNI / TLS certificate host.\"\n },\n \"releasePin\": { \"$ref\": \"#/$defs/releasePin\" },\n \"requiredMode\": { \"enum\": [\"prod\", \"dev\", \"auto\"] },\n \"allowLocalAttestation\": {\n \"type\": \"boolean\",\n \"description\": \"Explicit local-dev fallback opt-in. Honored only for loopback non-prod endpoints.\"\n },\n \"roleHint\": { \"enum\": [\"leader\", \"watcher\"] },\n \"weight\": { \"type\": \"number\", \"minimum\": 0 }\n }\n },\n \"releasePin\": {\n \"title\": \"CoordinatorReleasePin\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"mrtd\"],\n \"properties\": {\n \"mrtd\": { \"type\": \"string\", \"description\": \"Hex MRTD release pin.\" },\n \"binaryHash\": {\n \"type\": \"string\",\n \"pattern\": \"^[0-9a-fA-F]{64}$\",\n \"description\": \"Optional SHA-256 hash of the approved coordinator binary; required for production Azure attestation.\"\n },\n \"runtimeProfile\": {\n \"enum\": [\"prod-hardened\", \"prod-devnet-simplified\"],\n \"description\": \"Optional compile-time coordinator runtime profile; production simplified deployments must pin it.\"\n },\n \"intelRootFingerprint\": {\n \"type\": \"string\",\n \"description\": \"Hex SHA-256 of the Intel root cert.\"\n },\n \"allowMissingDcapCollateral\": {\n \"type\": \"boolean\",\n \"description\": \"Temporary non-prod legacy escape hatch for coordinators that do not yet emit Intel DCAP collateral.\"\n },\n \"azureMaa\": { \"$ref\": \"#/$defs/azureMaaPin\" }\n }\n },\n \"azureMaaPin\": {\n \"title\": \"AzureMaaPin\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"issuer\", \"jwksUrl\", \"policyHash\"],\n \"properties\": {\n \"issuer\": { \"type\": \"string\" },\n \"jwksUrl\": { \"type\": \"string\" },\n \"policyHash\": { \"type\": \"string\" }\n }\n }\n }\n}\n","{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://invisible.exchange/schemas/sdk/lpPositionView.schema.json\",\n \"title\": \"LpPositionView\",\n \"description\": \"The actor-safe LP position projection (spec section 4.4.1). Earned fees are per-position, never aggregated globally.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"id\",\n \"status\",\n \"targetShardCount\",\n \"authPublicKey\",\n \"refillPublicKey\",\n \"withdrawalCommitment\",\n \"committedLamports\",\n \"earnedLamports\",\n \"refillThreshold\",\n \"shards\",\n \"createdAt\"\n ],\n \"properties\": {\n \"id\": { \"type\": \"string\", \"description\": \"lp_position_id\" },\n \"status\": { \"enum\": [\"dkg_pending\", \"active\", \"withdrawing\", \"closed\"] },\n \"targetShardCount\": { \"type\": \"integer\", \"minimum\": 0, \"maximum\": 300 },\n \"authPublicKey\": {\n \"type\": \"string\",\n \"description\": \"Derived from the LP Position Code; signs LP commands.\"\n },\n \"refillPublicKey\": { \"type\": \"string\", \"description\": \"Ed25519, 32 bytes.\" },\n \"withdrawalCommitment\": {\n \"type\": \"string\",\n \"description\": \"SHA256(withdrawal_secret).\"\n },\n \"committedLamports\": { \"type\": \"integer\", \"minimum\": 0 },\n \"earnedLamports\": { \"type\": \"integer\", \"minimum\": 0 },\n \"refillThreshold\": { \"type\": \"integer\", \"minimum\": 0 },\n \"shards\": {\n \"type\": \"array\",\n \"description\": \"LpInventoryShard[] from the protocol package; opaque to the SDK skeleton.\",\n \"items\": { \"type\": \"object\" }\n },\n \"createdAt\": { \"type\": \"integer\", \"minimum\": 0 }\n }\n}\n","{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://invisible.exchange/schemas/sdk/storageEnvelope.schema.json\",\n \"title\": \"StorageEnvelope\",\n \"description\": \"Optional wrapped form for callers or future encrypted storage adapters (spec section 7). Current browser and extension adapters persist caller-supplied bytes; callers decide whether those bytes are plaintext, wrapped, or encrypted.\",\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"namespace\", \"key\", \"alg\", \"ciphertext\", \"createdAtMs\"],\n \"properties\": {\n \"namespace\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"key\": {\n \"type\": \"string\",\n \"minLength\": 1\n },\n \"alg\": {\n \"enum\": [\"AES-GCM\", \"none\"],\n \"description\": \"Wrapping algorithm. `none` means the caller supplied bytes without an envelope-level transform.\"\n },\n \"ciphertext\": {\n \"type\": \"string\",\n \"description\": \"Base64url-encoded wrapped bytes, encrypted bytes, or caller-supplied plaintext bytes when alg is `none`.\"\n },\n \"iv\": {\n \"type\": \"string\",\n \"description\": \"Base64url-encoded AES-GCM nonce; required when alg is AES-GCM.\"\n },\n \"createdAtMs\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n },\n \"allOf\": [\n {\n \"if\": {\n \"properties\": { \"alg\": { \"const\": \"AES-GCM\" } },\n \"required\": [\"alg\"]\n },\n \"then\": {\n \"properties\": { \"iv\": { \"type\": \"string\" } },\n \"required\": [\"iv\"]\n }\n }\n ]\n}\n","/**\n * Shared AJV instance and compiled schema validators.\n *\n * Mirrors protocol/src/coordinator/envelope.ts: a single strict `Ajv2020`\n * instance (draft 2020-12) with the SDK schemas compiled once at module load.\n * These validators check structural shape only; semantic rules that JSON Schema\n * cannot express (e.g. payout shares summing to 100) live in the per-type\n * validators alongside.\n */\n\n// ajv's `dist/2020` exposes the class as a named export (`exports.Ajv2020`),\n// which resolves cleanly under both Node's ESM/CJS interop and NodeNext +\n// verbatimModuleSyntax - unlike the default export, whose CJS interop is\n// self-referential.\nimport { Ajv2020 } from \"ajv/dist/2020.js\";\nimport type { ErrorObject, ValidateFunction } from \"ajv\";\nimport payoutPolicySchema from \"../schemas/payoutPolicy.schema.json\" with { type: \"json\" };\nimport coordinatorPoolConfigSchema from \"../schemas/coordinatorPoolConfig.schema.json\" with { type: \"json\" };\nimport lpPositionViewSchema from \"../schemas/lpPositionView.schema.json\" with { type: \"json\" };\nimport storageEnvelopeSchema from \"../schemas/storageEnvelope.schema.json\" with { type: \"json\" };\nimport type {\n CoordinatorPoolConfig,\n LpPositionView,\n PayoutPolicy,\n StorageEnvelope,\n} from \"../schemas/types.generated.js\";\n\nconst ajv = new Ajv2020({ allErrors: true, strict: true });\n\nexport const validatePayoutPolicyShape: ValidateFunction<PayoutPolicy> =\n ajv.compile<PayoutPolicy>(payoutPolicySchema);\n\nexport const validateCoordinatorPoolConfigShape: ValidateFunction<CoordinatorPoolConfig> =\n ajv.compile<CoordinatorPoolConfig>(coordinatorPoolConfigSchema);\n\nexport const validateLpPositionViewShape: ValidateFunction<LpPositionView> =\n ajv.compile<LpPositionView>(lpPositionViewSchema);\n\nexport const validateStorageEnvelopeShape: ValidateFunction<StorageEnvelope> =\n ajv.compile<StorageEnvelope>(storageEnvelopeSchema);\n\n/** Render AJV errors into a compact, readable single line. */\nexport function formatAjvErrors(errors: ErrorObject[] | null | undefined): string {\n if (!errors || errors.length === 0) return \"schema validation failed\";\n return errors\n .map((e) => `${e.instancePath || \"(root)\"} ${e.message ?? \"is invalid\"}`.trim())\n .join(\"; \");\n}\n","/**\n * Re-attestation over a live secure channel.\n *\n * The initial attestation runs inside {@link establishSecureChannel} during\n * handshake. Re-attestation reuses the already-promoted Noise cipher: it sends\n * a fresh attestation-request plaintext through {@link SecureChannel.send} (the\n * channel Noise-encrypts it) and verifies the next inbound plaintext, which the\n * channel has already Noise-decrypted.\n *\n * Returns a fresh {@link AttestationResult} on success; throws\n * {@link AttestationError} / {@link TransportError} on failure so the caller can\n * fail closed and notify policy-violation handlers.\n *\n * @module JW-428\n */\n\nimport { TransportError } from \"../core/errors.js\";\nimport { toAttestationPolicy } from \"../session/secureChannel.js\";\nimport type { SessionState } from \"../session/state.js\";\nimport { verifyAttestation } from \"./verifier.js\";\nimport type { AttestationResult } from \"../transport/handshake.js\";\nimport type { CoordinatorEndpoint } from \"../schemas/types.generated.js\";\n\nconst DEFAULT_REATTEST_TIMEOUT_MS = 30_000;\n\n/**\n * Re-run attestation over `state.channel` against `endpoint`, returning the\n * fresh result. Does not mutate session state - the caller decides how to apply\n * the outcome.\n */\nexport async function reattest(\n state: SessionState,\n endpoint: CoordinatorEndpoint,\n timeoutMs: number = DEFAULT_REATTEST_TIMEOUT_MS,\n): Promise<AttestationResult> {\n const { channel, remoteStaticPublicKey } = state;\n if (channel === null || remoteStaticPublicKey === null) {\n throw new TransportError(\"CONNECTION_LOST\", \"re-attestation requires a live attested channel\");\n }\n\n const nonce = crypto.getRandomValues(new Uint8Array(32));\n const response = await channel.requestAttestation(toHex(nonce), timeoutMs);\n\n const metadata = await verifyAttestation({\n response,\n expectedNonce: nonce,\n expectedNoiseStaticPub: remoteStaticPublicKey,\n policy: toAttestationPolicy(endpoint),\n timeoutMs,\n });\n\n return {\n mrtd: metadata.mrtd,\n mode: metadata.mode,\n binaryHash: metadata.binaryHash,\n runtimeProfile: metadata.runtimeProfile,\n pubkeyHex: metadata.pubkeyHex,\n localAttestation: metadata.localAttestation,\n rtmr0: metadata.rtmr0,\n rtmr1: metadata.rtmr1,\n rtmr2: metadata.rtmr2,\n rtmr3: metadata.rtmr3,\n verifiedAtMs: Date.now(),\n };\n}\n\nexport function reattestSerialized(\n state: SessionState,\n endpoint: CoordinatorEndpoint,\n timeoutMs: number = DEFAULT_REATTEST_TIMEOUT_MS,\n): Promise<AttestationResult> {\n if (state.reattestPromise !== null) {\n return state.reattestPromise;\n }\n const promise = Promise.resolve()\n .then(() => reattest(state, endpoint, timeoutMs))\n .finally(() => {\n if (state.reattestPromise === promise) {\n state.reattestPromise = null;\n }\n });\n state.reattestPromise = promise;\n return promise;\n}\n\nfunction toHex(b: Uint8Array): string {\n let s = \"\";\n for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, \"0\");\n return s;\n}\n","/**\n * `createSession` - the single entrypoint that opens an attested session.\n *\n * It validates the endpoint pool, opens the transport, runs the Noise XX\n * handshake + TDX attestation, and returns an opaque {@link Session} that has\n * already passed attestation (`attested === true`). It resolves only once\n * attestation succeeds; any transport or attestation failure rejects with a\n * typed {@link TransportError} / {@link AttestationError}.\n *\n * A re-attestation timer re-runs verification over the live channel every\n * {@link REATTEST_EVERY_MS}; on failure it marks the session unattested and\n * notifies any registered policy-violation handlers. The transport is\n * injectable for tests.\n */\n\nimport type { Session } from \"../core/session.js\";\nimport type { Transport } from \"../transport/types.js\";\nimport type { CoordinatorPoolConfig } from \"../schemas/types.generated.js\";\nimport { establishAttestedChannel } from \"../transport/handshake.js\";\nimport { noiseWebSocketTransport } from \"../transport/noiseWebSocketTransport.js\";\nimport { formatAjvErrors, validateCoordinatorPoolConfigShape } from \"../validation/ajv.js\";\nimport { reattestSerialized } from \"../attestation/reattest.js\";\nimport {\n closeSessionState,\n createSessionHandle,\n failSessionClosed,\n getSessionState,\n type SessionState,\n} from \"./state.js\";\n\n/** Re-attest long-lived SDK Noise sessions at least every 15 minutes. */\nexport const REATTEST_EVERY_MS = 900_000;\n\n/** Options for {@link createSession}. */\nexport interface CreateSessionOptions {\n /**\n * The coordinator endpoint pool. Must contain at least one endpoint. No\n * hostname is provided by default; supply your own or use `@invisible-labs/sdk/presets`.\n */\n readonly coordinator: CoordinatorPoolConfig;\n /**\n * Storage adapter for recoverable secrets. Typed by `@invisible-labs/sdk/storage`;\n * accepted here so the session can be threaded into storage-backed flows.\n */\n readonly storage?: unknown;\n /** Wallet adapter used for storage key derivation and signing. */\n readonly wallet?: unknown;\n /**\n * Inject a transport. Defaults to a Noise WebSocket transport over the first\n * endpoint. Tests pass an in-memory transport (paired with a loopback\n * coordinator that can complete the handshake + attestation).\n */\n readonly transport?: Transport;\n}\n\n/**\n * Open an attested session against the configured coordinator pool.\n *\n * @throws Error if the pool config is structurally invalid (including an empty\n * `endpoints` array).\n * @throws TransportError if the connection or Noise handshake fails.\n * @throws AttestationError if attestation verification fails.\n */\nexport async function createSession(options: CreateSessionOptions): Promise<Session> {\n const { coordinator } = options;\n if (!validateCoordinatorPoolConfigShape(coordinator)) {\n throw new Error(\n `invalid coordinator pool config: ${formatAjvErrors(validateCoordinatorPoolConfigShape.errors)}`,\n );\n }\n\n const endpoint = coordinator.endpoints[0]!;\n assertExpectedHostname(endpoint);\n const timeoutMs = coordinator.noiseTransportTimeoutMs;\n const transport =\n options.transport ??\n noiseWebSocketTransport({ wsUrl: endpoint.wsUrl, connectTimeoutMs: timeoutMs });\n await transport.connect();\n\n // Fresh per-connection nonce (anti-replay): 32 bytes from a CSPRNG.\n const nonce = crypto.getRandomValues(new Uint8Array(32));\n\n let established;\n try {\n established = await establishAttestedChannel({ transport, endpoint, nonce, timeoutMs });\n } catch (err) {\n // Fail closed: never expose an unverified channel as a usable session.\n transport.close();\n throw err;\n }\n\n const state: SessionState = {\n attested: true,\n transport,\n pool: coordinator,\n attestation: established.attestation,\n channel: established.channel,\n nonce,\n remoteStaticPublicKey: established.handshake.noiseStaticPublicKey,\n reattestTimer: null,\n reattestPromise: null,\n lastFatalError: null,\n policyViolationHandlers: new Set(),\n close(): void {\n closeSessionState(this);\n },\n };\n\n established.channel.onFatal((error) => failSessionClosed(state, error));\n scheduleReattest(state, endpoint);\n\n return createSessionHandle(state);\n}\n\nfunction assertExpectedHostname(endpoint: CoordinatorPoolConfig[\"endpoints\"][number]): void {\n let hostname: string;\n try {\n hostname = new URL(endpoint.wsUrl).hostname;\n } catch (err) {\n const error = new Error(`invalid coordinator wsUrl: ${endpoint.wsUrl}`);\n (error as { cause?: unknown }).cause = err;\n throw error;\n }\n if (hostname.toLowerCase() !== endpoint.expectedHostname.toLowerCase()) {\n throw new Error(\n `coordinator endpoint hostname ${hostname} does not match expectedHostname ${endpoint.expectedHostname}`,\n );\n }\n}\n\n/** Close a session created by {@link createSession}. */\nexport function closeSession(session: Session): void {\n getSessionState(session).close();\n}\n\n/**\n * Arm a one-shot re-attestation timer. On fire it re-verifies over the live\n * channel; success re-arms the timer, failure marks the session unattested and\n * notifies policy-violation handlers. Leak-free: the timer is cleared on close.\n */\nfunction scheduleReattest(\n state: SessionState,\n endpoint: SessionState[\"pool\"][\"endpoints\"][number],\n): void {\n if (state.channel === null) return;\n const reattestEveryMs = state.pool.reattestEveryMs ?? REATTEST_EVERY_MS;\n const timer = setTimeout(() => {\n void runReattest(state, endpoint);\n }, reattestEveryMs);\n // Do not keep the process alive solely for re-attestation.\n if (typeof timer === \"object\" && timer !== null && \"unref\" in timer) {\n (timer as { unref(): void }).unref();\n }\n state.reattestTimer = timer;\n}\n\nasync function runReattest(\n state: SessionState,\n endpoint: SessionState[\"pool\"][\"endpoints\"][number],\n): Promise<void> {\n state.reattestTimer = null;\n if (state.channel === null || state.nonce === null || state.remoteStaticPublicKey === null) {\n return;\n }\n try {\n state.attestation = await reattestSerialized(\n state,\n endpoint,\n state.pool.noiseTransportTimeoutMs,\n );\n state.attested = true;\n scheduleReattest(state, endpoint);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n failSessionClosed(state, error);\n }\n}\n"]}