@terminal3/t3n-sdk 4.2.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1263,6 +1263,7 @@ declare class HttpTransport implements Transport {
1263
1263
  * mockTransport.mockResponse("auth.handshake", { result: "..." });
1264
1264
  *
1265
1265
  * const client = new T3nClient({
1266
+ * trustAnchor: { unsafe_trust_server: true },
1266
1267
  * transport: mockTransport,
1267
1268
  * wasmComponent: mockWasm,
1268
1269
  * });
@@ -1317,6 +1318,112 @@ declare class MockTransport implements Transport {
1317
1318
  send(request: JsonRpcRequest, headers: Record<string, string>): Promise<JsonRpcResponse>;
1318
1319
  }
1319
1320
 
1321
+ /**
1322
+ * TDX quote verifier backed by the Rust `signature` crate compiled to
1323
+ * WASM. Full cryptographic verification: ECDSA P-256 attestation-key
1324
+ * signature, PCK certificate chain walk to Intel's root CA, and
1325
+ * report_data + RTMR comparison.
1326
+ *
1327
+ * The WASM bytes are inlined as base64 (see quote_verifier_bytes.ts)
1328
+ * so the SDK works without bundler WASM plugins and without runtime
1329
+ * asset URL resolution.
1330
+ */
1331
+ interface QuoteVerifyResult {
1332
+ valid: boolean;
1333
+ error?: string;
1334
+ rtmr3?: string;
1335
+ report_data?: string;
1336
+ }
1337
+ interface PeerQuoteResult {
1338
+ peer_id: string;
1339
+ valid: boolean;
1340
+ error?: string;
1341
+ rtmr3?: string;
1342
+ }
1343
+ interface DkgVerifyResult {
1344
+ valid: boolean;
1345
+ results: PeerQuoteResult[];
1346
+ valid_count: number;
1347
+ expected_count: number;
1348
+ error?: string;
1349
+ }
1350
+ /**
1351
+ * Client-pinned anchor the DKG attestation bundle is verified against.
1352
+ *
1353
+ * Without it, "the server proved it runs in a TEE" only means "*some*
1354
+ * TDX box somewhere" — any attacker with their own TDX cloud VM can
1355
+ * forge a complete, cryptographically-valid bundle for their own key
1356
+ * (SP-003). The anchor is the independent ground truth that closes it:
1357
+ * the bundle must describe *our* cluster (`expected_peer_ids`) running
1358
+ * *our* image (`rtmr3_allowlist`).
1359
+ */
1360
+ interface TrustAnchor {
1361
+ /**
1362
+ * Base58 peer IDs the client expects in the cluster. The bundle's
1363
+ * `peer_ids` must equal this set exactly (order-insensitive) — a MITM
1364
+ * cannot substitute its own single-node participant set.
1365
+ */
1366
+ expected_peer_ids: string[];
1367
+ /**
1368
+ * Base64-encoded 48-byte RTMR3 measurements of the expected node
1369
+ * image. Every quote's RTMR3 must be a member. **Must be non-empty.**
1370
+ * An array (not a singleton) so a rolling deploy's two in-flight
1371
+ * image measurements both verify.
1372
+ */
1373
+ rtmr3_allowlist: string[];
1374
+ }
1375
+ /**
1376
+ * Escape hatch for local dev / tests against a node whose attestation
1377
+ * can't be anchored (e.g. a mock signer that publishes no bundle).
1378
+ *
1379
+ * The name is deliberately alarming so it stands out in code review and
1380
+ * grep — it is the *only* way to skip DKG attestation verification on
1381
+ * the handshake path.
1382
+ */
1383
+ interface UnsafeTrustServer {
1384
+ unsafe_trust_server: true;
1385
+ }
1386
+ type TrustAnchorOrUnsafe = TrustAnchor | UnsafeTrustServer;
1387
+ /** Narrow a {@link TrustAnchorOrUnsafe} to the explicit opt-out arm. */
1388
+ declare function isUnsafeTrustServer(anchor: TrustAnchorOrUnsafe): anchor is UnsafeTrustServer;
1389
+ /**
1390
+ * Verify a single TDX attestation quote with full cryptographic verification.
1391
+ *
1392
+ * @param quoteB64 - Base64-encoded raw TDX v4 quote
1393
+ * @param attestationMsgB64 - Base64-encoded attestation message
1394
+ * (for DKG: encaps_key || sorted_peer_id_bytes)
1395
+ * @param expectedRtmr3B64 - Optional base64-encoded 48-byte RTMR3
1396
+ * @returns Verification result with extracted measurements
1397
+ */
1398
+ declare function verifyTdxQuote(quoteB64: string, attestationMsgB64: string, expectedRtmr3B64?: string): Promise<QuoteVerifyResult>;
1399
+ /**
1400
+ * Verify a full DKG attestation bundle against a client-pinned
1401
+ * {@link TrustAnchor}: multiple TDX quotes from all participating
1402
+ * nodes, plus the binding between the quotes and the ML-KEM
1403
+ * encapsulation key. Checks:
1404
+ * 1. `expected_peer_ids` / `rtmr3_allowlist` are both non-empty
1405
+ * 2. the bundle's `peer_ids` equal the pinned set exactly
1406
+ * 3. attestationMsg starts with encapsKey (server can't swap the key)
1407
+ * 4. every quote's ECDSA signature chains to Intel's SGX root CA
1408
+ * 5. every quote's report_data == keccak512(attestationMsg)
1409
+ * 6. every quote's RTMR3 is a member of `rtmr3_allowlist`
1410
+ *
1411
+ * The anchor is **required**: there is no unauthenticated mode. Callers
1412
+ * that genuinely want to trust the server must not call this at all —
1413
+ * see `unsafe_trust_server` on the client config, which branches around
1414
+ * the whole verify path.
1415
+ *
1416
+ * @param encapsKeyB64 - Base64-encoded ML-KEM encapsulation key
1417
+ * (from `/status.encaps_key`)
1418
+ * @param attestationMsgB64 - Base64-encoded raw attestation message
1419
+ * (from `/status.dkg_attestation.attestation_msg`)
1420
+ * @param peerIds - Base58 peer IDs as reported by the bundle
1421
+ * @param quotes - Map of peer_id → base64-encoded TDX quote
1422
+ * @param anchor - Client-pinned expected peer IDs + RTMR3 allowlist
1423
+ * @returns Per-peer verification results and overall validity
1424
+ */
1425
+ declare function verifyDkgAttestation(encapsKeyB64: string, attestationMsgB64: string, peerIds: string[], quotes: Record<string, string>, anchor: TrustAnchor): Promise<DkgVerifyResult>;
1426
+
1320
1427
  /**
1321
1428
  * Configuration types for T3n Client
1322
1429
  */
@@ -1346,6 +1453,20 @@ interface T3nClientConfig {
1346
1453
  logger?: Logger;
1347
1454
  /** Optional guest-to-host request handlers - provides custom behavior for WASM requests */
1348
1455
  handlers?: GuestToHostHandlers;
1456
+ /**
1457
+ * **Required.** Client-pinned trust anchor the node's DKG attestation
1458
+ * is verified against before the handshake trusts its ML-KEM key
1459
+ * (SP-003). Either a {@link TrustAnchor} (`expected_peer_ids` +
1460
+ * `rtmr3_allowlist`) or the explicit `{ unsafe_trust_server: true }`
1461
+ * opt-out for local dev / mock-signer nodes.
1462
+ *
1463
+ * Without this, a network attacker with their own TDX VM can hand the
1464
+ * SDK a forged-but-valid attestation for a key it controls and read
1465
+ * every session. It is a required field precisely so no caller can
1466
+ * omit it by accident — bypassing verification must be a visible,
1467
+ * grep-able choice.
1468
+ */
1469
+ trustAnchor: TrustAnchorOrUnsafe;
1349
1470
  }
1350
1471
 
1351
1472
  /**
@@ -1452,6 +1573,29 @@ interface AgentAuthEntry {
1452
1573
  agentDid: string;
1453
1574
  scripts: AgentAuthScriptGrant[];
1454
1575
  }
1576
+ /**
1577
+ * The full agent-auth policy document in the camelCase write shape:
1578
+ * the per-agent grants plus the document-level discovery grants.
1579
+ *
1580
+ * `discoverDids` (contract wire: `discover_dids`) is the
1581
+ * list of DIDs the user lets their registered agents *enumerate the
1582
+ * contracts of* via `listContracts`: an org DID grants org-mode discovery,
1583
+ * the user's own DID grants self-mode discovery. It lives at document
1584
+ * level — not on a script grant — because discovery must surface contracts
1585
+ * the agent cannot yet call. The node's discovery gate additionally
1586
+ * requires the calling agent to be named in `agents` (subject binding), so
1587
+ * an unregistered agent discovers nothing regardless of this list.
1588
+ */
1589
+ interface AgentAuthPolicy {
1590
+ agents: AgentAuthEntry[];
1591
+ discoverDids: string[];
1592
+ }
1593
+ /**
1594
+ * Parse a full `agent-auth-get` response (the stored snake_case policy
1595
+ * document) into the camelCase write shape, including the document-level
1596
+ * `discover_dids`. A `null` / absent response is the empty policy.
1597
+ */
1598
+ declare function parseAgentAuthPolicy(response: unknown): AgentAuthPolicy;
1455
1599
  /** Extract the `agents` array from an `agent-auth-get` response. */
1456
1600
  declare function parseAgentAuthGet(response: unknown): AgentAuthEntry[];
1457
1601
  interface AgentAuthMergeResult {
@@ -1462,27 +1606,42 @@ interface AgentAuthMergeResult {
1462
1606
  }
1463
1607
  /** Input to the full-document write {@link T3nClient.agentAuthUpdate}. The
1464
1608
  * document IS the new state: an empty `agents` list revokes all agent
1465
- * access. Mirrors the contract `AgentAuthPolicy`. */
1609
+ * access, and an omitted / empty `discoverDids` persists an empty
1610
+ * discovery-grant list (the contract has no per-field merge). Mirrors the
1611
+ * contract `AgentAuthPolicy`. */
1466
1612
  interface AgentAuthUpdateInput {
1467
1613
  agents: AgentAuthEntry[];
1614
+ /** Document-level discovery grants — see {@link AgentAuthPolicy}. */
1615
+ discoverDids?: string[];
1468
1616
  }
1469
1617
  /**
1470
- * Serialise a camelCase `agents` list to the contract's canonical
1618
+ * Serialise a camelCase policy document to the contract's canonical
1471
1619
  * snake_case `agent-auth-update` wire (`agent_did` / `script_name` /
1472
1620
  * `version_req` / `read_scopes` / `valid_from_secs` / `valid_until_secs` /
1473
- * `allowed_hosts`), so neither write path relies on the contract's
1474
- * compatibility aliases. Absent optionals are omitted (never sent as
1475
- * `null`); empty `scopes` / `read_scopes` are omitted (the contract
1476
- * defaults both to empty). `functions` and `allowed_hosts` are always
1477
- * emitted — the contract requires explicit functions (`["*"]` = all) and
1478
- * reads an absent `allowed_hosts` as deny-all egress.
1479
- */
1480
- declare function toAgentAuthUpdateWire(agents: AgentAuthEntry[]): {
1621
+ * `allowed_hosts` / `discover_dids`), so neither write path relies on the
1622
+ * contract's compatibility aliases. Absent optionals are omitted (never
1623
+ * sent as `null`); empty `scopes` / `read_scopes` are omitted (the
1624
+ * contract defaults both to empty). `functions` and `allowed_hosts` are
1625
+ * always emitted — the contract requires explicit functions (`["*"]` =
1626
+ * all) and reads an absent `allowed_hosts` as deny-all egress. The
1627
+ * document-level `discover_dids` (strictly snake_case — the contract
1628
+ * defines no camelCase alias for it) is emitted only when non-empty; the
1629
+ * contract defaults an absent list to empty.
1630
+ */
1631
+ declare function toAgentAuthUpdateWire(agents: AgentAuthEntry[], discoverDids?: string[]): {
1481
1632
  agents: Array<{
1482
1633
  agent_did: string;
1483
1634
  scripts: Array<Record<string, unknown>>;
1484
1635
  }>;
1636
+ discover_dids?: string[];
1485
1637
  };
1638
+ /**
1639
+ * Order-preserving deduplicating union of discovery-grant DID lists —
1640
+ * the read-merge-write counterpart of {@link mergeAgentAuthEntries} for
1641
+ * the document-level `discoverDids` (the contract rejects duplicate
1642
+ * entries, so the union must dedupe).
1643
+ */
1644
+ declare function mergeDiscoverDids(existing: string[], additions: string[]): string[];
1486
1645
  /**
1487
1646
  * Merge new agent entries into the existing policy with script-level union
1488
1647
  * semantics: for an agent DID present on both sides, script rows whose
@@ -1628,6 +1787,95 @@ declare class KycStatusTimeoutError extends T3nError {
1628
1787
  lastStatus?: KycStatus | undefined);
1629
1788
  }
1630
1789
 
1790
+ /**
1791
+ * Contract-discovery wire shapes.
1792
+ *
1793
+ * Field-for-field mirrors of the node's `contracts.list` and `delegation.check`
1794
+ * JSON-RPC responses (`service::contract_discovery::{ListedContract,
1795
+ * ListContractsResponse}` and `service::grant_check::{GrantRef,
1796
+ * GrantCheckResponse}`). Both methods are session-authenticated plaintext reads
1797
+ * dispatched over `/api/rpc` — the same posture as `token.get-usage` — so the
1798
+ * SDK wrappers return the parsed `result` object directly.
1799
+ */
1800
+ /** The navigable starting points of the discovery funnel. */
1801
+ type ListContractsScope = "core" | "org" | "self";
1802
+ /** Params for `contracts.list` (every field optional; `{}` lists core). */
1803
+ interface ListContractsParams {
1804
+ /** `"core"` (default) | `"org"` | `"self"`. */
1805
+ scope?: ListContractsScope;
1806
+ /** Target org DID (required for scope `"org"`). */
1807
+ org_did?: string;
1808
+ /** The member the agent acts for (required for scope `"org"` / `"self"`). */
1809
+ pii_did?: string;
1810
+ /** Page offset (defaults to 0 server-side). */
1811
+ offset?: number;
1812
+ /** Page size (defaults + clamped server-side). */
1813
+ limit?: number;
1814
+ }
1815
+ /** Contract kind — `"core"` platform system contract, `"tenant"` z-space. */
1816
+ type ContractKind = "core" | "tenant";
1817
+ /** One contract as presented by `contracts.list`. */
1818
+ interface ListedContract {
1819
+ /** Canonical name: `tee:<name>` for core, `z:<tid>:<tail>` for tenant. */
1820
+ name: string;
1821
+ kind: ContractKind;
1822
+ /** Current registered version; `null` when the contract is not registered. */
1823
+ version: string | null;
1824
+ /** Descriptor summary, or empty when no descriptor is published. */
1825
+ summary: string;
1826
+ /** Descriptor tags, or empty. */
1827
+ tags: string[];
1828
+ /** Owning DID: the org DID (org mode) or the member's own DID (self mode). */
1829
+ owner_org_did?: string;
1830
+ /**
1831
+ * Human-facing short name: the trailing segment of `name` (`payroll` from
1832
+ * `z:<tid>:payroll`, `user` from `tee:user`). Present this to people instead
1833
+ * of the full canonical `name`, which remains the dispatch key.
1834
+ */
1835
+ short_name: string;
1836
+ }
1837
+ /** Response body for `contracts.list`. */
1838
+ interface ListContractsResult {
1839
+ scope: string;
1840
+ contracts: ListedContract[];
1841
+ next_offset: number | null;
1842
+ }
1843
+ /** Which standing grant a satisfied/missing entry refers to. */
1844
+ type DelegationGrantKind = "agent_auth" | "user_grant";
1845
+ /** Params for `delegation.check` (the generic capability read). */
1846
+ interface GrantCheckParams {
1847
+ /** The target contract whose requirements are checked. */
1848
+ contract: string;
1849
+ /** The member the agent wants to act for (the subject). */
1850
+ pii_did: string;
1851
+ /** Functions the intended action needs. */
1852
+ functions: string[];
1853
+ /** Org-data scopes the intended action needs. */
1854
+ scopes: string[];
1855
+ }
1856
+ /** One grant requirement — satisfied or missing. */
1857
+ interface DelegationGrantRef {
1858
+ grant: DelegationGrantKind;
1859
+ /** The target contract's canonical name. */
1860
+ contract: string;
1861
+ functions: string[];
1862
+ scopes: string[];
1863
+ }
1864
+ /**
1865
+ * Response for `delegation.check`: the `agent_auth ∩ UserGrant` verdict.
1866
+ *
1867
+ * `disclosed` is `true` only when the agent is registered under `pii_did`, so
1868
+ * org-side status was safe to disclose; `false` yields the uniform,
1869
+ * non-disclosive verdict (`authorised:false, satisfied:[], missing:[]`) that is
1870
+ * byte-invariant to the requested capability (R5 anti-enumeration).
1871
+ */
1872
+ interface GrantCheckResult {
1873
+ authorised: boolean;
1874
+ disclosed: boolean;
1875
+ satisfied: DelegationGrantRef[];
1876
+ missing: DelegationGrantRef[];
1877
+ }
1878
+
1631
1879
  /**
1632
1880
  * T3n Client - Main SDK class
1633
1881
  *
@@ -1809,6 +2057,35 @@ declare class T3nClient {
1809
2057
  * server-side handler does not run the encryption layer.
1810
2058
  */
1811
2059
  getUsage(opts?: GetUsageOptions): Promise<UsagePage>;
2060
+ /**
2061
+ * List the caller's discoverable contracts (`contracts.list`) — the
2062
+ * node-backed source for the MCP `listContracts` funnel tool.
2063
+ *
2064
+ * `scope` selects the starting point: `"core"` (curated platform contracts,
2065
+ * the default), `"org"` (one org's contracts — pass `org_did` + `pii_did`),
2066
+ * or `"self"` (the member's own contracts — pass `pii_did`). The acting agent
2067
+ * DID is resolved server-side from the session; org / self modes are
2068
+ * discovery-grant gated and return a uniform, non-disclosive empty page on a
2069
+ * gate miss (R5 anti-enumeration).
2070
+ *
2071
+ * Plaintext session read (like {@link getUsage}): the response carries only
2072
+ * public contract-registry metadata, so it is not sealed.
2073
+ */
2074
+ listContracts(params?: ListContractsParams): Promise<ListContractsResult>;
2075
+ /**
2076
+ * Generic capability check (`delegation.check`) — the
2077
+ * node-backed source for the MCP `checkDelegation` funnel tool.
2078
+ *
2079
+ * Returns the `agent_auth ∩ UserGrant` verdict for `(agent, contract,
2080
+ * pii_did)`: whether the acting agent (resolved from the session) holds the
2081
+ * standing grants that `contract`'s `functions` / `scopes` need for member
2082
+ * `pii_did`. The org half is vacuous for no-org (Individual-owned) targets,
2083
+ * and the verdict is uniform + non-disclosive (`disclosed:false`) when the
2084
+ * agent is not registered under the member (R5 anti-enumeration).
2085
+ *
2086
+ * Plaintext session read (like {@link getUsage}).
2087
+ */
2088
+ checkDelegation(params: GrantCheckParams): Promise<GrantCheckResult>;
1812
2089
  /**
1813
2090
  * Fetch a page of audit events. With no `pii_did`, returns
1814
2091
  * the caller's own audit trail (every actor). With a `pii_did` set to
@@ -1873,10 +2150,12 @@ declare class T3nClient {
1873
2150
  * `tee:user/contracts`, which is **SelfOnly**, so this always returns the
1874
2151
  * caller's own `AGENT_AUTH_MAP[self]` document.
1875
2152
  *
1876
- * @returns the `agents` entries (normalised to the camelCase write shape)
2153
+ * @returns the full policy document (normalised to the camelCase write
2154
+ * shape): the per-agent `agents` entries plus the document-level
2155
+ * `discoverDids` discovery grants
1877
2156
  * @throws if the session is not authenticated, or the contract refuses
1878
2157
  */
1879
- getAgentAuth(): Promise<AgentAuthEntry[]>;
2158
+ getAgentAuth(): Promise<AgentAuthPolicy>;
1880
2159
  /**
1881
2160
  * Authorise an agent for one contract on the caller's own behalf
1882
2161
  * (envelope-free authorisation). Read-merge-writes the
@@ -1893,13 +2172,24 @@ declare class T3nClient {
1893
2172
  * parameters for. The caller MUST be the delegating user, authenticated as
1894
2173
  * themselves — only they may create their own grant.
1895
2174
  *
2175
+ * The document-level `discoverDids` discovery grants ride the same
2176
+ * read-merge-write: the existing list is always carried forward (the
2177
+ * contract persists the whole document, so dropping it here would revoke
2178
+ * standing discovery), and any `options.discoverDids` are unioned in
2179
+ * (order-preserving, deduplicated).
2180
+ *
1896
2181
  * @param agentDid - the agent DID being authorised
1897
2182
  * @param grant - the single script grant to set (contract, functions,
1898
2183
  * scopes, validity, egress hosts)
2184
+ * @param options - optional `discoverDids` to union into the document's
2185
+ * discovery grants (org DIDs for org-mode `listContracts`, the caller's
2186
+ * own DID for self mode)
1899
2187
  * @returns the script rows preserved from the existing policy (audit aid)
1900
2188
  * @throws if the session is not authenticated, or the contract refuses
1901
2189
  */
1902
- updateAgentAuth(agentDid: string, grant: AgentAuthScriptGrant): Promise<{
2190
+ updateAgentAuth(agentDid: string, grant: AgentAuthScriptGrant, options?: {
2191
+ discoverDids?: string[];
2192
+ }): Promise<{
1903
2193
  preservedRows: string[];
1904
2194
  }>;
1905
2195
  /**
@@ -2151,15 +2441,18 @@ declare class T3nClient {
2151
2441
  /**
2152
2442
  * Replace this user's agent-authorisation policy (`tee:user/contracts` →
2153
2443
  * `agent-auth-update`). The supplied document IS the new state: an empty
2154
- * `agents` array revokes all agent access. This is the full-document
2444
+ * `agents` array revokes all agent access, and an omitted `discoverDids`
2445
+ * persists an empty discovery-grant list. This is the full-document
2155
2446
  * write — use {@link T3nClient.updateAgentAuth} for the single-grant
2156
- * read-merge-write that preserves other contracts' grants.
2447
+ * read-merge-write that preserves other contracts' grants and the
2448
+ * standing discovery grants.
2157
2449
  *
2158
2450
  * Typed wrapper over the raw contract call: callers pass camelCase input;
2159
2451
  * the SDK emits the canonical snake_case wire via
2160
2452
  * {@link toAgentAuthUpdateWire} (carrying `scopes` / `read_scopes` /
2161
- * validity alongside `functions` / `allowed_hosts`), so it does not rely
2162
- * on the contract's compatibility aliases.
2453
+ * validity alongside `functions` / `allowed_hosts`, plus the
2454
+ * document-level `discover_dids`), so it does not rely on the contract's
2455
+ * compatibility aliases.
2163
2456
  *
2164
2457
  * @throws {RpcError} if the contract rejects the policy (validation failure,
2165
2458
  * too many agents/grants).
@@ -2398,8 +2691,9 @@ declare function metamask_get_address(): Promise<string>;
2398
2691
  declare function eth_get_address(privateKey: string): string;
2399
2692
  /**
2400
2693
  * Create an MlKemPublicKey handler that lazily fetches the root public key
2401
- * from `${baseUrl}/status` on first invocation and caches the encoded
2402
- * response for subsequent calls.
2694
+ * from `${baseUrl}/status` on first invocation, verifies it against the
2695
+ * DKG attestation trust anchor (SP-003), and caches the encoded response
2696
+ * for subsequent calls.
2403
2697
  *
2404
2698
  * @param baseUrl - **Required**. The node URL whose `/status` endpoint should
2405
2699
  * serve the ML-KEM public key. Must be the same URL the
@@ -2411,8 +2705,12 @@ declare function eth_get_address(privateKey: string): string;
2411
2705
  * hit the wrong node. Three downstream consumers (demo.ts,
2412
2706
  * t3-apps dev wallet hooks, t3n-mcp session manager) all
2413
2707
  * hit this trap before we tightened the type.
2708
+ * @param trustAnchor - **Required**. Client-pinned expected peer IDs +
2709
+ * RTMR3 allowlist the DKG bundle is verified against, or
2710
+ * `{ unsafe_trust_server: true }` to skip verification.
2711
+ * The key is only cached/returned once verification passes.
2414
2712
  */
2415
- declare function createMlKemPublicKeyHandler(baseUrl: string): GuestToHostHandler;
2713
+ declare function createMlKemPublicKeyHandler(baseUrl: string, trustAnchor: TrustAnchorOrUnsafe): GuestToHostHandler;
2416
2714
  /**
2417
2715
  * Create Random handler backed by crypto.getRandomValues
2418
2716
  * Note: The Rust Vec<u8> type serializes as an array of bytes, not a base64 string
@@ -2423,8 +2721,11 @@ declare function createRandomHandler(): GuestToHostHandler;
2423
2721
  *
2424
2722
  * @param baseUrl - **Required**. Forwarded to `createMlKemPublicKeyHandler`
2425
2723
  * so the lazy /status fetch hits the right node.
2724
+ * @param trustAnchor - **Required**. Forwarded to the ML-KEM handler so the
2725
+ * fetched key is verified against the DKG attestation
2726
+ * (SP-003) before the handshake trusts it.
2426
2727
  */
2427
- declare function createDefaultHandlers(baseUrl: string): GuestToHostHandlers;
2728
+ declare function createDefaultHandlers(baseUrl: string, trustAnchor: TrustAnchorOrUnsafe): GuestToHostHandlers;
2428
2729
 
2429
2730
  /**
2430
2731
  * Payroll request shapes + shared encoding utilities.
@@ -2650,6 +2951,17 @@ interface OrgDataClientOptions extends ExecuteOrgDataActionOptions {
2650
2951
  * header (e.g. the staging Cloud Armor bypass token).
2651
2952
  */
2652
2953
  headers?: Record<string, string>;
2954
+ /**
2955
+ * **Required.** Trust anchor for the internal `T3nClient`'s DKG
2956
+ * attestation check (SP-003). Mirrors `T3nClientConfig.trustAnchor`:
2957
+ * either a pinned {@link TrustAnchor} or the explicit
2958
+ * `{ unsafe_trust_server: true }` opt-out. Required (no silent default)
2959
+ * so bypassing verification is always a visible, grep-able choice —
2960
+ * an authenticated ETH-key caller is still MITM-able on the ML-KEM key.
2961
+ * Signed trust-anchor manifests are not published yet, so most callers
2962
+ * pass `{ unsafe_trust_server: true }` today.
2963
+ */
2964
+ trustAnchor: TrustAnchorOrUnsafe;
2653
2965
  }
2654
2966
  /**
2655
2967
  * Client for session-authenticated org-data contract execution.
@@ -2666,7 +2978,7 @@ declare class OrgDataClient {
2666
2978
  private readonly userDid;
2667
2979
  private readonly opts;
2668
2980
  private clientPromise;
2669
- constructor(baseUrl: string, ethSecret: Uint8Array, userDid: string, opts?: OrgDataClientOptions);
2981
+ constructor(baseUrl: string, ethSecret: Uint8Array, userDid: string, opts: OrgDataClientOptions);
2670
2982
  private getAuthenticatedClient;
2671
2983
  private initialiseClient;
2672
2984
  private call;
@@ -2866,6 +3178,46 @@ declare function formatTokens(baseUnits: number | bigint): string;
2866
3178
  */
2867
3179
  declare function toBaseUnits(tokens: number): number;
2868
3180
 
3181
+ /** Closed-vocabulary serialisation annotations for a contract function's body. */
3182
+ interface WireBlock {
3183
+ /**
3184
+ * Field paths whose values are emitted as decimal strings. A path ending in
3185
+ * `.*` applies to every value of the named object/array (e.g.
3186
+ * `historical_baselines.*`).
3187
+ */
3188
+ u64_as_string?: string[];
3189
+ /**
3190
+ * Byte fields carried as typed strings. The value is passed through when it
3191
+ * is already a string; a byte input (`Uint8Array` or a `number[]` of octets)
3192
+ * is encoded per its kind.
3193
+ */
3194
+ string_encoded?: Record<string, StringEncoding>;
3195
+ }
3196
+ /** The closed set of `string_encoded` field kinds. */
3197
+ type StringEncoding = "did" | "address" | "hash";
3198
+ /**
3199
+ * Raised when a `wire` block asks for a projection the closed vocabulary cannot
3200
+ * express — an unrepresentable value for a declared field. It signals a
3201
+ * descriptor↔contract mismatch on the author's side, so callers surface it as a
3202
+ * terminal `unsupported_wire_encoding` rather than retrying.
3203
+ */
3204
+ declare class WireEncodingError extends T3nError {
3205
+ readonly field: string;
3206
+ readonly encoding?: StringEncoding | undefined;
3207
+ constructor(message: string, field: string, encoding?: StringEncoding | undefined);
3208
+ }
3209
+ type JsonRecord = Record<string, unknown>;
3210
+ /**
3211
+ * Project `args` into the plain-args body a z-space contract deserialises,
3212
+ * applying the descriptor's `wire` annotations. Returns a new object; `args` is
3213
+ * never mutated. With no `wire` block the body is returned unchanged (the
3214
+ * JSON-plain path).
3215
+ *
3216
+ * @throws {WireEncodingError} when a declared field holds a value the
3217
+ * vocabulary cannot express.
3218
+ */
3219
+ declare function requestToWire(args: JsonRecord, wire?: WireBlock): JsonRecord;
3220
+
2869
3221
  /**
2870
3222
  * Cryptographic utilities for T3n SDK
2871
3223
  *
@@ -2991,65 +3343,6 @@ interface ConfigValidationResult {
2991
3343
  errors: string[];
2992
3344
  }
2993
3345
 
2994
- /**
2995
- * TDX quote verifier backed by the Rust `signature` crate compiled to
2996
- * WASM. Full cryptographic verification: ECDSA P-256 attestation-key
2997
- * signature, PCK certificate chain walk to Intel's root CA, and
2998
- * report_data + RTMR comparison.
2999
- *
3000
- * The WASM bytes are inlined as base64 (see quote_verifier_bytes.ts)
3001
- * so the SDK works without bundler WASM plugins and without runtime
3002
- * asset URL resolution.
3003
- */
3004
- interface QuoteVerifyResult {
3005
- valid: boolean;
3006
- error?: string;
3007
- rtmr3?: string;
3008
- report_data?: string;
3009
- }
3010
- interface PeerQuoteResult {
3011
- peer_id: string;
3012
- valid: boolean;
3013
- error?: string;
3014
- rtmr3?: string;
3015
- }
3016
- interface DkgVerifyResult {
3017
- valid: boolean;
3018
- results: PeerQuoteResult[];
3019
- valid_count: number;
3020
- expected_count: number;
3021
- error?: string;
3022
- }
3023
- /**
3024
- * Verify a single TDX attestation quote with full cryptographic verification.
3025
- *
3026
- * @param quoteB64 - Base64-encoded raw TDX v4 quote
3027
- * @param attestationMsgB64 - Base64-encoded attestation message
3028
- * (for DKG: encaps_key || sorted_peer_id_bytes)
3029
- * @param expectedRtmr3B64 - Optional base64-encoded 48-byte RTMR3
3030
- * @returns Verification result with extracted measurements
3031
- */
3032
- declare function verifyTdxQuote(quoteB64: string, attestationMsgB64: string, expectedRtmr3B64?: string): Promise<QuoteVerifyResult>;
3033
- /**
3034
- * Verify a full DKG attestation bundle: multiple TDX quotes from all
3035
- * participating nodes, plus the binding between the quotes and the
3036
- * ML-KEM encapsulation key. Checks:
3037
- * 1. attestationMsg starts with encapsKey (server can't swap the key)
3038
- * 2. Every quote's ECDSA signature chains to Intel's SGX root CA
3039
- * 3. Every quote's report_data == keccak512(attestationMsg)
3040
- * 4. Optional RTMR3 pinning per quote
3041
- *
3042
- * @param encapsKeyB64 - Base64-encoded ML-KEM encapsulation key
3043
- * (from `/status.encaps_key`)
3044
- * @param attestationMsgB64 - Base64-encoded raw attestation message
3045
- * (from `/status.dkg_attestation.attestation_msg`)
3046
- * @param peerIds - Sorted array of base58 peer IDs
3047
- * @param quotes - Map of peer_id → base64-encoded TDX quote
3048
- * @param expectedRtmr3B64 - Optional base64-encoded 48-byte RTMR3
3049
- * @returns Per-peer verification results and overall validity
3050
- */
3051
- declare function verifyDkgAttestation(encapsKeyB64: string, attestationMsgB64: string, peerIds: string[], quotes: Record<string, string>, expectedRtmr3B64?: string): Promise<DkgVerifyResult>;
3052
-
3053
3346
  /**
3054
3347
  * Configuration validation for T3n SDK
3055
3348
  */
@@ -3262,6 +3555,22 @@ interface ContractPublishInput {
3262
3555
  */
3263
3556
  source_hash?: string;
3264
3557
  }
3558
+ /**
3559
+ * Input for `TenantContractsNamespace.setDescriptor`: publish the agent-facing
3560
+ * descriptor document for an already-registered contract version via
3561
+ * `tee:tenant/contracts.set-descriptor`.
3562
+ */
3563
+ interface ContractSetDescriptorInput {
3564
+ tail: string;
3565
+ /** Semver the descriptor is bound to; the `name@version` must already be registered. */
3566
+ version: string;
3567
+ /**
3568
+ * The descriptor document — contract-level metadata plus a non-empty
3569
+ * `functions` array of function descriptors — embedded as JSON and stored
3570
+ * verbatim at the version-scoped `:descriptor` sidecar.
3571
+ */
3572
+ descriptor: unknown;
3573
+ }
3265
3574
  interface ContractExecuteInput {
3266
3575
  version: string;
3267
3576
  functionName: string;
@@ -3293,6 +3602,7 @@ interface ExecuteBusinessContractOptions<T = unknown> {
3293
3602
  type TenantMapCreateInput = MapCreateInput;
3294
3603
  type TenantMapUpdatePatch = MapUpdateInput;
3295
3604
  type TenantContractPublishInput = ContractPublishInput;
3605
+ type TenantContractSetDescriptorInput = ContractSetDescriptorInput;
3296
3606
  type TenantContractExecuteInput = ContractExecuteInput;
3297
3607
  /**
3298
3608
  * Options shared by the `tee:tenant` management calls that accept an optional
@@ -3352,6 +3662,15 @@ declare class TenantContractsNamespace {
3352
3662
  constructor(client: TenantClient);
3353
3663
  publish(input: ContractPublishInput, opts?: TenantTargetOptions): Promise<ContractRegisterResult>;
3354
3664
  register(input: ContractPublishInput, opts?: TenantTargetOptions): Promise<ContractRegisterResult>;
3665
+ /**
3666
+ * Publish the agent-facing descriptor document for a registered
3667
+ * `name@version` via `set-descriptor`. Owner-gated by the
3668
+ * same tenant-resolution rules as `register`, and refused when the
3669
+ * `name@version` is not registered. The node serves the stored document as
3670
+ * the sole descriptor source for the MCP dispatch funnel, so a contract
3671
+ * without one is not dispatchable through it.
3672
+ */
3673
+ setDescriptor(input: ContractSetDescriptorInput, opts?: TenantTargetOptions): Promise<unknown>;
3355
3674
  disable(tail: string, opts?: TenantTargetOptions): Promise<unknown>;
3356
3675
  enable(tail: string, opts?: TenantTargetOptions): Promise<unknown>;
3357
3676
  unregister(tail: string, opts?: TenantTargetOptions): Promise<unknown>;
@@ -3459,5 +3778,5 @@ declare function tenantDidHex(tenantDid: string): string;
3459
3778
  declare function validateTail(tail: string): string;
3460
3779
  declare function canonicalTenantName(tenantDid: string, tail: string): string;
3461
3780
 
3462
- export { AuthMethod, AuthenticationError, BASE_UNITS_PER_TOKEN, ContractResponseError, DEFAULT_ENVIRONMENT, DEFAULT_INDIVIDUAL_THRESHOLD_CENTS, DEFAULT_KYC_POLL_CADENCE, HandshakeError, HttpTransport, KycStatusTimeoutError, LogLevel, MockTransport, NODE_URLS, OrgDataClient, OtpRateLimitedError, RpcError, SessionExpiredError, SessionOrgDataClient, SessionStateError, SessionStatus, T3nClient, T3nError, TERMINAL_KYC_STATUSES, TOKEN_DECIMALS, TenantClient, TenantContractsNamespace, TenantMapsNamespace, TenantNamespace, TenantSdkValidationError, TenantTokenNamespace, UnsupportedTenantSdkOperationError, UserUpsertError, WasmError, Z_PAYROLL_AUDIT_READ_FUNCTIONS, Z_PAYROLL_RUN_FUNCTIONS, _b64uEncode, assertShape, b64uDecodeStrict, b64uEncodeBytes, bytesToString, canonicalTenantName, clearKeyCache, compactDidFromBytes, createDefaultHandlers, createEmailOtpAuthInput, createEthAuthInput, createLogger, createMlKemPublicKeyHandler, createOidcAuthInput, createOrgDataClientFromSession, createRandomHandler, createWorkloadAuthInput, decodeWasmErrorMessage, eth_get_address, extractWasmError, fetchDkgAttestation, fetchMlKemPublicKey, formatTokens, generateRandomString, generateUUID, getEnvironment, getEnvironmentName, getGlobalLogLevel, getLogger, getNodeUrl, getScriptVersion, isDataGetResponse, isDataListResponse, isMutationResponse, isObject, isOrgContractGrants, isOrgPolicyMeta, isOrgPolicyView, isOrgWriters, loadConfig, loadWasmComponent, maskKeyMaterial, mergeAgentAuthEntries, metamask_get_address, metamask_sign, parseAgentAuthGet, parseContractResponse, redactSecrets, redactSecretsFromJson, setEnvironment, setGlobalLogLevel, setNodeUrl, stringToBytes, tenantDidHex, toAgentAuthUpdateWire, toBaseUnits, validateConfig, validateTail, verifyDkgAttestation, verifyTdxQuote };
3463
- export type { AdmitForOrgOptions, AgentAuthEntry, AgentAuthMergeResult, AgentAuthScriptGrant, AgentAuthUpdateInput, AuthInput, BalanceRow, ChargeReason, ClientAuth, ClientHandshake, ConfigValidationResult, ContractExecuteInput, ContractPublishInput, ContractRegisterResult, ContractResponseSchema, CreatePolicyInput, DataGetInput, DataGetResponse, DataListInput, DataListResponse, DeleteDataInput, DeleteGrantsInput, DeleteScopeInput, Did, Direction, DkgAttestation, DkgVerifyResult, EmailOtpAuthInput, EmailOtpCredentials, Environment, EthAuthInput, ExecuteBusinessContractOptions, ExecuteOrgDataActionOptions, GetUsageOptions, GrantsGetInput, GuestToHostHandler, GuestToHostHandlers, HandshakeResult, JsonRpcRequest, JsonRpcResponse, KycPollCadence, KycPollOptions, KycStatus, KycStatusKind, Logger, MapCreateInput, MapResponse, MapUpdateInput, MapVisibility, MutationResponse, OidcAuthInput, OidcCredentials, OrgContractGrants, OrgDataActionWire, OrgDataClientOptions, OrgPolicyMeta, OrgPolicyView, OrgWriters, OtpChannel, OtpMergeSuggestion, OtpRequestInput, OtpRequestResult, OtpVerifyInput, OtpVerifyResult, PayrollRunRequest, PeerQuoteResult, PolicyGetInput, QuoteVerifyResult, ReaderSet, SdkConfig, SessionCrypto, SessionId, SetGrantsInput, SetWritersInput, SubmitUserInputArgs, SubmitUserInputResult, T3nClientConfig, TenantAdmitProjection, TenantAdmitStatus, TenantBaseClient, TenantClientConfig, TenantContractExecuteInput, TenantContractPublishInput, TenantExecutionSession, TenantMapCreateInput, TenantMapUpdatePatch, TenantMeResponse, TenantSdkEnvironment, TenantSelfAdmitResult, TenantStatus, TenantTargetOptions, TokenTxKind, Transport, UpdateMetaInput, UsageEntry, UsagePage, UserGrant, UserInputProfile, UserUpsertErrorKind, WasmComponent, WasmNextResult, WorkloadAuthInput, WriteDataInput, WriterSet, WritersGetInput };
3781
+ export { AuthMethod, AuthenticationError, BASE_UNITS_PER_TOKEN, ContractResponseError, DEFAULT_ENVIRONMENT, DEFAULT_INDIVIDUAL_THRESHOLD_CENTS, DEFAULT_KYC_POLL_CADENCE, HandshakeError, HttpTransport, KycStatusTimeoutError, LogLevel, MockTransport, NODE_URLS, OrgDataClient, OtpRateLimitedError, RpcError, SessionExpiredError, SessionOrgDataClient, SessionStateError, SessionStatus, T3nClient, T3nError, TERMINAL_KYC_STATUSES, TOKEN_DECIMALS, TenantClient, TenantContractsNamespace, TenantMapsNamespace, TenantNamespace, TenantSdkValidationError, TenantTokenNamespace, UnsupportedTenantSdkOperationError, UserUpsertError, WasmError, WireEncodingError, Z_PAYROLL_AUDIT_READ_FUNCTIONS, Z_PAYROLL_RUN_FUNCTIONS, _b64uEncode, assertShape, b64uDecodeStrict, b64uEncodeBytes, bytesToString, canonicalTenantName, clearKeyCache, compactDidFromBytes, createDefaultHandlers, createEmailOtpAuthInput, createEthAuthInput, createLogger, createMlKemPublicKeyHandler, createOidcAuthInput, createOrgDataClientFromSession, createRandomHandler, createWorkloadAuthInput, decodeWasmErrorMessage, eth_get_address, extractWasmError, fetchDkgAttestation, fetchMlKemPublicKey, formatTokens, generateRandomString, generateUUID, getEnvironment, getEnvironmentName, getGlobalLogLevel, getLogger, getNodeUrl, getScriptVersion, isDataGetResponse, isDataListResponse, isMutationResponse, isObject, isOrgContractGrants, isOrgPolicyMeta, isOrgPolicyView, isOrgWriters, isUnsafeTrustServer, loadConfig, loadWasmComponent, maskKeyMaterial, mergeAgentAuthEntries, mergeDiscoverDids, metamask_get_address, metamask_sign, parseAgentAuthGet, parseAgentAuthPolicy, parseContractResponse, redactSecrets, redactSecretsFromJson, requestToWire, setEnvironment, setGlobalLogLevel, setNodeUrl, stringToBytes, tenantDidHex, toAgentAuthUpdateWire, toBaseUnits, validateConfig, validateTail, verifyDkgAttestation, verifyTdxQuote };
3782
+ export type { AdmitForOrgOptions, AgentAuthEntry, AgentAuthMergeResult, AgentAuthPolicy, AgentAuthScriptGrant, AgentAuthUpdateInput, AuthInput, BalanceRow, ChargeReason, ClientAuth, ClientHandshake, ConfigValidationResult, ContractExecuteInput, ContractKind, ContractPublishInput, ContractRegisterResult, ContractResponseSchema, ContractSetDescriptorInput, CreatePolicyInput, DataGetInput, DataGetResponse, DataListInput, DataListResponse, DelegationGrantKind, DelegationGrantRef, DeleteDataInput, DeleteGrantsInput, DeleteScopeInput, Did, Direction, DkgAttestation, DkgVerifyResult, EmailOtpAuthInput, EmailOtpCredentials, Environment, EthAuthInput, ExecuteBusinessContractOptions, ExecuteOrgDataActionOptions, GetUsageOptions, GrantCheckParams, GrantCheckResult, GrantsGetInput, GuestToHostHandler, GuestToHostHandlers, HandshakeResult, JsonRpcRequest, JsonRpcResponse, KycPollCadence, KycPollOptions, KycStatus, KycStatusKind, ListContractsParams, ListContractsResult, ListContractsScope, ListedContract, Logger, MapCreateInput, MapResponse, MapUpdateInput, MapVisibility, MutationResponse, OidcAuthInput, OidcCredentials, OrgContractGrants, OrgDataActionWire, OrgDataClientOptions, OrgPolicyMeta, OrgPolicyView, OrgWriters, OtpChannel, OtpMergeSuggestion, OtpRequestInput, OtpRequestResult, OtpVerifyInput, OtpVerifyResult, PayrollRunRequest, PeerQuoteResult, PolicyGetInput, QuoteVerifyResult, ReaderSet, SdkConfig, SessionCrypto, SessionId, SetGrantsInput, SetWritersInput, StringEncoding, SubmitUserInputArgs, SubmitUserInputResult, T3nClientConfig, TenantAdmitProjection, TenantAdmitStatus, TenantBaseClient, TenantClientConfig, TenantContractExecuteInput, TenantContractPublishInput, TenantContractSetDescriptorInput, TenantExecutionSession, TenantMapCreateInput, TenantMapUpdatePatch, TenantMeResponse, TenantSdkEnvironment, TenantSelfAdmitResult, TenantStatus, TenantTargetOptions, TokenTxKind, Transport, TrustAnchor, TrustAnchorOrUnsafe, UnsafeTrustServer, UpdateMetaInput, UsageEntry, UsagePage, UserGrant, UserInputProfile, UserUpsertErrorKind, WasmComponent, WasmNextResult, WireBlock, WorkloadAuthInput, WriteDataInput, WriterSet, WritersGetInput };