diff --git a/typescript/.changeset/loose-seals-walk.md b/typescript/.changeset/loose-seals-walk.md new file mode 100644 index 000000000..0e148d97c --- /dev/null +++ b/typescript/.changeset/loose-seals-walk.md @@ -0,0 +1,5 @@ +--- +"@coinbase/agentkit": patch +--- + +Added a new action provider to interact with Enso API diff --git a/typescript/agentkit/README.md b/typescript/agentkit/README.md index eb4570c2b..c777a6042 100644 --- a/typescript/agentkit/README.md +++ b/typescript/agentkit/README.md @@ -313,6 +313,15 @@ const agent = createReactAgent({ +Enso + + + route + Find and execute a route for entering or exiting any DeFi position or swapping any ERC20 tokens. + + + + ERC20 diff --git a/typescript/agentkit/package.json b/typescript/agentkit/package.json index 537907c06..abbb4e366 100644 --- a/typescript/agentkit/package.json +++ b/typescript/agentkit/package.json @@ -64,6 +64,7 @@ "md5": "^2.3.0", "opensea-js": "^7.1.18", "reflect-metadata": "^0.2.2", + "@ensofinance/sdk": "^2.0.6", "twitter-api-v2": "^1.18.2", "viem": "^2.22.16", "x402": "^0.6.0", diff --git a/typescript/agentkit/src/action-providers/enso/README.md b/typescript/agentkit/src/action-providers/enso/README.md new file mode 100644 index 000000000..0629e9705 --- /dev/null +++ b/typescript/agentkit/src/action-providers/enso/README.md @@ -0,0 +1,74 @@ +# Enso Action Provider + +This directory contains the **EnsoActionProvider** implementation, which provides actions to interact with the **Enso** API for executing complex DeFi routes and token swaps across multiple blockchain networks. + +## Directory Structure + +``` +enso/ +├── ensoActionProvider.ts # Main provider with Enso routing functionality +├── ensoActionProvider.test.ts # Test file for Enso provider +├── constants.ts # Constants for Enso provider +├── schemas.ts # Enso action schemas +├── index.ts # Main exports +└── README.md # This file +``` + +## Actions + +- `route`: Finds the optimal route for entering or exiting any DeFi position or swap between any ERC20 tokens efficiently. + +## Parameters + +### Route Action Parameters + +- `tokenIn`: Address of the token to swap from (for ETH, use `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) +- `tokenOut`: Address of the token to swap to (for ETH, use `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`) +- `amountIn`: Amount of tokenIn to swap in whole units (e.g., "100 USDC") +- `slippage`: Optional slippage tolerance in basis points (1/10000). Default is 50 (0.5%) + +## Network Support + +The Enso provider supports the following networks: + +- **Ethereum**: Chain ID 1 +- **Optimism**: Chain ID 10 +- **BNB Chain**: Chain ID 56 +- **Gnosis Chain**: Chain ID 100 +- **Unichain**: Chain ID 130 +- **Polygon**: Chain ID 137 +- **Sonic**: Chain ID 146 +- **World Chain**: Chain ID 480 +- **HyperEVM**: Chain ID 999 +- **Soneium**: Chain ID 1868 +- **Base**: Chain ID 8453 +- **Arbitrum**: Chain ID 42161 +- **Avalanche**: Chain ID 43114 +- **Ink**: Chain ID 57073 +- **Linea**: Chain ID 59144 +- **Berachain**: Chain ID 80094 +- **Plume**: Chain ID 98866 +- **Katana**: Chain ID 747474 + +## Adding New Actions + +To add new Enso actions: + +1. Define your action schema in `schemas.ts` +2. Implement the action in `ensoActionProvider.ts` +3. Add tests in `ensoActionProvider.test.ts` + +## Configuration + +The Enso provider uses a default API key for demonstration purposes. For production use, you can provide your own API key: + +```typescript +const ensoProvider = new EnsoActionProvider({ + apiKey: "your-enso-api-key" +}); +``` + +## Notes + +For more information on **Enso**, visit [Enso Documentation](https://docs.enso.finance/). + diff --git a/typescript/agentkit/src/action-providers/enso/constants.ts b/typescript/agentkit/src/action-providers/enso/constants.ts new file mode 100644 index 000000000..8cceda13c --- /dev/null +++ b/typescript/agentkit/src/action-providers/enso/constants.ts @@ -0,0 +1,8 @@ +export const ENSO_API_KEY = "1e02632d-6feb-4a75-a157-documentation" as const; +export const ENSO_ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" as const; +export const ENSO_ROUTE_SINGLE_SIG = "0xb94c3609" as const; + +export const ENSO_SUPPORTED_NETWORKS = new Set([ + 1, 10, 56, 100, 130, 137, 146, 480, 999, 1868, 8453, 42161, 43114, 57073, 59144, 80094, 98866, + 747474, +]); diff --git a/typescript/agentkit/src/action-providers/enso/ensoActionProvider.test.ts b/typescript/agentkit/src/action-providers/enso/ensoActionProvider.test.ts new file mode 100644 index 000000000..24858963f --- /dev/null +++ b/typescript/agentkit/src/action-providers/enso/ensoActionProvider.test.ts @@ -0,0 +1,172 @@ +import { getAddress } from "viem"; +import { EvmWalletProvider } from "../../wallet-providers"; +import { ensoActionProvider } from "./ensoActionProvider"; +import { EnsoRouteSchema } from "./schemas"; + +const MOCK_ADDRESS = "0x1234567890123456789012345678901234543210"; +const ENSO_ROUTER_BASE = "0xF75584eF6673aD213a685a1B58Cc0330B8eA22Cf"; + +const WETH = "0x4200000000000000000000000000000000000006"; +const USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; + +const mockGetTokenData = jest.fn(); +const mockGetRouteData = jest.fn(); +const mockGetApprovalData = jest.fn(); + +jest.mock("@ensofinance/sdk", () => { + return { + EnsoClient: jest.fn().mockImplementation(() => { + return { + getTokenData: mockGetTokenData, + getRouteData: mockGetRouteData, + getApprovalData: mockGetApprovalData, + }; + }), + }; +}); + +describe("Enso Route Schema", () => { + it("should successfully parse valid input", () => { + const validInput = { + tokenIn: USDC, + tokenOut: WETH, + amountIn: "100", + slippage: 50, + }; + + const result = EnsoRouteSchema.safeParse(validInput); + + expect(result.success).toBe(true); + expect(result.data).toEqual(validInput); + }); + + it("should fail parsing empty input", () => { + const emptyInput = {}; + const result = EnsoRouteSchema.safeParse(emptyInput); + + expect(result.success).toBe(false); + }); +}); + +describe("Enso Route Action", () => { + let mockWallet: jest.Mocked; + const actionProvider = ensoActionProvider(); + const args = { + tokenIn: USDC, + tokenOut: WETH, + amountIn: "100", + }; + + beforeEach(async () => { + jest.clearAllMocks(); + // Set up default mock responses for EnsoClient methods for successful scenarios + mockGetTokenData.mockResolvedValue({ + data: [ + { + address: USDC, + decimals: 6, + symbol: "USDC", + }, + ], + }); + mockGetRouteData.mockResolvedValue({ + tx: { + to: ENSO_ROUTER_BASE, + value: "0", + data: "0xb94c3609000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf0000000000000000000000000000000000000000000000000000000005f5e100", + }, + }); + mockGetApprovalData.mockResolvedValue({ + tx: { + to: USDC, + data: "0x095ea7b3000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf0000000000000000000000000000000000000000000000000000000005f5e100", + }, + }); + + mockWallet = { + getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS), + sendTransaction: jest.fn(), + waitForTransactionReceipt: jest.fn(), + getNetwork: jest.fn().mockReturnValue({ chainId: "8453" }), + } as unknown as jest.Mocked; + }); + + it("should successfully respond", async () => { + const hash = "0x1234567890123456789012345678901234567890"; + mockWallet.sendTransaction.mockResolvedValue(hash); + + const response = await actionProvider.route(mockWallet, args); + + // First transaction should be the approval + expect(mockWallet.sendTransaction).toHaveBeenNthCalledWith( + 1, // First call + expect.objectContaining({ + to: getAddress(args.tokenIn), + }), + ); + + // Second transaction should be the route execution + expect(mockWallet.sendTransaction).toHaveBeenNthCalledWith( + 2, // Second call + expect.objectContaining({ + to: ENSO_ROUTER_BASE, + value: BigInt(0), + }), + ); + + expect(response).toContain(`Route executed successfully, transaction hash: ${hash}`); + }); + + it("should fail with an error", async () => { + const error = new Error("Failed to route through Enso"); + mockWallet.sendTransaction.mockRejectedValue(error); + + const response = await actionProvider.route(mockWallet, args); + + // First transaction should be the approval + expect(mockWallet.sendTransaction).toHaveBeenNthCalledWith( + 1, // First call + expect.objectContaining({ + to: getAddress(args.tokenIn), + }), + ); + + expect(response).toContain(`Error routing token through Enso: ${error}`); + }); +}); + +describe("supportsNetwork", () => { + const actionProvider = ensoActionProvider(); + + it("should return false for base-mainnet (supported only with chainId)", () => { + const result = actionProvider.supportsNetwork({ + protocolFamily: "evm", + networkId: "base-mainnet", + }); + expect(result).toBe(false); + }); + + it("should return true for 8453 (base)", () => { + const result = actionProvider.supportsNetwork({ + protocolFamily: "evm", + chainId: "8453", + }); + expect(result).toBe(true); + }); + + it("should return false for base-sepolia", () => { + const result = actionProvider.supportsNetwork({ + protocolFamily: "evm", + networkId: "base-sepolia", + }); + expect(result).toBe(false); + }); + + it("should return true for 1 (mainnet)", () => { + const result = actionProvider.supportsNetwork({ + protocolFamily: "evm", + chainId: "1", + }); + expect(result).toBe(true); + }); +}); diff --git a/typescript/agentkit/src/action-providers/enso/ensoActionProvider.ts b/typescript/agentkit/src/action-providers/enso/ensoActionProvider.ts new file mode 100644 index 000000000..43f74c53e --- /dev/null +++ b/typescript/agentkit/src/action-providers/enso/ensoActionProvider.ts @@ -0,0 +1,131 @@ +import { z } from "zod"; +import { ActionProvider } from "../actionProvider"; +import { Network } from "../../network"; +import { CreateAction } from "../actionDecorator"; +import { EnsoActionProviderParams, EnsoRouteSchema } from "./schemas"; +import { getAddress, Hex, parseUnits } from "viem"; +import { EvmWalletProvider } from "../../wallet-providers"; +import { + ENSO_API_KEY, + ENSO_ETH, + ENSO_ROUTE_SINGLE_SIG, + ENSO_SUPPORTED_NETWORKS, +} from "./constants"; +import { EnsoClient, RouteParams } from "@ensofinance/sdk"; + +/** + * EnsoActionProvider is an action provider for Enso. + */ +export class EnsoActionProvider extends ActionProvider { + readonly ensoClient: EnsoClient; + /** + * Constructor for the EnsoActionProvider + * + * @param params - The initialization parameters for the Enso action provider + */ + constructor(params: EnsoActionProviderParams = {}) { + super("enso", []); + this.ensoClient = new EnsoClient({ apiKey: params.apiKey || ENSO_API_KEY }); + } + + /** + * Finds the optimal route from a token to a token and executes it. + * + * @param walletProvider - The wallet to execute the transaction from. + * @param args - The input arguments for the action. + * @returns A message containing the token route details. + */ + @CreateAction({ + name: "route", + description: `This tool will find the optimal route for entering or exiting any DeFi position or swapping any ERC20 tokens.`, + schema: EnsoRouteSchema, + }) + async route( + walletProvider: EvmWalletProvider, + args: z.infer, + ): Promise { + try { + const chainId = Number(walletProvider.getNetwork().chainId); + if (!chainId || !ENSO_SUPPORTED_NETWORKS.has(chainId)) { + return `Network ${chainId} is not supported by Enso`; + } + + const fromAddress = getAddress(walletProvider.getAddress()); + const tokenIn = getAddress(args.tokenIn); + const tokenOut = getAddress(args.tokenOut); + + const tokenInResponse = await this.ensoClient.getTokenData({ + address: tokenIn, + chainId, + }); + + if (tokenInResponse.data.length !== 1) { + throw `Could not find data for provided tokenIn`; + } + + const tokenInData = tokenInResponse.data[0]; + const amountIn = parseUnits(args.amountIn, tokenInData.decimals).toString(); + + const params: RouteParams = { + chainId, + tokenIn: [tokenIn], + tokenOut: [tokenOut], + amountIn: [amountIn], + routingStrategy: "router", + fromAddress, + receiver: fromAddress, + spender: fromAddress, + }; + + if (args.slippage) { + params.slippage = args.slippage; + } + + const routeData = await this.ensoClient.getRouteData(params); + + if (!routeData.tx.data.startsWith(ENSO_ROUTE_SINGLE_SIG)) { + return `Unsupported calldata returned from Enso API`; + } + + // If the tokenIn is ERC20, do approve + if (args.tokenIn.toLowerCase() !== ENSO_ETH.toLowerCase()) { + const approval = await this.ensoClient.getApprovalData({ + chainId, + amount: amountIn, + fromAddress, + tokenAddress: getAddress(args.tokenIn), + }); + + const hash = await walletProvider.sendTransaction({ + to: approval.tx.to, + data: approval.tx.data as Hex, + }); + await walletProvider.waitForTransactionReceipt(hash); + } + + const hash = await walletProvider.sendTransaction({ + to: routeData.tx.to, + value: BigInt(routeData.tx.value), + data: routeData.tx.data as Hex, + }); + await walletProvider.waitForTransactionReceipt(hash); + + return `Route executed successfully, transaction hash: ${hash}`; + } catch (error) { + return `Error routing token through Enso: ${error}`; + } + } + + /** + * Checks if the Enso action provider supports the given network. + * + * @param network - The network to check. + * @returns True if the Enso action provider supports the network, false otherwise. + */ + supportsNetwork = (network: Network) => { + const chainIdCheck = network.chainId && ENSO_SUPPORTED_NETWORKS.has(Number(network.chainId)); + return Boolean(chainIdCheck); + }; +} + +export const ensoActionProvider = () => new EnsoActionProvider(); diff --git a/typescript/agentkit/src/action-providers/enso/index.ts b/typescript/agentkit/src/action-providers/enso/index.ts new file mode 100644 index 000000000..d414789cd --- /dev/null +++ b/typescript/agentkit/src/action-providers/enso/index.ts @@ -0,0 +1 @@ +export * from "./ensoActionProvider"; diff --git a/typescript/agentkit/src/action-providers/enso/schemas.ts b/typescript/agentkit/src/action-providers/enso/schemas.ts new file mode 100644 index 000000000..1d67e5efc --- /dev/null +++ b/typescript/agentkit/src/action-providers/enso/schemas.ts @@ -0,0 +1,28 @@ +import { z } from "zod"; + +export interface EnsoActionProviderParams { + apiKey?: string; +} + +/** + * Input schema for route action. + */ +export const EnsoRouteSchema = z + .object({ + tokenIn: z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") + .describe( + "Address of the token to swap from. For ETH, use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + ), + tokenOut: z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") + .describe( + "Address of the token to swap to, For ETH, use 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + ), + amountIn: z.string().describe("Amount of tokenIn to swap in whole units (e.g. 100 USDC)"), + slippage: z.number().optional().describe("Slippage in basis points (1/10000). Default - 50"), + }) + .strip() + .describe("Instructions for routing through Enso API"); diff --git a/typescript/agentkit/src/action-providers/index.ts b/typescript/agentkit/src/action-providers/index.ts index b8d6977c5..3710f5f9e 100644 --- a/typescript/agentkit/src/action-providers/index.ts +++ b/typescript/agentkit/src/action-providers/index.ts @@ -11,6 +11,7 @@ export * from "./cdp-legacy"; export * from "./cdp"; export * from "./compound"; export * from "./defillama"; +export * from "./enso"; export * from "./erc20"; export * from "./erc721"; export * from "./farcaster"; diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index 8972eac54..402227b86 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: '@coinbase/x402': specifier: ^0.6.3 version: 0.6.4(@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@ensofinance/sdk': + specifier: ^2.0.6 + version: 2.0.6 '@jup-ag/api': specifier: ^6.0.39 version: 6.0.40 @@ -118,7 +121,7 @@ importers: version: 2.1.0 clanker-sdk: specifier: ^4.1.18 - version: 4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)) + version: 4.1.19(@types/node@22.13.14)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)) decimal.js: specifier: ^10.5.0 version: 10.5.0 @@ -176,7 +179,7 @@ importers: version: 14.1.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)) + version: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) mock-fs: specifier: ^5.2.0 version: 5.5.0 @@ -194,7 +197,7 @@ importers: version: 2.4.2 ts-jest: specifier: ^29.2.5 - version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2) tsd: specifier: ^0.31.2 version: 0.31.2 @@ -972,6 +975,9 @@ packages: peerDependencies: '@noble/ciphers': ^1.0.0 + '@ensofinance/sdk@2.0.6': + resolution: {integrity: sha512-IRYW9NcV3YLcbVXZ/TaEoSwIV+309Rrpvh/P88uKaRhloYV+ZRySAoRvCWP+9ANqiVfEbuxdkIJBVxUmFFSRxA==} + '@es-joy/jsdoccomment@0.46.0': resolution: {integrity: sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==} engines: {node: '>=16'} @@ -6880,6 +6886,12 @@ snapshots: dependencies: '@noble/ciphers': 1.3.0 + '@ensofinance/sdk@2.0.6': + dependencies: + axios: 1.12.2 + transitivePeerDependencies: + - debug + '@es-joy/jsdoccomment@0.46.0': dependencies: comment-parser: 1.4.1 @@ -7293,12 +7305,12 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@inquirer/external-editor@1.0.1(@types/node@20.17.27)': + '@inquirer/external-editor@1.0.1(@types/node@22.13.14)': dependencies: chardet: 2.1.0 iconv-lite: 0.6.3 optionalDependencies: - '@types/node': 20.17.27 + '@types/node': 22.13.14 '@istanbuljs/load-nyc-config@1.1.0': dependencies: @@ -7354,6 +7366,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.27 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -10402,12 +10449,12 @@ snapshots: cjs-module-lexer@1.4.3: {} - clanker-sdk@4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)): + clanker-sdk@4.1.19(@types/node@22.13.14)(typescript@5.8.2)(viem@2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)): dependencies: '@openzeppelin/merkle-tree': 1.0.8 abitype: 1.0.8(typescript@5.8.2)(zod@3.25.56) dotenv: 16.4.7 - inquirer: 8.2.7(@types/node@20.17.27) + inquirer: 8.2.7(@types/node@22.13.14) viem: 2.23.15(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) zod: 3.25.56 transitivePeerDependencies: @@ -10525,6 +10572,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-fetch@3.2.0: @@ -11636,9 +11698,9 @@ snapshots: inherits@2.0.4: {} - inquirer@8.2.7(@types/node@20.17.27): + inquirer@8.2.7(@types/node@22.13.14): dependencies: - '@inquirer/external-editor': 1.0.1(@types/node@20.17.27) + '@inquirer/external-editor': 1.0.1(@types/node@22.13.14) ansi-escapes: 4.3.2 chalk: 4.1.2 cli-cursor: 3.1.0 @@ -11959,6 +12021,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)): dependencies: '@babel/core': 7.26.10 @@ -11990,6 +12071,68 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.27 + ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.13.14 + ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -12217,6 +12360,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jose@4.15.9: {} jose@5.10.0: {} @@ -13767,6 +13922,26 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) + ts-jest@29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.1 + type-fest: 4.38.0 + typescript: 5.8.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.26.10 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + ts-node@10.9.2(@types/node@18.19.83)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1
route