From 98f37421636c53a44fa1f5628de889f1dbeca097 Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Tue, 2 Jun 2026 14:15:37 -0500 Subject: [PATCH 1/4] feat: add audit event backed TIPS routes --- src/app/api/block/[hash]/route.ts | 39 +++- src/app/api/bundle/[hash]/route.ts | 9 +- src/app/api/rejected/route.ts | 13 ++ src/app/api/txn/[hash]/route.ts | 35 ++++ src/lib/audit-events.test.ts | 88 +++++++++ src/lib/audit-events.ts | 282 +++++++++++++++++++++++++++++ 6 files changed, 462 insertions(+), 4 deletions(-) create mode 100644 src/lib/audit-events.test.ts create mode 100644 src/lib/audit-events.ts diff --git a/src/app/api/block/[hash]/route.ts b/src/app/api/block/[hash]/route.ts index 37d01449..d6c86531 100644 --- a/src/app/api/block/[hash]/route.ts +++ b/src/app/api/block/[hash]/route.ts @@ -1,6 +1,12 @@ import { type NextRequest, NextResponse } from "next/server"; import { type Block, createPublicClient, type Hash, http } from "viem"; import { mainnet } from "viem/chains"; +import { + getAuditEventsByTransactionHash, + isAuditEventBackend, + meterBundleResponseFromAuditEvent, + transactionMetadataFromAuditEvents, +} from "@/lib/audit-events"; import { type BlockData, type BlockTransaction, @@ -82,6 +88,23 @@ async function enrichTransactionWithBundleData(txHash: string): Promise<{ bundleId: string | null; meterBundleResponse: Record | null; }> { + if (isAuditEventBackend()) { + const events = await getAuditEventsByTransactionHash(txHash); + const metadata = transactionMetadataFromAuditEvents(events); + const accepted = events.find( + (event) => event.event_type === "SIMULATION_ACCEPTED", + ); + return { + bundleId: metadata?.bundle_ids[0] ?? null, + meterBundleResponse: accepted + ? (meterBundleResponseFromAuditEvent(accepted) as unknown as Record< + string, + unknown + >) + : null, + }; + } + const metadata = await getTransactionMetadataByHash(txHash); if (!metadata || metadata.bundle_ids.length === 0) { return { bundleId: null, meterBundleResponse: null }; @@ -111,6 +134,7 @@ async function buildAndCacheBlockData( rpcBlock: Block, hash: Hash, number: bigint, + shouldCache = true, ): Promise { const transactions: BlockTransaction[] = await Promise.all( rpcBlock.transactions.map(async (tx, index) => { @@ -137,7 +161,9 @@ async function buildAndCacheBlockData( cachedAt: Date.now(), }; - await cacheBlockData(blockData); + if (shouldCache) { + await cacheBlockData(blockData); + } return blockData; } @@ -197,6 +223,7 @@ export async function GET( ) { try { const { hash: identifier } = await params; + const auditBackend = isAuditEventBackend(); // If the identifier is a block number, resolve it to a hash first if (isBlockNumber(identifier)) { @@ -206,7 +233,9 @@ export async function GET( } // Check cache by resolved hash - const cachedBlock = await getBlockFromCache(rpcBlock.hash); + const cachedBlock = auditBackend + ? null + : await getBlockFromCache(rpcBlock.hash); if (cachedBlock) { const { updatedBlock, hasUpdates } = await refetchMissingTransactionSimulations(cachedBlock); @@ -220,11 +249,14 @@ export async function GET( rpcBlock, rpcBlock.hash, rpcBlock.number, + !auditBackend, ); return NextResponse.json(serializeBlockData(blockData)); } - const cachedBlock = await getBlockFromCache(identifier); + const cachedBlock = auditBackend + ? null + : await getBlockFromCache(identifier); if (cachedBlock) { const { updatedBlock, hasUpdates } = await refetchMissingTransactionSimulations(cachedBlock); @@ -245,6 +277,7 @@ export async function GET( rpcBlock, rpcBlock.hash, rpcBlock.number, + !auditBackend, ); return NextResponse.json(serializeBlockData(blockData)); } catch (error) { diff --git a/src/app/api/bundle/[hash]/route.ts b/src/app/api/bundle/[hash]/route.ts index 3d9e3f69..5857a7ad 100644 --- a/src/app/api/bundle/[hash]/route.ts +++ b/src/app/api/bundle/[hash]/route.ts @@ -1,4 +1,9 @@ import { type NextRequest, NextResponse } from "next/server"; +import { + bundleHistoryFromAuditEvents, + getAuditEventsByBundle, + isAuditEventBackend, +} from "@/lib/audit-events"; import { type BundleEvent, getBundleHistory } from "@/lib/s3"; export interface BundleHistoryResponse { @@ -13,7 +18,9 @@ export async function GET( try { const { hash } = await params; - const bundle = await getBundleHistory(hash); + const bundle = isAuditEventBackend() + ? bundleHistoryFromAuditEvents(hash, await getAuditEventsByBundle(hash)) + : await getBundleHistory(hash); if (!bundle) { return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); } diff --git a/src/app/api/rejected/route.ts b/src/app/api/rejected/route.ts index aacc63a9..ba79bb87 100644 --- a/src/app/api/rejected/route.ts +++ b/src/app/api/rejected/route.ts @@ -1,4 +1,9 @@ import { NextResponse } from "next/server"; +import { + getAuditRejectedTransactionEvents, + isAuditEventBackend, + rejectedTransactionFromAuditEvent, +} from "@/lib/audit-events"; import { getRejectedTransaction, listRejectedTransactions, @@ -11,6 +16,14 @@ export interface RejectedTransactionsResponse { export async function GET() { try { + if (isAuditEventBackend()) { + const transactions = (await getAuditRejectedTransactionEvents(100)) + .map(rejectedTransactionFromAuditEvent) + .filter((tx): tx is RejectedTransaction => tx !== null); + + return NextResponse.json({ transactions }); + } + const summaries = await listRejectedTransactions(100); const transactions = ( diff --git a/src/app/api/txn/[hash]/route.ts b/src/app/api/txn/[hash]/route.ts index 44f68243..67326c56 100644 --- a/src/app/api/txn/[hash]/route.ts +++ b/src/app/api/txn/[hash]/route.ts @@ -1,4 +1,11 @@ import { type NextRequest, NextResponse } from "next/server"; +import { + bundleHistoryFromAuditEvents, + getAuditEventsByBundle, + getAuditEventsByTransactionHash, + isAuditEventBackend, + transactionMetadataFromAuditEvents, +} from "@/lib/audit-events"; import { type BundleEvent, getBundleHistory, @@ -41,6 +48,34 @@ export async function GET( try { const { hash } = await params; + if (isAuditEventBackend()) { + const events = await getAuditEventsByTransactionHash(hash); + const metadata = transactionMetadataFromAuditEvents(events); + if (!metadata) { + return NextResponse.json( + { error: "Transaction not found" }, + { status: 404 }, + ); + } + + const bundleId = metadata.bundle_ids[0]; + const bundle = + bundleId !== undefined + ? bundleHistoryFromAuditEvents( + bundleId, + await getAuditEventsByBundle(bundleId), + ) + : { history: [] }; + + const response: TransactionHistoryResponse = { + hash, + bundle_ids: metadata.bundle_ids, + history: bundle?.history ?? [], + }; + + return NextResponse.json(response); + } + const metadata = await getTransactionMetadataByHash(hash); if (!metadata) { diff --git a/src/lib/audit-events.test.ts b/src/lib/audit-events.test.ts new file mode 100644 index 00000000..46e02b94 --- /dev/null +++ b/src/lib/audit-events.test.ts @@ -0,0 +1,88 @@ +import assert from "node:assert/strict"; +import { describe, test } from "node:test"; +import { + type AuditTransactionEventRecord, + bundleHistoryFromAuditEvents, + isAuditEventBackend, + rejectedTransactionFromAuditEvent, + transactionMetadataFromAuditEvents, +} from "./audit-events"; + +const acceptedEvent: AuditTransactionEventRecord = { + schema_version: "transaction-event/v1", + event_id: "event-1", + event_time: "2026-06-02T00:00:00Z", + ingested_at: "2026-06-02T00:00:01Z", + producer: "ingress-rpc", + event_type: "SIMULATION_ACCEPTED", + tx_hash: "0xabc", + block_number: null, + data: { + bundle_hash: "0xbundle", + bundle_id: "bundle-id", + state_block_number: 123, + total_gas_used: 21000, + total_execution_time_us: "500", + state_root_time_us: "50", + results: [ + { + txHash: "0xabc", + fromAddress: "0xsender", + toAddress: "0xto", + gasUsed: 21000, + executionTimeUs: "500", + }, + ], + }, +}; + +describe("audit event route adapters", () => { + test("old mode remains the default unless the audit backend flag is set", () => { + delete process.env.TIPS_UI_QUERY_BACKEND; + assert.equal(isAuditEventBackend(), false); + + process.env.TIPS_UI_QUERY_BACKEND = "audit"; + assert.equal(isAuditEventBackend(), true); + delete process.env.TIPS_UI_QUERY_BACKEND; + }); + + test("new mode adapts audit bundle events to the existing bundle route shape", () => { + const history = bundleHistoryFromAuditEvents("0xbundle", [acceptedEvent]); + + assert.equal(history?.history.length, 1); + assert.equal(history?.history[0]?.event, "Received"); + assert.equal( + history?.history[0]?.data.bundle?.meter_bundle_response.results[0] + ?.txHash, + "0xabc", + ); + }); + + test("new mode derives transaction metadata from audit join fields", () => { + const metadata = transactionMetadataFromAuditEvents([acceptedEvent]); + + assert.deepEqual(metadata?.bundle_ids, ["bundle-id"]); + }); + + test("new mode adapts rejected audit events to the existing rejected route shape", () => { + const rejected = rejectedTransactionFromAuditEvent({ + ...acceptedEvent, + event_id: "event-2", + event_type: "BUILDER_REJECTED", + block_number: 123, + data: { + ...acceptedEvent.data, + reason: { + executionTimeExceeded: { + tx_time_us: 1000, + limit_us: 500, + }, + }, + }, + }); + + assert.equal(rejected?.blockNumber, 123); + assert.equal(rejected?.txHash, "0xabc"); + assert.equal(rejected?.metering.totalGasUsed, 21000); + }); +}); diff --git a/src/lib/audit-events.ts b/src/lib/audit-events.ts new file mode 100644 index 00000000..16fec749 --- /dev/null +++ b/src/lib/audit-events.ts @@ -0,0 +1,282 @@ +import type { + BundleEvent, + BundleHistory, + MeterBundleResponse, + RejectedTransaction, + RejectionReason, + TransactionMetadata, +} from "@/lib/s3"; + +const AUDIT_RPC_URL = + process.env.TIPS_UI_AUDIT_RPC_URL || "http://localhost:8080"; + +export function isAuditEventBackend(): boolean { + return process.env.TIPS_UI_QUERY_BACKEND === "audit"; +} + +export interface AuditTransactionEventRecord { + schema_version: string; + event_id: string; + event_time: string; + ingested_at: string; + producer: string; + event_type: string; + network?: string | null; + tx_hash?: string | null; + block_hash?: string | null; + block_number?: number | null; + payload_id?: string | null; + request_id?: string | null; + data: Record; +} + +interface JsonRpcResponse { + result?: T; + error?: { code: number; message: string }; +} + +async function auditRpc(method: string, params: unknown[]): Promise { + const response = await fetch(AUDIT_RPC_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method, + params, + }), + }); + + if (!response.ok) { + throw new Error(`audit RPC HTTP ${response.status}`); + } + + const body = (await response.json()) as JsonRpcResponse; + if (body.error) { + throw new Error(body.error.message); + } + if (body.result === undefined) { + throw new Error("audit RPC response missing result"); + } + return body.result; +} + +export async function getAuditEventsByTransactionHash( + hash: string, + limit = 500, +): Promise { + return auditRpc("base_getTransactionEventsByHash", [hash, limit]); +} + +export async function getAuditEventsByBlockNumber( + blockNumber: number, + limit = 500, +): Promise { + return auditRpc("base_getTransactionEventsByBlockNumber", [ + blockNumber, + limit, + ]); +} + +export async function getAuditEventsByBlockHash( + blockHash: string, + limit = 500, +): Promise { + return auditRpc("base_getTransactionEventsByBlockHash", [blockHash, limit]); +} + +export async function getAuditEventsByBundle( + bundleKey: string, + limit = 500, +): Promise { + return auditRpc("base_getTransactionEventsByBundle", [bundleKey, limit]); +} + +export async function getAuditRejectedTransactionEvents( + limit = 100, +): Promise { + return auditRpc("base_getRejectedTransactionEvents", [{ limit }]); +} + +export function transactionMetadataFromAuditEvents( + events: AuditTransactionEventRecord[], +): TransactionMetadata | null { + if (events.length === 0) return null; + + const bundleIds = Array.from( + new Set( + events + .map((event) => stringField(event.data.bundle_id)) + .filter((value): value is string => value !== null), + ), + ); + const bundleHashes = Array.from( + new Set( + events + .map((event) => stringField(event.data.bundle_hash)) + .filter((value): value is string => value !== null), + ), + ); + + return { + bundle_ids: bundleIds.length > 0 ? bundleIds : bundleHashes, + sender: "", + nonce: "", + }; +} + +export function bundleHistoryFromAuditEvents( + bundleKey: string, + events: AuditTransactionEventRecord[], +): BundleHistory | null { + if (events.length === 0) return null; + return { + history: events + .map((event) => bundleEventFromAuditEvent(bundleKey, event)) + .sort((lhs, rhs) => lhs.data.timestamp - rhs.data.timestamp), + }; +} + +export function meterBundleResponseFromAuditEvent( + event: AuditTransactionEventRecord, +): MeterBundleResponse | null { + if ( + event.event_type !== "SIMULATION_ACCEPTED" && + event.event_type !== "BUILDER_REJECTED" + ) { + return null; + } + return meterBundleResponseFromData(event.data); +} + +export function rejectedTransactionFromAuditEvent( + event: AuditTransactionEventRecord, +): RejectedTransaction | null { + if ( + event.event_type !== "SIMULATION_REJECTED" && + event.event_type !== "BUILDER_REJECTED" + ) { + return null; + } + + const txHash = event.tx_hash; + if (!txHash) return null; + + return { + blockNumber: + event.block_number ?? numberField(event.data.state_block_number) ?? 0, + txHash, + reason: rejectionReasonFromData(event.data), + timestamp: Math.floor(Date.parse(event.event_time) / 1000), + metering: meterBundleResponseFromData(event.data), + }; +} + +function bundleEventFromAuditEvent( + bundleKey: string, + event: AuditTransactionEventRecord, +): BundleEvent { + const timestamp = Date.parse(event.event_time); + if (event.event_type === "SIMULATION_ACCEPTED") { + return { + event: "Received", + data: { + key: event.event_id, + timestamp, + bundle: { + uuid: stringField(event.data.bundle_id) ?? bundleKey, + txs: [], + block_number: String(event.data.state_block_number ?? ""), + max_timestamp: 0, + reverting_tx_hashes: event.tx_hash ? [event.tx_hash] : [], + meter_bundle_response: meterBundleResponseFromData(event.data), + }, + }, + }; + } + + return { + event: event.event_type, + data: { + key: event.event_id, + timestamp, + block_number: + event.block_number ?? + numberField(event.data.state_block_number) ?? + undefined, + block_hash: event.block_hash ?? undefined, + reason: + stringField(event.data.rejection_reason) ?? + stringField(event.data.reason) ?? + undefined, + }, + }; +} + +function meterBundleResponseFromData( + data: Record, +): MeterBundleResponse { + return { + bundleGasPrice: "0", + bundleHash: stringField(data.bundle_hash) ?? "", + coinbaseDiff: "0", + ethSentToCoinbase: "0", + gasFees: "0", + results: arrayField(data.results).map((result) => ({ + coinbaseDiff: "0", + ethSentToCoinbase: "0", + fromAddress: stringField(result.fromAddress) ?? "", + gasFees: "0", + gasPrice: "0", + gasUsed: numberField(result.gasUsed) ?? 0, + toAddress: stringField(result.toAddress) ?? "", + txHash: stringField(result.txHash) ?? "", + value: "0", + executionTimeUs: numberField(result.executionTimeUs) ?? 0, + })), + stateBlockNumber: numberField(data.state_block_number) ?? 0, + totalGasUsed: numberField(data.total_gas_used) ?? 0, + totalExecutionTimeUs: numberField(data.total_execution_time_us) ?? 0, + stateRootTimeUs: numberField(data.state_root_time_us) ?? 0, + stateRootAccountLeafCount: + numberField(data.state_root_account_leaf_count) ?? 0, + stateRootAccountBranchCount: + numberField(data.state_root_account_branch_count) ?? 0, + stateRootStorageLeafCount: + numberField(data.state_root_storage_leaf_count) ?? 0, + stateRootStorageBranchCount: + numberField(data.state_root_storage_branch_count) ?? 0, + }; +} + +function rejectionReasonFromData( + data: Record, +): RejectionReason { + const reason = data.reason; + if (isRecord(reason)) { + return reason as RejectionReason; + } + + return {}; +} + +function stringField(value: unknown): string | null { + return typeof value === "string" && value.length > 0 ? value : null; +} + +function numberField(value: unknown): number | null { + if (typeof value === "number") return value; + if (typeof value === "string" && value.length > 0) { + const parsed = Number(value); + return Number.isFinite(parsed) ? parsed : null; + } + return null; +} + +function arrayField(value: unknown): Record[] { + return Array.isArray(value) ? value.filter(isRecord) : []; +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} From 6e549694e10cc464364e4e9f2d9673f980810ab9 Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Thu, 11 Jun 2026 17:43:54 -0500 Subject: [PATCH 2/4] Use audit API for TIPS transaction data --- .env.example | 7 +- bun.lock | 457 ++++++++--------------------- package.json | 1 - src/app/api/block/[hash]/route.ts | 142 +-------- src/app/api/bundle/[hash]/route.ts | 10 +- src/app/api/rejected/route.ts | 25 +- src/app/api/txn/[hash]/route.ts | 54 +--- src/app/block/[hash]/page.tsx | 2 +- src/app/bundles/[hash]/page.tsx | 5 +- src/app/page.tsx | 2 +- src/lib/audit-events.test.ts | 47 ++- src/lib/audit-events.ts | 45 +-- src/lib/s3.ts | 355 ---------------------- src/lib/transaction-data.ts | 129 ++++++++ 14 files changed, 340 insertions(+), 941 deletions(-) delete mode 100644 src/lib/s3.ts create mode 100644 src/lib/transaction-data.ts diff --git a/.env.example b/.env.example index 925008d0..e96b9e71 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,3 @@ NEXT_PUBLIC_BLOCK_EXPLORER_URL=https://base.blockscout.com TIPS_UI_RPC_URL=http://localhost:8545 -TIPS_UI_AWS_REGION=us-east-1 -TIPS_UI_S3_BUCKET_NAME=tips -TIPS_UI_S3_CONFIG_TYPE=manual -TIPS_UI_S3_ENDPOINT=http://localhost:7000 -TIPS_UI_S3_ACCESS_KEY_ID=minioadmin -TIPS_UI_S3_SECRET_ACCESS_KEY=minioadmin +TIPS_UI_AUDIT_RPC_URL=http://localhost:8080 diff --git a/bun.lock b/bun.lock index 929dbf55..9d851eca 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,6 @@ "": { "name": "ui", "dependencies": { - "@aws-sdk/client-s3": "3.940.0", "next": "16.0.7", "react": "19.2.1", "react-dom": "19.2.1", @@ -23,460 +22,254 @@ }, }, "packages": { - "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="], + "@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "https://registry-npm.cbhq.net/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="], - "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "https://registry-npm.cbhq.net/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], - "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], + "@biomejs/biome": ["@biomejs/biome@2.3.8", "https://registry-npm.cbhq.net/@biomejs/biome/-/biome-2.3.8.tgz", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="], - "@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.8.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww=="], - "@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.8.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA=="], - "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.8.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g=="], - "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.8.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA=="], - "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.8.tgz", { "os": "linux", "cpu": "x64" }, "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw=="], - "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.8.tgz", { "os": "linux", "cpu": "x64" }, "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA=="], - "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.940.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-bucket-endpoint": "3.936.0", "@aws-sdk/middleware-expect-continue": "3.936.0", "@aws-sdk/middleware-flexible-checksums": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-location-constraint": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-sdk-s3": "3.940.0", "@aws-sdk/middleware-ssec": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-Wi4qnBT6shRRMXuuTgjMFTU5mu2KFWisgcigEMPptjPGUtJvBVi4PTGgS64qsLoUk/obqDAyOBOfEtRZ2ddC2w=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.8.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg=="], - "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.8.tgz", { "os": "win32", "cpu": "x64" }, "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w=="], - "@aws-sdk/core": ["@aws-sdk/core@3.940.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA=="], + "@emnapi/runtime": ["@emnapi/runtime@1.9.1", "https://registry-npm.cbhq.net/@emnapi/runtime/-/runtime-1.9.1.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw=="], + "@img/colour": ["@img/colour@1.1.0", "https://registry-npm.cbhq.net/@img/colour/-/colour-1.1.0.tgz", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-login": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw=="], + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg=="], + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.940.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.940.0", "@aws-sdk/credential-provider-http": "3.940.0", "@aws-sdk/credential-provider-ini": "3.940.0", "@aws-sdk/credential-provider-process": "3.940.0", "@aws-sdk/credential-provider-sso": "3.940.0", "@aws-sdk/credential-provider-web-identity": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g=="], + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ=="], + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.940.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.940.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/token-providers": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw=="], + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w=="], + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], - "@aws-sdk/middleware-bucket-endpoint": ["@aws-sdk/middleware-bucket-endpoint@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg=="], + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], - "@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA=="], + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], - "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.940.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-WdsxDAVj5qaa5ApAP+JbpCOMHFGSmzjs2Y2OBSbWPeR9Ew7t/Okj+kUub94QJPsgzhvU1/cqNejhsw5VxeFKSQ=="], + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], - "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], - "@aws-sdk/middleware-location-constraint": ["@aws-sdk/middleware-location-constraint@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw=="], + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "https://registry-npm.cbhq.net/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], - "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], - "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], - "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ=="], + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], - "@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA=="], + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], - "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], - "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], - "@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], - "@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.893.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA=="], + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], - "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "https://registry-npm.cbhq.net/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], - "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.5", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "https://registry-npm.cbhq.net/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "https://registry-npm.cbhq.net/@jridgewell/remapping/-/remapping-2.3.5.tgz", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.940.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A=="], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "https://registry-npm.cbhq.net/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "https://registry-npm.cbhq.net/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "https://registry-npm.cbhq.net/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@biomejs/biome": ["@biomejs/biome@2.3.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="], + "@next/env": ["@next/env@16.0.7", "https://registry-npm.cbhq.net/@next/env/-/env-16.0.7.tgz", {}, "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww=="], + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.7", "https://registry-npm.cbhq.net/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA=="], + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.7", "https://registry-npm.cbhq.net/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g=="], + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.0.7", "https://registry-npm.cbhq.net/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA=="], + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.0.7", "https://registry-npm.cbhq.net/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.8", "", { "os": "linux", "cpu": "x64" }, "sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw=="], + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.0.7", "https://registry-npm.cbhq.net/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz", { "os": "linux", "cpu": "x64" }, "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.8", "", { "os": "linux", "cpu": "x64" }, "sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA=="], + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.0.7", "https://registry-npm.cbhq.net/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz", { "os": "linux", "cpu": "x64" }, "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg=="], + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.0.7", "https://registry-npm.cbhq.net/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.8", "", { "os": "win32", "cpu": "x64" }, "sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w=="], + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.7", "https://registry-npm.cbhq.net/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz", { "os": "win32", "cpu": "x64" }, "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug=="], - "@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], + "@noble/ciphers": ["@noble/ciphers@1.3.0", "https://registry-npm.cbhq.net/@noble/ciphers/-/ciphers-1.3.0.tgz", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], - "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + "@noble/curves": ["@noble/curves@1.9.1", "https://registry-npm.cbhq.net/@noble/curves/-/curves-1.9.1.tgz", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + "@noble/hashes": ["@noble/hashes@1.8.0", "https://registry-npm.cbhq.net/@noble/hashes/-/hashes-1.8.0.tgz", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + "@scure/base": ["@scure/base@1.2.6", "https://registry-npm.cbhq.net/@scure/base/-/base-1.2.6.tgz", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + "@scure/bip32": ["@scure/bip32@1.7.0", "https://registry-npm.cbhq.net/@scure/bip32/-/bip32-1.7.0.tgz", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + "@scure/bip39": ["@scure/bip39@1.6.0", "https://registry-npm.cbhq.net/@scure/bip39/-/bip39-1.6.0.tgz", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + "@swc/helpers": ["@swc/helpers@0.5.15", "https://registry-npm.cbhq.net/@swc/helpers/-/helpers-0.5.15.tgz", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + "@tailwindcss/node": ["@tailwindcss/node@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/node/-/node-4.1.17.tgz", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="], - "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide/-/oxide-4.1.17.tgz", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.17", "@tailwindcss/oxide-darwin-arm64": "4.1.17", "@tailwindcss/oxide-darwin-x64": "4.1.17", "@tailwindcss/oxide-freebsd-x64": "4.1.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", "@tailwindcss/oxide-linux-x64-musl": "4.1.17", "@tailwindcss/oxide-wasm32-wasi": "4.1.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA=="], - "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", { "os": "android", "cpu": "arm64" }, "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ=="], - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg=="], - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog=="], - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g=="], - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", { "os": "linux", "cpu": "arm" }, "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg=="], - "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", { "os": "linux", "cpu": "x64" }, "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ=="], - "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", { "os": "linux", "cpu": "x64" }, "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", { "dependencies": { "@emnapi/core": "^1.6.0", "@emnapi/runtime": "^1.6.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", { "os": "win32", "cpu": "x64" }, "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/postcss/-/postcss-4.1.17.tgz", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "postcss": "^8.4.41", "tailwindcss": "4.1.17" } }, "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + "@types/node": ["@types/node@20.19.25", "https://registry-npm.cbhq.net/@types/node/-/node-20.19.25.tgz", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="], - "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + "@types/react": ["@types/react@19.2.7", "https://registry-npm.cbhq.net/@types/react/-/react-19.2.7.tgz", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + "@types/react-dom": ["@types/react-dom@19.2.3", "https://registry-npm.cbhq.net/@types/react-dom/-/react-dom-19.2.3.tgz", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + "abitype": ["abitype@1.1.0", "https://registry-npm.cbhq.net/abitype/-/abitype-1.1.0.tgz", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + "caniuse-lite": ["caniuse-lite@1.0.30001781", "https://registry-npm.cbhq.net/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", {}, "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw=="], - "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + "client-only": ["client-only@0.0.1", "https://registry-npm.cbhq.net/client-only/-/client-only-0.0.1.tgz", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + "csstype": ["csstype@3.2.3", "https://registry-npm.cbhq.net/csstype/-/csstype-3.2.3.tgz", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + "detect-libc": ["detect-libc@2.1.2", "https://registry-npm.cbhq.net/detect-libc/-/detect-libc-2.1.2.tgz", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "enhanced-resolve": ["enhanced-resolve@5.20.1", "https://registry-npm.cbhq.net/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], - "@next/env": ["@next/env@16.0.7", "", {}, "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw=="], + "eventemitter3": ["eventemitter3@5.0.1", "https://registry-npm.cbhq.net/eventemitter3/-/eventemitter3-5.0.1.tgz", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg=="], + "graceful-fs": ["graceful-fs@4.2.11", "https://registry-npm.cbhq.net/graceful-fs/-/graceful-fs-4.2.11.tgz", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA=="], + "isows": ["isows@1.0.7", "https://registry-npm.cbhq.net/isows/-/isows-1.0.7.tgz", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], - "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.0.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww=="], + "jiti": ["jiti@2.6.1", "https://registry-npm.cbhq.net/jiti/-/jiti-2.6.1.tgz", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.0.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g=="], + "lightningcss": ["lightningcss@1.30.2", "https://registry-npm.cbhq.net/lightningcss/-/lightningcss-1.30.2.tgz", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], - "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.0.7", "", { "os": "linux", "cpu": "x64" }, "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA=="], + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "https://registry-npm.cbhq.net/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], - "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.0.7", "", { "os": "linux", "cpu": "x64" }, "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w=="], + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "https://registry-npm.cbhq.net/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], - "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.0.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q=="], + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "https://registry-npm.cbhq.net/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], - "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.7", "", { "os": "win32", "cpu": "x64" }, "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug=="], + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "https://registry-npm.cbhq.net/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], - "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "https://registry-npm.cbhq.net/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], - "@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "https://registry-npm.cbhq.net/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], - "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "https://registry-npm.cbhq.net/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], - "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "https://registry-npm.cbhq.net/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], - "@scure/bip32": ["@scure/bip32@1.7.0", "", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "https://registry-npm.cbhq.net/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], - "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "https://registry-npm.cbhq.net/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], - "@smithy/abort-controller": ["@smithy/abort-controller@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q=="], + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "https://registry-npm.cbhq.net/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], - "@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw=="], + "magic-string": ["magic-string@0.30.21", "https://registry-npm.cbhq.net/magic-string/-/magic-string-0.30.21.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - "@smithy/chunked-blob-reader-native": ["@smithy/chunked-blob-reader-native@4.2.3", "", { "dependencies": { "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw=="], + "nanoid": ["nanoid@3.3.11", "https://registry-npm.cbhq.net/nanoid/-/nanoid-3.3.11.tgz", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "@smithy/config-resolver": ["@smithy/config-resolver@4.4.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg=="], + "next": ["next@16.0.7", "https://registry-npm.cbhq.net/next/-/next-16.0.7.tgz", { "dependencies": { "@next/env": "16.0.7", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.7", "@next/swc-darwin-x64": "16.0.7", "@next/swc-linux-arm64-gnu": "16.0.7", "@next/swc-linux-arm64-musl": "16.0.7", "@next/swc-linux-x64-gnu": "16.0.7", "@next/swc-linux-x64-musl": "16.0.7", "@next/swc-win32-arm64-msvc": "16.0.7", "@next/swc-win32-x64-msvc": "16.0.7", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A=="], - "@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="], + "ox": ["ox@0.9.6", "https://registry-npm.cbhq.net/ox/-/ox-0.9.6.tgz", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg=="], - "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg=="], + "picocolors": ["picocolors@1.1.1", "https://registry-npm.cbhq.net/picocolors/-/picocolors-1.1.1.tgz", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.12", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA=="], + "postcss": ["postcss@8.5.8", "https://registry-npm.cbhq.net/postcss/-/postcss-8.5.8.tgz", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], - "@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.12", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A=="], + "react": ["react@19.2.1", "https://registry-npm.cbhq.net/react/-/react-19.2.1.tgz", {}, "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw=="], - "@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q=="], + "react-dom": ["react-dom@19.2.1", "https://registry-npm.cbhq.net/react-dom/-/react-dom-19.2.1.tgz", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.1" } }, "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg=="], - "@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.12", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA=="], + "scheduler": ["scheduler@0.27.0", "https://registry-npm.cbhq.net/scheduler/-/scheduler-0.27.0.tgz", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - "@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.12", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ=="], + "semver": ["semver@7.7.4", "https://registry-npm.cbhq.net/semver/-/semver-7.7.4.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.15", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A=="], + "sharp": ["sharp@0.34.5", "https://registry-npm.cbhq.net/sharp/-/sharp-0.34.5.tgz", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], - "@smithy/hash-blob-browser": ["@smithy/hash-blob-browser@4.2.13", "", { "dependencies": { "@smithy/chunked-blob-reader": "^5.2.2", "@smithy/chunked-blob-reader-native": "^4.2.3", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-YrF4zWKh+ghLuquldj6e/RzE3xZYL8wIPfkt0MqCRphVICjyyjH8OwKD7LLlKpVEbk4FLizFfC1+gwK6XQdR3g=="], + "source-map-js": ["source-map-js@1.2.1", "https://registry-npm.cbhq.net/source-map-js/-/source-map-js-1.2.1.tgz", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - "@smithy/hash-node": ["@smithy/hash-node@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w=="], + "styled-jsx": ["styled-jsx@5.1.6", "https://registry-npm.cbhq.net/styled-jsx/-/styled-jsx-5.1.6.tgz", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], - "@smithy/hash-stream-node": ["@smithy/hash-stream-node@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-O3YbmGExeafuM/kP7Y8r6+1y0hIh3/zn6GROx0uNlB54K9oihAL75Qtc+jFfLNliTi6pxOAYZrRKD9A7iA6UFw=="], + "tailwindcss": ["tailwindcss@4.1.17", "https://registry-npm.cbhq.net/tailwindcss/-/tailwindcss-4.1.17.tgz", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], - "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g=="], + "tapable": ["tapable@2.3.2", "https://registry-npm.cbhq.net/tapable/-/tapable-2.3.2.tgz", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], - "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow=="], + "tslib": ["tslib@2.8.1", "https://registry-npm.cbhq.net/tslib/-/tslib-2.8.1.tgz", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@smithy/md5-js": ["@smithy/md5-js@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-W/oIpHCpWU2+iAkfZYyGWE+qkpuf3vEXHLxQQDx9FPNZTTdnul0dZ2d/gUFrtQ5je1G2kp4cjG0/24YueG2LbQ=="], + "typescript": ["typescript@5.9.3", "https://registry-npm.cbhq.net/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA=="], + "undici-types": ["undici-types@6.21.0", "https://registry-npm.cbhq.net/undici-types/-/undici-types-6.21.0.tgz", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], - "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="], + "viem": ["viem@2.40.3", "https://registry-npm.cbhq.net/viem/-/viem-2.40.3.tgz", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.1.0", "isows": "1.0.7", "ox": "0.9.6", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA=="], - "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="], + "ws": ["ws@8.18.3", "https://registry-npm.cbhq.net/ws/-/ws-8.18.3.tgz", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], - "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "https://registry-npm.cbhq.net/@emnapi/core/-/core-1.9.1.tgz", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], - "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "https://registry-npm.cbhq.net/@emnapi/runtime/-/runtime-1.9.1.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], - "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.12", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "https://registry-npm.cbhq.net/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "https://registry-npm.cbhq.net/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - "@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="], + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "https://registry-npm.cbhq.net/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@smithy/protocol-http": ["@smithy/protocol-http@5.3.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw=="], + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "https://registry-npm.cbhq.net/tslib/-/tslib-2.8.1.tgz", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg=="], - - "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw=="], - - "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1" } }, "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ=="], - - "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.7", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw=="], - - "@smithy/signature-v4": ["@smithy/signature-v4@5.3.12", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw=="], - - "@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="], - - "@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="], - - "@smithy/url-parser": ["@smithy/url-parser@4.2.12", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA=="], - - "@smithy/util-base64": ["@smithy/util-base64@4.3.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ=="], - - "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ=="], - - "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g=="], - - "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.2", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q=="], - - "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ=="], - - "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="], - - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="], - - "@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig=="], - - "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg=="], - - "@smithy/util-middleware": ["@smithy/util-middleware@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ=="], - - "@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="], - - "@smithy/util-stream": ["@smithy/util-stream@4.5.20", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.0", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw=="], - - "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw=="], - - "@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], - - "@smithy/util-waiter": ["@smithy/util-waiter@4.2.13", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-2zdZ9DTHngRtcYxJK1GUDxruNr53kv5W2Lupe0LMU+Imr6ohQg8M2T14MNkj1Y0wS3FFwpgpGQyvuaMF7CiTmQ=="], - - "@smithy/uuid": ["@smithy/uuid@1.1.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g=="], - - "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], - - "@tailwindcss/node": ["@tailwindcss/node@4.1.17", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="], - - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.17", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.17", "@tailwindcss/oxide-darwin-arm64": "4.1.17", "@tailwindcss/oxide-darwin-x64": "4.1.17", "@tailwindcss/oxide-freebsd-x64": "4.1.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", "@tailwindcss/oxide-linux-x64-musl": "4.1.17", "@tailwindcss/oxide-wasm32-wasi": "4.1.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA=="], - - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.17", "", { "os": "android", "cpu": "arm64" }, "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ=="], - - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg=="], - - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog=="], - - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.17", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g=="], - - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17", "", { "os": "linux", "cpu": "arm" }, "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ=="], - - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ=="], - - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg=="], - - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.17", "", { "os": "linux", "cpu": "x64" }, "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ=="], - - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.17", "", { "os": "linux", "cpu": "x64" }, "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ=="], - - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.17", "", { "dependencies": { "@emnapi/core": "^1.6.0", "@emnapi/runtime": "^1.6.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg=="], - - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A=="], - - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.17", "", { "os": "win32", "cpu": "x64" }, "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw=="], - - "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.17", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "postcss": "^8.4.41", "tailwindcss": "4.1.17" } }, "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw=="], - - "@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="], - - "@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="], - - "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], - - "abitype": ["abitype@1.1.0", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A=="], - - "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001781", "", {}, "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw=="], - - "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], - - "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - - "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], - - "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], - - "fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], - - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - - "isows": ["isows@1.0.7", "", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], - - "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - - "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], - - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], - - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], - - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], - - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], - - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], - - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], - - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], - - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], - - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], - - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], - - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], - - "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - - "next": ["next@16.0.7", "", { "dependencies": { "@next/env": "16.0.7", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.7", "@next/swc-darwin-x64": "16.0.7", "@next/swc-linux-arm64-gnu": "16.0.7", "@next/swc-linux-arm64-musl": "16.0.7", "@next/swc-linux-x64-gnu": "16.0.7", "@next/swc-linux-x64-musl": "16.0.7", "@next/swc-win32-arm64-msvc": "16.0.7", "@next/swc-win32-x64-msvc": "16.0.7", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A=="], - - "ox": ["ox@0.9.6", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], - - "react": ["react@19.2.1", "", {}, "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw=="], - - "react-dom": ["react-dom@19.2.1", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.1" } }, "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg=="], - - "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - - "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - - "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "strnum": ["strnum@2.2.2", "", {}, "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA=="], - - "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], - - "tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], - - "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], - - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], - - "viem": ["viem@2.40.3", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.1.0", "isows": "1.0.7", "ox": "0.9.6", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA=="], - - "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], - - "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - - "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - - "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], - - "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], - - "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - - "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], - - "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - - "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - - "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], - - "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - - "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], - - "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + "next/postcss": ["postcss@8.4.31", "https://registry-npm.cbhq.net/postcss/-/postcss-8.4.31.tgz", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], } } diff --git a/package.json b/package.json index 54d105ce..b6af038b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "format": "biome format --write" }, "dependencies": { - "@aws-sdk/client-s3": "3.940.0", "next": "16.0.7", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/src/app/api/block/[hash]/route.ts b/src/app/api/block/[hash]/route.ts index d6c86531..dd6d0a5e 100644 --- a/src/app/api/block/[hash]/route.ts +++ b/src/app/api/block/[hash]/route.ts @@ -3,18 +3,10 @@ import { type Block, createPublicClient, type Hash, http } from "viem"; import { mainnet } from "viem/chains"; import { getAuditEventsByTransactionHash, - isAuditEventBackend, meterBundleResponseFromAuditEvent, transactionMetadataFromAuditEvents, } from "@/lib/audit-events"; -import { - type BlockData, - type BlockTransaction, - cacheBlockData, - getBlockFromCache, - getBundleHistory, - getTransactionMetadataByHash, -} from "@/lib/s3"; +import type { BlockData, BlockTransaction } from "@/lib/transaction-data"; function serializeBlockData(block: BlockData) { return { @@ -88,45 +80,19 @@ async function enrichTransactionWithBundleData(txHash: string): Promise<{ bundleId: string | null; meterBundleResponse: Record | null; }> { - if (isAuditEventBackend()) { - const events = await getAuditEventsByTransactionHash(txHash); - const metadata = transactionMetadataFromAuditEvents(events); - const accepted = events.find( - (event) => event.event_type === "SIMULATION_ACCEPTED", - ); - return { - bundleId: metadata?.bundle_ids[0] ?? null, - meterBundleResponse: accepted - ? (meterBundleResponseFromAuditEvent(accepted) as unknown as Record< - string, - unknown - >) - : null, - }; - } - - const metadata = await getTransactionMetadataByHash(txHash); - if (!metadata || metadata.bundle_ids.length === 0) { - return { bundleId: null, meterBundleResponse: null }; - } - - const bundleId = metadata.bundle_ids[0]; - const bundleHistory = await getBundleHistory(bundleId); - if (!bundleHistory) { - return { bundleId, meterBundleResponse: null }; - } - - const receivedEvent = bundleHistory.history.find( - (e) => e.event === "Received", + const events = await getAuditEventsByTransactionHash(txHash); + const metadata = transactionMetadataFromAuditEvents(events); + const accepted = events.find( + (event) => event.event_type === "SIMULATION_SUCCEEDED", ); - if (!receivedEvent?.data?.bundle?.meter_bundle_response) { - return { bundleId, meterBundleResponse: null }; - } - return { - bundleId, - meterBundleResponse: receivedEvent.data.bundle - .meter_bundle_response as unknown as Record, + bundleId: metadata?.bundle_ids[0] ?? null, + meterBundleResponse: accepted + ? (meterBundleResponseFromAuditEvent(accepted) as unknown as Record< + string, + unknown + >) + : null, }; } @@ -134,7 +100,6 @@ async function buildAndCacheBlockData( rpcBlock: Block, hash: Hash, number: bigint, - shouldCache = true, ): Promise { const transactions: BlockTransaction[] = await Promise.all( rpcBlock.transactions.map(async (tx, index) => { @@ -161,69 +126,15 @@ async function buildAndCacheBlockData( cachedAt: Date.now(), }; - if (shouldCache) { - await cacheBlockData(blockData); - } - return blockData; } -// On OP Stack, the first transaction (index 0) is the L1 attributes deposit transaction. -// This is not a perfect check (ideally we'd check tx.type === 'deposit' or type 0x7e), -// but sufficient for filtering out system transactions that don't need simulation data. -function isSystemTransaction(tx: BlockTransaction): boolean { - return tx.index === 0; -} - -async function refetchMissingTransactionSimulations( - block: BlockData, -): Promise<{ updatedBlock: BlockData; hasUpdates: boolean }> { - const transactionsToRefetch = block.transactions.filter( - (tx) => tx.bundleId === null && !isSystemTransaction(tx), - ); - - if (transactionsToRefetch.length === 0) { - return { updatedBlock: block, hasUpdates: false }; - } - - const refetchResults = await Promise.all( - transactionsToRefetch.map(async (tx) => { - const enriched = await enrichTransactionWithBundleData(tx.hash); - return { hash: tx.hash, ...enriched }; - }), - ); - - let hasUpdates = false; - const updatedTransactions = block.transactions.map((tx) => { - const refetchResult = refetchResults.find((r) => r.hash === tx.hash); - if (refetchResult && refetchResult.bundleId !== null) { - hasUpdates = true; - return { - ...tx, - bundleId: refetchResult.bundleId, - meterBundleResponse: refetchResult.meterBundleResponse, - }; - } - return tx; - }); - - return { - updatedBlock: { - ...block, - transactions: updatedTransactions, - cachedAt: hasUpdates ? Date.now() : block.cachedAt, - }, - hasUpdates, - }; -} - export async function GET( _request: NextRequest, { params }: { params: Promise<{ hash: string }> }, ) { try { const { hash: identifier } = await params; - const auditBackend = isAuditEventBackend(); // If the identifier is a block number, resolve it to a hash first if (isBlockNumber(identifier)) { @@ -232,42 +143,14 @@ export async function GET( return NextResponse.json({ error: "Block not found" }, { status: 404 }); } - // Check cache by resolved hash - const cachedBlock = auditBackend - ? null - : await getBlockFromCache(rpcBlock.hash); - if (cachedBlock) { - const { updatedBlock, hasUpdates } = - await refetchMissingTransactionSimulations(cachedBlock); - if (hasUpdates) { - await cacheBlockData(updatedBlock); - } - return NextResponse.json(serializeBlockData(updatedBlock)); - } - const blockData = await buildAndCacheBlockData( rpcBlock, rpcBlock.hash, rpcBlock.number, - !auditBackend, ); return NextResponse.json(serializeBlockData(blockData)); } - const cachedBlock = auditBackend - ? null - : await getBlockFromCache(identifier); - if (cachedBlock) { - const { updatedBlock, hasUpdates } = - await refetchMissingTransactionSimulations(cachedBlock); - - if (hasUpdates) { - await cacheBlockData(updatedBlock); - } - - return NextResponse.json(serializeBlockData(updatedBlock)); - } - const rpcBlock = await fetchBlockFromRpc(identifier); if (!rpcBlock || !rpcBlock.hash || !rpcBlock.number) { return NextResponse.json({ error: "Block not found" }, { status: 404 }); @@ -277,7 +160,6 @@ export async function GET( rpcBlock, rpcBlock.hash, rpcBlock.number, - !auditBackend, ); return NextResponse.json(serializeBlockData(blockData)); } catch (error) { diff --git a/src/app/api/bundle/[hash]/route.ts b/src/app/api/bundle/[hash]/route.ts index 5857a7ad..6e7886c4 100644 --- a/src/app/api/bundle/[hash]/route.ts +++ b/src/app/api/bundle/[hash]/route.ts @@ -2,9 +2,8 @@ import { type NextRequest, NextResponse } from "next/server"; import { bundleHistoryFromAuditEvents, getAuditEventsByBundle, - isAuditEventBackend, } from "@/lib/audit-events"; -import { type BundleEvent, getBundleHistory } from "@/lib/s3"; +import type { BundleEvent } from "@/lib/transaction-data"; export interface BundleHistoryResponse { hash: string; @@ -18,9 +17,10 @@ export async function GET( try { const { hash } = await params; - const bundle = isAuditEventBackend() - ? bundleHistoryFromAuditEvents(hash, await getAuditEventsByBundle(hash)) - : await getBundleHistory(hash); + const bundle = bundleHistoryFromAuditEvents( + hash, + await getAuditEventsByBundle(hash), + ); if (!bundle) { return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); } diff --git a/src/app/api/rejected/route.ts b/src/app/api/rejected/route.ts index ba79bb87..11c4381f 100644 --- a/src/app/api/rejected/route.ts +++ b/src/app/api/rejected/route.ts @@ -1,14 +1,9 @@ import { NextResponse } from "next/server"; import { getAuditRejectedTransactionEvents, - isAuditEventBackend, rejectedTransactionFromAuditEvent, } from "@/lib/audit-events"; -import { - getRejectedTransaction, - listRejectedTransactions, - type RejectedTransaction, -} from "@/lib/s3"; +import type { RejectedTransaction } from "@/lib/transaction-data"; export interface RejectedTransactionsResponse { transactions: RejectedTransaction[]; @@ -16,21 +11,9 @@ export interface RejectedTransactionsResponse { export async function GET() { try { - if (isAuditEventBackend()) { - const transactions = (await getAuditRejectedTransactionEvents(100)) - .map(rejectedTransactionFromAuditEvent) - .filter((tx): tx is RejectedTransaction => tx !== null); - - return NextResponse.json({ transactions }); - } - - const summaries = await listRejectedTransactions(100); - - const transactions = ( - await Promise.all( - summaries.map((s) => getRejectedTransaction(s.blockNumber, s.txHash)), - ) - ).filter((tx): tx is RejectedTransaction => tx !== null); + const transactions = (await getAuditRejectedTransactionEvents(100)) + .map(rejectedTransactionFromAuditEvent) + .filter((tx): tx is RejectedTransaction => tx !== null); const response: RejectedTransactionsResponse = { transactions }; return NextResponse.json(response); diff --git a/src/app/api/txn/[hash]/route.ts b/src/app/api/txn/[hash]/route.ts index 67326c56..8d0446a4 100644 --- a/src/app/api/txn/[hash]/route.ts +++ b/src/app/api/txn/[hash]/route.ts @@ -3,14 +3,9 @@ import { bundleHistoryFromAuditEvents, getAuditEventsByBundle, getAuditEventsByTransactionHash, - isAuditEventBackend, transactionMetadataFromAuditEvents, } from "@/lib/audit-events"; -import { - type BundleEvent, - getBundleHistory, - getTransactionMetadataByHash, -} from "@/lib/s3"; +import type { BundleEvent } from "@/lib/transaction-data"; export interface TransactionEvent { type: string; @@ -48,36 +43,8 @@ export async function GET( try { const { hash } = await params; - if (isAuditEventBackend()) { - const events = await getAuditEventsByTransactionHash(hash); - const metadata = transactionMetadataFromAuditEvents(events); - if (!metadata) { - return NextResponse.json( - { error: "Transaction not found" }, - { status: 404 }, - ); - } - - const bundleId = metadata.bundle_ids[0]; - const bundle = - bundleId !== undefined - ? bundleHistoryFromAuditEvents( - bundleId, - await getAuditEventsByBundle(bundleId), - ) - : { history: [] }; - - const response: TransactionHistoryResponse = { - hash, - bundle_ids: metadata.bundle_ids, - history: bundle?.history ?? [], - }; - - return NextResponse.json(response); - } - - const metadata = await getTransactionMetadataByHash(hash); - + const events = await getAuditEventsByTransactionHash(hash); + const metadata = transactionMetadataFromAuditEvents(events); if (!metadata) { return NextResponse.json( { error: "Transaction not found" }, @@ -85,16 +52,19 @@ export async function GET( ); } - // TODO: Can be in multiple bundles - const bundle = await getBundleHistory(metadata.bundle_ids[0]); - if (!bundle) { - return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); - } + const bundleId = metadata.bundle_ids[0]; + const bundle = + bundleId !== undefined + ? bundleHistoryFromAuditEvents( + bundleId, + await getAuditEventsByBundle(bundleId), + ) + : { history: [] }; const response: TransactionHistoryResponse = { hash, bundle_ids: metadata.bundle_ids, - history: bundle.history, + history: bundle?.history ?? [], }; return NextResponse.json(response); diff --git a/src/app/block/[hash]/page.tsx b/src/app/block/[hash]/page.tsx index c5d0a4a0..caecb721 100644 --- a/src/app/block/[hash]/page.tsx +++ b/src/app/block/[hash]/page.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { useEffect, useState } from "react"; -import type { BlockData, BlockTransaction } from "@/lib/s3"; +import type { BlockData, BlockTransaction } from "@/lib/transaction-data"; const BLOCK_EXPLORER_URL = process.env.NEXT_PUBLIC_BLOCK_EXPLORER_URL; diff --git a/src/app/bundles/[hash]/page.tsx b/src/app/bundles/[hash]/page.tsx index 9ea8602a..370b6e94 100644 --- a/src/app/bundles/[hash]/page.tsx +++ b/src/app/bundles/[hash]/page.tsx @@ -3,7 +3,10 @@ import Link from "next/link"; import { useEffect, useState } from "react"; import type { BundleHistoryResponse } from "@/app/api/bundle/[hash]/route"; -import type { BundleTransaction, MeterBundleResponse } from "@/lib/s3"; +import type { + BundleTransaction, + MeterBundleResponse, +} from "@/lib/transaction-data"; const WEI_PER_GWEI = 10n ** 9n; const WEI_PER_ETH = 10n ** 18n; diff --git a/src/app/page.tsx b/src/app/page.tsx index 1b031193..29b9c61e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,7 +7,7 @@ import { formatRejectionReason, type MeterBundleResponse, type RejectedTransaction, -} from "@/lib/s3"; +} from "@/lib/transaction-data"; import type { BlockSummary, BlocksResponse } from "./api/blocks/route"; import type { RejectedTransactionsResponse } from "./api/rejected/route"; diff --git a/src/lib/audit-events.test.ts b/src/lib/audit-events.test.ts index 46e02b94..36d30e93 100644 --- a/src/lib/audit-events.test.ts +++ b/src/lib/audit-events.test.ts @@ -3,7 +3,6 @@ import { describe, test } from "node:test"; import { type AuditTransactionEventRecord, bundleHistoryFromAuditEvents, - isAuditEventBackend, rejectedTransactionFromAuditEvent, transactionMetadataFromAuditEvents, } from "./audit-events"; @@ -14,39 +13,33 @@ const acceptedEvent: AuditTransactionEventRecord = { event_time: "2026-06-02T00:00:00Z", ingested_at: "2026-06-02T00:00:01Z", producer: "ingress-rpc", - event_type: "SIMULATION_ACCEPTED", + event_type: "SIMULATION_SUCCEEDED", tx_hash: "0xabc", block_number: null, data: { bundle_hash: "0xbundle", bundle_id: "bundle-id", - state_block_number: 123, - total_gas_used: 21000, - total_execution_time_us: "500", - state_root_time_us: "50", - results: [ - { - txHash: "0xabc", - fromAddress: "0xsender", - toAddress: "0xto", - gasUsed: 21000, - executionTimeUs: "500", - }, - ], + meter_bundle_response: { + bundleHash: "0xbundle", + stateBlockNumber: 123, + totalGasUsed: 21000, + totalExecutionTimeUs: "500", + stateRootTimeUs: "50", + results: [ + { + txHash: "0xabc", + fromAddress: "0xsender", + toAddress: "0xto", + gasUsed: 21000, + executionTimeUs: "500", + }, + ], + }, }, }; describe("audit event route adapters", () => { - test("old mode remains the default unless the audit backend flag is set", () => { - delete process.env.TIPS_UI_QUERY_BACKEND; - assert.equal(isAuditEventBackend(), false); - - process.env.TIPS_UI_QUERY_BACKEND = "audit"; - assert.equal(isAuditEventBackend(), true); - delete process.env.TIPS_UI_QUERY_BACKEND; - }); - - test("new mode adapts audit bundle events to the existing bundle route shape", () => { + test("adapts audit bundle events to the existing bundle route shape", () => { const history = bundleHistoryFromAuditEvents("0xbundle", [acceptedEvent]); assert.equal(history?.history.length, 1); @@ -58,13 +51,13 @@ describe("audit event route adapters", () => { ); }); - test("new mode derives transaction metadata from audit join fields", () => { + test("derives transaction metadata from audit join fields", () => { const metadata = transactionMetadataFromAuditEvents([acceptedEvent]); assert.deepEqual(metadata?.bundle_ids, ["bundle-id"]); }); - test("new mode adapts rejected audit events to the existing rejected route shape", () => { + test("adapts rejected audit events to the existing rejected route shape", () => { const rejected = rejectedTransactionFromAuditEvent({ ...acceptedEvent, event_id: "event-2", diff --git a/src/lib/audit-events.ts b/src/lib/audit-events.ts index 16fec749..25dd887d 100644 --- a/src/lib/audit-events.ts +++ b/src/lib/audit-events.ts @@ -5,15 +5,11 @@ import type { RejectedTransaction, RejectionReason, TransactionMetadata, -} from "@/lib/s3"; +} from "@/lib/transaction-data"; const AUDIT_RPC_URL = process.env.TIPS_UI_AUDIT_RPC_URL || "http://localhost:8080"; -export function isAuditEventBackend(): boolean { - return process.env.TIPS_UI_QUERY_BACKEND === "audit"; -} - export interface AuditTransactionEventRecord { schema_version: string; event_id: string; @@ -141,7 +137,7 @@ export function meterBundleResponseFromAuditEvent( event: AuditTransactionEventRecord, ): MeterBundleResponse | null { if ( - event.event_type !== "SIMULATION_ACCEPTED" && + event.event_type !== "SIMULATION_SUCCEEDED" && event.event_type !== "BUILDER_REJECTED" ) { return null; @@ -153,7 +149,7 @@ export function rejectedTransactionFromAuditEvent( event: AuditTransactionEventRecord, ): RejectedTransaction | null { if ( - event.event_type !== "SIMULATION_REJECTED" && + event.event_type !== "SIMULATION_FAILED" && event.event_type !== "BUILDER_REJECTED" ) { return null; @@ -177,7 +173,7 @@ function bundleEventFromAuditEvent( event: AuditTransactionEventRecord, ): BundleEvent { const timestamp = Date.parse(event.event_time); - if (event.event_type === "SIMULATION_ACCEPTED") { + if (event.event_type === "SIMULATION_SUCCEEDED") { return { event: "Received", data: { @@ -216,13 +212,15 @@ function bundleEventFromAuditEvent( function meterBundleResponseFromData( data: Record, ): MeterBundleResponse { + const metering = recordField(data.meter_bundle_response) ?? data; return { bundleGasPrice: "0", - bundleHash: stringField(data.bundle_hash) ?? "", + bundleHash: + stringField(metering.bundleHash) ?? stringField(data.bundle_hash) ?? "", coinbaseDiff: "0", ethSentToCoinbase: "0", gasFees: "0", - results: arrayField(data.results).map((result) => ({ + results: arrayField(metering.results).map((result) => ({ coinbaseDiff: "0", ethSentToCoinbase: "0", fromAddress: stringField(result.fromAddress) ?? "", @@ -234,29 +232,34 @@ function meterBundleResponseFromData( value: "0", executionTimeUs: numberField(result.executionTimeUs) ?? 0, })), - stateBlockNumber: numberField(data.state_block_number) ?? 0, - totalGasUsed: numberField(data.total_gas_used) ?? 0, - totalExecutionTimeUs: numberField(data.total_execution_time_us) ?? 0, - stateRootTimeUs: numberField(data.state_root_time_us) ?? 0, + stateBlockNumber: numberField(metering.stateBlockNumber) ?? 0, + totalGasUsed: numberField(metering.totalGasUsed) ?? 0, + totalExecutionTimeUs: numberField(metering.totalExecutionTimeUs) ?? 0, + stateRootTimeUs: numberField(metering.stateRootTimeUs) ?? 0, stateRootAccountLeafCount: - numberField(data.state_root_account_leaf_count) ?? 0, + numberField(metering.stateRootAccountLeafCount) ?? 0, stateRootAccountBranchCount: - numberField(data.state_root_account_branch_count) ?? 0, + numberField(metering.stateRootAccountBranchCount) ?? 0, stateRootStorageLeafCount: - numberField(data.state_root_storage_leaf_count) ?? 0, + numberField(metering.stateRootStorageLeafCount) ?? 0, stateRootStorageBranchCount: - numberField(data.state_root_storage_branch_count) ?? 0, + numberField(metering.stateRootStorageBranchCount) ?? 0, }; } function rejectionReasonFromData( data: Record, -): RejectionReason { +): RejectionReason | string { const reason = data.reason; if (isRecord(reason)) { return reason as RejectionReason; } + const rejectionReason = stringField(data.rejection_reason); + if (rejectionReason !== null) { + return rejectionReason; + } + return {}; } @@ -277,6 +280,10 @@ function arrayField(value: unknown): Record[] { return Array.isArray(value) ? value.filter(isRecord) : []; } +function recordField(value: unknown): Record | null { + return isRecord(value) ? value : null; +} + function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } diff --git a/src/lib/s3.ts b/src/lib/s3.ts deleted file mode 100644 index 6e11aa1b..00000000 --- a/src/lib/s3.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { - GetObjectCommand, - ListObjectsV2Command, - PutObjectCommand, - S3Client, - type S3ClientConfig, -} from "@aws-sdk/client-s3"; - -function createS3Client(): S3Client { - const configType = process.env.TIPS_UI_S3_CONFIG_TYPE || "aws"; - const region = process.env.TIPS_UI_AWS_REGION || "us-east-1"; - - if (configType === "manual") { - console.log("Using Manual S3 configuration"); - const config: S3ClientConfig = { - region, - forcePathStyle: true, - }; - - if (process.env.TIPS_UI_S3_ENDPOINT) { - config.endpoint = process.env.TIPS_UI_S3_ENDPOINT; - } - - if ( - process.env.TIPS_UI_S3_ACCESS_KEY_ID && - process.env.TIPS_UI_S3_SECRET_ACCESS_KEY - ) { - config.credentials = { - accessKeyId: process.env.TIPS_UI_S3_ACCESS_KEY_ID, - secretAccessKey: process.env.TIPS_UI_S3_SECRET_ACCESS_KEY, - }; - } - - return new S3Client(config); - } - - console.log("Using AWS S3 configuration"); - return new S3Client({ - region, - }); -} - -const s3Client = createS3Client(); - -const BUCKET_NAME = process.env.TIPS_UI_S3_BUCKET_NAME || "tips"; - -export interface TransactionMetadata { - bundle_ids: string[]; - sender: string; - nonce: string; -} - -async function getObjectContent(key: string): Promise { - try { - const command = new GetObjectCommand({ - Bucket: BUCKET_NAME, - Key: key, - }); - - const response = await s3Client.send(command); - const body = await response.Body?.transformToString(); - return body || null; - } catch (_error) { - return null; - } -} - -export async function getTransactionMetadataByHash( - hash: string, -): Promise { - const key = `transactions/by_hash/${hash}`; - const content = await getObjectContent(key); - - if (!content) { - return null; - } - - try { - return JSON.parse(content) as TransactionMetadata; - } catch (error) { - console.error( - `Failed to parse transaction metadata for hash ${hash}:`, - error, - ); - return null; - } -} - -export interface BundleTransaction { - signer: string; - type: string; - chainId: string; - nonce: string; - gas: string; - maxFeePerGas: string; - maxPriorityFeePerGas: string; - to: string | null; - value: string; - accessList: unknown[]; - input: string; - r: string; - s: string; - yParity: string; - v: string; - hash: string; -} - -export interface MeterBundleResult { - coinbaseDiff: string; - ethSentToCoinbase: string; - fromAddress: string; - gasFees: string; - gasPrice: string; - gasUsed: number; - toAddress: string; - txHash: string; - value: string; - executionTimeUs: number; -} - -export interface MeterBundleResponse { - bundleGasPrice: string; - bundleHash: string; - coinbaseDiff: string; - ethSentToCoinbase: string; - gasFees: string; - results: MeterBundleResult[]; - stateBlockNumber: number; - totalGasUsed: number; - totalExecutionTimeUs: number; - stateRootTimeUs: number; - stateRootAccountLeafCount: number; - stateRootAccountBranchCount: number; - stateRootStorageLeafCount: number; - stateRootStorageBranchCount: number; -} - -export interface BundleData { - uuid: string; - txs: BundleTransaction[]; - block_number: string; - max_timestamp: number; - reverting_tx_hashes: string[]; - meter_bundle_response: MeterBundleResponse; -} - -export interface BundleEventData { - key: string; - timestamp: number; - bundle?: BundleData; - block_number?: number; - block_hash?: string; - builder?: string; - flashblock_index?: number; - reason?: string; -} - -export interface BundleEvent { - event: string; - data: BundleEventData; -} - -export interface BundleHistory { - history: BundleEvent[]; -} - -export async function getBundleHistory( - bundleKey: string, -): Promise { - const prefix = `bundles/${bundleKey}/`; - const listCommand = new ListObjectsV2Command({ - Bucket: BUCKET_NAME, - Prefix: prefix, - }); - - const listResponse = await s3Client.send(listCommand); - const keys = listResponse.Contents?.map((obj) => obj.Key).filter( - Boolean, - ) as string[]; - - if (!keys || keys.length === 0) { - return null; - } - - const history: BundleEvent[] = []; - for (const key of keys) { - const content = await getObjectContent(key); - if (content) { - try { - history.push(JSON.parse(content) as BundleEvent); - } catch (error) { - console.error(`Failed to parse event at ${key}:`, error); - } - } - } - - return { history }; -} - -export interface BlockTransaction { - hash: string; - from: string; - to: string | null; - gasLimit: bigint; - bundleId: string | null; - index: number; - meterBundleResponse: Record | null; -} - -export interface BlockData { - hash: string; - number: bigint; - timestamp: bigint; - transactions: BlockTransaction[]; - gasUsed: bigint; - gasLimit: bigint; - cachedAt: number; -} - -export async function getBlockFromCache( - blockHash: string, -): Promise { - const key = `blocks/${blockHash}`; - const content = await getObjectContent(key); - - if (!content) { - return null; - } - - try { - const parsed = JSON.parse(content); - return { - ...parsed, - number: BigInt(parsed.number), - timestamp: BigInt(parsed.timestamp), - gasUsed: BigInt(parsed.gasUsed), - gasLimit: BigInt(parsed.gasLimit), - transactions: parsed.transactions.map( - (tx: { gasLimit?: string; [key: string]: unknown }) => ({ - ...tx, - gasLimit: BigInt(tx.gasLimit ?? "0"), - meterBundleResponse: tx.meterBundleResponse ?? null, - }), - ), - } as BlockData; - } catch (error) { - console.error(`Failed to parse block data for hash ${blockHash}:`, error); - return null; - } -} - -export interface RejectionReason { - executionTimeExceeded?: { - tx_time_us: number; - limit_us: number; - }; -} - -export interface RejectedTransaction { - blockNumber: number; - txHash: string; - reason: RejectionReason; - timestamp: number; - metering: MeterBundleResponse; -} - -export function formatRejectionReason( - reason: RejectionReason | string, -): string { - if (typeof reason === "string") return reason; - if (reason?.executionTimeExceeded) { - const { tx_time_us, limit_us } = reason.executionTimeExceeded; - return `Execution time exceeded: ${tx_time_us.toLocaleString()}μs > ${limit_us.toLocaleString()}μs limit`; - } - return "Unknown reason"; -} - -export interface RejectedTransactionSummary { - blockNumber: number; - txHash: string; -} - -export async function listRejectedTransactions( - limit = 100, -): Promise { - try { - const command = new ListObjectsV2Command({ - Bucket: BUCKET_NAME, - Prefix: "rejected/", - MaxKeys: limit, - }); - - const response = await s3Client.send(command); - const contents = response.Contents || []; - - const summaries: RejectedTransactionSummary[] = []; - for (const obj of contents) { - if (!obj.Key) continue; - // S3 key format matches Rust S3Key::Rejected: rejected/{block_number}/{tx_hash} - const parts = obj.Key.split("/"); - if (parts.length !== 3) continue; - const blockNumber = parseInt(parts[1], 10); - const txHash = parts[2]; - if (Number.isNaN(blockNumber) || !txHash) continue; - summaries.push({ blockNumber, txHash }); - } - - summaries.sort((a, b) => b.blockNumber - a.blockNumber); - return summaries; - } catch (error) { - console.error("Failed to list rejected transactions:", error); - return []; - } -} - -export async function getRejectedTransaction( - blockNumber: number, - txHash: string, -): Promise { - const key = `rejected/${blockNumber}/${txHash}`; - const content = await getObjectContent(key); - - if (!content) { - return null; - } - - try { - return JSON.parse(content) as RejectedTransaction; - } catch (error) { - console.error( - `Failed to parse rejected transaction ${blockNumber}/${txHash}:`, - error, - ); - return null; - } -} - -export async function cacheBlockData(blockData: BlockData): Promise { - const key = `blocks/${blockData.hash}`; - - try { - const command = new PutObjectCommand({ - Bucket: BUCKET_NAME, - Key: key, - Body: JSON.stringify(blockData, (_, value) => - typeof value === "bigint" ? value.toString() : value, - ), - ContentType: "application/json", - }); - - await s3Client.send(command); - } catch (error) { - console.error(`Failed to cache block data for ${blockData.hash}:`, error); - } -} diff --git a/src/lib/transaction-data.ts b/src/lib/transaction-data.ts new file mode 100644 index 00000000..ff4297ba --- /dev/null +++ b/src/lib/transaction-data.ts @@ -0,0 +1,129 @@ +export interface TransactionMetadata { + bundle_ids: string[]; + sender: string; + nonce: string; +} + +export interface BundleTransaction { + signer: string; + type: string; + chainId: string; + nonce: string; + gas: string; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + to: string | null; + value: string; + accessList: unknown[]; + input: string; + r: string; + s: string; + yParity: string; + v: string; + hash: string; +} + +export interface MeterBundleResult { + coinbaseDiff: string; + ethSentToCoinbase: string; + fromAddress: string; + gasFees: string; + gasPrice: string; + gasUsed: number; + toAddress: string; + txHash: string; + value: string; + executionTimeUs: number; +} + +export interface MeterBundleResponse { + bundleGasPrice: string; + bundleHash: string; + coinbaseDiff: string; + ethSentToCoinbase: string; + gasFees: string; + results: MeterBundleResult[]; + stateBlockNumber: number; + totalGasUsed: number; + totalExecutionTimeUs: number; + stateRootTimeUs: number; + stateRootAccountLeafCount: number; + stateRootAccountBranchCount: number; + stateRootStorageLeafCount: number; + stateRootStorageBranchCount: number; +} + +export interface BundleData { + uuid: string; + txs: BundleTransaction[]; + block_number: string; + max_timestamp: number; + reverting_tx_hashes: string[]; + meter_bundle_response: MeterBundleResponse; +} + +export interface BundleEventData { + key: string; + timestamp: number; + bundle?: BundleData; + block_number?: number; + block_hash?: string; + builder?: string; + flashblock_index?: number; + reason?: string; +} + +export interface BundleEvent { + event: string; + data: BundleEventData; +} + +export interface BundleHistory { + history: BundleEvent[]; +} + +export interface BlockTransaction { + hash: string; + from: string; + to: string | null; + gasLimit: bigint; + bundleId: string | null; + index: number; + meterBundleResponse: Record | null; +} + +export interface BlockData { + hash: string; + number: bigint; + timestamp: bigint; + transactions: BlockTransaction[]; + gasUsed: bigint; + gasLimit: bigint; + cachedAt: number; +} + +export interface RejectionReason { + executionTimeExceeded?: { + tx_time_us: number; + limit_us: number; + }; +} + +export interface RejectedTransaction { + blockNumber: number; + txHash: string; + reason: RejectionReason | string; + timestamp: number; + metering: MeterBundleResponse; +} + +export function formatRejectionReason( + reason: RejectionReason | string, +): string { + if (typeof reason === "string") return reason; + if (reason?.executionTimeExceeded) { + const { tx_time_us, limit_us } = reason.executionTimeExceeded; + return `Execution time exceeded: ${tx_time_us.toLocaleString()}μs > ${limit_us.toLocaleString()}μs limit`; + } + return "Unknown reason"; +} From f4eded460979fe73a7ee174e6e9c92bf2a455615 Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Wed, 17 Jun 2026 22:57:53 -0500 Subject: [PATCH 3/4] Polish audit event history UI --- bun.lock | 89 +++++++++++++ next.config.ts | 4 + package.json | 1 + src/app/api/block/[hash]/route.ts | 22 ++++ src/app/api/bundle/[hash]/route.ts | 96 ++++++++++++-- src/app/api/rejected/route.ts | 33 ++++- src/app/api/txn/[hash]/route.ts | 60 +++++++-- src/app/block/[hash]/page.tsx | 39 ++++++ src/app/bundles/[hash]/page.tsx | 89 ++----------- src/app/event-history-row.tsx | 204 +++++++++++++++++++++++++++++ src/lib/audit-events.test.ts | 109 ++++++++++++++- src/lib/audit-events.ts | 197 ++++++++++++++++++++++++++-- src/lib/s3.ts | 191 +++++++++++++++++++++++++++ src/lib/transaction-data.ts | 4 + 14 files changed, 1023 insertions(+), 115 deletions(-) create mode 100644 src/app/event-history-row.tsx create mode 100644 src/lib/s3.ts diff --git a/bun.lock b/bun.lock index 9d851eca..67e1d573 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "ui", "dependencies": { + "@aws-sdk/client-s3": "^3.1071.0", "next": "16.0.7", "react": "19.2.1", "react-dom": "19.2.1", @@ -26,6 +27,60 @@ "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "https://registry-npm.cbhq.net/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/crc32/-/crc32-5.2.0.tgz", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], + + "@aws-crypto/crc32c": ["@aws-crypto/crc32c@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag=="], + + "@aws-crypto/sha1-browser": ["@aws-crypto/sha1-browser@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", { "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg=="], + + "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], + + "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], + + "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="], + + "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "https://registry-npm.cbhq.net/@aws-crypto/util/-/util-5.2.0.tgz", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + + "@aws-sdk/checksums": ["@aws-sdk/checksums@3.1000.7", "https://registry-npm.cbhq.net/@aws-sdk/checksums/-/checksums-3.1000.7.tgz", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "^3.974.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-qh0fG/RtrFztst4+vn1HZehAvAhr5Jlq/WMP7e5KvvfF16oNVBc9CDNVdxdm19vzOY2x0qiDMFCRjhxQAusGWQ=="], + + "@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.1071.0", "https://registry-npm.cbhq.net/@aws-sdk/client-s3/-/client-s3-3.1071.0.tgz", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.22", "@aws-sdk/credential-provider-node": "^3.972.57", "@aws-sdk/middleware-flexible-checksums": "^3.974.32", "@aws-sdk/middleware-sdk-s3": "^3.972.53", "@aws-sdk/signature-v4-multi-region": "^3.996.35", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-BqsqkaU/FztbQnq5Aw0BK6/weQgwnC3n2w19M7CjEjRHscr5dZU8+ihi7PIY6UMW9RkJrzUUEmaoHQrIVScFYQ=="], + + "@aws-sdk/core": ["@aws-sdk/core@3.974.22", "https://registry-npm.cbhq.net/@aws-sdk/core/-/core-3.974.22.tgz", { "dependencies": { "@aws-sdk/types": "^3.973.13", "@aws-sdk/xml-builder": "^3.972.30", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.6", "@smithy/signature-v4": "^5.4.6", "@smithy/types": "^4.14.3", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-YofH63shc6YRdXjz80BJkpJW+Bkn0Cuu2dn4Rv7s9G2Idt58tgtzQEWxrR2xVljlVfIBeUjPuULnSVYLke3sUQ=="], + + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.48", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.48.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-h6FEC95fbexUd6zxm4PdgS82bTcI2PRtUb2ZwMipb/Xr8bPwtf0G8rBo2jp7NA24Mbx2JA8/WingiYpA9RCCyw=="], + + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.50", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.50.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-lJO3OLpjvz5m/RSBQmsG/CEUGsvCy5ruxKwPQaOCqxqCMuyYT2BZwQUTDZVVwqQ9LrZKuK24JSa6r31hL/tvkg=="], + + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.55", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.55.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/credential-provider-env": "^3.972.48", "@aws-sdk/credential-provider-http": "^3.972.50", "@aws-sdk/credential-provider-login": "^3.972.54", "@aws-sdk/credential-provider-process": "^3.972.48", "@aws-sdk/credential-provider-sso": "^3.972.54", "@aws-sdk/credential-provider-web-identity": "^3.972.54", "@aws-sdk/nested-clients": "^3.997.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-TBoF4buBGYhXjdZAryayY2TrkQj2B2KfE/msG4V53XCt+w0EhEwM2JRjx8p2grJ2C6gtH5++SAwEvGMRdi0yyw=="], + + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.54", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.54.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/nested-clients": "^3.997.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-hBWI3wZTdTGiuMfmPts6AWbAjFfRniOQnqx68tc2cQvRKWawFbN9wkLOVPWM1FAOyowZU73mC6Fi+rHSHNyLFw=="], + + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.57", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.57.tgz", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.48", "@aws-sdk/credential-provider-http": "^3.972.50", "@aws-sdk/credential-provider-ini": "^3.972.55", "@aws-sdk/credential-provider-process": "^3.972.48", "@aws-sdk/credential-provider-sso": "^3.972.54", "@aws-sdk/credential-provider-web-identity": "^3.972.54", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-u6dClpzNdWf1HGWz4wwhdXi1wiOofCLniM9S4BQQGlLAN9TW7VB+ld5V533GdKrYMaFeBGFqKnj0JCYvynLqwQ=="], + + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.48", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.48.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-w6VZwojPt12WnEkAUy6Nu4K6sWCbBmR7QX390b0nE6vRvkXbrYr9Lq9VySGkfjiMjpUA87op+J4EgvRmtWIDoQ=="], + + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.54", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.54.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/nested-clients": "^3.997.22", "@aws-sdk/token-providers": "3.1071.0", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-23uZpIpF2SIFDCa1fcWa202tK4gGeyvX6GIIAjiB8WBsvsVRBMnJ/7dCxHzxf7eZT7GToJg837LDIBnZsl/VUg=="], + + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.54", "https://registry-npm.cbhq.net/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.54.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/nested-clients": "^3.997.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-0Iv5QttS6wcATlodYKgvQj6B9Db51rx7NU9fqu0PoLeS4BIgdYMc/QK4smwLwpm5RFrs02V/eLyEFp3FklvlNQ=="], + + "@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.974.32", "https://registry-npm.cbhq.net/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.32.tgz", { "dependencies": { "@aws-sdk/checksums": "^3.1000.7", "tslib": "^2.6.2" } }, "sha512-KhuzFMzUbb3oEj43CdPDbEJ/RG/RkErkmXk3J/LE8OPFNvkCn8PYPMpjOLgzAzvxBacsSyytdWf+R50q0alJ4w=="], + + "@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.53", "https://registry-npm.cbhq.net/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.53.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/signature-v4-multi-region": "^3.996.35", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-keWp6Z5cEIJzPwoCf/WRm0ceAeephPDDivhRsK/xXs2ZYXyypJ2/DL9G1IR0bz/s+iZC0EgzmFV4r7rlvLlxQQ=="], + + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.22", "https://registry-npm.cbhq.net/@aws-sdk/nested-clients/-/nested-clients-3.997.22.tgz", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.22", "@aws-sdk/signature-v4-multi-region": "^3.996.35", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-4IwtcYSxEIVw5hcp8ogq0CMbFNZFw7jJUetpfFUhFFeqsa1K8j2Ihg2hnxLyOp3stMZnXda6VzOmPi1AFZQXcg=="], + + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.35", "https://registry-npm.cbhq.net/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.35.tgz", { "dependencies": { "@aws-sdk/types": "^3.973.13", "@smithy/signature-v4": "^5.4.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-6L/VWs+Wch2stHemCGTmUNqKLMzURxQDK5boNG3Jn3kAOp71meDUuS5sbObpEvFxHDq0uWeSLFDNSYsjNt+Dlg=="], + + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1071.0", "https://registry-npm.cbhq.net/@aws-sdk/token-providers/-/token-providers-3.1071.0.tgz", { "dependencies": { "@aws-sdk/core": "^3.974.22", "@aws-sdk/nested-clients": "^3.997.22", "@aws-sdk/types": "^3.973.13", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-4LDW2Qob6LoLFuqYSYZq2AyTE9koSE9+i+n5UZcm10GpmQOK0zRD9L4uYlzItiTKksIWgC/qMFChAi3RvKYtMg=="], + + "@aws-sdk/types": ["@aws-sdk/types@3.973.13", "https://registry-npm.cbhq.net/@aws-sdk/types/-/types-3.973.13.tgz", { "dependencies": { "@smithy/types": "^4.14.3", "tslib": "^2.6.2" } }, "sha512-pEHZqRkAlHfnfAU9tK+WpKv/gBNjGJrHMgA3A0iYRGyswBS2t0pfez+lWlwktb3Bqa0ovh7w/QJTFwp3fDxLNg=="], + + "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.8", "https://registry-npm.cbhq.net/@aws-sdk/util-locate-window/-/util-locate-window-3.965.8.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g=="], + + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.30", "https://registry-npm.cbhq.net/@aws-sdk/xml-builder/-/xml-builder-3.972.30.tgz", { "dependencies": { "@smithy/types": "^4.14.3", "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" } }, "sha512-StElZPEoBquWwNqw1AcfpzEyZqJvFxouG+mpDNYlcH6ZOrqd2CuIryv+8LV8gNHZUOyKyJF3Dq9vxaXEmDR9TQ=="], + + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "https://registry-npm.cbhq.net/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], + "@biomejs/biome": ["@biomejs/biome@2.3.8", "https://registry-npm.cbhq.net/@biomejs/biome/-/biome-2.3.8.tgz", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="], "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.8", "https://registry-npm.cbhq.net/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.8.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww=="], @@ -130,12 +185,32 @@ "@noble/hashes": ["@noble/hashes@1.8.0", "https://registry-npm.cbhq.net/@noble/hashes/-/hashes-1.8.0.tgz", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "@nodable/entities": ["@nodable/entities@2.2.0", "https://registry-npm.cbhq.net/@nodable/entities/-/entities-2.2.0.tgz", {}, "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg=="], + "@scure/base": ["@scure/base@1.2.6", "https://registry-npm.cbhq.net/@scure/base/-/base-1.2.6.tgz", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], "@scure/bip32": ["@scure/bip32@1.7.0", "https://registry-npm.cbhq.net/@scure/bip32/-/bip32-1.7.0.tgz", { "dependencies": { "@noble/curves": "~1.9.0", "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw=="], "@scure/bip39": ["@scure/bip39@1.6.0", "https://registry-npm.cbhq.net/@scure/bip39/-/bip39-1.6.0.tgz", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], + "@smithy/core": ["@smithy/core@3.25.1", "https://registry-npm.cbhq.net/@smithy/core/-/core-3.25.1.tgz", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.15.0", "tslib": "^2.6.2" } }, "sha512-zpDbpXBCBsxfLtG2GEUyfgvHvSFrw5CwDZSNzL0v52gx/c3oPlPbm+7W7num8xs6vyiUBn+bvYPHcQDOXZynCQ=="], + + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.1", "https://registry-npm.cbhq.net/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.1.tgz", { "dependencies": { "@smithy/core": "^3.25.1", "@smithy/types": "^4.15.0", "tslib": "^2.6.2" } }, "sha512-TSAF5NHgxEsllbErYWbK8aLnl5L601NGc5VYJlSPsKnf3YlkhdoBN+geGcaU00oiw2OK3QO5LA3QNXiiWhCidQ=="], + + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.5.1", "https://registry-npm.cbhq.net/@smithy/fetch-http-handler/-/fetch-http-handler-5.5.1.tgz", { "dependencies": { "@smithy/core": "^3.25.1", "@smithy/types": "^4.15.0", "tslib": "^2.6.2" } }, "sha512-96JrD1q71anokymx9Iblb+zKmNQYNstlV/25A9ZYIJ2A0rp1r7/GZAIm0bDWSmVvz3DpNOCZuabzsiL+w0UHhw=="], + + "@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "https://registry-npm.cbhq.net/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.8.1", "https://registry-npm.cbhq.net/@smithy/node-http-handler/-/node-http-handler-4.8.1.tgz", { "dependencies": { "@smithy/core": "^3.25.1", "@smithy/types": "^4.15.0", "tslib": "^2.6.2" } }, "sha512-emtXvoky671puri18ETf64AFIQUGIEA093F2drXpBgB0OGnBLjcwNR3CA2mYu62IAqNsS56xa5lnTxAgPq7cjw=="], + + "@smithy/signature-v4": ["@smithy/signature-v4@5.5.1", "https://registry-npm.cbhq.net/@smithy/signature-v4/-/signature-v4-5.5.1.tgz", { "dependencies": { "@smithy/core": "^3.25.1", "@smithy/types": "^4.15.0", "tslib": "^2.6.2" } }, "sha512-X9rVls3En0z3NtrmguTmpRM0/NqtWUxBjal6fcAkwtsub+gOdLZ6kD+V7xhUgFMGdG14bHbZ7M5QjaRI1+DatQ=="], + + "@smithy/types": ["@smithy/types@4.15.0", "https://registry-npm.cbhq.net/@smithy/types/-/types-4.15.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg=="], + + "@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "https://registry-npm.cbhq.net/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + + "@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "https://registry-npm.cbhq.net/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@swc/helpers": ["@swc/helpers@0.5.15", "https://registry-npm.cbhq.net/@swc/helpers/-/helpers-0.5.15.tgz", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], "@tailwindcss/node": ["@tailwindcss/node@4.1.17", "https://registry-npm.cbhq.net/@tailwindcss/node/-/node-4.1.17.tgz", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="], @@ -176,6 +251,10 @@ "abitype": ["abitype@1.1.0", "https://registry-npm.cbhq.net/abitype/-/abitype-1.1.0.tgz", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A=="], + "anynum": ["anynum@1.0.0", "https://registry-npm.cbhq.net/anynum/-/anynum-1.0.0.tgz", {}, "sha512-xjR9/zBVnUOP6ztMIIgShjsxui80nQUQH+5xJnvrYLs+90bF25/KJqaAi8mk+B4RDtX1Nspi6fmp4YTEts8SfA=="], + + "bowser": ["bowser@2.14.1", "https://registry-npm.cbhq.net/bowser/-/bowser-2.14.1.tgz", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], + "caniuse-lite": ["caniuse-lite@1.0.30001781", "https://registry-npm.cbhq.net/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", {}, "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw=="], "client-only": ["client-only@0.0.1", "https://registry-npm.cbhq.net/client-only/-/client-only-0.0.1.tgz", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], @@ -188,6 +267,10 @@ "eventemitter3": ["eventemitter3@5.0.1", "https://registry-npm.cbhq.net/eventemitter3/-/eventemitter3-5.0.1.tgz", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "fast-xml-builder": ["fast-xml-builder@1.2.0", "https://registry-npm.cbhq.net/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="], + + "fast-xml-parser": ["fast-xml-parser@5.7.3", "https://registry-npm.cbhq.net/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="], + "graceful-fs": ["graceful-fs@4.2.11", "https://registry-npm.cbhq.net/graceful-fs/-/graceful-fs-4.2.11.tgz", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], "isows": ["isows@1.0.7", "https://registry-npm.cbhq.net/isows/-/isows-1.0.7.tgz", { "peerDependencies": { "ws": "*" } }, "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg=="], @@ -226,6 +309,8 @@ "ox": ["ox@0.9.6", "https://registry-npm.cbhq.net/ox/-/ox-0.9.6.tgz", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg=="], + "path-expression-matcher": ["path-expression-matcher@1.5.0", "https://registry-npm.cbhq.net/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="], + "picocolors": ["picocolors@1.1.1", "https://registry-npm.cbhq.net/picocolors/-/picocolors-1.1.1.tgz", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], "postcss": ["postcss@8.5.8", "https://registry-npm.cbhq.net/postcss/-/postcss-8.5.8.tgz", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], @@ -242,6 +327,8 @@ "source-map-js": ["source-map-js@1.2.1", "https://registry-npm.cbhq.net/source-map-js/-/source-map-js-1.2.1.tgz", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "strnum": ["strnum@2.4.0", "https://registry-npm.cbhq.net/strnum/-/strnum-2.4.0.tgz", { "dependencies": { "anynum": "^1.0.0" } }, "sha512-sHrVyWWdq28RbhjuJdZsA1SnGRJV6NiXbk6AXBxDOsgAcA+lmpUZCYjOdLBxkXMwis6RRe7dlZt4VlIWFVzkmg=="], + "styled-jsx": ["styled-jsx@5.1.6", "https://registry-npm.cbhq.net/styled-jsx/-/styled-jsx-5.1.6.tgz", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], "tailwindcss": ["tailwindcss@4.1.17", "https://registry-npm.cbhq.net/tailwindcss/-/tailwindcss-4.1.17.tgz", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], @@ -258,6 +345,8 @@ "ws": ["ws@8.18.3", "https://registry-npm.cbhq.net/ws/-/ws-8.18.3.tgz", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + "xml-naming": ["xml-naming@0.1.0", "https://registry-npm.cbhq.net/xml-naming/-/xml-naming-0.1.0.tgz", {}, "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "https://registry-npm.cbhq.net/@emnapi/core/-/core-1.9.1.tgz", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "https://registry-npm.cbhq.net/@emnapi/runtime/-/runtime-1.9.1.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], diff --git a/next.config.ts b/next.config.ts index 68a6c64d..ee6198d2 100644 --- a/next.config.ts +++ b/next.config.ts @@ -2,6 +2,10 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { output: "standalone", + outputFileTracingRoot: __dirname, + turbopack: { + root: __dirname, + }, }; export default nextConfig; diff --git a/package.json b/package.json index b6af038b..34850080 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "format": "biome format --write" }, "dependencies": { + "@aws-sdk/client-s3": "^3.1071.0", "next": "16.0.7", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/src/app/api/block/[hash]/route.ts b/src/app/api/block/[hash]/route.ts index dd6d0a5e..70ddfdbb 100644 --- a/src/app/api/block/[hash]/route.ts +++ b/src/app/api/block/[hash]/route.ts @@ -2,11 +2,21 @@ import { type NextRequest, NextResponse } from "next/server"; import { type Block, createPublicClient, type Hash, http } from "viem"; import { mainnet } from "viem/chains"; import { + bundleHistoryFromAuditEvents, + getAuditEventsByBlockNumber, getAuditEventsByTransactionHash, meterBundleResponseFromAuditEvent, transactionMetadataFromAuditEvents, } from "@/lib/audit-events"; import type { BlockData, BlockTransaction } from "@/lib/transaction-data"; +import { getBlockFromCache } from "@/lib/s3"; + +const BLOCK_EVENT_TYPES = new Set([ + "BUILDER_FLASHBLOCK_STARTED", + "BUILDER_FLASHBLOCK_PUBLISHED", + "BUILDER_FLASHBLOCK_BUILD_STOPPED", + "BUILDER_PAYLOAD_FINALIZED", +]); function serializeBlockData(block: BlockData) { return { @@ -32,6 +42,7 @@ function serializeBlockData(block: BlockData) { metering, }; }), + eventHistory: block.eventHistory ?? [], }; } @@ -121,6 +132,13 @@ async function buildAndCacheBlockData( number, timestamp: rpcBlock.timestamp, transactions, + eventHistory: + bundleHistoryFromAuditEvents( + hash, + (await getAuditEventsByBlockNumber(Number(number))).filter((event) => + BLOCK_EVENT_TYPES.has(event.event_type), + ), + )?.history ?? [], gasUsed: rpcBlock.gasUsed, gasLimit: rpcBlock.gasLimit, cachedAt: Date.now(), @@ -153,6 +171,10 @@ export async function GET( const rpcBlock = await fetchBlockFromRpc(identifier); if (!rpcBlock || !rpcBlock.hash || !rpcBlock.number) { + const cachedBlock = await getBlockFromCache(identifier); + if (cachedBlock) { + return NextResponse.json(serializeBlockData(cachedBlock)); + } return NextResponse.json({ error: "Block not found" }, { status: 404 }); } diff --git a/src/app/api/bundle/[hash]/route.ts b/src/app/api/bundle/[hash]/route.ts index 6e7886c4..9e5b54ed 100644 --- a/src/app/api/bundle/[hash]/route.ts +++ b/src/app/api/bundle/[hash]/route.ts @@ -1,15 +1,88 @@ import { type NextRequest, NextResponse } from "next/server"; +import { createPublicClient, type Hash, http } from "viem"; +import { mainnet } from "viem/chains"; import { bundleHistoryFromAuditEvents, - getAuditEventsByBundle, + getJoinedAuditEventsByBundle, } from "@/lib/audit-events"; -import type { BundleEvent } from "@/lib/transaction-data"; +import type { BundleEvent, BundleTransaction } from "@/lib/transaction-data"; +import { getBundleHistory } from "@/lib/s3"; + +const RPC_URL = process.env.TIPS_UI_RPC_URL || "http://localhost:8545"; + +const client = createPublicClient({ + chain: mainnet, + transport: http(RPC_URL), +}); export interface BundleHistoryResponse { hash: string; history: BundleEvent[]; } +function bigintToHex(value: bigint | null | undefined): string { + return value === null || value === undefined ? "0x0" : `0x${value.toString(16)}`; +} + +function numberToHex(value: number | null | undefined): string { + return value === null || value === undefined ? "0x0" : `0x${value.toString(16)}`; +} + +async function enrichBundleTransactionsFromRpc( + history: BundleEvent[], +): Promise { + const hashes = Array.from( + new Set( + history.flatMap((event) => + event.data.bundle?.txs.map((tx) => tx.hash).filter(Boolean) ?? [], + ), + ), + ); + const transactions = new Map(); + + await Promise.all( + hashes.map(async (hash) => { + try { + const tx = await client.getTransaction({ hash: hash as Hash }); + transactions.set(hash, { + signer: tx.from, + type: tx.typeHex ?? "", + chainId: numberToHex(tx.chainId), + nonce: numberToHex(tx.nonce), + gas: bigintToHex(tx.gas), + maxFeePerGas: bigintToHex(tx.maxFeePerGas ?? tx.gasPrice), + maxPriorityFeePerGas: bigintToHex(tx.maxPriorityFeePerGas), + to: tx.to, + value: bigintToHex(tx.value), + accessList: [...(tx.accessList ?? [])], + input: tx.input, + r: tx.r, + s: tx.s, + yParity: numberToHex(tx.yParity), + v: bigintToHex(tx.v), + hash: tx.hash, + }); + } catch (error) { + console.error(`Failed to fetch transaction ${hash} from RPC:`, error); + } + }), + ); + + return history.map((event) => { + if (!event.data.bundle) return event; + return { + ...event, + data: { + ...event.data, + bundle: { + ...event.data.bundle, + txs: event.data.bundle.txs.map((tx) => transactions.get(tx.hash) ?? tx), + }, + }, + }; + }); +} + export async function GET( _request: NextRequest, { params }: { params: Promise<{ hash: string }> }, @@ -17,22 +90,19 @@ export async function GET( try { const { hash } = await params; - const bundle = bundleHistoryFromAuditEvents( - hash, - await getAuditEventsByBundle(hash), - ); + const bundle = await getAuditBundleHistory(hash); if (!bundle) { return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); } - const history = bundle.history; + const history = await enrichBundleTransactionsFromRpc(bundle.history); history.sort((lhs, rhs) => lhs.data.timestamp < rhs.data.timestamp ? -1 : 1, ); const response: BundleHistoryResponse = { hash, - history: bundle.history, + history, }; return NextResponse.json(response); @@ -44,3 +114,13 @@ export async function GET( ); } } + +async function getAuditBundleHistory(hash: string) { + try { + const events = await getJoinedAuditEventsByBundle(hash); + return bundleHistoryFromAuditEvents(hash, events) ?? getBundleHistory(hash); + } catch (error) { + console.error("Falling back to S3 bundle history:", error); + return getBundleHistory(hash); + } +} diff --git a/src/app/api/rejected/route.ts b/src/app/api/rejected/route.ts index 11c4381f..33817085 100644 --- a/src/app/api/rejected/route.ts +++ b/src/app/api/rejected/route.ts @@ -4,6 +4,10 @@ import { rejectedTransactionFromAuditEvent, } from "@/lib/audit-events"; import type { RejectedTransaction } from "@/lib/transaction-data"; +import { + getRejectedTransaction, + listRejectedTransactions, +} from "@/lib/s3"; export interface RejectedTransactionsResponse { transactions: RejectedTransaction[]; @@ -11,9 +15,11 @@ export interface RejectedTransactionsResponse { export async function GET() { try { - const transactions = (await getAuditRejectedTransactionEvents(100)) - .map(rejectedTransactionFromAuditEvent) - .filter((tx): tx is RejectedTransaction => tx !== null); + const auditTransactions = await getAuditRejectedTransactions(); + const transactions = + auditTransactions.length > 0 + ? auditTransactions + : await getS3RejectedTransactions(); const response: RejectedTransactionsResponse = { transactions }; return NextResponse.json(response); @@ -25,3 +31,24 @@ export async function GET() { ); } } + +async function getAuditRejectedTransactions(): Promise { + try { + return (await getAuditRejectedTransactionEvents(100)) + .map(rejectedTransactionFromAuditEvent) + .filter((tx): tx is RejectedTransaction => tx !== null); + } catch (error) { + console.error("Falling back to S3 rejected transactions:", error); + return []; + } +} + +async function getS3RejectedTransactions(): Promise { + const summaries = await listRejectedTransactions(100); + const transactions = await Promise.all( + summaries.map((summary) => + getRejectedTransaction(summary.blockNumber, summary.txHash), + ), + ); + return transactions.filter((tx): tx is RejectedTransaction => tx !== null); +} diff --git a/src/app/api/txn/[hash]/route.ts b/src/app/api/txn/[hash]/route.ts index 8d0446a4..073dce48 100644 --- a/src/app/api/txn/[hash]/route.ts +++ b/src/app/api/txn/[hash]/route.ts @@ -1,11 +1,16 @@ import { type NextRequest, NextResponse } from "next/server"; import { bundleHistoryFromAuditEvents, - getAuditEventsByBundle, + getJoinedAuditEventsByBundle, getAuditEventsByTransactionHash, + mergeAuditEvents, transactionMetadataFromAuditEvents, } from "@/lib/audit-events"; import type { BundleEvent } from "@/lib/transaction-data"; +import { + getBundleHistory, + getTransactionMetadataByHash, +} from "@/lib/s3"; export interface TransactionEvent { type: string; @@ -43,8 +48,12 @@ export async function GET( try { const { hash } = await params; - const events = await getAuditEventsByTransactionHash(hash); - const metadata = transactionMetadataFromAuditEvents(events); + const audit = await getAuditTransactionHistory(hash); + if (audit) { + return NextResponse.json(audit); + } + + const metadata = await getTransactionMetadataByHash(hash); if (!metadata) { return NextResponse.json( { error: "Transaction not found" }, @@ -53,18 +62,15 @@ export async function GET( } const bundleId = metadata.bundle_ids[0]; - const bundle = - bundleId !== undefined - ? bundleHistoryFromAuditEvents( - bundleId, - await getAuditEventsByBundle(bundleId), - ) - : { history: [] }; + const bundle = bundleId ? await getBundleHistory(bundleId) : null; + if (!bundle) { + return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); + } const response: TransactionHistoryResponse = { hash, bundle_ids: metadata.bundle_ids, - history: bundle?.history ?? [], + history: bundle.history, }; return NextResponse.json(response); @@ -76,3 +82,35 @@ export async function GET( ); } } + +async function getAuditTransactionHistory( + hash: string, +): Promise { + try { + const events = await getAuditEventsByTransactionHash(hash); + const metadata = transactionMetadataFromAuditEvents(events); + if (!metadata) return null; + + const bundleId = metadata.bundle_ids[0]; + let history: BundleEvent[] = []; + if (bundleId !== undefined) { + const bundle = bundleHistoryFromAuditEvents( + bundleId, + mergeAuditEvents([ + await getJoinedAuditEventsByBundle(bundleId), + events, + ]), + ); + history = bundle?.history ?? []; + } + + return { + hash, + bundle_ids: metadata.bundle_ids, + history, + }; + } catch (error) { + console.error("Falling back to S3 transaction history:", error); + return null; + } +} diff --git a/src/app/block/[hash]/page.tsx b/src/app/block/[hash]/page.tsx index caecb721..0a5473a2 100644 --- a/src/app/block/[hash]/page.tsx +++ b/src/app/block/[hash]/page.tsx @@ -2,6 +2,7 @@ import Link from "next/link"; import { useEffect, useState } from "react"; +import { EventHistoryRow } from "@/app/event-history-row"; import type { BlockData, BlockTransaction } from "@/lib/transaction-data"; const BLOCK_EXPLORER_URL = process.env.NEXT_PUBLIC_BLOCK_EXPLORER_URL; @@ -96,6 +97,37 @@ function Card({ ); } +function EventHistory({ + events, +}: { + events: NonNullable; +}) { + if (events.length === 0) { + return ( + +
+ No transaction events recorded for this block. +
+
+ ); + } + + return ( + +
+ {events.map((event, index) => ( + + ))} +
+
+ ); +} + function getHeatmapStyle( timeUs: number, maxTime: number, @@ -521,6 +553,13 @@ export default function BlockPage({ params }: PageProps) { )} + +
+

+ Event History +

+ +
)} diff --git a/src/app/bundles/[hash]/page.tsx b/src/app/bundles/[hash]/page.tsx index 370b6e94..b2325200 100644 --- a/src/app/bundles/[hash]/page.tsx +++ b/src/app/bundles/[hash]/page.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import { useEffect, useState } from "react"; import type { BundleHistoryResponse } from "@/app/api/bundle/[hash]/route"; +import { EventHistoryRow } from "@/app/event-history-row"; import type { BundleTransaction, MeterBundleResponse, @@ -119,29 +120,6 @@ function CopyButton({ text }: { text: string }) { ); } -function Badge({ - children, - variant = "default", -}: { - children: React.ReactNode; - variant?: "default" | "success" | "warning" | "error"; -}) { - const variants = { - default: "bg-blue-50 text-blue-700 ring-blue-600/20", - success: "bg-emerald-50 text-emerald-700 ring-emerald-600/20", - warning: "bg-amber-50 text-amber-700 ring-amber-600/20", - error: "bg-red-50 text-red-700 ring-red-600/20", - }; - - return ( - - {children} - - ); -} - function Card({ children, className = "", @@ -408,70 +386,19 @@ function SimulationCard({ meter }: { meter: MeterBundleResponse }) { ); } -function TimelineEventDetails({ - event, -}: { - event: BundleHistoryResponse["history"][0]; -}) { - if (event.event === "BlockIncluded" && event.data?.block_hash) { - return ( -
- {event.event} - - Block #{event.data.block_number} - -
- ); - } - - if (event.event === "BuilderIncluded" && event.data?.builder) { - return ( -
- {event.event} - - {event.data.builder} (flashblock #{event.data.flashblock_index}) - -
- ); - } - - if (event.event === "Dropped" && event.data?.reason) { - return ( -
- {event.event} - {event.data.reason} -
- ); - } - - return {event.event}; -} - function Timeline({ events }: { events: BundleHistoryResponse["history"] }) { if (events.length === 0) return null; return ( -
+
{events.map((event, index) => ( -
-
-
-
-
- - -
-
+ event={event} + isLast={index === events.length - 1} + startTimestamp={events[0]?.data.timestamp ?? event.data.timestamp} + highlightIncluded + /> ))}
); diff --git a/src/app/event-history-row.tsx b/src/app/event-history-row.tsx new file mode 100644 index 00000000..6c903c81 --- /dev/null +++ b/src/app/event-history-row.tsx @@ -0,0 +1,204 @@ +"use client"; + +import Link from "next/link"; +import { useState } from "react"; +import type { BundleEvent } from "@/lib/transaction-data"; + +function EventChip({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +function EventMarker({ + success, + isLast, +}: { + success: boolean; + isLast: boolean; +}) { + return ( +
+ {!isLast &&
} +
+
+
+
+ ); +} + +function metadataChips(event: BundleEvent) { + return [ + event.data.producer ? `source: ${event.data.producer}` : null, + event.data.target ? `target: ${event.data.target}` : null, + event.data.reason ? `reason: ${event.data.reason}` : null, + ].filter((value): value is string => value !== null); +} + +function formatLatency(milliseconds: number): string { + if (milliseconds < 1000) { + return `${Math.round(milliseconds)} ms`; + } + return `${(milliseconds / 1000).toFixed(2)} s`; +} + +function BlockFlashblockContext({ event }: { event: BundleEvent }) { + const blockNumber = event.data.block_number; + const flashblockIndex = event.data.flashblock_index; + + if (blockNumber === undefined && flashblockIndex === undefined) { + return null; + } + + const label = [ + blockNumber !== undefined ? `Block #${blockNumber}` : null, + flashblockIndex !== undefined ? `FB${flashblockIndex}` : null, + ] + .filter((value): value is string => value !== null) + .join(" · "); + + const className = + "mt-1 inline-flex text-xs font-medium text-gray-500 tabular-nums"; + + if (event.data.block_hash) { + return ( + + {label} + + ); + } + + return {label}; +} + +function JsonToggle({ + expanded, + onClick, +}: { + expanded: boolean; + onClick: () => void; +}) { + return ( + + ); +} + +export function EventHistoryRow({ + event, + isLast, + startTimestamp, + highlightIncluded = false, +}: { + event: BundleEvent; + isLast: boolean; + startTimestamp: number; + highlightIncluded?: boolean; +}) { + const [jsonExpanded, setJsonExpanded] = useState(false); + const success = highlightIncluded && event.event === "BUILDER_INCLUDED"; + const chips = metadataChips(event); + const elapsedMs = event.data.timestamp - startTimestamp; + + return ( +
+ +
+
+
+
+
+ {event.event} +
+ +
+
+ {chips.map((chip) => ( + {chip} + ))} +
+
+ + {event.data.originalEvent !== undefined && ( + setJsonExpanded((value) => !value)} + /> + )} +
+
+ {event.data.originalEvent !== undefined && jsonExpanded && ( +
+              {JSON.stringify(event.data.originalEvent, null, 2)}
+            
+ )} +
+
+
+ ); +} diff --git a/src/lib/audit-events.test.ts b/src/lib/audit-events.test.ts index 36d30e93..c9ebc9bc 100644 --- a/src/lib/audit-events.test.ts +++ b/src/lib/audit-events.test.ts @@ -3,8 +3,11 @@ import { describe, test } from "node:test"; import { type AuditTransactionEventRecord, bundleHistoryFromAuditEvents, + bundleKeysFromAuditEvents, + mergeAuditEvents, rejectedTransactionFromAuditEvent, transactionMetadataFromAuditEvents, + transactionHashesFromAuditEvents, } from "./audit-events"; const acceptedEvent: AuditTransactionEventRecord = { @@ -43,12 +46,17 @@ describe("audit event route adapters", () => { const history = bundleHistoryFromAuditEvents("0xbundle", [acceptedEvent]); assert.equal(history?.history.length, 1); - assert.equal(history?.history[0]?.event, "Received"); + assert.equal(history?.history[0]?.event, "SIMULATION_SUCCEEDED"); + assert.equal(history?.history[0]?.data.producer, "ingress-rpc"); + assert.deepEqual(history?.history[0]?.data.originalEvent, acceptedEvent); assert.equal( history?.history[0]?.data.bundle?.meter_bundle_response.results[0] ?.txHash, "0xabc", ); + assert.equal(history?.history[0]?.data.bundle?.txs[0]?.hash, "0xabc"); + assert.equal(history?.history[0]?.data.bundle?.txs[0]?.signer, "0xsender"); + assert.equal(history?.history[0]?.data.bundle?.txs[0]?.to, "0xto"); }); test("derives transaction metadata from audit join fields", () => { @@ -57,6 +65,105 @@ describe("audit event route adapters", () => { assert.deepEqual(metadata?.bundle_ids, ["bundle-id"]); }); + test("derives related bundle keys for id and hash lookups", () => { + assert.deepEqual(bundleKeysFromAuditEvents("bundle-id", [acceptedEvent]), [ + "bundle-id", + "0xbundle", + ]); + }); + + test("deduplicates events fetched through related bundle keys", () => { + const merged = mergeAuditEvents([[acceptedEvent], [acceptedEvent]]); + + assert.equal(merged.length, 1); + assert.equal(merged[0]?.event_id, "event-1"); + }); + + test("derives transaction hashes from envelope and metering results", () => { + const hashes = transactionHashesFromAuditEvents([ + { + ...acceptedEvent, + tx_hash: null, + }, + ]); + + assert.deepEqual(hashes, ["0xabc"]); + }); + + test("keeps payload and block join fields on builder events", () => { + const payloadEvent = bundleHistoryFromAuditEvents("0xbundle", [ + { + ...acceptedEvent, + event_id: "event-3", + event_type: "BUILDER_ACCEPTED", + producer: "base-builder", + payload_id: "0xpayload", + block_number: 123, + data: { + flashblock_index: 2, + }, + }, + ]); + + assert.equal(payloadEvent?.history[0]?.data.originalEvent?.payload_id, "0xpayload"); + assert.equal(payloadEvent?.history[0]?.data.originalEvent?.block_number, 123); + assert.equal( + payloadEvent?.history[0]?.data.originalEvent?.data.flashblock_index, + 2, + ); + }); + + test("does not decorate audit history with derived display latencies", () => { + const history = bundleHistoryFromAuditEvents("0xbundle", [ + { + ...acceptedEvent, + event_id: "event-proxy", + event_time: "2026-06-02T00:00:00.100Z", + event_type: "PROXY_RECEIVED", + producer: "base-routing/proxyd", + }, + { + ...acceptedEvent, + event_id: "event-builder-considered", + event_time: "2026-06-02T00:00:00.175Z", + event_type: "BUILDER_CONSIDERED", + producer: "base-builder", + }, + { + ...acceptedEvent, + event_id: "event-builder-accepted", + event_time: "2026-06-02T00:00:00.225Z", + event_type: "BUILDER_ACCEPTED", + producer: "base-builder", + }, + { + ...acceptedEvent, + event_id: "event-flashblock-published", + event_time: "2026-06-02T00:00:00.700Z", + event_type: "BUILDER_FLASHBLOCK_PUBLISHED", + producer: "base-builder", + }, + { + ...acceptedEvent, + event_id: "event-builder-included", + event_time: "2026-06-02T00:00:01.350Z", + event_type: "BUILDER_INCLUDED", + producer: "base-builder", + }, + ]); + + assert.deepEqual( + history?.history.map((event) => event.event), + [ + "PROXY_RECEIVED", + "BUILDER_CONSIDERED", + "BUILDER_ACCEPTED", + "BUILDER_FLASHBLOCK_PUBLISHED", + "BUILDER_INCLUDED", + ], + ); + }); + test("adapts rejected audit events to the existing rejected route shape", () => { const rejected = rejectedTransactionFromAuditEvent({ ...acceptedEvent, diff --git a/src/lib/audit-events.ts b/src/lib/audit-events.ts index 25dd887d..29b8bf28 100644 --- a/src/lib/audit-events.ts +++ b/src/lib/audit-events.ts @@ -1,6 +1,7 @@ import type { BundleEvent, BundleHistory, + BundleTransaction, MeterBundleResponse, RejectedTransaction, RejectionReason, @@ -133,6 +134,141 @@ export function bundleHistoryFromAuditEvents( }; } +export function bundleKeysFromAuditEvents( + bundleKey: string, + events: AuditTransactionEventRecord[], +): string[] { + return Array.from( + new Set( + [ + bundleKey, + ...events.flatMap((event) => [ + stringField(event.data.bundle_id), + stringField(event.data.bundle_hash), + ]), + ].filter((value): value is string => value !== null), + ), + ); +} + +export function transactionHashesFromAuditEvents( + events: AuditTransactionEventRecord[], +): string[] { + return Array.from( + new Set( + events + .flatMap((event) => [ + event.tx_hash, + ...arrayField(recordField(event.data.meter_bundle_response)?.results) + .map((result) => stringField(result.txHash)) + .filter((value): value is string => value !== null), + ]) + .filter((value): value is string => value !== null), + ), + ); +} + +interface PayloadFlashblockContext { + payloadId: string; + blockNumber: number; + flashblockIndex: number; +} + +function payloadFlashblockContextsFromAuditEvents( + events: AuditTransactionEventRecord[], +): PayloadFlashblockContext[] { + const contexts = new Map(); + for (const event of events) { + const payloadId = stringField(event.payload_id); + const blockNumber = numberField(event.block_number); + const flashblockIndex = numberField(event.data.flashblock_index); + if (payloadId === null || blockNumber === null || flashblockIndex === null) { + continue; + } + + contexts.set(`${payloadId}:${blockNumber}:${flashblockIndex}`, { + payloadId, + blockNumber, + flashblockIndex, + }); + } + return Array.from(contexts.values()); +} + +async function getPayloadContextEvents( + events: AuditTransactionEventRecord[], +): Promise { + const contexts = payloadFlashblockContextsFromAuditEvents(events); + if (contexts.length === 0) return []; + + const blockNumbers = Array.from( + new Set(contexts.map((context) => context.blockNumber)), + ); + const blockEventGroups = await Promise.all( + blockNumbers.map((blockNumber) => getAuditEventsByBlockNumber(blockNumber)), + ); + + return blockEventGroups.flat().filter((event) => { + const payloadId = stringField(event.payload_id); + if (payloadId === null) return false; + + if (event.event_type === "BUILDER_PAYLOAD_FINALIZED") { + return contexts.some((context) => context.payloadId === payloadId); + } + + if ( + event.event_type !== "BUILDER_FLASHBLOCK_STARTED" && + event.event_type !== "BUILDER_FLASHBLOCK_PUBLISHED" + ) { + return false; + } + + const blockNumber = numberField(event.block_number); + const flashblockIndex = numberField(event.data.flashblock_index); + return contexts.some( + (context) => + context.payloadId === payloadId && + context.blockNumber === blockNumber && + context.flashblockIndex === flashblockIndex, + ); + }); +} + +export async function getJoinedAuditEventsByBundle( + bundleKey: string, +): Promise { + const initialEvents = await getAuditEventsByBundle(bundleKey); + const bundleKeys = bundleKeysFromAuditEvents(bundleKey, initialEvents); + const relatedBundleEventGroups = await Promise.all( + bundleKeys + .filter((key) => key !== bundleKey) + .map((key) => getAuditEventsByBundle(key)), + ); + const bundleEvents = mergeAuditEvents([ + initialEvents, + ...relatedBundleEventGroups, + ]); + const txHashes = transactionHashesFromAuditEvents(bundleEvents); + const txEventGroups = await Promise.all( + txHashes.map((txHash) => getAuditEventsByTransactionHash(txHash)), + ); + const txEvents = mergeAuditEvents(txEventGroups); + const payloadContextEvents = await getPayloadContextEvents(txEvents); + return mergeAuditEvents([bundleEvents, txEvents, payloadContextEvents]); +} + +export function mergeAuditEvents( + eventGroups: AuditTransactionEventRecord[][], +): AuditTransactionEventRecord[] { + const eventsById = new Map(); + for (const event of eventGroups.flat()) { + eventsById.set(event.event_id, event); + } + return Array.from(eventsById.values()).sort( + (lhs, rhs) => Date.parse(lhs.event_time) - Date.parse(rhs.event_time), + ); +} + export function meterBundleResponseFromAuditEvent( event: AuditTransactionEventRecord, ): MeterBundleResponse | null { @@ -175,13 +311,20 @@ function bundleEventFromAuditEvent( const timestamp = Date.parse(event.event_time); if (event.event_type === "SIMULATION_SUCCEEDED") { return { - event: "Received", + event: event.event_type, data: { key: event.event_id, timestamp, + producer: event.producer, + reason: + stringField(event.data.rejection_reason) ?? + stringField(event.data.reason) ?? + undefined, + target: stringField(event.data.target) ?? undefined, + originalEvent: event, bundle: { uuid: stringField(event.data.bundle_id) ?? bundleKey, - txs: [], + txs: transactionsFromMeterBundleResponse(event.data), block_number: String(event.data.state_block_number ?? ""), max_timestamp: 0, reverting_tx_hashes: event.tx_hash ? [event.tx_hash] : [], @@ -201,35 +344,63 @@ function bundleEventFromAuditEvent( numberField(event.data.state_block_number) ?? undefined, block_hash: event.block_hash ?? undefined, + flashblock_index: numberField(event.data.flashblock_index) ?? undefined, + producer: event.producer, reason: stringField(event.data.rejection_reason) ?? stringField(event.data.reason) ?? undefined, + target: stringField(event.data.target) ?? undefined, + originalEvent: event, }, }; } +function transactionsFromMeterBundleResponse( + data: Record, +): BundleTransaction[] { + const metering = recordField(data.meter_bundle_response) ?? data; + return arrayField(metering.results).map((result) => ({ + signer: stringField(result.fromAddress) ?? "", + type: "", + chainId: "", + nonce: "0x0", + gas: numberToHex(numberField(result.gasUsed) ?? 0), + maxFeePerGas: stringField(result.gasPrice) ?? "0x0", + maxPriorityFeePerGas: "0x0", + to: stringField(result.toAddress), + value: stringField(result.value) ?? "0x0", + accessList: [], + input: "0x", + r: "", + s: "", + yParity: "", + v: "", + hash: stringField(result.txHash) ?? "", + })); +} + function meterBundleResponseFromData( data: Record, ): MeterBundleResponse { const metering = recordField(data.meter_bundle_response) ?? data; return { - bundleGasPrice: "0", + bundleGasPrice: stringField(metering.bundleGasPrice) ?? "0", bundleHash: stringField(metering.bundleHash) ?? stringField(data.bundle_hash) ?? "", - coinbaseDiff: "0", - ethSentToCoinbase: "0", - gasFees: "0", + coinbaseDiff: stringField(metering.coinbaseDiff) ?? "0", + ethSentToCoinbase: stringField(metering.ethSentToCoinbase) ?? "0", + gasFees: stringField(metering.gasFees) ?? "0", results: arrayField(metering.results).map((result) => ({ - coinbaseDiff: "0", - ethSentToCoinbase: "0", + coinbaseDiff: stringField(result.coinbaseDiff) ?? "0", + ethSentToCoinbase: stringField(result.ethSentToCoinbase) ?? "0", fromAddress: stringField(result.fromAddress) ?? "", - gasFees: "0", - gasPrice: "0", + gasFees: stringField(result.gasFees) ?? "0", + gasPrice: stringField(result.gasPrice) ?? "0", gasUsed: numberField(result.gasUsed) ?? 0, toAddress: stringField(result.toAddress) ?? "", txHash: stringField(result.txHash) ?? "", - value: "0", + value: stringField(result.value) ?? "0", executionTimeUs: numberField(result.executionTimeUs) ?? 0, })), stateBlockNumber: numberField(metering.stateBlockNumber) ?? 0, @@ -276,6 +447,10 @@ function numberField(value: unknown): number | null { return null; } +function numberToHex(value: number): string { + return `0x${Math.max(0, Math.trunc(value)).toString(16)}`; +} + function arrayField(value: unknown): Record[] { return Array.isArray(value) ? value.filter(isRecord) : []; } diff --git a/src/lib/s3.ts b/src/lib/s3.ts new file mode 100644 index 00000000..0303787a --- /dev/null +++ b/src/lib/s3.ts @@ -0,0 +1,191 @@ +import { + GetObjectCommand, + ListObjectsV2Command, + S3Client, + type S3ClientConfig, +} from "@aws-sdk/client-s3"; +import type { + BlockData, + BundleEvent, + BundleHistory, + RejectedTransaction, + TransactionMetadata, +} from "@/lib/transaction-data"; + +function createS3Client(): S3Client { + const configType = process.env.TIPS_UI_S3_CONFIG_TYPE || "aws"; + const region = process.env.TIPS_UI_AWS_REGION || "us-east-1"; + + if (configType === "manual") { + const config: S3ClientConfig = { + region, + forcePathStyle: true, + }; + + if (process.env.TIPS_UI_S3_ENDPOINT) { + config.endpoint = process.env.TIPS_UI_S3_ENDPOINT; + } + + if ( + process.env.TIPS_UI_S3_ACCESS_KEY_ID && + process.env.TIPS_UI_S3_SECRET_ACCESS_KEY + ) { + config.credentials = { + accessKeyId: process.env.TIPS_UI_S3_ACCESS_KEY_ID, + secretAccessKey: process.env.TIPS_UI_S3_SECRET_ACCESS_KEY, + }; + } + + return new S3Client(config); + } + + return new S3Client({ region }); +} + +const s3Client = createS3Client(); +const BUCKET_NAME = process.env.TIPS_UI_S3_BUCKET_NAME || "tips"; + +async function getObjectContent(key: string): Promise { + try { + const response = await s3Client.send( + new GetObjectCommand({ + Bucket: BUCKET_NAME, + Key: key, + }), + ); + return (await response.Body?.transformToString()) || null; + } catch { + return null; + } +} + +export async function getTransactionMetadataByHash( + hash: string, +): Promise { + const content = await getObjectContent(`transactions/by_hash/${hash}`); + if (!content) return null; + + try { + return JSON.parse(content) as TransactionMetadata; + } catch (error) { + console.error( + `Failed to parse transaction metadata for hash ${hash}:`, + error, + ); + return null; + } +} + +export async function getBundleHistory( + bundleKey: string, +): Promise { + try { + const listResponse = await s3Client.send( + new ListObjectsV2Command({ + Bucket: BUCKET_NAME, + Prefix: `bundles/${bundleKey}/`, + }), + ); + const keys = listResponse.Contents?.map((obj) => obj.Key).filter( + Boolean, + ) as string[]; + if (!keys || keys.length === 0) return null; + + const history: BundleEvent[] = []; + for (const key of keys) { + const content = await getObjectContent(key); + if (!content) continue; + try { + history.push(JSON.parse(content) as BundleEvent); + } catch (error) { + console.error(`Failed to parse event at ${key}:`, error); + } + } + + return { history }; + } catch (error) { + console.error(`Failed to list bundle history for ${bundleKey}:`, error); + return null; + } +} + +export async function getBlockFromCache( + blockHash: string, +): Promise { + const content = await getObjectContent(`blocks/${blockHash}`); + if (!content) return null; + + try { + const parsed = JSON.parse(content); + return { + ...parsed, + number: BigInt(parsed.number), + timestamp: BigInt(parsed.timestamp), + gasUsed: BigInt(parsed.gasUsed), + gasLimit: BigInt(parsed.gasLimit), + transactions: parsed.transactions.map( + (tx: { gasLimit?: string; [key: string]: unknown }) => ({ + ...tx, + gasLimit: BigInt(tx.gasLimit ?? "0"), + meterBundleResponse: tx.meterBundleResponse ?? null, + }), + ), + } as BlockData; + } catch (error) { + console.error(`Failed to parse block data for hash ${blockHash}:`, error); + return null; + } +} + +interface RejectedTransactionSummary { + blockNumber: number; + txHash: string; +} + +export async function listRejectedTransactions( + limit = 100, +): Promise { + try { + const response = await s3Client.send( + new ListObjectsV2Command({ + Bucket: BUCKET_NAME, + Prefix: "rejected/", + MaxKeys: limit, + }), + ); + + const summaries: RejectedTransactionSummary[] = []; + for (const obj of response.Contents || []) { + if (!obj.Key) continue; + const parts = obj.Key.split("/"); + if (parts.length !== 3) continue; + const blockNumber = Number.parseInt(parts[1] ?? "", 10); + const txHash = parts[2]; + if (Number.isNaN(blockNumber) || !txHash) continue; + summaries.push({ blockNumber, txHash }); + } + + return summaries.sort((a, b) => b.blockNumber - a.blockNumber); + } catch (error) { + console.error("Failed to list rejected transactions:", error); + return []; + } +} + +export async function getRejectedTransaction( + blockNumber: number, + txHash: string, +): Promise { + const content = await getObjectContent(`rejected/${blockNumber}/${txHash}`); + if (!content) return null; + + try { + return JSON.parse(content) as RejectedTransaction; + } catch (error) { + console.error( + `Failed to parse rejected transaction ${blockNumber}/${txHash}:`, + error, + ); + return null; + } +} diff --git a/src/lib/transaction-data.ts b/src/lib/transaction-data.ts index ff4297ba..de701f24 100644 --- a/src/lib/transaction-data.ts +++ b/src/lib/transaction-data.ts @@ -70,7 +70,10 @@ export interface BundleEventData { block_hash?: string; builder?: string; flashblock_index?: number; + producer?: string; reason?: string; + target?: string; + originalEvent?: unknown; } export interface BundleEvent { @@ -97,6 +100,7 @@ export interface BlockData { number: bigint; timestamp: bigint; transactions: BlockTransaction[]; + eventHistory?: BundleEvent[]; gasUsed: bigint; gasLimit: bigint; cachedAt: number; From 095191c32349ff6e7bf8437b833dbb61bb3e8a39 Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Wed, 17 Jun 2026 23:41:17 -0500 Subject: [PATCH 4/4] Highlight published flashblock events --- src/app/event-history-row.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/event-history-row.tsx b/src/app/event-history-row.tsx index 6c903c81..8759eb6c 100644 --- a/src/app/event-history-row.tsx +++ b/src/app/event-history-row.tsx @@ -151,7 +151,10 @@ export function EventHistoryRow({ highlightIncluded?: boolean; }) { const [jsonExpanded, setJsonExpanded] = useState(false); - const success = highlightIncluded && event.event === "BUILDER_INCLUDED"; + const success = + highlightIncluded && + (event.event === "BUILDER_INCLUDED" || + event.event === "BUILDER_FLASHBLOCK_PUBLISHED"); const chips = metadataChips(event); const elapsedMs = event.data.timestamp - startTimestamp;