diff --git a/app/landing/public/schemas/v0.1/envelope.json b/app/landing/public/schemas/v0.1/envelope.json new file mode 100644 index 0000000..dd3f56e --- /dev/null +++ b/app/landing/public/schemas/v0.1/envelope.json @@ -0,0 +1,810 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema#", + "$id": "https://txkit.dev/schemas/v0.1/envelope.json", + "title": "PreparedTransaction Envelope v0.1", + "description": "Off-chain envelope for prepared-but-not-yet-signed transactions, batches, and signature requests. Reference implementation for the Ethereum ERC \"Prepared Transaction Envelope\" specification.", + "$ref": "#/definitions/PreparedEnvelope", + "definitions": { + "PreparedEnvelope": { + "anyOf": [ + { + "type": "object", + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "id": { + "type": "string", + "maxLength": 4096 + }, + "issuedAt": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$" + }, + "expiresAt": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/issuedAt" + }, + "nonce": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]*$" + }, + "producer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string" + }, + "signature": { + "type": "object", + "properties": { + "scheme": { + "type": "string", + "minLength": 1 + }, + "publicKey": { + "type": "string" + }, + "signature": { + "type": "string", + "minLength": 1 + }, + "coverage": { + "type": "string", + "enum": [ + "envelope", + "content" + ] + } + }, + "required": [ + "scheme", + "signature", + "coverage" + ], + "additionalProperties": false + } + }, + "required": [ + "id" + ], + "additionalProperties": false + }, + "origin": { + "type": "object", + "properties": { + "url": { + "type": "string", + "minLength": 1 + }, + "verifyStatus": { + "type": "string", + "enum": [ + "VERIFIED", + "UNVERIFIED", + "MISMATCH" + ] + }, + "attestation": { + "type": "string" + } + }, + "required": [ + "url", + "verifyStatus" + ], + "additionalProperties": false + }, + "risk": { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": [ + "ALLOW", + "WARN", + "BLOCK" + ] + }, + "score": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "warnings": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "minLength": 1 + }, + "severity": { + "type": "string", + "enum": [ + "low", + "medium", + "high", + "critical" + ] + }, + "message": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "code", + "severity", + "message" + ], + "additionalProperties": false + } + }, + "scanners": { + "type": "array", + "items": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "minLength": 1 + }, + "verdict": { + "type": "string", + "enum": [ + "ALLOW", + "WARN", + "BLOCK" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "provider", + "verdict" + ], + "additionalProperties": false + } + } + }, + "required": [ + "action", + "warnings" + ], + "additionalProperties": false + }, + "capabilities": { + "type": "object", + "properties": { + "atomicRequired": { + "type": "boolean" + }, + "paymasterService": { + "type": "object", + "properties": { + "url": { + "type": "string", + "minLength": 1 + }, + "sponsor": { + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + } + }, + "required": [ + "url" + ], + "additionalProperties": false + }, + "permissions": { + "type": "object", + "properties": { + "context": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/nonce" + }, + "type": { + "type": "string", + "minLength": 1 + }, + "expiry": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + } + }, + "required": [ + "context", + "type" + ], + "additionalProperties": false + }, + "requiresAccountType": { + "type": "string", + "enum": [ + "eoa", + "delegated-eoa", + "erc-4337" + ] + } + }, + "additionalProperties": {} + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "kind": { + "type": "string", + "const": "evm-tx" + }, + "content": { + "type": "object", + "properties": { + "chain": { + "type": "string", + "pattern": "^[-a-z0-9]{3,8}:[-a-zA-Z0-9]{1,41}$" + }, + "chainId": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + }, + "from": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "calls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "to": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "value": { + "type": "string", + "pattern": "^0x([0-9a-fA-F]+|0)$" + }, + "data": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/nonce" + }, + "operation": { + "type": "string", + "enum": [ + "call", + "delegatecall" + ] + }, + "capabilities": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "to" + ], + "additionalProperties": false + }, + "minItems": 1 + }, + "validity": { + "type": "object", + "properties": { + "notBefore": { + "type": "integer", + "minimum": 0 + }, + "notAfter": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + }, + "nonceKind": { + "type": "string", + "enum": [ + "sequential", + "durable", + "bitmap" + ] + }, + "blockhashRecency": { + "type": "object", + "properties": { + "maxAge": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + } + }, + "required": [ + "maxAge" + ], + "additionalProperties": false + } + }, + "required": [ + "notAfter" + ], + "additionalProperties": false + }, + "description": { + "type": "object", + "properties": { + "short": { + "type": "string", + "minLength": 1 + }, + "long": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "transfer", + "approve", + "permit", + "revoke-approval", + "swap", + "stake", + "unstake", + "claim", + "restake", + "mint", + "burn", + "deposit", + "withdraw", + "delegate", + "bridge", + "admin-op", + "other" + ] + } + }, + "required": [ + "short", + "action" + ], + "additionalProperties": false + }, + "metadata": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "minLength": 1 + }, + "tokenMovements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "anyOf": [ + { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + { + "type": "string", + "const": "native" + } + ] + }, + "standard": { + "type": "string", + "enum": [ + "erc20", + "erc721", + "erc1155", + "native" + ] + }, + "symbol": { + "type": "string", + "minLength": 1 + }, + "decimals": { + "type": "integer", + "minimum": 0, + "maximum": 77 + }, + "amount": { + "type": "string", + "pattern": "^-?(0|[1-9]\\d*)$" + }, + "tokenId": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "kind": { + "type": "string", + "enum": [ + "transfer", + "approve", + "permit", + "mint", + "burn", + "revoke" + ] + }, + "isUnlimited": { + "type": "boolean" + }, + "from": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "to": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "usdValue": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "token", + "standard", + "symbol", + "decimals", + "amount", + "kind", + "from", + "to" + ], + "additionalProperties": false + } + }, + "counterparties": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "role": { + "type": "string", + "enum": [ + "recipient", + "spender", + "swap-venue", + "pool", + "bridge", + "admin", + "unknown" + ] + }, + "label": { + "type": "string" + }, + "labelSource": { + "type": "string", + "enum": [ + "contact_book", + "protocol_directory", + "recent_interaction", + "untrusted" + ] + }, + "similarityWarning": { + "type": "object", + "properties": { + "similarTo": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "distance": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "similarTo", + "distance" + ], + "additionalProperties": false + } + }, + "required": [ + "address", + "role" + ], + "additionalProperties": false + } + }, + "feeBreakdown": { + "type": "object", + "properties": { + "serviceFee": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "slippageCost": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "protocolFee": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "total": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "denomination": { + "anyOf": [ + { + "type": "string", + "const": "native" + }, + { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + } + ] + } + }, + "required": [ + "total", + "denomination" + ], + "additionalProperties": false + }, + "estimation": { + "type": "object", + "properties": { + "effectivePrice": { + "type": "string" + }, + "minOutputAmount": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "maxInputAmount": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + }, + "expiration": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + }, + "quoteTimestamp": { + "type": "integer", + "minimum": 0 + } + }, + "additionalProperties": false + }, + "estimatedGas": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata/properties/tokenMovements/items/properties/amount" + } + }, + "required": [ + "protocol", + "tokenMovements", + "counterparties" + ], + "additionalProperties": false + }, + "decoderRef": { + "type": "string" + }, + "clearSigning": { + "type": "object", + "additionalProperties": {} + } + }, + "required": [ + "chain", + "calls", + "validity", + "description", + "metadata" + ], + "additionalProperties": false + } + }, + "required": [ + "$schema", + "issuedAt", + "kind", + "content" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "$schema": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/$schema" + }, + "id": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/id" + }, + "issuedAt": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/issuedAt" + }, + "expiresAt": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/expiresAt" + }, + "nonce": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/nonce" + }, + "producer": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/producer" + }, + "origin": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/origin" + }, + "risk": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/risk" + }, + "capabilities": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities" + }, + "meta": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/meta" + }, + "kind": { + "type": "string", + "const": "evm-batch" + }, + "content": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content" + } + }, + "required": [ + "$schema", + "issuedAt", + "kind", + "content" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "$schema": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/$schema" + }, + "id": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/id" + }, + "issuedAt": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/issuedAt" + }, + "expiresAt": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/expiresAt" + }, + "nonce": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/nonce" + }, + "producer": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/producer" + }, + "origin": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/origin" + }, + "risk": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/risk" + }, + "capabilities": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities" + }, + "meta": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/meta" + }, + "kind": { + "type": "string", + "const": "signature" + }, + "content": { + "type": "object", + "properties": { + "chain": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/chain" + }, + "chainId": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + }, + "from": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "scheme": { + "type": "string", + "enum": [ + "eip-712", + "personal-sign", + "siwe" + ] + }, + "domain": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "chainId": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + }, + "verifyingContract": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/capabilities/properties/paymasterService/properties/sponsor" + }, + "salt": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/nonce" + } + }, + "additionalProperties": false + }, + "types": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name", + "type" + ], + "additionalProperties": false + } + } + }, + "primaryType": { + "type": "string" + }, + "message": { + "type": "object", + "additionalProperties": {} + }, + "messageText": { + "type": "string" + }, + "description": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/description" + }, + "metadata": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/metadata" + }, + "validity": { + "$ref": "#/definitions/PreparedEnvelope/anyOf/0/properties/content/properties/validity" + }, + "erc6492": { + "type": "boolean" + } + }, + "required": [ + "chain", + "scheme", + "description" + ], + "additionalProperties": false + } + }, + "required": [ + "$schema", + "issuedAt", + "kind", + "content" + ], + "additionalProperties": false + } + ] + } + } +} diff --git a/packages/ows-adapter/src/__tests__/ows.spec.ts b/packages/ows-adapter/src/__tests__/ows.spec.ts index fdfd3f4..a36576f 100644 --- a/packages/ows-adapter/src/__tests__/ows.spec.ts +++ b/packages/ows-adapter/src/__tests__/ows.spec.ts @@ -147,7 +147,7 @@ describe('toOwsSignAndSend', () => { }) envelope.risk = { action: 'WARN', - warnings: [{ code: 'unbounded-approval', severity: 'WARN', message: 'MAX approval' }], + warnings: [{ code: 'unbounded-approval', severity: 'high', message: 'MAX approval' }], } const payload = toOwsSignAndSend(envelope) diff --git a/packages/tx-protocol/CHANGELOG.md b/packages/tx-protocol/CHANGELOG.md index 61e5b36..21b9274 100644 --- a/packages/tx-protocol/CHANGELOG.md +++ b/packages/tx-protocol/CHANGELOG.md @@ -1,5 +1,29 @@ # @txkit/tx-protocol +## [0.1.0-alpha.2] - 2026-05-11 + +Aligns the reference implementation with the ERC `Prepared Transaction Envelope` body draft (Phase 3 complete, ready for Phase 4 red-team). Five breaking changes follow. + +### Breaking changes + +- **Drop `version` field from `BaseEnvelope`.** The `$schema` URL is the version contract per ERC §1.2: envelopes MUST NOT carry a separate `version` field. `SPEC_VERSION` constant and `SpecVersion` type removed from exports. `SPEC_SCHEMA_URL` retained as the canonical version identifier. +- **Drop reserved post-quantum signature schemes from `SignatureScheme`.** `'ml-dsa-44' | 'ml-dsa-65' | 'ml-dsa-87' | 'slh-dsa-sha2-128s'` literals removed. The type remains an open string per ERC §3.2: implementations MAY use any scheme by agreement between producer and consumer, including future post-quantum algorithms, without revising this type. +- **Rename `'smart-account-7702'` → `'delegated-eoa'` in `RequiredAccountType`.** Removes the explicit EIP-7702 callout from the normative enum per ERC review decision H3. Same semantic (an EOA with installed code), neutral naming. +- **Close `RiskWarning.severity` enum to four lowercase values.** Was `'INFO' | 'WARN' | 'CRITICAL'`. Now `'low' | 'medium' | 'high' | 'critical'`, matching ERC §7 (CVSS-style severity ladder). Policy engines now have a fixed vocabulary across vendors. +- **Constrain `ScannerVerdict.verdict` to a closed enum.** Was `string`. Now `'ALLOW' | 'WARN' | 'BLOCK'`, matching `RiskAssessment.action` and ERC §7. Scanner verdicts share the same three-valued action language as the overall risk verdict. + +### Spec sync + +Canonical spec at `packages/tx-protocol/spec/v0.1/prepared-transaction.md` synced with the same five changes (drop `version`, drop PQ enums, rename account type, close severity, close verdict). + +### Migration + +Producers that emitted `version: '0.1'` MUST stop including the field. Consumers MAY accept old envelopes with the field for one release cycle by ignoring it. Producers using PQ scheme literals MUST switch to the open-string form; consumers MUST NOT reject envelopes solely because the scheme is not one of the recognised three values (§3.2). Producers using `'smart-account-7702'` MUST rename to `'delegated-eoa'`. Producers emitting `RiskWarning` MUST use lowercase severity values from the new four-value enum. Producers emitting `ScannerVerdict.verdict` MUST use one of `'ALLOW' | 'WARN' | 'BLOCK'`. + +### Reference + +ERC body draft is complete in private wiki (`projects/txkit-erc-draft/erc-draft_prepared_tx_envelope.md`). Will be submitted to `ethereum/ERCs` in Phase 6 after Phase 4 red-team (security + standards-process agents) and Phase 5 pre-Magicians outreach. + ## [0.1.0-alpha.0] - 2026-04-29 Initial alpha release. Defines the `PreparedEnvelope` shape for agent-to-wallet diff --git a/packages/tx-protocol/examples/multicall-batch.ts b/packages/tx-protocol/examples/multicall-batch.ts new file mode 100644 index 0000000..497436d --- /dev/null +++ b/packages/tx-protocol/examples/multicall-batch.ts @@ -0,0 +1,145 @@ +/** + * packages/tx-protocol/examples/multicall-batch.ts + * + * Example: PreparedEnvelope (kind: 'evm-batch') for an atomic + * approve + swap flow via ERC-5792 wallet_sendCalls. + * + * Demonstrates: + * - evm-batch kind with calls.length >= 2 (Spec §5.1) + * - atomicRequired capability per ERC-5792 (Spec §8.1) + * - Multi-call tokenMovements enumeration covering approve + transfer + * in the same envelope (Spec §5.6) + * + * Run: + * pnpm exec tsx packages/tx-protocol/examples/multicall-batch.ts + */ + +import { + createEvmBatch, + deserialize, + serialize, + validateEnvelope, +} from '@txkit/tx-protocol' +import type { EvmTxContent } from '@txkit/tx-protocol' + +const USER = '0xdeadBeefdeaDbEEfDEaDbeefdEADBEeFDEaDBEEf' as const +const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as const +const UNISWAP_V3_ROUTER = '0xE592427A0AEce92De3Edee1F18E0157C05861564' as const + +// 1,000 USDC = 1_000 * 10^6 (USDC has 6 decimals) +const AMOUNT_RAW = '1000000000' + +const content: EvmTxContent = { + chain: 'eip155:1', + chainId: 1, + from: USER, + calls: [ + { + // Call 1: approve USDC for 1000 to Uniswap V3 Router. + // approve(spender=router, amount=1_000_000_000) + to: USDC, + data: '0x095ea7b3000000000000000000000000e592427a0aece92de3edee1f18e0157c0586156400000000000000000000000000000000000000000000000000000000003b9aca00', + value: '0x0', + operation: 'call', + }, + { + // Call 2: exactInputSingle USDC -> ETH on Uniswap V3 (0.05% pool). + // Calldata truncated for brevity; in production the consumer decodes + // the full selector + struct against the canonical Router ABI. + to: UNISWAP_V3_ROUTER, + data: '0x414bf389000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + value: '0x0', + operation: 'call', + }, + ], + validity: { + notAfter: Math.floor(Date.now() / 1000) + 1800, + nonceKind: 'sequential', + }, + description: { + short: 'Swap 1000 USDC for ETH (atomic approve + swap)', + long: 'Atomic batch: approve 1000 USDC to Uniswap V3 Router, then swap 1000 USDC for ETH via exactInputSingle on the 0.05% pool. Either both calls execute or both revert per ERC-5792 atomicRequired.', + action: 'swap', + }, + metadata: { + protocol: 'uniswap-v3', + tokenMovements: [ + { + token: USDC, + standard: 'erc20', + symbol: 'USDC', + decimals: 6, + amount: AMOUNT_RAW, + kind: 'approve', + from: USER, + to: UNISWAP_V3_ROUTER, + isUnlimited: false, + }, + { + token: USDC, + standard: 'erc20', + symbol: 'USDC', + decimals: 6, + amount: AMOUNT_RAW, + kind: 'transfer', + from: USER, + to: UNISWAP_V3_ROUTER, + }, + ], + counterparties: [ + { + address: USDC, + role: 'unknown', + label: 'USDC', + labelSource: 'protocol_directory', + }, + { + address: UNISWAP_V3_ROUTER, + role: 'swap-venue', + label: 'Uniswap V3 Router', + labelSource: 'protocol_directory', + }, + ], + estimatedGas: '180000', + }, + decoderRef: 'uniswap-v3/router/exactInputSingle', +} + +const envelope = createEvmBatch(content, { + origin: { url: 'https://app.uniswap.org', verifyStatus: 'VERIFIED' }, + producer: { + id: 'did:web:uniswap.org#agent-tools', + name: 'uniswap/agent-tools', + }, + capabilities: { + atomicRequired: true, + }, +}) + +const result = validateEnvelope(envelope) +if (!result.ok) { + console.error('Validation failed:', result.error) + console.error(result.issues) + process.exit(1) +} + +console.log('Valid PreparedEnvelope:', result.value.content.description.short) +console.log('Kind:', result.value.kind) +console.log('Chain:', result.value.content.chain) +console.log('Calls:', result.value.content.calls.length) +console.log('Atomic required:', result.value.capabilities?.atomicRequired) +console.log('Origin verify status:', result.value.origin?.verifyStatus ?? 'none') +console.log('Expires at:', result.value.expiresAt) +if (result.warnings) { + console.log('Advisories:') + for (const warning of result.warnings) { + console.log(` [${warning.severity}] ${warning.path}: ${warning.message}`) + } +} + +const json = serialize(envelope) +console.log('\nSerialized payload (first 200 chars):') +console.log(json.slice(0, 200) + '...') + +const restored = deserialize(json) +console.log('\nRoundtrip kind preserved:', restored.kind === envelope.kind) diff --git a/packages/tx-protocol/package.json b/packages/tx-protocol/package.json index c3e53a4..5ce7bf6 100644 --- a/packages/tx-protocol/package.json +++ b/packages/tx-protocol/package.json @@ -1,6 +1,6 @@ { "name": "@txkit/tx-protocol", - "version": "0.1.0-alpha.0", + "version": "0.1.0-alpha.2", "description": "Open protocol for prepared Web3 operations - envelope + content discriminated union, CAIP-2 chain ids, EIP-5792 aligned batches, EIP-712 signature requests. Post-quantum ready producer signatures.", "license": "MIT", "author": "Michael Diamond", @@ -66,15 +66,18 @@ "clean": "rm -rf dist", "lint": "tsc --noEmit", "typecheck": "tsc --noEmit", - "test": "vitest run" + "test": "vitest run", + "gen:schema": "tsx scripts/generate-schema.ts" }, "dependencies": { "zod": "^3.23.8" }, "devDependencies": { "tsup": "^8.4.0", + "tsx": "^4.21.0", "typescript": "^5.7.3", - "vitest": "^4.1.1" + "vitest": "^4.1.1", + "zod-to-json-schema": "^3.25.2" }, "sideEffects": false } diff --git a/packages/tx-protocol/scripts/generate-schema.ts b/packages/tx-protocol/scripts/generate-schema.ts new file mode 100644 index 0000000..6995393 --- /dev/null +++ b/packages/tx-protocol/scripts/generate-schema.ts @@ -0,0 +1,50 @@ +/** + * Generates a JSON Schema (Draft 2020-12 compatible) from the zod source of truth + * `packages/tx-protocol/src/schema.ts`, and writes it to: + * `app/landing/public/schemas/v0.1/envelope.json` + * + * The generated file is served at `https://txkit.dev/schemas/v0.1/envelope.json`, + * which is the canonical `$schema` URL referenced by every prepared envelope per + * the ERC submission Specification section 1.2. + * + * Run via: + * pnpm --filter @txkit/tx-protocol gen:schema + */ + +import { writeFileSync } from 'node:fs' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { zodToJsonSchema } from 'zod-to-json-schema' +import { preparedEnvelopeSchema } from '../src/schema' + +const __dirname = dirname(fileURLToPath(import.meta.url)) + +const SCHEMA_ID = 'https://txkit.dev/schemas/v0.1/envelope.json' +const SCHEMA_TITLE = 'PreparedTransaction Envelope v0.1' +const SCHEMA_DESCRIPTION = + 'Off-chain envelope for prepared-but-not-yet-signed transactions, batches, and signature requests. ' + + 'Reference implementation for the Ethereum ERC "Prepared Transaction Envelope" specification.' + +const OUTPUT_PATH = resolve( + __dirname, + '../../../app/landing/public/schemas/v0.1/envelope.json', +) + +const jsonSchema = zodToJsonSchema(preparedEnvelopeSchema, { + name: 'PreparedEnvelope', + $refStrategy: 'root', + target: 'jsonSchema2019-09', +}) + +const root = jsonSchema as Record +const augmented = { + $schema: 'https://json-schema.org/draft/2020-12/schema', + $id: SCHEMA_ID, + title: SCHEMA_TITLE, + description: SCHEMA_DESCRIPTION, + ...root, +} + +writeFileSync(OUTPUT_PATH, JSON.stringify(augmented, null, 2) + '\n', 'utf8') + +console.log(`Wrote ${OUTPUT_PATH}`) diff --git a/packages/tx-protocol/spec/v0.1/prepared-transaction.md b/packages/tx-protocol/spec/v0.1/prepared-transaction.md index 2b96f79..f295913 100644 --- a/packages/tx-protocol/spec/v0.1/prepared-transaction.md +++ b/packages/tx-protocol/spec/v0.1/prepared-transaction.md @@ -39,8 +39,7 @@ Neither layer is mandatory in v0.1. Both are recommended. Wallets MAY treat miss ```typescript interface BaseEnvelope { - $schema: string // "https://txkit.dev/schemas/v0.1/envelope.json" - version: '0.1' + $schema: string // "https://txkit.dev/schemas/v0.1/envelope.json" - version contract kind: K // discriminator; see §3 id?: string // idempotency, 4096 chars max (EIP-5792 convention) issuedAt: string // RFC3339 UTC @@ -55,11 +54,13 @@ interface BaseEnvelope { } ``` +The `$schema` URL is the version contract per ERC `Prepared Transaction Envelope`. Envelopes do not carry a separate `version` field; the URL path identifies the spec version. + ### 2.1 Required vs recommended | Field | Required | Notes | |---|---|---| -| `$schema`, `version`, `kind`, `issuedAt`, `content` | yes | | +| `$schema`, `kind`, `issuedAt`, `content` | yes | | | `content` kind-specific required sub-fields | yes | see per-kind §6 | | `id` | no | wallets MAY assign if producer omits; required for `wallet_getCallsStatus` | | `expiresAt` | no | if present, MUST equal `content.validity.notAfter` for tx kinds | @@ -105,10 +106,11 @@ interface Producer { signature?: ProducerSignature } +// Open string per the ERC. Implementations SHOULD support secp256k1, ed25519, +// and p256. Other schemes (including future post-quantum algorithms) MAY be +// used without revising this type. type SignatureScheme = | 'secp256k1' | 'ed25519' | 'p256' - | 'ml-dsa-44' | 'ml-dsa-65' | 'ml-dsa-87' // PQ reserved (NIST FIPS 204) - | 'slh-dsa-sha2-128s' // PQ reserved (NIST FIPS 205) | string // open for future schemes interface ProducerSignature { @@ -260,8 +262,16 @@ This closes the blind-signing gap for Permit, Permit2, CoW orders, UniswapX Dutc interface RiskAssessment { action: 'ALLOW' | 'WARN' | 'BLOCK' score?: number // 0-100 - warnings: Array<{ code, severity, message }> - scanners?: Array<{ provider, verdict, url? }> + warnings: Array<{ + code: string + severity: 'low' | 'medium' | 'high' | 'critical' + message: string + }> + scanners?: Array<{ + provider: string + verdict: 'ALLOW' | 'WARN' | 'BLOCK' + url?: string + }> } ``` @@ -274,7 +284,7 @@ interface Capabilities { atomicRequired?: boolean // EIP-5792 paymasterService?: { url: string; sponsor?: Address } // ERC-4337 paymaster hint permissions?: { context: Hex; type: string; expiry? } // ERC-7715 session - requiresAccountType?: 'eoa' | 'smart-account-7702' | 'erc-4337' + requiresAccountType?: 'eoa' | 'delegated-eoa' | 'erc-4337' [k: string]: unknown // open for vendors; MUST use 'x-' prefix } ``` diff --git a/packages/tx-protocol/src/__tests__/validate.spec.ts b/packages/tx-protocol/src/__tests__/validate.spec.ts index d1fbac1..4e0fc4c 100644 --- a/packages/tx-protocol/src/__tests__/validate.spec.ts +++ b/packages/tx-protocol/src/__tests__/validate.spec.ts @@ -4,7 +4,6 @@ import { IMPLEMENTED_KINDS, RESERVED_KINDS, SPEC_SCHEMA_URL, - SPEC_VERSION, createEvmBatch, createEvmTx, createSignature, @@ -75,10 +74,10 @@ describe('envelope + evm-tx validation', () => { } }) - it('populates $schema, version and issuedAt via createEvmTx', () => { + it('populates $schema and issuedAt via createEvmTx (no version field per spec)', () => { const env = evmTx() expect(env.$schema).toBe(SPEC_SCHEMA_URL) - expect(env.version).toBe(SPEC_VERSION) + expect((env as Record).version).toBeUndefined() expect(typeof env.issuedAt).toBe('string') }) @@ -285,7 +284,7 @@ describe('origin + risk + capabilities', () => { risk: { action: 'WARN', warnings: [ - { code: 'NEW_COUNTERPARTY', severity: 'INFO', message: 'first interaction' }, + { code: 'NEW_COUNTERPARTY', severity: 'low', message: 'first interaction' }, ], }, capabilities: { atomicRequired: true, paymasterService: { url: 'https://pm.example' } }, @@ -308,7 +307,7 @@ describe('serialize / deserialize', () => { }) it('deserialize throws on invalid JSON shape', () => { - expect(() => deserialize('{"version":"0.2","kind":"evm-tx"}')).toThrow(/deserialize:/) + expect(() => deserialize('{"kind":"evm-tx"}')).toThrow(/deserialize:/) }) }) diff --git a/packages/tx-protocol/src/helpers.ts b/packages/tx-protocol/src/helpers.ts index a6b7c9d..df01ca7 100644 --- a/packages/tx-protocol/src/helpers.ts +++ b/packages/tx-protocol/src/helpers.ts @@ -1,4 +1,4 @@ -import { SPEC_SCHEMA_URL, SPEC_VERSION } from './types' +import { SPEC_SCHEMA_URL } from './types' import type { EvmBatchEnvelope, EvmTxContent, @@ -39,7 +39,6 @@ export const createEvmTx = ( envelope: EnvelopeCommon = {}, ): EvmTxEnvelope => ({ $schema: SPEC_SCHEMA_URL, - version: SPEC_VERSION, kind: 'evm-tx', id: envelope.id, issuedAt: envelope.issuedAt ?? rfc3339Now(), @@ -57,7 +56,6 @@ export const createEvmBatch = ( envelope: EnvelopeCommon = {}, ): EvmBatchEnvelope => ({ $schema: SPEC_SCHEMA_URL, - version: SPEC_VERSION, kind: 'evm-batch', id: envelope.id, issuedAt: envelope.issuedAt ?? rfc3339Now(), @@ -75,7 +73,6 @@ export const createSignature = ( envelope: EnvelopeCommon = {}, ): SignatureEnvelope => ({ $schema: SPEC_SCHEMA_URL, - version: SPEC_VERSION, kind: 'signature', id: envelope.id, issuedAt: envelope.issuedAt ?? rfc3339Now(), diff --git a/packages/tx-protocol/src/index.ts b/packages/tx-protocol/src/index.ts index eb9f5b8..64775d1 100644 --- a/packages/tx-protocol/src/index.ts +++ b/packages/tx-protocol/src/index.ts @@ -3,13 +3,11 @@ export { IMPLEMENTED_KINDS, RESERVED_KINDS, SPEC_SCHEMA_URL, - SPEC_VERSION, } from './types' export type { ImplementedKind, Kind, ReservedKind, - SpecVersion, ActionType, BaseEnvelope, Caip2Chain, diff --git a/packages/tx-protocol/src/schema.ts b/packages/tx-protocol/src/schema.ts index 8edf584..6ed0625 100644 --- a/packages/tx-protocol/src/schema.ts +++ b/packages/tx-protocol/src/schema.ts @@ -2,7 +2,6 @@ import { z } from 'zod' import { IMPLEMENTED_KINDS, RESERVED_KINDS, - SPEC_VERSION, } from './types' import type { ActionType, @@ -99,13 +98,13 @@ export const originSchema: z.ZodType = z.object({ export const riskWarningSchema: z.ZodType = z.object({ code: z.string().min(1), - severity: z.enum([ 'INFO', 'WARN', 'CRITICAL' ]), + severity: z.enum([ 'low', 'medium', 'high', 'critical' ]), message: z.string().min(1), }) export const scannerVerdictSchema: z.ZodType = z.object({ provider: z.string().min(1), - verdict: z.string().min(1), + verdict: z.enum([ 'ALLOW', 'WARN', 'BLOCK' ]), url: z.string().optional(), }) @@ -132,7 +131,7 @@ export const capabilitiesSchema = z atomicRequired: z.boolean().optional(), paymasterService: paymasterServiceSchema.optional(), permissions: permissionsSchema.optional(), - requiresAccountType: z.enum([ 'eoa', 'smart-account-7702', 'erc-4337' ]).optional(), + requiresAccountType: z.enum([ 'eoa', 'delegated-eoa', 'erc-4337' ]).optional(), }) .catchall(z.unknown()) satisfies z.ZodType @@ -322,7 +321,6 @@ export const signatureContentSchema = z.object({ const baseEnvelopeFields = { $schema: z.string().url(), - version: z.literal(SPEC_VERSION), id: z.string().max(4096).optional(), issuedAt: rfc3339, expiresAt: rfc3339.optional(), diff --git a/packages/tx-protocol/src/types.ts b/packages/tx-protocol/src/types.ts index 5680d82..bf1d8f2 100644 --- a/packages/tx-protocol/src/types.ts +++ b/packages/tx-protocol/src/types.ts @@ -1,9 +1,11 @@ /* ====================================================================== - * Spec version + * Spec schema URL (version contract) + * + * The $schema URL is the version contract per the ERC. Envelopes do not + * carry a separate `version` field - the URL path identifies the spec + * version that an envelope conforms to. * ==================================================================== */ -export const SPEC_VERSION = '0.1' as const -export type SpecVersion = typeof SPEC_VERSION export const SPEC_SCHEMA_URL = 'https://txkit.dev/schemas/v0.1/envelope.json' as const /* ====================================================================== @@ -54,14 +56,13 @@ export type Producer = { signature?: ProducerSignature } +// Scheme is an open string per the ERC (§3.2). Implementations SHOULD +// support secp256k1, ed25519, and p256; other schemes (including future +// post-quantum algorithms) MAY be added without revising this type. export type SignatureScheme = | 'secp256k1' | 'ed25519' | 'p256' - | 'ml-dsa-44' - | 'ml-dsa-65' - | 'ml-dsa-87' - | 'slh-dsa-sha2-128s' | (string & {}) export type ProducerSignature = { @@ -79,13 +80,13 @@ export type Origin = { export type RiskWarning = { code: string - severity: 'INFO' | 'WARN' | 'CRITICAL' + severity: 'low' | 'medium' | 'high' | 'critical' message: string } export type ScannerVerdict = { provider: string - verdict: string + verdict: 'ALLOW' | 'WARN' | 'BLOCK' url?: string } @@ -107,7 +108,7 @@ export type PaymasterService = { sponsor?: HexAddress } -export type RequiredAccountType = 'eoa' | 'smart-account-7702' | 'erc-4337' +export type RequiredAccountType = 'eoa' | 'delegated-eoa' | 'erc-4337' export type Capabilities = { atomicRequired?: boolean @@ -119,7 +120,6 @@ export type Capabilities = { export type BaseEnvelope = { $schema: string - version: SpecVersion kind: K id?: string issuedAt: string diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ceaebaf..5ccf295 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: version: 8.5.8 postcss-cli: specifier: ^11.0.1 - version: 11.0.1(jiti@2.6.1)(postcss@8.5.8) + version: 11.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0) postcss-import: specifier: ^16.1.1 version: 16.1.1(postcss@8.5.8) @@ -60,7 +60,7 @@ importers: version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^4.1.1 - version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) app/docs: dependencies: @@ -78,7 +78,7 @@ importers: version: 19.2.4(react@19.2.4) vocs: specifier: 1.4.1 - version: 1.4.1(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(typescript@5.9.3) + version: 1.4.1(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(tsx@4.21.0)(typescript@5.9.3) devDependencies: typescript: specifier: ^5.7.3 @@ -91,7 +91,7 @@ importers: version: 0.9.9(prettier@3.8.3)(typescript@5.9.3) '@astrojs/react': specifier: ^5.0.4 - version: 5.0.4(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yaml@2.8.3) + version: 5.0.4(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(yaml@2.8.3) '@astrojs/sitemap': specifier: ^3.7.2 version: 3.7.2 @@ -109,7 +109,7 @@ importers: version: 4.1.17(react@19.2.4)(typescript@5.9.3) astro: specifier: ^6.3.0 - version: 6.3.0(@types/node@25.5.0)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.59.0)(yaml@2.8.3) + version: 6.3.0(@types/node@25.5.0)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.59.0)(tsx@4.21.0)(yaml@2.8.3) motion: specifier: ^12.23.24 version: 12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -174,22 +174,22 @@ importers: version: 15.5.13 '@vitejs/plugin-react': specifier: ^4.3.0 - version: 4.7.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) + version: 4.7.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)) typescript: specifier: ^5.7.3 version: 5.9.3 vite: specifier: ^7.1.13 - version: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + version: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) vite-plugin-node-polyfills: specifier: ^0.26.0 - version: 0.26.0(rollup@4.59.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) + version: 0.26.0(rollup@4.59.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)) packages/core: devDependencies: tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 @@ -211,13 +211,13 @@ importers: version: 22.19.17 tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 vitest: specifier: ^4.1.1 - version: 4.1.1(@types/node@22.19.17)(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.1(@types/node@22.19.17)(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/ows-adapter: dependencies: @@ -227,13 +227,13 @@ importers: devDependencies: tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 vitest: specifier: ^4.1.1 - version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/react: dependencies: @@ -258,7 +258,7 @@ importers: version: 8.5.8 postcss-cli: specifier: ^11.0.1 - version: 11.0.1(jiti@2.6.1)(postcss@8.5.8) + version: 11.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0) react: specifier: ^19.0.0 version: 19.2.4 @@ -267,7 +267,7 @@ importers: version: 19.2.4(react@19.2.4) tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 @@ -282,7 +282,7 @@ importers: devDependencies: tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 @@ -298,13 +298,13 @@ importers: devDependencies: tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 vitest: specifier: ^4.1.1 - version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages/tx-protocol: dependencies: @@ -314,13 +314,19 @@ importers: devDependencies: tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.3 vitest: specifier: ^4.1.1 - version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + zod-to-json-schema: + specifier: ^3.25.2 + version: 3.25.2(zod@3.25.76) packages/x402-adapter: dependencies: @@ -330,13 +336,13 @@ importers: devDependencies: tsup: specifier: ^8.4.0 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) typescript: specifier: ^5.7.3 version: 5.9.3 vitest: specifier: ^4.1.1 - version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + version: 4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) packages: @@ -4309,6 +4315,9 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + get-tsconfig@5.0.0-beta.4: resolution: {integrity: sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ==} engines: {node: '>=20.20.0'} @@ -6448,6 +6457,11 @@ packages: typescript: optional: true + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + tty-browserify@0.0.1: resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} @@ -7122,6 +7136,11 @@ packages: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -7277,17 +7296,17 @@ snapshots: dependencies: prismjs: 1.30.0 - '@astrojs/react@5.0.4(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yaml@2.8.3)': + '@astrojs/react@5.0.4(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(yaml@2.8.3)': dependencies: '@astrojs/internal-helpers': 0.9.0 '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@vitejs/plugin-react': 5.2.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) + '@vitejs/plugin-react': 5.2.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)) devalue: 5.8.0 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) ultrahtml: 1.6.0 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -9664,12 +9683,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.15 '@tailwindcss/oxide-win32-x64-msvc': 4.1.15 - '@tailwindcss/vite@4.1.15(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))': + '@tailwindcss/vite@4.1.15(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.1.15 '@tailwindcss/oxide': 4.1.15 tailwindcss: 4.1.15 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) '@tanstack/query-core@5.90.20': {} @@ -10029,12 +10048,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@vanilla-extract/compiler@0.6.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)': + '@vanilla-extract/compiler@0.6.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)': dependencies: '@vanilla-extract/css': 1.20.0 '@vanilla-extract/integration': 8.0.9 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) - vite-node: 6.0.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) + vite-node: 6.0.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -10116,11 +10135,11 @@ snapshots: dependencies: '@vanilla-extract/css': 1.17.3 - '@vanilla-extract/vite-plugin@5.2.1(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))(yaml@2.8.3)': + '@vanilla-extract/vite-plugin@5.2.1(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: - '@vanilla-extract/compiler': 0.6.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + '@vanilla-extract/compiler': 0.6.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) '@vanilla-extract/integration': 8.0.9 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -10146,7 +10165,7 @@ snapshots: optionalDependencies: react: 19.2.4 - '@vitejs/plugin-react@4.7.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))': + '@vitejs/plugin-react@4.7.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -10154,11 +10173,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@5.2.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))': + '@vitejs/plugin-react@5.2.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -10166,7 +10185,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -10179,21 +10198,29 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.1(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3))': + '@vitest/mocker@4.1.1(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.1 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.1.1(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3))': + '@vitest/mocker@4.1.1(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.1 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + + '@vitest/mocker@4.1.1(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 4.1.1 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) '@vitest/pretty-format@4.1.1': dependencies: @@ -10992,7 +11019,7 @@ snapshots: astring@1.9.0: {} - astro@6.3.0(@types/node@25.5.0)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.59.0)(yaml@2.8.3): + astro@6.3.0(@types/node@25.5.0)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.32.0)(rollup@4.59.0)(tsx@4.21.0)(yaml@2.8.3): dependencies: '@astrojs/compiler': 4.0.0 '@astrojs/internal-helpers': 0.9.0 @@ -11044,8 +11071,8 @@ snapshots: unist-util-visit: 5.1.0 unstorage: 1.17.5(idb-keyval@6.2.2) vfile: 6.0.3 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) - vitefu: 1.1.3(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) + vitefu: 1.1.3(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)) xxhash-wasm: 1.1.0 yargs-parser: 22.0.0 zod: 4.3.6 @@ -12301,6 +12328,10 @@ snapshots: get-stream@6.0.1: {} + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + get-tsconfig@5.0.0-beta.4: dependencies: resolve-pkg-maps: 1.0.0 @@ -14032,14 +14063,14 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-cli@11.0.1(jiti@2.6.1)(postcss@8.5.8): + postcss-cli@11.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0): dependencies: chokidar: 3.6.0 dependency-graph: 1.0.0 fs-extra: 11.3.4 picocolors: 1.1.1 postcss: 8.5.8 - postcss-load-config: 5.1.0(jiti@2.6.1)(postcss@8.5.8) + postcss-load-config: 5.1.0(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0) postcss-reporter: 7.1.0(postcss@8.5.8) pretty-hrtime: 1.0.3 read-cache: 1.0.0 @@ -14057,20 +14088,22 @@ snapshots: read-cache: 1.0.0 resolve: 1.22.11 - postcss-load-config@5.1.0(jiti@2.6.1)(postcss@8.5.8): + postcss-load-config@5.1.0(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0): dependencies: lilconfig: 3.1.3 yaml: 2.8.3 optionalDependencies: jiti: 2.6.1 postcss: 8.5.8 + tsx: 4.21.0 - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.3): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 postcss: 8.5.8 + tsx: 4.21.0 yaml: 2.8.3 postcss-reporter@7.1.0(postcss@8.5.8): @@ -15073,7 +15106,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3): + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.4) cac: 6.7.14 @@ -15084,7 +15117,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.3) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 @@ -15101,6 +15134,13 @@ snapshots: - tsx - yaml + tsx@4.21.0: + dependencies: + esbuild: 0.27.4 + get-tsconfig: 4.14.0 + optionalDependencies: + fsevents: 2.3.3 + tty-browserify@0.0.1: {} turbo@2.9.6: @@ -15415,13 +15455,13 @@ snapshots: - utf-8-validate - zod - vite-node@6.0.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3): + vite-node@6.0.0(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: cac: 7.0.0 es-module-lexer: 2.0.0 obug: 2.1.1 pathe: 2.0.3 - vite: 8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -15436,15 +15476,15 @@ snapshots: - tsx - yaml - vite-plugin-node-polyfills@0.26.0(rollup@4.59.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)): + vite-plugin-node-polyfills@0.26.0(rollup@4.59.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@rollup/plugin-inject': 5.0.5(rollup@4.59.0) node-stdlib-browser: 1.3.1 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - rollup - vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3): + vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3): dependencies: esbuild: 0.27.4 fdir: 6.5.0(picomatch@4.0.4) @@ -15457,9 +15497,10 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.32.0 + tsx: 4.21.0 yaml: 2.8.3 - vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3): + vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -15471,9 +15512,25 @@ snapshots: esbuild: 0.28.0 fsevents: 2.3.3 jiti: 2.6.1 + tsx: 4.21.0 + yaml: 2.8.3 + + vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.15 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.5.0 + esbuild: 0.27.4 + fsevents: 2.3.3 + jiti: 2.6.1 + tsx: 4.21.0 yaml: 2.8.3 - vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3): + vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -15485,16 +15542,17 @@ snapshots: esbuild: 0.28.0 fsevents: 2.3.3 jiti: 2.6.1 + tsx: 4.21.0 yaml: 2.8.3 - vitefu@1.1.3(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)): + vitefu@1.1.3(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)): optionalDependencies: - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) - vitest@4.1.1(@types/node@22.19.17)(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)): + vitest@4.1.1(@types/node@22.19.17)(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.1 - '@vitest/mocker': 4.1.1(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + '@vitest/mocker': 4.1.1(vite@8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/pretty-format': 4.1.1 '@vitest/runner': 4.1.1 '@vitest/snapshot': 4.1.1 @@ -15511,17 +15569,44 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.8(@types/node@22.19.17)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.17 transitivePeerDependencies: - msw - vitest@4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)): + vitest@4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.1 + '@vitest/mocker': 4.1.1(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.1 + '@vitest/runner': 4.1.1 + '@vitest/snapshot': 4.1.1 + '@vitest/spy': 4.1.1 + '@vitest/utils': 4.1.1 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.5.0 + transitivePeerDependencies: + - msw + + vitest@4.1.1(@types/node@25.5.0)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.1 - '@vitest/mocker': 4.1.1(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3)) + '@vitest/mocker': 4.1.1(vite@8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/pretty-format': 4.1.1 '@vitest/runner': 4.1.1 '@vitest/snapshot': 4.1.1 @@ -15538,7 +15623,7 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(yaml@2.8.3) + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.5.0 @@ -15547,7 +15632,7 @@ snapshots: vm-browserify@1.1.2: {} - vocs@1.4.1(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(typescript@5.9.3): + vocs@1.4.1(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.59.0)(tsx@4.21.0)(typescript@5.9.3): dependencies: '@floating-ui/react': 0.27.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@hono/node-server': 1.19.14(hono@4.12.12) @@ -15566,11 +15651,11 @@ snapshots: '@shikijs/rehype': 1.29.2 '@shikijs/transformers': 1.29.2 '@shikijs/twoslash': 1.29.2(typescript@5.9.3) - '@tailwindcss/vite': 4.1.15(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) + '@tailwindcss/vite': 4.1.15(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)) '@vanilla-extract/css': 1.20.0 '@vanilla-extract/dynamic': 2.1.5 - '@vanilla-extract/vite-plugin': 5.2.1(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3))(yaml@2.8.3) - '@vitejs/plugin-react': 5.2.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3)) + '@vanilla-extract/vite-plugin': 5.2.1(@types/node@25.5.0)(esbuild@0.28.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + '@vitejs/plugin-react': 5.2.0(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3)) autoprefixer: 10.4.27(postcss@8.5.8) cac: 6.7.14 chroma-js: 3.2.0 @@ -15620,7 +15705,7 @@ snapshots: unified: 11.0.5 unist-util-visit: 5.1.0 vfile-matter: 5.0.1 - vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(yaml@2.8.3) + vite: 7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)(yaml@2.8.3) yaml: 2.8.3 transitivePeerDependencies: - '@remix-run/react' @@ -15923,6 +16008,10 @@ snapshots: yocto-queue@1.2.2: {} + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod-validation-error@4.0.2(zod@4.3.6): dependencies: zod: 4.3.6