From 48abb5932d9da15d1037dcba921561b6107de939 Mon Sep 17 00:00:00 2001 From: Manos Liolios Date: Thu, 21 May 2026 10:13:50 +0300 Subject: [PATCH 1/3] add lint + e2e test scaffold, move tests to --- packages/mpp/biome.json | 32 + packages/mpp/package.json | 14 +- packages/mpp/src/client.test.ts | 116 -- packages/mpp/src/client.ts | 18 +- packages/mpp/src/server.ts | 49 +- packages/mpp/src/utils.ts | 5 +- packages/mpp/test/e2e/globalSetup.ts | 55 + packages/mpp/test/e2e/setup.ts | 44 + packages/mpp/test/e2e/setupEnv.ts | 9 + packages/mpp/test/e2e/sui-payment.test.ts | 100 ++ packages/mpp/test/unit/client.test.ts | 135 ++ .../mpp/{src => test/unit}/server.test.ts | 124 +- packages/mpp/{src => test/unit}/utils.test.ts | 4 +- packages/mpp/vitest.config.ts | 2 +- packages/mpp/vitest.e2e.config.ts | 12 + pnpm-lock.yaml | 1194 ++++++++++++++++- 16 files changed, 1711 insertions(+), 202 deletions(-) create mode 100644 packages/mpp/biome.json delete mode 100644 packages/mpp/src/client.test.ts create mode 100644 packages/mpp/test/e2e/globalSetup.ts create mode 100644 packages/mpp/test/e2e/setup.ts create mode 100644 packages/mpp/test/e2e/setupEnv.ts create mode 100644 packages/mpp/test/e2e/sui-payment.test.ts create mode 100644 packages/mpp/test/unit/client.test.ts rename packages/mpp/{src => test/unit}/server.test.ts (69%) rename packages/mpp/{src => test/unit}/utils.test.ts (84%) create mode 100644 packages/mpp/vitest.e2e.config.ts diff --git a/packages/mpp/biome.json b/packages/mpp/biome.json new file mode 100644 index 0000000..2e7ff48 --- /dev/null +++ b/packages/mpp/biome.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json", + "files": { + "ignore": [ + "node_modules", + "dist", + ".pnpm-store", + "*.lock", + "*.toml", + "**/move/**/build" + ] + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "semicolons": "always" + } + } +} diff --git a/packages/mpp/package.json b/packages/mpp/package.json index 10b136a..6c015bb 100644 --- a/packages/mpp/package.json +++ b/packages/mpp/package.json @@ -23,10 +23,7 @@ "require": "./dist/server.cjs" } }, - "files": [ - "dist", - "README.md" - ], + "files": ["dist", "README.md"], "keywords": [ "mpp", "sui", @@ -49,9 +46,13 @@ "build": "tsup", "dev": "tsup --watch", "test": "vitest run", + "test:e2e": "vitest run --config vitest.e2e.config.ts", "test:watch": "vitest", "typecheck": "tsc --noEmit", - "lint": "eslint src/", + "check": "biome check .", + "check:fix": "biome check --write .", + "lint": "biome check .", + "lint:fix": "biome check --write .", "clean": "rm -rf dist" }, "dependencies": { @@ -60,8 +61,9 @@ "zod": "^4.3.6" }, "devDependencies": { + "@biomejs/biome": "^1.9.0", "@types/node": "^20", - "eslint": "^9", + "testcontainers": "^12.0.0", "tsup": "^8", "typescript": "^5", "vitest": "^3" diff --git a/packages/mpp/src/client.test.ts b/packages/mpp/src/client.test.ts deleted file mode 100644 index fc19028..0000000 --- a/packages/mpp/src/client.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; - -vi.mock('@mysten/sui/transactions', () => { - const coinWithBalance = vi.fn(() => 'coin_with_balance_result'); - const Transaction = vi.fn().mockImplementation(() => ({ - setSender: vi.fn(), - transferObjects: vi.fn(), - build: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3])), - })); - return { Transaction, coinWithBalance }; -}); - -const mockExecuteTransaction = vi.fn(); - -const mockClient = { - core: { - executeTransaction: mockExecuteTransaction, - }, -}; - -const mockSigner = { - toSuiAddress: () => '0xagent_address', - signTransaction: vi.fn().mockResolvedValue({ bytes: 'mock_bytes', signature: 'mock_sig' }), -}; - -describe('client createCredential', () => { - let suiFn: typeof import('./client.js').sui; - - beforeEach(async () => { - vi.clearAllMocks(); - const mod = await import('./client.js'); - suiFn = mod.sui; - }); - - it('builds transaction with coinWithBalance and executes it', async () => { - mockExecuteTransaction.mockResolvedValue({ - Transaction: { digest: '0xtxdigest' }, - }); - - const clientMethod = suiFn({ - client: mockClient as any, - signer: mockSigner as any, - }); - - const challenge = { - request: { - amount: '0.01', - currency: '0x::usdc::USDC', - recipient: '0xrecipient', - }, - }; - - try { - await (clientMethod as any).createCredential({ challenge }); - } catch { - // Credential.serialize may not be available in test — we're testing TX building - } - - expect(mockSigner.signTransaction).toHaveBeenCalled(); - expect(mockExecuteTransaction).toHaveBeenCalledWith({ - transaction: expect.any(Uint8Array), - signatures: ['mock_sig'], - include: { effects: true }, - }); - }); - - it('throws when transaction execution fails', async () => { - mockExecuteTransaction.mockResolvedValue({ - FailedTransaction: { status: { error: 'out of gas' } }, - }); - - const clientMethod = suiFn({ - client: mockClient as any, - signer: mockSigner as any, - }); - - const challenge = { - request: { - amount: '0.01', - currency: '0x::usdc::USDC', - recipient: '0xrecipient', - }, - }; - - await expect( - (clientMethod as any).createCredential({ challenge }), - ).rejects.toThrow('Payment transaction failed'); - }); - - it('uses custom execute when provided', async () => { - const customExecute = vi.fn().mockResolvedValue({ digest: '0xcustom', effects: {} }); - - const clientMethod = suiFn({ - client: mockClient as any, - signer: mockSigner as any, - execute: customExecute, - }); - - const challenge = { - request: { - amount: '1.00', - currency: '0x::usdc::USDC', - recipient: '0xrecipient', - }, - }; - - try { - await (clientMethod as any).createCredential({ challenge }); - } catch { - // Credential.serialize may not be available in test - } - - expect(customExecute).toHaveBeenCalled(); - expect(mockExecuteTransaction).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/mpp/src/client.ts b/packages/mpp/src/client.ts index c23d91f..341d485 100644 --- a/packages/mpp/src/client.ts +++ b/packages/mpp/src/client.ts @@ -1,7 +1,7 @@ -import { Method, Credential } from 'mppx'; import type { ClientWithCoreApi } from '@mysten/sui/client'; import type { Signer } from '@mysten/sui/cryptography'; -import { coinWithBalance, Transaction } from '@mysten/sui/transactions'; +import { Transaction, coinWithBalance } from '@mysten/sui/transactions'; +import { Credential, Method } from 'mppx'; import { suiCharge } from './method.js'; import { parseAmountToRaw } from './utils.js'; @@ -17,6 +17,8 @@ export interface SuiChargeOptions { execute?: (tx: Transaction) => Promise<{ digest: string }>; } +type TransactionResult = { digest: string }; + export function sui(options: SuiChargeOptions) { const address = options.signer.toSuiAddress(); const decimals = options.decimals ?? 6; @@ -32,7 +34,7 @@ export function sui(options: SuiChargeOptions) { const payment = coinWithBalance({ balance: amountRaw, type: currency }); tx.transferObjects([payment], recipient); - let result; + let result: TransactionResult; try { if (options.execute) { result = await options.execute(tx); @@ -45,9 +47,15 @@ export function sui(options: SuiChargeOptions) { include: { effects: true }, }); if (execResult.FailedTransaction) { - throw new Error(execResult.FailedTransaction.status.error?.message ?? 'Transaction failed'); + throw new Error( + execResult.FailedTransaction.status.error?.message ?? + 'Transaction failed', + ); + } + if (!execResult.Transaction) { + throw new Error('Transaction failed'); } - result = execResult.Transaction!; + result = execResult.Transaction; } } catch (err: unknown) { const msg = err instanceof Error ? err.message : String(err); diff --git a/packages/mpp/src/server.ts b/packages/mpp/src/server.ts index 7d820ee..6201e50 100644 --- a/packages/mpp/src/server.ts +++ b/packages/mpp/src/server.ts @@ -1,9 +1,10 @@ -import { Method, Receipt } from 'mppx'; import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc'; import { normalizeSuiAddress } from '@mysten/sui/utils'; +import { Method, Receipt } from 'mppx'; +import { InMemoryDigestStore } from './in-memory-digest-store.js'; import { suiCharge } from './method.js'; import { parseAmountToRaw, withRetry } from './utils.js'; -import { InMemoryDigestStore } from './in-memory-digest-store.js'; export { suiCharge } from './method.js'; export { SUI_USDC_TYPE } from './constants.js'; @@ -28,7 +29,7 @@ export interface SuiServerOptions { /** Number of decimal places for the currency (default: 6, e.g. USDC). */ decimals?: number; rpcUrl?: string; - network?: 'mainnet' | 'testnet' | 'devnet'; + network?: 'mainnet' | 'testnet' | 'devnet' | 'localnet'; /** Digest store for replay protection. Required in production. Falls back to in-memory in dev. */ store?: DigestStore; /** Called after successful on-chain verification with payment data. */ @@ -40,11 +41,14 @@ let _defaultStore: DigestStore | undefined; function resolveStore(options: SuiServerOptions): DigestStore { if (options.store) return options.store; - if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') { + if ( + typeof process !== 'undefined' && + process.env?.NODE_ENV === 'production' + ) { throw new Error( '[suimpp] DigestStore is required in production. ' + - 'Provide a Redis or DB-backed store via SuiServerOptions.store. ' + - 'The default in-memory store is single-instance only and unsafe for multi-instance deployments.', + 'Provide a Redis or DB-backed store via SuiServerOptions.store. ' + + 'The default in-memory store is single-instance only and unsafe for multi-instance deployments.', ); } @@ -52,7 +56,7 @@ function resolveStore(options: SuiServerOptions): DigestStore { _defaultStore = new InMemoryDigestStore(); console.warn( '[suimpp] No DigestStore provided. Using in-memory store. ' + - 'This is NOT safe for production or multi-instance deployments.', + 'This is NOT safe for production or multi-instance deployments.', ); } return _defaultStore; @@ -61,8 +65,13 @@ function resolveStore(options: SuiServerOptions): DigestStore { export function sui(options: SuiServerOptions) { const network = options.network ?? 'mainnet'; const decimals = options.decimals ?? 6; + const baseUrl = + options.rpcUrl ?? + (network === 'localnet' + ? 'http://127.0.0.1:9000' + : getJsonRpcFullnodeUrl(network)); const client = new SuiGrpcClient({ - baseUrl: options.rpcUrl ?? `https://fullnode.${network}.sui.io:443`, + baseUrl, network, }); @@ -85,10 +94,15 @@ export function sui(options: SuiServerOptions) { ); } - const tx = await withRetry( - () => client.core.getTransaction({ digest, include: { balanceChanges: true } }), + const tx = await withRetry(() => + client.core.getTransaction({ + digest, + include: { balanceChanges: true }, + }), ).catch(() => { - throw new Error(`Could not find the referenced transaction [${digest}]`); + throw new Error( + `Could not find the referenced transaction [${digest}]`, + ); }); const resolved = tx.Transaction ?? tx.FailedTransaction; @@ -104,13 +118,14 @@ export function sui(options: SuiServerOptions) { ); if (!payment) { - throw new Error( - 'Payment not found in transaction balance changes', - ); + throw new Error('Payment not found in transaction balance changes'); } const transferredRaw = BigInt(payment.amount); - const requestedRaw = parseAmountToRaw(credential.challenge.request.amount, decimals); + const requestedRaw = parseAmountToRaw( + credential.challenge.request.amount, + decimals, + ); if (transferredRaw < requestedRaw) { throw new Error( `Transferred ${transferredRaw} < requested ${requestedRaw} (raw units)`, @@ -138,7 +153,9 @@ export function sui(options: SuiServerOptions) { }; if (options.onPayment) { - try { options.onPayment(report); } catch {} + try { + options.onPayment(report); + } catch {} } return receipt; diff --git a/packages/mpp/src/utils.ts b/packages/mpp/src/utils.ts index d08108c..f003215 100644 --- a/packages/mpp/src/utils.ts +++ b/packages/mpp/src/utils.ts @@ -14,7 +14,10 @@ export function parseAmountToRaw(amount: string, decimals: number): bigint { */ export async function withRetry( fn: () => Promise, - { attempts = 5, baseDelayMs = 1000 }: { attempts?: number; baseDelayMs?: number } = {}, + { + attempts = 5, + baseDelayMs = 1000, + }: { attempts?: number; baseDelayMs?: number } = {}, ): Promise { let lastError: unknown; for (let i = 0; i < attempts; i++) { diff --git a/packages/mpp/test/e2e/globalSetup.ts b/packages/mpp/test/e2e/globalSetup.ts new file mode 100644 index 0000000..bf334bf --- /dev/null +++ b/packages/mpp/test/e2e/globalSetup.ts @@ -0,0 +1,55 @@ +import { GenericContainer, type StartedTestContainer } from 'testcontainers'; +import type { TestProject } from 'vitest/node'; + +declare module 'vitest' { + export interface ProvidedContext { + localnetPort: number; + faucetPort: number; + suiToolsContainerId: string; + } +} + +const SUI_TOOLS_TAG = + process.env.SUI_TOOLS_TAG || + (process.arch === 'arm64' + ? '951cae315d8b252131836a331bcc16b89eb340d6-arm64' + : '951cae315d8b252131836a331bcc16b89eb340d6'); + +export default async function setup(project: TestProject) { + const containers: StartedTestContainer[] = []; + + console.log('Starting Sui localnet container...'); + const localnet = await new GenericContainer( + `mysten/sui-tools:${SUI_TOOLS_TAG}`, + ) + .withCommand(['sui', 'start', '--with-faucet', '--force-regenesis']) + .withExposedPorts(9000, 9123) + .withLogConsumer((stream) => { + stream.on('data', (data) => { + const msg = data.toString(); + if ( + msg.includes('error') || + msg.includes('Fullnode') || + msg.includes('faucet') + ) { + console.log(msg.trimEnd()); + } + }); + }) + .start(); + containers.push(localnet); + + project.provide('localnetPort', localnet.getMappedPort(9000)); + project.provide('faucetPort', localnet.getMappedPort(9123)); + project.provide('suiToolsContainerId', localnet.getId()); + + console.log( + `Sui localnet ready: fullnode=${localnet.getMappedPort(9000)}, faucet=${localnet.getMappedPort(9123)}`, + ); + + return async () => { + await Promise.allSettled( + containers.reverse().map((container) => container.stop()), + ); + }; +} diff --git a/packages/mpp/test/e2e/setup.ts b/packages/mpp/test/e2e/setup.ts new file mode 100644 index 0000000..f27c71e --- /dev/null +++ b/packages/mpp/test/e2e/setup.ts @@ -0,0 +1,44 @@ +import { + FaucetRateLimitError, + requestSuiFromFaucetV2, +} from '@mysten/sui/faucet'; +import { SuiGrpcClient } from '@mysten/sui/grpc'; + +const DEFAULT_FAUCET_URL = process.env.FAUCET_URL ?? 'http://127.0.0.1:9123'; +const DEFAULT_FULLNODE_URL = + process.env.LOCALNET_FULLNODE_URL ?? 'http://127.0.0.1:9000'; + +function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +export function getFullnodeUrl() { + return DEFAULT_FULLNODE_URL; +} + +export function getClient(): SuiGrpcClient { + return new SuiGrpcClient({ + network: 'localnet', + baseUrl: DEFAULT_FULLNODE_URL, + }); +} + +export async function fundAddress(address: string) { + let lastError: unknown; + + for (let attempt = 0; attempt < 6; attempt++) { + try { + await requestSuiFromFaucetV2({ + host: DEFAULT_FAUCET_URL, + recipient: address, + }); + return; + } catch (error) { + if (error instanceof FaucetRateLimitError) throw error; + lastError = error; + await delay(1000 * (attempt + 1)); + } + } + + throw lastError; +} diff --git a/packages/mpp/test/e2e/setupEnv.ts b/packages/mpp/test/e2e/setupEnv.ts new file mode 100644 index 0000000..7d4e06d --- /dev/null +++ b/packages/mpp/test/e2e/setupEnv.ts @@ -0,0 +1,9 @@ +import { inject } from 'vitest'; + +for (const [key, value] of Object.entries({ + LOCALNET_FULLNODE_URL: `http://127.0.0.1:${inject('localnetPort')}`, + FAUCET_URL: `http://127.0.0.1:${inject('faucetPort')}`, + NODE_ENV: 'test', +})) { + process.env[key] = value; +} diff --git a/packages/mpp/test/e2e/sui-payment.test.ts b/packages/mpp/test/e2e/sui-payment.test.ts new file mode 100644 index 0000000..10338a4 --- /dev/null +++ b/packages/mpp/test/e2e/sui-payment.test.ts @@ -0,0 +1,100 @@ +import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; +import { SUI_TYPE_ARG } from '@mysten/sui/utils'; +import { Challenge, Credential } from 'mppx'; +import { beforeAll, describe, expect, it, vi } from 'vitest'; +import { sui as createSuiClient } from '../../src/client.js'; +import { InMemoryDigestStore } from '../../src/in-memory-digest-store.js'; +import { suiCharge } from '../../src/method.js'; +import { sui as createSuiServer } from '../../src/server.js'; +import { fundAddress, getClient, getFullnodeUrl } from './setup.js'; + +const PAYMENT_AMOUNT = '0.01'; +const SUI_DECIMALS = 9; + +type SuiChargeRequest = { + amount: string; + currency: string; + recipient: string; +}; +type SuiChargeChallenge = Challenge.Challenge< + SuiChargeRequest, + 'charge', + 'sui' +>; +type SuiChargeCredential = Credential.Credential< + { digest: string }, + SuiChargeChallenge +>; + +describe('Sui localnet e2e payment', () => { + const localnetClient = getClient(); + const payerKeypair = Ed25519Keypair.generate(); + const recipientKeypair = Ed25519Keypair.generate(); + const recipient = recipientKeypair.getPublicKey().toSuiAddress(); + + beforeAll(async () => { + await fundAddress(payerKeypair.getPublicKey().toSuiAddress()); + }); + + it('creates an on-chain credential and verifies the payment once', async () => { + const onPayment = vi.fn(); + const challenge = Challenge.fromMethod(suiCharge, { + id: 'sui-localnet-e2e-payment', + realm: 'suimpp-e2e', + request: { + amount: PAYMENT_AMOUNT, + currency: SUI_TYPE_ARG, + recipient, + }, + }) as SuiChargeChallenge; + const clientMethod = createSuiClient({ + client: localnetClient, + signer: payerKeypair, + decimals: SUI_DECIMALS, + }); + const serverMethod = createSuiServer({ + currency: SUI_TYPE_ARG, + recipient, + decimals: SUI_DECIMALS, + rpcUrl: getFullnodeUrl(), + network: 'localnet', + store: new InMemoryDigestStore(), + onPayment, + }); + + const authorization = await clientMethod.createCredential({ challenge }); + const credential = Credential.deserialize<{ digest: string }>( + authorization, + ) as SuiChargeCredential; + await localnetClient.waitForTransaction({ + digest: credential.payload.digest, + }); + + const receipt = await serverMethod.verify({ + credential, + request: challenge.request, + }); + + expect(receipt).toMatchObject({ + method: 'sui', + reference: credential.payload.digest, + status: 'success', + }); + expect(onPayment).toHaveBeenCalledWith( + expect.objectContaining({ + digest: credential.payload.digest, + recipient, + amount: PAYMENT_AMOUNT, + currency: SUI_TYPE_ARG, + network: 'localnet', + }), + ); + + await expect( + serverMethod.verify({ + credential, + request: challenge.request, + }), + ).rejects.toThrow('Digest already used'); + }); +}); diff --git a/packages/mpp/test/unit/client.test.ts b/packages/mpp/test/unit/client.test.ts new file mode 100644 index 0000000..ef90d6b --- /dev/null +++ b/packages/mpp/test/unit/client.test.ts @@ -0,0 +1,135 @@ +import type { Challenge } from 'mppx'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import type { + SuiChargeOptions, + sui as createSuiClient, +} from '../../src/client.js'; + +vi.mock('@mysten/sui/transactions', () => { + const coinWithBalance = vi.fn(() => 'coin_with_balance_result'); + const Transaction = vi.fn().mockImplementation(() => ({ + setSender: vi.fn(), + transferObjects: vi.fn(), + build: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3])), + })); + return { Transaction, coinWithBalance }; +}); + +const mockExecuteTransaction = vi.fn(); + +const mockClient = { + core: { + executeTransaction: mockExecuteTransaction, + }, +}; + +const mockSigner = { + toSuiAddress: () => '0xagent_address', + signTransaction: vi + .fn() + .mockResolvedValue({ bytes: 'mock_bytes', signature: 'mock_sig' }), +}; + +const typedMockClient = mockClient as unknown as SuiChargeOptions['client']; +const typedMockSigner = mockSigner as unknown as SuiChargeOptions['signer']; + +type SuiChargeRequest = { + amount: string; + currency: string; + recipient: string; +}; +type SuiChargeChallenge = Challenge.Challenge< + SuiChargeRequest, + 'charge', + 'sui' +>; + +function buildChallenge(amount = '0.01'): SuiChargeChallenge { + return { + id: 'test-challenge', + intent: 'charge', + method: 'sui', + realm: 'test', + request: { + amount, + currency: '0x::usdc::USDC', + recipient: '0xrecipient', + }, + }; +} + +describe('client createCredential', () => { + let suiFn: typeof createSuiClient; + + beforeEach(async () => { + vi.clearAllMocks(); + const mod = await import('../../src/client.js'); + suiFn = mod.sui; + }); + + it('builds transaction with coinWithBalance and executes it', async () => { + mockExecuteTransaction.mockResolvedValue({ + Transaction: { digest: '0xtxdigest' }, + }); + + const clientMethod = suiFn({ + client: typedMockClient, + signer: typedMockSigner, + }); + + const challenge = buildChallenge(); + + try { + await clientMethod.createCredential({ challenge }); + } catch { + // Credential.serialize may not be available in test; this verifies TX building. + } + + expect(mockSigner.signTransaction).toHaveBeenCalled(); + expect(mockExecuteTransaction).toHaveBeenCalledWith({ + transaction: expect.any(Uint8Array), + signatures: ['mock_sig'], + include: { effects: true }, + }); + }); + + it('throws when transaction execution fails', async () => { + mockExecuteTransaction.mockResolvedValue({ + FailedTransaction: { status: { error: 'out of gas' } }, + }); + + const clientMethod = suiFn({ + client: typedMockClient, + signer: typedMockSigner, + }); + + const challenge = buildChallenge(); + + await expect(clientMethod.createCredential({ challenge })).rejects.toThrow( + 'Payment transaction failed', + ); + }); + + it('uses custom execute when provided', async () => { + const customExecute = vi + .fn() + .mockResolvedValue({ digest: '0xcustom', effects: {} }); + + const clientMethod = suiFn({ + client: typedMockClient, + signer: typedMockSigner, + execute: customExecute, + }); + + const challenge = buildChallenge('1.00'); + + try { + await clientMethod.createCredential({ challenge }); + } catch { + // Credential.serialize may not be available in test. + } + + expect(customExecute).toHaveBeenCalled(); + expect(mockExecuteTransaction).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/mpp/src/server.test.ts b/packages/mpp/test/unit/server.test.ts similarity index 69% rename from packages/mpp/src/server.test.ts rename to packages/mpp/test/unit/server.test.ts index 0973ce3..cdb5b64 100644 --- a/packages/mpp/src/server.test.ts +++ b/packages/mpp/test/unit/server.test.ts @@ -1,10 +1,30 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { InMemoryDigestStore } from './in-memory-digest-store.js'; - -const USDC_TYPE = '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'; +import type { Challenge, Credential, Method } from 'mppx'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { InMemoryDigestStore } from '../../src/in-memory-digest-store.js'; +import type { suiCharge } from '../../src/method.js'; +import type { DigestStore, sui as createSuiServer } from '../../src/server.js'; + +const USDC_TYPE = + '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'; const RECIPIENT = '0xrecipient_address'; const SENDER = '0xsender_address'; +type SuiServerMethod = Method.Server; +type SuiChargeRequest = { + amount: string; + currency: string; + recipient: string; +}; +type SuiChargeChallenge = Challenge.Challenge< + SuiChargeRequest, + 'charge', + 'sui' +>; +type SuiCredential = Credential.Credential< + { digest: string }, + SuiChargeChallenge +>; + function buildMockTx({ success = true, coinType = USDC_TYPE, @@ -32,10 +52,17 @@ function buildMockTx({ : { Transaction: undefined, FailedTransaction: txData }; } -function buildCredential(digest = '0xdigest123', amount = '0.01') { +function buildCredential( + digest = '0xdigest123', + amount = '0.01', +): SuiCredential { return { payload: { digest }, challenge: { + id: 'test-challenge', + intent: 'charge', + method: 'sui', + realm: 'test', request: { amount, currency: USDC_TYPE, @@ -45,6 +72,16 @@ function buildCredential(digest = '0xdigest123', amount = '0.01') { }; } +function verifyPayment( + serverMethod: SuiServerMethod, + credential = buildCredential(), +) { + return serverMethod.verify({ + credential, + request: credential.challenge.request, + }); +} + const mockGetTransaction = vi.fn(); vi.mock('@mysten/sui/grpc', () => ({ @@ -60,12 +97,12 @@ vi.mock('@mysten/sui/utils', () => ({ })); describe('server verify', () => { - let suiFn: typeof import('./server.js').sui; + let suiFn: typeof createSuiServer; const originalEnv = process.env.NODE_ENV; beforeEach(async () => { vi.clearAllMocks(); - const mod = await import('./server.js'); + const mod = await import('../../src/server.js'); suiFn = mod.sui; }); @@ -82,9 +119,7 @@ describe('server verify', () => { store: new InMemoryDigestStore(), }); - const result = await (serverMethod as any).verify({ - credential: buildCredential(), - }); + const result = await verifyPayment(serverMethod); expect(result.reference).toBe('0xdigest123'); expect(result.status).toBe('success'); @@ -99,9 +134,9 @@ describe('server verify', () => { store: new InMemoryDigestStore(), }); - await expect( - (serverMethod as any).verify({ credential: buildCredential() }), - ).rejects.toThrow('Transaction failed on-chain'); + await expect(verifyPayment(serverMethod)).rejects.toThrow( + 'Transaction failed on-chain', + ); }); it('rejects when payment not sent to recipient', async () => { @@ -115,9 +150,9 @@ describe('server verify', () => { store: new InMemoryDigestStore(), }); - await expect( - (serverMethod as any).verify({ credential: buildCredential() }), - ).rejects.toThrow('Payment not found'); + await expect(verifyPayment(serverMethod)).rejects.toThrow( + 'Payment not found', + ); }); it('rejects when amount is less than requested', async () => { @@ -129,9 +164,7 @@ describe('server verify', () => { store: new InMemoryDigestStore(), }); - await expect( - (serverMethod as any).verify({ credential: buildCredential() }), - ).rejects.toThrow('Transferred'); + await expect(verifyPayment(serverMethod)).rejects.toThrow('Transferred'); }); it('rejects when no balance changes', async () => { @@ -149,19 +182,19 @@ describe('server verify', () => { store: new InMemoryDigestStore(), }); - await expect( - (serverMethod as any).verify({ credential: buildCredential() }), - ).rejects.toThrow('Payment not found'); + await expect(verifyPayment(serverMethod)).rejects.toThrow( + 'Payment not found', + ); }); }); describe('digest replay protection', () => { - let suiFn: typeof import('./server.js').sui; + let suiFn: typeof createSuiServer; const originalEnv = process.env.NODE_ENV; beforeEach(async () => { vi.clearAllMocks(); - const mod = await import('./server.js'); + const mod = await import('../../src/server.js'); suiFn = mod.sui; }); @@ -179,9 +212,7 @@ describe('digest replay protection', () => { store, }); - const result = await (serverMethod as any).verify({ - credential: buildCredential(), - }); + const result = await verifyPayment(serverMethod); expect(result.reference).toBe('0xdigest123'); expect(result.status).toBe('success'); @@ -197,14 +228,10 @@ describe('digest replay protection', () => { store, }); - await (serverMethod as any).verify({ - credential: buildCredential(), - }); + await verifyPayment(serverMethod); await expect( - (serverMethod as any).verify({ - credential: buildCredential('0xdigest123', '0.02'), - }), + verifyPayment(serverMethod, buildCredential('0xdigest123', '0.02')), ).rejects.toThrow('Digest already used'); }); @@ -218,9 +245,7 @@ describe('digest replay protection', () => { }); mockGetTransaction.mockResolvedValue(buildMockTx()); - await (serverMethod as any).verify({ - credential: buildCredential('0xdigest123'), - }); + await verifyPayment(serverMethod, buildCredential('0xdigest123')); mockGetTransaction.mockResolvedValue({ Transaction: { @@ -233,9 +258,10 @@ describe('digest replay protection', () => { }, }); - const result = await (serverMethod as any).verify({ - credential: buildCredential('0xdigest456'), - }); + const result = await verifyPayment( + serverMethod, + buildCredential('0xdigest456'), + ); expect(result.reference).toBe('0xdigest456'); }); @@ -250,30 +276,26 @@ describe('digest replay protection', () => { store, }); - await (serverMethod as any).verify({ - credential: buildCredential(), - }); + await verifyPayment(serverMethod); await new Promise((r) => setTimeout(r, 100)); - const result = await (serverMethod as any).verify({ - credential: buildCredential(), - }); + const result = await verifyPayment(serverMethod); expect(result.status).toBe('success'); }); it('throws on missing store in production', () => { process.env.NODE_ENV = 'production'; - expect(() => - suiFn({ currency: USDC_TYPE, recipient: RECIPIENT }), - ).toThrow('DigestStore is required in production'); + expect(() => suiFn({ currency: USDC_TYPE, recipient: RECIPIENT })).toThrow( + 'DigestStore is required in production', + ); }); it('marks digest before returning receipt (store.set failure = no free call)', async () => { const store = { has: vi.fn().mockResolvedValue(false), set: vi.fn().mockRejectedValue(new Error('Redis down')), - } satisfies import('./server.js').DigestStore; + } satisfies DigestStore; mockGetTransaction.mockResolvedValue(buildMockTx()); const serverMethod = suiFn({ @@ -282,9 +304,7 @@ describe('digest replay protection', () => { store, }); - await expect( - (serverMethod as any).verify({ credential: buildCredential() }), - ).rejects.toThrow('Redis down'); + await expect(verifyPayment(serverMethod)).rejects.toThrow('Redis down'); expect(store.set).toHaveBeenCalledWith('0xdigest123'); }); diff --git a/packages/mpp/src/utils.test.ts b/packages/mpp/test/unit/utils.test.ts similarity index 84% rename from packages/mpp/src/utils.test.ts rename to packages/mpp/test/unit/utils.test.ts index 24a83f9..5cb4bf9 100644 --- a/packages/mpp/src/utils.test.ts +++ b/packages/mpp/test/unit/utils.test.ts @@ -1,5 +1,5 @@ -import { describe, it, expect } from 'vitest'; -import { parseAmountToRaw } from './utils.js'; +import { describe, expect, it } from 'vitest'; +import { parseAmountToRaw } from '../../src/utils.js'; describe('parseAmountToRaw', () => { it('converts whole number', () => { diff --git a/packages/mpp/vitest.config.ts b/packages/mpp/vitest.config.ts index e68a190..810703e 100644 --- a/packages/mpp/vitest.config.ts +++ b/packages/mpp/vitest.config.ts @@ -4,7 +4,7 @@ export default defineConfig({ test: { globals: true, environment: 'node', - include: ['src/**/*.test.ts'], + include: ['test/unit/**/*.test.ts'], testTimeout: 30_000, }, }); diff --git a/packages/mpp/vitest.e2e.config.ts b/packages/mpp/vitest.e2e.config.ts new file mode 100644 index 0000000..a3d2034 --- /dev/null +++ b/packages/mpp/vitest.e2e.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'node', + include: ['test/e2e/**/*.test.ts'], + setupFiles: ['test/e2e/setupEnv.ts'], + globalSetup: ['test/e2e/globalSetup.ts'], + hookTimeout: 600_000, + testTimeout: 120_000, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25f4ad0..ed357b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,12 +89,15 @@ importers: specifier: ^4.3.6 version: 4.3.6 devDependencies: + '@biomejs/biome': + specifier: ^1.9.0 + version: 1.9.4 '@types/node': specifier: ^20 version: 20.19.37 - eslint: - specifier: ^9 - version: 9.39.4(jiti@2.6.1) + testcontainers: + specifier: ^12.0.0 + version: 12.0.0 tsup: specifier: ^8 version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.9.3)(yaml@2.8.3) @@ -146,6 +149,62 @@ packages: resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} + '@balena/dockerignore@1.0.2': + resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} + + '@biomejs/biome@1.9.4': + resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.9.4': + resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.9.4': + resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.9.4': + resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.9.4': + resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.9.4': + resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.9.4': + resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.9.4': + resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.9.4': + resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + '@emnapi/runtime@1.9.1': resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} @@ -368,6 +427,20 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@grpc/grpc-js@1.14.4': + resolution: {integrity: sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.7.15': + resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==} + engines: {node: '>=6'} + hasBin: true + + '@grpc/proto-loader@0.8.1': + resolution: {integrity: sha512-wtF6h+DY6M3YaDBPAmvuuA6jV8Sif9MjtOI5euKFWRgCDl5PeDpPsHR9u2l6St5ceY8AZgoNDww5+HvEsXFsGg==} + engines: {node: '>=6'} + hasBin: true + '@hono/node-server@1.19.12': resolution: {integrity: sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==} engines: {node: '>=18.14.1'} @@ -531,6 +604,10 @@ packages: cpu: [x64] os: [win32] + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -547,6 +624,12 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + + '@kwsites/file-exists@1.1.1': + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + '@modelcontextprotocol/sdk@1.28.0': resolution: {integrity: sha512-gmloF+i+flI8ouQK7MWW4mOwuMh4RePBuPFAEPC6+pdqyWOUMDOixb6qZ69owLJpz6XmyllCouc4t8YWO+E2Nw==} engines: {node: '>=18'} @@ -638,6 +721,10 @@ packages: resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} engines: {node: '>= 20.19.0'} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@prisma/client@6.19.2': resolution: {integrity: sha512-gR2EMvfK/aTxsuooaDA32D8v+us/8AAet+C3J1cc04SW35FPdZYgLF+iN4NDLUgAaUGTKdAB0CYenu1TAgGdMg==} engines: {node: '>=18.18'} @@ -677,6 +764,36 @@ packages: '@protobuf-ts/runtime@2.11.1': resolution: {integrity: sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.2': + resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + '@readme/better-ajv-errors@2.4.0': resolution: {integrity: sha512-9WODaOAKSl/mU+MYNZ2aHCrkoRSvmQ+1YkLj589OEqqjOAhbn8j7Z+ilYoiTu/he6X63/clsxxAB4qny9/dDzg==} engines: {node: '>=18'} @@ -978,12 +1095,21 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/docker-modem@3.0.6': + resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} + + '@types/dockerode@4.0.1': + resolution: {integrity: sha512-cmUpB+dPN955PxBEuXE3f6lKO1hHiIGYJA46IVF3BJpNsZGvtBDcRnlrHYHtOH/B6vtDOyl2kZ2ShAu3mgc27Q==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + '@types/node@20.19.37': resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==} @@ -998,6 +1124,15 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/ssh2-streams@0.1.13': + resolution: {integrity: sha512-faHyY3brO9oLEA0QlcO8N2wT7R0+1sHWZvQ+y3rMLwdY1ZyS1z0W3t65j9PqT4HmQ6ALzNe7RZlNuCNE0wBSWA==} + + '@types/ssh2@0.5.52': + resolution: {integrity: sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg==} + + '@types/ssh2@1.15.5': + resolution: {integrity: sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==} + '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} @@ -1038,6 +1173,10 @@ packages: zod: optional: true + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -1074,23 +1213,110 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + async-lock@1.4.1: + resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + b4a@1.8.1: + resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.8.3: + resolution: {integrity: sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.7.1: + resolution: {integrity: sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.9.1: + resolution: {integrity: sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.13.1: + resolution: {integrity: sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==} + peerDependencies: + bare-abort-controller: '*' + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.4.3: + resolution: {integrity: sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -1098,12 +1324,33 @@ packages: brace-expansion@1.1.13: resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + buildcheck@0.0.7: + resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==} + engines: {node: '>=10.0.0'} + bundle-require@5.1.0: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.18' + byline@5.0.0: + resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==} + engines: {node: '>=0.10.0'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -1151,6 +1398,9 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} @@ -1160,6 +1410,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1171,6 +1425,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1200,10 +1458,26 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + cpu-features@0.0.10: + resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} + engines: {node: '>=10.0.0'} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1245,6 +1519,18 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + docker-compose@1.4.2: + resolution: {integrity: sha512-rPHigTKGaEHpkUmfd69QgaOp+Os5vGJwG/Ry8lcr8W/382AmI+z/D7qoa9BybKIkqNppaIbs8RYeHSevdQjWww==} + engines: {node: '>= 6.0.0'} + + docker-modem@5.0.7: + resolution: {integrity: sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==} + engines: {node: '>= 8.0'} + + dockerode@5.0.0: + resolution: {integrity: sha512-C52mvJ+7lcyhWNfrzVfFsbTrBfy/ezE9FGEYLpu17FUeBcCkxERk9nN7uDl/478ynDiQ4U+5DbQC2vENHkVEtQ==} + engines: {node: '>= 14.17'} + dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -1253,12 +1539,21 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} effect@3.18.4: resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -1267,6 +1562,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enhanced-resolve@5.20.1: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} @@ -1291,6 +1589,10 @@ packages: engines: {node: '>=18'} hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -1347,9 +1649,20 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} @@ -1382,6 +1695,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -1422,6 +1738,10 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -1430,6 +1750,9 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1438,10 +1761,18 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-port@7.2.0: + resolution: {integrity: sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==} + engines: {node: '>=16'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -1454,6 +1785,11 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -1499,6 +1835,9 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1530,6 +1869,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1537,6 +1880,13 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1545,6 +1895,9 @@ packages: peerDependencies: ws: '*' + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -1588,6 +1941,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -1681,12 +2038,24 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -1713,6 +2082,26 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + mlly@1.8.2: resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} @@ -1741,6 +2130,9 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nan@2.27.0: + resolution: {integrity: sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1777,6 +2169,10 @@ packages: node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + nypm@0.6.5: resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==} engines: {node: '>=18'} @@ -1831,6 +2227,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -1847,6 +2246,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@8.4.0: resolution: {integrity: sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg==} @@ -1924,10 +2327,31 @@ packages: typescript: optional: true + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + properties-reader@3.0.1: + resolution: {integrity: sha512-WPn+h9RGEExOKdu4bsF4HksG/uzd3cFq3MFtq8PsFeExPse5Ha/VOjQNyHhjboBFwGXGev6muJYTSPAOkROq2g==} + engines: {node: '>=18'} + + protobufjs@7.6.0: + resolution: {integrity: sha512-LtESOsMPTZgyYtwxhvdgdjGL0HmXEaRA/hVD6sol4zA60hVXXXP/SGmxnqDbgGE8gy7pYex7cym+5vYPcmaXBQ==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1959,10 +2383,28 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -1975,6 +2417,10 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + rollup@4.60.1: resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1984,6 +2430,12 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -2037,6 +2489,13 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2045,6 +2504,16 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} + split-ca@1.0.1: + resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} + + ssh-remote-port-forward@1.0.4: + resolution: {integrity: sha512-x0LV1eVDwjf1gmG7TTnfqIzf+3VPRz7vrNIjX6oYLbeCrf/PeVY6hkT68Mg+q02qXxQhrLjB0jfgvhevoCRmLQ==} + + ssh2@1.17.0: + resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==} + engines: {node: '>=10.16.0'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -2055,6 +2524,31 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + streamx@2.25.0: + resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2094,6 +2588,28 @@ packages: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-fs@3.1.2: + resolution: {integrity: sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar-stream@3.2.0: + resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + + testcontainers@12.0.0: + resolution: {integrity: sha512-/PdRvFvuHPwX126HR7RO0cEgLD3Nr8sWZyWSv54ei92TT79BubUkOCU5uwTc8ufTsTGQf0v6nyvZJVVVyR9Uqw==} + + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -2127,6 +2643,10 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -2167,6 +2687,9 @@ packages: resolution: {integrity: sha512-FlJ8OD5Qcp0jTAM7E4a/RhUzRNds2GzKlyxHKA6N247VLy628rrxAGlMpIXSz6VB430+TiQDJ/SMl6PL1lu6wQ==} hasBin: true + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2183,9 +2706,16 @@ packages: ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} + engines: {node: '>=20.18.1'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -2193,6 +2723,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + valibot@1.3.1: resolution: {integrity: sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg==} peerDependencies: @@ -2300,6 +2833,14 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -2315,15 +2856,31 @@ packages: utf-8-validate: optional: true + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yaml@2.8.3: resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} hasBin: true + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + zod-to-json-schema@3.25.2: resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: @@ -2363,6 +2920,43 @@ snapshots: '@babel/runtime@7.29.2': {} + '@balena/dockerignore@1.0.2': {} + + '@biomejs/biome@1.9.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.9.4 + '@biomejs/cli-darwin-x64': 1.9.4 + '@biomejs/cli-linux-arm64': 1.9.4 + '@biomejs/cli-linux-arm64-musl': 1.9.4 + '@biomejs/cli-linux-x64': 1.9.4 + '@biomejs/cli-linux-x64-musl': 1.9.4 + '@biomejs/cli-win32-arm64': 1.9.4 + '@biomejs/cli-win32-x64': 1.9.4 + + '@biomejs/cli-darwin-arm64@1.9.4': + optional: true + + '@biomejs/cli-darwin-x64@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64@1.9.4': + optional: true + + '@biomejs/cli-linux-x64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-x64@1.9.4': + optional: true + + '@biomejs/cli-win32-arm64@1.9.4': + optional: true + + '@biomejs/cli-win32-x64@1.9.4': + optional: true + '@emnapi/runtime@1.9.1': dependencies: tslib: 2.8.1 @@ -2509,6 +3103,25 @@ snapshots: dependencies: graphql: 16.13.2 + '@grpc/grpc-js@1.14.4': + dependencies: + '@grpc/proto-loader': 0.8.1 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.7.15': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.6.0 + yargs: 17.7.2 + + '@grpc/proto-loader@0.8.1': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.6.0 + yargs: 17.7.2 + '@hono/node-server@1.19.12(hono@4.12.9)': dependencies: hono: 4.12.9 @@ -2623,6 +3236,15 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2642,6 +3264,14 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-sdsl/ordered-map@4.4.2': {} + + '@kwsites/file-exists@1.1.1': + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)': dependencies: '@hono/node-server': 1.19.12(hono@4.12.9) @@ -2735,6 +3365,9 @@ snapshots: '@noble/hashes@2.0.1': {} + '@pkgjs/parseargs@0.11.0': + optional: true + '@prisma/client@6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3)': optionalDependencies: prisma: 6.19.2(typescript@5.9.3) @@ -2781,6 +3414,28 @@ snapshots: '@protobuf-ts/runtime@2.11.1': {} + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + '@readme/better-ajv-errors@2.4.0(ajv@8.18.0)': dependencies: '@babel/code-frame': 7.29.0 @@ -3014,10 +3669,25 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/docker-modem@3.0.6': + dependencies: + '@types/node': 22.19.15 + '@types/ssh2': 1.15.5 + + '@types/dockerode@4.0.1': + dependencies: + '@types/docker-modem': 3.0.6 + '@types/node': 22.19.15 + '@types/ssh2': 1.15.5 + '@types/estree@1.0.8': {} '@types/json-schema@7.0.15': {} + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + '@types/node@20.19.37': dependencies: undici-types: 6.21.0 @@ -3034,6 +3704,19 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/ssh2-streams@0.1.13': + dependencies: + '@types/node': 22.19.15 + + '@types/ssh2@0.5.52': + dependencies: + '@types/node': 22.19.15 + '@types/ssh2-streams': 0.1.13 + + '@types/ssh2@1.15.5': + dependencies: + '@types/node': 18.19.130 + '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.3 @@ -3081,6 +3764,10 @@ snapshots: typescript: 5.9.3 zod: 4.3.6 + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -3114,18 +3801,102 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@6.2.3: {} + any-promise@1.3.0: {} + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.18.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 + tar-stream: 3.2.0 + zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + argparse@2.0.1: {} + asn1@0.2.6: + dependencies: + safer-buffer: 2.1.2 + assertion-error@2.0.1: {} + async-lock@1.4.1: {} + + async@3.2.6: {} + + b4a@1.8.1: {} + balanced-match@1.0.2: {} + bare-events@2.8.3: {} + + bare-fs@4.7.1: + dependencies: + bare-events: 2.8.3 + bare-path: 3.0.0 + bare-stream: 2.13.1(bare-events@2.8.3) + bare-url: 2.4.3 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-os@3.9.1: {} + + bare-path@3.0.0: + dependencies: + bare-os: 3.9.1 + + bare-stream@2.13.1(bare-events@2.8.3): + dependencies: + streamx: 2.25.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.8.3 + transitivePeerDependencies: + - react-native-b4a + + bare-url@2.4.3: + dependencies: + bare-path: 3.0.0 + + base64-js@1.5.1: {} + + bcrypt-pbkdf@1.0.2: + dependencies: + tweetnacl: 0.14.5 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -3145,11 +3916,32 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + + buffer-crc32@1.0.0: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buildcheck@0.0.7: + optional: true + bundle-require@5.1.0(esbuild@0.27.4): dependencies: esbuild: 0.27.4 load-tsconfig: 0.2.5 + byline@5.0.0: {} + bytes@3.1.2: {} c12@3.1.0: @@ -3202,6 +3994,8 @@ snapshots: dependencies: readdirp: 4.1.2 + chownr@1.1.4: {} + citty@0.1.6: dependencies: consola: 3.4.2 @@ -3210,6 +4004,12 @@ snapshots: client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -3218,6 +4018,14 @@ snapshots: commander@4.1.1: {} + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + concat-map@0.0.1: {} confbox@0.1.8: {} @@ -3234,11 +4042,26 @@ snapshots: cookie@0.7.2: {} + core-util-is@1.0.3: {} + cors@2.8.6: dependencies: object-assign: 4.1.1 vary: 1.1.2 + cpu-features@0.0.10: + dependencies: + buildcheck: 0.0.7 + nan: 2.27.0 + optional: true + + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -3265,6 +4088,30 @@ snapshots: detect-libc@2.1.2: {} + docker-compose@1.4.2: + dependencies: + yaml: 2.8.3 + + docker-modem@5.0.7: + dependencies: + debug: 4.4.3 + readable-stream: 3.6.2 + split-ca: 1.0.1 + ssh2: 1.17.0 + transitivePeerDependencies: + - supports-color + + dockerode@5.0.0: + dependencies: + '@balena/dockerignore': 1.0.2 + '@grpc/grpc-js': 1.14.4 + '@grpc/proto-loader': 0.7.15 + docker-modem: 5.0.7 + protobufjs: 7.6.0 + tar-fs: 2.1.4 + transitivePeerDependencies: + - supports-color + dotenv@16.6.1: {} dunder-proto@1.0.1: @@ -3273,6 +4120,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} effect@3.18.4: @@ -3280,10 +4129,18 @@ snapshots: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + empathic@2.0.0: {} encodeurl@2.0.0: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 @@ -3328,6 +4185,8 @@ snapshots: '@esbuild/win32-ia32': 0.27.4 '@esbuild/win32-x64': 0.27.4 + escalade@3.2.0: {} + escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} @@ -3406,8 +4265,18 @@ snapshots: etag@1.8.1: {} + event-target-shim@5.0.1: {} + eventemitter3@5.0.1: {} + events-universal@1.0.1: + dependencies: + bare-events: 2.8.3 + transitivePeerDependencies: + - bare-abort-controller + + events@3.3.0: {} + eventsource-parser@3.0.6: {} eventsource@3.0.7: @@ -3462,6 +4331,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-fifo@1.3.2: {} + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -3505,15 +4376,24 @@ snapshots: flatted@3.4.2: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + forwarded@0.2.0: {} fresh@2.0.0: {} + fs-constants@1.0.0: {} + fsevents@2.3.3: optional: true function-bind@1.1.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3527,6 +4407,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-port@7.2.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -3545,6 +4427,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + globals@14.0.0: {} gopd@1.2.0: {} @@ -3587,6 +4478,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} import-fresh@3.3.1: @@ -3617,18 +4510,30 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 is-promise@4.0.0: {} + is-stream@2.0.1: {} + + isarray@1.0.0: {} + isexe@2.0.0: {} isows@1.0.7(ws@8.18.3): dependencies: ws: 8.18.3 + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jiti@2.6.1: {} jose@6.2.2: {} @@ -3659,6 +4564,10 @@ snapshots: dependencies: json-buffer: 3.0.1 + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + leven@3.1.0: {} levn@0.4.1: @@ -3725,10 +4634,18 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.merge@4.6.2: {} + lodash@4.18.1: {} + + long@5.3.2: {} + loupe@3.2.1: {} + lru-cache@10.4.3: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -3749,6 +4666,20 @@ snapshots: dependencies: brace-expansion: 1.1.13 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.0 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minipass@7.1.3: {} + + mkdirp-classic@0.5.3: {} + + mkdirp@3.0.1: {} + mlly@1.8.2: dependencies: acorn: 8.16.0 @@ -3782,6 +4713,9 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nan@2.27.0: + optional: true + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -3813,6 +4747,8 @@ snapshots: node-fetch-native@1.6.7: {} + normalize-path@3.0.0: {} + nypm@0.6.5: dependencies: citty: 0.2.1 @@ -3882,6 +4818,8 @@ snapshots: dependencies: p-limit: 3.1.0 + package-json-from-dist@1.0.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -3892,6 +4830,11 @@ snapshots: path-key@3.1.1: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + path-to-regexp@8.4.0: {} pathe@2.0.3: {} @@ -3953,11 +4896,48 @@ snapshots: transitivePeerDependencies: - magicast + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + properties-reader@3.0.1: + dependencies: + '@kwsites/file-exists': 1.1.1 + mkdirp: 3.0.1 + transitivePeerDependencies: + - supports-color + + protobufjs@7.6.0: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 22.19.15 + long: 5.3.2 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode@2.3.1: {} pure-rand@6.1.0: {} @@ -3987,14 +4967,46 @@ snapshots: react@19.2.4: {} + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.9 + readdirp@4.1.2: {} + require-directory@2.1.1: {} + require-from-string@2.0.2: {} resolve-from@4.0.0: {} resolve-from@5.0.0: {} + retry@0.12.0: {} + rollup@4.60.1: dependencies: '@types/estree': 1.0.8 @@ -4036,6 +5048,10 @@ snapshots: transitivePeerDependencies: - supports-color + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} scheduler@0.27.0: {} @@ -4138,16 +5154,72 @@ snapshots: siginfo@2.0.0: {} + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + source-map-js@1.2.1: {} source-map@0.7.6: {} + split-ca@1.0.1: {} + + ssh-remote-port-forward@1.0.4: + dependencies: + '@types/ssh2': 0.5.52 + ssh2: 1.17.0 + + ssh2@1.17.0: + dependencies: + asn1: 0.2.6 + bcrypt-pbkdf: 1.0.2 + optionalDependencies: + cpu-features: 0.0.10 + nan: 2.27.0 + stackback@0.0.2: {} statuses@2.0.2: {} std-env@3.10.0: {} + streamx@2.25.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + strip-json-comments@3.1.1: {} strip-literal@3.1.0: @@ -4179,6 +5251,80 @@ snapshots: tapable@2.3.2: {} + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + + tar-fs@3.1.2: + dependencies: + pump: 3.0.4 + tar-stream: 3.2.0 + optionalDependencies: + bare-fs: 4.7.1 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar-stream@3.2.0: + dependencies: + b4a: 1.8.1 + bare-fs: 4.7.1 + fast-fifo: 1.3.2 + streamx: 2.25.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + teex@1.0.1: + dependencies: + streamx: 2.25.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + testcontainers@12.0.0: + dependencies: + '@balena/dockerignore': 1.0.2 + '@types/dockerode': 4.0.1 + archiver: 7.0.1 + async-lock: 1.4.1 + byline: 5.0.0 + debug: 4.4.3 + docker-compose: 1.4.2 + dockerode: 5.0.0 + get-port: 7.2.0 + proper-lockfile: 4.1.2 + properties-reader: 3.0.1 + ssh-remote-port-forward: 1.0.4 + tar-fs: 3.1.2 + tmp: 0.2.5 + undici: 7.25.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + - supports-color + + text-decoder@1.2.7: + dependencies: + b4a: 1.8.1 + transitivePeerDependencies: + - react-native-b4a + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -4204,6 +5350,8 @@ snapshots: tinyspy@4.0.4: {} + tmp@0.2.5: {} + toidentifier@1.0.1: {} tokenx@1.3.0: {} @@ -4251,6 +5399,8 @@ snapshots: '@turbo/windows-64': 2.8.21 '@turbo/windows-arm64': 2.8.21 + tweetnacl@0.14.5: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -4265,14 +5415,20 @@ snapshots: ufo@1.6.3: {} + undici-types@5.26.5: {} + undici-types@6.21.0: {} + undici@7.25.0: {} + unpipe@1.0.0: {} uri-js@4.4.1: dependencies: punycode: 2.3.1 + util-deprecate@1.0.2: {} + valibot@1.3.1(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -4384,14 +5540,46 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + wrappy@1.0.2: {} ws@8.18.3: {} + y18n@5.0.8: {} + yaml@2.8.3: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.7.0 + zod-to-json-schema@3.25.2(zod@4.3.6): dependencies: zod: 4.3.6 From 370ef53b56a7c51c89b89250d7b8a5eecb07d357 Mon Sep 17 00:00:00 2001 From: Manos Liolios Date: Thu, 21 May 2026 10:14:41 +0300 Subject: [PATCH 2/3] nit --- packages/mpp/test/unit/server.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/mpp/test/unit/server.test.ts b/packages/mpp/test/unit/server.test.ts index cdb5b64..00b50f5 100644 --- a/packages/mpp/test/unit/server.test.ts +++ b/packages/mpp/test/unit/server.test.ts @@ -2,10 +2,12 @@ import type { Challenge, Credential, Method } from 'mppx'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { InMemoryDigestStore } from '../../src/in-memory-digest-store.js'; import type { suiCharge } from '../../src/method.js'; -import type { DigestStore, sui as createSuiServer } from '../../src/server.js'; +import { + type DigestStore, + SUI_USDC_TYPE, + type sui as createSuiServer, +} from '../../src/server.js'; -const USDC_TYPE = - '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'; const RECIPIENT = '0xrecipient_address'; const SENDER = '0xsender_address'; @@ -27,7 +29,7 @@ type SuiCredential = Credential.Credential< function buildMockTx({ success = true, - coinType = USDC_TYPE, + coinType = SUI_USDC_TYPE, recipientAddr = RECIPIENT, amount = '10000', senderAddr = SENDER, From 59fef937238743957f60c1d782dc043cb32236ae Mon Sep 17 00:00:00 2001 From: Manos Liolios Date: Thu, 21 May 2026 10:16:59 +0300 Subject: [PATCH 3/3] nit --- packages/mpp/test/unit/server.test.ts | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/mpp/test/unit/server.test.ts b/packages/mpp/test/unit/server.test.ts index 00b50f5..2aa5be4 100644 --- a/packages/mpp/test/unit/server.test.ts +++ b/packages/mpp/test/unit/server.test.ts @@ -67,7 +67,7 @@ function buildCredential( realm: 'test', request: { amount, - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, }, }, @@ -116,7 +116,7 @@ describe('server verify', () => { mockGetTransaction.mockResolvedValue(buildMockTx()); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store: new InMemoryDigestStore(), }); @@ -131,7 +131,7 @@ describe('server verify', () => { mockGetTransaction.mockResolvedValue(buildMockTx({ success: false })); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store: new InMemoryDigestStore(), }); @@ -147,7 +147,7 @@ describe('server verify', () => { ); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store: new InMemoryDigestStore(), }); @@ -161,7 +161,7 @@ describe('server verify', () => { mockGetTransaction.mockResolvedValue(buildMockTx({ amount: '5000' })); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store: new InMemoryDigestStore(), }); @@ -179,7 +179,7 @@ describe('server verify', () => { }); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store: new InMemoryDigestStore(), }); @@ -209,7 +209,7 @@ describe('digest replay protection', () => { mockGetTransaction.mockResolvedValue(buildMockTx()); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store, }); @@ -225,7 +225,7 @@ describe('digest replay protection', () => { mockGetTransaction.mockResolvedValue(buildMockTx()); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store, }); @@ -241,7 +241,7 @@ describe('digest replay protection', () => { const store = new InMemoryDigestStore(); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store, }); @@ -254,8 +254,8 @@ describe('digest replay protection', () => { digest: '0xdigest456', status: { success: true }, balanceChanges: [ - { coinType: USDC_TYPE, address: RECIPIENT, amount: '10000' }, - { coinType: USDC_TYPE, address: SENDER, amount: '-10000' }, + { coinType: SUI_USDC_TYPE, address: RECIPIENT, amount: '10000' }, + { coinType: SUI_USDC_TYPE, address: SENDER, amount: '-10000' }, ], }, }); @@ -273,7 +273,7 @@ describe('digest replay protection', () => { mockGetTransaction.mockResolvedValue(buildMockTx()); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store, }); @@ -288,9 +288,9 @@ describe('digest replay protection', () => { it('throws on missing store in production', () => { process.env.NODE_ENV = 'production'; - expect(() => suiFn({ currency: USDC_TYPE, recipient: RECIPIENT })).toThrow( - 'DigestStore is required in production', - ); + expect(() => + suiFn({ currency: SUI_USDC_TYPE, recipient: RECIPIENT }), + ).toThrow('DigestStore is required in production'); }); it('marks digest before returning receipt (store.set failure = no free call)', async () => { @@ -301,7 +301,7 @@ describe('digest replay protection', () => { mockGetTransaction.mockResolvedValue(buildMockTx()); const serverMethod = suiFn({ - currency: USDC_TYPE, + currency: SUI_USDC_TYPE, recipient: RECIPIENT, store, });