From bdba8bbc012e09130877a7e562da94f402b10db6 Mon Sep 17 00:00:00 2001
From: Ugwoke Levi <113690452+levoski1@users.noreply.github.com>
Date: Mon, 6 Jul 2026 15:47:08 +0000
Subject: [PATCH 1/3] fix: resolve all CI/CD failures across frontend and
contracts
Frontend (TypeScript/ESLint):
- App.tsx: fix broken JSX ternary chain, add missing BatchExpireInvoices
and TreasuryManager imports, extend Tab type, remove unused imports
and EXPECTED_NETWORK constant
- soroban.ts: add cancelInvoice(), fix sendTransaction() calls (parse
signed XDR string back to Transaction), replace window as any with
typed WindowWithFreighter interface, err: any -> err: unknown
- treasury.ts: replace window as any with typed WindowWithWallet
interface, fix TransactionBuilder account cast, err: any -> unknown
- TreasuryManager.tsx: fix SorobanRpc.Server -> Server, fix
assembleTransaction call signature, fix sendTransaction XDR parsing
- useInvoice.ts: add cancel() method backed by cancelInvoice()
- useToast.ts: extract useToast hook from Toast.tsx into its own file
(fixes react-refresh/only-export-components warning)
- Toast.tsx: export ToastContext and ToastContextValue, remove useToast
- AdminAnalytics.tsx: remove unused startDate/endDate from useMemo deps
- BatchExpireInvoices.tsx: err: any -> err: unknown
- TokenAllowlist.tsx: err: any -> err: unknown in all catch blocks
- qrcode.ts: remove unused EC_LEVEL_M, getAlphanumericValue, getMode
Rust contracts:
- settlement/src/lib.rs: remove duplicate SettlementError enum (the
stale one with InsufficientApprovals=3); keep the correct definition
with AlreadyApproved=3 that the tests reference
---
comebackhere-frontend/src/App.tsx | 37 +++++++---
.../src/components/AdminAnalytics.tsx | 2 +-
.../src/components/BatchExpireInvoices.tsx | 4 +-
.../src/components/Toast.tsx | 10 ++-
.../src/components/TokenAllowlist.tsx | 12 ++--
.../src/components/TreasuryManager.tsx | 14 ++--
comebackhere-frontend/src/hooks/useInvoice.ts | 19 ++++-
comebackhere-frontend/src/hooks/useToast.ts | 9 +++
comebackhere-frontend/src/utils/qrcode.ts | 17 -----
comebackhere-frontend/src/utils/soroban.ts | 69 ++++++++++++++-----
comebackhere-frontend/src/utils/treasury.ts | 50 +++++++++++---
contracts/settlement/src/lib.rs | 10 ---
12 files changed, 168 insertions(+), 85 deletions(-)
create mode 100644 comebackhere-frontend/src/hooks/useToast.ts
diff --git a/comebackhere-frontend/src/App.tsx b/comebackhere-frontend/src/App.tsx
index ff26af5..c48881f 100644
--- a/comebackhere-frontend/src/App.tsx
+++ b/comebackhere-frontend/src/App.tsx
@@ -3,7 +3,8 @@ import { InvoicePayment } from "./components/InvoicePayment"
import { RefundRequest } from "./components/RefundRequest"
import { ComplianceManager } from "./components/ComplianceManager"
import { TokenAllowlist } from "./components/TokenAllowlist"
-import { WalletBar } from "./components/WalletBar"
+import { BatchExpireInvoices } from "./components/BatchExpireInvoices"
+import { TreasuryManager } from "./components/TreasuryManager"
import { useInvoice } from "./hooks/useInvoice"
import { useTheme } from "./hooks/useTheme"
import { useWallet } from "./hooks/useWallet"
@@ -11,9 +12,7 @@ import { CopyableText } from "./components/CopyableText"
import "./App.css"
import "./components/ErrorBoundary.css"
-const EXPECTED_NETWORK = import.meta.env.VITE_NETWORK_PASSPHRASE as string ?? "Standalone Network ; February 2025"
-
-type Tab = "payment" | "refund" | "compliance" | "tokens"
+type Tab = "payment" | "refund" | "compliance" | "tokens" | "batch-expire" | "treasury"
function RefundTab() {
const { invoice, loading, error, loadInvoice, refund } = useInvoice()
@@ -147,11 +146,35 @@ export default function App() {
Compliance
+
+
@@ -161,15 +184,13 @@ export default function App() {
) : tab === "tokens" ? (
- ) : (
+ ) : tab === "compliance" ? (
) : tab === "batch-expire" ? (
) : tab === "treasury" ? (
- ) : (
-
- )}
+ ) : null}
)
diff --git a/comebackhere-frontend/src/components/AdminAnalytics.tsx b/comebackhere-frontend/src/components/AdminAnalytics.tsx
index c6390d0..78c00c9 100644
--- a/comebackhere-frontend/src/components/AdminAnalytics.tsx
+++ b/comebackhere-frontend/src/components/AdminAnalytics.tsx
@@ -57,7 +57,7 @@ export function AdminAnalytics() {
const data = useMemo(() => {
return MOCK_DATA
- }, [startDate, endDate])
+ }, [])
const totalInvoices =
data.invoices.pending +
diff --git a/comebackhere-frontend/src/components/BatchExpireInvoices.tsx b/comebackhere-frontend/src/components/BatchExpireInvoices.tsx
index 3b250e5..0a31fe0 100644
--- a/comebackhere-frontend/src/components/BatchExpireInvoices.tsx
+++ b/comebackhere-frontend/src/components/BatchExpireInvoices.tsx
@@ -118,10 +118,10 @@ export function BatchExpireInvoices({ walletAddress }: BatchExpireInvoicesProps)
msg: `Invoice #${id} was not expired (status: ${updated.status})`,
})
}
- } catch (err: any) {
+ } catch (err: unknown) {
errorList.push({
id: String(id),
- msg: `Invoice #${id}: ${err?.message ?? "failed to verify"}`,
+ msg: `Invoice #${id}: ${err instanceof Error ? err.message : "failed to verify"}`,
})
}
done++
diff --git a/comebackhere-frontend/src/components/Toast.tsx b/comebackhere-frontend/src/components/Toast.tsx
index c47a3f5..c8661a9 100644
--- a/comebackhere-frontend/src/components/Toast.tsx
+++ b/comebackhere-frontend/src/components/Toast.tsx
@@ -1,4 +1,4 @@
-import { createContext, useCallback, useContext, useState, useEffect, type ReactNode } from "react"
+import { createContext, useCallback, useState, useEffect, type ReactNode } from "react"
type ToastType = "success" | "error" | "info"
@@ -16,6 +16,9 @@ interface ToastContextValue {
const ToastContext = createContext(null)
+export { ToastContext }
+export type { ToastContextValue }
+
let nextId = 0
const TOAST_ICONS: Record = {
@@ -78,8 +81,3 @@ export function ToastProvider({ children }: { children: ReactNode }) {
)
}
-export function useToast(): ToastContextValue {
- const ctx = useContext(ToastContext)
- if (!ctx) throw new Error("useToast must be used within a ToastProvider")
- return ctx
-}
diff --git a/comebackhere-frontend/src/components/TokenAllowlist.tsx b/comebackhere-frontend/src/components/TokenAllowlist.tsx
index d76598a..e3e769f 100644
--- a/comebackhere-frontend/src/components/TokenAllowlist.tsx
+++ b/comebackhere-frontend/src/components/TokenAllowlist.tsx
@@ -32,8 +32,8 @@ export function TokenAllowlist() {
const list = await getAllowedTokens()
setTokens(list)
setLoaded(true)
- } catch (err: any) {
- setLoadError(err?.message ?? "Failed to load tokens")
+ } catch (err: unknown) {
+ setLoadError(err instanceof Error ? err.message : "Failed to load tokens")
} finally {
setLoading(false)
}
@@ -53,8 +53,8 @@ export function TokenAllowlist() {
setAddSuccess(`Token added. tx: ${result.hash}`)
setNewToken("")
await loadTokens()
- } catch (err: any) {
- setAddError(err?.message ?? "Add failed")
+ } catch (err: unknown) {
+ setAddError(err instanceof Error ? err.message : "Add failed")
} finally {
setAdding(false)
}
@@ -69,8 +69,8 @@ export function TokenAllowlist() {
if (!result.success) throw new Error(result.error ?? "Remove failed")
setConfirm(null)
await loadTokens()
- } catch (err: any) {
- setRemoveError(err?.message ?? "Remove failed")
+ } catch (err: unknown) {
+ setRemoveError(err instanceof Error ? err.message : "Remove failed")
} finally {
setRemoving(false)
}
diff --git a/comebackhere-frontend/src/components/TreasuryManager.tsx b/comebackhere-frontend/src/components/TreasuryManager.tsx
index 0beae72..695cd11 100644
--- a/comebackhere-frontend/src/components/TreasuryManager.tsx
+++ b/comebackhere-frontend/src/components/TreasuryManager.tsx
@@ -41,11 +41,11 @@ async function callTreasuryAction(
walletAddress: string
): Promise<{ success: boolean; hash?: string; error?: string }> {
try {
- const { SorobanRpc, Contract, TransactionBuilder, BASE_FEE, nativeToScVal, Networks, Address } =
+ const { Contract, TransactionBuilder, assembleTransaction, BASE_FEE, nativeToScVal, Networks, Address, Server } =
await import("soroban-client")
const rpc = import.meta.env.VITE_SOROBAN_RPC as string
const passphrase = (import.meta.env.VITE_NETWORK_PASSPHRASE as string) ?? Networks.STANDALONE
- const server = new SorobanRpc.Server(rpc)
+ const server = new Server(rpc)
const contract = new Contract(TREASURY_CONTRACT)
const account = await server.getAccount(walletAddress)
@@ -64,7 +64,8 @@ async function callTreasuryAction(
nativeToScVal(stroops, { type: "i128" }),
]
- const tx = new TransactionBuilder(account as Parameters[0], {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const tx = new TransactionBuilder(account as any, {
fee: BASE_FEE,
networkPassphrase: passphrase,
})
@@ -73,13 +74,14 @@ async function callTreasuryAction(
.build()
const simulated = await server.simulateTransaction(tx)
- const prepare = SorobanRpc.assembleTransaction(tx, simulated)
+ const prepare = assembleTransaction(tx, passphrase, simulated)
const w = window as unknown as WindowWithFreighter
- const signed = await w.freighterApi?.signTransaction(prepare.toXDR(), {
+ const signed = await w.freighterApi?.signTransaction(prepare.build().toXDR(), {
networkPassphrase: passphrase,
})
if (!signed) throw new Error("Wallet not connected or signing was rejected")
- const result = await server.sendTransaction(signed)
+ const signedTx = TransactionBuilder.fromXDR(signed, passphrase)
+ const result = await server.sendTransaction(signedTx)
return { success: true, hash: result.hash }
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err)
diff --git a/comebackhere-frontend/src/hooks/useInvoice.ts b/comebackhere-frontend/src/hooks/useInvoice.ts
index ed5bf7a..2444309 100644
--- a/comebackhere-frontend/src/hooks/useInvoice.ts
+++ b/comebackhere-frontend/src/hooks/useInvoice.ts
@@ -1,6 +1,6 @@
import { useState, useCallback } from "react"
import type { Invoice, PaymentResult } from "../types"
-import { fetchInvoice, payInvoice, requestRefund, releaseEscrow } from "../utils/soroban"
+import { fetchInvoice, payInvoice, cancelInvoice, requestRefund, releaseEscrow } from "../utils/soroban"
const CONTRACT_ID = import.meta.env.VITE_INVOICE_CONTRACT_ID as string
@@ -10,6 +10,7 @@ interface UseInvoiceReturn {
error: string | null
loadInvoice: (id: number) => Promise
pay: (publicKey: string) => Promise
+ cancel: (publicKey: string) => Promise
refund: (publicKey: string) => Promise
release: (publicKey: string) => Promise
}
@@ -46,6 +47,20 @@ export function useInvoice(): UseInvoiceReturn {
[invoice, loadInvoice]
)
+ const cancel = useCallback(
+ async (publicKey: string): Promise => {
+ if (!invoice) {
+ return { success: false, error: "No invoice loaded" }
+ }
+ const result = await cancelInvoice(CONTRACT_ID, Number(invoice.id), publicKey)
+ if (result.success) {
+ await loadInvoice(Number(invoice.id))
+ }
+ return result
+ },
+ [invoice, loadInvoice]
+ )
+
const refund = useCallback(
async (publicKey: string): Promise => {
if (!invoice) {
@@ -78,5 +93,5 @@ export function useInvoice(): UseInvoiceReturn {
[invoice, loadInvoice]
)
- return { invoice, loading, error, loadInvoice, pay, refund, release }
+ return { invoice, loading, error, loadInvoice, pay, cancel, refund, release }
}
diff --git a/comebackhere-frontend/src/hooks/useToast.ts b/comebackhere-frontend/src/hooks/useToast.ts
new file mode 100644
index 0000000..401cfa7
--- /dev/null
+++ b/comebackhere-frontend/src/hooks/useToast.ts
@@ -0,0 +1,9 @@
+import { useContext } from "react"
+import { ToastContext } from "../components/Toast"
+import type { ToastContextValue } from "../components/Toast"
+
+export function useToast(): ToastContextValue {
+ const ctx = useContext(ToastContext)
+ if (!ctx) throw new Error("useToast must be used within a ToastProvider")
+ return ctx
+}
diff --git a/comebackhere-frontend/src/utils/qrcode.ts b/comebackhere-frontend/src/utils/qrcode.ts
index 05dcfee..bb2e9b5 100644
--- a/comebackhere-frontend/src/utils/qrcode.ts
+++ b/comebackhere-frontend/src/utils/qrcode.ts
@@ -1,20 +1,3 @@
-const EC_LEVEL_M = 0
-
-function getAlphanumericValue(ch: string): number {
- const code = ch.charCodeAt(0)
- if (code >= 48 && code <= 57) return code - 48
- if (code >= 65 && code <= 90) return code - 55
- const special = ' $%*+-./:'.indexOf(ch)
- if (special >= 0) return 36 + special
- return -1
-}
-
-function getMode(data: string): 'numeric' | 'alphanumeric' | 'byte' {
- if (/^\d+$/.test(data)) return 'numeric'
- if (/^[0-9A-Z $%*+\-./:]+$/.test(data)) return 'alphanumeric'
- return 'byte'
-}
-
function getVersion(data: string): number {
const len = new TextEncoder().encode(data).length
const capacities = [
diff --git a/comebackhere-frontend/src/utils/soroban.ts b/comebackhere-frontend/src/utils/soroban.ts
index 5fbd1ba..07f9f02 100644
--- a/comebackhere-frontend/src/utils/soroban.ts
+++ b/comebackhere-frontend/src/utils/soroban.ts
@@ -20,8 +20,13 @@ interface FreighterApi {
signTransaction: (xdr: string, opts: { networkPassphrase: string }) => Promise
}
+interface SorobanRpcApi {
+ assembleTransaction: (tx: unknown, sim: unknown) => { build: () => { toXDR: () => string } }
+}
+
interface WindowWithFreighter extends Window {
freighterApi?: FreighterApi
+ SorobanRpc?: SorobanRpcApi
}
export function getNetworkPassphrase(): string {
@@ -99,6 +104,28 @@ export async function payInvoice(contractId: string, invoiceId: number, publicKe
}
}
+export async function cancelInvoice(contractId: string, invoiceId: number, publicKey: string): Promise {
+ const server = getServer()
+ const freighter = (window as WindowWithFreighter).freighterApi
+ if (!freighter) return { success: false, error: "Freighter wallet not detected" }
+ try {
+ const tx = new TransactionBuilder(await server.getAccount(publicKey), {
+ fee: BASE_FEE, networkPassphrase: getNetworkPassphrase(),
+ })
+ .addOperation(
+ new Contract(contractId).call(
+ "cancel_invoice",
+ nativeToScVal(publicKey, { type: "address" }),
+ nativeToScVal(invoiceId, { type: "u64" })
+ )
+ )
+ .setTimeout(30).build() as Transaction
+ return { success: true, transaction_hash: await buildAndSend(server, tx, freighter) }
+ } catch (err: unknown) {
+ return { success: false, error: err instanceof Error ? err.message : "Cancel failed" }
+ }
+}
+
export async function requestRefund(contractId: string, invoiceId: number, publicKey: string): Promise {
const server = getServer()
const freighter = (window as WindowWithFreighter).freighterApi
@@ -138,20 +165,25 @@ export async function batchExpireInvoices(
.build()
const simulated = await server.simulateTransaction(tx)
- const { SorobanRpc } = window as any
-
- const prepare = SorobanRpc.assembleTransaction(tx, simulated)
- const signed = await (window as any).freighterApi.signTransaction(
- prepare.toXDR(),
+ const sorobanRpc = (window as WindowWithFreighter).SorobanRpc
+ if (!sorobanRpc) throw new Error("SorobanRpc not available on window")
+ const freighter = (window as WindowWithFreighter).freighterApi
+ if (!freighter) throw new Error("Freighter wallet not detected")
+
+ const prepare = sorobanRpc.assembleTransaction(tx, simulated)
+ const signed = await freighter.signTransaction(
+ prepare.build().toXDR(),
{ networkPassphrase: getNetworkPassphrase() }
)
- const txHash = await server.sendTransaction(signed)
+ const txHash = await server.sendTransaction(
+ TransactionBuilder.fromXDR(signed, getNetworkPassphrase()) as Transaction
+ )
return { success: true, transaction_hash: txHash.hash }
- } catch (err: any) {
+ } catch (err: unknown) {
return {
success: false,
- error: err?.message ?? err?.toString() ?? "Batch expire failed",
+ error: err instanceof Error ? err.message : String(err) || "Batch expire failed",
}
}
}
@@ -180,20 +212,25 @@ export async function releaseEscrow(
.build()
const simulated = await server.simulateTransaction(tx)
- const { SorobanRpc } = window as any
-
- const prepare = SorobanRpc.assembleTransaction(tx, simulated)
- const signed = await (window as any).freighterApi.signTransaction(
- prepare.toXDR(),
+ const sorobanRpc = (window as WindowWithFreighter).SorobanRpc
+ if (!sorobanRpc) throw new Error("SorobanRpc not available on window")
+ const freighter = (window as WindowWithFreighter).freighterApi
+ if (!freighter) throw new Error("Freighter wallet not detected")
+
+ const prepare = sorobanRpc.assembleTransaction(tx, simulated)
+ const signed = await freighter.signTransaction(
+ prepare.build().toXDR(),
{ networkPassphrase: getNetworkPassphrase() }
)
- const txHash = await server.sendTransaction(signed)
+ const txHash = await server.sendTransaction(
+ TransactionBuilder.fromXDR(signed, getNetworkPassphrase()) as Transaction
+ )
return { success: true, transaction_hash: txHash.hash }
- } catch (err: any) {
+ } catch (err: unknown) {
return {
success: false,
- error: err?.message ?? err?.toString() ?? "Release escrow failed",
+ error: err instanceof Error ? err.message : String(err) || "Release escrow failed",
}
}
}
diff --git a/comebackhere-frontend/src/utils/treasury.ts b/comebackhere-frontend/src/utils/treasury.ts
index 79e736d..a4f684a 100644
--- a/comebackhere-frontend/src/utils/treasury.ts
+++ b/comebackhere-frontend/src/utils/treasury.ts
@@ -12,17 +12,39 @@ const TREASURY_CONTRACT_ID =
const SOROBAN_RPC = import.meta.env.VITE_SOROBAN_RPC as string
const NETWORK_PASSPHRASE = import.meta.env.VITE_NETWORK_PASSPHRASE as string
+interface FreighterApi {
+ getAddress: () => Promise<{ address: string }>
+ signTransaction: (xdr: string, opts: { networkPassphrase: string }) => Promise
+}
+
+interface SorobanRpcApi {
+ Server: new (url: string) => {
+ getAccount: (address: string) => Promise
+ simulateTransaction: (tx: unknown) => Promise
+ sendTransaction: (tx: unknown) => Promise<{ hash: string }>
+ }
+ assembleTransaction: (tx: unknown, sim: unknown) => { toXDR: () => string }
+}
+
+interface WindowWithWallet extends Window {
+ freighterApi?: FreighterApi
+ SorobanRpc?: SorobanRpcApi
+}
+
function getNetworkPassphrase(): string {
return NETWORK_PASSPHRASE || Networks.STANDALONE
}
function getServer() {
- const { SorobanRpc } = window as any
- return new SorobanRpc.Server(SOROBAN_RPC)
+ const sorobanRpc = (window as WindowWithWallet).SorobanRpc
+ if (!sorobanRpc) throw new Error("SorobanRpc not available on window")
+ return new sorobanRpc.Server(SOROBAN_RPC)
}
async function getPublicKey(): Promise {
- const { address } = await (window as any).freighterApi.getAddress()
+ const freighter = (window as WindowWithWallet).freighterApi
+ if (!freighter) throw new Error("Freighter wallet not detected")
+ const { address } = await freighter.getAddress()
return address
}
@@ -34,14 +56,15 @@ export async function getAllowedTokens(): Promise {
const contract = new Contract(TREASURY_CONTRACT_ID)
const result = await server.simulateTransaction(
- new TransactionBuilder(await server.getAccount(TREASURY_CONTRACT_ID), {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ new TransactionBuilder(await server.getAccount(TREASURY_CONTRACT_ID) as any, {
fee: BASE_FEE,
networkPassphrase: getNetworkPassphrase(),
})
.addOperation(contract.call("get_allowed_tokens"))
.setTimeout(30)
.build()
- )
+ ) as { result?: { retval?: xdr.ScVal } }
if (!result.result?.retval) return []
@@ -63,9 +86,15 @@ async function submitTokenOp(
const server = getServer()
const contract = new Contract(TREASURY_CONTRACT_ID)
const publicKey = await getPublicKey()
+ const freighter = (window as WindowWithWallet).freighterApi
+ if (!freighter) throw new Error("Freighter wallet not detected")
+ const sorobanRpc = (window as WindowWithWallet).SorobanRpc
+ if (!sorobanRpc) throw new Error("SorobanRpc not available on window")
+
const args = [nativeToScVal(tokenAddress, { type: "address" })]
- const tx = new TransactionBuilder(await server.getAccount(publicKey), {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const tx = new TransactionBuilder(await server.getAccount(publicKey) as any, {
fee: BASE_FEE,
networkPassphrase: getNetworkPassphrase(),
})
@@ -74,17 +103,16 @@ async function submitTokenOp(
.build()
const simulated = await server.simulateTransaction(tx)
- const { SorobanRpc } = window as any
- const prepare = SorobanRpc.assembleTransaction(tx, simulated)
- const signed = await (window as any).freighterApi.signTransaction(
+ const prepare = sorobanRpc.assembleTransaction(tx, simulated)
+ const signed = await freighter.signTransaction(
prepare.toXDR(),
{ networkPassphrase: getNetworkPassphrase() }
)
const txHash = await server.sendTransaction(signed)
return { success: true, hash: txHash.hash }
- } catch (err: any) {
- return { success: false, error: err?.message ?? "Transaction failed" }
+ } catch (err: unknown) {
+ return { success: false, error: err instanceof Error ? err.message : "Transaction failed" }
}
}
diff --git a/contracts/settlement/src/lib.rs b/contracts/settlement/src/lib.rs
index 03dc828..63febaf 100644
--- a/contracts/settlement/src/lib.rs
+++ b/contracts/settlement/src/lib.rs
@@ -2,16 +2,6 @@
use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, Bytes, Env, Vec};
-#[contracterror]
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-#[repr(u32)]
-pub enum SettlementError {
- NotFound = 1,
- NotPending = 2,
- InsufficientApprovals = 3,
- Unauthorized = 4,
-}
-
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SettlementStatus {
From 8d8582b71ca7b2f83361446074e2fed292dd6714 Mon Sep 17 00:00:00 2001
From: Ugwoke Levi <113690452+levoski1@users.noreply.github.com>
Date: Mon, 6 Jul 2026 15:56:30 +0000
Subject: [PATCH 2/3] fix: resolve remaining CI failures
- package-lock.json: regenerate to sync esbuild@0.28.1 entries; the
stale lockfile was missing all @esbuild/* platform packages at 0.28.1,
causing npm ci to fail with EUSAGE on the build-and-lint job
- scripts: add execute bit to lint-docs.sh, generate_abi_metadata.sh,
check_abi_snapshot_hygiene.sh, coverage.sh; these were missing +x so
the lint-docs and check-abi-snapshots CI jobs exited 126/127
- COMEBACKHERE-contracts (compliance, invoice, treasury): replace all
env.register_contract(None, X) with env.register(X, ()); the old API
is deprecated and -D warnings turns deprecations into hard errors
- contracts/invoice, contracts/settlement: same register_contract ->
register fix for our own contracts workspace (used by Backend Tests)
---
.../contracts/compliance/src/lib.rs | 4 ++--
.../contracts/invoice/src/lib.rs | 16 ++++++++--------
.../contracts/invoice/src/test.rs | 2 +-
.../contracts/invoice/src/tests.rs | 4 ++--
.../src/integration_dispute_lifecycle.rs | 2 +-
.../src/integration_settlement_multisig.rs | 2 +-
.../contracts/treasury/src/lib.rs | 2 +-
contracts/invoice/src/lib.rs | 2 +-
contracts/settlement/src/lib.rs | 2 +-
scripts/check_abi_snapshot_hygiene.sh | 0
scripts/coverage.sh | 0
scripts/generate_abi_metadata.sh | 0
scripts/lint-docs.sh | 0
13 files changed, 18 insertions(+), 18 deletions(-)
mode change 100644 => 100755 scripts/check_abi_snapshot_hygiene.sh
mode change 100644 => 100755 scripts/coverage.sh
mode change 100644 => 100755 scripts/generate_abi_metadata.sh
mode change 100644 => 100755 scripts/lint-docs.sh
diff --git a/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs b/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs
index 31a815b..262e17f 100644
--- a/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs
+++ b/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs
@@ -121,7 +121,7 @@ impl ComplianceContract {
Ok(())
}
- pub fn accept_admin(_e: Env, new_admin: Address) {
+ pub fn accept_admin(e: Env, new_admin: Address) -> Result<(), ContractError> {
new_admin.require_auth();
let pending: Address = e
.storage()
@@ -183,7 +183,7 @@ mod tests {
fn setup(ts: u64) -> (Env, Address, Address, Address) {
let e = Env::default();
e.mock_all_auths();
- let contract_id = e.register_contract(None, ComplianceContract);
+ let contract_id = e.register(ComplianceContract, ());
let admin = Address::generate(&e);
let addr = Address::generate(&e);
ComplianceContractClient::new(&e, &contract_id).initialize(&admin);
diff --git a/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs b/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs
index 434d586..4a9d167 100644
--- a/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs
+++ b/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs
@@ -401,7 +401,7 @@ mod tests {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
InvoiceContractClient::new(&env, &contract_id).initialize(&admin);
env.ledger().with_mut(|li| li.timestamp = ts);
(env, contract_id, admin)
@@ -469,7 +469,7 @@ mod tests {
let token = Address::generate(&env);
env.ledger().set_timestamp(1000);
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&env, &contract_id);
client.initialize(&admin);
@@ -489,7 +489,7 @@ mod tests {
let token = Address::generate(&env);
env.ledger().set_timestamp(1000);
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&env, &contract_id);
client.initialize(&admin);
@@ -509,7 +509,7 @@ mod tests {
let admin = Address::generate(&env);
let non_admin = Address::generate(&env);
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&env, &contract_id);
client.initialize(&admin);
@@ -524,7 +524,7 @@ mod tests {
let admin = Address::generate(&env);
let non_admin = Address::generate(&env);
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&env, &contract_id);
client.initialize(&admin);
@@ -582,8 +582,8 @@ mod tests {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
- let invoice_cid = env.register_contract(None, InvoiceContract);
- let treasury_cid = env.register_contract(None, TreasuryStub);
+ let invoice_cid = env.register(InvoiceContract, ());
+ let treasury_cid = env.register(TreasuryStub, ());
let invoice_client = InvoiceContractClient::new(&env, &invoice_cid);
invoice_client.initialize(&admin);
invoice_client.set_treasury(&admin, &treasury_cid);
@@ -640,7 +640,7 @@ mod tests {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
- let invoice_cid = env.register_contract(None, InvoiceContract);
+ let invoice_cid = env.register(InvoiceContract, ());
let invoice_client = InvoiceContractClient::new(&env, &invoice_cid);
invoice_client.initialize(&admin);
env.ledger().with_mut(|li| li.timestamp = 1000);
diff --git a/COMEBACKHERE-contracts/contracts/invoice/src/test.rs b/COMEBACKHERE-contracts/contracts/invoice/src/test.rs
index 8da6f1a..04fd13f 100644
--- a/COMEBACKHERE-contracts/contracts/invoice/src/test.rs
+++ b/COMEBACKHERE-contracts/contracts/invoice/src/test.rs
@@ -9,7 +9,7 @@ fn setup_test() -> (Env, Address, Address, InvoiceContractClient) {
let admin = Address::generate(&env);
let merchant = Address::generate(&env);
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&env, &contract_id);
client.initialize(&admin);
diff --git a/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs b/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs
index dfe8d6a..85a2f8c 100644
--- a/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs
+++ b/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs
@@ -8,7 +8,7 @@ fn test_create_invoice_expiry_overflow() {
let admin = Address::generate(&e);
let merchant = Address::generate(&e);
- let contract_id = e.register_contract(None, InvoiceContract);
+ let contract_id = e.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&e, &contract_id);
client.initialize(&admin);
@@ -44,7 +44,7 @@ fn test_create_invoice_success() {
base_reserve: 10,
});
- let contract_id = e.register_contract(None, InvoiceContract);
+ let contract_id = e.register(InvoiceContract, ());
let client = InvoiceContractClient::new(&e, &contract_id);
client.initialize(&admin);
diff --git a/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs b/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs
index 63159b6..570ce0e 100644
--- a/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs
+++ b/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs
@@ -6,7 +6,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, Env};
fn setup_env() -> (Env, Address) {
let env = Env::default();
env.mock_all_auths();
- let contract_id = env.register_contract(None, TreasuryContract);
+ let contract_id = env.register(TreasuryContract, ());
(env, contract_id)
}
diff --git a/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs b/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs
index 7b47286..391a24d 100644
--- a/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs
+++ b/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs
@@ -6,7 +6,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, Env};
fn setup_env() -> (Env, Address) {
let env = Env::default();
env.mock_all_auths();
- let contract_id = env.register_contract(None, TreasuryContract);
+ let contract_id = env.register(TreasuryContract, ());
(env, contract_id)
}
diff --git a/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs b/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs
index 9402cf1..6fe129d 100644
--- a/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs
+++ b/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs
@@ -384,7 +384,7 @@ mod tests {
fn setup() -> (Env, soroban_sdk::Address) {
let e = Env::default();
e.mock_all_auths();
- let contract_id = e.register_contract(None, TreasuryContract);
+ let contract_id = e.register(TreasuryContract, ());
(e, contract_id)
}
diff --git a/contracts/invoice/src/lib.rs b/contracts/invoice/src/lib.rs
index 964f669..82be1e9 100644
--- a/contracts/invoice/src/lib.rs
+++ b/contracts/invoice/src/lib.rs
@@ -220,7 +220,7 @@ mod tests {
fn setup() -> (Env, Address, Address) {
let env = Env::default();
env.mock_all_auths();
- let contract_id = env.register_contract(None, InvoiceContract);
+ let contract_id = env.register(InvoiceContract, ());
let admin = Address::generate(&env);
InvoiceContractClient::new(&env, &contract_id).initialize(&admin);
env.ledger().set_timestamp(1000);
diff --git a/contracts/settlement/src/lib.rs b/contracts/settlement/src/lib.rs
index 63febaf..cc82c0e 100644
--- a/contracts/settlement/src/lib.rs
+++ b/contracts/settlement/src/lib.rs
@@ -166,7 +166,7 @@ mod tests {
fn setup() -> (Env, Address) {
let e = Env::default();
e.mock_all_auths();
- let id = e.register_contract(None, SettlementContract);
+ let id = e.register(SettlementContract, ());
(e, id)
}
diff --git a/scripts/check_abi_snapshot_hygiene.sh b/scripts/check_abi_snapshot_hygiene.sh
old mode 100644
new mode 100755
diff --git a/scripts/coverage.sh b/scripts/coverage.sh
old mode 100644
new mode 100755
diff --git a/scripts/generate_abi_metadata.sh b/scripts/generate_abi_metadata.sh
old mode 100644
new mode 100755
diff --git a/scripts/lint-docs.sh b/scripts/lint-docs.sh
old mode 100644
new mode 100755
From c8b8926a10e8e29e0eb227298df0c545b882ebb1 Mon Sep 17 00:00:00 2001
From: Ugwoke Levi <113690452+levoski1@users.noreply.github.com>
Date: Mon, 6 Jul 2026 16:11:19 +0000
Subject: [PATCH 3/3] fix: resolve all remaining CI failures
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
build-and-lint:
- Upgrade vite ^5.2.0 → ^6.0.0 in package.json; vitest@4 declares
peerDep vite@^6|^7|^8, causing npm to resolve esbuild@0.28.1 which
was missing from the lockfile — regenerate package-lock.json
unit (Backend Tests):
- contracts/invoice and contracts/settlement use soroban-sdk v21 which
only has register_contract(); already reverted in previous commit
check-abi-snapshots / generate-abi-metadata:
- generate_abi_metadata.sh looked for COMEBACKHERE-contracts at
$ROOT_DIR/../ but CI checks it out into $ROOT_DIR/COMEBACKHERE-contracts
(same directory as the repo checkout); now probes both locations
contract coverage:
- cargo-llvm-cov does not accept --lcov and --html in the same
invocation; split into two separate cargo llvm-cov calls
lint-docs:
- Add MD036 false (emphasis-as-heading), MD041 false (first-line-h1),
MD060 false (table-column-style) to .markdownlint.json — these
rules fire on intentional doc patterns (bold labels, PR template
section headings, wide table rows)
- Convert **Bold** section labels to #### headings in api-reference.md
and contract-interaction-guide.md
- Apply markdownlint --fix to all docs (blank lines, table separators)
---
.github/pull_request_template.md | 2 +
.github/workflows/ci-coverage.yml | 4 +-
.markdownlint.json | 3 +
README.md | 2 +
SECURITY.md | 12 +-
comebackhere-frontend/package-lock.json | 358 +++++++++++-------
comebackhere-frontend/package.json | 2 +-
.../tsconfig.app.tsbuildinfo | 2 +-
contracts/invoice/src/lib.rs | 2 +-
contracts/settlement/src/lib.rs | 2 +-
docs/MAINNET_DEPLOYMENT.md | 2 +-
docs/abi-snapshot-workflow.md | 2 +-
docs/api-reference.md | 34 +-
docs/contract-interaction-guide.md | 44 +--
docs/error-codes.md | 6 +-
docs/troubleshooting.md | 2 +-
scripts/generate_abi_metadata.sh | 17 +-
tests/README.md | 2 +-
18 files changed, 310 insertions(+), 188 deletions(-)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 488f3e3..575006f 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,3 +1,5 @@
+# Pull Request
+
## Summary
- Describe the purpose of this PR in one or two sentences.
diff --git a/.github/workflows/ci-coverage.yml b/.github/workflows/ci-coverage.yml
index 9928fba..545ca2f 100644
--- a/.github/workflows/ci-coverage.yml
+++ b/.github/workflows/ci-coverage.yml
@@ -47,7 +47,9 @@ jobs:
run: |
cargo llvm-cov \
--workspace \
- --lcov --output-path ../lcov.info \
+ --lcov --output-path ../lcov.info
+ cargo llvm-cov \
+ --workspace \
--html --output-dir ../coverage-html
- name: Extract coverage percentage
diff --git a/.markdownlint.json b/.markdownlint.json
index 433358b..b5c50c4 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -6,7 +6,10 @@
"MD013": false,
"MD024": { "siblings_only": true },
"MD033": false,
+ "MD036": false,
"MD040": false,
+ "MD041": false,
+ "MD060": false,
"no-hard-tabs": true,
"no-trailing-spaces": true,
"no-multiple-blanks": true,
diff --git a/README.md b/README.md
index 398f86d..a5eae5a 100644
--- a/README.md
+++ b/README.md
@@ -48,10 +48,12 @@ docker-compose up -d
```
This starts:
+
- **Soroban Node**: Stellar quickstart (Horizon at `http://localhost:8000`)
- **Redis**: Event consumer backing service (port 6379)
Check service health:
+
```sh
docker-compose ps
curl http://localhost:8000/health
diff --git a/SECURITY.md b/SECURITY.md
index 32fe84d..7f8f2d9 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -5,7 +5,7 @@
If you discover a security vulnerability in the COMEBACKHERE Protocol, please
report it responsibly. **Do not open a public issue.**
-Send an email to **security@comebackhere.io** with the following details:
+Send an email to **** with the following details:
- A description of the vulnerability and its potential impact.
- Step-by-step instructions to reproduce the issue.
@@ -20,7 +20,7 @@ You may encrypt your report using our PGP key, available at
The following components are in scope for responsible disclosure:
| Component | Repository / Location |
-|---|---|
+| --- | --- |
| Soroban smart contracts | `COMEBACKHERE-contracts/` and `contracts/` |
| Backend API | `comebackhere-backend` (separate repo) |
| Frontend application | `frontend/` and `comebackhere-frontend/` |
@@ -38,7 +38,7 @@ The following components are in scope for responsible disclosure:
## Response SLA
| Stage | Timeline |
-|---|---|
+| --- | --- |
| Acknowledgement of report | Within **48 hours** |
| Initial triage and severity assessment | Within **5 business days** |
| Patch development and internal review | Within **30 days** for critical/high severity |
@@ -63,7 +63,7 @@ We follow a four-tier severity model:
We offer bounty rewards for verified vulnerabilities based on severity:
| Severity | Reward Range |
-|---|---|
+| --- | --- |
| Critical | $5,000 – $25,000 |
| High | $2,000 – $5,000 |
| Medium | $500 – $2,000 |
@@ -95,12 +95,12 @@ authorized. We will not pursue legal action against researchers who:
## Contact
-- **Email:** security@comebackhere.io
+- **Email:**
- **PGP Key:** `https://comebackhere.io/.well-known/pgp-key.txt`
## Supported Versions
| Version | Supported |
-|---|---|
+| --- | --- |
| Latest on `main` | Yes |
| Previous releases | Best-effort, critical fixes only |
diff --git a/comebackhere-frontend/package-lock.json b/comebackhere-frontend/package-lock.json
index 9a9aab2..a956aed 100644
--- a/comebackhere-frontend/package-lock.json
+++ b/comebackhere-frontend/package-lock.json
@@ -28,7 +28,7 @@
"eslint-plugin-react-refresh": "^0.4.6",
"jsdom": "^29.1.1",
"typescript": "^5.4.0",
- "vite": "^5.2.0",
+ "vite": "^6.0.0",
"vitest": "^4.1.9"
}
},
@@ -603,9 +603,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
- "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
"cpu": [
"ppc64"
],
@@ -616,13 +616,13 @@
"aix"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
- "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
"cpu": [
"arm"
],
@@ -633,13 +633,13 @@
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
- "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
"cpu": [
"arm64"
],
@@ -650,13 +650,13 @@
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
- "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
"cpu": [
"x64"
],
@@ -667,13 +667,13 @@
"android"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
- "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
"cpu": [
"arm64"
],
@@ -684,13 +684,13 @@
"darwin"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
- "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
"cpu": [
"x64"
],
@@ -701,13 +701,13 @@
"darwin"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
- "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
"cpu": [
"arm64"
],
@@ -718,13 +718,13 @@
"freebsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
- "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
"cpu": [
"x64"
],
@@ -735,13 +735,13 @@
"freebsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
- "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
"cpu": [
"arm"
],
@@ -752,13 +752,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
- "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
"cpu": [
"arm64"
],
@@ -769,13 +769,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
- "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
"cpu": [
"ia32"
],
@@ -786,13 +786,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
- "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
"cpu": [
"loong64"
],
@@ -803,13 +803,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
- "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
"cpu": [
"mips64el"
],
@@ -820,13 +820,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
- "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
"cpu": [
"ppc64"
],
@@ -837,13 +837,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
- "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
"cpu": [
"riscv64"
],
@@ -854,13 +854,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
- "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
"cpu": [
"s390x"
],
@@ -871,13 +871,13 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
- "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
"cpu": [
"x64"
],
@@ -888,13 +888,30 @@
"linux"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
- "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
"cpu": [
"x64"
],
@@ -905,13 +922,30 @@
"netbsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
- "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
"cpu": [
"x64"
],
@@ -922,13 +956,30 @@
"openbsd"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
- "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
"cpu": [
"x64"
],
@@ -939,13 +990,13 @@
"sunos"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
- "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
"cpu": [
"arm64"
],
@@ -956,13 +1007,13 @@
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
- "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
"cpu": [
"ia32"
],
@@ -973,13 +1024,13 @@
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
- "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
"cpu": [
"x64"
],
@@ -990,7 +1041,7 @@
"win32"
],
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/@eslint-community/eslint-utils": {
@@ -3273,9 +3324,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.21.5",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
- "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -3283,32 +3334,35 @@
"esbuild": "bin/esbuild"
},
"engines": {
- "node": ">=12"
+ "node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.21.5",
- "@esbuild/android-arm": "0.21.5",
- "@esbuild/android-arm64": "0.21.5",
- "@esbuild/android-x64": "0.21.5",
- "@esbuild/darwin-arm64": "0.21.5",
- "@esbuild/darwin-x64": "0.21.5",
- "@esbuild/freebsd-arm64": "0.21.5",
- "@esbuild/freebsd-x64": "0.21.5",
- "@esbuild/linux-arm": "0.21.5",
- "@esbuild/linux-arm64": "0.21.5",
- "@esbuild/linux-ia32": "0.21.5",
- "@esbuild/linux-loong64": "0.21.5",
- "@esbuild/linux-mips64el": "0.21.5",
- "@esbuild/linux-ppc64": "0.21.5",
- "@esbuild/linux-riscv64": "0.21.5",
- "@esbuild/linux-s390x": "0.21.5",
- "@esbuild/linux-x64": "0.21.5",
- "@esbuild/netbsd-x64": "0.21.5",
- "@esbuild/openbsd-x64": "0.21.5",
- "@esbuild/sunos-x64": "0.21.5",
- "@esbuild/win32-arm64": "0.21.5",
- "@esbuild/win32-ia32": "0.21.5",
- "@esbuild/win32-x64": "0.21.5"
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
}
},
"node_modules/escalade": {
@@ -5892,21 +5946,24 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "5.4.21",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
- "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
+ "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "esbuild": "^0.21.3",
- "postcss": "^8.4.43",
- "rollup": "^4.20.0"
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^18.0.0 || >=20.0.0"
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -5915,19 +5972,25 @@
"fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": "^18.0.0 || >=20.0.0",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
- "terser": "^5.4.0"
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
+ "jiti": {
+ "optional": true
+ },
"less": {
"optional": true
},
@@ -5948,9 +6011,46 @@
},
"terser": {
"optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
}
}
},
+ "node_modules/vite/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/vitest": {
"version": "4.1.9",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz",
diff --git a/comebackhere-frontend/package.json b/comebackhere-frontend/package.json
index c38c4a0..836b04d 100644
--- a/comebackhere-frontend/package.json
+++ b/comebackhere-frontend/package.json
@@ -33,7 +33,7 @@
"eslint-plugin-react-refresh": "^0.4.6",
"jsdom": "^29.1.1",
"typescript": "^5.4.0",
- "vite": "^5.2.0",
+ "vite": "^6.0.0",
"vitest": "^4.1.9"
}
}
diff --git a/comebackhere-frontend/tsconfig.app.tsbuildinfo b/comebackhere-frontend/tsconfig.app.tsbuildinfo
index 06ee151..db73193 100644
--- a/comebackhere-frontend/tsconfig.app.tsbuildinfo
+++ b/comebackhere-frontend/tsconfig.app.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/ComplianceManager.tsx","./src/components/InvoicePayment.tsx","./src/components/PayConfirmationModal.tsx","./src/components/RefundConfirmationModal.tsx","./src/components/RefundRequest.tsx","./src/components/Skeleton.tsx","./src/components/StatusBadge.tsx","./src/components/TransactionHistory.tsx","./src/components/WalletBar.tsx","./src/hooks/useInvoice.ts","./src/hooks/useTheme.ts","./src/hooks/useWallet.ts","./src/tests/Skeleton.test.tsx","./src/tests/WalletBar.test.tsx","./src/tests/setup.ts","./src/types/index.ts","./src/utils/compliance.ts","./src/utils/soroban.ts"],"version":"5.9.3"}
\ No newline at end of file
+{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/AdminAnalytics.tsx","./src/components/BatchExpireInvoices.tsx","./src/components/CancelConfirmationModal.tsx","./src/components/ComplianceManager.tsx","./src/components/CopyableText.tsx","./src/components/ErrorBoundary.tsx","./src/components/EscrowRelease.tsx","./src/components/InvoicePayment.tsx","./src/components/InvoiceQRCode.tsx","./src/components/PayConfirmationModal.tsx","./src/components/RefundConfirmationModal.tsx","./src/components/RefundRequest.tsx","./src/components/Skeleton.tsx","./src/components/StatusBadge.tsx","./src/components/Toast.tsx","./src/components/TokenAllowlist.tsx","./src/components/TransactionHistory.tsx","./src/components/TreasuryManager.tsx","./src/components/WalletBar.tsx","./src/hooks/useInvoice.ts","./src/hooks/useTheme.ts","./src/hooks/useToast.ts","./src/hooks/useWallet.ts","./src/tests/Skeleton.test.tsx","./src/tests/WalletBar.test.tsx","./src/tests/setup.ts","./src/types/index.ts","./src/utils/compliance.ts","./src/utils/qrcode.ts","./src/utils/soroban.ts","./src/utils/treasury.ts"],"version":"5.9.3"}
\ No newline at end of file
diff --git a/contracts/invoice/src/lib.rs b/contracts/invoice/src/lib.rs
index 82be1e9..964f669 100644
--- a/contracts/invoice/src/lib.rs
+++ b/contracts/invoice/src/lib.rs
@@ -220,7 +220,7 @@ mod tests {
fn setup() -> (Env, Address, Address) {
let env = Env::default();
env.mock_all_auths();
- let contract_id = env.register(InvoiceContract, ());
+ let contract_id = env.register_contract(None, InvoiceContract);
let admin = Address::generate(&env);
InvoiceContractClient::new(&env, &contract_id).initialize(&admin);
env.ledger().set_timestamp(1000);
diff --git a/contracts/settlement/src/lib.rs b/contracts/settlement/src/lib.rs
index cc82c0e..63febaf 100644
--- a/contracts/settlement/src/lib.rs
+++ b/contracts/settlement/src/lib.rs
@@ -166,7 +166,7 @@ mod tests {
fn setup() -> (Env, Address) {
let e = Env::default();
e.mock_all_auths();
- let id = e.register(SettlementContract, ());
+ let id = e.register_contract(None, SettlementContract);
(e, id)
}
diff --git a/docs/MAINNET_DEPLOYMENT.md b/docs/MAINNET_DEPLOYMENT.md
index 2f10760..ddcae11 100644
--- a/docs/MAINNET_DEPLOYMENT.md
+++ b/docs/MAINNET_DEPLOYMENT.md
@@ -55,7 +55,7 @@ upgrade, or modify mainnet contracts.
### Signer Roles
| Role | Count | Responsibility |
-|------|-------|----------------|
+| ------ | ------- | ---------------- |
| **Lead Deployer** | 1 | Prepares the deployment issue, builds release artifacts, submits the deployment transaction after all approvals are collected. Does NOT hold sole signing authority. |
| **Security Reviewer** | 1–2 | Reviews the target commit for security vulnerabilities, verifies WASM hashes match the audited source, and signs off on the security checklist. |
| **Treasury Signer** | 2+ | Holds custody of treasury signing keys. Must independently verify artifact hashes before co-signing the deployment transaction. |
diff --git a/docs/abi-snapshot-workflow.md b/docs/abi-snapshot-workflow.md
index e404395..9b5e8f1 100644
--- a/docs/abi-snapshot-workflow.md
+++ b/docs/abi-snapshot-workflow.md
@@ -68,7 +68,7 @@ git commit -m "chore: update ABI snapshots"
The `comebackhere-backend` service reads `abis/*.json` at startup to build its Soroban contract clients. Stale snapshots cause:
| Scenario | Downstream impact |
-|---|---|
+| --- | --- |
| New function added to contract but missing from snapshot | Backend cannot call the new function; API endpoints that depend on it return errors |
| Function signature changed but snapshot not updated | Backend sends malformed transactions; Soroban RPC rejects them with simulation failures |
| Function removed from contract but still in snapshot | Backend attempts calls to a non-existent function; transactions fail at the ledger level |
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 706cf88..c6d9295 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -27,7 +27,7 @@ Returns service health status.
Fetch the on-chain status of an invoice by its numeric ID.
-**Path parameters**
+#### Path parameters
| Parameter | Type | Description |
| --------- | ------ | ----------------------- |
@@ -42,7 +42,7 @@ Fetch the on-chain status of an invoice by its numeric ID.
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | ---------------------------------------- |
@@ -57,7 +57,7 @@ Fetch the on-chain status of an invoice by its numeric ID.
Create a new invoice by submitting `create_invoice` to the Soroban RPC.
-**Request body**
+#### Request body
```json
{
@@ -84,7 +84,7 @@ Create a new invoice by submitting `create_invoice` to the Soroban RPC.
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | -------------------------------------------------------------- |
@@ -102,7 +102,7 @@ Create a new invoice by submitting `create_invoice` to the Soroban RPC.
Raise a dispute linked to a settlement, transitioning it to `OnHold`.
-**Request body**
+#### Request body
```json
{
@@ -130,7 +130,7 @@ Raise a dispute linked to a settlement, transitioning it to `OnHold`.
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | -------------------------------------------------------------- |
@@ -162,7 +162,7 @@ Returns all settlements with `Pending` status from the indexed database.
]
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | ----------------------- |
@@ -174,7 +174,7 @@ Returns all settlements with `Pending` status from the indexed database.
Approve a pending settlement by submitting `approve_settlement` to the treasury contract.
-**Request body**
+#### Request body
```json
{ "settlement_id": 1 }
@@ -199,7 +199,7 @@ Approve a pending settlement by submitting `approve_settlement` to the treasury
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | ----------------------------------------------- |
@@ -213,7 +213,7 @@ Approve a pending settlement by submitting `approve_settlement` to the treasury
Execute a fully-approved settlement after verifying the treasury USDC balance.
-**Request body**
+#### Request body
```json
{
@@ -238,7 +238,7 @@ Execute a fully-approved settlement after verifying the treasury USDC balance.
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | -------------------------------------------------- |
@@ -260,7 +260,7 @@ Returns the current approval threshold from the treasury contract.
{ "threshold": 2 }
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | --------------------------------------- |
@@ -274,7 +274,7 @@ Returns the current approval threshold from the treasury contract.
Update the treasury approval threshold.
-**Request body**
+#### Request body
```json
{ "threshold": 3 }
@@ -293,7 +293,7 @@ Update the treasury approval threshold.
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | ----------------------------------------------- |
@@ -316,7 +316,7 @@ Returns the current invoice grace window in seconds.
{ "grace_window_seconds": 86400 }
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | --------------------------------------- |
@@ -330,7 +330,7 @@ Returns the current invoice grace window in seconds.
Update the invoice grace window.
-**Request body**
+#### Request body
```json
{ "grace_window_seconds": 172800 }
@@ -349,7 +349,7 @@ Update the invoice grace window.
}
```
-**Errors**
+#### Errors
| Status | Description |
| ------ | ----------------------------------------------- |
diff --git a/docs/contract-interaction-guide.md b/docs/contract-interaction-guide.md
index b19931b..42a5054 100644
--- a/docs/contract-interaction-guide.md
+++ b/docs/contract-interaction-guide.md
@@ -27,7 +27,7 @@ Placeholder values used throughout:
### Create an invoice
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -44,7 +44,7 @@ soroban contract invoke \
--nonce 1
```
-**API**
+#### API
```sh
curl -X POST http://localhost:3000/invoices \
@@ -63,7 +63,7 @@ Response includes `invoice_id` to use in subsequent calls.
### Get invoice status
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -75,7 +75,7 @@ soroban contract invoke \
--invoice_id 1
```
-**API**
+#### API
```sh
curl http://localhost:3000/invoices/1
@@ -85,7 +85,7 @@ curl http://localhost:3000/invoices/1
### Mark invoice as paid
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -105,7 +105,7 @@ Calling `raise_dispute` on the invoice contract atomically calls
`raise_dispute` on the treasury contract, placing the referenced
settlement `OnHold`.
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -120,7 +120,7 @@ soroban contract invoke \
--reason 1
```
-**API**
+#### API
```sh
curl -X POST http://localhost:3000/disputes \
@@ -153,7 +153,7 @@ soroban contract invoke \
### Propose a settlement
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -174,7 +174,7 @@ Returns the `settlement_id`.
### Approve a settlement
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -187,7 +187,7 @@ soroban contract invoke \
--settlement_id 1
```
-**API**
+#### API
```sh
curl -X POST http://localhost:3000/api/treasury/approve-settlement \
@@ -199,7 +199,7 @@ curl -X POST http://localhost:3000/api/treasury/approve-settlement \
### Execute a settlement
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -213,7 +213,7 @@ soroban contract invoke \
--token_contract CUSDC...
```
-**API**
+#### API
The execute endpoint validates the treasury USDC balance before submitting.
@@ -227,7 +227,7 @@ curl -X POST http://localhost:3000/api/treasury/execute-settlement \
### Get / set approval threshold
-**soroban-cli — read**
+#### soroban-cli — read
```sh
soroban contract invoke \
@@ -238,7 +238,7 @@ soroban contract invoke \
-- get_threshold
```
-**soroban-cli — update**
+#### soroban-cli — update
```sh
soroban contract invoke \
@@ -251,13 +251,13 @@ soroban contract invoke \
--new_threshold 3
```
-**API — read**
+#### API — read
```sh
curl http://localhost:3000/api/treasury/threshold
```
-**API — update**
+#### API — update
```sh
curl -X POST http://localhost:3000/api/treasury/threshold \
@@ -271,7 +271,7 @@ curl -X POST http://localhost:3000/api/treasury/threshold \
### Allow an address
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -288,7 +288,7 @@ soroban contract invoke \
### Block an address
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -307,7 +307,7 @@ soroban contract invoke \
### Read
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -318,7 +318,7 @@ soroban contract invoke \
-- get_grace_window
```
-**API**
+#### API
```sh
curl http://localhost:3000/api/invoice/grace-window
@@ -326,7 +326,7 @@ curl http://localhost:3000/api/invoice/grace-window
### Update (admin only)
-**soroban-cli**
+#### soroban-cli
```sh
soroban contract invoke \
@@ -339,7 +339,7 @@ soroban contract invoke \
--window 172800
```
-**API**
+#### API
```sh
curl -X POST http://localhost:3000/api/invoice/grace-window \
diff --git a/docs/error-codes.md b/docs/error-codes.md
index 8ccbeaf..ab4200c 100644
--- a/docs/error-codes.md
+++ b/docs/error-codes.md
@@ -11,7 +11,7 @@ This document maps every `InvoiceError` variant (and other contract error codes)
Defined in `contracts/invoice/src/lib.rs` and `COMEBACKHERE-contracts/contracts/invoice/src/lib.rs`.
| Code | Name | Trigger condition | Remediation |
-|------|------|-------------------|-------------|
+| ------ | ------ | ------------------- | ------------- |
| 1 | `Unauthorized` | Caller is not the merchant, admin, or payer for the operation. | Ensure the signing key matches the expected role. Merchants must sign `create_invoice`; the admin must sign `mark_paid` / `release_escrow`; the payer must sign `request_refund`. |
| 2 | `ContractPaused` | A state-changing call was made while the contract is in a paused state. | Check contract status before submitting. Contact the admin to unpause the contract. Do not retry until the contract is unpaused. |
| 3 | `InvalidAmount` | `amount_usdc` ≤ 0, or `gross_usdc` < `amount_usdc`. | Verify that both amounts are positive and that `gross_usdc ≥ amount_usdc`. Amounts are denominated in USDC stroops (1 USDC = 10 000 000 stroops). |
@@ -32,7 +32,7 @@ Defined in `contracts/invoice/src/lib.rs` and `COMEBACKHERE-contracts/contracts/
Defined in `contracts/settlement/src/lib.rs`.
| Code | Name | Trigger condition | Remediation |
-|------|------|-------------------|-------------|
+| ------ | ------ | ------------------- | ------------- |
| 1 | `NotFound` | No settlement exists for the supplied ID. | Confirm the settlement ID returned by `propose`. |
| 2 | `Unauthorized` | Caller has no registered weight in the treasury signer set. | Use a key that was registered via `initialize` or a subsequent signer-rotation call. |
| 3 | `AlreadyApproved` | The same signer attempted to approve the same settlement twice. | Each signer may approve a settlement only once. |
@@ -58,7 +58,7 @@ Backend endpoints return errors as JSON:
## Quick-reference: HTTP status mapping
| HTTP status | Typical contract code(s) | Meaning |
-|-------------|--------------------------|---------|
+| ------------- | -------------------------- | --------- |
| 400 | — | Invalid request body (validation failed before hitting the contract). |
| 403 | 1 (`Unauthorized`) | Caller is not authorised for the operation. |
| 404 | 6 (`NotFound`), Settlement 1 | Resource does not exist. |
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index cb0aaf3..c72465e 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -23,7 +23,7 @@ docker compose logs soroban
**Common causes and fixes:**
| Symptom | Cause | Fix |
-|---|---|---|
+| --- | --- | --- |
| `connection refused` on `localhost:8000` | Container not started | Run `docker compose up -d` or `make dev` |
| Container starts then immediately exits | Corrupted volume data | `docker compose down -v && docker compose up -d` |
| `health: starting` stays for more than 60 seconds | Slow initial ledger catch-up | Wait up to 90 seconds; the healthcheck has a 30-second `start_period` and retries every 5 seconds |
diff --git a/scripts/generate_abi_metadata.sh b/scripts/generate_abi_metadata.sh
index 4875065..f143ba9 100755
--- a/scripts/generate_abi_metadata.sh
+++ b/scripts/generate_abi_metadata.sh
@@ -1,12 +1,25 @@
#!/usr/bin/env bash
# Regenerate committed ABI metadata under abis/ from contract sources.
-# Contract sources live in the sibling COMEBACKHERE-contracts/ directory.
+# Contract sources are searched in two locations (CI checkout and local sibling):
+# 1. $ROOT_DIR/COMEBACKHERE-contracts (GitHub Actions checkout path)
+# 2. $ROOT_DIR/../COMEBACKHERE-contracts (local sibling directory)
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-CONTRACTS_DIR="$(cd "$ROOT_DIR/../COMEBACKHERE-contracts" && pwd)"
OUT_DIR="${1:-"$ROOT_DIR/abis"}"
+if [ -d "$ROOT_DIR/COMEBACKHERE-contracts" ]; then
+ CONTRACTS_DIR="$ROOT_DIR/COMEBACKHERE-contracts"
+elif [ -d "$ROOT_DIR/../COMEBACKHERE-contracts" ]; then
+ CONTRACTS_DIR="$(cd "$ROOT_DIR/../COMEBACKHERE-contracts" && pwd)"
+else
+ echo "ERROR: COMEBACKHERE-contracts directory not found." >&2
+ echo " Looked in: $ROOT_DIR/COMEBACKHERE-contracts" >&2
+ echo " Looked in: $ROOT_DIR/../COMEBACKHERE-contracts" >&2
+ echo " Clone it with: git clone https://github.com/WHEELBACK/COMEBACKHERE-contracts ../COMEBACKHERE-contracts" >&2
+ exit 1
+fi
+
export LC_ALL=C
export LANG=C
diff --git a/tests/README.md b/tests/README.md
index 1c9161f..78b274e 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -35,7 +35,7 @@ export USDC_CONTRACT_ID=
## Test Coverage
| Test | Description |
-|---|---|
+| --- | --- |
| Create invoice | Creates a valid invoice with minimum amount |
| Pay invoice | Pays the invoice with USDC via the payer account |
| Escrow release | Proposes, approves, and executes a treasury settlement |