From b102a9206db272c72128dbb055dec085e9288874 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Wed, 25 Dec 2024 16:13:57 +0000 Subject: [PATCH 001/112] feat: support Intel SGX using gramine --- .gitignore | 4 ++ Makefile | 59 +++++++++++++++++++++++++++++ eliza.manifest.template | 84 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 Makefile create mode 100644 eliza.manifest.template diff --git a/.gitignore b/.gitignore index 97c88ce2953..ec3bfb98b5a 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,7 @@ coverage .eslintcache agent/content + +eliza.manifest +eliza.manifest.sgx +eliza.sig diff --git a/Makefile b/Makefile new file mode 100644 index 00000000000..12030cf5e55 --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +# Copyright (C) 2024 Gramine contributors +# SPDX-License-Identifier: BSD-3-Clause + +THIS_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +NODEJS_DIR ?= /usr/bin + +ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine) + +ifeq ($(DEBUG),1) +GRAMINE_LOG_LEVEL = debug +else +GRAMINE_LOG_LEVEL = error +endif + +.PHONY: all +all: eliza.manifest +ifeq ($(SGX),1) +all: eliza.manifest.sgx eliza.sig +endif + +.PHONY: eliza.manifest +eliza.manifest: eliza.manifest.template + gramine-manifest \ + -Dlog_level=$(GRAMINE_LOG_LEVEL) \ + -Darch_libdir=$(ARCH_LIBDIR) \ + -Dnodejs_dir=$(NODEJS_DIR) \ + $< >$@ + +# Make on Ubuntu <= 20.04 doesn't support "Rules with Grouped Targets" (`&:`), +# for details on this workaround see +# https://github.com/gramineproject/gramine/blob/e8735ea06c/CI-Examples/helloworld/Makefile +eliza.manifest.sgx eliza.sig: sgx_sign + @: + +.INTERMEDIATE: sgx_sign +sgx_sign: eliza.manifest + gramine-sgx-sign \ + --manifest $< \ + --output $<.sgx + +ifeq ($(SGX),) +GRAMINE = gramine-direct +else +GRAMINE = gramine-sgx +endif + +# Start the default character: +# SGX=1 make start +# Start a specific character by passing arguments: +# SGX=1 make start -- --character "character/your_character_file.json" +.PHONY: start +start: all + $(GRAMINE) ./eliza --loader ts-node/esm src/index.ts --isRoot $(filter-out $@,$(MAKECMDGOALS)) +.PHONY: clean +clean: + $(RM) *.manifest *.manifest.sgx *.sig + +.PHONY: distclean +distclean: clean \ No newline at end of file diff --git a/eliza.manifest.template b/eliza.manifest.template new file mode 100644 index 00000000000..ea7eaa9ce35 --- /dev/null +++ b/eliza.manifest.template @@ -0,0 +1,84 @@ +# Copyright (C) 2024 Gramine contributors +# SPDX-License-Identifier: BSD-3-Clause + +# Node.js manifest file example + +libos.entrypoint = "{{ nodejs_dir }}/node" + +fs.start_dir = "/agent" + +loader.log_level = "{{ log_level }}" + +loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}" + +# Insecure configuration for loading arguments and environment variables +# Do not set these configurations in production +loader.insecure__use_cmdline_argv = true +loader.insecure__use_host_env = true + +fs.mounts = [ + { uri = "file:{{ gramine.runtimedir() }}", path = "/lib" }, + { uri = "file:{{ arch_libdir }}", path = "{{ arch_libdir }}" }, + { uri = "file:/usr/{{ arch_libdir }}", path = "/usr/{{ arch_libdir }}" }, + { uri = "file:{{ nodejs_dir }}/node", path = "{{ nodejs_dir }}/node" }, + { type = "tmpfs", path = "/tmp" }, + { type = "tmpfs", path = "/agent/content_cache" }, +] + +sys.enable_extra_runtime_domain_names_conf = true +sys.fds.limit = 65535 + +sgx.debug = false +sgx.remote_attestation = "dcap" +sgx.max_threads = 64 + +# Some dependencies of Eliza utilize WebAssembly (WASM). +# Initializing WASM requires a substantial amount of memory. +# If there is insufficient memory, you may encounter the following error: +# RangeError: WebAssembly.instantiate(): Out of memory: Cannot allocate Wasm memory for a new instance. +# To address this, we set the enclave size to 64GB. +sgx.enclave_size = "64G" + +# `use_exinfo = true` is needed because Node.js uses memory mappings with `MAP_NORESERVE`, which +# will defer page accepts to page-fault events when EDMM is enabled +sgx.edmm_enable = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} +sgx.use_exinfo = {{ 'true' if env.get('EDMM', '0') == '1' else 'false' }} + +sgx.trusted_files = [ + "file:{{ gramine.runtimedir() }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:{{ nodejs_dir }}/node", + "file:characters/", + "file:agent/src/", + "file:agent/package.json", + "file:agent/tsconfig.json", + "file:package.json", + "file:.env", + + # Add these files to sgx.trusted_files in production and remove them from sgx.allowed_files. + # Trusting these files requires a high-performance SGX machine due to the large number of files, + # which could significantly increase startup time. + # To mitigate startup time degradation, we use allowed_files in development. + # + # "file:node_modules/", + # "file:packages/", + # These files are symbolic links to node_modules, + # and Gramine does not support adding symbolic link directories to sgx.trusted_files. + # Therefore, we must add each directory individually to sgx.trusted_files. + # "file:agent/node_modules/@elizaos/adapter-sqlite/", + # "file:agent/node_modules/@elizaos/.../", +] + +# Insecure configuration. Use gramine encrypted fs to store data in production. +sgx.allowed_files = [ + "file:agent/data/", + "file:agent/model.gguf", + + # Move these files to sgx.trusted_files in production. + "file:node_modules/", + "file:packages/", + "file:agent/node_modules/", +] + +loader.env.SGX = "1" \ No newline at end of file From a95abfe91efa5bf07b629a210c4f762bc9dceab0 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Thu, 26 Dec 2024 14:41:17 +0000 Subject: [PATCH 002/112] feat: add plugin-sgx --- agent/package.json | 1 + agent/src/index.ts | 2 + packages/plugin-sgx/.npmignore | 6 + packages/plugin-sgx/README.md | 28 +++++ packages/plugin-sgx/eslint.config.mjs | 3 + packages/plugin-sgx/package.json | 19 ++++ packages/plugin-sgx/src/index.ts | 10 ++ packages/plugin-sgx/src/plugins/sgxPlugin.ts | 12 ++ .../src/providers/sgxAttestationProvider.ts | 103 ++++++++++++++++++ packages/plugin-sgx/src/types/attestation.ts | 4 + packages/plugin-sgx/tsconfig.json | 13 +++ packages/plugin-sgx/tsup.config.ts | 21 ++++ pnpm-lock.yaml | 16 +++ 13 files changed, 238 insertions(+) create mode 100644 packages/plugin-sgx/.npmignore create mode 100644 packages/plugin-sgx/README.md create mode 100644 packages/plugin-sgx/eslint.config.mjs create mode 100644 packages/plugin-sgx/package.json create mode 100644 packages/plugin-sgx/src/index.ts create mode 100644 packages/plugin-sgx/src/plugins/sgxPlugin.ts create mode 100644 packages/plugin-sgx/src/providers/sgxAttestationProvider.ts create mode 100644 packages/plugin-sgx/src/types/attestation.ts create mode 100644 packages/plugin-sgx/tsconfig.json create mode 100644 packages/plugin-sgx/tsup.config.ts diff --git a/agent/package.json b/agent/package.json index 91a900d6006..174e7185da7 100644 --- a/agent/package.json +++ b/agent/package.json @@ -46,6 +46,7 @@ "@elizaos/plugin-solana": "workspace:*", "@elizaos/plugin-starknet": "workspace:*", "@elizaos/plugin-ton": "workspace:*", + "@elizaos/plugin-sgx": "workspace:*", "@elizaos/plugin-sui": "workspace:*", "@elizaos/plugin-tee": "workspace:*", "@elizaos/plugin-multiversx": "workspace:*", diff --git a/agent/src/index.ts b/agent/src/index.ts index 1e49bae84ff..9677ca11f49 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -51,6 +51,7 @@ import { nearPlugin } from "@elizaos/plugin-near"; import { nftGenerationPlugin } from "@elizaos/plugin-nft-generation"; import { createNodePlugin } from "@elizaos/plugin-node"; import { solanaPlugin } from "@elizaos/plugin-solana"; +import { sgxPlugin } from "@elizaos/plugin-sgx"; import { suiPlugin } from "@elizaos/plugin-sui"; import { TEEMode, teePlugin } from "@elizaos/plugin-tee"; import { tonPlugin } from "@elizaos/plugin-ton"; @@ -555,6 +556,7 @@ export async function createAgent( ...(teeMode !== TEEMode.OFF && walletSecretSalt ? [teePlugin, solanaPlugin] : []), + getSecret(character, "SGX") ? sgxPlugin : null, getSecret(character, "COINBASE_API_KEY") && getSecret(character, "COINBASE_PRIVATE_KEY") && getSecret(character, "COINBASE_NOTIFICATION_URI") diff --git a/packages/plugin-sgx/.npmignore b/packages/plugin-sgx/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-sgx/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-sgx/README.md b/packages/plugin-sgx/README.md new file mode 100644 index 00000000000..dd8551cd0fa --- /dev/null +++ b/packages/plugin-sgx/README.md @@ -0,0 +1,28 @@ +# SGX Plugin for Eliza + +The SGX Plugin for Eliza enhances the platform by providing Intel SGX attestation capabilities. + +Intel SGX is part of the Intel confidential computing technology portfolio that allows businesses to take advantage of the cloud while staying in control of their data. Intel SGX protects data actively being used in the processor and memory by creating a trusted execution environment (TEE) called an enclave. + +The attestation capabilities are based on [Gramine Library OS](https://github.com/gramineproject/gramine). + +## Components + +### Providers +- **sgxAttestationProvider**: This provider is responsible for generating SGX remote attestations within Gramine SGX environments. + +## Usage + +First, you need to prepare the SGX environment and install the Gramine dependencies. + +Then, start eliza in SGX: + +```bash +pnpm i +pnpm build + +# Start default character +SGX=1 make start +# Start specific character +SGX=1 make start -- --character "character/trump.character.json" +``` diff --git a/packages/plugin-sgx/eslint.config.mjs b/packages/plugin-sgx/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-sgx/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-sgx/package.json b/packages/plugin-sgx/package.json new file mode 100644 index 00000000000..3a7dd7f6470 --- /dev/null +++ b/packages/plugin-sgx/package.json @@ -0,0 +1,19 @@ +{ + "name": "@elizaos/plugin-sgx", + "version": "0.1.5-alpha.5", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "tsup": "8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "eslint --fix --cache ." + } +} diff --git a/packages/plugin-sgx/src/index.ts b/packages/plugin-sgx/src/index.ts new file mode 100644 index 00000000000..345a8088017 --- /dev/null +++ b/packages/plugin-sgx/src/index.ts @@ -0,0 +1,10 @@ +import { sgxPlugin } from './plugins/sgxPlugin'; + + + +export * from './plugins/sgxPlugin'; +export * from './providers/sgxAttestationProvider'; +export * from './types/attestation'; + + +export default sgxPlugin; diff --git a/packages/plugin-sgx/src/plugins/sgxPlugin.ts b/packages/plugin-sgx/src/plugins/sgxPlugin.ts new file mode 100644 index 00000000000..4e54dcee03d --- /dev/null +++ b/packages/plugin-sgx/src/plugins/sgxPlugin.ts @@ -0,0 +1,12 @@ +import { Plugin } from "@elizaos/core"; +import { sgxAttestationProvider } from "../providers/sgxAttestationProvider"; + +export const sgxPlugin: Plugin = { + name: "sgx", + description: "Intel SGX plugin for Eliza, providing SGX attestation", + actions: [], + providers: [sgxAttestationProvider], + evaluators: [], + services: [], + clients: [], +}; diff --git a/packages/plugin-sgx/src/providers/sgxAttestationProvider.ts b/packages/plugin-sgx/src/providers/sgxAttestationProvider.ts new file mode 100644 index 00000000000..7ed7891a8ee --- /dev/null +++ b/packages/plugin-sgx/src/providers/sgxAttestationProvider.ts @@ -0,0 +1,103 @@ +import { IAgentRuntime, Memory, Provider, State } from "@elizaos/core"; +import { SgxAttestation } from "../types/attestation"; +import { promises as fs } from 'fs'; +import { createHash } from 'crypto'; + +// Function to calculate SHA-256 and return a Buffer (32 bytes) +function calculateSHA256(input: string): Buffer { + const hash = createHash('sha256'); + hash.update(input); + return hash.digest(); +} + +class SgxAttestationProvider { + private readonly SGX_QUOTE_MAX_SIZE: number = 8192 * 4; + private readonly SGX_TARGET_INFO_SIZE: number = 512; + + private readonly MY_TARGET_INFO_PATH: string = "/dev/attestation/my_target_info"; + private readonly TARGET_INFO_PATH: string = "/dev/attestation/target_info"; + private readonly USER_REPORT_DATA_PATH: string = "/dev/attestation/user_report_data"; + private readonly QUOTE_PATH: string = "/dev/attestation/quote"; + + constructor() {} + + async generateAttestation( + reportData: string + ): Promise { + // Hash the report data to generate the raw user report. + // The resulting hash value is 32 bytes long. + // Ensure that the length of the raw user report does not exceed 64 bytes. + const rawUserReport = calculateSHA256(reportData); + + try { + // Check if the gramine attestation device file exists + await fs.access(this.MY_TARGET_INFO_PATH); + + const quote = await this.generateQuoteByGramine(rawUserReport); + const attestation: SgxAttestation = { + quote: quote, + timestamp: Date.now(), + }; + // console.log("SGX remote attestation: ", attestation); + return attestation; + } catch (error) { + console.error("Error generating SGX remote attestation:", error); + throw new Error( + `Failed to generate SGX Quote: ${ + error instanceof Error ? error.message : "Unknown error" + }` + ); + } + } + + async generateQuoteByGramine( + rawUserReport: Buffer + ): Promise { + if (rawUserReport.length > 64) { + throw new Error("the length of rawUserReport exceeds 64 bytes"); + } + + const myTargetInfo = await fs.readFile(this.MY_TARGET_INFO_PATH); + if (myTargetInfo.length !== this.SGX_TARGET_INFO_SIZE) { + throw new Error("Invalid my_target_info length"); + } + + await fs.writeFile(this.TARGET_INFO_PATH, myTargetInfo); + await fs.writeFile(this.USER_REPORT_DATA_PATH, rawUserReport); + + // Read quote + const quoteData = await fs.readFile(this.QUOTE_PATH); + if (quoteData.length > this.SGX_QUOTE_MAX_SIZE) { + throw new Error("Invalid quote length"); + } + + const realLen = quoteData.lastIndexOf(0); + if (realLen === -1) { + throw new Error("quote without EOF"); + } + + return '0x' + quoteData.subarray(0, realLen + 1).toString('hex'); + } +} + +const sgxAttestationProvider: Provider = { + get: async (runtime: IAgentRuntime, _message: Memory, _state?: State) => { + const provider = new SgxAttestationProvider(); + const agentId = runtime.agentId; + + try { + // console.log("Generating attestation for agent: ", agentId); + const attestation = await provider.generateAttestation(agentId); + return `Your Agent's remote attestation is: ${JSON.stringify(attestation)}`; + } catch (error) { + console.error("Error in remote attestation provider:", error); + throw new Error( + `Failed to generate SGX Quote: ${ + error instanceof Error ? error.message : "Unknown error" + }` + ); + } + }, +}; + +export { sgxAttestationProvider, SgxAttestationProvider }; diff --git a/packages/plugin-sgx/src/types/attestation.ts b/packages/plugin-sgx/src/types/attestation.ts new file mode 100644 index 00000000000..279e4b4b56c --- /dev/null +++ b/packages/plugin-sgx/src/types/attestation.ts @@ -0,0 +1,4 @@ +export interface SgxAttestation { + quote: string; + timestamp: number; +} \ No newline at end of file diff --git a/packages/plugin-sgx/tsconfig.json b/packages/plugin-sgx/tsconfig.json new file mode 100644 index 00000000000..18c600eec05 --- /dev/null +++ b/packages/plugin-sgx/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts", + ] +} \ No newline at end of file diff --git a/packages/plugin-sgx/tsup.config.ts b/packages/plugin-sgx/tsup.config.ts new file mode 100644 index 00000000000..1a96f24afa1 --- /dev/null +++ b/packages/plugin-sgx/tsup.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + "safe-buffer", + // Add other modules you want to externalize + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f0e904aa43..413a96b6575 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -180,6 +180,9 @@ importers: '@elizaos/plugin-node': specifier: workspace:* version: link:../packages/plugin-node + '@elizaos/plugin-sgx': + specifier: workspace:* + version: link:../packages/plugin-sgx '@elizaos/plugin-solana': specifier: workspace:* version: link:../packages/plugin-solana @@ -1473,6 +1476,19 @@ importers: specifier: 8.3.5 version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1) + packages/plugin-sgx: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + devDependencies: + '@types/node': + specifier: ^20.0.0 + version: 20.17.9 + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1) + packages/plugin-solana: dependencies: '@elizaos/core': From 51d8b99eb3ffd14d23c8266b5b78a1f7e1fc27c1 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Thu, 26 Dec 2024 14:47:29 +0000 Subject: [PATCH 003/112] feat: add plugin-tee-log to support TEE logging --- .env.example | 2 + agent/package.json | 1 + agent/src/index.ts | 6 + packages/client-direct/package.json | 1 + packages/client-direct/src/README.md | 97 ++++++++++++++ packages/client-direct/src/api.ts | 93 +++++++++++++ packages/core/src/types.ts | 6 + packages/plugin-tee-log/.npmignore | 6 + packages/plugin-tee-log/README.md | 6 + packages/plugin-tee-log/eslint.config.mjs | 3 + packages/plugin-tee-log/package.json | 23 ++++ .../plugin-tee-log/src/adapters/sqliteDAO.ts | 125 ++++++++++++++++++ .../src/adapters/sqliteTables.ts | 26 ++++ packages/plugin-tee-log/src/index.ts | 9 ++ .../src/plugins/teeLogPlugin.ts | 12 ++ .../src/services/teeLogManager.ts | 108 +++++++++++++++ .../src/services/teeLogService.ts | 120 +++++++++++++++++ packages/plugin-tee-log/src/types.ts | 66 +++++++++ packages/plugin-tee-log/tsconfig.json | 13 ++ packages/plugin-tee-log/tsup.config.ts | 21 +++ pnpm-lock.yaml | 31 +++++ 21 files changed, 775 insertions(+) create mode 100644 packages/plugin-tee-log/.npmignore create mode 100644 packages/plugin-tee-log/README.md create mode 100644 packages/plugin-tee-log/eslint.config.mjs create mode 100644 packages/plugin-tee-log/package.json create mode 100644 packages/plugin-tee-log/src/adapters/sqliteDAO.ts create mode 100644 packages/plugin-tee-log/src/adapters/sqliteTables.ts create mode 100644 packages/plugin-tee-log/src/index.ts create mode 100644 packages/plugin-tee-log/src/plugins/teeLogPlugin.ts create mode 100644 packages/plugin-tee-log/src/services/teeLogManager.ts create mode 100644 packages/plugin-tee-log/src/services/teeLogService.ts create mode 100644 packages/plugin-tee-log/src/types.ts create mode 100644 packages/plugin-tee-log/tsconfig.json create mode 100644 packages/plugin-tee-log/tsup.config.ts diff --git a/.env.example b/.env.example index b1f05998b7d..a5d30a59c59 100644 --- a/.env.example +++ b/.env.example @@ -244,6 +244,8 @@ ZEROG_FLOW_ADDRESS= TEE_MODE=OFF # LOCAL | DOCKER | PRODUCTION WALLET_SECRET_SALT= # ONLY define if you want to use TEE Plugin, otherwise it will throw errors +ENABLE_TEE_LOG=false # Set to true to enable TEE logging, only available when running eliza in TEE + # Galadriel Configuration GALADRIEL_API_KEY=gal-* # Get from https://dashboard.galadriel.com/ diff --git a/agent/package.json b/agent/package.json index 174e7185da7..0e3d49b1f72 100644 --- a/agent/package.json +++ b/agent/package.json @@ -49,6 +49,7 @@ "@elizaos/plugin-sgx": "workspace:*", "@elizaos/plugin-sui": "workspace:*", "@elizaos/plugin-tee": "workspace:*", + "@elizaos/plugin-tee-log": "workspace:*", "@elizaos/plugin-multiversx": "workspace:*", "@elizaos/plugin-near": "workspace:*", "@elizaos/plugin-zksync-era": "workspace:*", diff --git a/agent/src/index.ts b/agent/src/index.ts index 9677ca11f49..0c21a8f14a9 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -54,6 +54,7 @@ import { solanaPlugin } from "@elizaos/plugin-solana"; import { sgxPlugin } from "@elizaos/plugin-sgx"; import { suiPlugin } from "@elizaos/plugin-sui"; import { TEEMode, teePlugin } from "@elizaos/plugin-tee"; +import { teeLogPlugin } from "@elizaos/plugin-tee-log"; import { tonPlugin } from "@elizaos/plugin-ton"; import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era"; import Database from "better-sqlite3"; @@ -557,6 +558,11 @@ export async function createAgent( ? [teePlugin, solanaPlugin] : []), getSecret(character, "SGX") ? sgxPlugin : null, + (getSecret(character, "ENABLE_TEE_LOG") && + ((teeMode !== TEEMode.OFF && walletSecretSalt) || + getSecret(character, "SGX"))) + ? teeLogPlugin + : null, getSecret(character, "COINBASE_API_KEY") && getSecret(character, "COINBASE_PRIVATE_KEY") && getSecret(character, "COINBASE_NOTIFICATION_URI") diff --git a/packages/client-direct/package.json b/packages/client-direct/package.json index fe3f4c7afb0..b4ee2c4cc78 100644 --- a/packages/client-direct/package.json +++ b/packages/client-direct/package.json @@ -7,6 +7,7 @@ "dependencies": { "@elizaos/core": "workspace:*", "@elizaos/plugin-image-generation": "workspace:*", + "@elizaos/plugin-tee-log": "workspace:*", "@types/body-parser": "1.19.5", "@types/cors": "2.8.17", "@types/express": "5.0.0", diff --git a/packages/client-direct/src/README.md b/packages/client-direct/src/README.md index 7377eab6f3b..bed23f74b54 100644 --- a/packages/client-direct/src/README.md +++ b/packages/client-direct/src/README.md @@ -43,3 +43,100 @@ curl -X GET "http://localhost:3000/fine-tune/8566c47a-ada8-441c-95bc-7bb07656c4c -H "Content-Type: application/json" \ -H "Authorization: Bearer jvBpxrTNqGqhnfQhSEqCdsG6aTSP8IBL". ``` + +# TEE Log + +## Get all TEE agents Information + +```bash +curl -X GET --location "http://localhost:3000/tee/agents" +``` + +Example response: + +```json +{ + "agents": [ + { + "id": "f18738bb-edab-45f6-805d-7f26dbfdba87", + "agentId": "75490f32-c06a-0005-9804-339453d3fe2f", + "agentName": "tea", + "createdAt": 1735222963153, + "publicKey": "02e1a9dde5462ee40bc2df7cc3f0dc88c6e582ea1c4ccf5a30e9dd7fbed736b0fe", + "attestation": "{\"quote\":\"0x03000200000000000...d2d2d2d0a00\",\"timestamp\":1735222963152}" + } + ], + "attestation": "{\"quote\":\"0x0300020000000...4452d2d2d2d2d0a00\",\"timestamp\":1735223101255}" +} +``` + +## Get TEE agent Information by agentId + +```bash +curl -X GET --location "http://localhost:3000/tee/agents/75490f32-c06a-0005-9804-339453d3fe2f" +``` + +Example response: + +```json +{ + "agent": { + "id": "f18738bb-edab-45f6-805d-7f26dbfdba87", + "agentId": "75490f32-c06a-0005-9804-339453d3fe2f", + "agentName": "tea", + "createdAt": 1735222963153, + "publicKey": "02e1a9dde5462ee40bc2df7cc3f0dc88c6e582ea1c4ccf5a30e9dd7fbed736b0fe", + "attestation": "{\"quote\":\"0x0300020...452d2d2d2d2d0a00\",\"timestamp\":1735222963152}" + }, + "attestation": "{\"quote\":\"0x03000200000000000...d2d2d2d2d0a00\",\"timestamp\":1735223294916}" +} +``` + +## Get TEE log + +```bash +curl -X POST --location "http://localhost:3000/tee/logs" \ + -H "Content-Type: application/json" \ + -d '{ + "query": { + "agentId": "75490f32-c06a-0005-9804-339453d3fe2f" + }, + "page": 1, + "pageSize": 10 + }' +``` + +Example response: + +```json +{ + "logs": { + "page": 1, + "pageSize": 10, + "total": 2, + "data": [ + { + "id": "01aac44e-d482-42df-8acc-6e6bfbb798f0", + "agentId": "75490f32-c06a-0005-9804-339453d3fe2f", + "roomId": "322d5683-fe3c-056a-8f1a-6b002e0a5c22", + "userId": "12dea96f-ec20-0935-a6ab-75692c994959", + "type": "Action:CONTINUE", + "content": "Continue", + "timestamp": 1735222998263, + "signature": "0x304402201a5bd4eb5807293ba0612b835eaaa56742c04603dbe08e3c7d247cdae3dc4b6f022034a165e1d63f1d58cb0976f615f6acd052f5e11154cef76d7c14c8ba99249833" + }, + { + "id": "6275e742-3ebf-477c-ab45-99d2c701c4b5", + "agentId": "75490f32-c06a-0005-9804-339453d3fe2f", + "roomId": "322d5683-fe3c-056a-8f1a-6b002e0a5c22", + "userId": "12dea96f-ec20-0935-a6ab-75692c994959", + "type": "Action:CONTINUE", + "content": "Continue", + "timestamp": 1735223036272, + "signature": "0x304402201a5bd4eb5807293ba0612b835eaaa56742c04603dbe08e3c7d247cdae3dc4b6f022034a165e1d63f1d58cb0976f615f6acd052f5e11154cef76d7c14c8ba99249833" + } + ] + }, + "attestation": "{\"quote\":\"0x0300020000000000...4154452d2d2d2d2d0a00\",\"timestamp\":1735223364956}" +} +``` \ No newline at end of file diff --git a/packages/client-direct/src/api.ts b/packages/client-direct/src/api.ts index f74174e4453..8c786c33965 100644 --- a/packages/client-direct/src/api.ts +++ b/packages/client-direct/src/api.ts @@ -7,8 +7,10 @@ import { elizaLogger, getEnvVariable, validateCharacterConfig, + ServiceType, } from "@elizaos/core"; +import { TeeLogQuery, TeeLogService } from "@elizaos/plugin-tee-log"; import { REST, Routes } from "discord.js"; import { DirectClient } from "."; @@ -121,5 +123,96 @@ export function createApiRouter( } }); + router.get("/tee/agents", async (req, res) => { + try { + const allAgents = []; + + for (const agentRuntime of agents.values()) { + const teeLogService = agentRuntime + .getService( + ServiceType.TEE_LOG + ) + .getInstance(); + + const agents = await teeLogService.getAllAgents(); + allAgents.push(...agents) + } + + const runtime: AgentRuntime = agents.values().next().value; + const teeLogService = runtime.getService(ServiceType.TEE_LOG).getInstance(); + const attestation = await teeLogService.generateAttestation(JSON.stringify(allAgents)); + res.json({ agents: allAgents, attestation: attestation }); + } catch (error) { + elizaLogger.error("Failed to get TEE agents:", error); + res.status(500).json({ + error: "Failed to get TEE agents", + }); + } + }); + + router.get("/tee/agents/:agentId", async (req, res) => { + try { + const agentId = req.params.agentId; + const agentRuntime = agents.get(agentId); + if (!agentRuntime) { + res.status(404).json({ error: "Agent not found" }); + return; + } + + const teeLogService = agentRuntime + .getService( + ServiceType.TEE_LOG + ) + .getInstance(); + + const teeAgent = await teeLogService.getAgent(agentId); + const attestation = await teeLogService.generateAttestation(JSON.stringify(teeAgent)); + res.json({ agent: teeAgent, attestation: attestation }); + } catch (error) { + elizaLogger.error("Failed to get TEE agent:", error); + res.status(500).json({ + error: "Failed to get TEE agent", + }); + } + }); + + router.post( + "/tee/logs", + async (req: express.Request, res: express.Response) => { + try { + const query = req.body.query || {}; + const page = parseInt(req.body.page) || 1; + const pageSize = parseInt(req.body.pageSize) || 10; + + const teeLogQuery: TeeLogQuery = { + agentId: query.agentId || "", + roomId: query.roomId || "", + userId: query.userId || "", + type: query.type || "", + containsContent: query.containsContent || "", + startTimestamp: query.startTimestamp || undefined, + endTimestamp: query.endTimestamp || undefined, + }; + const agentRuntime: AgentRuntime = agents.values().next().value; + const teeLogService = agentRuntime + .getService( + ServiceType.TEE_LOG + ) + .getInstance(); + const pageQuery = await teeLogService.getLogs(teeLogQuery, page, pageSize); + const attestation = await teeLogService.generateAttestation(JSON.stringify(pageQuery)); + res.json({ + logs: pageQuery, + attestation: attestation, + }); + } catch (error) { + elizaLogger.error("Failed to get TEE logs:", error); + res.status(500).json({ + error: "Failed to get TEE logs", + }); + } + } + ); + return router; } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 8bb331e8977..2698fea917f 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1191,6 +1191,11 @@ export interface IAwsS3Service extends Service { generateSignedUrl(fileName: string, expiresIn: number): Promise; } +export interface ITeeLogService extends Service { + getInstance(): ITeeLogService; + log(agentId: string, roomId: string, userId: string, type: string, content: string): Promise; +} + export type SearchResult = { title: string; url: string; @@ -1220,6 +1225,7 @@ export enum ServiceType { AWS_S3 = "aws_s3", BUTTPLUG = "buttplug", SLACK = "slack", + TEE_LOG = "tee_log", } export enum LoggingLevel { diff --git a/packages/plugin-tee-log/.npmignore b/packages/plugin-tee-log/.npmignore new file mode 100644 index 00000000000..078562eceab --- /dev/null +++ b/packages/plugin-tee-log/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts \ No newline at end of file diff --git a/packages/plugin-tee-log/README.md b/packages/plugin-tee-log/README.md new file mode 100644 index 00000000000..c73775e8cb3 --- /dev/null +++ b/packages/plugin-tee-log/README.md @@ -0,0 +1,6 @@ +# TEE Log Plugin for Eliza + +The TEE Log Plugin for Eliza is designed to enhance the logging capabilities of the Eliza framework by providing a structured way to generate, store and verify TEE (Trusted Execution Environment) logs for agents. This plugin ensures that all interactions are securely logged, providing a transparent and tamper-resistant record of all activities. + +## Services +- **[TeeLogService]**: This service is responsible for generating and storing TEE logs for agents. diff --git a/packages/plugin-tee-log/eslint.config.mjs b/packages/plugin-tee-log/eslint.config.mjs new file mode 100644 index 00000000000..92fe5bbebef --- /dev/null +++ b/packages/plugin-tee-log/eslint.config.mjs @@ -0,0 +1,3 @@ +import eslintGlobalConfig from "../../eslint.config.mjs"; + +export default [...eslintGlobalConfig]; diff --git a/packages/plugin-tee-log/package.json b/packages/plugin-tee-log/package.json new file mode 100644 index 00000000000..b861f59e3fd --- /dev/null +++ b/packages/plugin-tee-log/package.json @@ -0,0 +1,23 @@ +{ + "name": "@elizaos/plugin-tee-log", + "version": "0.1.5-alpha.5", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "@elizaos/plugin-tee": "workspace:*", + "@elizaos/plugin-sgx": "workspace:*", + "better-sqlite3": "11.6.0", + "elliptic": "6.6.1" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "tsup": "8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "lint": "eslint --fix --cache ." + } +} diff --git a/packages/plugin-tee-log/src/adapters/sqliteDAO.ts b/packages/plugin-tee-log/src/adapters/sqliteDAO.ts new file mode 100644 index 00000000000..ae1c5adde2e --- /dev/null +++ b/packages/plugin-tee-log/src/adapters/sqliteDAO.ts @@ -0,0 +1,125 @@ +import { Database } from "better-sqlite3"; +import { TeeLogDAO, TeeAgent, TeeLog, TeeLogQuery, PageQuery } from "../types.ts"; +import { sqliteTables } from "./sqliteTables.ts"; + +export class SqliteTeeLogDAO extends TeeLogDAO { + constructor(db: Database) { + super(); + this.db = db; + } + + async initialize(): Promise { + this.db.exec(sqliteTables); + } + + async addLog(log: TeeLog): Promise { + const stmt = this.db.prepare( + "INSERT INTO tee_logs (id, agentId, roomId, userId, type, content, timestamp, signature) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" + ); + try { + stmt.run(log.id, log.agentId, log.roomId, log.userId, log.type, log.content, log.timestamp, log.signature); + return true; + } catch (error) { + console.error("Error adding log to database", error); + return false; + } + } + + async getPagedLogs(query: TeeLogQuery, page: number, pageSize: number): Promise> { + if (page < 1) { + page = 1; + } + const offset = (page - 1) * pageSize; + const limit = pageSize; + + const whereConditions = []; + const params = []; + + if (query.agentId && query.agentId !== "") { + whereConditions.push("agentId = ?"); + params.push(query.agentId); + } + if (query.roomId && query.roomId !== "") { + whereConditions.push("roomId = ?"); + params.push(query.roomId); + } + if (query.userId && query.userId !== "") { + whereConditions.push("userId = ?"); + params.push(query.userId); + } + if (query.type && query.type !== "") { + whereConditions.push("type = ?"); + params.push(query.type); + } + if (query.containsContent && query.containsContent !== "") { + whereConditions.push("content LIKE ?"); + params.push(`%${query.containsContent}%`); + } + if (query.startTimestamp) { + whereConditions.push("timestamp >= ?"); + params.push(query.startTimestamp); + } + if (query.endTimestamp) { + whereConditions.push("timestamp <= ?"); + params.push(query.endTimestamp); + } + + const whereClause = + whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : ""; + + try { + const total_stmt = this.db.prepare( + `SELECT COUNT(*) as total FROM tee_logs ${whereClause}` + ); + const total = total_stmt.get(params).total; + + const logs_stmt = this.db.prepare( + `SELECT * FROM tee_logs ${whereClause} ORDER BY timestamp ASC LIMIT ? OFFSET ?` + ); + const logs = logs_stmt.all(...params, limit, offset); + + return { + page, + pageSize, + total, + data: logs, + }; + } catch (error) { + console.error("Error getting paged logs from database", error); + throw error; + } + } + + async addAgent(agent: TeeAgent): Promise { + const stmt = this.db.prepare( + "INSERT INTO tee_agents (id, agentId, agentName, createdAt, publicKey, attestation) VALUES (?, ?, ?, ?, ?, ?)" + ); + try { + stmt.run(agent.id, agent.agentId, agent.agentName, agent.createdAt, agent.publicKey, agent.attestation); + return true; + } catch (error) { + console.error("Error adding agent to database", error); + return false; + } + } + + async getAgent(agentId: string): Promise { + const stmt = this.db.prepare("SELECT * FROM tee_agents WHERE agentId = ? ORDER BY createdAt DESC LIMIT 1"); + try { + return stmt.get(agentId); + } catch (error) { + console.error("Error getting agent from database", error); + throw error; + } + } + + async getAllAgents(): Promise { + const stmt = this.db.prepare("SELECT * FROM tee_agents"); + try { + return stmt.all(); + } catch (error) { + console.error("Error getting all agents from database", error); + throw error; + } + } +} diff --git a/packages/plugin-tee-log/src/adapters/sqliteTables.ts b/packages/plugin-tee-log/src/adapters/sqliteTables.ts new file mode 100644 index 00000000000..9d24b7820ad --- /dev/null +++ b/packages/plugin-tee-log/src/adapters/sqliteTables.ts @@ -0,0 +1,26 @@ +export const sqliteTables = ` +BEGIN TRANSACTION; + +-- Table: tee_logs +CREATE TABLE IF NOT EXISTS "tee_logs" ( + "id" TEXT PRIMARY KEY, + "agentId" TEXT NOT NULL, + "roomId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" TEXT NOT NULL, + "content" TEXT NOT NULL, + "timestamp" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "signature" TEXT NOT NULL +); + +-- Table: tee_agents +CREATE TABLE IF NOT EXISTS "tee_agents" ( + "id" TEXT PRIMARY KEY, + "agentId" TEXT NOT NULL, + "agentName" TEXT NOT NULL, + "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + "publicKey" TEXT NOT NULL, + "attestation" TEXT NOT NULL +); + +COMMIT;`; diff --git a/packages/plugin-tee-log/src/index.ts b/packages/plugin-tee-log/src/index.ts new file mode 100644 index 00000000000..2e64b8ac87a --- /dev/null +++ b/packages/plugin-tee-log/src/index.ts @@ -0,0 +1,9 @@ +import { teeLogPlugin } from './plugins/teeLogPlugin'; +import { TeeLogService } from './services/teeLogService'; + +export * from './plugins/teeLogPlugin'; +export * from './types'; +export { TeeLogService }; + +export default teeLogPlugin; + diff --git a/packages/plugin-tee-log/src/plugins/teeLogPlugin.ts b/packages/plugin-tee-log/src/plugins/teeLogPlugin.ts new file mode 100644 index 00000000000..d8416864d57 --- /dev/null +++ b/packages/plugin-tee-log/src/plugins/teeLogPlugin.ts @@ -0,0 +1,12 @@ +import { Plugin } from "@elizaos/core"; +import { TeeLogService } from "../services/teeLogService"; + +export const teeLogPlugin: Plugin = { + name: "TEE-log", + description: "Support verifiable logging for eliza running in TEE", + actions: [], + providers: [], + evaluators: [], + services: [new TeeLogService()], + clients: [], +}; diff --git a/packages/plugin-tee-log/src/services/teeLogManager.ts b/packages/plugin-tee-log/src/services/teeLogManager.ts new file mode 100644 index 00000000000..f6c867aee13 --- /dev/null +++ b/packages/plugin-tee-log/src/services/teeLogManager.ts @@ -0,0 +1,108 @@ +import { + TEEMode, + RemoteAttestationProvider as TdxAttestationProvider, +} from "@elizaos/plugin-tee"; +import { SgxAttestationProvider } from "@elizaos/plugin-sgx"; +import { TeeType, TeeLogDAO, TeeAgent, TeeLog, TeeLogQuery, PageQuery } from "../types"; +import elliptic from "elliptic"; +import { v4 } from "uuid"; + +export class TeeLogManager { + private teeLogDAO: TeeLogDAO; + private teeType: TeeType; + private teeMode: TEEMode; // Only used for plugin-tee with TDX dstack + + // Map of agentId to its key pair + // These keypairs only store in memory. + // When the agent restarts, we will generate new keypair. + private keyPairs: Map = new Map(); + + constructor(teeLogDAO: TeeLogDAO, teeType: TeeType, teeMode: TEEMode) { + this.teeLogDAO = teeLogDAO; + this.teeType = teeType; + this.teeMode = teeMode; + } + + public async registerAgent(agentId: string, agentName: string): Promise { + if (!agentId) { + throw new Error("Agent ID is required"); + } + + const keyPair = this.generateKeyPair(); + this.keyPairs.set(agentId, keyPair); + + const publicKey = keyPair.getPublic().encode('hex', true); + const attestation = await this.generateAttestation(publicKey); + + const new_agent = { + id: v4(), + agentId, + agentName: agentName || "", + createdAt: new Date().getTime(), + publicKey, + attestation, + }; + + console.log("registerAgent new_agent", new_agent); + + return this.teeLogDAO.addAgent(new_agent); + } + + public async getAllAgents(): Promise { + return this.teeLogDAO.getAllAgents(); + } + + public async getAgent(agentId: string): Promise { + return this.teeLogDAO.getAgent(agentId); + } + + public async log(agentId: string, roomId: string, userId: string, type: string, content: string): Promise { + const keyPair = this.keyPairs.get(agentId); + if (!keyPair) { + throw new Error(`Agent ${agentId} not found`); + } + + const timestamp = new Date().getTime(); + + // Join the information into a single string + const messageToSign = `${agentId}|${roomId}|${userId}|${type}|${content}|${timestamp}`; + + // Sign the joined message + const signature = "0x" + keyPair.sign(messageToSign).toDER('hex'); + + return this.teeLogDAO.addLog({ + id: v4(), + agentId, + roomId, + userId, + type, + content, + timestamp, + signature, + }); + } + + public async getLogs(query: TeeLogQuery, page: number, pageSize: number): Promise> { + return this.teeLogDAO.getPagedLogs(query, page, pageSize); + } + + public generateKeyPair(): elliptic.ec.KeyPair { + const ec = new elliptic.ec('secp256k1'); + const key = ec.genKeyPair(); + return key; + } + + public async generateAttestation(userReport: string): Promise { + if (this.teeType === TeeType.SGX_GRAMINE) { + const sgxAttestationProvider = new SgxAttestationProvider(); + const sgxAttestation = await sgxAttestationProvider.generateAttestation(userReport); + return JSON.stringify(sgxAttestation); + } else if (this.teeType === TeeType.TDX_DSTACK) { + const tdxAttestationProvider = new TdxAttestationProvider(); + const tdxAttestation = await tdxAttestationProvider.generateAttestation(userReport); + return JSON.stringify(tdxAttestation); + } else { + throw new Error("Invalid TEE type"); + } + } +} diff --git a/packages/plugin-tee-log/src/services/teeLogService.ts b/packages/plugin-tee-log/src/services/teeLogService.ts new file mode 100644 index 00000000000..d63d40f66f2 --- /dev/null +++ b/packages/plugin-tee-log/src/services/teeLogService.ts @@ -0,0 +1,120 @@ +import { IAgentRuntime, Service, ServiceType, ITeeLogService } from "@elizaos/core"; +import { TEEMode } from "@elizaos/plugin-tee"; +import { SqliteTeeLogDAO } from "../adapters/sqliteDAO"; +import { TeeType, TeeLogDAO, TeeAgent, TeeLog, TeeLogQuery, PageQuery } from "../types"; +import { TeeLogManager } from "./teeLogManager"; +import Database from "better-sqlite3"; + +export class TeeLogService extends Service implements ITeeLogService { + private readonly dbPath = "./data/tee_log.sqlite"; + + private initialized: boolean = false; + private enableTeeLog: boolean = false; + private teeType: TeeType; + private teeMode: TEEMode = TEEMode.OFF; // Only used for plugin-tee with TDX dstack + + private teeLogDAO: TeeLogDAO; + private teeLogManager: TeeLogManager; + + + getInstance(): TeeLogService { + return this; + } + + static get serviceType(): ServiceType { + return ServiceType.TEE_LOG; + } + + async initialize(runtime: IAgentRuntime): Promise { + if (this.initialized) { + return; + } + + const enableValues = ["true", "1", "yes", "enable", "enabled", "on"]; + + const enableTeeLog = runtime.getSetting("ENABLE_TEE_LOG"); + if (enableTeeLog === null) { + throw new Error("ENABLE_TEE_LOG is not set."); + } + this.enableTeeLog = enableValues.includes(enableTeeLog.toLowerCase()); + if (!this.enableTeeLog) { + console.log("TEE log is not enabled."); + return; + } + + const runInSgx = runtime.getSetting("SGX"); + const teeMode = runtime.getSetting("TEE_MODE"); + const walletSecretSalt = runtime.getSetting("WALLET_SECRET_SALT"); + + const useSgxGramine = runInSgx && enableValues.includes(runInSgx.toLowerCase()); + const useTdxDstack = !teeMode && teeMode !== TEEMode.OFF && walletSecretSalt; + + if (useSgxGramine && useTdxDstack) { + throw new Error("Cannot configure both SGX and TDX at the same time."); + } else if (useSgxGramine) { + this.teeType = TeeType.SGX_GRAMINE; + } else if (useTdxDstack) { + this.teeType = TeeType.TDX_DSTACK; + } else { + throw new Error("Invalid TEE configuration."); + } + + const db = new Database(this.dbPath); + this.teeLogDAO = new SqliteTeeLogDAO(db); + await this.teeLogDAO.initialize(); + this.teeLogManager = new TeeLogManager(this.teeLogDAO, this.teeType, this.teeMode); + + const isRegistered = await this.teeLogManager.registerAgent( + runtime?.agentId, + runtime?.character?.name, + ); + if (!isRegistered) { + throw new Error(`Failed to register agent ${runtime.agentId}`); + } + + this.initialized = true; + } + + async log(agentId: string, roomId: string, userId: string, type: string, content: string): Promise { + if (!this.enableTeeLog) { + return false; + } + + return this.teeLogManager.log(agentId, roomId, userId, type, content); + } + + async getAllAgents(): Promise { + if (!this.enableTeeLog) { + return []; + } + + return this.teeLogManager.getAllAgents(); + } + + async getAgent(agentId: string): Promise { + if (!this.enableTeeLog) { + return undefined; + } + + return this.teeLogManager.getAgent(agentId); + } + + async getLogs(query: TeeLogQuery, page: number, pageSize: number): Promise> { + if (!this.enableTeeLog) { + return { + data: [], + total: 0, + page: page, + pageSize: pageSize, + }; + } + + return this.teeLogManager.getLogs(query, page, pageSize); + } + + async generateAttestation(userReport: string): Promise { + return this.teeLogManager.generateAttestation(userReport); + } +} + +export default TeeLogService; diff --git a/packages/plugin-tee-log/src/types.ts b/packages/plugin-tee-log/src/types.ts new file mode 100644 index 00000000000..851d6217b33 --- /dev/null +++ b/packages/plugin-tee-log/src/types.ts @@ -0,0 +1,66 @@ +export enum TeeType { + SGX_GRAMINE = "sgx_gramine", + TDX_DSTACK = "tdx_dstack", +} + +// Represents a log entry in the TeeLog table, containing details about agent activities. +export interface TeeLog { + id: string; + agentId: string; + roomId: string; + userId: string; + type: string; + content: string; + timestamp: number; + signature: string; +} + +export interface TeeLogQuery { + agentId?: string; + roomId?: string; + userId?: string; + type?: string; + containsContent?: string; + startTimestamp?: number; + endTimestamp?: number; +} + +// Represents an agent in the TeeAgent table, containing details about the agent. +export interface TeeAgent { + id: string; // Primary key + // Allow duplicate agentId. + // This is to support the case where the same agentId is registered multiple times. + // Each time the agent restarts, we will generate a new keypair and attestation. + agentId: string; + agentName: string; + createdAt: number; + publicKey: string; + attestation: string; +} + +export interface PageQuery { + page: number; + pageSize: number; + total?: number; + data?: Result; +} + +export abstract class TeeLogDAO { + db: DB; + + abstract initialize(): Promise; + + abstract addLog(log: TeeLog): Promise; + + abstract getPagedLogs( + query: TeeLogQuery, + page: number, + pageSize: number + ): Promise>; + + abstract addAgent(agent: TeeAgent): Promise; + + abstract getAgent(agentId: string): Promise; + + abstract getAllAgents(): Promise; +} \ No newline at end of file diff --git a/packages/plugin-tee-log/tsconfig.json b/packages/plugin-tee-log/tsconfig.json new file mode 100644 index 00000000000..18c600eec05 --- /dev/null +++ b/packages/plugin-tee-log/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "types": [ + "node" + ] + }, + "include": [ + "src/**/*.ts", + ] +} \ No newline at end of file diff --git a/packages/plugin-tee-log/tsup.config.ts b/packages/plugin-tee-log/tsup.config.ts new file mode 100644 index 00000000000..1a96f24afa1 --- /dev/null +++ b/packages/plugin-tee-log/tsup.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], // Ensure you're targeting CommonJS + external: [ + "dotenv", // Externalize dotenv to prevent bundling + "fs", // Externalize fs to use Node.js built-in module + "path", // Externalize other built-ins if necessary + "@reflink/reflink", + "@node-llama-cpp", + "https", + "http", + "agentkeepalive", + "safe-buffer", + // Add other modules you want to externalize + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 413a96b6575..1c175ac9a72 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -198,6 +198,9 @@ importers: '@elizaos/plugin-tee': specifier: workspace:* version: link:../packages/plugin-tee + '@elizaos/plugin-tee-log': + specifier: workspace:* + version: link:../packages/plugin-tee-log '@elizaos/plugin-ton': specifier: workspace:* version: link:../packages/plugin-ton @@ -510,6 +513,9 @@ importers: '@elizaos/plugin-image-generation': specifier: workspace:* version: link:../plugin-image-generation + '@elizaos/plugin-tee-log': + specifier: workspace:* + version: link:../plugin-tee-log '@types/body-parser': specifier: 1.19.5 version: 1.19.5 @@ -1670,6 +1676,31 @@ importers: specifier: 7.1.0 version: 7.1.0 + packages/plugin-tee-log: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + '@elizaos/plugin-sgx': + specifier: workspace:* + version: link:../plugin-sgx + '@elizaos/plugin-tee': + specifier: workspace:* + version: link:../plugin-tee + better-sqlite3: + specifier: 11.6.0 + version: 11.6.0 + elliptic: + specifier: 6.6.1 + version: 6.6.1 + devDependencies: + '@types/node': + specifier: ^20.0.0 + version: 20.17.9 + tsup: + specifier: 8.3.5 + version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1) + packages/plugin-ton: dependencies: '@elizaos/core': From 3aeed4a1da05c2d56def417fbfcd43399478449e Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Fri, 27 Dec 2024 04:00:16 +0000 Subject: [PATCH 004/112] update plugin-sgx README --- packages/plugin-sgx/README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/plugin-sgx/README.md b/packages/plugin-sgx/README.md index dd8551cd0fa..622f1c3d81d 100644 --- a/packages/plugin-sgx/README.md +++ b/packages/plugin-sgx/README.md @@ -4,7 +4,18 @@ The SGX Plugin for Eliza enhances the platform by providing Intel SGX attestatio Intel SGX is part of the Intel confidential computing technology portfolio that allows businesses to take advantage of the cloud while staying in control of their data. Intel SGX protects data actively being used in the processor and memory by creating a trusted execution environment (TEE) called an enclave. -The attestation capabilities are based on [Gramine Library OS](https://github.com/gramineproject/gramine). +### Trusted Execution Environment (TEE) +A Trusted Execution Environment (TEE) is a secure area within a main processor that ensures sensitive data is stored, processed, and protected in an isolated environment. TEEs provide a higher level of security by allowing applications to run in a protected space, safeguarding them from unauthorized access and potential threats. + +### Software Guard Extensions (SGX) +Software Guard Extensions is a set of instructions on Intel processors for creating Trusted Execution Environments (TEE). SGX enables the creation of enclaves, which are protected areas of execution that ensure the confidentiality and integrity of the code and data within them. This allows applications to run securely, even in untrusted environments, by protecting sensitive information from being exposed to the host operating system or other applications. + +### Attestation +The attestation of TEE is a security mechanism that enables a TEE to provide cryptographic proof of its integrity and authenticity to external parties. By generating a unique attestation report that includes information about the software and its execution state, a TEE can assure remote verifiers that the code running within it has not been altered and is operating as intended. This process is essential for establishing trust in secure applications, allowing them to interact confidently with other systems and services in potentially untrusted environments. + +### Gramine +The attestation capabilities are based on [Gramine Library OS](https://github.com/gramineproject/gramine). Gramine is a Library OS for Unmodified Applications. Applications can benefit from confidentiality and integrity guarantees of Intel SGX, but developers need to be very skilled for effective partitioning and code modification for Intel SGX environment. +Gramine runs unmodified applications inside Intel SGX. It supports dynamically loaded libraries, runtime linking, multi-process abstractions, and file authentication. For additional security, Gramine performs cryptographic and semantic checks at untrusted host interface. Developers provide a manifest file to configure the application environment and isolation policies, Gramine automatically does the rest. ## Components @@ -14,6 +25,7 @@ The attestation capabilities are based on [Gramine Library OS](https://github.co ## Usage First, you need to prepare the SGX environment and install the Gramine dependencies. +You can install Gramine packages in your SGX machine or use the docker image. Follow the [Gramine installation options](https://gramine.readthedocs.io/en/latest/installation.html) for more details. Then, start eliza in SGX: @@ -26,3 +38,14 @@ SGX=1 make start # Start specific character SGX=1 make start -- --character "character/trump.character.json" ``` + +After starting Eliza, the provider `sgxAttestationProvider` will be registered into Eliza through plugin-sgx. The environment variable `SGX` is required to be set to `1` to enable plugin-sgx. And the `SGX` is always set to `1` in the SGX environment through the `eliza.manifest.template` file. + +When Eliza starts, the `sgxAttestationProvider` will generate SGX attestation in each request. And you can use the `SgxAttestationProvider` to generate SGX remote attestations for your own plugins / clients. + +### Example + +```typescript +const sgxAttestationProvider = new SgxAttestationProvider(); +const sgxAttestation = await sgxAttestationProvider.generateAttestation(userReport); +``` From 50323b7dba952af93769af7cd4a26533c3e6c44e Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Fri, 27 Dec 2024 04:19:37 +0000 Subject: [PATCH 005/112] update README of client-direct --- packages/client-direct/src/README.md | 56 ++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/client-direct/src/README.md b/packages/client-direct/src/README.md index bed23f74b54..547785563e8 100644 --- a/packages/client-direct/src/README.md +++ b/packages/client-direct/src/README.md @@ -44,7 +44,13 @@ curl -X GET "http://localhost:3000/fine-tune/8566c47a-ada8-441c-95bc-7bb07656c4c -H "Authorization: Bearer jvBpxrTNqGqhnfQhSEqCdsG6aTSP8IBL". ``` -# TEE Log +# TEE Logging + +TEE Logging is a feature that allows you to log the activities of your agents. Through these logs, you can verify that the actions of the agents are protected by the TEE and that they are executed autonomously by Eliza, without any third-party interference. + +## Setup + +You need to setup the TEE log plugin first. Follow the [TEE Log Plugin](../plugin-tee-log/README.md) to setup the plugin. ## Get all TEE agents Information @@ -52,7 +58,7 @@ curl -X GET "http://localhost:3000/fine-tune/8566c47a-ada8-441c-95bc-7bb07656c4c curl -X GET --location "http://localhost:3000/tee/agents" ``` -Example response: +Example response when success: ```json { @@ -70,13 +76,24 @@ Example response: } ``` +Note that the user report included in the attestation contains the SHA256 hash of the value of the "agents" field. Specifically, it is calculated as follows: `SHA256(JSON.stringify(agents value))`. By verifying the attestation, you can retrieve this hash value and ensure the integrity of the agents' information. + + +Example response when error: + +```json +{ + "error": "Failed to get TEE agents" +} +``` + ## Get TEE agent Information by agentId ```bash curl -X GET --location "http://localhost:3000/tee/agents/75490f32-c06a-0005-9804-339453d3fe2f" ``` -Example response: +Example response when success: ```json { @@ -92,6 +109,16 @@ Example response: } ``` +Note that the user report included in the attestation contains the SHA256 hash of the value of the "agent" field. Specifically, it is calculated as follows: `SHA256(JSON.stringify(agent value))`. By verifying the attestation, you can retrieve this hash value and ensure the integrity of the agent's information. + +Example response when error: + +```json +{ + "error": "Failed to get TEE agent" +} +``` + ## Get TEE log ```bash @@ -106,7 +133,18 @@ curl -X POST --location "http://localhost:3000/tee/logs" \ }' ``` -Example response: +There are optional parameters in the `query` parameter: + +- **agentId**: (string, optional) The ID of the agent whose logs you want to retrieve. +- **roomId**: (string, optional) The ID of the room associated with the logs. +- **userId**: (string, optional) The ID of the user related to the logs. +- **type**: (string, optional) The type of logs to filter. +- **containsContent**: (string, optional) A substring to search for within the log content. +- **startTimestamp**: (number, optional) The starting timestamp for filtering logs. +- **endTimestamp**: (number, optional) The ending timestamp for filtering logs. + + +Example response when success: ```json { @@ -139,4 +177,14 @@ Example response: }, "attestation": "{\"quote\":\"0x0300020000000000...4154452d2d2d2d2d0a00\",\"timestamp\":1735223364956}" } +``` + +Note that the user report included in the attestation contains the SHA256 hash of the value of the "logs" field. Specifically, it is calculated as follows: `SHA256(JSON.stringify(logs value))`. By verifying the attestation, you can retrieve this hash value and ensure the integrity of the logs + +Example response when error: + +```json +{ + "error": "Failed to get TEE logs" +} ``` \ No newline at end of file From dac76f5a7d8be888308baec4a30c94f7b8d66b2c Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Fri, 27 Dec 2024 04:40:48 +0000 Subject: [PATCH 006/112] update plugin-tee-log README --- packages/plugin-tee-log/README.md | 101 +++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/packages/plugin-tee-log/README.md b/packages/plugin-tee-log/README.md index c73775e8cb3..f23140e6202 100644 --- a/packages/plugin-tee-log/README.md +++ b/packages/plugin-tee-log/README.md @@ -1,6 +1,105 @@ # TEE Log Plugin for Eliza -The TEE Log Plugin for Eliza is designed to enhance the logging capabilities of the Eliza framework by providing a structured way to generate, store and verify TEE (Trusted Execution Environment) logs for agents. This plugin ensures that all interactions are securely logged, providing a transparent and tamper-resistant record of all activities. +The TEE Log Plugin for Eliza is designed to enhance the logging capabilities of the Eliza by providing a structured way to generate, store and verify TEE (Trusted Execution Environment) logs for agents. This plugin ensures that all sensitive interactions are securely logged, providing a transparent and tamper-resistant record of all sensitive activities. + +## Background + +As Eliza is a fully autonomous AI agent capable of running within a TEE, we need to demonstrate to the outside world that we are indeed operating within a TEE. This allows external parties to verify that our actions are protected by the TEE and that they are autonomously executed by Eliza, without any third-party interference. Therefore, it is necessary to leverage TEE's remote attestation and establish a TEE logging mechanism to prove that these operations are entirely and autonomously performed by Eliza within the TEE. + +## Requirements + +Since the TEE Logging is based on the TEE, it is necessary to have a TEE enabled environment. Currently, we support Intel SGX (Gramine) and Intel TDX (dstack). +- using Intel SGX (Gramine), you need to enable the plugin-sgx in the Eliza runtime, which is enabled in SGX env automatically. +- using Intel TDX (dstack), you need to enable the plugin-tee in the Eliza runtime. ## Services + - **[TeeLogService]**: This service is responsible for generating and storing TEE logs for agents. + +### Class: TeeLogService + +The `TeeLogService` class implements the `ITeeLogService` interface and extends the `Service` class. It manages the logging of sensitive interactions within a Trusted Execution Environment (TEE). + +#### Methods + +- **getInstance()**: `TeeLogService` + - Returns the singleton instance of the `TeeLogService`. + +- **static get serviceType()**: `ServiceType` + - Returns the service type for TEE logging. + +- **async initialize(runtime: IAgentRuntime): Promise** + - Initializes the TEE log service. It checks the runtime settings to configure the TEE type and enables logging if configured. + +- **async log(agentId: string, roomId: string, userId: string, type: string, content: string): Promise** + - Logs an interaction with the specified parameters. Returns `false` if TEE logging is not enabled. + +- **async getAllAgents(): Promise** + - Retrieves all agents that have been logged. Returns an empty array if TEE logging is not enabled. + +- **async getAgent(agentId: string): Promise** + - Retrieves the details of a specific agent by their ID. Returns `undefined` if TEE logging is not enabled. + +- **async getLogs(query: TeeLogQuery, page: number, pageSize: number): Promise>** + - Retrieves logs based on the provided query parameters. Returns an empty result if TEE logging is not enabled. + +- **async generateAttestation(userReport: string): Promise** + - Generates an attestation based on the provided user report. + +### Storage + +The TEE logs are stored in a SQLite database, which is located at `./data/tee_log.sqlite`. The database is automatically created when the service is initialized. + +Important: You need to use the encrypted file system to store the database file in production, otherwise the database will be compromised. Since TEE only protects memory-in-use, the disk is not protected by the TEE. However, Many TEE development tools support the encrypted file system, for example, you can refer to the [Gramine Encrypted files](https://gramine.readthedocs.io/en/latest/manifest-syntax.html#encrypted-files) documentation for more information. + +### Usage + +To use the `TeeLogService`, ensure that the TEE environment is properly configured and initialized. + +The logging isn't integrated for actions by default, you need to integrate the logging for the actions you want to log. For example, if you want to log the `Continue` action of plugin-bootstrap, you can do the following: + +First, add plugin-tee-log to the dependencies of plugin-bootstrap: + +```json +"@elizaos/plugin-tee-log": "workspace:*", +``` + +Then, add the following code to the `Continue` action: + +```typescript +import { + ServiceType, + ITeeLogService, +} from "@elizaos/core"; + + +// In the handler of the action + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: any, + callback: HandlerCallback + ) => { + // Continue the action + + // Log the action + const teeLogService = runtime + .getService(ServiceType.TEE_LOG) + .getInstance(); + if (teeLogService.log( + runtime.agentId, + message.roomId, + message.userId, + "The type of the log, for example, Action:CONTINUE", + "The content that you want to log" + ) + ) { + console.log("Logged TEE log successfully"); + } + + // Continue the action + } +``` + +After configuring the logging for the action, you can run the Eliza and see the logs through the client-direct REST API. See more details in the [Client-Direct REST API](../client-direct/src/README.md) documentation. \ No newline at end of file From 29654157af665f718dc64a539f9efc4ca1413959 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Fri, 27 Dec 2024 04:44:47 +0000 Subject: [PATCH 007/112] update plugin-tee-log README --- packages/plugin-tee-log/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/plugin-tee-log/README.md b/packages/plugin-tee-log/README.md index f23140e6202..e6be0067b03 100644 --- a/packages/plugin-tee-log/README.md +++ b/packages/plugin-tee-log/README.md @@ -12,6 +12,31 @@ Since the TEE Logging is based on the TEE, it is necessary to have a TEE enabled - using Intel SGX (Gramine), you need to enable the plugin-sgx in the Eliza runtime, which is enabled in SGX env automatically. - using Intel TDX (dstack), you need to enable the plugin-tee in the Eliza runtime. +## TEE Logging Mechanism + +## TEE Logging Mechanism + +1. **Key Pair Generation and Attestation**: + - During startup, each agent generates a key pair and creates a remote attestation for the public key. The private key is securely stored in the TEE's encrypted memory. The agent's relevant information, along with the public key and attestation, is recorded in a local database. A new key pair is generated each time the agent is updated or restarted to ensure key security. + +2. **Log Recording**: + - For each log entry, basic information is recorded, including `agentId`, `roomId`, `userId`, `type`, `content`, and `timestamp`. This information is concatenated and signed using the agent's corresponding private key to ensure verifiability. The verification process follows this trust chain: + - Verify the attestation. + - Trust the public key contained in the attestation. + - Use the public key to verify the signature. + - Trust the complete log record. + +3. **Data Storage**: + - All log data must be stored in the TEE's encrypted file system in production environments. Storing data in plaintext is prohibited to prevent tampering. + +4. **Log Extraction for Verification**: + - Third parties can extract TEE logs for verification purposes. Two types of information can be extracted: + - **Agent Information**: This includes the agent's metadata, public key, and attestation, which can be used to verify the agent's public key. + - **Log Information**: Required logs can be extracted, with the agent's attestation and public key used to verify the signature, ensuring that each record remains untampered. + +5. **Integrity Protection**: + - When users extract TEE logs via the REST API, the results are hashed, and an attestation is generated. After extraction, users can verify the attestation by comparing the hash value contained within it to the extracted results, thereby ensuring the integrity of the data. + ## Services - **[TeeLogService]**: This service is responsible for generating and storing TEE logs for agents. From fae497c2cc01cfedabc80fda48e24856cba519bc Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Fri, 27 Dec 2024 04:50:10 +0000 Subject: [PATCH 008/112] update plugin-tee-log README --- packages/plugin-tee-log/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/plugin-tee-log/README.md b/packages/plugin-tee-log/README.md index e6be0067b03..cd8207b7c62 100644 --- a/packages/plugin-tee-log/README.md +++ b/packages/plugin-tee-log/README.md @@ -81,6 +81,12 @@ Important: You need to use the encrypted file system to store the database file To use the `TeeLogService`, ensure that the TEE environment is properly configured and initialized. +Enable the TEE logging in the Eliza .env file: + +```env +TEE_LOG_ENABLED=true +``` + The logging isn't integrated for actions by default, you need to integrate the logging for the actions you want to log. For example, if you want to log the `Continue` action of plugin-bootstrap, you can do the following: First, add plugin-tee-log to the dependencies of plugin-bootstrap: From 24c9c3c6e5269b57100ce71d1c9ad076030bbc84 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Sat, 28 Dec 2024 15:46:01 +0000 Subject: [PATCH 009/112] add quick start for running Eliza in SGX --- packages/plugin-sgx/README.md | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/plugin-sgx/README.md b/packages/plugin-sgx/README.md index 622f1c3d81d..4eb05e0e96d 100644 --- a/packages/plugin-sgx/README.md +++ b/packages/plugin-sgx/README.md @@ -49,3 +49,50 @@ When Eliza starts, the `sgxAttestationProvider` will generate SGX attestation in const sgxAttestationProvider = new SgxAttestationProvider(); const sgxAttestation = await sgxAttestationProvider.generateAttestation(userReport); ``` + +## Quick Start + +First, you need to prepare a SGX enabled machine. + +Then, you can use the following command to start a Gramine Docker container: + +```bash +sudo docker run -it --name eliza_sgx \ + --mount type=bind,source={your_eliza_path},target=/root/eliza \ + --device /dev/sgx/enclave \ + --device /dev/sgx/provision \ + gramineproject/gramine:stable-jammy +``` + +After entering the docker, you can use the following command to prepare the Eliza environment: + +```bash +# Generate the private key for signing the SGX enclave +gramine-sgx-gen-private-key + +cd /root/eliza/ + +# Install nodejs and pnpm +# Node.js will be installed at `/usr/bin/node`. +# Gramine will utilize this path as the default Node.js location to run Eliza. +# If you prefer to use nvm for installing Node.js, please ensure to specify the Node.js path in the Makefile, as the installation path for nvm is not `/usr/bin/node`. +apt update +apt install -y build-essential +apt install -y curl +curl -fsSL https://deb.nodesource.com/setup_23.x | bash - +apt install -y nodejs=23.3.0-1nodesource1 +npm install -g pnpm + +# Build Eliza +pnpm i +# The build may fail on the first attempt due to the missing `plugin-tee` dependency in `plugin-tee-log`. Simply run the build command again to resolve the issue. +# TODO: fix the build issue +pnpm build + +# Copy the .env.example file to .env +cp .env.example .env +# Edit the .env file + +# Start Eliza in SGX +SGX=1 make start -- --character "character/c3po.character.json" +``` From 3b12c3b090b5f5b36cbc9af0d26af01571c17298 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Tue, 31 Dec 2024 06:53:00 +0000 Subject: [PATCH 010/112] update package version --- packages/plugin-sgx/package.json | 2 +- packages/plugin-tee-log/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-sgx/package.json b/packages/plugin-sgx/package.json index 3a7dd7f6470..951ef21c069 100644 --- a/packages/plugin-sgx/package.json +++ b/packages/plugin-sgx/package.json @@ -1,6 +1,6 @@ { "name": "@elizaos/plugin-sgx", - "version": "0.1.5-alpha.5", + "version": "0.1.7-alpha.2", "main": "dist/index.js", "type": "module", "types": "dist/index.d.ts", diff --git a/packages/plugin-tee-log/package.json b/packages/plugin-tee-log/package.json index b861f59e3fd..3c742edeb3d 100644 --- a/packages/plugin-tee-log/package.json +++ b/packages/plugin-tee-log/package.json @@ -1,6 +1,6 @@ { "name": "@elizaos/plugin-tee-log", - "version": "0.1.5-alpha.5", + "version": "0.1.7-alpha.2", "main": "dist/index.js", "type": "module", "types": "dist/index.d.ts", From afb164a1a65349f3c6cf6b638f95905f68baf8b6 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Tue, 31 Dec 2024 06:53:28 +0000 Subject: [PATCH 011/112] update pnpm-lock to fix building error --- pnpm-lock.yaml | 969 +++++++++++++++++++++++-------------------------- 1 file changed, 456 insertions(+), 513 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac43f3b08a9..3880c27a98c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ importers: version: 3.9.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) '@vitest/eslint-plugin': specifier: 1.0.1 - version: 1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + version: 1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) amqplib: specifier: 0.10.5 version: 0.10.5 @@ -74,7 +74,7 @@ importers: version: 9.1.7 lerna: specifier: 8.1.5 - version: 8.1.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(encoding@0.1.13) + version: 8.1.5(@swc/core@1.10.1)(encoding@0.1.13) only-allow: specifier: 1.2.1 version: 1.2.1 @@ -95,7 +95,7 @@ importers: version: 5.4.11(@types/node@22.10.2)(terser@5.37.0) vitest: specifier: 2.1.5 - version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) agent: dependencies: @@ -243,16 +243,16 @@ importers: version: 29.5.14 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + version: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) ts-jest: specifier: ^29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3) + version: 10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) client: dependencies: @@ -297,7 +297,7 @@ importers: version: 2.5.5 tailwindcss-animate: specifier: 1.0.7 - version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3))) + version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3))) vite-plugin-top-level-await: specifier: 1.4.4 version: 1.4.4(@swc/helpers@0.5.15)(rollup@4.29.1)(vite@client+@tanstack+router-plugin+vite) @@ -337,7 +337,7 @@ importers: version: 8.4.49 tailwindcss: specifier: 3.4.15 - version: 3.4.15(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + version: 3.4.15(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) typescript: specifier: 5.6.3 version: 5.6.3 @@ -352,22 +352,22 @@ importers: dependencies: '@docusaurus/core': specifier: 3.6.3 - version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/plugin-content-blog': specifier: 3.6.3 - version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/plugin-content-docs': specifier: 3.6.3 - version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/plugin-ideal-image': specifier: 3.6.3 - version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/preset-classic': specifier: 3.6.3 - version: 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/theme-mermaid': specifier: 3.6.3 - version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + version: 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@mdx-js/react': specifier: 3.0.1 version: 3.0.1(@types/react@18.3.12)(react@18.3.1) @@ -376,7 +376,7 @@ importers: version: 2.1.1 docusaurus-lunr-search: specifier: 3.5.0 - version: 3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) dotenv: specifier: ^16.4.7 version: 16.4.7 @@ -395,10 +395,10 @@ importers: devDependencies: '@docusaurus/module-type-aliases': specifier: 3.6.3 - version: 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/types': specifier: 3.6.3 - version: 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) docusaurus-plugin-typedoc: specifier: 1.0.5 version: 1.0.5(typedoc-plugin-markdown@4.2.10(typedoc@0.26.11(typescript@5.6.3))) @@ -423,7 +423,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/adapter-redis: dependencies: @@ -442,7 +442,7 @@ importers: version: 5.0.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/adapter-sqlite: dependencies: @@ -464,7 +464,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/adapter-sqljs: dependencies: @@ -486,7 +486,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/adapter-supabase: dependencies: @@ -502,7 +502,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-auto: dependencies: @@ -533,7 +533,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-direct: dependencies: @@ -579,7 +579,7 @@ importers: version: 1.4.12 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-discord: dependencies: @@ -616,7 +616,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-farcaster: dependencies: @@ -629,7 +629,7 @@ importers: devDependencies: tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-github: dependencies: @@ -654,7 +654,7 @@ importers: version: 8.1.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-lens: dependencies: @@ -676,7 +676,7 @@ importers: devDependencies: tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-slack: dependencies: @@ -722,19 +722,19 @@ importers: version: 18.19.68 jest: specifier: ^29.5.0 - version: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) + version: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) rimraf: specifier: ^5.0.0 version: 5.0.10 ts-jest: specifier: ^29.1.0 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)))(typescript@5.6.3) ts-node: specifier: ^10.9.1 - version: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3) + version: 10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3) tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) typescript: specifier: ^5.0.0 version: 5.6.3 @@ -756,7 +756,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/client-twitter: dependencies: @@ -778,7 +778,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/core: dependencies: @@ -911,13 +911,13 @@ importers: version: 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) '@vitest/coverage-v8': specifier: 2.1.5 - version: 2.1.5(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + version: 2.1.5(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) dotenv: specifier: 16.4.5 version: 16.4.5 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + version: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) lint-staged: specifier: 15.2.10 version: 15.2.10 @@ -935,16 +935,16 @@ importers: version: 2.79.2 ts-jest: specifier: 29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3) ts-node: specifier: 10.9.2 - version: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3) + version: 10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3) tslib: specifier: 2.8.1 version: 2.8.1 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) typescript: specifier: 5.6.3 version: 5.6.3 @@ -981,7 +981,7 @@ importers: version: 6.13.4(bufferutil@4.0.8)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-3d-generation: dependencies: @@ -990,7 +990,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1002,7 +1002,7 @@ importers: version: link:../core tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) viem: specifier: 2.21.53 version: 2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) @@ -1035,10 +1035,10 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1057,7 +1057,7 @@ importers: devDependencies: tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-bootstrap: dependencies: @@ -1066,7 +1066,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1097,7 +1097,7 @@ importers: version: 20.17.9 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-conflux: dependencies: @@ -1118,13 +1118,13 @@ importers: version: link:../plugin-trustdb tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) web3: specifier: ^4.15.0 version: 4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) web3-plugin-zksync: specifier: ^1.0.8 - version: 1.0.8(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + version: 1.0.8(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1157,7 +1157,7 @@ importers: version: 16.3.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) viem: specifier: 2.21.53 version: 2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) @@ -1172,7 +1172,7 @@ importers: version: 0.1.7-alpha.1(@google-cloud/vertexai@1.9.2(encoding@0.1.13))(@langchain/core@0.3.26(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)))(axios@1.7.9)(encoding@0.1.13)(react@18.3.1)(sswr@2.1.0(svelte@5.15.0))(svelte@5.15.0) tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) ws: specifier: ^8.18.0 version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -1231,10 +1231,10 @@ importers: version: 10.0.0 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) packages/plugin-fuel: dependencies: @@ -1246,13 +1246,13 @@ importers: version: 4.0.1 fuels: specifier: 0.97.2 - version: 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + version: 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1264,7 +1264,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-goat: dependencies: @@ -1285,7 +1285,7 @@ importers: version: 0.1.3(@goat-sdk/core@0.3.8(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10))(viem@2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) viem: specifier: 2.21.53 version: 2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) @@ -1319,7 +1319,7 @@ importers: version: 29.7.0(@types/node@22.10.2) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) typescript: specifier: 5.6.3 version: 5.6.3 @@ -1331,7 +1331,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1349,7 +1349,7 @@ importers: version: 1.0.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1376,10 +1376,10 @@ importers: version: 2.1.1 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) vitest: specifier: 2.1.5 - version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1406,7 +1406,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1451,7 +1451,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1632,7 +1632,7 @@ importers: version: 22.8.4 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-sgx: dependencies: @@ -1645,7 +1645,7 @@ importers: version: 20.17.9 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-solana: dependencies: @@ -1690,10 +1690,10 @@ importers: version: 1.3.2(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.29.1)(typescript@5.6.3)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1720,13 +1720,13 @@ importers: version: 6.18.0(encoding@0.1.13) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) unruggable-sdk: specifier: 1.4.0 version: 1.4.0(starknet@6.18.0(encoding@0.1.13)) vitest: specifier: 2.1.5 - version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1747,7 +1747,7 @@ importers: version: 1.2.0-rc.3(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) viem: specifier: 2.21.54 version: 2.21.54(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) @@ -1784,10 +1784,10 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) vitest: specifier: 2.1.4 - version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1823,7 +1823,7 @@ importers: version: 1.3.2(bufferutil@4.0.8)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(rollup@4.29.1)(typescript@5.6.3)(utf-8-validate@5.0.10) tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) viem: specifier: 2.21.53 version: 2.21.53(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) @@ -1854,7 +1854,7 @@ importers: version: 20.17.9 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-ton: dependencies: @@ -1881,7 +1881,7 @@ importers: version: 5.1.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1896,13 +1896,13 @@ importers: version: 3.2.2 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) uuid: specifier: 11.0.3 version: 11.0.3 vitest: specifier: 2.1.5 - version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + version: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1921,7 +1921,7 @@ importers: version: 0.0.17 tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) packages/plugin-video-generation: dependencies: @@ -1930,7 +1930,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1942,7 +1942,7 @@ importers: version: link:../core tsup: specifier: 8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -1970,10 +1970,10 @@ importers: version: 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.17.9) + version: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) ts-jest: specifier: 29.2.5 - version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9))(typescript@5.6.3) + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3) typescript: specifier: 5.6.3 version: 5.6.3 @@ -1988,13 +1988,13 @@ importers: version: link:../plugin-trustdb tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) web3: specifier: ^4.15.0 version: 4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) web3-plugin-zksync: specifier: ^1.0.8 - version: 1.0.8(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + version: 1.0.8(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) whatwg-url: specifier: 7.1.0 version: 7.1.0 @@ -22154,7 +22154,7 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/babel@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/babel@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: '@babel/core': 7.26.0 '@babel/generator': 7.26.3 @@ -22167,7 +22167,7 @@ snapshots: '@babel/runtime-corejs3': 7.26.0 '@babel/traverse': 7.26.4 '@docusaurus/logger': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) babel-plugin-dynamic-import-node: 2.3.3 fs-extra: 11.2.0 tslib: 2.8.1 @@ -22182,33 +22182,33 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/bundler@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/bundler@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: '@babel/core': 7.26.0 - '@docusaurus/babel': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/babel': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/cssnano-preset': 3.6.3 '@docusaurus/logger': 3.6.3 - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.97.1(@swc/core@1.10.1)) clean-css: 5.3.3 - copy-webpack-plugin: 11.0.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) - css-loader: 6.11.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) - css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + copy-webpack-plugin: 11.0.0(webpack@5.97.1(@swc/core@1.10.1)) + css-loader: 6.11.0(webpack@5.97.1(@swc/core@1.10.1)) + css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.97.1(@swc/core@1.10.1)) cssnano: 6.1.2(postcss@8.4.49) - file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1)) html-minifier-terser: 7.2.0 - mini-css-extract-plugin: 2.9.2(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) - null-loader: 4.0.1(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + mini-css-extract-plugin: 2.9.2(webpack@5.97.1(@swc/core@1.10.1)) + null-loader: 4.0.1(webpack@5.97.1(@swc/core@1.10.1)) postcss: 8.4.49 - postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + postcss-loader: 7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)) postcss-preset-env: 10.1.2(postcss@8.4.49) - react-dev-utils: 12.0.1(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) - terser-webpack-plugin: 5.3.11(@swc/core@1.10.1(@swc/helpers@0.5.15))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + react-dev-utils: 12.0.1(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.1)(webpack@5.97.1(@swc/core@1.10.1)) tslib: 2.8.1 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) - webpackbar: 6.0.1(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1)))(webpack@5.97.1(@swc/core@1.10.1)) + webpack: 5.97.1(@swc/core@1.10.1) + webpackbar: 6.0.1(webpack@5.97.1(@swc/core@1.10.1)) transitivePeerDependencies: - '@parcel/css' - '@rspack/core' @@ -22227,15 +22227,15 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/babel': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/bundler': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/babel': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/bundler': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@mdx-js/react': 3.0.1(@types/react@18.3.12)(react@18.3.1) boxen: 6.2.1 chalk: 4.1.2 @@ -22251,17 +22251,17 @@ snapshots: eval: 0.1.8 fs-extra: 11.2.0 html-tags: 3.3.1 - html-webpack-plugin: 5.6.3(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + html-webpack-plugin: 5.6.3(webpack@5.97.1(@swc/core@1.10.1)) leven: 3.1.0 lodash: 4.17.21 p-map: 4.0.0 prompts: 2.4.2 react: 18.3.1 - react-dev-utils: 12.0.1(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + react-dev-utils: 12.0.1(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)) react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' - react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.97.1(@swc/core@1.10.1)) react-router: 5.3.4(react@18.3.1) react-router-config: 5.1.1(react-router@5.3.4(react@18.3.1))(react@18.3.1) react-router-dom: 5.3.4(react@18.3.1) @@ -22271,9 +22271,9 @@ snapshots: shelljs: 0.8.5 tslib: 2.8.1 update-notifier: 6.0.2 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) webpack-bundle-analyzer: 4.10.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) - webpack-dev-server: 4.15.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + webpack-dev-server: 4.15.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)(webpack@5.97.1(@swc/core@1.10.1)) webpack-merge: 6.0.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -22307,26 +22307,26 @@ snapshots: chalk: 4.1.2 tslib: 2.8.1 - '@docusaurus/lqip-loader@3.6.3(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)))': + '@docusaurus/lqip-loader@3.6.3(webpack@5.97.1(@swc/core@1.10.1))': dependencies: '@docusaurus/logger': 3.6.3 - file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1)) lodash: 4.17.21 sharp: 0.32.6 tslib: 2.8.1 transitivePeerDependencies: - webpack - '@docusaurus/mdx-loader@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/mdx-loader@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: '@docusaurus/logger': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@mdx-js/mdx': 3.1.0(acorn@8.14.0) '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 estree-util-value-to-estree: 3.2.1 - file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1)) fs-extra: 11.2.0 image-size: 1.2.0 mdast-util-mdx: 3.0.0 @@ -22342,9 +22342,9 @@ snapshots: tslib: 2.8.1 unified: 11.0.5 unist-util-visit: 5.0.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1)))(webpack@5.97.1(@swc/core@1.10.1)) vfile: 6.0.3 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - '@swc/core' - acorn @@ -22354,9 +22354,9 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/module-type-aliases@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/module-type-aliases@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 '@types/react': 18.3.12 '@types/react-router-config': 5.0.11 @@ -22373,17 +22373,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-content-blog@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) cheerio: 1.0.0-rc.12 feed: 4.2.2 fs-extra: 11.2.0 @@ -22395,7 +22395,7 @@ snapshots: tslib: 2.8.1 unist-util-visit: 5.0.0 utility-types: 3.11.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -22417,17 +22417,17 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 fs-extra: 11.2.0 @@ -22437,7 +22437,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) tslib: 2.8.1 utility-types: 3.11.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -22459,18 +22459,18 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-pages@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-content-pages@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.8.1 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -22492,11 +22492,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-debug@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-debug@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -22523,11 +22523,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-analytics@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-google-analytics@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.8.1 @@ -22552,11 +22552,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-gtag@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-google-gtag@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@types/gtag.js': 0.0.12 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -22582,11 +22582,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-google-tag-manager@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tslib: 2.8.1 @@ -22611,21 +22611,21 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-ideal-image@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-ideal-image@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/lqip-loader': 3.6.3(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/lqip-loader': 3.6.3(webpack@5.97.1(@swc/core@1.10.1)) '@docusaurus/responsive-loader': 1.7.0(sharp@0.32.6) '@docusaurus/theme-translations': 3.6.3 - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@slorber/react-ideal-image': 0.0.12(prop-types@15.8.1)(react-waypoint@10.3.0(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-waypoint: 10.3.0(react@18.3.1) sharp: 0.32.6 tslib: 2.8.1 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -22648,14 +22648,14 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-sitemap@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/plugin-sitemap@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) fs-extra: 11.2.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -22682,21 +22682,21 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/preset-classic@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10)': - dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-debug': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-google-analytics': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-google-gtag': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-google-tag-manager': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-sitemap': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-classic': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/theme-search-algolia': 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/preset-classic@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10)': + dependencies: + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-debug': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-google-analytics': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-google-gtag': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-google-tag-manager': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-sitemap': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/theme-classic': 3.6.3(@swc/core@1.10.1)(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/theme-search-algolia': 3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: @@ -22734,21 +22734,21 @@ snapshots: optionalDependencies: sharp: 0.32.6 - '@docusaurus/theme-classic@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/theme-classic@3.6.3(@swc/core@1.10.1)(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/theme-translations': 3.6.3 - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@mdx-js/react': 3.0.1(@types/react@18.3.12)(react@18.3.1) clsx: 2.1.1 copy-text-to-clipboard: 3.2.0 @@ -22785,13 +22785,13 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: - '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/mdx-loader': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 '@types/react': 18.3.12 '@types/react-router-config': 5.0.11 @@ -22811,13 +22811,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-mermaid@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/theme-mermaid@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/module-type-aliases': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) mermaid: 11.4.1 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -22844,16 +22844,16 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-search-algolia@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10)': + '@docusaurus/theme-search-algolia@3.6.3(@algolia/client-search@5.18.0)(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(@types/react@18.3.12)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)(utf-8-validate@5.0.10)': dependencies: '@docsearch/react': 3.8.2(@algolia/client-search@5.18.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3) - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) '@docusaurus/logger': 3.6.3 - '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) - '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) '@docusaurus/theme-translations': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-validation': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) algoliasearch: 4.24.0 algoliasearch-helper: 3.22.6(algoliasearch@4.24.0) clsx: 2.1.1 @@ -22893,7 +22893,7 @@ snapshots: fs-extra: 11.2.0 tslib: 2.8.1 - '@docusaurus/types@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/types@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@mdx-js/mdx': 3.1.0(acorn@8.14.0) '@types/history': 4.7.11 @@ -22904,7 +22904,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-helmet-async: 1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) utility-types: 3.11.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) webpack-merge: 5.10.0 transitivePeerDependencies: - '@swc/core' @@ -22914,9 +22914,9 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/utils-common@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tslib: 2.8.1 transitivePeerDependencies: - '@swc/core' @@ -22928,11 +22928,11 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-validation@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/utils-validation@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: '@docusaurus/logger': 3.6.3 - '@docusaurus/utils': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) fs-extra: 11.2.0 joi: 17.13.3 js-yaml: 4.1.0 @@ -22949,14 +22949,14 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': + '@docusaurus/utils@3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)': dependencies: '@docusaurus/logger': 3.6.3 - '@docusaurus/types': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/types': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/utils-common': 3.6.3(@swc/core@1.10.1)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@svgr/webpack': 8.1.0(typescript@5.6.3) escape-string-regexp: 4.0.0 - file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1)) fs-extra: 11.2.0 github-slugger: 1.5.0 globby: 11.1.0 @@ -22969,9 +22969,9 @@ snapshots: resolve-pathname: 3.0.0 shelljs: 0.8.5 tslib: 2.8.1 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1)))(webpack@5.97.1(@swc/core@1.10.1)) utility-types: 3.11.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - '@swc/core' - acorn @@ -23749,23 +23749,23 @@ snapshots: '@floating-ui/utils@0.2.8': {} - '@fuel-ts/abi-coder@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/abi-coder@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 - '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) type-fest: 4.31.0 transitivePeerDependencies: - vitest - '@fuel-ts/abi-typegen@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/abi-typegen@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: '@fuel-ts/errors': 0.97.2 '@fuel-ts/interfaces': 0.97.2 - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/versions': 0.97.2 commander: 12.1.0 glob: 10.4.5 @@ -23776,18 +23776,18 @@ snapshots: transitivePeerDependencies: - vitest - '@fuel-ts/account@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/account@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 - '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/merkle': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/merkle': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/versions': 0.97.2 '@fuels/vm-asm': 0.58.2 '@noble/curves': 1.7.0 @@ -23800,30 +23800,30 @@ snapshots: - encoding - vitest - '@fuel-ts/address@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/address@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 '@fuel-ts/interfaces': 0.97.2 - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@noble/hashes': 1.6.1 bech32: 2.0.0 transitivePeerDependencies: - vitest - '@fuel-ts/contract@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/contract@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 - '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/merkle': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/merkle': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/versions': 0.97.2 '@fuels/vm-asm': 0.58.2 ramda: 0.30.1 @@ -23831,12 +23831,12 @@ snapshots: - encoding - vitest - '@fuel-ts/crypto@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/crypto@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: '@fuel-ts/errors': 0.97.2 '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@noble/hashes': 1.6.1 transitivePeerDependencies: - vitest @@ -23845,11 +23845,11 @@ snapshots: dependencies: '@fuel-ts/versions': 0.97.2 - '@fuel-ts/hasher@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/hasher@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@noble/hashes': 1.6.1 transitivePeerDependencies: - vitest @@ -23862,78 +23862,78 @@ snapshots: '@types/bn.js': 5.1.6 bn.js: 5.2.1 - '@fuel-ts/merkle@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/merkle@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/math': 0.97.2 transitivePeerDependencies: - vitest - '@fuel-ts/program@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/program@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuels/vm-asm': 0.58.2 ramda: 0.30.1 transitivePeerDependencies: - encoding - vitest - '@fuel-ts/recipes@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/recipes@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/abi-typegen': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/contract': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-typegen': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/contract': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 - '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) transitivePeerDependencies: - encoding - vitest - '@fuel-ts/script@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/script@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) transitivePeerDependencies: - encoding - vitest - '@fuel-ts/transactions@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/transactions@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 - '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) transitivePeerDependencies: - vitest - '@fuel-ts/utils@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@fuel-ts/utils@0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: '@fuel-ts/errors': 0.97.2 '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 '@fuel-ts/versions': 0.97.2 fflate: 0.8.2 - vitest: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + vitest: 2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) '@fuel-ts/versions@0.97.2': dependencies: @@ -24170,7 +24170,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -24184,7 +24184,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -24205,7 +24205,7 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -24219,7 +24219,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -24240,7 +24240,7 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -24254,7 +24254,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -24612,12 +24612,12 @@ snapshots: tslib: 2.8.1 zod: 3.23.8 - '@lerna/create@8.1.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(encoding@0.1.13)(typescript@5.6.3)': + '@lerna/create@8.1.5(@swc/core@1.10.1)(encoding@0.1.13)(typescript@5.6.3)': dependencies: '@npmcli/arborist': 7.5.3 '@npmcli/package-json': 5.2.0 '@npmcli/run-script': 8.1.0 - '@nx/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15))) + '@nx/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1)) '@octokit/plugin-enterprise-rest': 6.0.1 '@octokit/rest': 19.0.11(encoding@0.1.13) aproba: 2.0.0 @@ -24656,7 +24656,7 @@ snapshots: npm-package-arg: 11.0.2 npm-packlist: 8.0.2 npm-registry-fetch: 17.1.0 - nx: 19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)) + nx: 19.8.14(@swc/core@1.10.1) p-map: 4.0.0 p-map-series: 2.1.0 p-queue: 6.6.2 @@ -25613,15 +25613,15 @@ snapshots: - bluebird - supports-color - '@nrwl/devkit@19.8.14(nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)))': + '@nrwl/devkit@19.8.14(nx@19.8.14(@swc/core@1.10.1))': dependencies: - '@nx/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15))) + '@nx/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1)) transitivePeerDependencies: - nx - '@nrwl/tao@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15))': + '@nrwl/tao@19.8.14(@swc/core@1.10.1)': dependencies: - nx: 19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)) + nx: 19.8.14(@swc/core@1.10.1) tslib: 2.8.1 transitivePeerDependencies: - '@swc-node/register' @@ -25636,14 +25636,14 @@ snapshots: transitivePeerDependencies: - encoding - '@nx/devkit@19.8.14(nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)))': + '@nx/devkit@19.8.14(nx@19.8.14(@swc/core@1.10.1))': dependencies: - '@nrwl/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15))) + '@nrwl/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1)) ejs: 3.1.10 enquirer: 2.3.6 ignore: 5.3.2 minimatch: 9.0.3 - nx: 19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)) + nx: 19.8.14(@swc/core@1.10.1) semver: 7.6.3 tmp: 0.2.3 tslib: 2.8.1 @@ -26024,7 +26024,7 @@ snapshots: '@walletconnect/utils': 2.17.3(ioredis@5.4.2) postcss-cli: 11.0.0(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2) preact: 10.25.3 - tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -28899,7 +28899,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@2.1.5(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@vitest/coverage-v8@2.1.5(vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -28913,17 +28913,17 @@ snapshots: std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + vitest: 2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) transitivePeerDependencies: - supports-color - '@vitest/eslint-plugin@1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0))': + '@vitest/eslint-plugin@1.0.1(@typescript-eslint/utils@8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(vitest@2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0))': dependencies: eslint: 9.16.0(jiti@2.4.2) optionalDependencies: '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) typescript: 5.6.3 - vitest: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0) + vitest: 2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0) '@vitest/expect@2.1.4': dependencies: @@ -28955,6 +28955,14 @@ snapshots: optionalDependencies: vite: 5.4.11(@types/node@22.10.2)(terser@5.37.0) + '@vitest/mocker@2.1.5(vite@5.4.11(@types/node@22.8.4)(terser@5.37.0))': + dependencies: + '@vitest/spy': 2.1.5 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.11(@types/node@22.8.4)(terser@5.37.0) + '@vitest/pretty-format@2.1.4': dependencies: tinyrainbow: 1.2.0 @@ -30031,12 +30039,12 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.2.1(@babel/core@7.26.0)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + babel-loader@9.2.1(@babel/core@7.26.0)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.3.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) babel-messages@6.23.0: dependencies: @@ -31362,7 +31370,7 @@ snapshots: copy-text-to-clipboard@3.2.0: {} - copy-webpack-plugin@11.0.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + copy-webpack-plugin@11.0.0(webpack@5.97.1(@swc/core@1.10.1)): dependencies: fast-glob: 3.3.2 glob-parent: 6.0.2 @@ -31370,7 +31378,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.3.0 serialize-javascript: 6.0.2 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) core-js-compat@3.39.0: dependencies: @@ -31454,13 +31462,13 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)): + create-jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)): 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@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -31469,28 +31477,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.17.9): + create-jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)): 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@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - create-jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): - 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@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -31514,13 +31507,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + create-jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): 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.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -31602,7 +31595,7 @@ snapshots: postcss-selector-parser: 7.0.0 postcss-value-parser: 4.2.0 - css-loader@6.11.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + css-loader@6.11.0(webpack@5.97.1(@swc/core@1.10.1)): dependencies: icss-utils: 5.1.0(postcss@8.4.49) postcss: 8.4.49 @@ -31613,9 +31606,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) - css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@jridgewell/trace-mapping': 0.3.25 cssnano: 6.1.2(postcss@8.4.49) @@ -31623,7 +31616,7 @@ snapshots: postcss: 8.4.49 schema-utils: 4.3.0 serialize-javascript: 6.0.2 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) optionalDependencies: clean-css: 5.3.3 @@ -32297,9 +32290,9 @@ snapshots: dependencies: esutils: 2.0.3 - docusaurus-lunr-search@3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + docusaurus-lunr-search@3.5.0(@docusaurus/core@3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1(@swc/helpers@0.5.15))(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@docusaurus/core': 3.6.3(@mdx-js/react@3.0.1(@types/react@18.3.12)(react@18.3.1))(@swc/core@1.10.1)(acorn@8.14.0)(bufferutil@4.0.8)(eslint@9.16.0(jiti@2.4.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.3)(utf-8-validate@5.0.10) autocomplete.js: 0.37.1 clsx: 1.2.1 gauge: 3.0.2 @@ -33436,11 +33429,11 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) file-uri-to-path@1.0.0: {} @@ -33572,7 +33565,7 @@ snapshots: forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + fork-ts-checker-webpack-plugin@6.5.3(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@babel/code-frame': 7.26.2 '@types/json-schema': 7.0.15 @@ -33588,7 +33581,7 @@ snapshots: semver: 7.6.3 tapable: 1.1.3 typescript: 5.6.3 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) optionalDependencies: eslint: 9.16.0(jiti@2.4.2) @@ -33685,24 +33678,24 @@ snapshots: fsevents@2.3.3: optional: true - fuels@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)): + fuels@0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)): dependencies: - '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/abi-typegen': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/contract': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-coder': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/abi-typegen': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/account': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/address': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/contract': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/crypto': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/errors': 0.97.2 - '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/hasher': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/interfaces': 0.97.2 '@fuel-ts/math': 0.97.2 - '@fuel-ts/merkle': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/recipes': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/script': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) - '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/merkle': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/program': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/recipes': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/script': 0.97.2(encoding@0.1.13)(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/transactions': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) + '@fuel-ts/utils': 0.97.2(vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0)) '@fuel-ts/versions': 0.97.2 bundle-require: 5.1.0(esbuild@0.24.2) chalk: 4.1.2 @@ -34191,7 +34184,7 @@ snapshots: hard-rejection@2.1.0: {} - hardhat@2.22.17(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10): + hardhat@2.22.17(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 @@ -34238,7 +34231,7 @@ snapshots: uuid: 8.3.2 ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10) optionalDependencies: - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3) typescript: 5.6.3 transitivePeerDependencies: - bufferutil @@ -34543,7 +34536,7 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.3(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + html-webpack-plugin@5.6.3(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -34551,7 +34544,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) htmlescape@1.1.1: {} @@ -35338,35 +35331,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) - 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-cli@29.7.0(@types/node@20.17.9): + jest-cli@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.9) + create-jest: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35376,16 +35350,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + jest-cli@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + create-jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35397,7 +35371,7 @@ snapshots: jest-cli@29.7.0(@types/node@22.10.2): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 @@ -35414,16 +35388,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + jest-cli@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + create-jest: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-config: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -35433,7 +35407,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -35459,12 +35433,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 18.19.68 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -35490,12 +35464,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.17.9 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -35521,12 +35495,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.17.9 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -35552,7 +35526,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.17.9 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -35587,7 +35561,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + jest-config@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -35613,7 +35587,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.8.4 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -35839,36 +35813,24 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - jest@29.7.0(@types/node@20.17.9): + jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.9) + jest-cli: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)): + jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest-cli: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -35877,7 +35839,7 @@ snapshots: jest@29.7.0(@types/node@22.10.2): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) '@jest/types': 29.6.3 import-local: 3.2.0 jest-cli: 29.7.0(@types/node@22.10.2) @@ -35887,12 +35849,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest-cli: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -36231,13 +36193,13 @@ snapshots: leac@0.6.0: {} - lerna@8.1.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(encoding@0.1.13): + lerna@8.1.5(@swc/core@1.10.1)(encoding@0.1.13): dependencies: - '@lerna/create': 8.1.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(encoding@0.1.13)(typescript@5.6.3) + '@lerna/create': 8.1.5(@swc/core@1.10.1)(encoding@0.1.13)(typescript@5.6.3) '@npmcli/arborist': 7.5.3 '@npmcli/package-json': 5.2.0 '@npmcli/run-script': 8.1.0 - '@nx/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15))) + '@nx/devkit': 19.8.14(nx@19.8.14(@swc/core@1.10.1)) '@octokit/plugin-enterprise-rest': 6.0.1 '@octokit/rest': 19.0.11(encoding@0.1.13) aproba: 2.0.0 @@ -36282,7 +36244,7 @@ snapshots: npm-package-arg: 11.0.2 npm-packlist: 8.0.2 npm-registry-fetch: 17.1.0 - nx: 19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)) + nx: 19.8.14(@swc/core@1.10.1) p-map: 4.0.0 p-map-series: 2.1.0 p-pipe: 3.1.0 @@ -37379,11 +37341,11 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.9.2(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + mini-css-extract-plugin@2.9.2(webpack@5.97.1(@swc/core@1.10.1)): dependencies: schema-utils: 4.3.0 tapable: 2.2.1 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) minimalistic-assert@1.0.1: {} @@ -38038,18 +38000,18 @@ snapshots: dependencies: boolbase: 1.0.0 - null-loader@4.0.1(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + null-loader@4.0.1(webpack@5.97.1(@swc/core@1.10.1)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) nwsapi@2.2.16: {} - nx@19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)): + nx@19.8.14(@swc/core@1.10.1): dependencies: '@napi-rs/wasm-runtime': 0.2.4 - '@nrwl/tao': 19.8.14(@swc/core@1.10.1(@swc/helpers@0.5.15)) + '@nrwl/tao': 19.8.14(@swc/core@1.10.1) '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.0-rc.46 '@zkochan/js-yaml': 0.0.7 @@ -39087,13 +39049,13 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.4.49) postcss: 8.4.49 - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): dependencies: lilconfig: 3.1.3 yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 - ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3) + ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3) postcss-load-config@5.1.0(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2): dependencies: @@ -39113,13 +39075,13 @@ snapshots: tsx: 4.19.2 yaml: 2.6.1 - postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + postcss-loader@7.3.4(postcss@8.4.49)(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: cosmiconfig: 8.3.6(typescript@5.6.3) jiti: 1.21.7 postcss: 8.4.49 semver: 7.6.3 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - typescript @@ -39927,7 +39889,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dev-utils@12.0.1(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + react-dev-utils@12.0.1(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@babel/code-frame': 7.26.2 address: 1.2.2 @@ -39938,7 +39900,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3)(webpack@5.97.1(@swc/core@1.10.1)) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -39953,7 +39915,7 @@ snapshots: shell-quote: 1.8.2 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -39996,11 +39958,11 @@ snapshots: dependencies: react: 18.3.1 - react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@babel/runtime': 7.26.0 react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) react-refresh@0.14.2: {} @@ -41565,11 +41527,11 @@ snapshots: tailwind-merge@2.5.5: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3))): dependencies: - tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) - tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)): + tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -41588,7 +41550,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.10 @@ -41663,14 +41625,14 @@ snapshots: temp-dir@1.0.0: {} - terser-webpack-plugin@5.3.11(@swc/core@1.10.1(@swc/helpers@0.5.15))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + terser-webpack-plugin@5.3.11(@swc/core@1.10.1)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.37.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.15) @@ -41889,12 +41851,12 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3)) + jest: 29.7.0(@types/node@20.17.9)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -41909,12 +41871,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.0) esbuild: 0.24.2 - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3)) + jest: 29.7.0(@types/node@18.19.68)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -41928,31 +41890,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.0) - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.9))(typescript@5.6.3): + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.9) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.6.3 - typescript: 5.6.3 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.26.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.0) - - ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)))(typescript@5.6.3): - dependencies: - bs-logger: 0.2.6 - ejs: 3.1.10 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3)) + jest: 29.7.0(@types/node@22.8.4)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -41968,7 +41911,7 @@ snapshots: ts-mixer@6.0.4: {} - ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@18.19.68)(typescript@5.6.3): + ts-node@10.9.2(@swc/core@1.10.1)(@types/node@18.19.68)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -41988,7 +41931,7 @@ snapshots: optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@20.17.9)(typescript@5.6.3): + ts-node@10.9.2(@swc/core@1.10.1)(@types/node@20.17.9)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -42008,7 +41951,7 @@ snapshots: optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.15) - ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3): + ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -42029,7 +41972,7 @@ snapshots: '@swc/core': 1.10.1(@swc/helpers@0.5.15) optional: true - ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.8.4)(typescript@5.6.3): + ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.8.4)(typescript@5.6.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -42069,7 +42012,7 @@ snapshots: tsscmp@1.0.6: {} - tsup@8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1): + tsup@8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1): dependencies: bundle-require: 5.1.0(esbuild@0.24.2) cac: 6.7.14 @@ -42570,14 +42513,14 @@ snapshots: url-join@4.0.1: {} - url-loader@4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.97.1(@swc/core@1.10.1)))(webpack@5.97.1(@swc/core@1.10.1)): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) optionalDependencies: - file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + file-loader: 6.2.0(webpack@5.97.1(@swc/core@1.10.1)) url-parse@1.5.10: dependencies: @@ -42865,7 +42808,7 @@ snapshots: fsevents: 2.3.3 terser: 5.37.0 - vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + vitest@2.1.4(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0): dependencies: '@vitest/expect': 2.1.4 '@vitest/mocker': 2.1.4(vite@5.4.11(@types/node@22.10.2)(terser@5.37.0)) @@ -42901,7 +42844,7 @@ snapshots: - supports-color - terser - vitest@2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + vitest@2.1.5(@types/node@22.10.2)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0): dependencies: '@vitest/expect': 2.1.5 '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@22.10.2)(terser@5.37.0)) @@ -42937,10 +42880,10 @@ snapshots: - supports-color - terser - vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10))(terser@5.37.0): + vitest@2.1.5(@types/node@22.8.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10))(terser@5.37.0): dependencies: '@vitest/expect': 2.1.5 - '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@22.10.2)(terser@5.37.0)) + '@vitest/mocker': 2.1.5(vite@5.4.11(@types/node@22.8.4)(terser@5.37.0)) '@vitest/pretty-format': 2.1.8 '@vitest/runner': 2.1.5 '@vitest/snapshot': 2.1.5 @@ -43188,10 +43131,10 @@ snapshots: - encoding - utf-8-validate - web3-plugin-zksync@1.0.8(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)): + web3-plugin-zksync@1.0.8(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10)(web3@4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)): dependencies: ethereum-cryptography: 2.2.1 - hardhat: 2.22.17(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.15))(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10) + hardhat: 2.22.17(bufferutil@4.0.8)(ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.10.2)(typescript@5.6.3))(typescript@5.6.3)(utf-8-validate@5.0.10) web3: 4.16.0(bufferutil@4.0.8)(encoding@0.1.13)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) transitivePeerDependencies: - bufferutil @@ -43333,16 +43276,16 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@5.3.4(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + webpack-dev-middleware@5.3.4(webpack@5.97.1(@swc/core@1.10.1)): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.3.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) - webpack-dev-server@4.15.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + webpack-dev-server@4.15.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)(webpack@5.97.1(@swc/core@1.10.1)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -43372,10 +43315,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + webpack-dev-middleware: 5.3.4(webpack@5.97.1(@swc/core@1.10.1)) ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) transitivePeerDependencies: - bufferutil - debug @@ -43396,7 +43339,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)): + webpack@5.97.1(@swc/core@1.10.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -43418,7 +43361,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.10.1(@swc/helpers@0.5.15))(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.1)(webpack@5.97.1(@swc/core@1.10.1)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -43426,7 +43369,7 @@ snapshots: - esbuild - uglify-js - webpackbar@6.0.1(webpack@5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15))): + webpackbar@6.0.1(webpack@5.97.1(@swc/core@1.10.1)): dependencies: ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -43435,7 +43378,7 @@ snapshots: markdown-table: 2.0.0 pretty-time: 1.1.0 std-env: 3.8.0 - webpack: 5.97.1(@swc/core@1.10.1(@swc/helpers@0.5.15)) + webpack: 5.97.1(@swc/core@1.10.1) wrap-ansi: 7.0.0 websocket-driver@0.7.4: From f3b4f7599a8aa5777a2a05259af3563e9c6455d3 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Tue, 31 Dec 2024 07:01:50 +0000 Subject: [PATCH 012/112] update plugin-sgx README --- packages/plugin-sgx/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/plugin-sgx/README.md b/packages/plugin-sgx/README.md index 4eb05e0e96d..32007bd7b3a 100644 --- a/packages/plugin-sgx/README.md +++ b/packages/plugin-sgx/README.md @@ -85,8 +85,6 @@ npm install -g pnpm # Build Eliza pnpm i -# The build may fail on the first attempt due to the missing `plugin-tee` dependency in `plugin-tee-log`. Simply run the build command again to resolve the issue. -# TODO: fix the build issue pnpm build # Copy the .env.example file to .env From 9c5060a8d91210fb0fbcad236acbde47cc03f770 Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Tue, 31 Dec 2024 07:58:14 +0000 Subject: [PATCH 013/112] update packge verison --- packages/plugin-evm/package.json | 2 +- packages/plugin-ferePro/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/plugin-evm/package.json b/packages/plugin-evm/package.json index ce1c38085cf..ad14a009378 100644 --- a/packages/plugin-evm/package.json +++ b/packages/plugin-evm/package.json @@ -1,6 +1,6 @@ { "name": "@elizaos/plugin-evm", - "version": "0.1.7-alpha.1", + "version": "0.1.7-alpha.2", "main": "dist/index.js", "type": "module", "types": "dist/index.d.ts", diff --git a/packages/plugin-ferePro/package.json b/packages/plugin-ferePro/package.json index c65e8e429f3..3aea29b6d86 100644 --- a/packages/plugin-ferePro/package.json +++ b/packages/plugin-ferePro/package.json @@ -5,7 +5,7 @@ "type": "module", "types": "dist/index.d.ts", "dependencies": { - "@elizaos/core": "^0.1.7-alpha.1", + "@elizaos/core": "^0.1.7-alpha.2", "tsup": "^8.3.5", "ws": "^8.18.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3880c27a98c..452d183dd3c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1168,8 +1168,8 @@ importers: packages/plugin-ferePro: dependencies: '@elizaos/core': - specifier: ^0.1.7-alpha.1 - version: 0.1.7-alpha.1(@google-cloud/vertexai@1.9.2(encoding@0.1.13))(@langchain/core@0.3.26(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)))(axios@1.7.9)(encoding@0.1.13)(react@18.3.1)(sswr@2.1.0(svelte@5.15.0))(svelte@5.15.0) + specifier: ^0.1.7-alpha.2 + version: 0.1.7-alpha.2(@google-cloud/vertexai@1.9.2(encoding@0.1.13))(@langchain/core@0.3.26(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)))(axios@1.7.9)(encoding@0.1.13)(react@18.3.1)(sswr@2.1.0(svelte@5.15.0))(svelte@5.15.0) tsup: specifier: ^8.3.5 version: 8.3.5(@swc/core@1.10.1)(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) @@ -3914,8 +3914,8 @@ packages: peerDependencies: onnxruntime-node: 1.20.1 - '@elizaos/core@0.1.7-alpha.1': - resolution: {integrity: sha512-7Sq+ta7kKoZLgzx//DXeRK/SLVLdVo6DCRgv16B+i726HBEfh96gTLeB9J0S58tnGzJg2mkouvakwt16ETmAoQ==} + '@elizaos/core@0.1.7-alpha.2': + resolution: {integrity: sha512-gNvFw/Xnv4dlcfmmKxRa+baKq6en4TitAjUGvo8LgAUkSk156A0fffJ0lAsc1rX8zMB5NsIqdvMCbwKxDd54OQ==} '@emnapi/core@1.3.1': resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} @@ -23014,7 +23014,7 @@ snapshots: '@huggingface/jinja': 0.2.2 onnxruntime-node: 1.20.1 - '@elizaos/core@0.1.7-alpha.1(@google-cloud/vertexai@1.9.2(encoding@0.1.13))(@langchain/core@0.3.26(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)))(axios@1.7.9)(encoding@0.1.13)(react@18.3.1)(sswr@2.1.0(svelte@5.15.0))(svelte@5.15.0)': + '@elizaos/core@0.1.7-alpha.2(@google-cloud/vertexai@1.9.2(encoding@0.1.13))(@langchain/core@0.3.26(openai@4.73.0(encoding@0.1.13)(zod@3.23.8)))(axios@1.7.9)(encoding@0.1.13)(react@18.3.1)(sswr@2.1.0(svelte@5.15.0))(svelte@5.15.0)': dependencies: '@ai-sdk/anthropic': 0.0.56(zod@3.23.8) '@ai-sdk/google': 0.0.55(zod@3.23.8) From 4ed692cc75fca72505f34cdb1f326d7ddb7112db Mon Sep 17 00:00:00 2001 From: Stuart Wang Date: Tue, 31 Dec 2024 08:15:01 +0000 Subject: [PATCH 014/112] fix build order through turbo --- turbo.json | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/turbo.json b/turbo.json index 2f404476cbb..b973de83b1d 100644 --- a/turbo.json +++ b/turbo.json @@ -14,14 +14,35 @@ "outputs": ["dist/**"], "dependsOn": ["^@elizaos/core#build"] }, + "@elizaos/client-direct#build": { + "outputs": ["dist/**"], + "dependsOn": [ + "@elizaos/plugin-image-generation#build", + "@elizaos/plugin-tee-log#build" + ] + }, "@elizaos/plugin-solana#build": { "outputs": ["dist/**"], - "dependsOn": ["@elizaos/plugin-trustdb#build"] + "dependsOn": [ + "@elizaos/plugin-trustdb#build", + "@elizaos/plugin-tee#build" + ] }, "@elizaos/plugin-nft-generation#build": { "outputs": ["dist/**"], "dependsOn": ["@elizaos/plugin-node#build"] }, + "@elizaos/plugin-evm#build": { + "outputs": ["dist/**"], + "dependsOn": ["@elizaos/plugin-tee#build"] + }, + "@elizaos/plugin-tee-log#build": { + "outputs": ["dist/**"], + "dependsOn": [ + "@elizaos/plugin-tee#build", + "@elizaos/plugin-sgx#build" + ] + }, "eliza-docs#build": { "outputs": ["build/**"] }, From e69aeca365e173f3c5176c1661c6e0635008ad75 Mon Sep 17 00:00:00 2001 From: JSon Date: Fri, 20 Dec 2024 22:43:17 +0800 Subject: [PATCH 015/112] feat(plugin-nft-generation): add mint NFT with collection address action --- .../src/actions/mintNFTAction.ts | 381 ++++++++++++++++++ .../src/actions/nftCollectionGeneration.ts | 290 +++++++++++++ packages/plugin-nft-generation/src/index.ts | 189 +-------- .../src/provider/wallet/walletSolana.ts | 4 + 4 files changed, 679 insertions(+), 185 deletions(-) create mode 100644 packages/plugin-nft-generation/src/actions/mintNFTAction.ts create mode 100644 packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts new file mode 100644 index 00000000000..15515337159 --- /dev/null +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -0,0 +1,381 @@ +import { + Action, + composeContext, + Content, + elizaLogger, + generateObjectDeprecated, + getEmbeddingZeroVector, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + stringToUuid, +} from "@ai16z/eliza"; +import { createNFT } from "../handlers/createNFT.ts"; +import { verifyNFT } from "../handlers/verifyNFT.ts"; +import { sleep } from "../index.ts"; +import WalletSolana from "../provider/wallet/walletSolana.ts"; +import { PublicKey } from "@solana/web3.js"; + +const mintTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. + +Example response: +\`\`\`json +{ + "collectionAddress": "D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", +} +\`\`\` + +{{message}} + +Given the recent messages, extract the following information about the requested mint nft: +- collection contract address + +Respond with a JSON markdown block containing only the extracted values.`; + +export interface MintContent extends Content { + collectionAddress: string; +} + +function isMintNFTContent( + runtime: IAgentRuntime, + content: any +): content is MintContent { + console.log("Content for mint", content); + return typeof content.collectionAddress === "string"; +} + +const mintNFTAction: Action = { + name: "MINT_NFT", + similes: [ + "NFT_MINTING", + "NFT_CREATION", + "CREATE_NFT", + "GENERATE_NFT", + "MINT_TOKEN", + "CREATE_TOKEN", + "MAKE_NFT", + "TOKEN_GENERATION", + ], + description: "Mint NFTs for the collection", + validate: async (runtime: IAgentRuntime, _message: Memory) => { + const AwsAccessKeyIdOk = !!runtime.getSetting("AWS_ACCESS_KEY_ID"); + const AwsSecretAccessKeyOk = !!runtime.getSetting( + "AWS_SECRET_ACCESS_KEY" + ); + const AwsRegionOk = !!runtime.getSetting("AWS_REGION"); + const AwsS3BucketOk = !!runtime.getSetting("AWS_S3_BUCKET"); + + return ( + AwsAccessKeyIdOk || + AwsSecretAccessKeyOk || + AwsRegionOk || + AwsS3BucketOk + ); + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: { [key: string]: unknown }, + callback: HandlerCallback + ) => { + try { + elizaLogger.log("Composing state for message:", message); + const userId = runtime.agentId; + const agentName = runtime.character.name; + const roomId = stringToUuid("nft_generate_room-" + agentName); + + const memory: Memory = { + agentId: userId, + userId, + roomId, + content: { + text: message.content.text, + source: "nft-generator", + }, + createdAt: Date.now(), + embedding: getEmbeddingZeroVector(), + }; + const state = await runtime.composeState(memory, { + message: message.content.text, + }); + + elizaLogger.log("state:", state); + + // Compose transfer context + const transferContext = composeContext({ + state, + template: mintTemplate, + }); + + const content = await generateObjectDeprecated({ + runtime, + context: transferContext, + modelClass: ModelClass.LARGE, + }); + + elizaLogger.log("generateObjectDeprecated:", transferContext); + + if (!isMintNFTContent(runtime, content)) { + elizaLogger.error("Invalid content for MINT_NFT action."); + if (callback) { + callback({ + text: "Unable to process mint request. Invalid content provided.", + content: { error: "Invalid mint content" }, + }); + } + return false; + } + + elizaLogger.log("mint content", content); + + const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); + const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); + + const wallet = new WalletSolana( + new PublicKey(publicKey), + privateKey + ); + + const collectionInfo = await wallet.fetchDigitalAsset( + content.collectionAddress + ); + elizaLogger.log("Collection Info", collectionInfo); + const metadata = collectionInfo.metadata; + if (metadata.collection?.["value"]) { + callback({ + text: `Unable to process mint request. Invalid collection address ${content.collectionAddress}.`, + content: { error: "Invalid collection address." }, + }); + return false; + } + if (metadata) { + elizaLogger.log("nft params", {}); + const nftRes = await createNFT({ + runtime, + collectionName: metadata.name, + collectionAddress: content.collectionAddress, + collectionAdminPublicKey: metadata.updateAuthority, + collectionFee: metadata.sellerFeeBasisPoints, + tokenId: 1, + }); + + elizaLogger.log("NFT Address:", nftRes); + + if (nftRes) { + callback({ + text: `Congratulations to you! 🎉🎉🎉 \nCollection Address: ${content.collectionAddress}\n NFT Address: ${nftRes.address}\n NFT Link: ${nftRes.link}`, //caption.description, + attachments: [], + }); + await sleep(15000); + await verifyNFT({ + runtime, + collectionAddress: content.collectionAddress, + NFTAddress: nftRes.address, + }); + } else { + callback({ + text: `Mint NFT Error in ${content.collectionAddress}.`, + content: { error: "Mint NFT Error." }, + }); + return false; + } + } else { + callback({ + text: "Unable to process mint request. Invalid collection address.", + content: { error: "Invalid collection address." }, + }); + return false; + } + + // + // const userId = runtime.agentId; + // elizaLogger.log("User ID:", userId); + // + // const collectionAddressRes = await createCollection({ + // runtime, + // collectionName: runtime.character.name, + // }); + // + // const collectionInfo = collectionAddressRes.collectionInfo; + // + // elizaLogger.log("Collection Address:", collectionAddressRes); + + // + // elizaLogger.log("NFT Address:", nftRes); + // + // + // callback({ + // text: `Congratulations to you! 🎉🎉🎉 \nCollection : ${collectionAddressRes.link}\n NFT: ${nftRes.link}`, //caption.description, + // attachments: [], + // }); + // await sleep(15000); + // await verifyNFT({ + // runtime, + // collectionAddress: collectionAddressRes.address, + // NFTAddress: nftRes.address, + // }); + return []; + } catch (e: any) { + console.log(e); + } + + // callback(); + }, + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "mint nft for collection: D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've minted a new NFT in your specified collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Could you create an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Successfully minted your NFT in the specified collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Please mint a new token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Your NFT has been minted in the collection successfully.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Generate NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've generated and minted your NFT in the collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "I want to mint an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Your NFT has been successfully minted in the collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Create a new NFT token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection", + }, + }, + { + user: "{{agentName}}", + content: { + text: "The NFT has been created in your specified collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Issue an NFT for collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've issued your NFT in the requested collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Make a new NFT in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Your new NFT has been minted in the collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Can you mint an NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've completed minting your NFT in the collection.", + action: "MINT_NFT", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Add a new NFT to collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + }, + }, + { + user: "{{agentName}}", + content: { + text: "A new NFT has been added to your collection.", + action: "MINT_NFT", + }, + }, + ], + ], +} as Action; + +export default mintNFTAction; diff --git a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts new file mode 100644 index 00000000000..9973d734076 --- /dev/null +++ b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts @@ -0,0 +1,290 @@ +import { + Action, + elizaLogger, + HandlerCallback, + IAgentRuntime, + Memory, + State, +} from "@ai16z/eliza"; +import { createCollection } from "../handlers/createCollection.ts"; + +const nftCollectionGeneration: Action = { + name: "GENERATE_COLLECTION", + similes: [ + "COLLECTION_GENERATION", + "COLLECTION_GEN", + "CREATE_COLLECTION", + "MAKE_COLLECTION", + "GENERATE_COLLECTION", + ], + description: "Generate an NFT collection for the message", + validate: async (runtime: IAgentRuntime, _message: Memory) => { + const awsAccessKeyIdOk = !!runtime.getSetting("AWS_ACCESS_KEY_ID"); + const awsSecretAccessKeyOk = !!runtime.getSetting( + "AWS_SECRET_ACCESS_KEY" + ); + const awsRegionOk = !!runtime.getSetting("AWS_REGION"); + const awsS3BucketOk = !!runtime.getSetting("AWS_S3_BUCKET"); + const solanaPrivateKeyOk = !!runtime.getSetting("SOLANA_PRIVATE_KEY"); + const solanaPublicKeyOk = !!runtime.getSetting("SOLANA_PUBLIC_KEY"); + + return ( + awsAccessKeyIdOk || + awsSecretAccessKeyOk || + awsRegionOk || + awsS3BucketOk || + solanaPrivateKeyOk || + solanaPublicKeyOk + ); + }, + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + options: { [key: string]: unknown }, + callback: HandlerCallback + ) => { + try { + elizaLogger.log("Composing state for message:", message); + const collectionAddressRes = await createCollection({ + runtime, + collectionName: runtime.character.name, + }); + elizaLogger.log("Collection Info:", collectionAddressRes); + if (callback) { + callback({ + text: `Congratulations to you! 🎉🎉🎉 \nCollection Link : ${collectionAddressRes.link}\n Address: ${collectionAddressRes.address}`, //caption.description, + attachments: [], + }); + } + return []; + } catch (e: any) { + console.log(e); + throw e; + } + }, + examples: [ + [ + { + user: "{{user1}}", + content: { text: "Generate a collection" }, + }, + { + user: "{{agentName}}", + content: { + text: "Here's the collection you requested.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Generate a collection using {{agentName}}" }, + }, + { + user: "{{agentName}}", + content: { + text: "We've successfully created a collection.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Create a collection using {{agentName}}" }, + }, + { + user: "{{agentName}}", + content: { + text: "Here's the collection you requested.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Build a Collection" }, + }, + { + user: "{{agentName}}", + content: { + text: "The collection has been successfully built.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Assemble a collection with {{agentName}}" }, + }, + { + user: "{{agentName}}", + content: { + text: "The collection has been assembled", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Make a collection" }, + }, + { + user: "{{agentName}}", + content: { + text: "The collection has been produced successfully.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Could you create a new collection for my photos?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've created a new collection for your photos.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "I need a collection for organizing my music", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Your music collection has been generated.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Please set up a collection for my documents", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've set up a new collection for your documents.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Start a new collection for me" }, + }, + { + user: "{{agentName}}", + content: { + text: "Your new collection has been created.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "I'd like to make a collection of my recipes", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've generated a collection for your recipes.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Can you generate a collection for my artwork?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "Your artwork collection has been generated.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Initialize a new collection please" }, + }, + { + user: "{{agentName}}", + content: { + text: "I've initialized a new collection for you.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Create a collection for my travel memories" }, + }, + { + user: "{{agentName}}", + content: { + text: "Your travel memories collection has been created.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Would you make a collection for my projects?", + }, + }, + { + user: "{{agentName}}", + content: { + text: "I've made a collection for your projects.", + action: "GENERATE_COLLECTION", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { text: "Set up a collection for my bookmarks" }, + }, + { + user: "{{agentName}}", + content: { + text: "Your bookmarks collection has been set up.", + action: "GENERATE_COLLECTION", + }, + }, + ], + ], +} as Action; + +export default nftCollectionGeneration; diff --git a/packages/plugin-nft-generation/src/index.ts b/packages/plugin-nft-generation/src/index.ts index 07a147ef0d6..5540ec3a5b7 100644 --- a/packages/plugin-nft-generation/src/index.ts +++ b/packages/plugin-nft-generation/src/index.ts @@ -1,16 +1,6 @@ -import { - Action, - elizaLogger, - HandlerCallback, - IAgentRuntime, - Memory, - Plugin, - State, -} from "@elizaos/core"; - -import { createCollection } from "./handlers/createCollection.ts"; -import { createNFT } from "./handlers/createNFT.ts"; -import { verifyNFT } from "./handlers/verifyNFT.ts"; +import { Plugin } from "@ai16z/eliza"; +import nftCollectionGeneration from "./actions/nftCollectionGeneration.ts"; +import mintNFTAction from "./actions/mintNFTAction.ts"; export * from "./provider/wallet/walletSolana.ts"; export * from "./api.ts"; @@ -21,181 +11,10 @@ export async function sleep(ms: number = 3000) { }); } -const nftCollectionGeneration: Action = { - name: "GENERATE_COLLECTION", - similes: [ - "COLLECTION_GENERATION", - "COLLECTION_GEN", - "CREATE_COLLECTION", - "MAKE_COLLECTION", - "GENERATE_COLLECTION", - ], - description: "Generate an NFT collection for the message", - validate: async (runtime: IAgentRuntime, _message: Memory) => { - const AwsAccessKeyIdOk = !!runtime.getSetting("AWS_ACCESS_KEY_ID"); - const AwsSecretAccessKeyOk = !!runtime.getSetting( - "AWS_SECRET_ACCESS_KEY" - ); - const AwsRegionOk = !!runtime.getSetting("AWS_REGION"); - const AwsS3BucketOk = !!runtime.getSetting("AWS_S3_BUCKET"); - - return ( - AwsAccessKeyIdOk || - AwsSecretAccessKeyOk || - AwsRegionOk || - AwsS3BucketOk - ); - }, - handler: async ( - runtime: IAgentRuntime, - message: Memory, - state: State, - options: { [key: string]: unknown }, - callback: HandlerCallback - ) => { - try { - elizaLogger.log("Composing state for message:", message); - const userId = runtime.agentId; - elizaLogger.log("User ID:", userId); - - const collectionAddressRes = await createCollection({ - runtime, - collectionName: runtime.character.name, - }); - - const collectionInfo = collectionAddressRes.collectionInfo; - - elizaLogger.log("Collection Address:", collectionAddressRes); - - const nftRes = await createNFT({ - runtime, - collectionName: collectionInfo.name, - collectionAddress: collectionAddressRes.address, - collectionAdminPublicKey: collectionInfo.adminPublicKey, - collectionFee: collectionInfo.fee, - tokenId: 1, - }); - - elizaLogger.log("NFT Address:", nftRes); - - callback({ - text: `Congratulations to you! 🎉🎉🎉 \nCollection : ${collectionAddressRes.link}\n NFT: ${nftRes.link}`, //caption.description, - attachments: [], - }); - await sleep(15000); - await verifyNFT({ - runtime, - collectionAddress: collectionAddressRes.address, - NFTAddress: nftRes.address, - }); - return []; - } catch (e: any) { - console.log(e); - } - - // callback(); - }, - examples: [ - // TODO: We want to generate images in more abstract ways, not just when asked to generate an image - - [ - { - user: "{{user1}}", - content: { text: "Generate a collection" }, - }, - { - user: "{{agentName}}", - content: { - text: "Here's the collection you requested.", - action: "GENERATE_COLLECTION", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { text: "Generate a collection using {{agentName}}" }, - }, - { - user: "{{agentName}}", - content: { - text: "We've successfully created a collection.", - action: "GENERATE_COLLECTION", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { text: "Create a collection using {{agentName}}" }, - }, - { - user: "{{agentName}}", - content: { - text: "Here's the collection you requested.", - action: "GENERATE_COLLECTION", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { text: "Build a Collection" }, - }, - { - user: "{{agentName}}", - content: { - text: "The collection has been successfully built.", - action: "GENERATE_COLLECTION", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { text: "Assemble a collection with {{agentName}}" }, - }, - { - user: "{{agentName}}", - content: { - text: "The collection has been assembled", - action: "GENERATE_COLLECTION", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { text: "Make a collection" }, - }, - { - user: "{{agentName}}", - content: { - text: "The collection has been produced successfully.", - action: "GENERATE_COLLECTION", - }, - }, - ], - [ - { - user: "{{user1}}", - content: { text: "Compile a collection" }, - }, - { - user: "{{agentName}}", - content: { - text: "The collection has been compiled.", - action: "GENERATE_COLLECTION", - }, - }, - ], - ], -} as Action; - export const nftGenerationPlugin: Plugin = { name: "nftCollectionGeneration", description: "Generate NFT Collections", - actions: [nftCollectionGeneration], + actions: [nftCollectionGeneration, mintNFTAction], evaluators: [], providers: [], }; diff --git a/packages/plugin-nft-generation/src/provider/wallet/walletSolana.ts b/packages/plugin-nft-generation/src/provider/wallet/walletSolana.ts index 2bfeb85ca67..74a605c9c2b 100644 --- a/packages/plugin-nft-generation/src/provider/wallet/walletSolana.ts +++ b/packages/plugin-nft-generation/src/provider/wallet/walletSolana.ts @@ -10,6 +10,7 @@ import { createNft, findMetadataPda, mplTokenMetadata, + fetchDigitalAsset, updateV1, verifyCollectionV1, } from "@metaplex-foundation/mpl-token-metadata"; @@ -55,6 +56,9 @@ export class WalletSolana { this.umi = umi; } + async fetchDigitalAsset (address: string) { + return fetchDigitalAsset(this.umi, publicKey(address)) + } async getBalance() { const balance = await this.connection.getBalance(this.walletPublicKey); return { From 13b3fb11e90b880655fa68cd3769c5201d220dbb Mon Sep 17 00:00:00 2001 From: JSon Date: Fri, 20 Dec 2024 23:00:40 +0800 Subject: [PATCH 016/112] feat(plugin-nft-generation): change mintTemplate. --- .../src/actions/mintNFTAction.ts | 70 +++++++------------ 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts index 15515337159..a2a026a3aa1 100644 --- a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -27,12 +27,15 @@ Example response: } \`\`\` -{{message}} +{{recentMessages}} Given the recent messages, extract the following information about the requested mint nft: - collection contract address -Respond with a JSON markdown block containing only the extracted values.`; +Respond with a JSON markdown block containing only the extracted values. + +Note: Make sure to extract the collection address from the most recent messages whenever possible.` + export interface MintContent extends Content { collectionAddress: string; @@ -87,22 +90,25 @@ const mintNFTAction: Action = { const agentName = runtime.character.name; const roomId = stringToUuid("nft_generate_room-" + agentName); - const memory: Memory = { - agentId: userId, - userId, - roomId, - content: { - text: message.content.text, - source: "nft-generator", - }, - createdAt: Date.now(), - embedding: getEmbeddingZeroVector(), - }; - const state = await runtime.composeState(memory, { - message: message.content.text, - }); - - elizaLogger.log("state:", state); + // const memory: Memory = { + // agentId: userId, + // userId, + // roomId, + // content: { + // text: message.content.text, + // source: "nft-generator", + // }, + // createdAt: Date.now(), + // embedding: getEmbeddingZeroVector(), + // }; + // const state = await runtime.composeState(memory, { + // message: message.content.text, + // }); + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } // Compose transfer context const transferContext = composeContext({ @@ -189,34 +195,6 @@ const mintNFTAction: Action = { }); return false; } - - // - // const userId = runtime.agentId; - // elizaLogger.log("User ID:", userId); - // - // const collectionAddressRes = await createCollection({ - // runtime, - // collectionName: runtime.character.name, - // }); - // - // const collectionInfo = collectionAddressRes.collectionInfo; - // - // elizaLogger.log("Collection Address:", collectionAddressRes); - - // - // elizaLogger.log("NFT Address:", nftRes); - // - // - // callback({ - // text: `Congratulations to you! 🎉🎉🎉 \nCollection : ${collectionAddressRes.link}\n NFT: ${nftRes.link}`, //caption.description, - // attachments: [], - // }); - // await sleep(15000); - // await verifyNFT({ - // runtime, - // collectionAddress: collectionAddressRes.address, - // NFTAddress: nftRes.address, - // }); return []; } catch (e: any) { console.log(e); From 2c7c7ea22647e20c4048dd5d1349775d6fb415d8 Mon Sep 17 00:00:00 2001 From: JSon Date: Fri, 20 Dec 2024 23:08:32 +0800 Subject: [PATCH 017/112] chore --- .../src/actions/mintNFTAction.ts | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts index a2a026a3aa1..ecb8a47d619 100644 --- a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -4,13 +4,11 @@ import { Content, elizaLogger, generateObjectDeprecated, - getEmbeddingZeroVector, HandlerCallback, IAgentRuntime, Memory, ModelClass, State, - stringToUuid, } from "@ai16z/eliza"; import { createNFT } from "../handlers/createNFT.ts"; import { verifyNFT } from "../handlers/verifyNFT.ts"; @@ -34,8 +32,7 @@ Given the recent messages, extract the following information about the requested Respond with a JSON markdown block containing only the extracted values. -Note: Make sure to extract the collection address from the most recent messages whenever possible.` - +Note: Make sure to extract the collection address from the most recent messages whenever possible.`; export interface MintContent extends Content { collectionAddress: string; @@ -86,24 +83,6 @@ const mintNFTAction: Action = { ) => { try { elizaLogger.log("Composing state for message:", message); - const userId = runtime.agentId; - const agentName = runtime.character.name; - const roomId = stringToUuid("nft_generate_room-" + agentName); - - // const memory: Memory = { - // agentId: userId, - // userId, - // roomId, - // content: { - // text: message.content.text, - // source: "nft-generator", - // }, - // createdAt: Date.now(), - // embedding: getEmbeddingZeroVector(), - // }; - // const state = await runtime.composeState(memory, { - // message: message.content.text, - // }); if (!state) { state = (await runtime.composeState(message)) as State; } else { From c9cac7aac1beef7148621b9823e342d2138bbf9d Mon Sep 17 00:00:00 2001 From: JSon Date: Sun, 22 Dec 2024 00:46:33 +0800 Subject: [PATCH 018/112] feat: 1.using generateObject and templated type safe schema. 2.naming convention camelCase. 3.create a template and type file --- .../src/actions/mintNFTAction.ts | 73 +++++++------------ .../plugin-nft-generation/src/templates.ts | 18 +++++ packages/plugin-nft-generation/src/types.ts | 11 +++ 3 files changed, 57 insertions(+), 45 deletions(-) create mode 100644 packages/plugin-nft-generation/src/templates.ts create mode 100644 packages/plugin-nft-generation/src/types.ts diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts index ecb8a47d619..a6556b5cb75 100644 --- a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -1,9 +1,8 @@ import { Action, composeContext, - Content, elizaLogger, - generateObjectDeprecated, + generateObject, HandlerCallback, IAgentRuntime, Memory, @@ -15,34 +14,10 @@ import { verifyNFT } from "../handlers/verifyNFT.ts"; import { sleep } from "../index.ts"; import WalletSolana from "../provider/wallet/walletSolana.ts"; import { PublicKey } from "@solana/web3.js"; +import { mintNFTTemplate } from "../templates.ts"; +import { MintNFTContent, MintNFTSchema } from "../types.ts"; -const mintTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. - -Example response: -\`\`\`json -{ - "collectionAddress": "D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", -} -\`\`\` - -{{recentMessages}} - -Given the recent messages, extract the following information about the requested mint nft: -- collection contract address - -Respond with a JSON markdown block containing only the extracted values. - -Note: Make sure to extract the collection address from the most recent messages whenever possible.`; - -export interface MintContent extends Content { - collectionAddress: string; -} - -function isMintNFTContent( - runtime: IAgentRuntime, - content: any -): content is MintContent { - console.log("Content for mint", content); +function isMintNFTContent(content: any): content is MintNFTContent { return typeof content.collectionAddress === "string"; } @@ -60,18 +35,26 @@ const mintNFTAction: Action = { ], description: "Mint NFTs for the collection", validate: async (runtime: IAgentRuntime, _message: Memory) => { - const AwsAccessKeyIdOk = !!runtime.getSetting("AWS_ACCESS_KEY_ID"); - const AwsSecretAccessKeyOk = !!runtime.getSetting( + const awsAccessKeyIdOk = !!runtime.getSetting("AWS_ACCESS_KEY_ID"); + const awsSecretAccessKeyOk = !!runtime.getSetting( "AWS_SECRET_ACCESS_KEY" ); - const AwsRegionOk = !!runtime.getSetting("AWS_REGION"); - const AwsS3BucketOk = !!runtime.getSetting("AWS_S3_BUCKET"); + const awsRegionOk = !!runtime.getSetting("AWS_REGION"); + const awsS3BucketOk = !!runtime.getSetting("AWS_S3_BUCKET"); + const solanaAdminPrivateKeyOk = !!runtime.getSetting( + "SOLANA_ADMIN_PRIVATE_KEY" + ); + const solanaAdminPublicKeyOk = !!runtime.getSetting( + "SOLANA_ADMIN_PUBLIC_KEY" + ); return ( - AwsAccessKeyIdOk || - AwsSecretAccessKeyOk || - AwsRegionOk || - AwsS3BucketOk + awsAccessKeyIdOk || + awsSecretAccessKeyOk || + awsRegionOk || + awsS3BucketOk || + solanaAdminPrivateKeyOk || + solanaAdminPublicKeyOk ); }, handler: async ( @@ -92,18 +75,20 @@ const mintNFTAction: Action = { // Compose transfer context const transferContext = composeContext({ state, - template: mintTemplate, + template: mintNFTTemplate, }); - const content = await generateObjectDeprecated({ + const res = await generateObject({ runtime, context: transferContext, modelClass: ModelClass.LARGE, + schema: MintNFTSchema, }); + const content = res.object; - elizaLogger.log("generateObjectDeprecated:", transferContext); + elizaLogger.log("Generate Object:", content); - if (!isMintNFTContent(runtime, content)) { + if (!isMintNFTContent(content)) { elizaLogger.error("Invalid content for MINT_NFT action."); if (callback) { callback({ @@ -137,7 +122,6 @@ const mintNFTAction: Action = { return false; } if (metadata) { - elizaLogger.log("nft params", {}); const nftRes = await createNFT({ runtime, collectionName: metadata.name, @@ -176,10 +160,9 @@ const mintNFTAction: Action = { } return []; } catch (e: any) { - console.log(e); + elizaLogger.log(e); + throw e; } - - // callback(); }, examples: [ [ diff --git a/packages/plugin-nft-generation/src/templates.ts b/packages/plugin-nft-generation/src/templates.ts new file mode 100644 index 00000000000..8c6f9169edb --- /dev/null +++ b/packages/plugin-nft-generation/src/templates.ts @@ -0,0 +1,18 @@ + +export const mintNFTTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. + +Example response: +\`\`\`json +{ + "collectionAddress": "D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", +} +\`\`\` + +{{recentMessages}} + +Given the recent messages, extract the following information about the requested mint nft: +- collection contract address + +Respond with a JSON markdown block containing only the extracted values. + +Note: Make sure to extract the collection address from the most recent messages whenever possible.`; diff --git a/packages/plugin-nft-generation/src/types.ts b/packages/plugin-nft-generation/src/types.ts new file mode 100644 index 00000000000..d422bdea218 --- /dev/null +++ b/packages/plugin-nft-generation/src/types.ts @@ -0,0 +1,11 @@ +import { z } from "zod"; +import { Content } from "@ai16z/eliza"; + + +export interface MintNFTContent extends Content { + collectionAddress: string; +} + +export const MintNFTSchema = z.object({ + collectionAddress: z.string(), +}); From 53060702a01067acebfa6fcf3a1d1440a0915ab8 Mon Sep 17 00:00:00 2001 From: JSon Date: Sun, 22 Dec 2024 00:48:42 +0800 Subject: [PATCH 019/112] feat: Remove unnecessary logs --- packages/plugin-nft-generation/src/actions/mintNFTAction.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts index a6556b5cb75..2d9f0fb2c91 100644 --- a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -99,7 +99,6 @@ const mintNFTAction: Action = { return false; } - elizaLogger.log("mint content", content); const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); From c0470f25d81135d096da0f6725fa4aab94014861 Mon Sep 17 00:00:00 2001 From: JSon Date: Mon, 23 Dec 2024 10:39:42 +0800 Subject: [PATCH 020/112] feat: ai16z -> elizaos --- packages/plugin-nft-generation/src/actions/mintNFTAction.ts | 2 +- .../src/actions/nftCollectionGeneration.ts | 2 +- packages/plugin-nft-generation/src/index.ts | 2 +- packages/plugin-nft-generation/src/types.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts index 2d9f0fb2c91..61f4d70984e 100644 --- a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -8,7 +8,7 @@ import { Memory, ModelClass, State, -} from "@ai16z/eliza"; +} from "@elizaos/core"; import { createNFT } from "../handlers/createNFT.ts"; import { verifyNFT } from "../handlers/verifyNFT.ts"; import { sleep } from "../index.ts"; diff --git a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts index 9973d734076..19e1fc3f880 100644 --- a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts +++ b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts @@ -5,7 +5,7 @@ import { IAgentRuntime, Memory, State, -} from "@ai16z/eliza"; +} from "@elizaos/core"; import { createCollection } from "../handlers/createCollection.ts"; const nftCollectionGeneration: Action = { diff --git a/packages/plugin-nft-generation/src/index.ts b/packages/plugin-nft-generation/src/index.ts index 5540ec3a5b7..55f3fe0e3e2 100644 --- a/packages/plugin-nft-generation/src/index.ts +++ b/packages/plugin-nft-generation/src/index.ts @@ -1,4 +1,4 @@ -import { Plugin } from "@ai16z/eliza"; +import { Plugin } from "@elizaos/core"; import nftCollectionGeneration from "./actions/nftCollectionGeneration.ts"; import mintNFTAction from "./actions/mintNFTAction.ts"; diff --git a/packages/plugin-nft-generation/src/types.ts b/packages/plugin-nft-generation/src/types.ts index d422bdea218..e00fe709d97 100644 --- a/packages/plugin-nft-generation/src/types.ts +++ b/packages/plugin-nft-generation/src/types.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { Content } from "@ai16z/eliza"; +import { Content } from "@elizaos/core"; export interface MintNFTContent extends Content { From 58a40d31dacc3de30e135a879705808d13b7210f Mon Sep 17 00:00:00 2001 From: JSon Date: Thu, 2 Jan 2025 07:52:20 +0800 Subject: [PATCH 021/112] feat: plugin-nft-generation - evm chain deploy contract. --- .../contract/CustomERC721.sol | 28 +++ packages/plugin-nft-generation/package.json | 6 +- .../src/actions/nftCollectionGeneration.ts | 218 +++++++++++++++--- packages/plugin-nft-generation/src/api.ts | 4 +- ...ollection.ts => createSolanaCollection.ts} | 55 +++-- .../plugin-nft-generation/src/templates.ts | 26 ++- packages/plugin-nft-generation/src/types.ts | 8 + .../src/utils/deployEVMContract.ts | 96 ++++++++ .../src/utils/generateERC721ContractCode.ts | 58 +++++ .../src/utils/verifyEVMContract.ts | 86 +++++++ packages/plugin-nft-generation/tsconfig.json | 2 +- packages/plugin-nft-generation/tsup.config.ts | 1 + 12 files changed, 528 insertions(+), 60 deletions(-) create mode 100644 packages/plugin-nft-generation/contract/CustomERC721.sol rename packages/plugin-nft-generation/src/handlers/{createCollection.ts => createSolanaCollection.ts} (74%) create mode 100644 packages/plugin-nft-generation/src/utils/deployEVMContract.ts create mode 100644 packages/plugin-nft-generation/src/utils/generateERC721ContractCode.ts create mode 100644 packages/plugin-nft-generation/src/utils/verifyEVMContract.ts diff --git a/packages/plugin-nft-generation/contract/CustomERC721.sol b/packages/plugin-nft-generation/contract/CustomERC721.sol new file mode 100644 index 00000000000..fa356af59fe --- /dev/null +++ b/packages/plugin-nft-generation/contract/CustomERC721.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; + +contract NFTContractName is ERC721Enumerable { + uint256 public maxSupply; + uint256 public currentTokenId; + address public owner; + uint256 public royalty; + + constructor( + string memory _name, + string memory _symbol, + uint256 _maxSupply, + uint256 _royalty + ) ERC721(_name, _symbol) { + maxSupply = _maxSupply; + royalty = _royalty; + owner = msg.sender; + } + + function mint(address _to) public { + require(currentTokenId < maxSupply, "Max supply reached"); + currentTokenId++; + _mint(_to, currentTokenId); + } +} diff --git a/packages/plugin-nft-generation/package.json b/packages/plugin-nft-generation/package.json index 80e55d06049..bd61edb80bd 100644 --- a/packages/plugin-nft-generation/package.json +++ b/packages/plugin-nft-generation/package.json @@ -12,12 +12,16 @@ "@metaplex-foundation/mpl-toolbox": "^0.9.4", "@metaplex-foundation/umi": "^0.9.2", "@metaplex-foundation/umi-bundle-defaults": "^0.9.2", + "@openzeppelin/contracts": "^5.1.0", "@solana-developers/helpers": "^2.5.6", "@solana/web3.js": "1.95.5", "bs58": "6.0.0", + "ethers": "6.13.4", "express": "4.21.1", "node-cache": "5.1.2", - "tsup": "8.3.5" + "solc": "^0.8.28", + "tsup": "8.3.5", + "viem": "^2.21.60" }, "scripts": { "build": "tsup --format esm --dts", diff --git a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts index 19e1fc3f880..901915331ee 100644 --- a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts +++ b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts @@ -1,12 +1,34 @@ import { Action, + composeContext, elizaLogger, + generateObject, HandlerCallback, IAgentRuntime, Memory, + ModelClass, State, } from "@elizaos/core"; -import { createCollection } from "../handlers/createCollection.ts"; +import { createCollectionMetadata } from "../handlers/createSolanaCollection.ts"; +import { CreateCollectionSchema } from "../types.ts"; +import { createCollectionTemplate } from "../templates.ts"; +import * as viemChains from "viem/chains"; +import WalletSolana from "../provider/wallet/walletSolana.ts"; +import { PublicKey } from "@solana/web3.js"; +import { createPublicClient, createWalletClient, http } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { + compileContract, + deployContract, + encodeConstructorArguments, + generateERC721ContractCode, +} from "../utils/deployEVMContract.ts"; +import { verifyEVMContract } from "../utils/verifyEVMContract.ts"; +// import { verifyEVMContract } from "../utils/verifyEVMContract.ts"; + +const _SupportedChainList = Object.keys(viemChains) as Array< + keyof typeof viemChains +>; const nftCollectionGeneration: Action = { name: "GENERATE_COLLECTION", @@ -46,17 +68,131 @@ const nftCollectionGeneration: Action = { ) => { try { elizaLogger.log("Composing state for message:", message); - const collectionAddressRes = await createCollection({ + + const state = await runtime.composeState(message); + + // Compose transfer context + const context = composeContext({ + state, + template: createCollectionTemplate, + }); + const chains = _SupportedChainList; + + const supportedChains: ( + | (typeof chains)[number] + | "solana" + | null + )[] = [...chains, "solana", null]; + const contextWithChains = context.replace( + "SUPPORTED_CHAINS", + supportedChains + .map((item) => (item ? `"${item}"` : item)) + .join("|") + ); + + const res = await generateObject({ runtime, - collectionName: runtime.character.name, + context: contextWithChains, + modelClass: ModelClass.LARGE, + schema: CreateCollectionSchema, }); - elizaLogger.log("Collection Info:", collectionAddressRes); - if (callback) { - callback({ - text: `Congratulations to you! 🎉🎉🎉 \nCollection Link : ${collectionAddressRes.link}\n Address: ${collectionAddressRes.address}`, //caption.description, - attachments: [], + + const content = res.object as { + chainName: (typeof supportedChains)[number]; + }; + + console.log(111111, content); + if (content?.chainName === "solana") { + const collectionInfo = await createCollectionMetadata({ + runtime, + collectionName: runtime.character.name, + }); + if (!collectionInfo) return null; + const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); + const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); + const wallet = new WalletSolana( + new PublicKey(publicKey), + privateKey + ); + + const collectionAddressRes = await wallet.createCollection({ + ...collectionInfo, + }); + elizaLogger.log("Collection Info:", collectionAddressRes); + if (callback) { + callback({ + text: `Congratulations to you! 🎉🎉🎉 \nCollection Link : ${collectionAddressRes.link}\n Address: ${collectionAddressRes.address}`, //caption.description, + attachments: [], + }); + } + } else if (chains.indexOf(content.chainName)) { + const privateKey = runtime.getSetting( + "WALLET_PRIVATE_KEY" + ) as `0x${string}`; + if (!privateKey) return null; + const rpcUrl = + viemChains[content.chainName].rpcUrls.default.http[0]; + const chain = viemChains[content.chainName]; // 替换为目标链 + const provider = http(rpcUrl); + const account = privateKeyToAccount(privateKey); + const walletClient = createWalletClient({ + account, + chain: chain, + transport: provider, + }); + + const publicClient = createPublicClient({ + chain: chain, + transport: provider, + }); + + // const collectionInfo = await createCollectionMetadata({ + // runtime, + // collectionName: runtime.character.name, + // }); + + const contractName = runtime.character.name.replace('.', '_'); + const contractSymbol = `${contractName.toUpperCase()[0]}`; + const contractMaxSupply = 5000; + const royalty = 0; + const params = [ + contractName, + contractSymbol, + contractMaxSupply, + royalty, + ]; + const sourceCode = generateERC721ContractCode(contractName); + + const { abi, bytecode, metadata } = compileContract( + contractName, + sourceCode + ); + elizaLogger.log("ABI and Bytecode generated."); + const contractAddress = await deployContract({ + walletClient, + publicClient, + abi, + bytecode, + args: params, }); + elizaLogger.log( + `Deployed contract address: ${contractAddress}` + ); + const constructorArgs = encodeConstructorArguments(abi, params); + await verifyEVMContract({ + contractAddress: contractAddress, + sourceCode, + metadata, + constructorArgs, + }); + if (callback) { + callback({ + text: `Congratulations to you! 🎉🎉🎉 \nCollection Link : ${chain.blockExplorers.default.url}/address/${contractAddress}\n Address: ${contractAddress}`, //caption.description, + attachments: [], + }); + } } + return []; } catch (e: any) { console.log(e); @@ -67,7 +203,7 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Generate a collection" }, + content: { text: "Generate a collection on Solana" }, }, { user: "{{agentName}}", @@ -80,12 +216,14 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Generate a collection using {{agentName}}" }, + content: { + text: "Generate a collection using {{agentName}} on Solana", + }, }, { user: "{{agentName}}", content: { - text: "We've successfully created a collection.", + text: "We've successfully created a collection on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -93,7 +231,9 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Create a collection using {{agentName}}" }, + content: { + text: "Create a collection using {{agentName}} on Solana", + }, }, { user: "{{agentName}}", @@ -106,7 +246,7 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Build a Collection" }, + content: { text: "Build a Collection on Solana" }, }, { user: "{{agentName}}", @@ -119,7 +259,9 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Assemble a collection with {{agentName}}" }, + content: { + text: "Assemble a collection with {{agentName}} on Solana", + }, }, { user: "{{agentName}}", @@ -132,7 +274,7 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Make a collection" }, + content: { text: "Make a collection on Solana" }, }, { user: "{{agentName}}", @@ -146,13 +288,13 @@ const nftCollectionGeneration: Action = { { user: "{{user1}}", content: { - text: "Could you create a new collection for my photos?", + text: "Could you create a new collection for my photos on Solana?", }, }, { user: "{{agentName}}", content: { - text: "I've created a new collection for your photos.", + text: "I've created a new collection for your photos on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -161,13 +303,13 @@ const nftCollectionGeneration: Action = { { user: "{{user1}}", content: { - text: "I need a collection for organizing my music", + text: "I need a collection for organizing my music on Solana", }, }, { user: "{{agentName}}", content: { - text: "Your music collection has been generated.", + text: "Your music collection has been generated on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -176,13 +318,13 @@ const nftCollectionGeneration: Action = { { user: "{{user1}}", content: { - text: "Please set up a collection for my documents", + text: "Please set up a collection for my documents on Solana", }, }, { user: "{{agentName}}", content: { - text: "I've set up a new collection for your documents.", + text: "I've set up a new collection for your documents on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -190,12 +332,12 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Start a new collection for me" }, + content: { text: "Start a new collection for me on Solana" }, }, { user: "{{agentName}}", content: { - text: "Your new collection has been created.", + text: "Your new collection has been created on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -204,13 +346,13 @@ const nftCollectionGeneration: Action = { { user: "{{user1}}", content: { - text: "I'd like to make a collection of my recipes", + text: "I'd like to make a collection of my recipes on Solana", }, }, { user: "{{agentName}}", content: { - text: "I've generated a collection for your recipes.", + text: "I've generated a collection for your recipes on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -219,13 +361,13 @@ const nftCollectionGeneration: Action = { { user: "{{user1}}", content: { - text: "Can you generate a collection for my artwork?", + text: "Can you generate a collection for my artwork on Solana?", }, }, { user: "{{agentName}}", content: { - text: "Your artwork collection has been generated.", + text: "Your artwork collection has been generated on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -233,12 +375,14 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Initialize a new collection please" }, + content: { + text: "Initialize a new collection please on Solana", + }, }, { user: "{{agentName}}", content: { - text: "I've initialized a new collection for you.", + text: "I've initialized a new collection for you on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -246,12 +390,14 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Create a collection for my travel memories" }, + content: { + text: "Create a collection for my travel memories on Solana", + }, }, { user: "{{agentName}}", content: { - text: "Your travel memories collection has been created.", + text: "Your travel memories collection has been created on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -260,13 +406,13 @@ const nftCollectionGeneration: Action = { { user: "{{user1}}", content: { - text: "Would you make a collection for my projects?", + text: "Would you make a collection for my projects on Solana?", }, }, { user: "{{agentName}}", content: { - text: "I've made a collection for your projects.", + text: "I've made a collection for your projects on Solana.", action: "GENERATE_COLLECTION", }, }, @@ -274,12 +420,14 @@ const nftCollectionGeneration: Action = { [ { user: "{{user1}}", - content: { text: "Set up a collection for my bookmarks" }, + content: { + text: "Set up a collection for my bookmarks on Solana", + }, }, { user: "{{agentName}}", content: { - text: "Your bookmarks collection has been set up.", + text: "Your bookmarks collection has been set up on Solana.", action: "GENERATE_COLLECTION", }, }, diff --git a/packages/plugin-nft-generation/src/api.ts b/packages/plugin-nft-generation/src/api.ts index 1501a5a370e..002ec506910 100644 --- a/packages/plugin-nft-generation/src/api.ts +++ b/packages/plugin-nft-generation/src/api.ts @@ -1,7 +1,7 @@ import express from "express"; import { AgentRuntime } from "@elizaos/core"; -import { createCollection } from "./handlers/createCollection.ts"; +import { createSolanaCollection } from "./handlers/createSolanaCollection.ts"; import { createNFT, createNFTMetadata } from "./handlers/createNFT.ts"; import { verifyNFT } from "./handlers/verifyNFT.ts"; @@ -21,7 +21,7 @@ export function createNFTApiRouter( return; } try { - const collectionAddressRes = await createCollection({ + const collectionAddressRes = await createSolanaCollection({ runtime, collectionName: runtime.character.name, fee, diff --git a/packages/plugin-nft-generation/src/handlers/createCollection.ts b/packages/plugin-nft-generation/src/handlers/createSolanaCollection.ts similarity index 74% rename from packages/plugin-nft-generation/src/handlers/createCollection.ts rename to packages/plugin-nft-generation/src/handlers/createSolanaCollection.ts index 77cdd3d20dc..17ddd376ede 100644 --- a/packages/plugin-nft-generation/src/handlers/createCollection.ts +++ b/packages/plugin-nft-generation/src/handlers/createSolanaCollection.ts @@ -15,12 +15,9 @@ import { } from "@elizaos/plugin-image-generation"; import { PublicKey } from "@solana/web3.js"; import WalletSolana from "../provider/wallet/walletSolana.ts"; +import { collectionImageTemplate } from "../templates.ts"; -const collectionImageTemplate = ` -Generate a logo with the text "{{collectionName}}", using orange as the main color, with a sci-fi and mysterious background theme -`; - -export async function createCollection({ +export async function createCollectionMetadata({ runtime, collectionName, fee, @@ -41,7 +38,6 @@ export async function createCollection({ roomId, content: { text: "", - source: "nft-generator", }, createdAt: Date.now(), @@ -79,8 +75,6 @@ export async function createCollection({ `/${collectionName}`, false ); - const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); - const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); const adminPublicKey = runtime.getSetting("SOLANA_ADMIN_PUBLIC_KEY"); const collectionInfo = { name: `${collectionName}`, @@ -100,19 +94,40 @@ export async function createCollection({ ); collectionInfo.uri = jsonFilePath.url; - const wallet = new WalletSolana(new PublicKey(publicKey), privateKey); - - const collectionAddressRes = await wallet.createCollection({ - ...collectionInfo, - }); + return collectionInfo; - return { - network: "solana", - address: collectionAddressRes.address, - link: collectionAddressRes.link, - collectionInfo, - }; } - return; + return null; +} + +export async function createSolanaCollection({ + runtime, + collectionName, + fee, +}: { + runtime: IAgentRuntime; + collectionName: string; + fee?: number; +}) { + const collectionInfo = await createCollectionMetadata({ + runtime, + collectionName, + fee, + }); + if (!collectionInfo) return null + const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); + const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); + const wallet = new WalletSolana(new PublicKey(publicKey), privateKey); + + const collectionAddressRes = await wallet.createCollection({ + ...collectionInfo, + }); + + return { + network: "solana", + address: collectionAddressRes.address, + link: collectionAddressRes.link, + collectionInfo, + }; } diff --git a/packages/plugin-nft-generation/src/templates.ts b/packages/plugin-nft-generation/src/templates.ts index 8c6f9169edb..bcf3e75d3f4 100644 --- a/packages/plugin-nft-generation/src/templates.ts +++ b/packages/plugin-nft-generation/src/templates.ts @@ -1,4 +1,28 @@ +export const createCollectionTemplate = `Given the recent messages and wallet information below: + +{{recentMessages}} + +{{walletInfo}} + +Extract the following information about the requested transfer: +- Chain to execute on: Must be one of ["ethereum", "base", ...] (like in viem/chains) + +Respond with a JSON markdown block containing only the extracted values. All fields are required: + +\`\`\`json +{ + "chainName": SUPPORTED_CHAINS, +} +\`\`\` + +Note: Ensure to use the user’s latest instruction to extract data; if it is not within the defined options, use null. + +`; + +export const collectionImageTemplate = ` +Generate a logo with the text "{{collectionName}}", using orange as the main color, with a sci-fi and mysterious background theme +`; export const mintNFTTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. Example response: @@ -15,4 +39,4 @@ Given the recent messages, extract the following information about the requested Respond with a JSON markdown block containing only the extracted values. -Note: Make sure to extract the collection address from the most recent messages whenever possible.`; +Note: Ensure to use the user’s latest instruction to extract data; if it is not within the defined options, use null.`; diff --git a/packages/plugin-nft-generation/src/types.ts b/packages/plugin-nft-generation/src/types.ts index e00fe709d97..ec93468808f 100644 --- a/packages/plugin-nft-generation/src/types.ts +++ b/packages/plugin-nft-generation/src/types.ts @@ -1,6 +1,8 @@ import { z } from "zod"; import { Content } from "@elizaos/core"; +import * as viemChains from "viem/chains"; +const _SupportedChainList = Object.keys(viemChains); export interface MintNFTContent extends Content { collectionAddress: string; @@ -9,3 +11,9 @@ export interface MintNFTContent extends Content { export const MintNFTSchema = z.object({ collectionAddress: z.string(), }); + +const supportedChainTuple = [..._SupportedChainList, 'solana'] as unknown as [string, ...string[]]; +export const CreateCollectionSchema = z.object({ + chainName: z.enum([...supportedChainTuple]).nullable(), +}); + diff --git a/packages/plugin-nft-generation/src/utils/deployEVMContract.ts b/packages/plugin-nft-generation/src/utils/deployEVMContract.ts new file mode 100644 index 00000000000..1e859ad7547 --- /dev/null +++ b/packages/plugin-nft-generation/src/utils/deployEVMContract.ts @@ -0,0 +1,96 @@ +import { + createPublicClient, + createWalletClient, + encodeAbiParameters, + http, +} from "viem"; +import { fileURLToPath } from "url"; + +import { alienxHalTestnet } from "viem/chains"; +import { privateKeyToAccount } from "viem/accounts"; +import { compileWithImports } from "./generateERC721ContractCode.ts"; +import { verifyEVMContract } from "./verifyEVMContract.ts"; +import path from "path"; +import fs from "fs"; + +// 动态生成 ERC-721 合约代码 +export function generateERC721ContractCode(NFTContractName) { + const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file + const __dirname = path.dirname(__filename); // get the name of the directory + const solPath = path.resolve(__dirname, "../contract/CustomERC721.sol"); + return fs + .readFileSync(solPath, "utf8") + .replace("NFTContractName", NFTContractName); +} + +// 使用 Solidity 编译器生成 ABI 和 Bytecode +export function compileContract(contractName, sourceCode) { + const res = compileWithImports(contractName, sourceCode); + const { abi, bytecode, metadata } = res; + return { abi, bytecode, metadata }; +} + +// 部署合约 +export async function deployContract({ + walletClient, + publicClient, + abi, + bytecode, + args, +}) { + console.log("Deploying contract..."); + + const txHash = await walletClient.deployContract({ + abi: abi as any, + bytecode: bytecode as any, + args: args as any, + chain: undefined, + }); + + console.log(`Deployment transaction hash: ${txHash}`); + const receipt = await publicClient.waitForTransactionReceipt({ + hash: txHash, + }); + console.log(`Contract deployed at address: ${receipt.contractAddress}`); + return receipt.contractAddress; +} + +// 调用 mint 方法 +async function mintNFT({ + walletClient, + publicClient, + contractAddress, + abi, + recipient, +}: { + contractAddress: any; + abi: any; + recipient: any; + walletClient: any; + publicClient: any; +}) { + console.log("Minting NFT..."); + const txHash = await walletClient.writeContract({ + address: contractAddress as `0x${string}`, + abi: abi as any, + functionName: "mint", + args: [recipient] as any, + chain: undefined, + account: undefined, + }); + + console.log(`Mint transaction hash: ${txHash}`); + const receipt = await publicClient.waitForTransactionReceipt({ + hash: txHash, + }); + console.log("Mint successful!"); + return receipt; +} + +// 编码构造函数参数 +export function encodeConstructorArguments(abi, args) { + const argsData = encodeAbiParameters(abi[0].inputs, args); + + return argsData.slice(2); +} + diff --git a/packages/plugin-nft-generation/src/utils/generateERC721ContractCode.ts b/packages/plugin-nft-generation/src/utils/generateERC721ContractCode.ts new file mode 100644 index 00000000000..588c144aae7 --- /dev/null +++ b/packages/plugin-nft-generation/src/utils/generateERC721ContractCode.ts @@ -0,0 +1,58 @@ +import solc from "solc"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +// Load OpenZeppelin contract source code +export function loadOpenZeppelinFile(contractPath) { + const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file + const __dirname = path.dirname(__filename); // get the name of the directory + + const fullPath = path.resolve(__dirname, '../../../', "node_modules", contractPath); + return fs.readFileSync(fullPath, "utf8"); +} + +// Dynamic import callback for Solidity +export function importResolver(importPath) { + if (importPath.startsWith("@openzeppelin/")) { + return { + contents: loadOpenZeppelinFile(importPath), + }; + } + return { error: "File not found" }; +} + +// Compile contract with custom import callback +export function compileWithImports(contractName, sourceCode) { + const input = { + language: "Solidity", + sources: { + [`${contractName}.sol`]: { + content: sourceCode, + }, + }, + settings: { + outputSelection: { + "*": { + "*": ["*"], + }, + }, + }, + }; + + const output = JSON.parse( + solc.compile(JSON.stringify(input), { import: importResolver }) + ); + + if (output.errors) { + output.errors.forEach((err) => console.error(err)); + } + const contractFile = output.contracts[`${contractName}.sol`][`${contractName}`]; + + const metadata = JSON.parse(contractFile.metadata); + return { + abi: contractFile.abi, + bytecode: contractFile.evm.bytecode.object, + metadata + }; +} diff --git a/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts b/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts new file mode 100644 index 00000000000..1ae3b2b2aef --- /dev/null +++ b/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts @@ -0,0 +1,86 @@ +import axios from "axios"; +import { + loadOpenZeppelinFile, +} from "./generateERC721ContractCode.ts"; + +function getSources(metadata, sourceCode) { + const fileName = Object.keys(metadata.settings.compilationTarget)[0] + const obj = { + [fileName]: { + content: sourceCode, + }, + }; + const keys = Object.keys(metadata.sources); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + console.log(key, fileName); + if (key !== fileName) { + obj[key] = { + content: loadOpenZeppelinFile(key), + }; + } + } + return obj; +} + +export async function verifyEVMContract({ + contractAddress, + sourceCode, + metadata, + constructorArgs = "", +}) { + const apiEndpoint = "https://hal-explorer.alienxchain.io/api"; + const verificationData = { + module: "contract", + action: "verifysourcecode", + sourceCode: JSON.stringify({ + language: "Solidity", + sources: getSources(metadata, sourceCode), + settings: { + optimizer: { + enabled: metadata.settings.optimizer?.enabled, + runs: metadata.settings.optimizer?.runs, + }, + }, + }), + codeformat: "solidity-standard-json-input", + contractaddress: contractAddress, + contractname: "test", + compilerversion: `v${metadata.compiler.version}`, + optimizationUsed: metadata.settings.optimizer?.enabled ? 1 : 0, + runs: metadata.settings.optimizer?.runs || 200, + constructorArguements: constructorArgs, // Remove '0x' prefix + }; + + try { + const response = await axios.post(apiEndpoint, verificationData); + if (response.data.status === "1") { + const guid = response.data.result; + + // Check verification status + const checkStatus = async () => { + const statusResponse = await axios.get(apiEndpoint, { + params: { + module: "contract", + action: "checkverifystatus", + guid: guid, + }, + }); + console.log(111, statusResponse.data); + return statusResponse.data; + }; + + // Poll for completion + let status; + do { + await new Promise((resolve) => setTimeout(resolve, 3000)); + status = await checkStatus(); + } while (status.result === "Pending in queue"); + + return status; + } + return response.data; + } catch (error) { + throw new Error(`Verification failed: ${error.message}`); + } +} diff --git a/packages/plugin-nft-generation/tsconfig.json b/packages/plugin-nft-generation/tsconfig.json index 834c4dce269..abd2932121e 100644 --- a/packages/plugin-nft-generation/tsconfig.json +++ b/packages/plugin-nft-generation/tsconfig.json @@ -10,4 +10,4 @@ "include": [ "src/**/*.ts" ] -} \ No newline at end of file +} diff --git a/packages/plugin-nft-generation/tsup.config.ts b/packages/plugin-nft-generation/tsup.config.ts index 1a96f24afa1..f2d8f4c321c 100644 --- a/packages/plugin-nft-generation/tsup.config.ts +++ b/packages/plugin-nft-generation/tsup.config.ts @@ -16,6 +16,7 @@ export default defineConfig({ "http", "agentkeepalive", "safe-buffer", + "axios" // Add other modules you want to externalize ], }); From a66628e004b41800f1bef2262c61233af89ea725 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Fri, 3 Jan 2025 16:59:52 +0700 Subject: [PATCH 022/112] fix(adapter-postgres): #1687 Add vector embedding validation and tests --- .../adapter-postgres/src/__tests__/README.md | 71 +++ .../src/__tests__/docker-compose.test.yml | 16 + .../src/__tests__/run_tests.sh | 84 ++++ .../src/__tests__/vector-extension.test.ts | 433 ++++++++++++++++++ packages/adapter-postgres/src/index.ts | 24 +- 5 files changed, 627 insertions(+), 1 deletion(-) create mode 100644 packages/adapter-postgres/src/__tests__/README.md create mode 100644 packages/adapter-postgres/src/__tests__/docker-compose.test.yml create mode 100644 packages/adapter-postgres/src/__tests__/run_tests.sh create mode 100644 packages/adapter-postgres/src/__tests__/vector-extension.test.ts diff --git a/packages/adapter-postgres/src/__tests__/README.md b/packages/adapter-postgres/src/__tests__/README.md new file mode 100644 index 00000000000..98896ff4f2b --- /dev/null +++ b/packages/adapter-postgres/src/__tests__/README.md @@ -0,0 +1,71 @@ +# PostgreSQL Adapter Tests + +This directory contains tests for the PostgreSQL adapter with vector extension support. + +## Prerequisites + +- Docker installed and running +- Node.js and pnpm installed +- Bash shell (for Unix/Mac) or Git Bash (for Windows) + +## Test Environment + +The tests run against a PostgreSQL instance with the `pgvector` extension enabled. We use Docker to ensure a consistent test environment: + +- PostgreSQL 16 with pgvector extension +- Test database: `eliza_test` +- Port: 5433 (to avoid conflicts with local PostgreSQL) +- Vector dimensions: 1536 (OpenAI compatible) + +## Running Tests + +The easiest way to run tests is using the provided script: + +```bash +./run_tests.sh +``` + +This script will: +1. Start the PostgreSQL container with vector extension +2. Wait for the database to be ready +3. Run the test suite + +## Manual Setup + +If you prefer to run tests manually: + +1. Start the test database: + ```bash + docker compose -f docker-compose.test.yml up -d + ``` + +2. Wait for the database to be ready (about 30 seconds) + +3. Run tests: + ```bash + pnpm vitest vector-extension.test.ts + ``` + +## Test Structure + +- `vector-extension.test.ts`: Main test suite for vector operations +- `docker-compose.test.yml`: Docker configuration for test database +- `run_tests.sh`: Helper script to run tests + +## Troubleshooting + +1. If tests fail with connection errors: + - Check if Docker is running + - Verify port 5433 is available + - Wait a bit longer for database initialization + +2. If vector operations fail: + - Check if pgvector extension is properly loaded + - Verify schema initialization + - Check vector dimensions match (1536 for OpenAI) + +## Notes + +- Tests automatically clean up after themselves +- Each test run starts with a fresh database +- Vector extension is initialized as part of the schema setup \ No newline at end of file diff --git a/packages/adapter-postgres/src/__tests__/docker-compose.test.yml b/packages/adapter-postgres/src/__tests__/docker-compose.test.yml new file mode 100644 index 00000000000..7a589ec1926 --- /dev/null +++ b/packages/adapter-postgres/src/__tests__/docker-compose.test.yml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json +version: '3.8' +services: + postgres-test: + image: pgvector/pgvector:pg16 + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: eliza_test + ports: + - "5433:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 \ No newline at end of file diff --git a/packages/adapter-postgres/src/__tests__/run_tests.sh b/packages/adapter-postgres/src/__tests__/run_tests.sh new file mode 100644 index 00000000000..6a18b681eb9 --- /dev/null +++ b/packages/adapter-postgres/src/__tests__/run_tests.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Get script directory +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +SCHEMA_PATH="$SCRIPT_DIR/../../schema.sql" + +echo -e "${YELLOW}Starting PostgreSQL test environment...${NC}" + +# Determine Docker Compose command +if [[ "$OSTYPE" == "darwin"* ]]; then + DOCKER_COMPOSE_CMD="docker compose" +else + DOCKER_COMPOSE_CMD="docker-compose" +fi + +# Stop any existing containers +echo -e "${YELLOW}Cleaning up existing containers...${NC}" +$DOCKER_COMPOSE_CMD -f docker-compose.test.yml down + +# Start fresh container +echo -e "${YELLOW}Starting PostgreSQL container...${NC}" +$DOCKER_COMPOSE_CMD -f docker-compose.test.yml up -d + +# Function to check if PostgreSQL is ready +check_postgres() { + $DOCKER_COMPOSE_CMD -f docker-compose.test.yml exec -T postgres-test pg_isready -U postgres +} + +# Wait for PostgreSQL to be ready +echo -e "${YELLOW}Waiting for PostgreSQL to be ready...${NC}" +RETRIES=30 +until check_postgres || [ $RETRIES -eq 0 ]; do + echo -e "${YELLOW}Waiting for PostgreSQL to be ready... ($RETRIES attempts left)${NC}" + RETRIES=$((RETRIES-1)) + sleep 1 +done + +if [ $RETRIES -eq 0 ]; then + echo -e "${RED}Failed to connect to PostgreSQL${NC}" + $DOCKER_COMPOSE_CMD -f docker-compose.test.yml logs + exit 1 +fi + +echo -e "${GREEN}PostgreSQL is ready!${NC}" + +# Load schema +echo -e "${YELLOW}Loading database schema...${NC}" +if [ ! -f "$SCHEMA_PATH" ]; then + echo -e "${RED}Schema file not found at: $SCHEMA_PATH${NC}" + exit 1 +fi + +$DOCKER_COMPOSE_CMD -f docker-compose.test.yml exec -T postgres-test psql -U postgres -d eliza_test -f - < "$SCHEMA_PATH" +if [ $? -ne 0 ]; then + echo -e "${RED}Failed to load schema${NC}" + exit 1 +fi +echo -e "${GREEN}Schema loaded successfully!${NC}" + +# Run the tests +echo -e "${YELLOW}Running tests...${NC}" +pnpm vitest vector-extension.test.ts + +# Capture test exit code +TEST_EXIT_CODE=$? + +# Clean up +echo -e "${YELLOW}Cleaning up test environment...${NC}" +$DOCKER_COMPOSE_CMD -f docker-compose.test.yml down + +# Exit with test exit code +if [ $TEST_EXIT_CODE -eq 0 ]; then + echo -e "${GREEN}Tests completed successfully!${NC}" +else + echo -e "${RED}Tests failed!${NC}" +fi + +exit $TEST_EXIT_CODE \ No newline at end of file diff --git a/packages/adapter-postgres/src/__tests__/vector-extension.test.ts b/packages/adapter-postgres/src/__tests__/vector-extension.test.ts new file mode 100644 index 00000000000..7ced5873718 --- /dev/null +++ b/packages/adapter-postgres/src/__tests__/vector-extension.test.ts @@ -0,0 +1,433 @@ +import { PostgresDatabaseAdapter } from '../index'; +import pg from 'pg'; +import fs from 'fs'; +import path from 'path'; +import { describe, test, expect, beforeEach, afterEach, vi, beforeAll } from 'vitest'; +import { DatabaseAdapter, elizaLogger, type Memory, type Content, EmbeddingProvider } from '@elizaos/core'; + +// Increase test timeout +vi.setConfig({ testTimeout: 15000 }); + +// Mock the @elizaos/core module +vi.mock('@elizaos/core', () => ({ + elizaLogger: { + error: vi.fn().mockImplementation(console.error), + info: vi.fn().mockImplementation(console.log), + success: vi.fn().mockImplementation(console.log), + debug: vi.fn().mockImplementation(console.log), + warn: vi.fn().mockImplementation(console.warn), + }, + getEmbeddingConfig: () => ({ + provider: 'OpenAI', + dimensions: 1536, + model: 'text-embedding-3-small' + }), + DatabaseAdapter: class { + protected circuitBreaker = { + execute: async (operation: () => Promise) => operation() + }; + protected async withCircuitBreaker(operation: () => Promise) { + return this.circuitBreaker.execute(operation); + } + }, + EmbeddingProvider: { + OpenAI: 'OpenAI', + Ollama: 'Ollama', + BGE: 'BGE' + } +})); + +// Helper function to parse vector string from PostgreSQL +const parseVectorString = (vectorStr: string): number[] => { + if (!vectorStr) return []; + // Remove brackets and split by comma + return vectorStr.replace(/[\[\]]/g, '').split(',').map(Number); +}; + +describe('PostgresDatabaseAdapter - Vector Extension Validation', () => { + let adapter: PostgresDatabaseAdapter; + let testClient: pg.PoolClient; + let testPool: pg.Pool; + + const initializeDatabase = async (client: pg.PoolClient) => { + elizaLogger.info('Initializing database with schema...'); + try { + // Set app settings for vector dimension + await client.query(` + ALTER DATABASE eliza_test SET app.use_openai_embedding = 'true'; + ALTER DATABASE eliza_test SET app.use_ollama_embedding = 'false'; + `); + + // Read and execute schema file + const schemaPath = path.resolve(__dirname, '../../schema.sql'); + const schema = fs.readFileSync(schemaPath, 'utf8'); + await client.query(schema); + + // Verify schema setup + const { rows: vectorExt } = await client.query(` + SELECT * FROM pg_extension WHERE extname = 'vector' + `); + elizaLogger.info('Vector extension status:', { isInstalled: vectorExt.length > 0 }); + + const { rows: dimension } = await client.query('SELECT get_embedding_dimension()'); + elizaLogger.info('Vector dimension:', { dimension: dimension[0].get_embedding_dimension }); + + // Verify search path + const { rows: searchPath } = await client.query('SHOW search_path'); + elizaLogger.info('Search path:', { searchPath: searchPath[0].search_path }); + + } catch (error) { + elizaLogger.error(`Database initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }; + + const cleanDatabase = async (client: pg.PoolClient) => { + elizaLogger.info('Starting database cleanup...'); + try { + await client.query('DROP TABLE IF EXISTS relationships CASCADE'); + await client.query('DROP TABLE IF EXISTS participants CASCADE'); + await client.query('DROP TABLE IF EXISTS logs CASCADE'); + await client.query('DROP TABLE IF EXISTS goals CASCADE'); + await client.query('DROP TABLE IF EXISTS memories CASCADE'); + await client.query('DROP TABLE IF EXISTS rooms CASCADE'); + await client.query('DROP TABLE IF EXISTS accounts CASCADE'); + await client.query('DROP TABLE IF EXISTS cache CASCADE'); + await client.query('DROP EXTENSION IF EXISTS vector CASCADE'); + await client.query('DROP SCHEMA IF EXISTS extensions CASCADE'); + elizaLogger.success('Database cleanup completed successfully'); + } catch (error) { + elizaLogger.error(`Database cleanup failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }; + + beforeAll(async () => { + elizaLogger.info('Setting up test database...'); + const setupPool = new pg.Pool({ + host: 'localhost', + port: 5433, + database: 'eliza_test', + user: 'postgres', + password: 'postgres' + }); + + const setupClient = await setupPool.connect(); + try { + await cleanDatabase(setupClient); + await initializeDatabase(setupClient); + } finally { + await setupClient.release(); + await setupPool.end(); + } + }); + + beforeEach(async () => { + elizaLogger.info('Setting up test environment...'); + try { + // Setup test database connection + testPool = new pg.Pool({ + host: 'localhost', + port: 5433, + database: 'eliza_test', + user: 'postgres', + password: 'postgres' + }); + + testClient = await testPool.connect(); + elizaLogger.debug('Database connection established'); + + await cleanDatabase(testClient); + elizaLogger.debug('Database cleaned'); + + adapter = new PostgresDatabaseAdapter({ + host: 'localhost', + port: 5433, + database: 'eliza_test', + user: 'postgres', + password: 'postgres' + }); + elizaLogger.success('Test environment setup completed'); + } catch (error) { + elizaLogger.error(`Test environment setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }); + + afterEach(async () => { + elizaLogger.info('Cleaning up test environment...'); + try { + await cleanDatabase(testClient); + await testClient?.release(); + await testPool?.end(); + await adapter?.close(); + elizaLogger.success('Test environment cleanup completed'); + } catch (error) { + elizaLogger.error(`Test environment cleanup failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }); + + describe('Schema and Extension Management', () => { + test('should initialize with vector extension', async () => { + elizaLogger.info('Testing vector extension initialization...'); + try { + // Act + elizaLogger.debug('Initializing adapter...'); + await adapter.init(); + elizaLogger.success('Adapter initialized successfully'); + + // Assert + elizaLogger.debug('Verifying vector extension existence...'); + const { rows } = await testClient.query(` + SELECT 1 FROM pg_extension WHERE extname = 'vector' + `); + expect(rows.length).toBe(1); + elizaLogger.success('Vector extension verified successfully'); + } catch (error) { + elizaLogger.error(`Vector extension test failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }); + + test('should handle missing rooms table', async () => { + elizaLogger.info('Testing rooms table creation...'); + try { + // Act + elizaLogger.debug('Initializing adapter...'); + await adapter.init(); + elizaLogger.success('Adapter initialized successfully'); + + // Assert + elizaLogger.debug('Verifying rooms table existence...'); + const { rows } = await testClient.query(` + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = 'rooms' + ); + `); + expect(rows[0].exists).toBe(true); + elizaLogger.success('Rooms table verified successfully'); + } catch (error) { + elizaLogger.error(`Rooms table test failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }); + + test('should not reapply schema when everything exists', async () => { + elizaLogger.info('Testing schema reapplication prevention...'); + try { + // Arrange + elizaLogger.debug('Setting up initial schema...'); + await adapter.init(); + elizaLogger.success('Initial schema setup completed'); + + const spy = vi.spyOn(fs, 'readFileSync'); + elizaLogger.debug('File read spy installed'); + + // Act + elizaLogger.debug('Attempting schema reapplication...'); + await adapter.init(); + elizaLogger.success('Second initialization completed'); + + // Assert + expect(spy).not.toHaveBeenCalled(); + elizaLogger.success('Verified schema was not reapplied'); + spy.mockRestore(); + } catch (error) { + elizaLogger.error(`Schema reapplication test failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }); + + test('should handle transaction rollback on error', async () => { + elizaLogger.info('Testing transaction rollback...'); + try { + // Arrange + elizaLogger.debug('Setting up file read error simulation...'); + const spy = vi.spyOn(fs, 'readFileSync').mockImplementation(() => { + elizaLogger.warn('Simulating schema read error'); + throw new Error('Schema read error'); + }); + + // Act & Assert + elizaLogger.debug('Attempting initialization with error...'); + await expect(adapter.init()).rejects.toThrow('Schema read error'); + elizaLogger.success('Error thrown as expected'); + + // Verify no tables were created + elizaLogger.debug('Verifying rollback...'); + const { rows } = await testClient.query(` + SELECT EXISTS ( + SELECT FROM information_schema.tables + WHERE table_name = 'rooms' + ); + `); + expect(rows[0].exists).toBe(false); + elizaLogger.success('Rollback verified successfully'); + spy.mockRestore(); + } catch (error) { + elizaLogger.error(`Transaction rollback test failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw error; + } + }); + }); + + // Memory Operations tests will be updated in the next iteration + describe('Memory Operations with Vector', () => { + const TEST_UUID = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'; + const TEST_TABLE = 'test_memories'; + + beforeEach(async () => { + elizaLogger.info('Setting up memory operations test...'); + try { + // Ensure clean state and proper initialization + await adapter.init(); + + // Verify vector extension and search path + await testClient.query(` + SET search_path TO public, extensions; + SELECT set_config('app.use_openai_embedding', 'true', false); + `); + + // Create necessary account and room first + await testClient.query('BEGIN'); + try { + await testClient.query(` + INSERT INTO accounts (id, email) + VALUES ($1, 'test@test.com') + ON CONFLICT (id) DO NOTHING + `, [TEST_UUID]); + + await testClient.query(` + INSERT INTO rooms (id) + VALUES ($1) + ON CONFLICT (id) DO NOTHING + `, [TEST_UUID]); + + await testClient.query('COMMIT'); + } catch (error) { + await testClient.query('ROLLBACK'); + throw error; + } + + } catch (error) { + elizaLogger.error('Memory operations setup failed:', { + error: error instanceof Error ? error.message : String(error) + }); + throw error; + } + }); + + test('should create and retrieve memory with vector embedding', async () => { + // Arrange + const content: Content = { + text: 'test content' + }; + + const memory: Memory = { + id: TEST_UUID, + content, + embedding: new Array(1536).fill(0.1), + unique: true, + userId: TEST_UUID, + agentId: TEST_UUID, + roomId: TEST_UUID, + createdAt: Date.now() + }; + + // Act + await testClient.query('BEGIN'); + try { + await adapter.createMemory(memory, TEST_TABLE); + await testClient.query('COMMIT'); + } catch (error) { + await testClient.query('ROLLBACK'); + throw error; + } + + // Verify the embedding dimension + const { rows: [{ get_embedding_dimension }] } = await testClient.query('SELECT get_embedding_dimension()'); + expect(get_embedding_dimension).toBe(1536); + + // Retrieve and verify + const retrieved = await adapter.getMemoryById(TEST_UUID); + expect(retrieved).toBeDefined(); + const parsedEmbedding = typeof retrieved?.embedding === 'string' ? parseVectorString(retrieved.embedding) : retrieved?.embedding; + expect(Array.isArray(parsedEmbedding)).toBe(true); + expect(parsedEmbedding).toHaveLength(1536); + expect(retrieved?.content).toEqual(content); + }); + + test('should search memories by embedding', async () => { + // Arrange + const content: Content = { text: 'test content' }; + const embedding = new Array(1536).fill(0.1); + const memory: Memory = { + id: TEST_UUID, + content, + embedding, + unique: true, + userId: TEST_UUID, + agentId: TEST_UUID, + roomId: TEST_UUID, + createdAt: Date.now() + }; + + // Create memory within transaction + await testClient.query('BEGIN'); + try { + await adapter.createMemory(memory, TEST_TABLE); + await testClient.query('COMMIT'); + } catch (error) { + await testClient.query('ROLLBACK'); + throw error; + } + + // Act + const results = await adapter.searchMemoriesByEmbedding(embedding, { + tableName: TEST_TABLE, + roomId: TEST_UUID, + match_threshold: 0.8, + count: 1 + }); + + // Assert + expect(results).toBeDefined(); + expect(Array.isArray(results)).toBe(true); + expect(results.length).toBeGreaterThan(0); + const parsedEmbedding = typeof results[0].embedding === 'string' ? parseVectorString(results[0].embedding) : results[0].embedding; + expect(parsedEmbedding).toHaveLength(1536); + }); + + test('should handle invalid embedding dimensions', async () => { + // Arrange + const content: Content = { + text: 'test content' + }; + + const memory: Memory = { + id: TEST_UUID, + content, + embedding: new Array(100).fill(0.1), // Wrong dimension + unique: true, + userId: TEST_UUID, + agentId: TEST_UUID, + roomId: TEST_UUID, + createdAt: Date.now() + }; + + // Act & Assert + await testClient.query('BEGIN'); + try { + await expect(adapter.createMemory(memory, TEST_TABLE)) + .rejects + .toThrow('Invalid embedding dimension: expected 1536, got 100'); + await testClient.query('ROLLBACK'); + } catch (error) { + await testClient.query('ROLLBACK'); + throw error; + } + }, { timeout: 30000 }); // Increased timeout for retry attempts + }); +}); \ No newline at end of file diff --git a/packages/adapter-postgres/src/index.ts b/packages/adapter-postgres/src/index.ts index f1942b9fef9..48210999b9a 100644 --- a/packages/adapter-postgres/src/index.ts +++ b/packages/adapter-postgres/src/index.ts @@ -183,6 +183,27 @@ export class PostgresDatabaseAdapter }, "query"); } + private async validateVectorSetup(): Promise { + try { + const vectorExt = await this.query(` + SELECT 1 FROM pg_extension WHERE extname = 'vector' + `); + const hasVector = vectorExt.rows.length > 0; + + if (!hasVector) { + elizaLogger.error("Vector extension not found in database"); + return false; + } + + return true; + } catch (error) { + elizaLogger.error("Failed to validate vector extension:", { + error: error instanceof Error ? error.message : String(error) + }); + return false; + } + } + async init() { await this.testConnection(); @@ -211,7 +232,8 @@ export class PostgresDatabaseAdapter ); `); - if (!rows[0].exists) { + if (!rows[0].exists || !await this.validateVectorSetup()) { + elizaLogger.info("Applying database schema - tables or vector extension missing"); const schema = fs.readFileSync( path.resolve(__dirname, "../schema.sql"), "utf8" From 7d854f2dc3e2ea215ffee20db8551caed428da96 Mon Sep 17 00:00:00 2001 From: AIFlow_ML Date: Fri, 3 Jan 2025 17:13:39 +0700 Subject: [PATCH 023/112] fix(shell): Improve shell script exit code handling --- .../src/__tests__/run_tests.sh | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) mode change 100644 => 100755 packages/adapter-postgres/src/__tests__/run_tests.sh diff --git a/packages/adapter-postgres/src/__tests__/run_tests.sh b/packages/adapter-postgres/src/__tests__/run_tests.sh old mode 100644 new mode 100755 index 6a18b681eb9..f9acc13c13a --- a/packages/adapter-postgres/src/__tests__/run_tests.sh +++ b/packages/adapter-postgres/src/__tests__/run_tests.sh @@ -56,8 +56,8 @@ if [ ! -f "$SCHEMA_PATH" ]; then exit 1 fi -$DOCKER_COMPOSE_CMD -f docker-compose.test.yml exec -T postgres-test psql -U postgres -d eliza_test -f - < "$SCHEMA_PATH" -if [ $? -ne 0 ]; then +# Fix: Check exit code directly instead of using $? +if ! $DOCKER_COMPOSE_CMD -f docker-compose.test.yml exec -T postgres-test psql -U postgres -d eliza_test -f - < "$SCHEMA_PATH"; then echo -e "${RED}Failed to load schema${NC}" exit 1 fi @@ -65,20 +65,14 @@ echo -e "${GREEN}Schema loaded successfully!${NC}" # Run the tests echo -e "${YELLOW}Running tests...${NC}" -pnpm vitest vector-extension.test.ts +if ! pnpm vitest vector-extension.test.ts; then + echo -e "${RED}Tests failed!${NC}" + $DOCKER_COMPOSE_CMD -f docker-compose.test.yml down + exit 1 +fi -# Capture test exit code -TEST_EXIT_CODE=$? +echo -e "${GREEN}Tests completed successfully!${NC}" # Clean up echo -e "${YELLOW}Cleaning up test environment...${NC}" -$DOCKER_COMPOSE_CMD -f docker-compose.test.yml down - -# Exit with test exit code -if [ $TEST_EXIT_CODE -eq 0 ]; then - echo -e "${GREEN}Tests completed successfully!${NC}" -else - echo -e "${RED}Tests failed!${NC}" -fi - -exit $TEST_EXIT_CODE \ No newline at end of file +$DOCKER_COMPOSE_CMD -f docker-compose.test.yml down \ No newline at end of file From 0c3c3f32e5e9876071eec5a07bf6e6d1a0d44e08 Mon Sep 17 00:00:00 2001 From: Luka Petrovic Date: Fri, 3 Jan 2025 11:23:04 +0100 Subject: [PATCH 024/112] feat: add coingecko plugin --- packages/plugin-coingecko/.env.test | 1 + packages/plugin-coingecko/.npmignore | 6 + packages/plugin-coingecko/package.json | 17 ++ .../src/__tests__/getPrice.test.ts | 142 +++++++++++++ .../plugin-coingecko/src/actions/getPrice.ts | 195 ++++++++++++++++++ packages/plugin-coingecko/src/environment.ts | 30 +++ packages/plugin-coingecko/src/index.ts | 12 ++ packages/plugin-coingecko/src/types.ts | 22 ++ packages/plugin-coingecko/tsconfig.json | 10 + packages/plugin-coingecko/tsup.config.ts | 11 + 10 files changed, 446 insertions(+) create mode 100644 packages/plugin-coingecko/.env.test create mode 100644 packages/plugin-coingecko/.npmignore create mode 100644 packages/plugin-coingecko/package.json create mode 100644 packages/plugin-coingecko/src/__tests__/getPrice.test.ts create mode 100644 packages/plugin-coingecko/src/actions/getPrice.ts create mode 100644 packages/plugin-coingecko/src/environment.ts create mode 100644 packages/plugin-coingecko/src/index.ts create mode 100644 packages/plugin-coingecko/src/types.ts create mode 100644 packages/plugin-coingecko/tsconfig.json create mode 100644 packages/plugin-coingecko/tsup.config.ts diff --git a/packages/plugin-coingecko/.env.test b/packages/plugin-coingecko/.env.test new file mode 100644 index 00000000000..dafea90cce1 --- /dev/null +++ b/packages/plugin-coingecko/.env.test @@ -0,0 +1 @@ +COINGECKO_API_KEY=your_test_api_key_here \ No newline at end of file diff --git a/packages/plugin-coingecko/.npmignore b/packages/plugin-coingecko/.npmignore new file mode 100644 index 00000000000..0468b4b3648 --- /dev/null +++ b/packages/plugin-coingecko/.npmignore @@ -0,0 +1,6 @@ +* + +!dist/** +!package.json +!readme.md +!tsup.config.ts diff --git a/packages/plugin-coingecko/package.json b/packages/plugin-coingecko/package.json new file mode 100644 index 00000000000..fb1fe8b8307 --- /dev/null +++ b/packages/plugin-coingecko/package.json @@ -0,0 +1,17 @@ +{ + "name": "@elizaos/plugin-coingecko", + "version": "0.1.7-alpha.2", + "main": "dist/index.js", + "type": "module", + "types": "dist/index.d.ts", + "dependencies": { + "@elizaos/core": "workspace:*", + "axios": "^1.6.7", + "tsup": "^8.3.5" + }, + "scripts": { + "build": "tsup --format esm --dts", + "dev": "tsup --format esm --dts --watch", + "test": "vitest run" + } +} \ No newline at end of file diff --git a/packages/plugin-coingecko/src/__tests__/getPrice.test.ts b/packages/plugin-coingecko/src/__tests__/getPrice.test.ts new file mode 100644 index 00000000000..ed072b3e656 --- /dev/null +++ b/packages/plugin-coingecko/src/__tests__/getPrice.test.ts @@ -0,0 +1,142 @@ +import { defaultCharacter } from "@elizaos/core"; +import axios from "axios"; +import { + afterEach, + beforeAll, + beforeEach, + describe, + expect, + it, + vi, +} from "vitest"; +import getPriceAction from "../actions/getPrice"; + +// Mock axios +vi.mock("axios", () => ({ + default: { + get: vi.fn(), + }, +})); + +describe("getPrice Action", () => { + let mockedRuntime; + + beforeAll(() => { + mockedRuntime = { + character: defaultCharacter, + getSetting: vi.fn().mockReturnValue("test-api-key"), + composeState: vi.fn().mockResolvedValue({ + recentMessages: [ + { + id: "1", + timestamp: Date.now(), + content: { + text: "What is the price of Bitcoin?", + }, + user: "user1", + }, + ], + }), + updateRecentMessageState: vi + .fn() + .mockImplementation((state) => state), + }; + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + afterEach(() => { + vi.clearAllTimers(); + }); + + describe("Price Checking", () => { + it("should validate configuration successfully", async () => { + const result = await getPriceAction.validate(mockedRuntime, { + id: "1", + timestamp: Date.now(), + content: { text: "Check BTC price" }, + user: "user1", + }); + + expect(result).toBe(true); + }); + + it("should handle price fetch successfully", async () => { + const mockAxiosResponse = { + data: { + bitcoin: { + usd: 50000, + }, + }, + }; + + (axios.get as any).mockResolvedValueOnce(mockAxiosResponse); + + const mockCallback = vi.fn(); + + const result = await getPriceAction.handler( + mockedRuntime, + { + id: "1", + timestamp: Date.now(), + content: { text: "Check BTC price" }, + user: "user1", + }, + { + recentMessages: [ + { + id: "1", + timestamp: Date.now(), + content: { text: "Check BTC price" }, + user: "user1", + }, + ], + }, + {}, + mockCallback + ); + + expect(result).toBe(true); + expect(mockCallback).toHaveBeenCalledWith({ + text: expect.stringContaining("50000 USD"), + content: { price: 50000, currency: "usd" }, + }); + }); + + it("should handle API errors gracefully", async () => { + (axios.get as any).mockRejectedValueOnce(new Error("API Error")); + + const mockCallback = vi.fn(); + + const result = await getPriceAction.handler( + mockedRuntime, + { + id: "1", + timestamp: Date.now(), + content: { text: "Check BTC price" }, + user: "user1", + }, + { + recentMessages: [ + { + id: "1", + timestamp: Date.now(), + content: { text: "Check BTC price" }, + user: "user1", + }, + ], + }, + {}, + mockCallback + ); + + expect(result).toBe(false); + expect(mockCallback).toHaveBeenCalledWith({ + text: expect.stringContaining("Error fetching price"), + content: { error: "API Error" }, + }); + }); + }); +}); diff --git a/packages/plugin-coingecko/src/actions/getPrice.ts b/packages/plugin-coingecko/src/actions/getPrice.ts new file mode 100644 index 00000000000..852742bd267 --- /dev/null +++ b/packages/plugin-coingecko/src/actions/getPrice.ts @@ -0,0 +1,195 @@ +import { + ActionExample, + composeContext, + Content, + elizaLogger, + generateObject, + HandlerCallback, + IAgentRuntime, + Memory, + ModelClass, + State, + type Action, +} from "@elizaos/core"; +import axios from "axios"; +import { z } from "zod"; +import { validateCoingeckoConfig } from "../environment"; + +const GetPriceSchema = z.object({ + coinId: z.string(), + currency: z.string().default("usd"), +}); + +export interface GetPriceContent extends Content { + coinId: string; + currency: string; +} + +export function isGetPriceContent( + content: GetPriceContent +): content is GetPriceContent { + return ( + typeof content.coinId === "string" && + typeof content.currency === "string" + ); +} + +const getPriceTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. + +Here are several frequently used coin IDs. Use these for the corresponding tokens: +- bitcoin/btc: bitcoin +- ethereum/eth: ethereum +- usdc: usd-coin + +Example response: +\`\`\`json +{ + "coinId": "bitcoin", + "currency": "usd" +} +\`\`\` + +{{recentMessages}} + +Given the recent messages, extract the following information about the requested price check: +- Coin ID +- Currency (defaults to USD) + +Respond with a JSON markdown block containing only the extracted values.`; + +export default { + name: "GET_PRICE", + similes: [ + "CHECK_PRICE", + "PRICE_CHECK", + "GET_CRYPTO_PRICE", + "CHECK_CRYPTO_PRICE", + ], + validate: async (runtime: IAgentRuntime, message: Memory) => { + await validateCoingeckoConfig(runtime); + return true; + }, + description: "Get the current price of a cryptocurrency from CoinGecko", + handler: async ( + runtime: IAgentRuntime, + message: Memory, + state: State, + _options: { [key: string]: unknown }, + callback?: HandlerCallback + ): Promise => { + elizaLogger.log("Starting CoinGecko GET_PRICE handler..."); + + if (!state) { + state = (await runtime.composeState(message)) as State; + } else { + state = await runtime.updateRecentMessageState(state); + } + + const priceContext = composeContext({ + state, + template: getPriceTemplate, + }); + + const content = ( + await generateObject({ + runtime, + context: priceContext, + modelClass: ModelClass.SMALL, + schema: GetPriceSchema, + }) + ).object as unknown as GetPriceContent; + + if (!isGetPriceContent(content)) { + console.error("Invalid content for GET_PRICE action."); + if (callback) { + callback({ + text: "Unable to process price check request. Invalid content provided.", + content: { error: "Invalid price check content" }, + }); + } + return false; + } + + try { + const config = await validateCoingeckoConfig(runtime); + const response = await axios.get( + `https://api.coingecko.com/api/v3/simple/price`, + { + params: { + ids: content.coinId, + vs_currencies: content.currency, + x_cg_demo_api_key: config.COINGECKO_API_KEY, + }, + } + ); + + const price = response.data[content.coinId][content.currency]; + elizaLogger.success( + `Price retrieved successfully! ${content.coinId}: ${price} ${content.currency.toUpperCase()}` + ); + + if (callback) { + callback({ + text: `The current price of ${content.coinId} is ${price} ${content.currency.toUpperCase()}`, + content: { price, currency: content.currency }, + }); + } + + return true; + } catch (error) { + elizaLogger.error("Error fetching price:", error); + if (callback) { + callback({ + text: `Error fetching price: ${error.message}`, + content: { error: error.message }, + }); + } + return false; + } + }, + + examples: [ + [ + { + user: "{{user1}}", + content: { + text: "What's the current price of Bitcoin?", + }, + }, + { + user: "{{agent}}", + content: { + text: "Let me check the current Bitcoin price for you.", + action: "GET_PRICE", + }, + }, + { + user: "{{agent}}", + content: { + text: "The current price of Bitcoin is 65,432.21 USD", + }, + }, + ], + [ + { + user: "{{user1}}", + content: { + text: "Check ETH price in EUR", + }, + }, + { + user: "{{agent}}", + content: { + text: "I'll check the current Ethereum price in EUR.", + action: "GET_PRICE", + }, + }, + { + user: "{{agent}}", + content: { + text: "The current price of Ethereum is 2,345.67 EUR", + }, + }, + ], + ] as ActionExample[][], +} as Action; diff --git a/packages/plugin-coingecko/src/environment.ts b/packages/plugin-coingecko/src/environment.ts new file mode 100644 index 00000000000..276658e3714 --- /dev/null +++ b/packages/plugin-coingecko/src/environment.ts @@ -0,0 +1,30 @@ +import { IAgentRuntime } from "@elizaos/core"; +import { z } from "zod"; + +export const coingeckoEnvSchema = z.object({ + COINGECKO_API_KEY: z.string().min(1, "CoinGecko API key is required"), +}); + +export type CoingeckoConfig = z.infer; + +export async function validateCoingeckoConfig( + runtime: IAgentRuntime +): Promise { + try { + const config = { + COINGECKO_API_KEY: runtime.getSetting("COINGECKO_API_KEY"), + }; + + return coingeckoEnvSchema.parse(config); + } catch (error) { + if (error instanceof z.ZodError) { + const errorMessages = error.errors + .map((err) => `${err.path.join(".")}: ${err.message}`) + .join("\n"); + throw new Error( + `CoinGecko configuration validation failed:\n${errorMessages}` + ); + } + throw error; + } +} diff --git a/packages/plugin-coingecko/src/index.ts b/packages/plugin-coingecko/src/index.ts new file mode 100644 index 00000000000..b2962f10729 --- /dev/null +++ b/packages/plugin-coingecko/src/index.ts @@ -0,0 +1,12 @@ +import { Plugin } from "@elizaos/core"; +import getPrice from "./actions/getPrice"; + +export const coingeckoPlugin: Plugin = { + name: "coingecko", + description: "CoinGecko Plugin for Eliza", + actions: [getPrice], + evaluators: [], + providers: [], +}; + +export default coingeckoPlugin; diff --git a/packages/plugin-coingecko/src/types.ts b/packages/plugin-coingecko/src/types.ts new file mode 100644 index 00000000000..c2ee9d725d5 --- /dev/null +++ b/packages/plugin-coingecko/src/types.ts @@ -0,0 +1,22 @@ +// Type definitions for CoinGecko plugin + +export interface CoinGeckoConfig { + apiKey?: string; +} + +export interface PriceResponse { + [key: string]: { + [currency: string]: number; + }; +} + +export interface MarketData { + id: string; + symbol: string; + name: string; + current_price: number; + market_cap: number; + market_cap_rank: number; + price_change_percentage_24h: number; + total_volume: number; +} diff --git a/packages/plugin-coingecko/tsconfig.json b/packages/plugin-coingecko/tsconfig.json new file mode 100644 index 00000000000..73993deaaf7 --- /dev/null +++ b/packages/plugin-coingecko/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../core/tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts" + ] +} \ No newline at end of file diff --git a/packages/plugin-coingecko/tsup.config.ts b/packages/plugin-coingecko/tsup.config.ts new file mode 100644 index 00000000000..3e30481b3aa --- /dev/null +++ b/packages/plugin-coingecko/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + outDir: "dist", + sourcemap: true, + clean: true, + format: ["esm"], + dts: true, + external: ["dotenv", "fs", "path", "https", "http"] +}); From 67922dc4ab353f19430cb1640365f877a6b9afdc Mon Sep 17 00:00:00 2001 From: Luka Petrovic Date: Fri, 3 Jan 2025 12:22:08 +0100 Subject: [PATCH 025/112] test: removed deprecated test --- .../src/__tests__/getPrice.test.ts | 142 ------------------ pnpm-lock.yaml | 62 +++++--- 2 files changed, 44 insertions(+), 160 deletions(-) delete mode 100644 packages/plugin-coingecko/src/__tests__/getPrice.test.ts diff --git a/packages/plugin-coingecko/src/__tests__/getPrice.test.ts b/packages/plugin-coingecko/src/__tests__/getPrice.test.ts deleted file mode 100644 index ed072b3e656..00000000000 --- a/packages/plugin-coingecko/src/__tests__/getPrice.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { defaultCharacter } from "@elizaos/core"; -import axios from "axios"; -import { - afterEach, - beforeAll, - beforeEach, - describe, - expect, - it, - vi, -} from "vitest"; -import getPriceAction from "../actions/getPrice"; - -// Mock axios -vi.mock("axios", () => ({ - default: { - get: vi.fn(), - }, -})); - -describe("getPrice Action", () => { - let mockedRuntime; - - beforeAll(() => { - mockedRuntime = { - character: defaultCharacter, - getSetting: vi.fn().mockReturnValue("test-api-key"), - composeState: vi.fn().mockResolvedValue({ - recentMessages: [ - { - id: "1", - timestamp: Date.now(), - content: { - text: "What is the price of Bitcoin?", - }, - user: "user1", - }, - ], - }), - updateRecentMessageState: vi - .fn() - .mockImplementation((state) => state), - }; - }); - - beforeEach(() => { - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.clearAllTimers(); - }); - - describe("Price Checking", () => { - it("should validate configuration successfully", async () => { - const result = await getPriceAction.validate(mockedRuntime, { - id: "1", - timestamp: Date.now(), - content: { text: "Check BTC price" }, - user: "user1", - }); - - expect(result).toBe(true); - }); - - it("should handle price fetch successfully", async () => { - const mockAxiosResponse = { - data: { - bitcoin: { - usd: 50000, - }, - }, - }; - - (axios.get as any).mockResolvedValueOnce(mockAxiosResponse); - - const mockCallback = vi.fn(); - - const result = await getPriceAction.handler( - mockedRuntime, - { - id: "1", - timestamp: Date.now(), - content: { text: "Check BTC price" }, - user: "user1", - }, - { - recentMessages: [ - { - id: "1", - timestamp: Date.now(), - content: { text: "Check BTC price" }, - user: "user1", - }, - ], - }, - {}, - mockCallback - ); - - expect(result).toBe(true); - expect(mockCallback).toHaveBeenCalledWith({ - text: expect.stringContaining("50000 USD"), - content: { price: 50000, currency: "usd" }, - }); - }); - - it("should handle API errors gracefully", async () => { - (axios.get as any).mockRejectedValueOnce(new Error("API Error")); - - const mockCallback = vi.fn(); - - const result = await getPriceAction.handler( - mockedRuntime, - { - id: "1", - timestamp: Date.now(), - content: { text: "Check BTC price" }, - user: "user1", - }, - { - recentMessages: [ - { - id: "1", - timestamp: Date.now(), - content: { text: "Check BTC price" }, - user: "user1", - }, - ], - }, - {}, - mockCallback - ); - - expect(result).toBe(false); - expect(mockCallback).toHaveBeenCalledWith({ - text: expect.stringContaining("Error fetching price"), - content: { error: "API Error" }, - }); - }); - }); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e208d46a54..84fef3a8782 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1093,6 +1093,18 @@ importers: specifier: 8.3.5 version: 8.3.5(@swc/core@1.10.4(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.7.0) + packages/plugin-coingecko: + dependencies: + '@elizaos/core': + specifier: workspace:* + version: link:../core + axios: + specifier: ^1.6.7 + version: 1.7.9 + tsup: + specifier: ^8.3.5 + version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) + packages/plugin-conflux: dependencies: '@elizaos/core': @@ -19601,7 +19613,7 @@ snapshots: '@acuminous/bitsyntax@0.1.2': dependencies: buffer-more-ints: 1.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 safe-buffer: 5.1.2 transitivePeerDependencies: - supports-color @@ -21534,7 +21546,7 @@ snapshots: dependencies: '@scure/bip32': 1.6.0 abitype: 1.0.8(typescript@5.6.3)(zod@3.23.8) - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 axios-mock-adapter: 1.22.0(axios@1.7.9) axios-retry: 4.5.0(axios@1.7.9) bip32: 4.0.0 @@ -23369,7 +23381,7 @@ snapshots: '@eslint/config-array@0.19.1': dependencies: '@eslint/object-schema': 2.1.5 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -23395,7 +23407,7 @@ snapshots: '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -28792,7 +28804,7 @@ snapshots: '@typescript-eslint/types': 8.16.0 '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 eslint: 9.16.0(jiti@2.4.2) optionalDependencies: typescript: 5.6.3 @@ -28825,7 +28837,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.6.3) '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 eslint: 9.16.0(jiti@2.4.2) ts-api-utils: 1.4.3(typescript@5.6.3) optionalDependencies: @@ -28856,7 +28868,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.16.0 '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -29646,7 +29658,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -30038,13 +30050,13 @@ snapshots: axios-mock-adapter@1.22.0(axios@1.7.9): dependencies: - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 fast-deep-equal: 3.1.3 is-buffer: 2.0.5 axios-retry@4.5.0(axios@1.7.9): dependencies: - axios: 1.7.9(debug@4.4.0) + axios: 1.7.9 is-retry-allowed: 2.2.0 axios@0.21.4: @@ -30055,7 +30067,7 @@ snapshots: axios@0.27.2: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.9 form-data: 4.0.1 transitivePeerDependencies: - debug @@ -30084,6 +30096,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.7.9: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axios@1.7.9(debug@4.4.0): dependencies: follow-redirects: 1.15.9(debug@4.4.0) @@ -32119,6 +32139,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.0: + dependencies: + ms: 2.1.3 + debug@4.4.0(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -33018,7 +33042,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -33604,6 +33628,8 @@ snapshots: async: 0.2.10 which: 1.3.1 + follow-redirects@1.15.9: {} + follow-redirects@1.15.9(debug@4.3.7): optionalDependencies: debug: 4.3.7 @@ -34682,7 +34708,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -34738,14 +34764,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -41113,7 +41139,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -42122,7 +42148,7 @@ snapshots: tuf-js@2.2.1: dependencies: '@tufjs/models': 2.0.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color @@ -42914,7 +42940,7 @@ snapshots: '@vitest/spy': 2.1.5 '@vitest/utils': 2.1.5 chai: 5.1.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0 expect-type: 1.1.0 magic-string: 0.30.17 pathe: 1.1.2 From c5d6367a71ff10ab227a22826a5279c141b64e6a Mon Sep 17 00:00:00 2001 From: Luka Petrovic Date: Fri, 3 Jan 2025 15:16:39 +0100 Subject: [PATCH 026/112] feat: add readme.md, fix getprice --- agent/package.json | 149 +++++++++--------- agent/src/index.ts | 28 ++-- packages/plugin-coingecko/README.md | 49 ++++++ .../plugin-coingecko/src/actions/getPrice.ts | 123 ++++++--------- .../plugin-coingecko/src/templates/price.ts | 31 ++++ packages/plugin-coingecko/src/utils/coin.ts | 22 +++ pnpm-lock.yaml | 55 +++---- 7 files changed, 266 insertions(+), 191 deletions(-) create mode 100644 packages/plugin-coingecko/README.md create mode 100644 packages/plugin-coingecko/src/templates/price.ts create mode 100644 packages/plugin-coingecko/src/utils/coin.ts diff --git a/agent/package.json b/agent/package.json index 48b3f4270ab..a3172b1e523 100644 --- a/agent/package.json +++ b/agent/package.json @@ -1,75 +1,76 @@ { - "name": "@elizaos/agent", - "version": "0.1.7-alpha.2", - "main": "src/index.ts", - "type": "module", - "scripts": { - "start": "node --loader ts-node/esm src/index.ts", - "dev": "node --loader ts-node/esm src/index.ts", - "check-types": "tsc --noEmit", - "test": "jest" - }, - "nodemonConfig": { - "watch": [ - "src", - "../core/dist" - ], - "ext": "ts,json", - "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" - }, - "dependencies": { - "@elizaos/adapter-postgres": "workspace:*", - "@elizaos/adapter-redis": "workspace:*", - "@elizaos/adapter-sqlite": "workspace:*", - "@elizaos/client-auto": "workspace:*", - "@elizaos/client-direct": "workspace:*", - "@elizaos/client-discord": "workspace:*", - "@elizaos/client-farcaster": "workspace:*", - "@elizaos/client-lens": "workspace:*", - "@elizaos/client-telegram": "workspace:*", - "@elizaos/client-twitter": "workspace:*", - "@elizaos/client-slack": "workspace:*", - "@elizaos/core": "workspace:*", - "@elizaos/plugin-0g": "workspace:*", - "@elizaos/plugin-abstract": "workspace:*", - "@elizaos/plugin-aptos": "workspace:*", - "@elizaos/plugin-bootstrap": "workspace:*", - "@elizaos/plugin-intiface": "workspace:*", - "@elizaos/plugin-coinbase": "workspace:*", - "@elizaos/plugin-conflux": "workspace:*", - "@elizaos/plugin-evm": "workspace:*", - "@elizaos/plugin-echochambers": "workspace:*", - "@elizaos/plugin-flow": "workspace:*", - "@elizaos/plugin-gitbook": "workspace:*", - "@elizaos/plugin-story": "workspace:*", - "@elizaos/plugin-goat": "workspace:*", - "@elizaos/plugin-icp": "workspace:*", - "@elizaos/plugin-image-generation": "workspace:*", - "@elizaos/plugin-nft-generation": "workspace:*", - "@elizaos/plugin-node": "workspace:*", - "@elizaos/plugin-solana": "workspace:*", - "@elizaos/plugin-starknet": "workspace:*", - "@elizaos/plugin-ton": "workspace:*", - "@elizaos/plugin-sui": "workspace:*", - "@elizaos/plugin-tee": "workspace:*", - "@elizaos/plugin-multiversx": "workspace:*", - "@elizaos/plugin-near": "workspace:*", - "@elizaos/plugin-zksync-era": "workspace:*", - "@elizaos/plugin-twitter": "workspace:*", - "@elizaos/plugin-cronoszkevm": "workspace:*", - "@elizaos/plugin-3d-generation": "workspace:*", - "@elizaos/plugin-fuel": "workspace:*", - "@elizaos/plugin-avalanche": "workspace:*", - "@elizaos/plugin-web-search": "workspace:*", - "readline": "1.3.0", - "ws": "8.18.0", - "yargs": "17.7.2" - }, - "devDependencies": { - "@types/jest": "^29.5.14", - "jest": "^29.7.0", - "ts-jest": "^29.2.5", - "ts-node": "10.9.2", - "tsup": "8.3.5" - } -} + "name": "@elizaos/agent", + "version": "0.1.7-alpha.2", + "main": "src/index.ts", + "type": "module", + "scripts": { + "start": "node --loader ts-node/esm src/index.ts", + "dev": "node --loader ts-node/esm src/index.ts", + "check-types": "tsc --noEmit", + "test": "jest" + }, + "nodemonConfig": { + "watch": [ + "src", + "../core/dist" + ], + "ext": "ts,json", + "exec": "node --enable-source-maps --loader ts-node/esm src/index.ts" + }, + "dependencies": { + "@elizaos/adapter-postgres": "workspace:*", + "@elizaos/adapter-redis": "workspace:*", + "@elizaos/adapter-sqlite": "workspace:*", + "@elizaos/client-auto": "workspace:*", + "@elizaos/client-direct": "workspace:*", + "@elizaos/client-discord": "workspace:*", + "@elizaos/client-farcaster": "workspace:*", + "@elizaos/client-lens": "workspace:*", + "@elizaos/client-telegram": "workspace:*", + "@elizaos/client-twitter": "workspace:*", + "@elizaos/client-slack": "workspace:*", + "@elizaos/core": "workspace:*", + "@elizaos/plugin-0g": "workspace:*", + "@elizaos/plugin-abstract": "workspace:*", + "@elizaos/plugin-aptos": "workspace:*", + "@elizaos/plugin-bootstrap": "workspace:*", + "@elizaos/plugin-intiface": "workspace:*", + "@elizaos/plugin-coinbase": "workspace:*", + "@elizaos/plugin-coingecko": "workspace:*", + "@elizaos/plugin-conflux": "workspace:*", + "@elizaos/plugin-evm": "workspace:*", + "@elizaos/plugin-echochambers": "workspace:*", + "@elizaos/plugin-flow": "workspace:*", + "@elizaos/plugin-gitbook": "workspace:*", + "@elizaos/plugin-story": "workspace:*", + "@elizaos/plugin-goat": "workspace:*", + "@elizaos/plugin-icp": "workspace:*", + "@elizaos/plugin-image-generation": "workspace:*", + "@elizaos/plugin-nft-generation": "workspace:*", + "@elizaos/plugin-node": "workspace:*", + "@elizaos/plugin-solana": "workspace:*", + "@elizaos/plugin-starknet": "workspace:*", + "@elizaos/plugin-ton": "workspace:*", + "@elizaos/plugin-sui": "workspace:*", + "@elizaos/plugin-tee": "workspace:*", + "@elizaos/plugin-multiversx": "workspace:*", + "@elizaos/plugin-near": "workspace:*", + "@elizaos/plugin-zksync-era": "workspace:*", + "@elizaos/plugin-twitter": "workspace:*", + "@elizaos/plugin-cronoszkevm": "workspace:*", + "@elizaos/plugin-3d-generation": "workspace:*", + "@elizaos/plugin-fuel": "workspace:*", + "@elizaos/plugin-avalanche": "workspace:*", + "@elizaos/plugin-web-search": "workspace:*", + "readline": "1.3.0", + "ws": "8.18.0", + "yargs": "17.7.2" + }, + "devDependencies": { + "@types/jest": "^29.5.14", + "jest": "^29.7.0", + "ts-jest": "^29.2.5", + "ts-node": "10.9.2", + "tsup": "8.3.5" + } +} \ No newline at end of file diff --git a/agent/src/index.ts b/agent/src/index.ts index 53058cf4ece..2179101b0ce 100644 --- a/agent/src/index.ts +++ b/agent/src/index.ts @@ -1,4 +1,5 @@ import { PostgresDatabaseAdapter } from "@elizaos/adapter-postgres"; +import { RedisClient } from "@elizaos/adapter-redis"; import { SqliteDatabaseAdapter } from "@elizaos/adapter-sqlite"; import { AutoClientInterface } from "@elizaos/client-auto"; import { DiscordClientInterface } from "@elizaos/client-discord"; @@ -10,31 +11,32 @@ import { TwitterClientInterface } from "@elizaos/client-twitter"; import { AgentRuntime, CacheManager, + CacheStore, Character, + Client, Clients, DbCacheAdapter, defaultCharacter, elizaLogger, FsCacheAdapter, IAgentRuntime, + ICacheManager, IDatabaseAdapter, IDatabaseCacheAdapter, ModelProviderName, settings, stringToUuid, validateCharacterConfig, - CacheStore, - Client, - ICacheManager, - parseBooleanFromText, } from "@elizaos/core"; -import { RedisClient } from "@elizaos/adapter-redis"; import { zgPlugin } from "@elizaos/plugin-0g"; import { bootstrapPlugin } from "@elizaos/plugin-bootstrap"; import createGoatPlugin from "@elizaos/plugin-goat"; // import { intifacePlugin } from "@elizaos/plugin-intiface"; import { DirectClient } from "@elizaos/client-direct"; +import { ThreeDGenerationPlugin } from "@elizaos/plugin-3d-generation"; +import { abstractPlugin } from "@elizaos/plugin-abstract"; import { aptosPlugin } from "@elizaos/plugin-aptos"; +import { avalanchePlugin } from "@elizaos/plugin-avalanche"; import { advancedTradePlugin, coinbaseCommercePlugin, @@ -43,33 +45,31 @@ import { tradePlugin, webhookPlugin, } from "@elizaos/plugin-coinbase"; +import { coingeckoPlugin } from "@elizaos/plugin-coingecko"; import { confluxPlugin } from "@elizaos/plugin-conflux"; +import { cronosZkEVMPlugin } from "@elizaos/plugin-cronoszkevm"; +import { echoChamberPlugin } from "@elizaos/plugin-echochambers"; import { evmPlugin } from "@elizaos/plugin-evm"; -import { storyPlugin } from "@elizaos/plugin-story"; import { flowPlugin } from "@elizaos/plugin-flow"; import { fuelPlugin } from "@elizaos/plugin-fuel"; import { imageGenerationPlugin } from "@elizaos/plugin-image-generation"; -import { ThreeDGenerationPlugin } from "@elizaos/plugin-3d-generation"; import { multiversxPlugin } from "@elizaos/plugin-multiversx"; import { nearPlugin } from "@elizaos/plugin-near"; import { nftGenerationPlugin } from "@elizaos/plugin-nft-generation"; import { createNodePlugin } from "@elizaos/plugin-node"; import { solanaPlugin } from "@elizaos/plugin-solana"; +import { storyPlugin } from "@elizaos/plugin-story"; import { suiPlugin } from "@elizaos/plugin-sui"; import { TEEMode, teePlugin } from "@elizaos/plugin-tee"; import { tonPlugin } from "@elizaos/plugin-ton"; -import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era"; -import { cronosZkEVMPlugin } from "@elizaos/plugin-cronoszkevm"; -import { abstractPlugin } from "@elizaos/plugin-abstract"; -import { avalanchePlugin } from "@elizaos/plugin-avalanche"; import { webSearchPlugin } from "@elizaos/plugin-web-search"; -import { echoChamberPlugin } from "@elizaos/plugin-echochambers"; +import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era"; import Database from "better-sqlite3"; import fs from "fs"; +import net from "net"; import path from "path"; import { fileURLToPath } from "url"; import yargs from "yargs"; -import net from "net"; const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file const __dirname = path.dirname(__filename); // get the name of the directory @@ -585,6 +585,8 @@ export async function createAgent( ? webhookPlugin : null, goatPlugin, + getSecret(character, "COINGECKO_API_KEY") ? coingeckoPlugin : null, + getSecret(character, "EVM_PROVIDER_URL") ? goatPlugin : null, getSecret(character, "ABSTRACT_PRIVATE_KEY") ? abstractPlugin : null, diff --git a/packages/plugin-coingecko/README.md b/packages/plugin-coingecko/README.md new file mode 100644 index 00000000000..ded984b61c4 --- /dev/null +++ b/packages/plugin-coingecko/README.md @@ -0,0 +1,49 @@ +# Plugin CoinGecko + +A plugin for fetching cryptocurrency price data from the CoinGecko API. + +## Overview + +The Plugin CoinGecko provides a simple interface to get real-time cryptocurrency prices. It integrates with CoinGecko's API to fetch current prices for various cryptocurrencies in different fiat currencies. + +## Installation + +```bash +pnpm add @elizaos/plugin-coingecko +``` + +## Configuration + +Set up your environment with the required CoinGecko API key: + +| Variable Name | Description | +| ------------------- | ---------------------- | +| `COINGECKO_API_KEY` | Your CoinGecko API key | + +## Usage + +```typescript +import { coingeckoPlugin } from "@elizaos/plugin-coingecko"; + +// Initialize the plugin +const plugin = coingeckoPlugin; + +// The plugin provides the GET_PRICE action which can be used to fetch prices +// Supported coins: BTC, ETH, USDC, and more +``` + +## Actions + +### GET_PRICE + +Fetches the current price of a cryptocurrency. + +Examples: + +- "What's the current price of Bitcoin?" +- "Check ETH price in EUR" +- "What's USDC worth?" + +## License + +MIT diff --git a/packages/plugin-coingecko/src/actions/getPrice.ts b/packages/plugin-coingecko/src/actions/getPrice.ts index 852742bd267..deb923b2e91 100644 --- a/packages/plugin-coingecko/src/actions/getPrice.ts +++ b/packages/plugin-coingecko/src/actions/getPrice.ts @@ -3,7 +3,7 @@ import { composeContext, Content, elizaLogger, - generateObject, + generateObjectDeprecated, HandlerCallback, IAgentRuntime, Memory, @@ -12,51 +12,15 @@ import { type Action, } from "@elizaos/core"; import axios from "axios"; -import { z } from "zod"; import { validateCoingeckoConfig } from "../environment"; - -const GetPriceSchema = z.object({ - coinId: z.string(), - currency: z.string().default("usd"), -}); +import { getPriceTemplate } from "../templates/price"; +import { normalizeCoinId } from "../utils/coin"; export interface GetPriceContent extends Content { coinId: string; currency: string; } -export function isGetPriceContent( - content: GetPriceContent -): content is GetPriceContent { - return ( - typeof content.coinId === "string" && - typeof content.currency === "string" - ); -} - -const getPriceTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. - -Here are several frequently used coin IDs. Use these for the corresponding tokens: -- bitcoin/btc: bitcoin -- ethereum/eth: ethereum -- usdc: usd-coin - -Example response: -\`\`\`json -{ - "coinId": "bitcoin", - "currency": "usd" -} -\`\`\` - -{{recentMessages}} - -Given the recent messages, extract the following information about the requested price check: -- Coin ID -- Currency (defaults to USD) - -Respond with a JSON markdown block containing only the extracted values.`; - export default { name: "GET_PRICE", similes: [ @@ -79,65 +43,82 @@ export default { ): Promise => { elizaLogger.log("Starting CoinGecko GET_PRICE handler..."); + // Initialize or update state if (!state) { state = (await runtime.composeState(message)) as State; } else { state = await runtime.updateRecentMessageState(state); } - const priceContext = composeContext({ - state, - template: getPriceTemplate, - }); - - const content = ( - await generateObject({ + try { + // Compose price check context + elizaLogger.log("Composing price context..."); + const priceContext = composeContext({ + state, + template: getPriceTemplate, + }); + + elizaLogger.log("Composing content..."); + const content = (await generateObjectDeprecated({ runtime, context: priceContext, - modelClass: ModelClass.SMALL, - schema: GetPriceSchema, - }) - ).object as unknown as GetPriceContent; + modelClass: ModelClass.LARGE, + })) as unknown as GetPriceContent; - if (!isGetPriceContent(content)) { - console.error("Invalid content for GET_PRICE action."); - if (callback) { - callback({ - text: "Unable to process price check request. Invalid content provided.", - content: { error: "Invalid price check content" }, - }); + // Validate content structure first + if (!content || typeof content !== "object") { + throw new Error("Invalid response format from model"); } - return false; - } - try { + // Get and validate coin ID + const coinId = content.coinId + ? normalizeCoinId(content.coinId) + : null; + if (!coinId) { + throw new Error( + `Unsupported or invalid cryptocurrency: ${content.coinId}` + ); + } + + // Normalize currency + const currency = (content.currency || "usd").toLowerCase(); + + // Fetch price from CoinGecko const config = await validateCoingeckoConfig(runtime); + elizaLogger.log(`Fetching price for ${coinId} in ${currency}...`); + const response = await axios.get( `https://api.coingecko.com/api/v3/simple/price`, { params: { - ids: content.coinId, - vs_currencies: content.currency, + ids: coinId, + vs_currencies: currency, x_cg_demo_api_key: config.COINGECKO_API_KEY, }, } ); - const price = response.data[content.coinId][content.currency]; + if (!response.data[coinId]?.[currency]) { + throw new Error( + `No price data available for ${coinId} in ${currency}` + ); + } + + const price = response.data[coinId][currency]; elizaLogger.success( - `Price retrieved successfully! ${content.coinId}: ${price} ${content.currency.toUpperCase()}` + `Price retrieved successfully! ${coinId}: ${price} ${currency.toUpperCase()}` ); if (callback) { callback({ - text: `The current price of ${content.coinId} is ${price} ${content.currency.toUpperCase()}`, - content: { price, currency: content.currency }, + text: `The current price of ${coinId} is ${price} ${currency.toUpperCase()}`, + content: { price, currency }, }); } return true; } catch (error) { - elizaLogger.error("Error fetching price:", error); + elizaLogger.error("Error in GET_PRICE handler:", error); if (callback) { callback({ text: `Error fetching price: ${error.message}`, @@ -159,14 +140,14 @@ export default { { user: "{{agent}}", content: { - text: "Let me check the current Bitcoin price for you.", + text: "I'll check the current Bitcoin price for you.", action: "GET_PRICE", }, }, { user: "{{agent}}", content: { - text: "The current price of Bitcoin is 65,432.21 USD", + text: "The current price of bitcoin is {{dynamic}} USD", }, }, ], @@ -180,14 +161,14 @@ export default { { user: "{{agent}}", content: { - text: "I'll check the current Ethereum price in EUR.", + text: "I'll check the current Ethereum price in EUR for you.", action: "GET_PRICE", }, }, { user: "{{agent}}", content: { - text: "The current price of Ethereum is 2,345.67 EUR", + text: "The current price of ethereum is {{dynamic}} EUR", }, }, ], diff --git a/packages/plugin-coingecko/src/templates/price.ts b/packages/plugin-coingecko/src/templates/price.ts new file mode 100644 index 00000000000..e30175c6bf3 --- /dev/null +++ b/packages/plugin-coingecko/src/templates/price.ts @@ -0,0 +1,31 @@ +export const getPriceTemplate = `Given the message, extract information about the cryptocurrency price check request. Look for coin name/symbol and currency. + +Common coin mappings: +- BTC/Bitcoin -> "bitcoin" +- ETH/Ethereum -> "ethereum" +- USDC -> "usd-coin" + +Format the response as a JSON object with these fields: +- coinId: the normalized coin ID (e.g., "bitcoin", "ethereum", "usd-coin") +- currency: the currency for price (default to "usd" if not specified) + +Example responses: +For "What's the price of Bitcoin?": +\`\`\`json +{ + "coinId": "bitcoin", + "currency": "usd" +} +\`\`\` + +For "Check ETH price in EUR": +\`\`\`json +{ + "coinId": "ethereum", + "currency": "eur" +} +\`\`\` + +{{recentMessages}} + +Extract the cryptocurrency and currency information from the above messages and respond with the appropriate JSON.`; diff --git a/packages/plugin-coingecko/src/utils/coin.ts b/packages/plugin-coingecko/src/utils/coin.ts new file mode 100644 index 00000000000..6a30d8510cf --- /dev/null +++ b/packages/plugin-coingecko/src/utils/coin.ts @@ -0,0 +1,22 @@ +export const COIN_ID_MAPPING = { + // Bitcoin variations + btc: "bitcoin", + bitcoin: "bitcoin", + // Ethereum variations + eth: "ethereum", + ethereum: "ethereum", + // USDC variations + usdc: "usd-coin", + "usd-coin": "usd-coin", + // Add more mappings as needed +} as const; + +/** + * Normalizes a coin name/symbol to its CoinGecko ID + * @param input The coin name or symbol to normalize + * @returns The normalized CoinGecko ID or null if not found + */ +export function normalizeCoinId(input: string): string | null { + const normalized = input.toLowerCase().trim(); + return COIN_ID_MAPPING[normalized] || null; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84fef3a8782..597bfa7e52b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -159,6 +159,9 @@ importers: '@elizaos/plugin-coinbase': specifier: workspace:* version: link:../packages/plugin-coinbase + '@elizaos/plugin-coingecko': + specifier: workspace:* + version: link:../packages/plugin-coingecko '@elizaos/plugin-conflux': specifier: workspace:* version: link:../packages/plugin-conflux @@ -1100,7 +1103,7 @@ importers: version: link:../core axios: specifier: ^1.6.7 - version: 1.7.9 + version: 1.7.9(debug@4.4.0) tsup: specifier: ^8.3.5 version: 8.3.5(@swc/core@1.10.1(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.1) @@ -19613,7 +19616,7 @@ snapshots: '@acuminous/bitsyntax@0.1.2': dependencies: buffer-more-ints: 1.0.0 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) safe-buffer: 5.1.2 transitivePeerDependencies: - supports-color @@ -21546,7 +21549,7 @@ snapshots: dependencies: '@scure/bip32': 1.6.0 abitype: 1.0.8(typescript@5.6.3)(zod@3.23.8) - axios: 1.7.9 + axios: 1.7.9(debug@4.4.0) axios-mock-adapter: 1.22.0(axios@1.7.9) axios-retry: 4.5.0(axios@1.7.9) bip32: 4.0.0 @@ -23381,7 +23384,7 @@ snapshots: '@eslint/config-array@0.19.1': dependencies: '@eslint/object-schema': 2.1.5 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -23407,7 +23410,7 @@ snapshots: '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -28804,7 +28807,7 @@ snapshots: '@typescript-eslint/types': 8.16.0 '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) eslint: 9.16.0(jiti@2.4.2) optionalDependencies: typescript: 5.6.3 @@ -28837,7 +28840,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.16.0(typescript@5.6.3) '@typescript-eslint/utils': 8.16.0(eslint@9.16.0(jiti@2.4.2))(typescript@5.6.3) - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) eslint: 9.16.0(jiti@2.4.2) ts-api-utils: 1.4.3(typescript@5.6.3) optionalDependencies: @@ -28868,7 +28871,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.16.0 '@typescript-eslint/visitor-keys': 8.16.0 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -29658,7 +29661,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -30050,13 +30053,13 @@ snapshots: axios-mock-adapter@1.22.0(axios@1.7.9): dependencies: - axios: 1.7.9 + axios: 1.7.9(debug@4.4.0) fast-deep-equal: 3.1.3 is-buffer: 2.0.5 axios-retry@4.5.0(axios@1.7.9): dependencies: - axios: 1.7.9 + axios: 1.7.9(debug@4.4.0) is-retry-allowed: 2.2.0 axios@0.21.4: @@ -30067,7 +30070,7 @@ snapshots: axios@0.27.2: dependencies: - follow-redirects: 1.15.9 + follow-redirects: 1.15.9(debug@4.4.0) form-data: 4.0.1 transitivePeerDependencies: - debug @@ -30096,14 +30099,6 @@ snapshots: transitivePeerDependencies: - debug - axios@1.7.9: - dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.1 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - axios@1.7.9(debug@4.4.0): dependencies: follow-redirects: 1.15.9(debug@4.4.0) @@ -32139,10 +32134,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.0: - dependencies: - ms: 2.1.3 - debug@4.4.0(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -33042,7 +33033,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -33628,8 +33619,6 @@ snapshots: async: 0.2.10 which: 1.3.1 - follow-redirects@1.15.9: {} - follow-redirects@1.15.9(debug@4.3.7): optionalDependencies: debug: 4.3.7 @@ -34708,7 +34697,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -34764,14 +34753,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -41139,7 +41128,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -42148,7 +42137,7 @@ snapshots: tuf-js@2.2.1: dependencies: '@tufjs/models': 2.0.1 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) make-fetch-happen: 13.0.1 transitivePeerDependencies: - supports-color @@ -42940,7 +42929,7 @@ snapshots: '@vitest/spy': 2.1.5 '@vitest/utils': 2.1.5 chai: 5.1.2 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) expect-type: 1.1.0 magic-string: 0.30.17 pathe: 1.1.2 From 39e0cef9d1fea636c1333770ea434a525694bc39 Mon Sep 17 00:00:00 2001 From: JSon Date: Thu, 2 Jan 2025 22:46:06 +0800 Subject: [PATCH 027/112] feat: plugin-nft-generation support evm chain mint nft --- .../src/actions/mintNFTAction.ts | 209 ++++++++++++------ .../src/actions/nftCollectionGeneration.ts | 4 +- .../plugin-nft-generation/src/templates.ts | 7 +- packages/plugin-nft-generation/src/types.ts | 4 +- .../src/utils/deployEVMContract.ts | 29 +-- .../src/utils/verifyEVMContract.ts | 4 +- 6 files changed, 157 insertions(+), 100 deletions(-) diff --git a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts index 61f4d70984e..ab268b5fd33 100644 --- a/packages/plugin-nft-generation/src/actions/mintNFTAction.ts +++ b/packages/plugin-nft-generation/src/actions/mintNFTAction.ts @@ -16,9 +16,16 @@ import WalletSolana from "../provider/wallet/walletSolana.ts"; import { PublicKey } from "@solana/web3.js"; import { mintNFTTemplate } from "../templates.ts"; import { MintNFTContent, MintNFTSchema } from "../types.ts"; +import * as viemChains from "viem/chains"; +import { createPublicClient, createWalletClient, http } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { mintNFT } from "../utils/deployEVMContract.ts"; +const _SupportedChainList = Object.keys(viemChains) as Array< + keyof typeof viemChains +>; function isMintNFTContent(content: any): content is MintNFTContent { - return typeof content.collectionAddress === "string"; + return typeof content.collectionAddress === "string" && typeof content.collectionAddress === "string"; } const mintNFTAction: Action = { @@ -72,19 +79,35 @@ const mintNFTAction: Action = { state = await runtime.updateRecentMessageState(state); } - // Compose transfer context - const transferContext = composeContext({ + const context = composeContext({ state, template: mintNFTTemplate, }); + const chains = _SupportedChainList; + + const supportedChains: ( + | (typeof chains)[number] + | "solana" + | null + )[] = [...chains, "solana", null]; + const contextWithChains = context.replace( + "SUPPORTED_CHAINS", + supportedChains + .map((item) => (item ? `"${item}"` : item)) + .join("|") + ); + const res = await generateObject({ runtime, - context: transferContext, + context: contextWithChains, modelClass: ModelClass.LARGE, schema: MintNFTSchema, }); - const content = res.object; + const content = res.object as { + collectionAddress: string, + chainName: (typeof supportedChains)[number]; + }; elizaLogger.log("Generate Object:", content); @@ -99,63 +122,111 @@ const mintNFTAction: Action = { return false; } + if (content?.chainName === "solana") { + const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); + const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); - const publicKey = runtime.getSetting("SOLANA_PUBLIC_KEY"); - const privateKey = runtime.getSetting("SOLANA_PRIVATE_KEY"); + const wallet = new WalletSolana( + new PublicKey(publicKey), + privateKey + ); - const wallet = new WalletSolana( - new PublicKey(publicKey), - privateKey - ); - - const collectionInfo = await wallet.fetchDigitalAsset( - content.collectionAddress - ); - elizaLogger.log("Collection Info", collectionInfo); - const metadata = collectionInfo.metadata; - if (metadata.collection?.["value"]) { - callback({ - text: `Unable to process mint request. Invalid collection address ${content.collectionAddress}.`, - content: { error: "Invalid collection address." }, - }); - return false; - } - if (metadata) { - const nftRes = await createNFT({ - runtime, - collectionName: metadata.name, - collectionAddress: content.collectionAddress, - collectionAdminPublicKey: metadata.updateAuthority, - collectionFee: metadata.sellerFeeBasisPoints, - tokenId: 1, - }); - - elizaLogger.log("NFT Address:", nftRes); - - if (nftRes) { + const collectionInfo = await wallet.fetchDigitalAsset( + content.collectionAddress + ); + elizaLogger.log("Collection Info", collectionInfo); + const metadata = collectionInfo.metadata; + if (metadata.collection?.["value"]) { callback({ - text: `Congratulations to you! 🎉🎉🎉 \nCollection Address: ${content.collectionAddress}\n NFT Address: ${nftRes.address}\n NFT Link: ${nftRes.link}`, //caption.description, - attachments: [], + text: `Unable to process mint request. Invalid collection address ${content.collectionAddress}.`, + content: { error: "Invalid collection address." }, }); - await sleep(15000); - await verifyNFT({ + return false; + } + if (metadata) { + const nftRes = await createNFT({ runtime, + collectionName: metadata.name, collectionAddress: content.collectionAddress, - NFTAddress: nftRes.address, + collectionAdminPublicKey: metadata.updateAuthority, + collectionFee: metadata.sellerFeeBasisPoints, + tokenId: 1, }); + + elizaLogger.log("NFT Address:", nftRes); + + if (nftRes) { + callback({ + text: `Congratulations to you! 🎉🎉🎉 \nCollection Address: ${content.collectionAddress}\n NFT Address: ${nftRes.address}\n NFT Link: ${nftRes.link}`, //caption.description, + attachments: [], + }); + await sleep(15000); + await verifyNFT({ + runtime, + collectionAddress: content.collectionAddress, + NFTAddress: nftRes.address, + }); + } else { + callback({ + text: `Mint NFT Error in ${content.collectionAddress}.`, + content: { error: "Mint NFT Error." }, + }); + return false; + } } else { callback({ - text: `Mint NFT Error in ${content.collectionAddress}.`, - content: { error: "Mint NFT Error." }, + text: "Unable to process mint request. Invalid collection address.", + content: { error: "Invalid collection address." }, }); return false; } - } else { - callback({ - text: "Unable to process mint request. Invalid collection address.", - content: { error: "Invalid collection address." }, + } else if (chains.indexOf(content.chainName)) { + const privateKey = runtime.getSetting( + "WALLET_PRIVATE_KEY" + ) as `0x${string}`; + if (!privateKey) return null; + const rpcUrl = + viemChains[content.chainName].rpcUrls.default.http[0]; + const chain = viemChains[content.chainName]; // 替换为目标链 + const provider = http(rpcUrl); + const account = privateKeyToAccount(privateKey); + const walletClient = createWalletClient({ + account, + chain: chain, + transport: provider, }); - return false; + + const publicClient = createPublicClient({ + chain: chain, + transport: provider, + }); + await mintNFT({ + walletClient, + publicClient, + contractAddress: content.collectionAddress, + abi: [ + { + "inputs": [ + { + "internalType": "address", + "name": "_to", + "type": "address" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + recipient: account.address, + }) + if (callback) { + callback({ + text: `Congratulations to you! 🎉🎉🎉 \nCollection Address: ${content.collectionAddress}\n `, //caption.description, + attachments: [], + }); + } } return []; } catch (e: any) { @@ -168,13 +239,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "mint nft for collection: D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + text: "mint nft for collection: D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana", }, }, { user: "{{agentName}}", content: { - text: "I've minted a new NFT in your specified collection.", + text: "I've minted a new NFT in your specified collection on Solana.", action: "MINT_NFT", }, }, @@ -183,13 +254,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Could you create an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS?", + text: "Could you create an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana?", }, }, { user: "{{agentName}}", content: { - text: "Successfully minted your NFT in the specified collection.", + text: "Successfully minted your NFT in the specified collection on Solana.", action: "MINT_NFT", }, }, @@ -198,13 +269,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Please mint a new token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection", + text: "Please mint a new token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection on Solana", }, }, { user: "{{agentName}}", content: { - text: "Your NFT has been minted in the collection successfully.", + text: "Your NFT has been minted in the collection successfully on Solana.", action: "MINT_NFT", }, }, @@ -213,13 +284,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Generate NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + text: "Generate NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana", }, }, { user: "{{agentName}}", content: { - text: "I've generated and minted your NFT in the collection.", + text: "I've generated and minted your NFT in the collection on Solana.", action: "MINT_NFT", }, }, @@ -228,13 +299,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "I want to mint an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + text: "I want to mint an NFT in collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana", }, }, { user: "{{agentName}}", content: { - text: "Your NFT has been successfully minted in the collection.", + text: "Your NFT has been successfully minted in the collection on Solana.", action: "MINT_NFT", }, }, @@ -243,13 +314,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Create a new NFT token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection", + text: "Create a new NFT token in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection on Solana", }, }, { user: "{{agentName}}", content: { - text: "The NFT has been created in your specified collection.", + text: "The NFT has been created in your specified collection on Solana.", action: "MINT_NFT", }, }, @@ -258,13 +329,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Issue an NFT for collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + text: "Issue an NFT for collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana", }, }, { user: "{{agentName}}", content: { - text: "I've issued your NFT in the requested collection.", + text: "I've issued your NFT in the requested collection on Solana.", action: "MINT_NFT", }, }, @@ -273,13 +344,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Make a new NFT in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + text: "Make a new NFT in D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana", }, }, { user: "{{agentName}}", content: { - text: "Your new NFT has been minted in the collection.", + text: "Your new NFT has been minted in the collection on Solana.", action: "MINT_NFT", }, }, @@ -288,13 +359,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Can you mint an NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection?", + text: "Can you mint an NFT for D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS collection on Solana?", }, }, { user: "{{agentName}}", content: { - text: "I've completed minting your NFT in the collection.", + text: "I've completed minting your NFT in the collection on Solana.", action: "MINT_NFT", }, }, @@ -303,13 +374,13 @@ const mintNFTAction: Action = { { user: "{{user1}}", content: { - text: "Add a new NFT to collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + text: "Add a new NFT to collection D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS on Solana", }, }, { user: "{{agentName}}", content: { - text: "A new NFT has been added to your collection.", + text: "A new NFT has been added to your collection on Solana.", action: "MINT_NFT", }, }, diff --git a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts index 901915331ee..daaf29f5e33 100644 --- a/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts +++ b/packages/plugin-nft-generation/src/actions/nftCollectionGeneration.ts @@ -24,7 +24,6 @@ import { generateERC721ContractCode, } from "../utils/deployEVMContract.ts"; import { verifyEVMContract } from "../utils/verifyEVMContract.ts"; -// import { verifyEVMContract } from "../utils/verifyEVMContract.ts"; const _SupportedChainList = Object.keys(viemChains) as Array< keyof typeof viemChains @@ -101,7 +100,6 @@ const nftCollectionGeneration: Action = { chainName: (typeof supportedChains)[number]; }; - console.log(111111, content); if (content?.chainName === "solana") { const collectionInfo = await createCollectionMetadata({ runtime, @@ -179,11 +177,13 @@ const nftCollectionGeneration: Action = { `Deployed contract address: ${contractAddress}` ); const constructorArgs = encodeConstructorArguments(abi, params); + const blockExplorers = chain.blockExplorers?.default await verifyEVMContract({ contractAddress: contractAddress, sourceCode, metadata, constructorArgs, + apiEndpoint: (blockExplorers as typeof blockExplorers & { apiUrl?: string })?.apiUrl || `${chain.blockExplorers.default.url}/api`, }); if (callback) { callback({ diff --git a/packages/plugin-nft-generation/src/templates.ts b/packages/plugin-nft-generation/src/templates.ts index bcf3e75d3f4..e3833cede6e 100644 --- a/packages/plugin-nft-generation/src/templates.ts +++ b/packages/plugin-nft-generation/src/templates.ts @@ -6,7 +6,7 @@ export const createCollectionTemplate = `Given the recent messages and wallet in {{walletInfo}} Extract the following information about the requested transfer: -- Chain to execute on: Must be one of ["ethereum", "base", ...] (like in viem/chains) +- chainName to execute on: Must be one of ["ethereum", "base", ...] (like in viem/chains) Respond with a JSON markdown block containing only the extracted values. All fields are required: @@ -24,11 +24,11 @@ export const collectionImageTemplate = ` Generate a logo with the text "{{collectionName}}", using orange as the main color, with a sci-fi and mysterious background theme `; export const mintNFTTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. - -Example response: +Respond with a JSON markdown block containing only the extracted values. All fields are required: \`\`\`json { "collectionAddress": "D8j4ubQ3MKwmAqiJw83qT7KQNKjhsuoC7zJJdJa5BkvS", + "chainName": SUPPORTED_CHAINS, } \`\`\` @@ -37,6 +37,5 @@ Example response: Given the recent messages, extract the following information about the requested mint nft: - collection contract address -Respond with a JSON markdown block containing only the extracted values. Note: Ensure to use the user’s latest instruction to extract data; if it is not within the defined options, use null.`; diff --git a/packages/plugin-nft-generation/src/types.ts b/packages/plugin-nft-generation/src/types.ts index ec93468808f..99b74b1b0fd 100644 --- a/packages/plugin-nft-generation/src/types.ts +++ b/packages/plugin-nft-generation/src/types.ts @@ -3,16 +3,18 @@ import { Content } from "@elizaos/core"; import * as viemChains from "viem/chains"; const _SupportedChainList = Object.keys(viemChains); +const supportedChainTuple = [..._SupportedChainList, 'solana'] as unknown as [string, ...string[]]; export interface MintNFTContent extends Content { collectionAddress: string; + chainName: string; } export const MintNFTSchema = z.object({ collectionAddress: z.string(), + chainName: z.enum([...supportedChainTuple]).nullable(), }); -const supportedChainTuple = [..._SupportedChainList, 'solana'] as unknown as [string, ...string[]]; export const CreateCollectionSchema = z.object({ chainName: z.enum([...supportedChainTuple]).nullable(), }); diff --git a/packages/plugin-nft-generation/src/utils/deployEVMContract.ts b/packages/plugin-nft-generation/src/utils/deployEVMContract.ts index 1e859ad7547..044b800fd60 100644 --- a/packages/plugin-nft-generation/src/utils/deployEVMContract.ts +++ b/packages/plugin-nft-generation/src/utils/deployEVMContract.ts @@ -1,15 +1,6 @@ -import { - createPublicClient, - createWalletClient, - encodeAbiParameters, - http, -} from "viem"; +import { encodeAbiParameters } from "viem"; import { fileURLToPath } from "url"; - -import { alienxHalTestnet } from "viem/chains"; -import { privateKeyToAccount } from "viem/accounts"; import { compileWithImports } from "./generateERC721ContractCode.ts"; -import { verifyEVMContract } from "./verifyEVMContract.ts"; import path from "path"; import fs from "fs"; @@ -41,10 +32,9 @@ export async function deployContract({ console.log("Deploying contract..."); const txHash = await walletClient.deployContract({ - abi: abi as any, - bytecode: bytecode as any, - args: args as any, - chain: undefined, + abi, + bytecode, + args, }); console.log(`Deployment transaction hash: ${txHash}`); @@ -56,7 +46,7 @@ export async function deployContract({ } // 调用 mint 方法 -async function mintNFT({ +export async function mintNFT({ walletClient, publicClient, contractAddress, @@ -71,12 +61,10 @@ async function mintNFT({ }) { console.log("Minting NFT..."); const txHash = await walletClient.writeContract({ - address: contractAddress as `0x${string}`, - abi: abi as any, + address: contractAddress, + abi: abi, functionName: "mint", - args: [recipient] as any, - chain: undefined, - account: undefined, + args: [recipient], }); console.log(`Mint transaction hash: ${txHash}`); @@ -93,4 +81,3 @@ export function encodeConstructorArguments(abi, args) { return argsData.slice(2); } - diff --git a/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts b/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts index 1ae3b2b2aef..91d264af5da 100644 --- a/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts +++ b/packages/plugin-nft-generation/src/utils/verifyEVMContract.ts @@ -13,7 +13,6 @@ function getSources(metadata, sourceCode) { const keys = Object.keys(metadata.sources); for (let i = 0; i < keys.length; i++) { const key = keys[i]; - console.log(key, fileName); if (key !== fileName) { obj[key] = { content: loadOpenZeppelinFile(key), @@ -28,8 +27,8 @@ export async function verifyEVMContract({ sourceCode, metadata, constructorArgs = "", + apiEndpoint }) { - const apiEndpoint = "https://hal-explorer.alienxchain.io/api"; const verificationData = { module: "contract", action: "verifysourcecode", @@ -66,7 +65,6 @@ export async function verifyEVMContract({ guid: guid, }, }); - console.log(111, statusResponse.data); return statusResponse.data; }; From 77ea4c32e5e99f60b9b224d2ae71b40353df15e3 Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 6 Jan 2025 18:34:28 +0100 Subject: [PATCH 028/112] upd: initialized empty remix app --- client/.eslintrc.cjs | 84 + client/.gitignore | 25 +- client/README.md | 40 + client/app/entry.client.tsx | 18 + client/app/entry.server.tsx | 140 + client/app/root.tsx | 45 + client/app/routes/_index.tsx | 138 + client/app/tailwind.css | 12 + client/components.json | 21 - client/eslint.config.js | 28 - client/index.html | 13 - client/package.json | 88 +- client/postcss.config.js | 8 +- client/public/favicon.ico | Bin 0 -> 16958 bytes client/public/logo-dark.png | Bin 0 -> 80332 bytes client/public/logo-light.png | Bin 0 -> 5906 bytes client/public/vite.svg | 1 - client/src/Agent.tsx | 10 - client/src/Agents.tsx | 35 - client/src/App.css | 41 - client/src/App.tsx | 12 - client/src/Character.tsx | 7 - client/src/Chat.tsx | 162 - client/src/Layout.tsx | 12 - client/src/api/index.ts | 2 - client/src/api/mutations/index.ts | 1 - .../src/api/mutations/sendMessageMutation.ts | 60 - client/src/api/queries/index.ts | 1 - client/src/api/queries/queries.ts | 3 - client/src/api/queries/useGetAgentsQuery.ts | 23 - client/src/api/routes.ts | 4 - client/src/api/types.ts | 13 - client/src/assets/react.svg | 1 - client/src/components/app-sidebar.tsx | 60 - client/src/components/theme-toggle.tsx | 19 - client/src/components/ui/button.tsx | 57 - client/src/components/ui/card.tsx | 83 - client/src/components/ui/input.tsx | 22 - client/src/components/ui/separator.tsx | 33 - client/src/components/ui/sheet.tsx | 136 - client/src/components/ui/sidebar.tsx | 786 ----- client/src/components/ui/skeleton.tsx | 15 - client/src/components/ui/tooltip.tsx | 32 - client/src/hooks/use-mobile.tsx | 23 - client/src/hooks/use-theme.tsx | 32 - client/src/index.css | 109 - client/src/lib/utils.ts | 6 - client/src/main.tsx | 27 - client/src/router.tsx | 32 - client/src/vite-env.d.ts | 1 - client/tailwind.config.js | 57 - client/tailwind.config.ts | 22 + client/tsconfig.app.json | 28 - client/tsconfig.json | 45 +- client/tsconfig.node.json | 22 - client/vite.config.ts | 53 +- pnpm-lock.yaml | 3101 ++++++++++++----- 57 files changed, 2789 insertions(+), 3060 deletions(-) create mode 100644 client/.eslintrc.cjs create mode 100644 client/README.md create mode 100644 client/app/entry.client.tsx create mode 100644 client/app/entry.server.tsx create mode 100644 client/app/root.tsx create mode 100644 client/app/routes/_index.tsx create mode 100644 client/app/tailwind.css delete mode 100644 client/components.json delete mode 100644 client/eslint.config.js delete mode 100644 client/index.html create mode 100644 client/public/favicon.ico create mode 100644 client/public/logo-dark.png create mode 100644 client/public/logo-light.png delete mode 100644 client/public/vite.svg delete mode 100644 client/src/Agent.tsx delete mode 100644 client/src/Agents.tsx delete mode 100644 client/src/App.css delete mode 100644 client/src/App.tsx delete mode 100644 client/src/Character.tsx delete mode 100644 client/src/Chat.tsx delete mode 100644 client/src/Layout.tsx delete mode 100644 client/src/api/index.ts delete mode 100644 client/src/api/mutations/index.ts delete mode 100644 client/src/api/mutations/sendMessageMutation.ts delete mode 100644 client/src/api/queries/index.ts delete mode 100644 client/src/api/queries/queries.ts delete mode 100644 client/src/api/queries/useGetAgentsQuery.ts delete mode 100644 client/src/api/routes.ts delete mode 100644 client/src/api/types.ts delete mode 100644 client/src/assets/react.svg delete mode 100644 client/src/components/app-sidebar.tsx delete mode 100644 client/src/components/theme-toggle.tsx delete mode 100644 client/src/components/ui/button.tsx delete mode 100644 client/src/components/ui/card.tsx delete mode 100644 client/src/components/ui/input.tsx delete mode 100644 client/src/components/ui/separator.tsx delete mode 100644 client/src/components/ui/sheet.tsx delete mode 100644 client/src/components/ui/sidebar.tsx delete mode 100644 client/src/components/ui/skeleton.tsx delete mode 100644 client/src/components/ui/tooltip.tsx delete mode 100644 client/src/hooks/use-mobile.tsx delete mode 100644 client/src/hooks/use-theme.tsx delete mode 100644 client/src/index.css delete mode 100644 client/src/lib/utils.ts delete mode 100644 client/src/main.tsx delete mode 100644 client/src/router.tsx delete mode 100644 client/src/vite-env.d.ts delete mode 100644 client/tailwind.config.js create mode 100644 client/tailwind.config.ts delete mode 100644 client/tsconfig.app.json delete mode 100644 client/tsconfig.node.json diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs new file mode 100644 index 00000000000..4f6f59eee1e --- /dev/null +++ b/client/.eslintrc.cjs @@ -0,0 +1,84 @@ +/** + * This is intended to be a basic starting point for linting in your app. + * It relies on recommended configs out of the box for simplicity, but you can + * and should modify this configuration to best suit your team's needs. + */ + +/** @type {import('eslint').Linter.Config} */ +module.exports = { + root: true, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, + }, + env: { + browser: true, + commonjs: true, + es6: true, + }, + ignorePatterns: ["!**/.server", "!**/.client"], + + // Base config + extends: ["eslint:recommended"], + + overrides: [ + // React + { + files: ["**/*.{js,jsx,ts,tsx}"], + plugins: ["react", "jsx-a11y"], + extends: [ + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", + "plugin:jsx-a11y/recommended", + ], + settings: { + react: { + version: "detect", + }, + formComponents: ["Form"], + linkComponents: [ + { name: "Link", linkAttribute: "to" }, + { name: "NavLink", linkAttribute: "to" }, + ], + "import/resolver": { + typescript: {}, + }, + }, + }, + + // Typescript + { + files: ["**/*.{ts,tsx}"], + plugins: ["@typescript-eslint", "import"], + parser: "@typescript-eslint/parser", + settings: { + "import/internal-regex": "^~/", + "import/resolver": { + node: { + extensions: [".ts", ".tsx"], + }, + typescript: { + alwaysTryTypes: true, + }, + }, + }, + extends: [ + "plugin:@typescript-eslint/recommended", + "plugin:import/recommended", + "plugin:import/typescript", + ], + }, + + // Node + { + files: [".eslintrc.cjs"], + env: { + node: true, + }, + }, + ], +}; diff --git a/client/.gitignore b/client/.gitignore index a547bf36d8d..80ec311f4ff 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,24 +1,5 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - node_modules -dist -dist-ssr -*.local -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +/.cache +/build +.env diff --git a/client/README.md b/client/README.md new file mode 100644 index 00000000000..6c4d2168fa5 --- /dev/null +++ b/client/README.md @@ -0,0 +1,40 @@ +# Welcome to Remix! + +- 📖 [Remix docs](https://remix.run/docs) + +## Development + +Run the dev server: + +```shellscript +npm run dev +``` + +## Deployment + +First, build your app for production: + +```sh +npm run build +``` + +Then run the app in production mode: + +```sh +npm start +``` + +Now you'll need to pick a host to deploy it to. + +### DIY + +If you're familiar with deploying Node applications, the built-in Remix app server is production-ready. + +Make sure to deploy the output of `npm run build` + +- `build/server` +- `build/client` + +## Styling + +This template comes with [Tailwind CSS](https://tailwindcss.com/) already configured for a simple default starting experience. You can use whatever css framework you prefer. See the [Vite docs on css](https://vitejs.dev/guide/features.html#css) for more information. diff --git a/client/app/entry.client.tsx b/client/app/entry.client.tsx new file mode 100644 index 00000000000..94d5dc0de0f --- /dev/null +++ b/client/app/entry.client.tsx @@ -0,0 +1,18 @@ +/** + * By default, Remix will handle hydrating your app on the client for you. + * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ + * For more information, see https://remix.run/file-conventions/entry.client + */ + +import { RemixBrowser } from "@remix-run/react"; +import { startTransition, StrictMode } from "react"; +import { hydrateRoot } from "react-dom/client"; + +startTransition(() => { + hydrateRoot( + document, + + + + ); +}); diff --git a/client/app/entry.server.tsx b/client/app/entry.server.tsx new file mode 100644 index 00000000000..45db3229c68 --- /dev/null +++ b/client/app/entry.server.tsx @@ -0,0 +1,140 @@ +/** + * By default, Remix will handle generating the HTTP Response for you. + * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ + * For more information, see https://remix.run/file-conventions/entry.server + */ + +import { PassThrough } from "node:stream"; + +import type { AppLoadContext, EntryContext } from "@remix-run/node"; +import { createReadableStreamFromReadable } from "@remix-run/node"; +import { RemixServer } from "@remix-run/react"; +import { isbot } from "isbot"; +import { renderToPipeableStream } from "react-dom/server"; + +const ABORT_DELAY = 5_000; + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, + // This is ignored so we can keep it in the template for visibility. Feel + // free to delete this parameter in your app if you're not using it! + // eslint-disable-next-line @typescript-eslint/no-unused-vars + loadContext: AppLoadContext +) { + return isbot(request.headers.get("user-agent") || "") + ? handleBotRequest( + request, + responseStatusCode, + responseHeaders, + remixContext + ) + : handleBrowserRequest( + request, + responseStatusCode, + responseHeaders, + remixContext + ); +} + +function handleBotRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) { + return new Promise((resolve, reject) => { + let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( + , + { + onAllReady() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set("Content-Type", "text/html"); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }) + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + } + ); + + setTimeout(abort, ABORT_DELAY); + }); +} + +function handleBrowserRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) { + return new Promise((resolve, reject) => { + let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( + , + { + onShellReady() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set("Content-Type", "text/html"); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }) + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + } + ); + + setTimeout(abort, ABORT_DELAY); + }); +} diff --git a/client/app/root.tsx b/client/app/root.tsx new file mode 100644 index 00000000000..61c8b983d28 --- /dev/null +++ b/client/app/root.tsx @@ -0,0 +1,45 @@ +import { + Links, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from "@remix-run/react"; +import type { LinksFunction } from "@remix-run/node"; + +import "./tailwind.css"; + +export const links: LinksFunction = () => [ + { rel: "preconnect", href: "https://fonts.googleapis.com" }, + { + rel: "preconnect", + href: "https://fonts.gstatic.com", + crossOrigin: "anonymous", + }, + { + rel: "stylesheet", + href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap", + }, +]; + +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + + {children} + + + + + ); +} + +export default function App() { + return ; +} diff --git a/client/app/routes/_index.tsx b/client/app/routes/_index.tsx new file mode 100644 index 00000000000..13a5c00468c --- /dev/null +++ b/client/app/routes/_index.tsx @@ -0,0 +1,138 @@ +import type { MetaFunction } from "@remix-run/node"; + +export const meta: MetaFunction = () => { + return [ + { title: "New Remix App" }, + { name: "description", content: "Welcome to Remix!" }, + ]; +}; + +export default function Index() { + return ( +
+
+
+

+ Welcome to Remix +

+
+ Remix + Remix +
+
+ +
+
+ ); +} + +const resources = [ + { + href: "https://remix.run/start/quickstart", + text: "Quick Start (5 min)", + icon: ( + + + + ), + }, + { + href: "https://remix.run/start/tutorial", + text: "Tutorial (30 min)", + icon: ( + + + + ), + }, + { + href: "https://remix.run/docs", + text: "Remix Docs", + icon: ( + + + + ), + }, + { + href: "https://rmx.as/discord", + text: "Join Discord", + icon: ( + + + + ), + }, +]; diff --git a/client/app/tailwind.css b/client/app/tailwind.css new file mode 100644 index 00000000000..303fe158fcf --- /dev/null +++ b/client/app/tailwind.css @@ -0,0 +1,12 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, +body { + @apply bg-white dark:bg-gray-950; + + @media (prefers-color-scheme: dark) { + color-scheme: dark; + } +} diff --git a/client/components.json b/client/components.json deleted file mode 100644 index 9efb29d6726..00000000000 --- a/client/components.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/index.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "iconLibrary": "lucide" -} diff --git a/client/eslint.config.js b/client/eslint.config.js deleted file mode 100644 index 9d1c0c63b18..00000000000 --- a/client/eslint.config.js +++ /dev/null @@ -1,28 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import tseslint from "typescript-eslint"; - -export default tseslint.config( - { ignores: ["dist"] }, - { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ["**/*.{ts,tsx}"], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": [ - "warn", - { allowConstantExport: true }, - ], - }, - } -); diff --git a/client/index.html b/client/index.html deleted file mode 100644 index 342f8872933..00000000000 --- a/client/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Eliza - - -
- - - diff --git a/client/package.json b/client/package.json index ba963ec4e47..ec44645443f 100644 --- a/client/package.json +++ b/client/package.json @@ -1,47 +1,43 @@ { - "name": "eliza-client", - "private": true, - "version": "0.1.7", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "check-types": "tsc --noEmit", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@elizaos/core": "workspace:*", - "@radix-ui/react-dialog": "1.1.2", - "@radix-ui/react-separator": "1.1.0", - "@radix-ui/react-slot": "1.1.0", - "@radix-ui/react-tooltip": "1.1.4", - "@tanstack/react-query": "5.61.0", - "class-variance-authority": "0.7.1", - "clsx": "2.1.1", - "lucide-react": "0.460.0", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-router-dom": "6.22.1", - "tailwind-merge": "2.5.5", - "tailwindcss-animate": "1.0.7", - "vite-plugin-top-level-await": "1.4.4", - "vite-plugin-wasm": "3.3.0" - }, - "devDependencies": { - "@eslint/js": "9.16.0", - "@types/node": "22.8.4", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "4.3.3", - "autoprefixer": "10.4.20", - "eslint-plugin-react-hooks": "5.0.0", - "eslint-plugin-react-refresh": "0.4.14", - "globals": "15.11.0", - "postcss": "8.4.49", - "tailwindcss": "3.4.15", - "typescript": "5.6.3", - "typescript-eslint": "8.11.0", - "vite": "link:@tanstack/router-plugin/vite" - } -} + "name": "client", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "build": "remix vite:build", + "dev": "remix vite:dev", + "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", + "start": "remix-serve ./build/server/index.js", + "typecheck": "tsc" + }, + "dependencies": { + "@remix-run/node": "^2.15.2", + "@remix-run/react": "^2.15.2", + "@remix-run/serve": "^2.15.2", + "isbot": "^4.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@remix-run/dev": "^2.15.2", + "@types/react": "^18.2.20", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "@typescript-eslint/parser": "^6.7.4", + "autoprefixer": "^10.4.19", + "eslint": "^8.38.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "postcss": "^8.4.38", + "tailwindcss": "^3.4.4", + "typescript": "^5.1.6", + "vite": "^5.1.0", + "vite-tsconfig-paths": "^4.2.1" + }, + "engines": { + "node": ">=20.0.0" + } +} \ No newline at end of file diff --git a/client/postcss.config.js b/client/postcss.config.js index 49c0612d5c2..2aa7205d4b4 100644 --- a/client/postcss.config.js +++ b/client/postcss.config.js @@ -1,6 +1,6 @@ export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, }; diff --git a/client/public/favicon.ico b/client/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8830cf6821b354114848e6354889b8ecf6d2bc61 GIT binary patch literal 16958 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 EKbET!0{{R3 literal 0 HcmV?d00001 diff --git a/client/public/logo-dark.png b/client/public/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..b24c7aee3a86dad7eb334ba6fba94e5b18b84215 GIT binary patch literal 80332 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 BAPKNXC&B9%2=3YBbo!Y+L4D-GS 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�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 F{{et{IHv#r literal 0 HcmV?d00001 diff --git a/client/public/vite.svg b/client/public/vite.svg deleted file mode 100644 index e7b8dfb1b2a..00000000000 --- a/client/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/Agent.tsx b/client/src/Agent.tsx deleted file mode 100644 index f3094f14ebb..00000000000 --- a/client/src/Agent.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export default function Agent() { - return ( -
    -

    - Select an option from the sidebar to configure, view, or chat - with your ELIZA agent -

    -
    - ); -} diff --git a/client/src/Agents.tsx b/client/src/Agents.tsx deleted file mode 100644 index 55dc8e1ee11..00000000000 --- a/client/src/Agents.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { useNavigate } from "react-router-dom"; -import { useGetAgentsQuery } from "@/api"; -import "./App.css"; - -function Agents() { - const navigate = useNavigate(); - const { data: agents, isLoading } = useGetAgentsQuery(); - - return ( -
    -

    Select your agent:

    - - {isLoading ? ( -
    Loading agents...
    - ) : ( -
    - {agents?.map((agent) => ( - - ))} -
    - )} -
    - ); -} - -export default Agents; diff --git a/client/src/App.css b/client/src/App.css deleted file mode 100644 index d6055f0d020..00000000000 --- a/client/src/App.css +++ /dev/null @@ -1,41 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/client/src/App.tsx b/client/src/App.tsx deleted file mode 100644 index c5b0826f12e..00000000000 --- a/client/src/App.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import "./App.css"; -import Agents from "./Agents"; - -function App() { - return ( -
    - -
    - ); -} - -export default App; diff --git a/client/src/Character.tsx b/client/src/Character.tsx deleted file mode 100644 index bdb53882adf..00000000000 --- a/client/src/Character.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function Character() { - return ( -
    -

    WIP

    -
    - ); -} diff --git a/client/src/Chat.tsx b/client/src/Chat.tsx deleted file mode 100644 index 6158d639db4..00000000000 --- a/client/src/Chat.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import type { TextResponse } from "@/api"; -import { useSendMessageMutation } from "@/api"; -import { ImageIcon } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; -import { useParams } from "react-router-dom"; -import "./App.css"; - -export default function Chat() { - const { agentId } = useParams(); - const [input, setInput] = useState(""); - const [messages, setMessages] = useState([]); - const [selectedFile, setSelectedFile] = useState(null); - const fileInputRef = useRef(null); - const messagesEndRef = useRef(null); - const { mutate: sendMessage, isPending } = useSendMessageMutation({ - setMessages, - setSelectedFile, - }); - - const scrollToBottom = () => { - messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); - }; - - useEffect(() => { - scrollToBottom(); - }, [messages]); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if ((!input.trim() && !selectedFile) || !agentId) return; - - // Add user message immediately to state - const userMessage: TextResponse = { - text: input, - user: "user", - attachments: selectedFile - ? [ - { - url: URL.createObjectURL(selectedFile), - contentType: selectedFile.type, - title: selectedFile.name, - }, - ] - : undefined, - }; - setMessages((prev) => [...prev, userMessage]); - - sendMessage({ text: input, agentId, selectedFile }); - setInput(""); - }; - - const handleFileSelect = () => { - fileInputRef.current?.click(); - }; - - const handleFileChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file && file.type.startsWith("image/")) { - setSelectedFile(file); - } - }; - - return ( -
    -
    -
    - {messages.length > 0 ? ( - messages.map((message, index) => ( -
    -
    -                                    {message.text}
    -                                    {message.attachments?.map(
    -                                        (attachment, i) =>
    -                                            attachment.contentType.startsWith(
    -                                                "image/"
    -                                            ) && (
    -                                                {
    -                                            )
    -                                    )}
    -                                
    -
    - )) - ) : ( -
    - No messages yet. Start a conversation! -
    - )} -
    -
    -
    - -
    -
    -
    - - setInput(e.target.value)} - placeholder="Type a message..." - className="flex-1" - disabled={isPending} - /> - - -
    - {selectedFile && ( -
    - Selected file: {selectedFile.name} -
    - )} -
    -
    -
    - ); -} diff --git a/client/src/Layout.tsx b/client/src/Layout.tsx deleted file mode 100644 index 70c79f74032..00000000000 --- a/client/src/Layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { SidebarProvider } from "@/components/ui/sidebar"; -import { AppSidebar } from "@/components/app-sidebar"; -import { Outlet } from "react-router-dom"; - -export default function Layout() { - return ( - - - - - ); -} diff --git a/client/src/api/index.ts b/client/src/api/index.ts deleted file mode 100644 index 0c2adeab024..00000000000 --- a/client/src/api/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./mutations"; -export * from "./queries"; diff --git a/client/src/api/mutations/index.ts b/client/src/api/mutations/index.ts deleted file mode 100644 index ca9f0653dc5..00000000000 --- a/client/src/api/mutations/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./sendMessageMutation"; diff --git a/client/src/api/mutations/sendMessageMutation.ts b/client/src/api/mutations/sendMessageMutation.ts deleted file mode 100644 index 500e19d2e10..00000000000 --- a/client/src/api/mutations/sendMessageMutation.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { CustomMutationResult } from "../types"; - -import { useMutation } from "@tanstack/react-query"; -import { ROUTES } from "../routes"; -import { SetStateAction } from "react"; - -export type TextResponse = { - text: string; - user: string; - attachments?: { url: string; contentType: string; title: string }[]; -}; - -type SendMessageMutationProps = { - text: string; - agentId: string; - selectedFile: File | null; -}; - -type Props = Required<{ - setMessages: (value: SetStateAction) => void; - setSelectedFile: (value: SetStateAction) => void; -}>; - -export const useSendMessageMutation = ({ - setMessages, - setSelectedFile, -}: Props): CustomMutationResult => { - const mutation = useMutation({ - mutationFn: async ({ - text, - agentId, - selectedFile, - }: SendMessageMutationProps) => { - const formData = new FormData(); - formData.append("text", text); - formData.append("userId", "user"); - formData.append("roomId", `default-room-${agentId}`); - - if (selectedFile) { - formData.append("file", selectedFile); - } - - const res = await fetch(ROUTES.sendMessage(agentId), { - method: "POST", - body: formData, - }); - - return res.json() as Promise; - }, - onSuccess: (data) => { - setMessages((prev) => [...prev, ...data]); - setSelectedFile(null); - }, - onError: (error) => { - console.error("[useSendMessageMutation]:", error); - }, - }); - - return mutation; -}; diff --git a/client/src/api/queries/index.ts b/client/src/api/queries/index.ts deleted file mode 100644 index 1b1c08c1e91..00000000000 --- a/client/src/api/queries/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./useGetAgentsQuery"; diff --git a/client/src/api/queries/queries.ts b/client/src/api/queries/queries.ts deleted file mode 100644 index 40253fe29d6..00000000000 --- a/client/src/api/queries/queries.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum Queries { - AGENTS = "agents", -} diff --git a/client/src/api/queries/useGetAgentsQuery.ts b/client/src/api/queries/useGetAgentsQuery.ts deleted file mode 100644 index 88f91ff7e78..00000000000 --- a/client/src/api/queries/useGetAgentsQuery.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useQuery } from "@tanstack/react-query"; -import type { CustomQueryResult } from "../types"; -import { Queries } from "./queries"; -import { ROUTES } from "../routes"; - -export type Agent = { - id: string; - name: string; -}; - -export const useGetAgentsQuery = (): CustomQueryResult => { - return useQuery({ - queryKey: [Queries.AGENTS], - queryFn: async () => { - const res = await fetch(ROUTES.getAgents()); - const data = await res.json(); - return data.agents as Agent[]; - }, - retry: (failureCount) => failureCount < 3, - staleTime: 5 * 60 * 1000, // 5 minutes - refetchOnWindowFocus: false, - }); -}; diff --git a/client/src/api/routes.ts b/client/src/api/routes.ts deleted file mode 100644 index 1005a61a72e..00000000000 --- a/client/src/api/routes.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const ROUTES = { - sendMessage: (agentId: string): string => `/api/${agentId}/message`, - getAgents: (): string => `/api/agents`, -}; diff --git a/client/src/api/types.ts b/client/src/api/types.ts deleted file mode 100644 index 286daf64b55..00000000000 --- a/client/src/api/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { UseMutationResult, UseQueryResult } from "@tanstack/react-query"; - -export type CustomMutationResult = UseMutationResult< - TData, - Error, - TArgs, - unknown ->; - -export type CustomQueryResult = Omit< - UseQueryResult, - "data" | "refetch" | "promise" -> & { data: TData; refetch: () => void; promise: unknown }; diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg deleted file mode 100644 index 6c87de9bb33..00000000000 --- a/client/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/components/app-sidebar.tsx b/client/src/components/app-sidebar.tsx deleted file mode 100644 index 9fc89184278..00000000000 --- a/client/src/components/app-sidebar.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Calendar, Inbox } from "lucide-react"; -import { useParams } from "react-router-dom"; -import { ThemeToggle } from "@/components/theme-toggle"; - -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarGroup, - SidebarGroupContent, - SidebarGroupLabel, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from "@/components/ui/sidebar"; - -// Menu items. -const items = [ - { - title: "Chat", - url: "chat", - icon: Inbox, - }, - { - title: "Character Overview", - url: "character", - icon: Calendar, - }, -]; - -export function AppSidebar() { - const { agentId } = useParams(); - - return ( - - - - Application - - - {items.map((item) => ( - - -
    - - {item.title} - - - - ))} - - - - - - - - - ); -} diff --git a/client/src/components/theme-toggle.tsx b/client/src/components/theme-toggle.tsx deleted file mode 100644 index 91677a4a78b..00000000000 --- a/client/src/components/theme-toggle.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Moon, Sun } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { useTheme } from "@/hooks/use-theme"; - -export function ThemeToggle() { - const { theme, setTheme } = useTheme(); - - return ( - - ); -} diff --git a/client/src/components/ui/button.tsx b/client/src/components/ui/button.tsx deleted file mode 100644 index 8c1b26a1652..00000000000 --- a/client/src/components/ui/button.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react"; -import { Slot } from "@radix-ui/react-slot"; -import { cva, type VariantProps } from "class-variance-authority"; - -import { cn } from "@/lib/utils"; - -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: - "bg-primary text-primary-foreground shadow hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", - outline: - "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-9 w-9", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -); - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean; -} - -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button"; - return ( - - ); - } -); -Button.displayName = "Button"; - -export { Button, buttonVariants }; diff --git a/client/src/components/ui/card.tsx b/client/src/components/ui/card.tsx deleted file mode 100644 index 25157bf2d3c..00000000000 --- a/client/src/components/ui/card.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)); -Card.displayName = "Card"; - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)); -CardHeader.displayName = "CardHeader"; - -const CardTitle = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)); -CardTitle.displayName = "CardTitle"; - -const CardDescription = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)); -CardDescription.displayName = "CardDescription"; - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)); -CardContent.displayName = "CardContent"; - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)); -CardFooter.displayName = "CardFooter"; - -export { - Card, - CardHeader, - CardFooter, - CardTitle, - CardDescription, - CardContent, -}; diff --git a/client/src/components/ui/input.tsx b/client/src/components/ui/input.tsx deleted file mode 100644 index 9661e332a70..00000000000 --- a/client/src/components/ui/input.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -const Input = React.forwardRef>( - ({ className, type, ...props }, ref) => { - return ( - - ); - } -); -Input.displayName = "Input"; - -export { Input }; diff --git a/client/src/components/ui/separator.tsx b/client/src/components/ui/separator.tsx deleted file mode 100644 index 2af4ec891eb..00000000000 --- a/client/src/components/ui/separator.tsx +++ /dev/null @@ -1,33 +0,0 @@ -"use client"; - -import * as React from "react"; -import * as SeparatorPrimitive from "@radix-ui/react-separator"; - -import { cn } from "@/lib/utils"; - -const Separator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->( - ( - { className, orientation = "horizontal", decorative = true, ...props }, - ref - ) => ( - - ) -); -Separator.displayName = SeparatorPrimitive.Root.displayName; - -export { Separator }; diff --git a/client/src/components/ui/sheet.tsx b/client/src/components/ui/sheet.tsx deleted file mode 100644 index e18e295c73c..00000000000 --- a/client/src/components/ui/sheet.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import * as React from "react"; -import * as SheetPrimitive from "@radix-ui/react-dialog"; -import { cva, type VariantProps } from "class-variance-authority"; -import { X } from "lucide-react"; - -import { cn } from "@/lib/utils"; - -const Sheet = SheetPrimitive.Root; - -const SheetTrigger = SheetPrimitive.Trigger; - -const SheetClose = SheetPrimitive.Close; - -const SheetPortal = SheetPrimitive.Portal; - -const SheetOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SheetOverlay.displayName = SheetPrimitive.Overlay.displayName; - -const sheetVariants = cva( - "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out", - { - variants: { - side: { - top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", - bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", - left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", - right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", - }, - }, - defaultVariants: { - side: "right", - }, - } -); - -interface SheetContentProps - extends React.ComponentPropsWithoutRef, - VariantProps {} - -const SheetContent = React.forwardRef< - React.ElementRef, - SheetContentProps ->(({ side = "right", className, children, ...props }, ref) => ( - - - - - - Close - - {children} - - -)); -SheetContent.displayName = SheetPrimitive.Content.displayName; - -const SheetHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
    -); -SheetHeader.displayName = "SheetHeader"; - -const SheetFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
    -); -SheetFooter.displayName = "SheetFooter"; - -const SheetTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SheetTitle.displayName = SheetPrimitive.Title.displayName; - -const SheetDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -SheetDescription.displayName = SheetPrimitive.Description.displayName; - -export { - Sheet, - SheetPortal, - SheetOverlay, - SheetTrigger, - SheetClose, - SheetContent, - SheetHeader, - SheetFooter, - SheetTitle, - SheetDescription, -}; diff --git a/client/src/components/ui/sidebar.tsx b/client/src/components/ui/sidebar.tsx deleted file mode 100644 index ab5862ab35a..00000000000 --- a/client/src/components/ui/sidebar.tsx +++ /dev/null @@ -1,786 +0,0 @@ -import * as React from "react"; -import { Slot } from "@radix-ui/react-slot"; -import { VariantProps, cva } from "class-variance-authority"; -import { PanelLeft } from "lucide-react"; - -import { useIsMobile } from "@/hooks/use-mobile"; -import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Separator } from "@/components/ui/separator"; -import { Sheet, SheetContent } from "@/components/ui/sheet"; -import { Skeleton } from "@/components/ui/skeleton"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; - -const SIDEBAR_COOKIE_NAME = "sidebar:state"; -const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; -const SIDEBAR_WIDTH = "16rem"; -const SIDEBAR_WIDTH_MOBILE = "18rem"; -const SIDEBAR_WIDTH_ICON = "3rem"; -const SIDEBAR_KEYBOARD_SHORTCUT = "b"; - -type SidebarContext = { - state: "expanded" | "collapsed"; - open: boolean; - setOpen: (open: boolean) => void; - openMobile: boolean; - setOpenMobile: (open: boolean) => void; - isMobile: boolean; - toggleSidebar: () => void; -}; - -const SidebarContext = React.createContext(null); - -function useSidebar() { - const context = React.useContext(SidebarContext); - if (!context) { - throw new Error("useSidebar must be used within a SidebarProvider."); - } - - return context; -} - -const SidebarProvider = React.forwardRef< - HTMLDivElement, - React.ComponentProps<"div"> & { - defaultOpen?: boolean; - open?: boolean; - onOpenChange?: (open: boolean) => void; - } ->( - ( - { - defaultOpen = true, - open: openProp, - onOpenChange: setOpenProp, - className, - style, - children, - ...props - }, - ref - ) => { - const isMobile = useIsMobile(); - const [openMobile, setOpenMobile] = React.useState(false); - - // This is the internal state of the sidebar. - // We use openProp and setOpenProp for control from outside the component. - const [_open, _setOpen] = React.useState(defaultOpen); - const open = openProp ?? _open; - const setOpen = React.useCallback( - (value: boolean | ((value: boolean) => boolean)) => { - const openState = - typeof value === "function" ? value(open) : value; - if (setOpenProp) { - setOpenProp(openState); - } else { - _setOpen(openState); - } - - // This sets the cookie to keep the sidebar state. - document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; - }, - [setOpenProp, open] - ); - - // Helper to toggle the sidebar. - const toggleSidebar = React.useCallback(() => { - return isMobile - ? setOpenMobile((open) => !open) - : setOpen((open) => !open); - }, [isMobile, setOpen, setOpenMobile]); - - // Adds a keyboard shortcut to toggle the sidebar. - React.useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - event.key === SIDEBAR_KEYBOARD_SHORTCUT && - (event.metaKey || event.ctrlKey) - ) { - event.preventDefault(); - toggleSidebar(); - } - }; - - window.addEventListener("keydown", handleKeyDown); - return () => window.removeEventListener("keydown", handleKeyDown); - }, [toggleSidebar]); - - // We add a state so that we can do data-state="expanded" or "collapsed". - // This makes it easier to style the sidebar with Tailwind classes. - const state = open ? "expanded" : "collapsed"; - - const contextValue = React.useMemo( - () => ({ - state, - open, - setOpen, - isMobile, - openMobile, - setOpenMobile, - toggleSidebar, - }), - [ - state, - open, - setOpen, - isMobile, - openMobile, - setOpenMobile, - toggleSidebar, - ] - ); - - return ( - - -
    - {children} -
    -
    -
    - ); - } -); -SidebarProvider.displayName = "SidebarProvider"; - -const Sidebar = React.forwardRef< - HTMLDivElement, - React.ComponentProps<"div"> & { - side?: "left" | "right"; - variant?: "sidebar" | "floating" | "inset"; - collapsible?: "offcanvas" | "icon" | "none"; - } ->( - ( - { - side = "left", - variant = "sidebar", - collapsible = "offcanvas", - className, - children, - ...props - }, - ref - ) => { - const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); - - if (collapsible === "none") { - return ( -
    - {children} -
    - ); - } - - if (isMobile) { - return ( - - -
    - {children} -
    -
    -
    - ); - } - - return ( -
    - {/* This is what handles the sidebar gap on desktop */} -
    - -
    - ); - } -); -Sidebar.displayName = "Sidebar"; - -const SidebarTrigger = React.forwardRef< - React.ElementRef, - React.ComponentProps ->(({ className, onClick, ...props }, ref) => { - const { toggleSidebar } = useSidebar(); - - return ( - - ); -}); -SidebarTrigger.displayName = "SidebarTrigger"; - -const SidebarRail = React.forwardRef< - HTMLButtonElement, - React.ComponentProps<"button"> ->(({ className, ...props }, ref) => { - const { toggleSidebar } = useSidebar(); - - return ( - +
    + ); +} \ No newline at end of file diff --git a/client/app/tailwind.css b/client/app/tailwind.css index 303fe158fcf..be310705e9d 100644 --- a/client/app/tailwind.css +++ b/client/app/tailwind.css @@ -2,11 +2,68 @@ @tailwind components; @tailwind utilities; -html, -body { - @apply bg-white dark:bg-gray-950; +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 5.9% 10%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } - @media (prefers-color-scheme: dark) { - color-scheme: dark; + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; } } diff --git a/client/app/types/index.ts b/client/app/types/index.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/client/components.json b/client/components.json new file mode 100644 index 00000000000..d4e662d533b --- /dev/null +++ b/client/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "app/tailwind.css", + "baseColor": "zinc", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "~/components", + "utils": "~/lib/utils", + "ui": "~/components/ui", + "lib": "~/lib", + "hooks": "~/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/client/package.json b/client/package.json index ec44645443f..dedb4fa5662 100644 --- a/client/package.json +++ b/client/package.json @@ -11,12 +11,20 @@ "typecheck": "tsc" }, "dependencies": { + "@elizaos/core": "workspace:*", + "@radix-ui/react-slot": "^1.1.1", "@remix-run/node": "^2.15.2", "@remix-run/react": "^2.15.2", "@remix-run/serve": "^2.15.2", + "@tanstack/react-query": "^5.62.15", + "class-variance-authority": "^0.7.1", + "clsx": "2.1.1", "isbot": "^4.1.0", + "lucide-react": "^0.469.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "tailwind-merge": "^2.6.0", + "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@remix-run/dev": "^2.15.2", diff --git a/client/tailwind.config.ts b/client/tailwind.config.ts index 5f06ad4ba5a..79c018f5ebf 100644 --- a/client/tailwind.config.ts +++ b/client/tailwind.config.ts @@ -1,22 +1,70 @@ import type { Config } from "tailwindcss"; export default { - content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], + darkMode: ["class"], + content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], theme: { - extend: { - fontFamily: { - sans: [ - "Inter", - "ui-sans-serif", - "system-ui", - "sans-serif", - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol", - "Noto Color Emoji", - ], - }, - }, + extend: { + fontFamily: { + sans: [ + 'Inter', + 'ui-sans-serif', + 'system-ui', + 'sans-serif', + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji' + ] + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + colors: { + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + } + } }, - plugins: [], + plugins: [require("tailwindcss-animate")], } satisfies Config; diff --git a/client/vite.config.ts b/client/vite.config.ts index e4e8cefc3ba..e0986efb4ac 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -3,22 +3,22 @@ import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; declare module "@remix-run/node" { - interface Future { - v3_singleFetch: true; - } + interface Future { + v3_singleFetch: true; + } } export default defineConfig({ - plugins: [ - remix({ - future: { - v3_fetcherPersist: true, - v3_relativeSplatPath: true, - v3_throwAbortReason: true, - v3_singleFetch: true, - v3_lazyRouteDiscovery: true, - }, - }), - tsconfigPaths(), - ], + plugins: [ + remix({ + future: { + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_singleFetch: true, + v3_lazyRouteDiscovery: true, + }, + }), + tsconfigPaths(), + ], }); From c73df1171b7112b3bb8dc117d911a9fd5ec10cb9 Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 6 Jan 2025 19:44:02 +0100 Subject: [PATCH 030/112] upd: created initial sidebar for Agents --- client/app/components/app-sidebar.tsx | 49 ++ client/app/components/ui/avatar.tsx | 48 ++ client/app/components/ui/breadcrumb.tsx | 115 ++++ client/app/components/ui/collapsible.tsx | 9 + client/app/components/ui/input.tsx | 22 + client/app/components/ui/separator.tsx | 29 + client/app/components/ui/sheet.tsx | 138 ++++ client/app/components/ui/sidebar.tsx | 762 +++++++++++++++++++++++ client/app/components/ui/skeleton.tsx | 15 + client/app/components/ui/tooltip.tsx | 32 + client/app/hooks/use-mobile.tsx | 19 + client/app/lib/api.ts | 2 +- client/app/root.tsx | 16 +- client/app/routes/_index.tsx | 11 +- client/app/tailwind.css | 16 + client/package.json | 6 + client/tailwind.config.ts | 10 + 17 files changed, 1287 insertions(+), 12 deletions(-) create mode 100644 client/app/components/app-sidebar.tsx create mode 100644 client/app/components/ui/avatar.tsx create mode 100644 client/app/components/ui/breadcrumb.tsx create mode 100644 client/app/components/ui/collapsible.tsx create mode 100644 client/app/components/ui/input.tsx create mode 100644 client/app/components/ui/separator.tsx create mode 100644 client/app/components/ui/sheet.tsx create mode 100644 client/app/components/ui/sidebar.tsx create mode 100644 client/app/components/ui/skeleton.tsx create mode 100644 client/app/components/ui/tooltip.tsx create mode 100644 client/app/hooks/use-mobile.tsx diff --git a/client/app/components/app-sidebar.tsx b/client/app/components/app-sidebar.tsx new file mode 100644 index 00000000000..6bcec7a43cd --- /dev/null +++ b/client/app/components/app-sidebar.tsx @@ -0,0 +1,49 @@ +import { useQuery } from "@tanstack/react-query"; +import { Calendar, Home, Inbox, Search, Settings } from "lucide-react"; + +import { + Sidebar, + SidebarContent, + SidebarGroup, + SidebarGroupContent, + SidebarGroupLabel, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, +} from "~/components/ui/sidebar"; +import { apiClient } from "~/lib/api"; + +export function AppSidebar() { + const query = useQuery({ + queryKey: ["agents"], + queryFn: () => apiClient.getAgents(), + }); + + const agents = query?.data?.agents; + + return ( + + + + Agents + + + {agents?.map((agent) => ( + + +
    +
    + {agent?.name?.substring(0,2)} +
    + {agent.name} +
    +
    +
    + ))} +
    +
    +
    +
    +
    + ); +} diff --git a/client/app/components/ui/avatar.tsx b/client/app/components/ui/avatar.tsx new file mode 100644 index 00000000000..706f1778bab --- /dev/null +++ b/client/app/components/ui/avatar.tsx @@ -0,0 +1,48 @@ +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "~/lib/utils" + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Avatar.displayName = AvatarPrimitive.Root.displayName + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarImage.displayName = AvatarPrimitive.Image.displayName + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/client/app/components/ui/breadcrumb.tsx b/client/app/components/ui/breadcrumb.tsx new file mode 100644 index 00000000000..2ca8b012a16 --- /dev/null +++ b/client/app/components/ui/breadcrumb.tsx @@ -0,0 +1,115 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "~/lib/utils" + +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode + } +>(({ ...props }, ref) =>