diff --git a/typescript/.changeset/big-ads-swim.md b/typescript/.changeset/big-ads-swim.md new file mode 100644 index 000000000..f32d2ebaf --- /dev/null +++ b/typescript/.changeset/big-ads-swim.md @@ -0,0 +1,5 @@ +--- +"@coinbase/agentkit": minor +--- + +Added a new action provider to interact with Noves Intents diff --git a/typescript/agentkit/package.json b/typescript/agentkit/package.json index f8107edc4..a77f5fda6 100644 --- a/typescript/agentkit/package.json +++ b/typescript/agentkit/package.json @@ -44,6 +44,7 @@ "@coinbase/cdp-sdk": "^1.3.0", "@coinbase/coinbase-sdk": "^0.20.0", "@jup-ag/api": "^6.0.39", + "@noves/intent-ethers-provider": "^0.1.3", "@privy-io/public-api": "2.18.5", "@privy-io/server-auth": "1.18.4", "@solana/spl-token": "^0.4.12", diff --git a/typescript/agentkit/src/action-providers/noves/README.md b/typescript/agentkit/src/action-providers/noves/README.md new file mode 100644 index 000000000..292fe1674 --- /dev/null +++ b/typescript/agentkit/src/action-providers/noves/README.md @@ -0,0 +1,40 @@ +# Noves Action Provider + +This directory contains the **NovesActionProvider** implementation, which provides actions to interact with **Noves Intents** for retrieving token prices, transaction descriptions, and recent transactions. + +## Directory Structure + +``` +noves/ +├── novesActionProvider.ts # Main provider with Noves Intents functionality +├── novesActionProvider.test.ts # Test file for Noves provider +├── schemas.ts # Noves action schemas +├── index.ts # Main exports +└── README.md # This file +``` + +## Actions + +- `getTranslatedTransaction`: Get a human-readable description of a transaction for specified transaction hash and network + +- `getRecentTransactions`: Get a list of recent transactions on a given chain for a given wallet, with a human-readable description + +- `getTokenCurrentPrice`: Get the price of a token at the given timestamp, or the current price if no timestamp is provided + +## Adding New Actions + +To add new Alchemy actions: + +1. Define your action schema in `schemas.ts` +2. Implement the action in `novesActionProvider.ts` +3. Add tests in `novesActionProvider.test.ts` + +## Network Support + +Noves Intents support 100+ blockchain networks. For more information, visit [Noves](https://www.noves.fi/). + +## Notes + +- Rate limits applied + +For more information on the **Noves API**, visit [Noves API Documentation](https://docs.noves.fi/reference/api-overview). diff --git a/typescript/agentkit/src/action-providers/noves/index.ts b/typescript/agentkit/src/action-providers/noves/index.ts new file mode 100644 index 000000000..8e2589ffc --- /dev/null +++ b/typescript/agentkit/src/action-providers/noves/index.ts @@ -0,0 +1,2 @@ +export * from "./novesActionProvider"; +export * from "./schemas"; diff --git a/typescript/agentkit/src/action-providers/noves/novesActionProvider.test.ts b/typescript/agentkit/src/action-providers/noves/novesActionProvider.test.ts new file mode 100644 index 000000000..ad634f96b --- /dev/null +++ b/typescript/agentkit/src/action-providers/noves/novesActionProvider.test.ts @@ -0,0 +1,200 @@ +import { NovesActionProvider } from "./novesActionProvider"; + +const mockGetRecentTxs = jest.fn(); +const mockGetTranslatedTx = jest.fn(); +const mockGetTokenPrice = jest.fn(); + +jest.mock("@noves/intent-ethers-provider", () => { + return { + IntentProvider: jest.fn().mockImplementation(() => ({ + getRecentTxs: mockGetRecentTxs, + getTranslatedTx: mockGetTranslatedTx, + getTokenPrice: mockGetTokenPrice, + })), + }; +}); + +describe("NovesActionProvider", () => { + let actionProvider: NovesActionProvider; + + /** + * Set up test environment before each test. + * Initializes mocks and creates fresh instances of required objects. + */ + beforeEach(() => { + jest.clearAllMocks(); + actionProvider = new NovesActionProvider(); + }); + + describe("supportsNetwork", () => { + /** + * Test that the provider correctly supports all networks + */ + it("should return true for all networks", () => { + expect(actionProvider.supportsNetwork()).toBe(true); + }); + }); + + describe("getRecentTransactions", () => { + const recentTxsArgs = { + chain: "base", + wallet: "0x2748f93c54042bfbe8691cdf3bd19adb12f7cfa0e30ea38128c5ed606b7a7f44", + }; + + const mockRecentTxs = [ + { + txTypeVersion: 2, + chain: "base", + accountAddress: "0x2748f93c54042bfbe8691cdf3bd19adb12f7cfa0e30ea38128c5ed606b7a7f44", + classificationData: { + type: "transfer", + source: { type: "inference" }, + description: "Transferred 1 ETH", + protocol: { name: null }, + sent: [], + received: [], + }, + rawTransactionData: { + transactionHash: "0x1234567890abcdef", + fromAddress: "0x2748f93c54042bfbe8691cdf3bd19adb12f7cfa0e30ea38128c5ed606b7a7f44", + toAddress: "0x9876543210abcdef", + blockNumber: 26586523, + gas: 5000000, + gasUsed: 377942, + gasPrice: 1826005, + transactionFee: { + amount: "0.000000693359358418", + token: { symbol: "ETH", name: "ETH", decimals: 18, address: "ETH" }, + }, + timestamp: 1739962393, + }, + }, + ]; + + it("should get recent transactions successfully", async () => { + mockGetRecentTxs.mockResolvedValue(mockRecentTxs); + const result = await actionProvider.getRecentTransactions(recentTxsArgs); + + expect(mockGetRecentTxs).toHaveBeenCalledWith(recentTxsArgs.chain, recentTxsArgs.wallet); + expect(result).toEqual(JSON.stringify(mockRecentTxs, null, 2)); + }); + + it("should handle errors when getting recent transactions", async () => { + const error = new Error("Failed to fetch recent transactions"); + mockGetRecentTxs.mockRejectedValue(error); + + const result = await actionProvider.getRecentTransactions(recentTxsArgs); + expect(result).toEqual(`Error getting recent transactions: ${error}`); + }); + }); + + describe("getTokenCurrentPrice", () => { + const tokenPriceArgs = { + chain: "base", + token_address: "0x1234567890abcdef", + }; + + const mockTokenPrice = { + price: "1800.50", + token: { + symbol: "ETH", + name: "Ethereum", + decimals: 18, + address: "0x1234567890abcdef", + }, + timestamp: 1739962393, + }; + + it("should get token price successfully", async () => { + mockGetTokenPrice.mockResolvedValue(mockTokenPrice); + const result = await actionProvider.getTokenCurrentPrice(tokenPriceArgs); + + expect(mockGetTokenPrice).toHaveBeenCalledWith({ + chain: tokenPriceArgs.chain, + token_address: tokenPriceArgs.token_address, + }); + expect(result).toEqual(JSON.stringify(mockTokenPrice, null, 2)); + }); + + it("should handle errors when getting token price", async () => { + const error = new Error("Failed to fetch token price"); + mockGetTokenPrice.mockRejectedValue(error); + + const result = await actionProvider.getTokenCurrentPrice(tokenPriceArgs); + expect(result).toEqual(`Error getting token price: ${error}`); + }); + }); + + describe("getTranslatedTransaction", () => { + const translatedTxArgs = { + chain: "base", + tx: "0x2748f93c54042bfbe8691cdf3bd19adb12f7cfa0e30ea38128c5ed606b7a7f44", + }; + + const mockTranslatedTx = { + txTypeVersion: 2, + chain: "base", + accountAddress: "0xed4B16e8c43AD2f6e08e6E9Bf1b8848644A8C6F6", + classificationData: { + type: "stakeNFT", + source: { type: "inference" }, + description: "Staked Slipstream Position NFT v1 #7595063.", + protocol: { name: null }, + sent: [ + { + action: "staked", + amount: "1", + nft: { + name: "Slipstream Position NFT v1", + id: "7595063", + symbol: "AERO-CL-POS", + address: "0x827922686190790b37229fd06084350E74485b72", + }, + from: { name: "This wallet", address: "0xed4B16e8c43AD2f6e08e6E9Bf1b8848644A8C6F6" }, + to: { name: null, address: "0x282ece21a112950f62EC4493E2Bd2b27a74c7937" }, + }, + { + action: "paidGas", + from: { name: "This wallet", address: "0xed4B16e8c43AD2f6e08e6E9Bf1b8848644A8C6F6" }, + to: { name: null, address: null }, + amount: "0.000000693359358418", + token: { symbol: "ETH", name: "ETH", decimals: 18, address: "ETH" }, + }, + ], + received: [], + }, + rawTransactionData: { + transactionHash: "0x2748f93c54042bfbe8691cdf3bd19adb12f7cfa0e30ea38128c5ed606b7a7f44", + fromAddress: "0xed4B16e8c43AD2f6e08e6E9Bf1b8848644A8C6F6", + toAddress: "0x282ece21a112950f62EC4493E2Bd2b27a74c7937", + blockNumber: 26586523, + gas: 5000000, + gasUsed: 377942, + gasPrice: 1826005, + l1Gas: 1600, + l1GasPrice: 726849409, + transactionFee: { + amount: "0.000000693359358418", + token: { symbol: "ETH", name: "ETH", decimals: 18, address: "ETH" }, + }, + timestamp: 1739962393, + }, + }; + + it("should get translated transaction successfully", async () => { + mockGetTranslatedTx.mockResolvedValue(mockTranslatedTx); + const result = await actionProvider.getTranslatedTransaction(translatedTxArgs); + + expect(mockGetTranslatedTx).toHaveBeenCalledWith(translatedTxArgs.chain, translatedTxArgs.tx); + expect(result).toEqual(JSON.stringify(mockTranslatedTx, null, 2)); + }); + + it("should handle errors when getting translated transaction", async () => { + const error = new Error("Failed to fetch translated transaction"); + mockGetTranslatedTx.mockRejectedValue(error); + + const result = await actionProvider.getTranslatedTransaction(translatedTxArgs); + expect(result).toEqual(`Error getting translated transaction: ${error}`); + }); + }); +}); diff --git a/typescript/agentkit/src/action-providers/noves/novesActionProvider.ts b/typescript/agentkit/src/action-providers/noves/novesActionProvider.ts new file mode 100644 index 000000000..0d463dc94 --- /dev/null +++ b/typescript/agentkit/src/action-providers/noves/novesActionProvider.ts @@ -0,0 +1,108 @@ +import { z } from "zod"; +import { ActionProvider } from "../actionProvider"; +import { CreateAction } from "../actionDecorator"; +import { + NovesTranslatedTxSchema, + NovesRecentTxsSchema, + NovesTokenCurrentPriceSchema, +} from "./schemas"; +import { IntentProvider } from "@noves/intent-ethers-provider"; + +/** + * NovesActionProvider is an action provider for fetching transaction descriptions, recent transactions, and token prices via Noves Intents. + */ +export class NovesActionProvider extends ActionProvider { + private intentProvider: IntentProvider; + + /** + * Creates a new instance of NovesActionProvider + */ + constructor() { + super("noves", []); + this.intentProvider = new IntentProvider(); + } + + /** + * Get a human-readable description of a transaction + * + * @param args - The arguments containing the transaction hash and the chain. + * @returns A JSON string with the transaction description or an error message. + */ + @CreateAction({ + name: "getTranslatedTransaction", + description: + "This tool will fetch a human-readable description of a transaction on a given chain", + schema: NovesTranslatedTxSchema, + }) + async getTranslatedTransaction(args: z.infer): Promise { + try { + const tx = await this.intentProvider.getTranslatedTx(args.chain, args.tx); + return JSON.stringify(tx, null, 2); + } catch (error) { + return `Error getting translated transaction: ${error}`; + } + } + + /** + * Get a list of recent transactions + * + * @param args - The arguments containing the chain and wallet address. + * @returns A JSON string with the list of recent transactions or an error message. + */ + @CreateAction({ + name: "getRecentTransactions", + description: + "This tool will fetch a list of recent transactions for a given wallet on a given chain", + schema: NovesRecentTxsSchema, + }) + async getRecentTransactions(args: z.infer): Promise { + try { + const txs = await this.intentProvider.getRecentTxs(args.chain, args.wallet); + return JSON.stringify(txs, null, 2); + } catch (error) { + return `Error getting recent transactions: ${error}`; + } + } + + /** + * Get the current price of a token + * + * @param args - The arguments containing the chain, token address, and timestamp (optional). + * @returns A JSON string with the current token price or an error message. + */ + @CreateAction({ + name: "getTokenCurrentPrice", + description: + "This tool will fetch the price of a token on a given chain at a given timestamp or the current price if no timestamp is provided", + schema: NovesTokenCurrentPriceSchema, + }) + async getTokenCurrentPrice(args: z.infer): Promise { + try { + const price = await this.intentProvider.getTokenPrice({ + chain: args.chain, + token_address: args.token_address, + timestamp: args.timestamp ? new Date(args.timestamp).getTime().toString() : undefined, + }); + return JSON.stringify(price, null, 2); + } catch (error) { + return `Error getting token price: ${error}`; + } + } + + /** + * Checks if the Noves action provider supports the given network. + * Since the API works with +100 networks, this always returns true. + * + * @returns Always returns true. + */ + supportsNetwork = (): boolean => { + return true; + }; +} + +/** + * Factory function to create a new NovesActionProvider instance. + * + * @returns A new instance of NovesActionProvider. + */ +export const novesActionProvider = () => new NovesActionProvider(); diff --git a/typescript/agentkit/src/action-providers/noves/schemas.ts b/typescript/agentkit/src/action-providers/noves/schemas.ts new file mode 100644 index 000000000..a3437a7f4 --- /dev/null +++ b/typescript/agentkit/src/action-providers/noves/schemas.ts @@ -0,0 +1,32 @@ +import { z } from "zod"; + +/** + * Input schema for fetching a translated transaction. + * + * The API expects a transaction hash and a chain identifier. + */ +export const NovesTranslatedTxSchema = z.object({ + tx: z.string().describe("Transaction hash"), + chain: z.string().describe("Chain identifier (e.g., eth, base etc.)"), +}); + +/** + * Input schema for fetching recent transactions. + * + * The API expects a chain identifier and a wallet address. + */ +export const NovesRecentTxsSchema = z.object({ + chain: z.string().describe("Chain identifier (e.g., eth, base etc.)"), + wallet: z.string().describe("Wallet address"), +}); + +/** + * Input schema for fetching the current price of a token. + * + * The API expects a chain identifier, token address, and timestamp (optional). + */ +export const NovesTokenCurrentPriceSchema = z.object({ + chain: z.string().describe("Chain identifier (e.g., eth, base etc.)"), + token_address: z.string().describe("Token address"), + timestamp: z.string().optional().describe("Timestamp in seconds"), +}); diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index 50d2ff5e0..1d961cc1f 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -77,6 +77,9 @@ importers: '@jup-ag/api': specifier: ^6.0.39 version: 6.0.40 + '@noves/intent-ethers-provider': + specifier: ^0.1.3 + version: 0.1.3(ethers@6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@privy-io/public-api': specifier: 2.18.5 version: 2.18.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -158,7 +161,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 @@ -176,7 +179,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 @@ -1403,6 +1406,11 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@noves/intent-ethers-provider@0.1.3': + resolution: {integrity: sha512-9xyx6f0smfexUc2ZyusvvXlu9pLY91I6MQOGhh6VVFzbXzU0BFL8rLsFcwCKMYT8Q/qvzxd478+ngWA0535SWg==} + peerDependencies: + ethers: ^6.0.0 + '@opensea/seaport-js@4.0.4': resolution: {integrity: sha512-pOBgU+y1H9Bh463ZdgFshFBxnBQvEaGfoOJFDHbkvZTNLSqIOyuDmICFTQJEiPjYsS6tMQTbw2oJBtcVLFUT2g==} engines: {node: '>=20.0.0'} @@ -5915,6 +5923,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 @@ -6173,6 +6216,10 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@noves/intent-ethers-provider@0.1.3(ethers@6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@opensea/seaport-js@4.0.4(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -7295,6 +7342,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-spawn@7.0.6: @@ -8529,6 +8591,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 @@ -8560,6 +8641,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 @@ -8787,6 +8930,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: {} @@ -9981,6 +10136,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