diff --git a/.github/workflows/deploy-monitoring-randomness.yml b/.github/workflows/deploy-monitoring-randomness.yml new file mode 100644 index 0000000000..bc4d2889fb --- /dev/null +++ b/.github/workflows/deploy-monitoring-randomness.yml @@ -0,0 +1,85 @@ +name: Deploy Randomness Monitor + +on: + workflow_dispatch: + +env: + REGISTRY: ghcr.io + ORGANIZATION: happychaindevs + PM2_PROCESS_NAME: randomness-monitor + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout code + uses: actions/checkout@v4.2.0 + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Build code + run: | + make randomness-monitor.build + + - name: Copy files to server + uses: appleboy/scp-action@v0.1.7 + with: + host: ${{ secrets.SERVER_2_HOST }} + username: ${{ secrets.SERVER_2_USERNAME }} + key: ${{ secrets.SERVER_2_KEY }} + port: ${{ secrets.SERVER_2_PORT }} + source: "apps/randomness-monitor/build/*,node_modules/better-sqlite3,node_modules/bindings,node_modules/file-uri-to-path" + target: /home/deployer/randomness-monitor + strip_components: 1 + rm: true + + - name: Deploy randomness to server + uses: appleboy/ssh-action@v1.1.0 + with: + host: ${{ secrets.SERVER_2_HOST }} + username: ${{ secrets.SERVER_2_USERNAME }} + key: ${{ secrets.SERVER_2_KEY }} + port: ${{ secrets.SERVER_2_PORT }} + # We copy better-sqlite3, bindings, and file-uri-to-path separately because the bundled file does not include + # better-sqlite3 and its dependencies + script: | + chmod -R o+rX /home/deployer/randomness-monitor + mv /home/deployer/randomness-monitor /tmp + sudo -u randomness-monitor bash -c ' + rm -rf /home/randomness-monitor/build + rm -rf /home/randomness-monitor/node_modules + cp -r /tmp/randomness-monitor/randomness-monitor/build /home/randomness-monitor/build + + mkdir -p /home/randomness-monitor/node_modules + cp -r /tmp/randomness-monitor/better-sqlite3 /home/randomness-monitor/node_modules/better-sqlite3 + cp -r /tmp/randomness-monitor/bindings /home/randomness-monitor/node_modules/bindings + cp -r /tmp/randomness-monitor/file-uri-to-path /home/randomness-monitor/node_modules/file-uri-to-path + + cd /home/randomness-monitor + + rm -f .env + + cat > .env <<-EOF + ${{vars.RANDOMNESS_MONITOR_ENV}} + EOF + + npm rebuild + + pm2 delete ${{ env.PM2_PROCESS_NAME }} + + source .env && node ./build/migrate.es.js + + source .env && pm2 start ./build/index.es.js \ + --name ${{ env.PM2_PROCESS_NAME }} + pm2 save + ' + rm -rf /tmp/randomness-monitor \ No newline at end of file diff --git a/Makefile b/Makefile index 6463a93bc8..ccaf340be7 100644 --- a/Makefile +++ b/Makefile @@ -365,6 +365,10 @@ randomness.build: setup.ts shared.build cd apps/randomness && make build .PHONY: randomness.build +randomness-monitor.build: setup.ts shared.build + cd apps/randomness-monitor && make build +.PHONY: randomness-monitor.build + txm.build: setup.ts shared.build cd packages/txm && make build .PHONY: txm.build diff --git a/apps/docs/src/pages/txm/getting-started.mdx b/apps/docs/src/pages/txm/getting-started.mdx index bffba40ddc..0c48a3d498 100644 --- a/apps/docs/src/pages/txm/getting-started.mdx +++ b/apps/docs/src/pages/txm/getting-started.mdx @@ -182,8 +182,4 @@ const hookHandler: TxmHookHandler = (tx: Transaction) => { } txm.addHook(TxmHookType.OnStatusChange, hookHandler) -<<<<<<< HEAD ``` -======= -``` ->>>>>>> e24f8b15 (fix: docs) diff --git a/apps/randomness-monitor/.env.example b/apps/randomness-monitor/.env.example new file mode 100644 index 0000000000..5166b96b9d --- /dev/null +++ b/apps/randomness-monitor/.env.example @@ -0,0 +1,4 @@ +MONITORING_DB_PATH= +RPC_URL=wss://rpc.testnet.happy.tech/ws +CHAIN_ID=216 +RANDOM_CONTRACT_ADDRESS=0xd7dafcdC292906540Cc3357E9fD913390256b978 \ No newline at end of file diff --git a/apps/randomness-monitor/Makefile b/apps/randomness-monitor/Makefile new file mode 100644 index 0000000000..7583c245fe --- /dev/null +++ b/apps/randomness-monitor/Makefile @@ -0,0 +1,14 @@ +SRC_ROOT_DIR := src + +include ../../makefiles/lib.mk +include ../../makefiles/formatting.mk +include ../../makefiles/bundling.mk +include ../../makefiles/help.mk + +start: ## Starts the randomness service + node --env-file=.env dist/index.es.js +.PHONY: start + +migrate: ## Runs pending migrations + node --env-file=.env dist/migrate.es.js +PHONY: migrate \ No newline at end of file diff --git a/apps/randomness-monitor/README.md b/apps/randomness-monitor/README.md new file mode 100644 index 0000000000..79be056527 --- /dev/null +++ b/apps/randomness-monitor/README.md @@ -0,0 +1,9 @@ +# Randomness Monitor + +This application monitors the randomness service by directly inspecting the blockchain to verify whether randomness data is included in each block. + +The results are stored in a SQLite database and visualized via Grafana on the following dashboard: + +🔗 [View Dashboard](https://grafana.happy.tech/goto/BMpaDZbNg?orgId=1) + +In addition to visualization, the collected data is used to trigger alerts when the randomness service's performance drops below 95% block coverage. \ No newline at end of file diff --git a/apps/randomness-monitor/build.config.ts b/apps/randomness-monitor/build.config.ts new file mode 100644 index 0000000000..1ee0717c15 --- /dev/null +++ b/apps/randomness-monitor/build.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "@happy.tech/happybuild" + +export default defineConfig({ + exports: [".", "./migrate"], + bunConfig: { + minify: false, + target: "node", + external: ["better-sqlite3"], + }, +}) diff --git a/apps/randomness-monitor/package.json b/apps/randomness-monitor/package.json new file mode 100644 index 0000000000..676439358b --- /dev/null +++ b/apps/randomness-monitor/package.json @@ -0,0 +1,25 @@ +{ + "name": "@happy.tech/randomness-monitor", + "private": true, + "version": "0.1.0", + "type": "module", + "main": "./dist/index.es.js", + "module": "./dist/index.es.js", + "exports": { + ".": "./dist/index.es.js", + "./migrate": "./dist/migrate.es.js" + }, + "dependencies": { + "@happy.tech/common": "workspace:0.1.0", + "zod": "^3.23.8", + "better-sqlite3": "^11.7.0", + "kysely": "^0.27.5", + "viem": "^2.21.53", + "neverthrow": "^8.1.0", + "@happy.tech/contracts": "workspace:0.1.0" + }, + "devDependencies": { + "@happy.tech/happybuild": "workspace:0.1.1", + "typescript": "^5.6.2" + } +} diff --git a/apps/randomness-monitor/src/Check.ts b/apps/randomness-monitor/src/Check.ts new file mode 100644 index 0000000000..49cc03f4a4 --- /dev/null +++ b/apps/randomness-monitor/src/Check.ts @@ -0,0 +1,26 @@ +export enum CheckResult { + Success = "success", + Failure = "failure", +} + +export class Check { + readonly blockNumber: bigint + readonly blockTimestamp: bigint + readonly result: CheckResult + readonly errorDescription: string | undefined + readonly value: string | undefined + + constructor( + blockNumber: bigint, + blockTimestamp: bigint, + result: CheckResult, + errorDescription?: string, + value?: string, + ) { + this.blockNumber = blockNumber + this.blockTimestamp = blockTimestamp + this.result = result + this.errorDescription = errorDescription + this.value = value + } +} diff --git a/apps/randomness-monitor/src/CheckRepository.ts b/apps/randomness-monitor/src/CheckRepository.ts new file mode 100644 index 0000000000..5930d7b9c8 --- /dev/null +++ b/apps/randomness-monitor/src/CheckRepository.ts @@ -0,0 +1,38 @@ +import { unknownToError } from "@happy.tech/common" +import { type Result, ResultAsync, err, ok } from "neverthrow" +import { db } from "./db/driver" +import { checkEntityToRow, checkRowToEntity } from "./db/types" +import type { Check } from "./Check" + +const PRUNE_BLOCK_TIMESTAMP_THRESHOLD_SECONDS = 60 * 60 * 24 * 30 // 30 days + +export class CheckRepository { + async saveCheck(check: Check): Promise> { + const row = checkEntityToRow(check) + + return await ResultAsync.fromPromise(db.insertInto("checks").values(row).execute(), unknownToError).map( + () => undefined, + ) + } + + async findLatestCheck(): Promise> { + const result = await ResultAsync.fromPromise( + db.selectFrom("checks").selectAll().orderBy("blockNumber", "desc").limit(1).executeTakeFirst(), + unknownToError, + ) + if (result.isErr()) { + return err(result.error) + } + return ok(result.value ? checkRowToEntity(result.value) : undefined) + } + + async pruneChecks(blockTimestamp: bigint): Promise> { + return await ResultAsync.fromPromise( + db + .deleteFrom("checks") + .where("blockTimestamp", "<", Number(blockTimestamp) - PRUNE_BLOCK_TIMESTAMP_THRESHOLD_SECONDS) + .execute(), + unknownToError, + ).map(() => undefined) + } +} diff --git a/apps/randomness-monitor/src/constants.ts b/apps/randomness-monitor/src/constants.ts new file mode 100644 index 0000000000..db523d5264 --- /dev/null +++ b/apps/randomness-monitor/src/constants.ts @@ -0,0 +1,2 @@ +// Quantity of digits in the max uint256 value +export const DIGITS_MAX_UINT256 = 78 diff --git a/apps/randomness-monitor/src/db/driver.ts b/apps/randomness-monitor/src/db/driver.ts new file mode 100644 index 0000000000..167fc46521 --- /dev/null +++ b/apps/randomness-monitor/src/db/driver.ts @@ -0,0 +1,16 @@ +import SQLite from "better-sqlite3" +import { Kysely, SqliteDialect } from "kysely" +import { env } from "../env.js" +import type { Database } from "./types.js" + +const sqlite3 = new SQLite(env.MONITORING_DB_PATH ?? ":memory:") + +sqlite3.defaultSafeIntegers() + +const dialect = new SqliteDialect({ + database: sqlite3, +}) + +export const db = new Kysely({ + dialect, +}) diff --git a/apps/randomness-monitor/src/db/migrations/Migration20250403123000.ts b/apps/randomness-monitor/src/db/migrations/Migration20250403123000.ts new file mode 100644 index 0000000000..f3620edca8 --- /dev/null +++ b/apps/randomness-monitor/src/db/migrations/Migration20250403123000.ts @@ -0,0 +1,15 @@ +import type { Kysely } from "kysely" +import type { Database } from "../types" + +export async function up(db: Kysely) { + await db.schema + .createTable("checks") + .addColumn("blockNumber", "integer", (col) => col.notNull()) + .addColumn("blockTimestamp", "integer", (col) => col.notNull()) + .addColumn("result", "text", (col) => col.notNull()) + .addColumn("errorDescription", "text") + .addColumn("value", "text") + .execute() +} + +export const migration20250403123000 = { up } diff --git a/apps/randomness-monitor/src/db/migrations/index.ts b/apps/randomness-monitor/src/db/migrations/index.ts new file mode 100644 index 0000000000..6f8cb9a8c9 --- /dev/null +++ b/apps/randomness-monitor/src/db/migrations/index.ts @@ -0,0 +1,5 @@ +import { migration20250403123000 } from "./Migration20250403123000" + +export const migrations = { + "20250403123000": migration20250403123000, +} diff --git a/apps/randomness-monitor/src/db/types.ts b/apps/randomness-monitor/src/db/types.ts new file mode 100644 index 0000000000..b5daf6f465 --- /dev/null +++ b/apps/randomness-monitor/src/db/types.ts @@ -0,0 +1,33 @@ +import { Check, type CheckResult } from "../Check" + +export interface CheckRow { + blockNumber: number + blockTimestamp: number + result: CheckResult + errorDescription: string | undefined + value: string | undefined +} + +export function checkRowToEntity(row: CheckRow): Check { + return new Check( + BigInt(row.blockNumber), + BigInt(row.blockTimestamp), + row.result, + row.errorDescription, + row.value, + ) +} + +export function checkEntityToRow(entity: Check): CheckRow { + return { + blockNumber: Number(entity.blockNumber), + blockTimestamp: Number(entity.blockTimestamp), + result: entity.result, + errorDescription: entity.errorDescription, + value: entity.value, + } +} + +export interface Database { + checks: CheckRow +} diff --git a/apps/randomness-monitor/src/env.ts b/apps/randomness-monitor/src/env.ts new file mode 100644 index 0000000000..01440b9019 --- /dev/null +++ b/apps/randomness-monitor/src/env.ts @@ -0,0 +1,21 @@ +import { z } from "zod" +import { hexSchema } from "./utils/schemas" + +const envSchema = z.object({ + MONITORING_DB_PATH: z.string().trim(), + RPC_URL: z.string().trim(), + CHAIN_ID: z + .string() + .trim() + .transform((value) => Number(value)), + RANDOM_CONTRACT_ADDRESS: hexSchema, +}) + +const parsedEnv = envSchema.safeParse(process.env) + +if (!parsedEnv.success) { + console.log(parsedEnv.error.issues) + throw new Error("There is an error with the server environment variables") +} + +export const env = parsedEnv.data diff --git a/apps/randomness-monitor/src/index.ts b/apps/randomness-monitor/src/index.ts new file mode 100644 index 0000000000..ab1e5afd6e --- /dev/null +++ b/apps/randomness-monitor/src/index.ts @@ -0,0 +1,224 @@ +import { bigIntReplacer, unknownToError } from "@happy.tech/common" +import { getUrlProtocol } from "@happy.tech/common" +import { abis } from "@happy.tech/contracts/random/anvil" +import { type Result, err, ok } from "neverthrow" +import { http, type Block, type PublicClient, type Transport, createPublicClient, defineChain, webSocket } from "viem" +import { CheckRepository } from "./CheckRepository" +import { Check, CheckResult } from "./Check" +import { env } from "./env" +import { logger } from "./utils/logger" + +/** + * Main monitoring service for tracking blockchain randomness + */ +export class MonitoringService { + private readonly checkRepository: CheckRepository + private readonly viemClient: PublicClient + private readonly protocol: "http" | "websocket" + + private latestBlockchainBlockNumber: bigint | undefined + private latestMonitoringBlockNumber: bigint | undefined + private isProcessing = false + + constructor() { + this.checkRepository = new CheckRepository() + + const protocolResult = getUrlProtocol(env.RPC_URL) + + if (protocolResult.isErr()) { + throw protocolResult.error + } + + this.protocol = protocolResult.value + + let transport: Transport + if (this.protocol === "http") { + transport = http(env.RPC_URL) + } else { + transport = webSocket(env.RPC_URL) + } + + /** + * Define the viem chain object. + * Certain properties required by viem are set to "Unknown" because they are not relevant to our library. + * This approach eliminates the need for users to provide unnecessary properties when configuring the library. + */ + const chain = defineChain({ + id: env.CHAIN_ID, + name: "Unknown", + rpcUrls: { + default: { + http: this.protocol === "http" ? [env.RPC_URL] : [], + webSocket: this.protocol === "websocket" ? [env.RPC_URL] : [], + }, + }, + nativeCurrency: { + name: "Unknown", + symbol: "UNKNOWN", + decimals: 18, + }, + }) + + this.viemClient = createPublicClient({ + transport, + chain, + }) + } + + /** + * Initialize and start the monitoring service + */ + async start(): Promise { + await this.initializeClient() + await this.initializeMonitoring() + } + + /** + * Initialize the blockchain client + */ + private async initializeClient(): Promise { + await this.viemClient.watchBlocks({ + onBlock: this.onBlock.bind(this), + ...(this.protocol === "http" ? { pollingInterval: 250 } : {}), + onError: (error) => { + console.error("Error in watching blocks:", error) + process.exit(1) + }, + }) + } + + /** + * Initialize monitoring state from database + */ + private async initializeMonitoring(): Promise { + const latestCheck = await this.checkRepository.findLatestCheck() + + if (latestCheck.isErr()) { + console.error("Failed to retrieve latest check:", latestCheck.error) + process.exit(1) + } + + this.latestMonitoringBlockNumber = latestCheck.value?.blockNumber + console.log("Starting monitoring from block:", this.latestMonitoringBlockNumber) + } + + /** + * Handle new blocks from the blockchain + */ + private async onBlock(block: Block | undefined): Promise { + if (!block) { + return + } + + this.checkRepository.pruneChecks(block.timestamp) + + this.latestBlockchainBlockNumber = block.number + + await this.processPendingMonitoring() + } + + /** + * Process all blocks that haven't been monitored yet + */ + private async processPendingMonitoring(): Promise { + if (this.isProcessing) { + return + } + + this.isProcessing = true + + try { + if (!this.latestBlockchainBlockNumber) { + return + } + + if (!this.latestMonitoringBlockNumber) { + this.latestMonitoringBlockNumber = this.latestBlockchainBlockNumber + } + + let blockToMonitor = this.latestMonitoringBlockNumber + 1n + const endBlock = this.latestBlockchainBlockNumber + + while (blockToMonitor < endBlock) { + const result = await this.monitorBlock(blockToMonitor) + if (result.isErr()) { + break + } + + this.latestMonitoringBlockNumber = blockToMonitor + blockToMonitor = blockToMonitor + 1n + } + } catch (error) { + console.error("Error in processing monitoring:", error) + } finally { + this.isProcessing = false + } + } + + /** + * Monitor a specific block for randomness + */ + private async monitorBlock(blockNumber: bigint): Promise> { + logger.info(`Monitoring block ${blockNumber}`) + + let block: Block | undefined + try { + block = await this.viemClient.getBlock({ + blockNumber, + }) + } catch (error) { + console.error(`Failed to fetch block ${blockNumber}:`, error) + return err(unknownToError(error)) + } + + if (!block) { + console.warn(`Block ${blockNumber} not found`) + return err(new Error(`Block ${blockNumber} not found`)) + } + + try { + const random = await this.viemClient.readContract({ + address: env.RANDOM_CONTRACT_ADDRESS, + abi: abis.Random, + functionName: "random", + blockNumber, + }) + await this.checkRepository + .saveCheck( + new Check(blockNumber, block.timestamp, CheckResult.Success, undefined, random), + ) + .catch((error) => { + console.error("Error in saving check:", error) + }) + } catch (err: unknown) { + let errorMessage: string | undefined + + if (err && typeof err === "object" && "metaMessages" in err) { + errorMessage = JSON.stringify(err.metaMessages, bigIntReplacer) + } else { + errorMessage = JSON.stringify(err, bigIntReplacer) + } + + await this.checkRepository + .saveCheck(new Check(blockNumber, block.timestamp, CheckResult.Failure, errorMessage)) + .catch((error) => { + console.error("Error in saving check:", error) + }) + } + + return ok(undefined) + } +} + +async function main() { + try { + const monitoringService = new MonitoringService() + await monitoringService.start() + console.log("Monitoring service started successfully") + } catch (error) { + console.error("Failed to start monitoring service:", error) + process.exit(1) + } +} + +main() diff --git a/apps/randomness-monitor/src/migrate.ts b/apps/randomness-monitor/src/migrate.ts new file mode 100644 index 0000000000..b7e7f4444c --- /dev/null +++ b/apps/randomness-monitor/src/migrate.ts @@ -0,0 +1,38 @@ +import { type Migration, type MigrationProvider, Migrator } from "kysely" +import { db } from "./db/driver" +import { migrations } from "./db/migrations" + +class ObjectMigrationProvider implements MigrationProvider { + constructor(private migrations: Record) {} + + async getMigrations(): Promise> { + return this.migrations + } +} + +async function migrateToLatest() { + const migrator = new Migrator({ + db, + provider: new ObjectMigrationProvider(migrations), + }) + + const { error, results } = await migrator.migrateToLatest() + + results?.forEach((it) => { + if (it.status === "Success") { + console.log(`migration "${it.migrationName}" was executed successfully`) + } else if (it.status === "Error") { + console.error(`failed to execute migration "${it.migrationName}"`) + } + }) + + if (error) { + console.error("failed to migrate") + console.error(error) + process.exit(1) + } + + await db.destroy() +} + +migrateToLatest() diff --git a/apps/randomness-monitor/src/utils/logger.ts b/apps/randomness-monitor/src/utils/logger.ts new file mode 100644 index 0000000000..e3c8d0cde5 --- /dev/null +++ b/apps/randomness-monitor/src/utils/logger.ts @@ -0,0 +1,2 @@ +import { Logger } from "@happy.tech/common" +export const logger = Logger.create("RandomnessMonitor") diff --git a/apps/randomness-monitor/src/utils/schemas.ts b/apps/randomness-monitor/src/utils/schemas.ts new file mode 100644 index 0000000000..abb58d3c45 --- /dev/null +++ b/apps/randomness-monitor/src/utils/schemas.ts @@ -0,0 +1,10 @@ +import type { Hex } from "viem" +import { z } from "zod" + +export const hexSchema = z + .string() + .trim() + .refine((s) => s.startsWith("0x"), { + message: "Hex string must start with 0x", + }) + .transform((hex) => hex as Hex) diff --git a/apps/randomness-monitor/tsconfig.build.json b/apps/randomness-monitor/tsconfig.build.json new file mode 100644 index 0000000000..5391b3f5e4 --- /dev/null +++ b/apps/randomness-monitor/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": ["../../support/configs/tsconfig.base.json", "../../support/configs/tsconfig.types.json"], + "include": ["src"] +} diff --git a/apps/randomness-monitor/tsconfig.json b/apps/randomness-monitor/tsconfig.json new file mode 100644 index 0000000000..626aea6852 --- /dev/null +++ b/apps/randomness-monitor/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": ["../../support/configs/tsconfig.base.json"], + "include": ["*.ts", "src"] +} diff --git a/bun.lock b/bun.lock index cbe177c509..dd99ecc1be 100644 --- a/bun.lock +++ b/bun.lock @@ -118,6 +118,23 @@ "typescript": "^5.6.2", }, }, + "apps/randomness-monitor": { + "name": "@happy.tech/randomness-monitor", + "version": "0.1.0", + "dependencies": { + "@happy.tech/common": "workspace:0.1.0", + "@happy.tech/contracts": "workspace:0.1.0", + "better-sqlite3": "^11.7.0", + "kysely": "^0.27.5", + "neverthrow": "^8.1.0", + "viem": "^2.21.53", + "zod": "^3.23.8", + }, + "devDependencies": { + "@happy.tech/happybuild": "workspace:0.1.1", + "typescript": "^5.6.2", + }, + }, "apps/submitter": { "name": "submitter", "dependencies": { @@ -823,6 +840,8 @@ "@happy.tech/randomness": ["@happy.tech/randomness@workspace:apps/randomness"], + "@happy.tech/randomness-monitor": ["@happy.tech/randomness-monitor@workspace:apps/randomness-monitor"], + "@happy.tech/react": ["@happy.tech/react@workspace:packages/react"], "@happy.tech/submitter": ["@happy.tech/submitter@workspace:packages/submitter"], @@ -1305,27 +1324,27 @@ "@solidity-parser/parser": ["@solidity-parser/parser@0.19.0", "", {}, "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA=="], - "@swc/core": ["@swc/core@1.11.22", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.21" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.11.22", "@swc/core-darwin-x64": "1.11.22", "@swc/core-linux-arm-gnueabihf": "1.11.22", "@swc/core-linux-arm64-gnu": "1.11.22", "@swc/core-linux-arm64-musl": "1.11.22", "@swc/core-linux-x64-gnu": "1.11.22", "@swc/core-linux-x64-musl": "1.11.22", "@swc/core-win32-arm64-msvc": "1.11.22", "@swc/core-win32-ia32-msvc": "1.11.22", "@swc/core-win32-x64-msvc": "1.11.22" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-mjPYbqq8XjwqSE0hEPT9CzaJDyxql97LgK4iyvYlwVSQhdN1uK0DBG4eP9PxYzCS2MUGAXB34WFLegdUj5HGpg=="], + "@swc/core": ["@swc/core@1.11.21", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.21" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.11.21", "@swc/core-darwin-x64": "1.11.21", "@swc/core-linux-arm-gnueabihf": "1.11.21", "@swc/core-linux-arm64-gnu": "1.11.21", "@swc/core-linux-arm64-musl": "1.11.21", "@swc/core-linux-x64-gnu": "1.11.21", "@swc/core-linux-x64-musl": "1.11.21", "@swc/core-win32-arm64-msvc": "1.11.21", "@swc/core-win32-ia32-msvc": "1.11.21", "@swc/core-win32-x64-msvc": "1.11.21" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-/Y3BJLcwd40pExmdar8MH2UGGvCBrqNN7hauOMckrEX2Ivcbv3IMhrbGX4od1dnF880Ed8y/E9aStZCIQi0EGw=="], - "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.11.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-upSiFQfo1TE2QM3+KpBcp5SrOdKKjoc+oUoD1mmBDU2Wv4Bjjv16Z2I5ADvIqMV+b87AhYW+4Qu6iVrQD7j96Q=="], + "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.11.21", "", { "os": "darwin", "cpu": "arm64" }, "sha512-v6gjw9YFWvKulCw3ZA1dY+LGMafYzJksm1mD4UZFZ9b36CyHFowYVYug1ajYRIRqEvvfIhHUNV660zTLoVFR8g=="], - "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.11.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-8PEuF/gxIMJVK21DjuCOtzdqstn2DqnxVhpAYfXEtm3WmMqLIOIZBypF/xafAozyaHws4aB/5xmz8/7rPsjavw=="], + "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.11.21", "", { "os": "darwin", "cpu": "x64" }, "sha512-CUiTiqKlzskwswrx9Ve5NhNoab30L1/ScOfQwr1duvNlFvarC8fvQSgdtpw2Zh3MfnfNPpyLZnYg7ah4kbT9JQ=="], - "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.11.22", "", { "os": "linux", "cpu": "arm" }, "sha512-NIPTXvqtn9e7oQHgdaxM9Z/anHoXC3Fg4ZAgw5rSGa1OlnKKupt5sdfJamNggSi+eAtyoFcyfkgqHnfe2u63HA=="], + "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.11.21", "", { "os": "linux", "cpu": "arm" }, "sha512-YyBTAFM/QPqt1PscD8hDmCLnqPGKmUZpqeE25HXY8OLjl2MUs8+O4KjwPZZ+OGxpdTbwuWFyMoxjcLy80JODvg=="], - "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.11.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-xZ+bgS60c5r8kAeYsLNjJJhhQNkXdidQ277pUabSlu5GjR0CkQUPQ+L9hFeHf8DITEqpPBPRiAiiJsWq5eqMBg=="], + "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.11.21", "", { "os": "linux", "cpu": "arm64" }, "sha512-DQD+ooJmwpNsh4acrftdkuwl5LNxxg8U4+C/RJNDd7m5FP9Wo4c0URi5U0a9Vk/6sQNh9aSGcYChDpqCDWEcBw=="], - "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.11.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-JhrP/q5VqQl2eJR0xKYIkKTPjgf8CRsAmRnjJA2PtZhfQ543YbYvUqxyXSRyBOxdyX8JwzuAxIPEAlKlT7PPuQ=="], + "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.11.21", "", { "os": "linux", "cpu": "arm64" }, "sha512-y1L49+snt1a1gLTYPY641slqy55QotPdtRK9Y6jMi4JBQyZwxC8swWYlQWb+MyILwxA614fi62SCNZNznB3XSA=="], - "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.11.22", "", { "os": "linux", "cpu": "x64" }, "sha512-htmAVL+U01gk9GyziVUP0UWYaUQBgrsiP7Ytf6uDffrySyn/FclUS3MDPocNydqYsOpj3OpNKPxkaHK+F+X5fg=="], + "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.11.21", "", { "os": "linux", "cpu": "x64" }, "sha512-NesdBXv4CvVEaFUlqKj+GA4jJMNUzK2NtKOrUNEtTbXaVyNiXjFCSaDajMTedEB0jTAd9ybB0aBvwhgkJUWkWA=="], - "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.11.22", "", { "os": "linux", "cpu": "x64" }, "sha512-PL0VHbduWPX+ANoyOzr58jBiL2VnD0xGSFwPy7NRZ1Pr6SNWm4jw3x2u6RjLArGhS5EcWp64BSk9ZxqmTV3FEg=="], + "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.11.21", "", { "os": "linux", "cpu": "x64" }, "sha512-qFV60pwpKVOdmX67wqQzgtSrUGWX9Cibnp1CXyqZ9Mmt8UyYGvmGu7p6PMbTyX7vdpVUvWVRf8DzrW2//wmVHg=="], - "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.11.22", "", { "os": "win32", "cpu": "arm64" }, "sha512-moJvFhhTVGoMeEThtdF7hQog80Q00CS06v5uB+32VRuv+I31+4WPRyGlTWHO+oY4rReNcXut/mlDHPH7p0LdFg=="], + "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.11.21", "", { "os": "win32", "cpu": "arm64" }, "sha512-DJJe9k6gXR/15ZZVLv1SKhXkFst8lYCeZRNHH99SlBodvu4slhh/MKQ6YCixINRhCwliHrpXPym8/5fOq8b7Ig=="], - "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.11.22", "", { "os": "win32", "cpu": "ia32" }, "sha512-/jnsPJJz89F1aKHIb5ScHkwyzBciz2AjEq2m9tDvQdIdVufdJ4SpEDEN9FqsRNRLcBHjtbLs6bnboA+B+pRFXw=="], + "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.11.21", "", { "os": "win32", "cpu": "ia32" }, "sha512-TqEXuy6wedId7bMwLIr9byds+mKsaXVHctTN88R1UIBPwJA92Pdk0uxDgip0pEFzHB/ugU27g6d8cwUH3h2eIw=="], - "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.11.22", "", { "os": "win32", "cpu": "x64" }, "sha512-lc93Y8Mku7LCFGqIxJ91coXZp2HeoDcFZSHCL90Wttg5xhk5xVM9uUCP+OdQsSsEixLF34h5DbT9ObzP8rAdRw=="], + "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.11.21", "", { "os": "win32", "cpu": "x64" }, "sha512-BT9BNNbMxdpUM1PPAkYtviaV0A8QcXttjs2MDtOeSqqvSJaPtyM+Fof2/+xSwQDmDEFzbGCcn75M5+xy3lGqpA=="], "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], @@ -1341,7 +1360,7 @@ "@tanstack/query-core": ["@tanstack/query-core@5.74.7", "", {}, "sha512-X3StkN/Y6KGHndTjJf8H8th7AX4bKfbRpiVhVqevf0QWlxl6DhyJ0TYG3R0LARa/+xqDwzU9mA4pbJxzPCI29A=="], - "@tanstack/react-query": ["@tanstack/react-query@5.74.7", "", { "dependencies": { "@tanstack/query-core": "5.74.7" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-u4o/RIWnnrq26orGZu2NDPwmVof1vtAiiV6KYUXd49GuK+8HX+gyxoAYqIaZogvCE1cqOuZAhQKcrKGYGkrLxg=="], + "@tanstack/react-query": ["@tanstack/react-query@5.74.8", "", { "dependencies": { "@tanstack/query-core": "5.74.7" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-Hs3QHLYyyc/yUI8tS7CIM8vRmlm+2gPBiNsHzcDclvqZNCgTc0LdXRrZDhSxxhcnXJrIMnIcoNPwj9BshsCT+Q=="], "@tanstack/react-router": ["@tanstack/react-router@1.117.1", "", { "dependencies": { "@tanstack/history": "1.115.0", "@tanstack/react-store": "^0.7.0", "@tanstack/router-core": "1.117.1", "jsesc": "^3.1.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-w4TwKzPZgUM9m+yCvaWa4dw0kVn15Cy9iZivkakQaYU2psqKE6q0OXUrIejRMThkerqK64OZeAKtPToyT8K9bA=="], @@ -1365,7 +1384,7 @@ "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.115.0", "", {}, "sha512-XLUh1Py3AftcERrxkxC5Y5m5mfllRH3YR6YVlyjFgI2Tc2Ssy2NKmQFQIafoxfW459UJ8Dn81nWKETEIJifE4g=="], - "@tanstack/vue-query": ["@tanstack/vue-query@5.74.7", "", { "dependencies": { "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/query-core": "5.74.7", "@vue/devtools-api": "^6.6.3", "vue-demi": "^0.14.10" }, "peerDependencies": { "@vue/composition-api": "^1.1.2", "vue": "^2.6.0 || ^3.3.0" }, "optionalPeers": ["@vue/composition-api"] }, "sha512-9QsGF1PyYa3jqCaPMlQgc5P9fxMaAnwiLVaiFnqJYmPdycDKrk0LuPJiEfAhY2eAgZ4adKtAPR1JTRaxKkiVmw=="], + "@tanstack/vue-query": ["@tanstack/vue-query@5.74.8", "", { "dependencies": { "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/query-core": "5.74.7", "@vue/devtools-api": "^6.6.3", "vue-demi": "^0.14.10" }, "peerDependencies": { "@vue/composition-api": "^1.1.2", "vue": "^2.6.0 || ^3.3.0" }, "optionalPeers": ["@vue/composition-api"] }, "sha512-knyyIS/Ao/caVgCTKoCHHhDEBq5Ffzv4Xfd7a2TmdQ/rPFQO9ZPfoDYCjZEEaGzpZ0JmUuuXwIPSpxGGqZ+HXQ=="], "@testing-library/dom": ["@testing-library/dom@10.4.0", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" } }, "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ=="], @@ -1467,7 +1486,7 @@ "@types/bn.js": ["@types/bn.js@5.1.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w=="], - "@types/bun": ["@types/bun@1.2.10", "", { "dependencies": { "bun-types": "1.2.10" } }, "sha512-eilv6WFM3M0c9ztJt7/g80BDusK98z/FrFwseZgT4bXCq2vPhXD4z8R3oddmAn+R/Nmz9vBn4kweJKmGTZj+lg=="], + "@types/bun": ["@types/bun@1.2.11", "", { "dependencies": { "bun-types": "1.2.11" } }, "sha512-ZLbbI91EmmGwlWTRWuV6J19IUiUC5YQ3TCEuSHI3usIP75kuoA8/0PVF+LTrbEnVc8JIhpElWOxv1ocI1fJBbw=="], "@types/byte-size": ["@types/byte-size@8.1.2", "", {}, "sha512-jGyVzYu6avI8yuqQCNTZd65tzI8HZrLjKX9sdMqZrGWVlNChu0rf6p368oVEDCYJe5BMx2Ov04tD1wqtgTwGSA=="], @@ -1995,7 +2014,7 @@ "builtin-status-codes": ["builtin-status-codes@3.0.0", "", {}, "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ=="], - "bun-types": ["bun-types@1.2.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-b5ITZMnVdf3m1gMvJHG+gIfeJHiQPJak0f7925Hxu6ZN5VKA8AGy4GZ4lM+Xkn6jtWxg5S3ldWvfmXdvnkp3GQ=="], + "bun-types": ["bun-types@1.2.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-dbkp5Lo8HDrXkLrONm6bk+yiiYQSntvFUzQp0v3pzTAsXk6FtgVMjdQ+lzFNVAmQFUkPQZ3WMZqH5tTo+Dp/IA=="], "byte-size": ["byte-size@9.0.1", "", { "peerDependencies": { "@75lb/nature": "latest" }, "optionalPeers": ["@75lb/nature"] }, "sha512-YLe9x3rabBrcI0cueCdLS2l5ONUKywcRpTs02B8KP9/Cimhj7o3ZccGrPnRvcbyHMbb7W79/3MUJl7iGgTXKEw=="], @@ -2271,7 +2290,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.143", "", {}, "sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g=="], + "electron-to-chromium": ["electron-to-chromium@1.5.144", "", {}, "sha512-eJIaMRKeAzxfBSxtjYnoIAw/tdD6VIH6tHBZepZnAbE3Gyqqs5mGN87DvcldPUbVkIljTK8pY0CMcUljP64lfQ=="], "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], @@ -2651,7 +2670,7 @@ "hono": ["hono@4.7.8", "", {}, "sha512-PCibtFdxa7/Ldud9yddl1G81GjYaeMYYTq4ywSaNsYbB1Lug4mwtOMJf2WXykL0pntYwmpRJeOI3NmoDgD+Jxw=="], - "hono-openapi": ["hono-openapi@0.4.6", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0-rc.25", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "openapi-types", "valibot", "zod", "zod-openapi"] }, "sha512-wSDySp2cS5Zcf1OeLG7nCP3eMsCpcDomN137T9B6/Z5Qq3D0nWgMf0I3Gl41SE1rE37OBQ0Smqx3LOP9Hk//7A=="], + "hono-openapi": ["hono-openapi@0.4.7", "", { "dependencies": { "json-schema-walker": "^2.0.0" }, "peerDependencies": { "@hono/arktype-validator": "^2.0.0", "@hono/effect-validator": "^1.2.0", "@hono/typebox-validator": "^0.2.0 || ^0.3.0", "@hono/valibot-validator": "^0.5.1", "@hono/zod-validator": "^0.4.1", "@sinclair/typebox": "^0.34.9", "@valibot/to-json-schema": "^1.0.0-beta.3", "arktype": "^2.0.0", "effect": "^3.11.3", "hono": "^4.6.13", "openapi-types": "^12.1.3", "valibot": "^1.0.0-beta.9", "zod": "^3.23.8", "zod-openapi": "^4.0.0" }, "optionalPeers": ["@hono/arktype-validator", "@hono/effect-validator", "@hono/typebox-validator", "@hono/valibot-validator", "@hono/zod-validator", "@sinclair/typebox", "@valibot/to-json-schema", "arktype", "effect", "hono", "valibot", "zod", "zod-openapi"] }, "sha512-ooBNhDEsFdB9cqxZVHljonW1uiTTioZR8OyPHh9OzWOyh4vsrmSHEnSmEoFJaERfEvel0jEEh1FtV7csOMOkLQ=="], "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], @@ -3223,6 +3242,8 @@ "oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], + "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + "optionator": ["optionator@0.8.3", "", { "dependencies": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", "word-wrap": "~1.2.3" } }, "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA=="], "ora": ["ora@7.0.1", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.9.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.3.0", "log-symbols": "^5.1.0", "stdin-discarder": "^0.1.0", "string-width": "^6.1.0", "strip-ansi": "^7.1.0" } }, "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw=="], @@ -3819,7 +3840,7 @@ "tsort": ["tsort@0.0.1", "", {}, "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw=="], - "tsx": ["tsx@4.19.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ=="], + "tsx": ["tsx@4.19.4", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q=="], "tty-browserify": ["tty-browserify@0.0.1", "", {}, "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw=="], @@ -3947,7 +3968,7 @@ "vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="], - "viem": ["viem@2.28.0", "", { "dependencies": { "@noble/curves": "1.8.2", "@noble/hashes": "1.7.2", "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", "isows": "1.0.6", "ox": "0.6.9", "ws": "8.18.1" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-Z4W5O1pe+6pirYTFm451FcZmfGAUxUWt2L/eWC+YfTF28j/8rd7q6MBAi05lMN4KhLJjhN0s5YGIPB+kf1L20g=="], + "viem": ["viem@2.28.1", "", { "dependencies": { "@noble/curves": "1.8.2", "@noble/hashes": "1.7.2", "@scure/bip32": "1.6.2", "@scure/bip39": "1.5.4", "abitype": "1.0.8", "isows": "1.0.6", "ox": "0.6.9", "ws": "8.18.1" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-7eqGfxAPlMW9u9aE3SMEFPzNYqqU7uFLKUQyd/GwccyW4OAdq7VqJkPIpdULUePN9m3XmfBunA9mswYFp9sUuQ=="], "vite": ["vite@5.4.18", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA=="], diff --git a/packages/txm/lib/TransactionManager.ts b/packages/txm/lib/TransactionManager.ts index 40c46bf9b1..a29b48713b 100644 --- a/packages/txm/lib/TransactionManager.ts +++ b/packages/txm/lib/TransactionManager.ts @@ -1,4 +1,5 @@ import type { UUID } from "@happy.tech/common" +import { getUrlProtocol } from "@happy.tech/common" import { trace } from "@opentelemetry/api" import type { MetricReader } from "@opentelemetry/sdk-metrics" import type { SpanExporter } from "@opentelemetry/sdk-trace-node" @@ -30,7 +31,6 @@ import { TxMonitor } from "./TxMonitor.js" import { type EIP1559Parameters, opStackDefaultEIP1559Parameters } from "./eip1559.js" import { initializeTelemetry } from "./telemetry/instrumentation" import { TxmMetrics } from "./telemetry/metrics" -import { getUrlProtocol } from "./utils/getUrlProtocol" import type { SafeViemPublicClient, SafeViemWalletClient } from "./utils/safeViemClients" import { convertToSafeViemPublicClient, convertToSafeViemWalletClient } from "./utils/safeViemClients" diff --git a/support/common/lib/index.ts b/support/common/lib/index.ts index d30acc7d36..3a56a9fef6 100644 --- a/support/common/lib/index.ts +++ b/support/common/lib/index.ts @@ -89,6 +89,8 @@ export { hasKey, hasDefinedKey, getProp } from "./utils/objects" export { stringify } from "./utils/string" +export { getUrlProtocol } from "./utils/urlProtocol" + // === DATA ======================================================================================== export { injectedProviderInfo, happyProviderInfo } from "./data/providers" diff --git a/packages/txm/lib/utils/getUrlProtocol.ts b/support/common/lib/utils/urlProtocol.ts similarity index 100% rename from packages/txm/lib/utils/getUrlProtocol.ts rename to support/common/lib/utils/urlProtocol.ts