diff --git a/README.md b/README.md
index baefd94..d761c95 100644
--- a/README.md
+++ b/README.md
@@ -26,13 +26,14 @@ npm install @suimpp/mpp mppx
```
```typescript
-import { sui } from '@suimpp/mpp/server';
+import { InMemoryDigestStore, USDC, sui } from '@suimpp/mpp/server';
import { Mppx } from 'mppx';
const mppx = Mppx.create({
methods: [sui({
- currency: '0xdba...::usdc::USDC',
+ currency: USDC,
recipient: '0xYOUR_ADDRESS',
+ store: new InMemoryDigestStore(), // Use Redis/DB in production.
})],
});
@@ -44,16 +45,19 @@ export const GET = mppx.charge({ amount: '0.01' })(
### Make Payments (Client)
```typescript
-import { sui } from '@suimpp/mpp/client';
+import { USDC, sui } from '@suimpp/mpp/client';
import { Mppx } from 'mppx/client';
const mppx = Mppx.create({
- methods: [sui({ client, signer })],
+ methods: [sui({ client, signer, currency: USDC })],
});
const response = await mppx.fetch('https://api.example.com/resource');
```
+`@suimpp/mpp` exports `USDC`, `USDC_TESTNET`, and `SUI_DOLLAR`
+currency presets. The SDK handles gasless tier behavior automatically.
+
### Validate a Server
```bash
@@ -87,7 +91,8 @@ Agent Server Sui
│ └─ TX confirmed ←──────────────────────────────────────────────│
│ digest: "Hp4oHHs..." │ │
│ │ │
- │── Retry + credential {digest} ──>│ │
+ │── Retry + credential ───────────>│ │
+ │ {digest, signature} │ │
│ │── getTransaction(digest) ──>│
│ │ verify: success, amount, │
│ │ recipient matches │
@@ -171,12 +176,12 @@ Payments are reported by the gateway (application layer), not by the library dir
└─────────────────────┘
```
-**Why this pattern?** The `verify()` callback has on-chain data (sender from balance changes) but no HTTP context (which endpoint was called). The gateway's charge wrapper has HTTP context but no on-chain data. The `onPayment` callback bridges the two layers using the digest as the join key.
+**Why this pattern?** The `verify()` callback has on-chain data (transaction sender, digest, amount, recipient) but no HTTP context (which endpoint was called). The gateway's charge wrapper has HTTP context but no on-chain data. The `onPayment` callback bridges the two layers using the digest as the join key.
**Implementation:**
```typescript
-import { sui } from '@suimpp/mpp/server';
+import { InMemoryDigestStore, USDC, sui } from '@suimpp/mpp/server';
import type { PaymentReport } from '@suimpp/mpp/server';
// 1. Library emits on-chain data via callback
@@ -184,8 +189,9 @@ const pendingReports = new Map();
const mppx = Mppx.create({
methods: [sui({
- currency: SUI_USDC_TYPE,
+ currency: USDC,
recipient: TREASURY_ADDRESS,
+ store: new InMemoryDigestStore(), // Use Redis/DB in production.
network: 'mainnet',
onPayment: (report) => {
pendingReports.set(report.digest, report);
diff --git a/apps/suimpp/app/components/CodeBlocks.tsx b/apps/suimpp/app/components/CodeBlocks.tsx
index 9ee0a16..806e8e4 100644
--- a/apps/suimpp/app/components/CodeBlocks.tsx
+++ b/apps/suimpp/app/components/CodeBlocks.tsx
@@ -53,11 +53,11 @@ function CodeBlock({
}
const CLIENT_CODE = `import { Mppx } from 'mppx/client';
-import { sui } from '@suimpp/mpp/client';
+import { USDC, sui } from '@suimpp/mpp/client';
import { SuiGrpcClient } from '@mysten/sui/grpc';
const mpp = Mppx.create({
- methods: [sui({ client, signer })],
+ methods: [sui({ client, signer, currency: USDC })],
});
const res = await mpp.fetch(
@@ -66,13 +66,14 @@ const res = await mpp.fetch(
);`;
const SERVER_CODE = `import { Mppx } from 'mppx/nextjs';
-import { sui } from '@suimpp/mpp/server';
+import { InMemoryDigestStore, USDC, sui } from '@suimpp/mpp/server';
const mpp = Mppx.create({
realm: 'api.example.com',
methods: [sui({
- currency: SUI_USDC_TYPE,
+ currency: USDC,
recipient: '0x...',
+ store: new InMemoryDigestStore(), // Use Redis/DB in production.
})],
});
diff --git a/apps/suimpp/app/docs/DocsContent.tsx b/apps/suimpp/app/docs/DocsContent.tsx
index fcb3b7d..1ba6313 100644
--- a/apps/suimpp/app/docs/DocsContent.tsx
+++ b/apps/suimpp/app/docs/DocsContent.tsx
@@ -29,10 +29,10 @@ export function DocsContent() {
@@ -226,13 +230,14 @@ const data = await response.json();`}
│
│ + payment credential │── verify TX on-chain via gRPC
- │ (Sui tx digest) │
+ │ (digest + signature) │
│<── 200 OK + data ────────│
```
@@ -120,12 +124,12 @@ No facilitator. No intermediary. The server verifies the Sui transaction directl
Creates a Sui payment method for the server.
```typescript
-import { sui } from '@suimpp/mpp/server';
+import { InMemoryDigestStore, USDC, sui } from '@suimpp/mpp/server';
const method = sui({
- currency: SUI_USDC, // Sui coin type (e.g. USDC)
+ currency: USDC, // Sui coin type + decimals
recipient: '0xYOUR_ADDR', // Where payments are sent
- decimals: 6, // Optional: currency decimals (default: 6)
+ store: new InMemoryDigestStore(), // Required. Use Redis/DB in production.
rpcUrl: '...', // Optional: custom gRPC endpoint
network: 'mainnet', // Optional: 'mainnet' | 'testnet' | 'devnet'
registryUrl: 'https://suimpp.dev/api/report', // Optional: report payments to suimpp.dev
@@ -136,6 +140,8 @@ Verification checks:
- Transaction succeeded on-chain
- Payment sent to correct recipient (address-normalized comparison)
- Amount >= requested (BigInt precision, no floating-point)
+- Payment proof signature matches the transaction sender
+- Digest has not been used before according to the required `store`
## Client API
@@ -144,12 +150,12 @@ Verification checks:
Creates a Sui payment method for the client.
```typescript
-import { sui } from '@suimpp/mpp/client';
+import { USDC, sui } from '@suimpp/mpp/client';
const method = sui({
client: grpcClient, // Any Sui client (SuiGrpcClient, etc.)
signer: ed25519Keypair, // Signer from @mysten/sui/cryptography
- decimals: 6, // Optional: currency decimals (default: 6)
+ currency: USDC, // Coin type + decimals
execute: async (tx) => { // Optional: custom execution (gas sponsor, etc.)
return myGasManager.execute(tx);
},
@@ -160,20 +166,23 @@ const method = sui({
|--------|------|----------|-------------|
| `client` | `ClientWithCoreApi` | Yes | Any Sui client implementing the core API |
| `signer` | `Signer` | Yes | Any `Signer` from `@mysten/sui/cryptography` — `Ed25519Keypair` works |
-| `decimals` | `number` | No | Decimal places for the currency (default: 6) |
+| `currency` | `Currency` | Yes | Single-currency metadata including coin type and decimals |
| `execute` | `(tx: Transaction) => Promise<{ digest: string }>` | No | Override transaction execution (e.g. gas sponsor/manager) |
-The client uses the [`coinWithBalance`](https://sdk.mystenlabs.com/sui/transaction-building/intents) intent to automatically resolve, merge, and split coins for the exact payment amount, then signs and broadcasts the transaction (or delegates to `execute` if provided).
+The client builds a `0x2::coin::send_funds` transaction for the exact payment amount, then signs and broadcasts it (or delegates to `execute` if provided).
## Constants
-### `SUI_USDC_TYPE`
+### Known currencies
-The Sui coin type for Circle-issued USDC on mainnet.
+The package exports common `Currency` presets and their raw coin type strings.
```typescript
-import { SUI_USDC_TYPE } from '@suimpp/mpp';
-// '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
+import { SUI_DOLLAR, USDC, USDC_TESTNET } from '@suimpp/mpp';
+
+USDC; // { type: SUI_USDC_TYPE, decimals: 6 }
+USDC_TESTNET; // { type: SUI_USDC_TESTNET_TYPE, decimals: 6 }
+SUI_DOLLAR; // { type: SUI_DOLLAR_TYPE, decimals: 6 }
```
## Utilities
@@ -201,7 +210,7 @@ MPP is chain-agnostic. We chose Sui because agent payments need:
## Testing
```bash
-pnpm --filter @suimpp/mpp test # 13 tests
+pnpm --filter @suimpp/mpp test # 29 tests
pnpm --filter @suimpp/mpp typecheck
```
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..4a78fae 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,19 +46,24 @@
"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": {
- "@mysten/sui": "^2",
+ "@mysten/sui": "^2.17.0",
"mppx": "^0.4.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..0e52366 100644
--- a/packages/mpp/src/client.ts
+++ b/packages/mpp/src/client.ts
@@ -1,62 +1,99 @@
-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 } from '@mysten/sui/transactions';
+import { Credential, Method } from 'mppx';
+import type { Currency } from './constants.js';
import { suiCharge } from './method.js';
+import { createSuiPaymentProofBytes } from './proof.js';
import { parseAmountToRaw } from './utils.js';
export { suiCharge } from './method.js';
-export { SUI_USDC_TYPE } from './constants.js';
+export {
+ SUI_DOLLAR,
+ SUI_DOLLAR_TYPE,
+ SUI_USDC_TESTNET_TYPE,
+ SUI_USDC_TYPE,
+ USDC,
+ USDC_TESTNET,
+} from './constants.js';
+export type { Currency } from './constants.js';
export interface SuiChargeOptions {
client: ClientWithCoreApi;
signer: Signer;
- /** Number of decimal places for the currency (default: 6, e.g. USDC). */
- decimals?: number;
+ currency: Currency;
/** Override transaction execution (e.g. to route through a gas manager). */
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;
+ if (!options.currency) {
+ throw new Error('[suimpp] Currency is required');
+ }
return Method.toClient(suiCharge, {
async createCredential({ challenge }) {
const { amount, currency, recipient } = challenge.request;
- const amountRaw = parseAmountToRaw(amount, decimals);
+ if (currency !== options.currency.type) {
+ throw new Error(`Unsupported currency: ${currency}`);
+ }
+ const amountRaw = parseAmountToRaw(amount, options.currency.decimals);
const tx = new Transaction();
- tx.setSender(address);
+ tx.setSender(options.signer.toSuiAddress());
- const payment = coinWithBalance({ balance: amountRaw, type: currency });
- tx.transferObjects([payment], recipient);
+ // `send_funds` so that the recipient receives the balance in ABs (not coins)
+ tx.moveCall({
+ target: '0x2::balance::send_funds',
+ arguments: [
+ tx.balance({ type: options.currency.type, balance: amountRaw }),
+ tx.pure.address(recipient),
+ ],
+ typeArguments: [options.currency.type],
+ });
- let result;
+ let result: TransactionResult;
try {
if (options.execute) {
result = await options.execute(tx);
} else {
- const built = await tx.build({ client: options.client });
- const { signature } = await options.signer.signTransaction(built);
- const execResult = await options.client.core.executeTransaction({
- transaction: built,
- signatures: [signature],
- include: { effects: true },
- });
+ const execResult =
+ await options.client.core.signAndExecuteTransaction({
+ transaction: await tx.build({ client: options.client }),
+ signer: options.signer,
+ 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',
+ );
}
- result = execResult.Transaction!;
+ if (!execResult.Transaction) {
+ throw new Error('Transaction failed');
+ }
+ result = execResult.Transaction;
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
throw new Error(`Payment transaction failed: ${msg}`);
}
+ const proof = await options.signer.signPersonalMessage(
+ createSuiPaymentProofBytes({
+ challenge,
+ digest: result.digest,
+ }),
+ );
+
return Credential.serialize({
challenge,
- payload: { digest: result.digest },
+ payload: {
+ digest: result.digest,
+ signature: proof.signature,
+ },
});
},
});
diff --git a/packages/mpp/src/constants.ts b/packages/mpp/src/constants.ts
index 1d59a66..f56609d 100644
--- a/packages/mpp/src/constants.ts
+++ b/packages/mpp/src/constants.ts
@@ -1,2 +1,28 @@
+export interface Currency {
+ type: string;
+ decimals: number;
+}
+
export const SUI_USDC_TYPE =
'0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC';
+
+export const SUI_USDC_TESTNET_TYPE =
+ '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC';
+
+export const SUI_DOLLAR_TYPE =
+ '0x44f838219cf67b058f3b37907b655f226153c18e33dfcd0da559a844fea9b1c1::usdsui::USDSUI';
+
+export const USDC = {
+ type: SUI_USDC_TYPE,
+ decimals: 6,
+} as const satisfies Currency;
+
+export const USDC_TESTNET = {
+ type: SUI_USDC_TESTNET_TYPE,
+ decimals: 6,
+} as const satisfies Currency;
+
+export const SUI_DOLLAR = {
+ type: SUI_DOLLAR_TYPE,
+ decimals: 6,
+} as const satisfies Currency;
diff --git a/packages/mpp/src/index.ts b/packages/mpp/src/index.ts
index ae41860..257433c 100644
--- a/packages/mpp/src/index.ts
+++ b/packages/mpp/src/index.ts
@@ -5,4 +5,12 @@ export { sui as suiServer } from './server.js';
export type { SuiServerOptions, PaymentReport, DigestStore } from './server.js';
export { InMemoryDigestStore } from './in-memory-digest-store.js';
export { parseAmountToRaw, withRetry } from './utils.js';
-export { SUI_USDC_TYPE } from './constants.js';
+export {
+ SUI_DOLLAR,
+ SUI_DOLLAR_TYPE,
+ SUI_USDC_TESTNET_TYPE,
+ SUI_USDC_TYPE,
+ USDC,
+ USDC_TESTNET,
+} from './constants.js';
+export type { Currency } from './constants.js';
diff --git a/packages/mpp/src/method.ts b/packages/mpp/src/method.ts
index 0406df7..f3fc505 100644
--- a/packages/mpp/src/method.ts
+++ b/packages/mpp/src/method.ts
@@ -7,6 +7,7 @@ export const suiCharge = Method.from({
credential: {
payload: z.object({
digest: z.string(),
+ signature: z.string(),
}),
},
request: z.object({
diff --git a/packages/mpp/src/proof.ts b/packages/mpp/src/proof.ts
new file mode 100644
index 0000000..6bf5a37
--- /dev/null
+++ b/packages/mpp/src/proof.ts
@@ -0,0 +1,39 @@
+import type { Challenge } from 'mppx';
+
+export interface SuiPaymentProofMessage {
+ challenge: Challenge.Challenge<
+ {
+ amount: string;
+ currency: string;
+ recipient: string;
+ },
+ 'charge',
+ 'sui'
+ >;
+ digest: string;
+}
+
+const textEncoder = new TextEncoder();
+
+export function createSuiPaymentProofMessage({
+ challenge,
+ digest,
+}: SuiPaymentProofMessage): string {
+ return JSON.stringify({
+ domain: 'suimpp.sui.payment-proof',
+ version: 1,
+ method: challenge.method,
+ intent: challenge.intent,
+ challengeId: challenge.id,
+ amount: challenge.request.amount,
+ currency: challenge.request.currency,
+ recipient: challenge.request.recipient,
+ digest,
+ });
+}
+
+export function createSuiPaymentProofBytes(
+ message: SuiPaymentProofMessage,
+): Uint8Array {
+ return textEncoder.encode(createSuiPaymentProofMessage(message));
+}
diff --git a/packages/mpp/src/server.test.ts b/packages/mpp/src/server.test.ts
deleted file mode 100644
index 0973ce3..0000000
--- a/packages/mpp/src/server.test.ts
+++ /dev/null
@@ -1,291 +0,0 @@
-import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
-import { InMemoryDigestStore } from './in-memory-digest-store.js';
-
-const USDC_TYPE = '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC';
-const RECIPIENT = '0xrecipient_address';
-const SENDER = '0xsender_address';
-
-function buildMockTx({
- success = true,
- coinType = USDC_TYPE,
- recipientAddr = RECIPIENT,
- amount = '10000',
- senderAddr = SENDER,
-}: {
- success?: boolean;
- coinType?: string;
- recipientAddr?: string;
- amount?: string;
- senderAddr?: string;
-} = {}) {
- const txData = {
- digest: '0xdigest123',
- status: { success },
- balanceChanges: [
- { coinType, address: recipientAddr, amount },
- { coinType, address: senderAddr, amount: `-${amount}` },
- ],
- };
-
- return success
- ? { Transaction: txData, FailedTransaction: undefined }
- : { Transaction: undefined, FailedTransaction: txData };
-}
-
-function buildCredential(digest = '0xdigest123', amount = '0.01') {
- return {
- payload: { digest },
- challenge: {
- request: {
- amount,
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- },
- },
- };
-}
-
-const mockGetTransaction = vi.fn();
-
-vi.mock('@mysten/sui/grpc', () => ({
- SuiGrpcClient: vi.fn().mockImplementation(() => ({
- core: {
- getTransaction: mockGetTransaction,
- },
- })),
-}));
-
-vi.mock('@mysten/sui/utils', () => ({
- normalizeSuiAddress: vi.fn((addr: string) => addr.toLowerCase()),
-}));
-
-describe('server verify', () => {
- let suiFn: typeof import('./server.js').sui;
- const originalEnv = process.env.NODE_ENV;
-
- beforeEach(async () => {
- vi.clearAllMocks();
- const mod = await import('./server.js');
- suiFn = mod.sui;
- });
-
- afterEach(() => {
- process.env.NODE_ENV = originalEnv;
- });
-
- it('accepts valid payment with correct amount', async () => {
- mockGetTransaction.mockResolvedValue(buildMockTx());
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store: new InMemoryDigestStore(),
- });
-
- const result = await (serverMethod as any).verify({
- credential: buildCredential(),
- });
-
- expect(result.reference).toBe('0xdigest123');
- expect(result.status).toBe('success');
- });
-
- it('rejects failed transaction', async () => {
- mockGetTransaction.mockResolvedValue(buildMockTx({ success: false }));
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store: new InMemoryDigestStore(),
- });
-
- await expect(
- (serverMethod as any).verify({ credential: buildCredential() }),
- ).rejects.toThrow('Transaction failed on-chain');
- });
-
- it('rejects when payment not sent to recipient', async () => {
- mockGetTransaction.mockResolvedValue(
- buildMockTx({ recipientAddr: '0xwrong_address' }),
- );
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store: new InMemoryDigestStore(),
- });
-
- await expect(
- (serverMethod as any).verify({ credential: buildCredential() }),
- ).rejects.toThrow('Payment not found');
- });
-
- it('rejects when amount is less than requested', async () => {
- mockGetTransaction.mockResolvedValue(buildMockTx({ amount: '5000' }));
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store: new InMemoryDigestStore(),
- });
-
- await expect(
- (serverMethod as any).verify({ credential: buildCredential() }),
- ).rejects.toThrow('Transferred');
- });
-
- it('rejects when no balance changes', async () => {
- mockGetTransaction.mockResolvedValue({
- Transaction: {
- digest: '0xdigest123',
- status: { success: true },
- balanceChanges: [],
- },
- });
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store: new InMemoryDigestStore(),
- });
-
- await expect(
- (serverMethod as any).verify({ credential: buildCredential() }),
- ).rejects.toThrow('Payment not found');
- });
-});
-
-describe('digest replay protection', () => {
- let suiFn: typeof import('./server.js').sui;
- const originalEnv = process.env.NODE_ENV;
-
- beforeEach(async () => {
- vi.clearAllMocks();
- const mod = await import('./server.js');
- suiFn = mod.sui;
- });
-
- afterEach(() => {
- process.env.NODE_ENV = originalEnv;
- });
-
- it('accepts a valid digest on first use', async () => {
- const store = new InMemoryDigestStore();
- mockGetTransaction.mockResolvedValue(buildMockTx());
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store,
- });
-
- const result = await (serverMethod as any).verify({
- credential: buildCredential(),
- });
-
- expect(result.reference).toBe('0xdigest123');
- expect(result.status).toBe('success');
- });
-
- it('rejects the same digest on second use', async () => {
- const store = new InMemoryDigestStore();
- mockGetTransaction.mockResolvedValue(buildMockTx());
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store,
- });
-
- await (serverMethod as any).verify({
- credential: buildCredential(),
- });
-
- await expect(
- (serverMethod as any).verify({
- credential: buildCredential('0xdigest123', '0.02'),
- }),
- ).rejects.toThrow('Digest already used');
- });
-
- it('accepts a different digest after first is consumed', async () => {
- const store = new InMemoryDigestStore();
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store,
- });
-
- mockGetTransaction.mockResolvedValue(buildMockTx());
- await (serverMethod as any).verify({
- credential: buildCredential('0xdigest123'),
- });
-
- mockGetTransaction.mockResolvedValue({
- Transaction: {
- digest: '0xdigest456',
- status: { success: true },
- balanceChanges: [
- { coinType: USDC_TYPE, address: RECIPIENT, amount: '10000' },
- { coinType: USDC_TYPE, address: SENDER, amount: '-10000' },
- ],
- },
- });
-
- const result = await (serverMethod as any).verify({
- credential: buildCredential('0xdigest456'),
- });
-
- expect(result.reference).toBe('0xdigest456');
- });
-
- it('accepts the same digest after TTL expiry', async () => {
- const store = new InMemoryDigestStore(50);
- mockGetTransaction.mockResolvedValue(buildMockTx());
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store,
- });
-
- await (serverMethod as any).verify({
- credential: buildCredential(),
- });
-
- await new Promise((r) => setTimeout(r, 100));
-
- const result = await (serverMethod as any).verify({
- credential: buildCredential(),
- });
- 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');
- });
-
- 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;
- mockGetTransaction.mockResolvedValue(buildMockTx());
-
- const serverMethod = suiFn({
- currency: USDC_TYPE,
- recipient: RECIPIENT,
- store,
- });
-
- await expect(
- (serverMethod as any).verify({ credential: buildCredential() }),
- ).rejects.toThrow('Redis down');
-
- expect(store.set).toHaveBeenCalledWith('0xdigest123');
- });
-});
diff --git a/packages/mpp/src/server.ts b/packages/mpp/src/server.ts
index 7d820ee..311e94e 100644
--- a/packages/mpp/src/server.ts
+++ b/packages/mpp/src/server.ts
@@ -1,12 +1,24 @@
-import { Method, Receipt } from 'mppx';
import { SuiGrpcClient } from '@mysten/sui/grpc';
+import { getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc';
import { normalizeSuiAddress } from '@mysten/sui/utils';
+import { verifyPersonalMessageSignature } from '@mysten/sui/verify';
+import { Method, Receipt } from 'mppx';
+import type { Currency } from './constants.js';
import { suiCharge } from './method.js';
+import { createSuiPaymentProofBytes } from './proof.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';
+export { InMemoryDigestStore } from './in-memory-digest-store.js';
+export {
+ SUI_DOLLAR,
+ SUI_DOLLAR_TYPE,
+ SUI_USDC_TESTNET_TYPE,
+ SUI_USDC_TYPE,
+ USDC,
+ USDC_TESTNET,
+} from './constants.js';
+export type { Currency } from './constants.js';
export interface DigestStore {
has(digest: string): Promise;
@@ -23,46 +35,42 @@ export interface PaymentReport {
}
export interface SuiServerOptions {
- currency: string;
+ currency: Currency;
recipient: string;
- /** Number of decimal places for the currency (default: 6, e.g. USDC). */
- decimals?: number;
rpcUrl?: string;
- network?: 'mainnet' | 'testnet' | 'devnet';
- /** Digest store for replay protection. Required in production. Falls back to in-memory in dev. */
- store?: DigestStore;
+ network?: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
+ /** Digest store for replay protection. Use a shared durable store in production. */
+ store: DigestStore;
/** Called after successful on-chain verification with payment data. */
onPayment?: (report: PaymentReport) => void;
}
-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 (!options.store) {
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.',
+ '[suimpp] DigestStore is required. ' +
+ 'Provide a Redis or DB-backed store via SuiServerOptions.store. ' +
+ 'Use InMemoryDigestStore explicitly only for local development or tests.',
);
}
-
- if (!_defaultStore) {
- _defaultStore = new InMemoryDigestStore();
- console.warn(
- '[suimpp] No DigestStore provided. Using in-memory store. ' +
- 'This is NOT safe for production or multi-instance deployments.',
- );
+ if (!options.store.has || typeof options.store.has !== 'function') {
+ throw new Error('[suimpp] DigestStore must implement has method');
}
- return _defaultStore;
+ if (!options.store.set || typeof options.store.set !== 'function') {
+ throw new Error('[suimpp] DigestStore must implement set method');
+ }
+ return options.store;
}
export function sui(options: SuiServerOptions) {
+ if (!options.currency) {
+ throw new Error('[suimpp] Currency is required');
+ }
+
const network = options.network ?? 'mainnet';
- const decimals = options.decimals ?? 6;
+ const baseUrl = options.rpcUrl ?? getJsonRpcFullnodeUrl(network);
const client = new SuiGrpcClient({
- baseUrl: options.rpcUrl ?? `https://fullnode.${network}.sui.io:443`,
+ baseUrl,
network,
});
@@ -71,12 +79,17 @@ export function sui(options: SuiServerOptions) {
return Method.toServer(suiCharge, {
defaults: {
- currency: options.currency,
+ currency: options.currency.type,
recipient: options.recipient,
},
async verify({ credential }) {
const digest = credential.payload.digest;
+ if (credential.challenge.request.currency !== options.currency.type) {
+ throw new Error(
+ `Unsupported currency: ${credential.challenge.request.currency}`,
+ );
+ }
const alreadyUsed = await digestStore.has(digest);
if (alreadyUsed) {
@@ -85,10 +98,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, transaction: 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;
@@ -98,25 +116,48 @@ export function sui(options: SuiServerOptions) {
const payment = resolved.balanceChanges.find(
(bc) =>
- bc.coinType === options.currency &&
+ bc.coinType === options.currency.type &&
normalizeSuiAddress(bc.address) === normalizedRecipient &&
BigInt(bc.amount) > 0n,
);
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,
+ options.currency.decimals,
+ );
if (transferredRaw < requestedRaw) {
throw new Error(
`Transferred ${transferredRaw} < requested ${requestedRaw} (raw units)`,
);
}
+ const publicKey = await verifyPersonalMessageSignature(
+ createSuiPaymentProofBytes({
+ challenge: credential.challenge,
+ digest,
+ }),
+ credential.payload.signature,
+ ).catch(() => {
+ throw new Error('Invalid payment proof signature');
+ });
+ const sender = resolved.transaction?.sender;
+ if (!sender) {
+ throw new Error('Transaction sender not found');
+ }
+ if (
+ normalizeSuiAddress(publicKey.toSuiAddress()) !==
+ normalizeSuiAddress(sender)
+ ) {
+ throw new Error(
+ 'Payment proof signer does not match transaction sender',
+ );
+ }
+
await digestStore.set(digest);
const receipt = Receipt.from({
@@ -128,17 +169,17 @@ export function sui(options: SuiServerOptions) {
const report: PaymentReport = {
digest,
- sender: resolved.balanceChanges.find(
- (bc) => bc.coinType === options.currency && BigInt(bc.amount) < 0n,
- )?.address,
+ sender,
recipient: options.recipient,
amount: credential.challenge.request.amount,
- currency: options.currency,
+ currency: options.currency.type,
network,
};
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..7b329e2
--- /dev/null
+++ b/packages/mpp/test/e2e/globalSetup.ts
@@ -0,0 +1,56 @@
+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_BASE_TAG = 'd0b6a5d9663a5e3e4cfe4a04fdc92130f8ed502c';
+const SUI_TOOLS_TAG =
+ process.env.SUI_TOOLS_TAG ||
+ (process.arch === 'arm64'
+ ? `${SUI_TOOLS_BASE_TAG}-arm64`
+ : SUI_TOOLS_BASE_TAG);
+
+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..2022f19
--- /dev/null
+++ b/packages/mpp/test/e2e/sui-payment.test.ts
@@ -0,0 +1,165 @@
+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 { createSuiPaymentProofBytes } from '../../src/proof.js';
+import {
+ type PaymentReport,
+ SUI_USDC_TYPE,
+ 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; signature: string },
+ SuiChargeChallenge
+>;
+
+describe('Sui localnet e2e payment', () => {
+ const localnetClient = getClient();
+ const payerKeypair = Ed25519Keypair.generate();
+ const thiefKeypair = Ed25519Keypair.generate();
+ const recipientKeypair = Ed25519Keypair.generate();
+ const recipient = recipientKeypair.getPublicKey().toSuiAddress();
+
+ beforeAll(async () => {
+ await fundAddress(payerKeypair.getPublicKey().toSuiAddress());
+ });
+
+ function buildChallenge(id: string): SuiChargeChallenge {
+ return Challenge.fromMethod(suiCharge, {
+ id,
+ realm: 'suimpp-e2e',
+ request: {
+ amount: PAYMENT_AMOUNT,
+ currency: SUI_TYPE_ARG,
+ recipient,
+ },
+ }) as SuiChargeChallenge;
+ }
+
+ function buildServerMethod(onPayment?: (report: PaymentReport) => void) {
+ return createSuiServer({
+ currency: { type: SUI_TYPE_ARG, decimals: SUI_DECIMALS },
+ recipient,
+ rpcUrl: getFullnodeUrl(),
+ network: 'localnet',
+ store: new InMemoryDigestStore(),
+ onPayment,
+ });
+ }
+
+ async function createCredential(challenge: SuiChargeChallenge) {
+ const clientMethod = createSuiClient({
+ client: localnetClient,
+ signer: payerKeypair,
+ currency: { type: SUI_TYPE_ARG, decimals: SUI_DECIMALS },
+ });
+ const authorization = await clientMethod.createCredential({ challenge });
+ const credential = Credential.deserialize<{ digest: string }>(
+ authorization,
+ ) as SuiChargeCredential;
+
+ await localnetClient.waitForTransaction({
+ digest: credential.payload.digest,
+ });
+
+ return credential;
+ }
+
+ it('creates an on-chain credential and verifies the payment once', async () => {
+ const onPayment = vi.fn();
+ const challenge = buildChallenge('sui-localnet-e2e-payment');
+ const serverMethod = buildServerMethod(onPayment);
+ const credential = await createCredential(challenge);
+
+ 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');
+ });
+
+ it('rejects a stolen proof signed by a different key', async () => {
+ const challenge = buildChallenge('sui-localnet-e2e-stolen-proof');
+ const serverMethod = buildServerMethod();
+ const credential = await createCredential(challenge);
+
+ const stolenProof = await thiefKeypair.signPersonalMessage(
+ createSuiPaymentProofBytes({
+ challenge,
+ digest: credential.payload.digest,
+ }),
+ );
+ const stolenCredential: SuiChargeCredential = {
+ ...credential,
+ payload: {
+ ...credential.payload,
+ signature: stolenProof.signature,
+ },
+ };
+
+ await expect(
+ serverMethod.verify({
+ credential: stolenCredential,
+ request: challenge.request,
+ }),
+ ).rejects.toThrow('Payment proof signer does not match transaction sender');
+ });
+
+ it('rejects a payment made with the wrong currency', async () => {
+ const challenge = buildChallenge('sui-localnet-e2e-wrong-currency');
+ const credential = await createCredential(challenge);
+ const serverMethod = createSuiServer({
+ currency: { type: SUI_USDC_TYPE, decimals: 6 },
+ recipient,
+ rpcUrl: getFullnodeUrl(),
+ network: 'localnet',
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(
+ serverMethod.verify({
+ credential,
+ request: challenge.request,
+ }),
+ ).rejects.toThrow(`Unsupported currency: ${SUI_TYPE_ARG}`);
+ });
+});
diff --git a/packages/mpp/test/unit/client.test.ts b/packages/mpp/test/unit/client.test.ts
new file mode 100644
index 0000000..501378c
--- /dev/null
+++ b/packages/mpp/test/unit/client.test.ts
@@ -0,0 +1,218 @@
+import type { Challenge } from 'mppx';
+import { Credential } from 'mppx';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import type {
+ SuiChargeOptions,
+ sui as createSuiClient,
+} from '../../src/client.js';
+
+const { mockBalance, mockBuild, mockMoveCall, mockPureAddress } = vi.hoisted(
+ () => ({
+ mockBalance: vi.fn(() => 'balance_result'),
+ mockBuild: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3])),
+ mockMoveCall: vi.fn(),
+ mockPureAddress: vi.fn(() => 'recipient_address_result'),
+ }),
+);
+
+vi.mock('@mysten/sui/transactions', () => {
+ const Transaction = vi.fn().mockImplementation(() => ({
+ setSender: vi.fn(),
+ balance: mockBalance,
+ pure: {
+ address: mockPureAddress,
+ },
+ moveCall: mockMoveCall,
+ build: mockBuild,
+ }));
+ return { Transaction };
+});
+
+const mockSignAndExecuteTransaction = vi.fn();
+
+const mockClient = {
+ core: {
+ signAndExecuteTransaction: mockSignAndExecuteTransaction,
+ },
+};
+
+const mockSigner = {
+ toSuiAddress: () => '0xagent_address',
+ signPersonalMessage: vi
+ .fn()
+ .mockResolvedValue({ bytes: 'proof_bytes', signature: 'proof_sig' }),
+ 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'
+>;
+const USDC = { type: '0x::usdc::USDC', decimals: 6 };
+
+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 send_funds and executes it', async () => {
+ mockSignAndExecuteTransaction.mockResolvedValue({
+ Transaction: { digest: '0xtxdigest' },
+ });
+
+ const clientMethod = suiFn({
+ client: typedMockClient,
+ signer: typedMockSigner,
+ currency: USDC,
+ });
+
+ const challenge = buildChallenge();
+
+ const authorization = await clientMethod.createCredential({ challenge });
+ const credential = Credential.deserialize<{
+ digest: string;
+ signature: string;
+ }>(authorization);
+
+ expect(mockSigner.signPersonalMessage).toHaveBeenCalledWith(
+ expect.any(Uint8Array),
+ );
+ expect(mockMoveCall).toHaveBeenCalledWith({
+ target: '0x2::balance::send_funds',
+ arguments: ['balance_result', 'recipient_address_result'],
+ typeArguments: ['0x::usdc::USDC'],
+ });
+ expect(mockBuild).toHaveBeenCalledWith({ client: typedMockClient });
+ expect(mockSignAndExecuteTransaction).toHaveBeenCalledWith({
+ transaction: expect.any(Uint8Array),
+ signer: typedMockSigner,
+ include: { effects: true },
+ });
+ expect(credential.payload).toEqual({
+ digest: '0xtxdigest',
+ signature: 'proof_sig',
+ });
+ });
+
+ it('throws when transaction execution fails', async () => {
+ mockSignAndExecuteTransaction.mockResolvedValue({
+ FailedTransaction: { status: { error: 'out of gas' } },
+ });
+
+ const clientMethod = suiFn({
+ client: typedMockClient,
+ signer: typedMockSigner,
+ currency: USDC,
+ });
+
+ const challenge = buildChallenge();
+
+ await expect(clientMethod.createCredential({ challenge })).rejects.toThrow(
+ 'Payment transaction failed',
+ );
+ });
+
+ it('uses decimals from configured Currency', async () => {
+ mockSignAndExecuteTransaction.mockResolvedValue({
+ Transaction: { digest: '0xtxdigest' },
+ });
+
+ const clientMethod = suiFn({
+ client: typedMockClient,
+ signer: typedMockSigner,
+ currency: { type: '0x::usdc::USDC', decimals: 2 },
+ });
+
+ await clientMethod.createCredential({
+ challenge: buildChallenge('1.23'),
+ });
+
+ expect(mockBalance).toHaveBeenCalledWith({
+ balance: 123n,
+ type: '0x::usdc::USDC',
+ });
+ });
+
+ it('requires configured currency metadata', async () => {
+ mockSignAndExecuteTransaction.mockResolvedValue({
+ Transaction: { digest: '0xtxdigest' },
+ });
+
+ expect(() =>
+ // @ts-expect-error Runtime guard protects JavaScript callers too.
+ suiFn({ client: typedMockClient, signer: typedMockSigner }),
+ ).toThrow('Currency is required');
+ });
+
+ it('rejects an unsupported configured currency', async () => {
+ const clientMethod = suiFn({
+ client: typedMockClient,
+ signer: typedMockSigner,
+ currency: { type: '0x::eurc::EURC', decimals: 6 },
+ });
+
+ await expect(
+ clientMethod.createCredential({ challenge: buildChallenge() }),
+ ).rejects.toThrow('Unsupported currency: 0x::usdc::USDC');
+ });
+
+ it('uses custom execute when provided', async () => {
+ const customExecute = vi
+ .fn()
+ .mockResolvedValue({ digest: '0xcustom', effects: {} });
+
+ const clientMethod = suiFn({
+ client: typedMockClient,
+ signer: typedMockSigner,
+ currency: USDC,
+ execute: customExecute,
+ });
+
+ const challenge = buildChallenge('1.00');
+
+ const authorization = await clientMethod.createCredential({ challenge });
+ const credential = Credential.deserialize<{
+ digest: string;
+ signature: string;
+ }>(authorization);
+
+ expect(customExecute).toHaveBeenCalled();
+ expect(mockSigner.signPersonalMessage).toHaveBeenCalledWith(
+ expect.any(Uint8Array),
+ );
+ expect(mockSignAndExecuteTransaction).not.toHaveBeenCalled();
+ expect(credential.payload).toMatchObject({
+ digest: '0xcustom',
+ signature: 'proof_sig',
+ });
+ });
+});
diff --git a/packages/mpp/test/unit/server.test.ts b/packages/mpp/test/unit/server.test.ts
new file mode 100644
index 0000000..f7338d1
--- /dev/null
+++ b/packages/mpp/test/unit/server.test.ts
@@ -0,0 +1,458 @@
+import type { Challenge, Credential, Method } from 'mppx';
+import { 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_USDC_TYPE,
+ USDC,
+ type sui as createSuiServer,
+} from '../../src/server.js';
+
+const RECIPIENT = '0xrecipient_address';
+const SENDER = '0xsender_address';
+const ALT_CURRENCY = '0x::eurc::EURC';
+
+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; signature: string },
+ SuiChargeChallenge
+>;
+
+function buildMockTx({
+ success = true,
+ coinType = SUI_USDC_TYPE,
+ recipientAddr = RECIPIENT,
+ amount = '10000',
+ senderAddr = SENDER,
+}: {
+ success?: boolean;
+ coinType?: string;
+ recipientAddr?: string;
+ amount?: string;
+ senderAddr?: string;
+} = {}) {
+ const txData = {
+ digest: '0xdigest123',
+ status: { success },
+ transaction: {
+ sender: senderAddr,
+ },
+ balanceChanges: [
+ { coinType, address: recipientAddr, amount },
+ { coinType, address: senderAddr, amount: `-${amount}` },
+ ],
+ };
+
+ return success
+ ? { Transaction: txData, FailedTransaction: undefined }
+ : { Transaction: undefined, FailedTransaction: txData };
+}
+
+function buildCredential(
+ digest = '0xdigest123',
+ amount = '0.01',
+ signature = 'proof_sig',
+ currency = SUI_USDC_TYPE,
+): SuiCredential {
+ return {
+ payload: { digest, signature },
+ challenge: {
+ id: 'test-challenge',
+ intent: 'charge',
+ method: 'sui',
+ realm: 'test',
+ request: {
+ amount,
+ currency,
+ recipient: RECIPIENT,
+ },
+ },
+ };
+}
+
+function verifyPayment(
+ serverMethod: SuiServerMethod,
+ credential = buildCredential(),
+) {
+ return serverMethod.verify({
+ credential,
+ request: credential.challenge.request,
+ });
+}
+
+const { mockGetTransaction, mockVerifyPersonalMessageSignature } = vi.hoisted(
+ () => ({
+ mockGetTransaction: vi.fn(),
+ mockVerifyPersonalMessageSignature: vi.fn(),
+ }),
+);
+
+vi.mock('@mysten/sui/grpc', () => ({
+ SuiGrpcClient: vi.fn().mockImplementation(() => ({
+ core: {
+ getTransaction: mockGetTransaction,
+ },
+ })),
+}));
+
+vi.mock('@mysten/sui/utils', () => ({
+ normalizeSuiAddress: vi.fn((addr: string) => addr.toLowerCase()),
+}));
+
+vi.mock('@mysten/sui/verify', () => ({
+ verifyPersonalMessageSignature: mockVerifyPersonalMessageSignature,
+}));
+
+describe('server verify', () => {
+ let suiFn: typeof createSuiServer;
+
+ beforeEach(async () => {
+ vi.clearAllMocks();
+ mockVerifyPersonalMessageSignature.mockResolvedValue({
+ toSuiAddress: () => SENDER,
+ });
+ const mod = await import('../../src/server.js');
+ suiFn = mod.sui;
+ });
+
+ it('accepts valid payment with correct amount', async () => {
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ const result = await verifyPayment(serverMethod);
+
+ expect(result.reference).toBe('0xdigest123');
+ expect(result.status).toBe('success');
+ });
+
+ it('rejects failed transaction', async () => {
+ mockGetTransaction.mockResolvedValue(buildMockTx({ success: false }));
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow(
+ 'Transaction failed on-chain',
+ );
+ });
+
+ it('rejects when payment not sent to recipient', async () => {
+ mockGetTransaction.mockResolvedValue(
+ buildMockTx({ recipientAddr: '0xwrong_address' }),
+ );
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow(
+ 'Payment not found',
+ );
+ });
+
+ it('rejects when amount is less than requested', async () => {
+ mockGetTransaction.mockResolvedValue(buildMockTx({ amount: '5000' }));
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow('Transferred');
+ });
+
+ it('accepts a configured non-default currency', async () => {
+ const onPayment = vi.fn();
+ mockGetTransaction.mockResolvedValue(
+ buildMockTx({ coinType: ALT_CURRENCY, amount: '123' }),
+ );
+
+ const serverMethod = suiFn({
+ currency: { type: ALT_CURRENCY, decimals: 2 },
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ onPayment,
+ });
+
+ const credential = buildCredential(
+ '0xdigest123',
+ '1.23',
+ 'proof_sig',
+ ALT_CURRENCY,
+ );
+ const result = await verifyPayment(serverMethod, credential);
+
+ expect(result.status).toBe('success');
+ expect(onPayment).toHaveBeenCalledWith(
+ expect.objectContaining({ currency: ALT_CURRENCY, amount: '1.23' }),
+ );
+ });
+
+ it('rejects an unconfigured challenge currency', async () => {
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(
+ verifyPayment(
+ serverMethod,
+ buildCredential('0xdigest123', '0.01', 'proof_sig', ALT_CURRENCY),
+ ),
+ ).rejects.toThrow(`Unsupported currency: ${ALT_CURRENCY}`);
+ expect(mockGetTransaction).not.toHaveBeenCalled();
+ });
+
+ it('uses configured currency decimals for amount checks', async () => {
+ mockGetTransaction.mockResolvedValue(
+ buildMockTx({ coinType: ALT_CURRENCY, amount: '122' }),
+ );
+
+ const serverMethod = suiFn({
+ currency: { type: ALT_CURRENCY, decimals: 2 },
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(
+ verifyPayment(
+ serverMethod,
+ buildCredential('0xdigest123', '1.23', 'proof_sig', ALT_CURRENCY),
+ ),
+ ).rejects.toThrow('Transferred 122 < requested 123');
+ });
+
+ it('rejects when no balance changes', async () => {
+ mockGetTransaction.mockResolvedValue({
+ Transaction: {
+ digest: '0xdigest123',
+ status: { success: true },
+ balanceChanges: [],
+ },
+ });
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow(
+ 'Payment not found',
+ );
+ });
+
+ it('rejects when proof signature is invalid', async () => {
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+ mockVerifyPersonalMessageSignature.mockRejectedValue(
+ new Error('bad signature'),
+ );
+
+ const store = {
+ has: vi.fn().mockResolvedValue(false),
+ set: vi.fn(),
+ } satisfies DigestStore;
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow(
+ 'Invalid payment proof signature',
+ );
+ expect(store.set).not.toHaveBeenCalled();
+ });
+
+ it('rejects when proof signer is not the transaction sender', async () => {
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+ mockVerifyPersonalMessageSignature.mockResolvedValue({
+ toSuiAddress: () => '0xthief',
+ });
+
+ const store = {
+ has: vi.fn().mockResolvedValue(false),
+ set: vi.fn(),
+ } satisfies DigestStore;
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow(
+ 'Payment proof signer does not match transaction sender',
+ );
+ expect(store.set).not.toHaveBeenCalled();
+ });
+
+ it('rejects when transaction sender is missing', async () => {
+ mockGetTransaction.mockResolvedValue({
+ Transaction: {
+ digest: '0xdigest123',
+ status: { success: true },
+ transaction: undefined,
+ balanceChanges: [
+ { coinType: SUI_USDC_TYPE, address: RECIPIENT, amount: '10000' },
+ { coinType: SUI_USDC_TYPE, address: SENDER, amount: '-10000' },
+ ],
+ },
+ });
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store: new InMemoryDigestStore(),
+ });
+
+ await expect(verifyPayment(serverMethod)).rejects.toThrow(
+ 'Transaction sender not found',
+ );
+ });
+});
+
+describe('digest replay protection', () => {
+ let suiFn: typeof createSuiServer;
+
+ beforeEach(async () => {
+ vi.clearAllMocks();
+ mockVerifyPersonalMessageSignature.mockResolvedValue({
+ toSuiAddress: () => SENDER,
+ });
+ const mod = await import('../../src/server.js');
+ suiFn = mod.sui;
+ });
+
+ it('accepts a valid digest on first use', async () => {
+ const store = new InMemoryDigestStore();
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ const result = await verifyPayment(serverMethod);
+
+ expect(result.reference).toBe('0xdigest123');
+ expect(result.status).toBe('success');
+ });
+
+ it('rejects the same digest on second use', async () => {
+ const store = new InMemoryDigestStore();
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ await verifyPayment(serverMethod);
+
+ await expect(
+ verifyPayment(serverMethod, buildCredential('0xdigest123', '0.02')),
+ ).rejects.toThrow('Digest already used');
+ });
+
+ it('accepts a different digest after first is consumed', async () => {
+ const store = new InMemoryDigestStore();
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+ await verifyPayment(serverMethod, buildCredential('0xdigest123'));
+
+ mockGetTransaction.mockResolvedValue({
+ Transaction: {
+ digest: '0xdigest456',
+ status: { success: true },
+ transaction: {
+ sender: SENDER,
+ },
+ balanceChanges: [
+ { coinType: SUI_USDC_TYPE, address: RECIPIENT, amount: '10000' },
+ { coinType: SUI_USDC_TYPE, address: SENDER, amount: '-10000' },
+ ],
+ },
+ });
+
+ const result = await verifyPayment(
+ serverMethod,
+ buildCredential('0xdigest456'),
+ );
+
+ expect(result.reference).toBe('0xdigest456');
+ });
+
+ it('accepts the same digest after TTL expiry', async () => {
+ const store = new InMemoryDigestStore(50);
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ await verifyPayment(serverMethod);
+
+ await new Promise((r) => setTimeout(r, 100));
+
+ const result = await verifyPayment(serverMethod);
+ expect(result.status).toBe('success');
+ });
+
+ it('throws on missing store', () => {
+ expect(() =>
+ // @ts-expect-error Runtime guard protects JavaScript callers too.
+ suiFn({ currency: USDC, recipient: RECIPIENT }),
+ ).toThrow('DigestStore is required');
+ });
+
+ 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 DigestStore;
+ mockGetTransaction.mockResolvedValue(buildMockTx());
+
+ const serverMethod = suiFn({
+ currency: USDC,
+ recipient: RECIPIENT,
+ store,
+ });
+
+ 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 52%
rename from packages/mpp/src/utils.test.ts
rename to packages/mpp/test/unit/utils.test.ts
index 24a83f9..b3977e6 100644
--- a/packages/mpp/src/utils.test.ts
+++ b/packages/mpp/test/unit/utils.test.ts
@@ -1,5 +1,11 @@
-import { describe, it, expect } from 'vitest';
-import { parseAmountToRaw } from './utils.js';
+import { describe, expect, it } from 'vitest';
+import {
+ SUI_DOLLAR,
+ SUI_DOLLAR_TYPE,
+ USDC,
+ USDC_TESTNET,
+} from '../../src/constants.js';
+import { parseAmountToRaw } from '../../src/utils.js';
describe('parseAmountToRaw', () => {
it('converts whole number', () => {
@@ -22,3 +28,14 @@ describe('parseAmountToRaw', () => {
expect(parseAmountToRaw('0.0000001', 6)).toBe(0n);
});
});
+
+describe('known currencies', () => {
+ it('exports individual Currency presets', () => {
+ expect(USDC).toMatchObject({ decimals: 6 });
+ expect(USDC_TESTNET).toMatchObject({ decimals: 6 });
+ expect(SUI_DOLLAR).toEqual({
+ type: SUI_DOLLAR_TYPE,
+ decimals: 6,
+ });
+ });
+});
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..761a9a4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -80,8 +80,8 @@ importers:
packages/mpp:
dependencies:
'@mysten/sui':
- specifier: ^2
- version: 2.13.0(typescript@5.9.3)
+ specifier: ^2.17.0
+ version: 2.17.0(typescript@5.9.3)
mppx:
specifier: ^0.4.9
version: 0.4.12(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(express@5.2.1)(hono@4.12.9)(openapi-types@12.1.3)(typescript@5.9.3)(viem@2.47.6(typescript@5.9.3)(zod@4.3.6))
@@ -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'}
@@ -557,15 +640,15 @@ packages:
'@cfworker/json-schema':
optional: true
- '@mysten/bcs@2.0.3':
- resolution: {integrity: sha512-dwcaL4HNAsEGpU3hKUAsXgCZp9l6++e2A3THpzoYZ8e7bsy4XH1V0dXD5dIzgNcVZiZfb6ZnDMG+gdF6+1WOQA==}
+ '@mysten/bcs@2.0.5':
+ resolution: {integrity: sha512-Dop9Xq36DPLlsmIDQZvUg4uJeBBxIGirgp2OXGaEff+mtLKFBoW2HnE3aSTSSpiMQH9XRhjwtiM16zFJhFqz0Q==}
- '@mysten/sui@2.13.0':
- resolution: {integrity: sha512-GG/XBUqrplPM1jEFMCiv7xA15qo5laaVmCVcdsZsJhzZInDJhxgV7IxFvkgrzA8bwIMhPMAA+m0CTXxznaS3eA==}
+ '@mysten/sui@2.17.0':
+ resolution: {integrity: sha512-TrS1BCPm4V6rC69MBejmcqnKIyJ5t1iksax4XA9jWarZxAAp9LMmdxEBebejyDT/yAJxYIf3fNm5WBkHE2qnIw==}
engines: {node: '>=22'}
- '@mysten/utils@0.3.1':
- resolution: {integrity: sha512-36KhxG284uhDdSnlkyNaS6fzKTX9FpP2WQWOwUKIRsqQFFIm2ooCf2TP1IuqrtMpkairwpiWkAS0eg7cpemVzg==}
+ '@mysten/utils@0.3.3':
+ resolution: {integrity: sha512-gVHn5toh24eXXLEyBknwwM2F/tbDgqPX0yj77KtHjuoYUallcQ9vSwGfGsAy39IcTB259Yprt/ZOEwdup+zrpA==}
'@next/env@15.5.14':
resolution: {integrity: sha512-aXeirLYuASxEgi4X4WhfXsShCFxWDfNn/8ZeC5YXAS2BB4A8FJi1kwwGL6nvMVboE7fZCzmJPNdMvVHc8JpaiA==}
@@ -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)
@@ -2664,16 +3294,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@mysten/bcs@2.0.3':
+ '@mysten/bcs@2.0.5':
dependencies:
- '@mysten/utils': 0.3.1
+ '@mysten/utils': 0.3.3
'@scure/base': 2.0.0
- '@mysten/sui@2.13.0(typescript@5.9.3)':
+ '@mysten/sui@2.17.0(typescript@5.9.3)':
dependencies:
'@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2)
- '@mysten/bcs': 2.0.3
- '@mysten/utils': 0.3.1
+ '@mysten/bcs': 2.0.5
+ '@mysten/utils': 0.3.3
'@noble/curves': 2.0.1
'@noble/hashes': 2.0.1
'@protobuf-ts/grpcweb-transport': 2.11.1
@@ -2691,7 +3321,7 @@ snapshots:
- '@gql.tada/vue-support'
- typescript
- '@mysten/utils@0.3.1':
+ '@mysten/utils@0.3.3':
dependencies:
'@scure/base': 2.0.0
@@ -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