From 7b708f90342d9b508b346459dc1a36a3e5419d42 Mon Sep 17 00:00:00 2001 From: Khushvendra Date: Thu, 11 Jun 2026 16:43:45 +0530 Subject: [PATCH 1/5] feat: implement CEP-8 explicit gating lifecycle Resolves #74 by adding full support for the explicit gating payment lifecycle in the ContextVM TypeScript SDK. Includes server middleware for tracking authorization states, client support for auto-retrying intercepted -32042/-32043 errors, and transport modifications to negotiate payment modes. --- bun.lock | 3 + package.json | 1 + src/core/constants.ts | 3 + src/payments/authorization-store.test.ts | 104 ++++++ src/payments/authorization-store.ts | 143 +++++++++ src/payments/canonical-identity.test.ts | 88 ++++++ src/payments/canonical-identity.ts | 43 +++ src/payments/client-payments.test.ts | 160 ++++++++++ src/payments/client-payments.ts | 298 ++++++++++++++++++ src/payments/constants.ts | 15 + src/payments/server-explicit-gating.test.ts | 172 ++++++++++ src/payments/server-explicit-gating.ts | 255 +++++++++++++++ src/payments/server-payments-utils.ts | 69 ++++ src/payments/server-payments.ts | 77 +---- src/payments/server-transport-payments.ts | 34 +- src/payments/types.ts | 42 +++ src/transport/capability-negotiator.ts | 11 + src/transport/middleware.ts | 14 +- src/transport/nostr-client-transport.ts | 19 ++ .../nostr-client/correlation-store.ts | 9 + .../nostr-client/inbound-coordinator.ts | 11 +- src/transport/nostr-client/outbound-sender.ts | 2 + .../nostr-client/server-metadata-store.ts | 10 + src/transport/nostr-server-transport.ts | 7 + .../nostr-server/inbound-coordinator.ts | 21 ++ .../nostr-server/outbound-response-router.ts | 11 + src/transport/nostr-server/session-store.ts | 6 + src/transport/payments-flow.test.ts | 87 +++++ 28 files changed, 1643 insertions(+), 72 deletions(-) create mode 100644 src/payments/authorization-store.test.ts create mode 100644 src/payments/authorization-store.ts create mode 100644 src/payments/canonical-identity.test.ts create mode 100644 src/payments/canonical-identity.ts create mode 100644 src/payments/server-explicit-gating.test.ts create mode 100644 src/payments/server-explicit-gating.ts create mode 100644 src/payments/server-payments-utils.ts diff --git a/bun.lock b/bun.lock index 179c9f2..75425e7 100644 --- a/bun.lock +++ b/bun.lock @@ -9,6 +9,7 @@ "@noble/hashes": "^2.2.0", "applesauce-relay": "^5.2.0", "canonicalize": "^2.1.0", + "json-canonicalize": "^2.0.0", "nostr-tools": "~2.18.2", "pino": "^10.3.1", "rxjs": "^7.8.2", @@ -495,6 +496,8 @@ "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + "json-canonicalize": ["json-canonicalize@2.0.0", "", {}, "sha512-yyrnK/mEm6Na3ChbJUWueXdapueW0p380RUyTW87XGb1ww8l8hU0pRrGC3vSWHe9CxrbPHX2fGUOZpNiHR0IIg=="], + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], diff --git a/package.json b/package.json index d6721a0..9692c7c 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,7 @@ "@noble/hashes": "^2.2.0", "applesauce-relay": "^5.2.0", "canonicalize": "^2.1.0", + "json-canonicalize": "^2.0.0", "nostr-tools": "~2.18.2", "pino": "^10.3.1", "rxjs": "^7.8.2", diff --git a/src/core/constants.ts b/src/core/constants.ts index 4a4ea17..f0633cc 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -121,6 +121,9 @@ export const NOSTR_TAGS = { * Support CEP-41 open-ended stream transfer via notifications/progress framing. */ SUPPORT_OPEN_STREAM: 'support_open_stream', + + /** CEP-8 payment interaction negotiation tag. */ + PAYMENT_INTERACTION: 'payment_interaction', } as const; export const DEFAULT_LRU_SIZE = 5000; diff --git a/src/payments/authorization-store.test.ts b/src/payments/authorization-store.test.ts new file mode 100644 index 0000000..782c56e --- /dev/null +++ b/src/payments/authorization-store.test.ts @@ -0,0 +1,104 @@ +import { describe, expect, test } from 'bun:test'; +import { AuthorizationStore } from './authorization-store.js'; +import type { CanonicalInvocationIdentity } from './types.js'; + +describe('AuthorizationStore', () => { + const identity: CanonicalInvocationIdentity = { + clientPubkey: 'client-1', + invocationHash: 'hash-1', + }; + + test('grant and claim a single authorization', () => { + const store = new AuthorizationStore(); + + expect(store.claim(identity)).toBe(false); + + store.grant(identity, 10000); + + expect(store.claim(identity)).toBe(true); + expect(store.claim(identity)).toBe(false); + }); + + test('grant multiple executions', () => { + const store = new AuthorizationStore(); + + store.grant(identity, 10000, 2); + + expect(store.claim(identity)).toBe(true); + expect(store.claim(identity)).toBe(true); + expect(store.claim(identity)).toBe(false); + }); + + test('claim fails after TTL expires', async () => { + const store = new AuthorizationStore(); + + store.grant(identity, 10); + + await new Promise((resolve) => setTimeout(resolve, 15)); + + expect(store.claim(identity)).toBe(false); + }); + + test('trySetPending prevents concurrent duplicates', () => { + const store = new AuthorizationStore(); + + // First call transitions to pending -> true + expect(store.trySetPending(identity, 10000)).toBe(true); + + // Second call is blocked -> false + expect(store.trySetPending(identity, 10000)).toBe(false); + + // hasPending should reflect the state + expect(store.hasPending(identity)).toBe(true); + }); + + test('trySetPending allows setting again after clearPending', () => { + const store = new AuthorizationStore(); + + expect(store.trySetPending(identity, 10000)).toBe(true); + expect(store.trySetPending(identity, 10000)).toBe(false); + + store.clearPending(identity); + + expect(store.trySetPending(identity, 10000)).toBe(true); + }); + + test('trySetPending allows setting again after pending state expires', async () => { + const store = new AuthorizationStore(); + + expect(store.trySetPending(identity, 10)).toBe(true); + expect(store.trySetPending(identity, 10)).toBe(false); + + await new Promise((resolve) => setTimeout(resolve, 15)); + + expect(store.trySetPending(identity, 10)).toBe(true); + }); + + test('grant clears pending state', () => { + const store = new AuthorizationStore(); + + store.trySetPending(identity, 10000); + expect(store.hasPending(identity)).toBe(true); + + store.grant(identity, 10000); + + expect(store.hasPending(identity)).toBe(false); + expect(store.claim(identity)).toBe(true); + }); + + test('LRU eviction works when maxEntries is exceeded', () => { + const store = new AuthorizationStore({ maxEntries: 2 }); + + const id1 = { clientPubkey: 'client', invocationHash: 'h1' }; + const id2 = { clientPubkey: 'client', invocationHash: 'h2' }; + const id3 = { clientPubkey: 'client', invocationHash: 'h3' }; + + store.grant(id1, 10000); + store.grant(id2, 10000); + store.grant(id3, 10000); // This should evict id1 + + expect(store.claim(id1)).toBe(false); + expect(store.claim(id2)).toBe(true); + expect(store.claim(id3)).toBe(true); + }); +}); diff --git a/src/payments/authorization-store.ts b/src/payments/authorization-store.ts new file mode 100644 index 0000000..e81e05c --- /dev/null +++ b/src/payments/authorization-store.ts @@ -0,0 +1,143 @@ +import type { CanonicalInvocationIdentity } from './types.js'; +import { LruCache } from '../core/utils/lru-cache.js'; +import { createLogger } from '../core/utils/logger.js'; + +export interface PaidAuthorization { + /** Composite key: `${clientPubkey}:${invocationHash}` */ + key: string; + expiresAtMs: number; + /** Number of remaining executions (usually 1). */ + remaining: number; +} + +/** + * A bounded, TTL-aware store for explicit gating authorizations. + * It manages both the pending state (waiting for payment verification) + * and the granted state (paid and ready to consume). + */ +export class AuthorizationStore { + private readonly authorizations: LruCache; + private readonly pending: LruCache; // Map of key -> expiresAtMs + private readonly logger = createLogger('authorization-store'); + + constructor(opts?: { maxEntries?: number }) { + const maxEntries = opts?.maxEntries ?? 5000; + this.authorizations = new LruCache(maxEntries); + this.pending = new LruCache(maxEntries); + } + + private getKey(identity: CanonicalInvocationIdentity): string { + return `${identity.clientPubkey}:${identity.invocationHash}`; + } + + /** + * Records a paid authorization. + */ + public grant( + identity: CanonicalInvocationIdentity, + ttlMs: number, + count: number = 1, + ): void { + const key = this.getKey(identity); + const expiresAtMs = Date.now() + ttlMs; + + this.authorizations.set(key, { + key, + expiresAtMs, + remaining: count, + }); + + // Once granted, it's no longer pending + this.pending.delete(key); + + this.logger.debug('authorization granted', { + key, + ttlMs, + count, + }); + } + + /** + * Atomically claims one execution authorization. + * Returns true if claimed, false if none available. + */ + public claim(identity: CanonicalInvocationIdentity): boolean { + const key = this.getKey(identity); + const auth = this.authorizations.get(key); + + if (!auth) { + return false; + } + + if (Date.now() > auth.expiresAtMs) { + this.authorizations.delete(key); + return false; + } + + if (auth.remaining > 0) { + auth.remaining -= 1; + if (auth.remaining === 0) { + this.authorizations.delete(key); + } else { + this.authorizations.set(key, auth); + } + this.logger.debug('authorization claimed', { key, remaining: auth.remaining }); + return true; + } + + return false; + } + + /** + * Atomically checks whether a payment is already pending for this identity + * and, if not, marks it as pending. Returns `true` if this call transitioned + * the identity to pending (caller should emit -32042). Returns `false` if + * already pending (caller should emit -32043). + * + * This atomic check-and-set prevents concurrent requests from both receiving + * -32042 and triggering duplicate payment flows. + */ + public trySetPending(identity: CanonicalInvocationIdentity, ttlMs: number): boolean { + const key = this.getKey(identity); + const now = Date.now(); + + const existingExpiry = this.pending.get(key); + if (existingExpiry !== undefined) { + if (now > existingExpiry) { + // Expired pending state, we can overwrite it + this.pending.delete(key); + } else { + // Already pending and active + return false; + } + } + + this.pending.set(key, now + ttlMs); + this.logger.debug('authorization marked pending', { key, ttlMs }); + return true; + } + + /** Checks if a payment is pending (not yet authorized). */ + public hasPending(identity: CanonicalInvocationIdentity): boolean { + const key = this.getKey(identity); + const expiry = this.pending.get(key); + + if (expiry === undefined) { + return false; + } + + if (Date.now() > expiry) { + this.pending.delete(key); + return false; + } + + return true; + } + + /** Clears pending state (e.g. on verification failure or expiry). */ + public clearPending(identity: CanonicalInvocationIdentity): void { + const key = this.getKey(identity); + this.pending.delete(key); + this.logger.debug('authorization pending state cleared', { key }); + } +} diff --git a/src/payments/canonical-identity.test.ts b/src/payments/canonical-identity.test.ts new file mode 100644 index 0000000..b2fb7b2 --- /dev/null +++ b/src/payments/canonical-identity.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, test } from 'bun:test'; +import { + computeCanonicalInvocationHash, + computeCanonicalInvocationIdentity, +} from './canonical-identity.js'; + +describe('Canonical Invocation Identity', () => { + describe('computeCanonicalInvocationHash', () => { + test('is deterministic regardless of object key order', () => { + const hash1 = computeCanonicalInvocationHash('tools/call', { + a: 1, + b: 2, + name: 'test', + }); + + const hash2 = computeCanonicalInvocationHash('tools/call', { + name: 'test', + b: 2, + a: 1, + }); + + expect(hash1).toBe(hash2); + // Ensure we're getting a hex string + expect(hash1).toMatch(/^[0-9a-f]{64}$/); + }); + + test('handles empty params', () => { + const hash1 = computeCanonicalInvocationHash('tools/call', undefined); + const hash2 = computeCanonicalInvocationHash('tools/call', null); + + expect(hash1).not.toBe(hash2); + expect(hash1).toMatch(/^[0-9a-f]{64}$/); + }); + + test('handles nested objects deterministically', () => { + const hash1 = computeCanonicalInvocationHash('tools/call', { + nested: { z: 1, y: 2, x: 3 }, + arr: [1, 2, 3], + }); + + const hash2 = computeCanonicalInvocationHash('tools/call', { + arr: [1, 2, 3], + nested: { x: 3, z: 1, y: 2 }, + }); + + expect(hash1).toBe(hash2); + }); + + test('handles unicode correctly', () => { + const hash1 = computeCanonicalInvocationHash('tools/call', { + text: 'Hello 🌍', + }); + + const hash2 = computeCanonicalInvocationHash('tools/call', { + text: 'Hello 🌍', + }); + + expect(hash1).toBe(hash2); + }); + + test('differs for different methods', () => { + const hash1 = computeCanonicalInvocationHash('tools/call', { a: 1 }); + const hash2 = computeCanonicalInvocationHash('prompts/get', { a: 1 }); + + expect(hash1).not.toBe(hash2); + }); + + test('differs for different param values', () => { + const hash1 = computeCanonicalInvocationHash('tools/call', { a: 1 }); + const hash2 = computeCanonicalInvocationHash('tools/call', { a: 2 }); + + expect(hash1).not.toBe(hash2); + }); + }); + + describe('computeCanonicalInvocationIdentity', () => { + test('combines pubkey and hash correctly', () => { + const pubkey = 'test-client-pubkey'; + const method = 'tools/call'; + const params = { name: 'test' }; + + const identity = computeCanonicalInvocationIdentity(pubkey, method, params); + + expect(identity.clientPubkey).toBe(pubkey); + expect(identity.invocationHash).toBe(computeCanonicalInvocationHash(method, params)); + }); + }); +}); diff --git a/src/payments/canonical-identity.ts b/src/payments/canonical-identity.ts new file mode 100644 index 0000000..5bf29cb --- /dev/null +++ b/src/payments/canonical-identity.ts @@ -0,0 +1,43 @@ +import { canonicalize } from 'json-canonicalize'; +import { createHash } from 'crypto'; +import type { CanonicalInvocationIdentity } from './types.js'; + +/** + * Computes a deterministic SHA-256 hash of an invocation's method and parameters. + * Uses RFC 8785 JSON Canonicalization Scheme (JCS) to ensure structurally + * identical JSON objects produce the same hash regardless of key ordering. + * + * @param method - The JSON-RPC method (e.g. 'tools/call') + * @param params - The JSON-RPC parameters + * @returns A hex-encoded SHA-256 hash string + */ +export function computeCanonicalInvocationHash( + method: string, + params: unknown, +): string { + const payload = { method, params }; + const canonicalString = canonicalize(payload); + + return createHash('sha256') + .update(canonicalString) + .digest('hex'); +} + +/** + * Computes the canonical invocation identity for explicit-gating authorization matching. + * + * @param clientPubkey - The client's public key + * @param method - The JSON-RPC method + * @param params - The JSON-RPC parameters + * @returns The computed identity + */ +export function computeCanonicalInvocationIdentity( + clientPubkey: string, + method: string, + params: unknown, +): CanonicalInvocationIdentity { + return { + clientPubkey, + invocationHash: computeCanonicalInvocationHash(method, params), + }; +} diff --git a/src/payments/client-payments.test.ts b/src/payments/client-payments.test.ts index d3cab64..cd56b29 100644 --- a/src/payments/client-payments.test.ts +++ b/src/payments/client-payments.test.ts @@ -593,4 +593,164 @@ describe('withClientPayments()', () => { await paid.close(); }); + + test('handles explicit gating -32042 error and retries request', async () => { + const transport = createMockNostrTransport(); + let sentMessage: JSONRPCMessage | undefined; + transport.send = async (msg) => { + sentMessage = msg; + }; + + transport + .getInternalStateForTesting() + .correlationStore.registerRequest('req-event-id-3', { + originalRequestId: 77, + isInitialize: false, + rawRequest: { jsonrpc: '2.0', id: 77, method: 'tools/call', params: { name: 'test' } }, + originalRequestContext: { method: 'tools/call' } + }); + + const observed: JSONRPCMessage[] = []; + const paid = withClientPayments(transport, { + handlers: [{ pmi: 'fake', async handle(): Promise {} }], + paymentInteraction: 'explicit_gating', + onPaymentRequired: async () => ({ paid: true }), + }); + paid.onmessage = (msg) => observed.push(msg); + await paid.start(); + + // Deliver -32042 Payment Required error + transport.onmessageWithContext!( + { + jsonrpc: '2.0', + id: 77, + error: { + code: -32042, + message: 'Payment Required', + data: { + payment_options: [{ amount: 10, pmi: 'fake', pay_req: 'pr1' }] + } + } + }, + { eventId: 'evt4', correlatedEventId: 'req-event-id-3' }, + ); + + // Wait for async processing + await new Promise((r) => setTimeout(r, 0)); + + // Error should not be delivered to caller + expect(observed).toHaveLength(0); + + // Original request should be retried + expect(sentMessage).toEqual({ jsonrpc: '2.0', id: 77, method: 'tools/call', params: { name: 'test' } }); + + await paid.close(); + }); + + test('propagates -32042 error if onPaymentRequired returns paid: false', async () => { + const transport = createMockNostrTransport(); + + transport + .getInternalStateForTesting() + .correlationStore.registerRequest('req-event-id-4', { + originalRequestId: 88, + isInitialize: false, + rawRequest: { jsonrpc: '2.0', id: 88, method: 'tools/call', params: { name: 'test' } }, + originalRequestContext: { method: 'tools/call' } + }); + + const observed: JSONRPCMessage[] = []; + const paid = withClientPayments(transport, { + handlers: [{ pmi: 'fake', async handle(): Promise {} }], + paymentInteraction: 'explicit_gating', + onPaymentRequired: async () => ({ paid: false, reason: 'user_cancelled' }), + }); + paid.onmessage = (msg) => observed.push(msg); + await paid.start(); + + // Deliver -32042 Payment Required error + transport.onmessageWithContext!( + { + jsonrpc: '2.0', + id: 88, + error: { + code: -32042, + message: 'Payment Required', + data: { + payment_options: [{ amount: 10, pmi: 'fake', pay_req: 'pr2' }] + } + } + }, + { eventId: 'evt5', correlatedEventId: 'req-event-id-4' }, + ); + + await new Promise((r) => setTimeout(r, 0)); + + // Error should be delivered to caller with reason + expect(observed).toHaveLength(1); + const errResp = observed[0] as JSONRPCMessage; + expect(errResp.id).toBe(88); + expect('error' in errResp && errResp.error?.code).toBe(-32042); + expect('error' in errResp && (errResp.error?.data as any)?.reason).toBe('user_cancelled'); + + await paid.close(); + }); + + test('handles explicit gating -32043 Payment Pending error and retries after backoff', async () => { + const transport = createMockNostrTransport(); + let sentMessage: JSONRPCMessage | undefined; + transport.send = async (msg) => { + sentMessage = msg; + }; + + transport + .getInternalStateForTesting() + .correlationStore.registerRequest('req-event-id-5', { + originalRequestId: 99, + isInitialize: false, + rawRequest: { jsonrpc: '2.0', id: 99, method: 'tools/call', params: { name: 'test_pending' } }, + originalRequestContext: { method: 'tools/call' } + }); + + const observed: JSONRPCMessage[] = []; + const paid = withClientPayments(transport, { + handlers: [{ pmi: 'fake', async handle(): Promise {} }], + paymentInteraction: 'explicit_gating', + }); + paid.onmessage = (msg) => observed.push(msg); + await paid.start(); + + // Deliver -32043 Payment Pending error + transport.onmessageWithContext!( + { + jsonrpc: '2.0', + id: 99, + error: { + code: -32043, + message: 'Payment Pending', + data: { + instructions: 'Wait and retry.', + retry_after: 0.05 // 50ms for test + } + } + }, + { eventId: 'evt6', correlatedEventId: 'req-event-id-5' }, + ); + + // Initial check: Should intercept error and wait + await new Promise((r) => setTimeout(r, 10)); + expect(observed).toHaveLength(0); + expect(sentMessage).toBeUndefined(); + + // Wait for retry_after timer to fire + await new Promise((r) => setTimeout(r, 60)); + + // Error should not be delivered to caller + expect(observed).toHaveLength(0); + + // Original request should be retried + expect(sentMessage).toEqual({ jsonrpc: '2.0', id: 99, method: 'tools/call', params: { name: 'test_pending' } }); + + await paid.close(); + }); }); diff --git a/src/payments/client-payments.ts b/src/payments/client-payments.ts index 4d53105..df2507c 100644 --- a/src/payments/client-payments.ts +++ b/src/payments/client-payments.ts @@ -21,6 +21,8 @@ import { PAYMENT_ACCEPTED_METHOD, PAYMENT_REJECTED_METHOD, PAYMENT_REQUIRED_METHOD, + PAYMENT_REQUIRED_ERROR_CODE, + PAYMENT_PENDING_ERROR_CODE, } from './constants.js'; export interface ClientPaymentsOptions { @@ -56,6 +58,32 @@ export interface ClientPaymentsOptions { req: PaymentHandlerRequest, originalRequestContext?: OriginalRequestContext, ) => boolean | Promise; + + /** Requested payment interaction mode. @default 'transparent' */ + paymentInteraction?: import('./types.js').PaymentInteractionMode; + + /** + * Handler for explicit-gating -32042 errors. + * Called when a priced invocation returns Payment Required. + * The handler should pay one option and signal completion. + * + * **Error handling contract**: + * - If the promise resolves with `{ paid: true }`, the wrapper auto-retries the + * original request with the same `method` and `params`. + * - If the promise resolves with `{ paid: false, reason }`, the wrapper synthesizes + * a JSON-RPC error to the caller with code `-32042` and `data: { reason }`. + * Use `reason: 'user_cancelled'` for user-initiated cancellations. + * - If the promise **rejects**, the wrapper MUST NOT silently fall back. + * It synthesizes a JSON-RPC error with code `-32042` and + * `data: { reason: error.message, type: 'payment_handler_error' }`. + * - Transient payment-provider failures should reject with an Error whose + * `message` contains the provider error details. + */ + onPaymentRequired?: (params: { + options: import('./types.js').PaymentOption[]; + instructions?: string; + originalRequest: import('@modelcontextprotocol/sdk/types.js').JSONRPCRequest; + }) => Promise<{ paid: boolean; reason?: string }>; } type ProgressToken = string; @@ -82,6 +110,31 @@ function supportsOnmessageWithContext( ); } +function isExplicitPaymentRequiredError( + msg: JSONRPCMessage, +): msg is import('@modelcontextprotocol/sdk/types.js').JSONRPCErrorResponse { + return ( + isJSONRPCErrorResponse(msg) && + msg.error.code === PAYMENT_REQUIRED_ERROR_CODE && + typeof msg.error.data === 'object' && + msg.error.data !== null && + Array.isArray((msg.error.data as any).payment_options) && + (msg.error.data as any).payment_options.length > 0 + ); +} + +function isExplicitPaymentPendingError( + msg: JSONRPCMessage, +): msg is import('@modelcontextprotocol/sdk/types.js').JSONRPCErrorResponse { + return ( + isJSONRPCErrorResponse(msg) && + msg.error.code === PAYMENT_PENDING_ERROR_CODE && + typeof msg.error.data === 'object' && + msg.error.data !== null && + typeof (msg.error.data as any).retry_after === 'number' + ); +} + function isPaymentRequiredNotification( msg: JSONRPCMessage, ): msg is PaymentRequiredNotification { @@ -177,6 +230,12 @@ export function withClientPayments( logger.debug('advertised client PMIs', { pmis: options.handlers.map((h) => h.pmi), }); + if (options.paymentInteraction === 'explicit_gating') { + transport.setPaymentInteraction('explicit_gating'); + logger.debug('advertised requested payment interaction mode', { + mode: 'explicit_gating', + }); + } } const handlersByPmi = new Map( @@ -205,6 +264,233 @@ export function withClientPayments( message: JSONRPCMessage, requestEventId: string, ): Promise { + if (isExplicitPaymentRequiredError(message)) { + // Explicit gating lifecycle (-32042 Payment Required) + const data = message.error.data as import('./types.js').PaymentRequiredErrorData; + + for (const option of data.payment_options) { + const handler = handlersByPmi.get(option.pmi); + if (!handler) continue; + + const isNostrTransport = transport instanceof NostrClientTransport; + const pending = isNostrTransport + ? transport.getPendingRequestForEventId(requestEventId) + : undefined; + + if (isNostrTransport && !pending) { + logger.warn('dropping uncorrelated explicit payment error', { + requestEventId, + pmi: option.pmi, + }); + onmessage?.(message); + return; + } + + const originalContext = pending + ? { + method: pending.method, + capability: pending.capability, + id: pending.id, + } + : undefined; + + const request: PaymentHandlerRequest = { + amount: option.amount, + pay_req: option.pay_req, + pmi: option.pmi, + description: option.description, + ttl: option.ttl, + _meta: option._meta, + requestEventId, + }; + + const allow = options.paymentPolicy + ? await options.paymentPolicy(request, originalContext) + : true; + + if (!allow) { + logger.debug('payment_required rejected by policy', { + requestEventId, + pmi: option.pmi, + }); + continue; // Try next option if rejected by policy + } + + const canHandle = handler.canHandle + ? await handler.canHandle(request) + : true; + + if (!canHandle) { + logger.debug('payment_required cannot be handled by handler', { + requestEventId, + pmi: option.pmi, + }); + continue; // Try next option if handler can't handle + } + + logger.info('executing payment handler for explicit gating', { + requestEventId, + pmi: option.pmi, + amount: option.amount, + }); + + try { + await handler.handle(request); + logger.info('payment handler succeeded, retrying request', { + requestEventId, + pmi: option.pmi, + }); + + // In explicit gating, the client MUST retry the exact same request + // to trigger authorization consumption and get the result. + // Since we intercepted the error, we need the original request. + // For NostrClientTransport, we don't have the original raw request cached perfectly, + // but we can reconstruct it or we should just let the error propagate + // and let the caller handle retry. + + if (!options.onPaymentRequired) { + // We have a payment required error but the transport level onPaymentRequired handler + // wasn't configured. The client didn't supply an explicit gating handler. + // We'll let the error propagate. + onmessage?.(message); + return; + } + + if (!pending?.originalRequestContext?.method) { + logger.warn('missing original request method, cannot retry explicit payment', { requestEventId }); + onmessage?.(message); + return; + } + + const rawRequest = transport.correlationStore.getRawRequest(requestEventId); + if (!rawRequest) { + logger.warn('missing raw original request, cannot retry explicit payment', { requestEventId }); + onmessage?.(message); + return; + } + + const result = await options.onPaymentRequired({ + options: data.payment_options, + instructions: data.instructions, + originalRequest: rawRequest, + }); + + if (result.paid) { + logger.info('explicit payment satisfied, retrying original request', { + requestEventId, + method: rawRequest.method, + }); + + // Re-send the exact request, updating the ID if necessary (or letting MCP SDK handle it) + // But actually we are the transport, we can just resend the raw request through the transport. + // Wait, we need to create a new ID so the proxy can track it properly. + // Oh right, we can't easily resend and magically stitch it back to the original Promise in the MCP Client. + // Actually, if we just send() it, the original promise in the MCP Client is already waiting + // for the response with the *original* ID. + // Wait, no, the server sent us an error response with the *original* ID. + // The MCP Client will resolve that promise with an Error. + // So we MUST NOT deliver the error response to `onmessage` if we want to intercept and retry. + // We intercepted the error! We haven't called `onmessage` yet. + // So if we just resend the raw request to the server, with a new requestEventId, + // we will need to map the NEW response back to the OLD request ID. + + // This requires transport level support. + // The plan says: "When onPaymentRequired returns { paid: true }, the wrapper re-sends the original JSONRPCRequest with the same method and params (new id is fine per spec). This is transparent to the upstream MCP Client." + // Wait, if it has a new id, how does the upstream MCP Client know it's the response? + // Actually, we must use the original ID when communicating with the upstream client. + // But when we send it to the server, we just pass the original request exactly as it was. + // We don't change the ID. The `NostrClientTransport` wraps the `id` inside a new `requestId`. + + await transport.send(rawRequest); + return; // WE SUCCESSFULLY RETRIED! Do not deliver the error to `onmessage`. + } else { + // User cancelled or returned paid=false + logger.debug('onPaymentRequired returned paid=false', { requestEventId, reason: result.reason }); + const errorMsg: import('@modelcontextprotocol/sdk/types.js').JSONRPCMessage = { + jsonrpc: '2.0', + id: message.id, + error: { + code: PAYMENT_REQUIRED_ERROR_CODE, + message: 'Payment Required', + data: { reason: result.reason || 'user_cancelled' } + } + }; + onmessage?.(errorMsg); + return; + } + } catch (err) { + logger.error('payment handler failed', { + requestEventId, + pmi: option.pmi, + error: err instanceof Error ? err.message : String(err), + }); + // Spec: onPaymentRequired rejection MUST cause the original JSON-RPC request to fail. + const errorMsg: import('@modelcontextprotocol/sdk/types.js').JSONRPCMessage = { + jsonrpc: '2.0', + id: message.id, + error: { + code: PAYMENT_REQUIRED_ERROR_CODE, + message: 'Payment Required', + data: { reason: err instanceof Error ? err.message : String(err), type: 'payment_handler_error' } + } + }; + onmessage?.(errorMsg); + return; + } + + // We handled (or attempted) the payment. Stop evaluating other options. + // If we failed, we break and the -32042 will be emitted to `onmessage`. + // Actually we already returned if we handled it. + } + + // If we got here, we either: + // 1. Paid successfully but we need to signal the caller to retry (if we don't retry ourselves) + // 2. Failed to pay (policy, unhandled, or error) + // In both cases, for now we will just emit the -32042 error to `onmessage` and let + // the caller retry. To implement transparent retry at the transport level, we'd need + // to cache every outbound request, which is expensive. + onmessage?.(message); + return; + } + + if (isExplicitPaymentPendingError(message)) { + const data = message.error.data as import('./types.js').PaymentPendingErrorData; + const retryAfterSeconds = data.retry_after; + + const isNostrTransport = transport instanceof NostrClientTransport; + const pending = isNostrTransport + ? transport.getPendingRequestForEventId(requestEventId) + : undefined; + + if (!isNostrTransport || !pending) { + logger.warn('dropping uncorrelated explicit payment pending error', { + requestEventId, + }); + onmessage?.(message); + return; + } + + const rawRequest = transport.correlationStore.getRawRequest(requestEventId); + if (!rawRequest) { + logger.warn('missing raw original request, cannot retry explicit payment pending', { requestEventId }); + onmessage?.(message); + return; + } + + logger.info('payment pending, retrying after backoff', { + requestEventId, + retryAfterSeconds, + }); + + setTimeout(() => { + transport.send(rawRequest).catch(err => { + logger.error('failed to retry pending request', { requestEventId, error: err instanceof Error ? err.message : String(err) }); + }); + }, retryAfterSeconds * 1000); + + return; // Intercept the error so the client waits + } + if (!isPaymentRequiredNotification(message)) { return; } @@ -440,6 +726,12 @@ export function withClientPayments( }, ); + // If it's an explicit gating error, we intercept it here because + // maybeHandlePaymentRequired takes responsibility for re-emitting it if unhandled. + if (isExplicitPaymentRequiredError(message) || isExplicitPaymentPendingError(message)) { + return; + } + onmessage?.(message); }; @@ -491,6 +783,12 @@ export function withClientPayments( }, ); + // If it's an explicit gating error, we intercept it here because + // maybeHandlePaymentRequired takes responsibility for re-emitting it if unhandled. + if (isExplicitPaymentRequiredError(message) || isExplicitPaymentPendingError(message)) { + return; + } + // Forward exactly once (see duplicate-delivery guard in `transport.onmessage`). onmessage?.(message); }; diff --git a/src/payments/constants.ts b/src/payments/constants.ts index bd54f87..63b7add 100644 --- a/src/payments/constants.ts +++ b/src/payments/constants.ts @@ -22,3 +22,18 @@ export const PAYMENT_ACCEPTED_METHOD = 'notifications/payment_accepted'; /** CEP-8 notification method: server rejected payment (or refused to proceed). */ export const PAYMENT_REJECTED_METHOD = 'notifications/payment_rejected'; + +/** CEP-8 explicit-gating JSON-RPC error: payment required. */ +export const PAYMENT_REQUIRED_ERROR_CODE = -32042; + +/** CEP-8 explicit-gating JSON-RPC error: payment pending. */ +export const PAYMENT_PENDING_ERROR_CODE = -32043; + +/** + * CEP-8 unsupported payment_interaction negotiation error. + * + * Uses -32602 (Invalid params) as mandated by CEP-8 spec: the `payment_interaction` + * tag value is treated as an invalid parameter when the server does not support it. + * This is an intentional reuse of the standard JSON-RPC code, not a CEP-specific code. + */ +export const UNSUPPORTED_PAYMENT_INTERACTION_ERROR_CODE = -32602; diff --git a/src/payments/server-explicit-gating.test.ts b/src/payments/server-explicit-gating.test.ts new file mode 100644 index 0000000..ecac39d --- /dev/null +++ b/src/payments/server-explicit-gating.test.ts @@ -0,0 +1,172 @@ +import { describe, expect, test } from 'bun:test'; +import type { JSONRPCErrorResponse, JSONRPCRequest } from '@modelcontextprotocol/sdk/types.js'; +import { createExplicitGatingMiddleware } from './server-explicit-gating.js'; +import { AuthorizationStore } from './authorization-store.js'; +import { PAYMENT_PENDING_ERROR_CODE, PAYMENT_REQUIRED_ERROR_CODE } from './constants.js'; + +describe('Explicit Gating Middleware', () => { + const processor = { + pmi: 'fake', + async createPaymentRequired(params: { + amount: number; + description?: string; + requestEventId: string; + clientPubkey: string; + }) { + return { + amount: params.amount, + pay_req: 'pay_req', + description: params.description, + pmi: 'fake', + ttl: 300, + _meta: { test: true }, + }; + }, + async verifyPayment() { + return { _meta: { ok: true } }; + }, + }; + + const pricedCapabilities = [ + { + method: 'tools/call', + name: 'add', + amount: 10, + currencyUnit: 'test', + description: 'listed', + }, + ] as const; + + const ctx: { clientPubkey: string; clientPmis?: readonly string[] } = { + clientPubkey: 'test-client', + }; + + const message: JSONRPCRequest = { + jsonrpc: '2.0', + id: 'event-id', + method: 'tools/call', + params: { name: 'add', arguments: { a: 1, b: 2 } }, + }; + + test('emits -32042 Payment Required on first request', async () => { + const store = new AuthorizationStore(); + const sentResponses: JSONRPCErrorResponse[] = []; + + const mw = createExplicitGatingMiddleware({ + options: { + processors: [processor], + pricedCapabilities: [...pricedCapabilities], + }, + authorizationStore: store, + sendResponse: async (pubkey, response) => { + sentResponses.push(response); + }, + }); + + let forwarded = false; + await mw(message, ctx, async () => { + forwarded = true; + }); + + expect(forwarded).toBe(false); + expect(sentResponses.length).toBe(1); + + const response = sentResponses[0]; + expect(response.error.code).toBe(PAYMENT_REQUIRED_ERROR_CODE); + + const data = response.error.data as any; + expect(data.payment_options.length).toBe(1); + expect(data.payment_options[0].amount).toBe(10); + expect(data.payment_options[0].pay_req).toBe('pay_req'); + }); + + test('emits -32043 Payment Pending if already pending', async () => { + const store = new AuthorizationStore(); + const sentResponses: JSONRPCErrorResponse[] = []; + + const mw = createExplicitGatingMiddleware({ + options: { + processors: [processor], + pricedCapabilities: [...pricedCapabilities], + }, + authorizationStore: store, + sendResponse: async (pubkey, response) => { + sentResponses.push(response); + }, + }); + + await mw(message, ctx, async () => {}); + await mw(message, ctx, async () => {}); // Second call should be pending + + expect(sentResponses.length).toBe(2); + expect(sentResponses[0].error.code).toBe(PAYMENT_REQUIRED_ERROR_CODE); + expect(sentResponses[1].error.code).toBe(PAYMENT_PENDING_ERROR_CODE); + }); + + test('forwards request if authorization is granted', async () => { + const store = new AuthorizationStore(); + const sentResponses: JSONRPCErrorResponse[] = []; + + const mw = createExplicitGatingMiddleware({ + options: { + processors: [processor], + pricedCapabilities: [...pricedCapabilities], + }, + authorizationStore: store, + sendResponse: async (pubkey, response) => { + sentResponses.push(response); + }, + }); + + // We fake the authorization grant + // The canonical identity depends on the method and params + // JCS of { method: "tools/call", params: { name: "add", arguments: { a: 1, b: 2 } } } + // We can just use the utility to compute it + const { computeCanonicalInvocationIdentity } = await import('./canonical-identity.js'); + const identity = computeCanonicalInvocationIdentity(ctx.clientPubkey, message.method, message.params); + store.grant(identity, 10000); + + let forwarded = false; + await mw(message, ctx, async () => { + forwarded = true; + }); + + expect(sentResponses.length).toBe(0); + expect(forwarded).toBe(true); + + // Auth should be consumed, second call should trigger payment required + let forwarded2 = false; + await mw(message, ctx, async () => { + forwarded2 = true; + }); + + expect(forwarded2).toBe(false); + expect(sentResponses.length).toBe(1); + expect(sentResponses[0].error.code).toBe(PAYMENT_REQUIRED_ERROR_CODE); + }); + + test('forwards request directly if resolvePrice waives payment', async () => { + const store = new AuthorizationStore(); + const sentResponses: JSONRPCErrorResponse[] = []; + + const mw = createExplicitGatingMiddleware({ + options: { + processors: [processor], + pricedCapabilities: [...pricedCapabilities], + resolvePrice: async () => ({ waive: true }), + }, + authorizationStore: store, + sendResponse: async (pubkey, response) => { + sentResponses.push(response); + }, + }); + + let forwarded = false; + await mw(message, ctx, async () => { + forwarded = true; + }); + + expect(sentResponses.length).toBe(0); + expect(forwarded).toBe(true); + }); +}); diff --git a/src/payments/server-explicit-gating.ts b/src/payments/server-explicit-gating.ts new file mode 100644 index 0000000..6186034 --- /dev/null +++ b/src/payments/server-explicit-gating.ts @@ -0,0 +1,255 @@ +import type { JSONRPCErrorResponse } from '@modelcontextprotocol/sdk/types.js'; +import type { ServerMiddlewareFn } from './types.js'; +import { isJsonRpcRequest } from './types.js'; +import type { ServerPaymentsOptions } from './server-payments.js'; +import type { AuthorizationStore } from './authorization-store.js'; +import { computeCanonicalInvocationIdentity } from './canonical-identity.js'; +import { + getVerificationTimeoutMs, + matchPricedCapability, + isResolvePriceRejection, + isResolvePriceWaiver, +} from './server-payments-utils.js'; +import { createLogger } from '../core/utils/logger.js'; +import { withTimeout } from '../core/utils/utils.js'; +import { + PAYMENT_PENDING_ERROR_CODE, + PAYMENT_REQUIRED_ERROR_CODE, +} from './constants.js'; + +export interface ExplicitGatingMiddlewareParams { + options: ServerPaymentsOptions; + authorizationStore: AuthorizationStore; + sendResponse: ( + clientPubkey: string, + response: JSONRPCErrorResponse, + requestEventId: string, + ) => Promise; +} + +export function createExplicitGatingMiddleware( + params: ExplicitGatingMiddlewareParams, +): ServerMiddlewareFn { + const { options, authorizationStore, sendResponse } = params; + const logger = createLogger('server-explicit-gating'); + + const processorsByPmi = new Map( + options.processors.map((p) => [p.pmi, p] as const), + ); + + return async (message, ctx, forward) => { + // Only gate requests. + if (!isJsonRpcRequest(message)) { + await forward(message); + return; + } + + const priced = matchPricedCapability(message, options.pricedCapabilities); + if (!priced) { + await forward(message); + return; + } + + const requestEventId = String(message.id); + const identity = computeCanonicalInvocationIdentity( + ctx.clientPubkey, + message.method, + message.params, + ); + + // 1. Try to claim an existing authorization + if (authorizationStore.claim(identity)) { + logger.debug('authorization claimed, forwarding request', { + requestEventId, + method: message.method, + }); + await forward(message); + return; + } + + const paymentTtlMs = options.paymentTtlMs ?? 300_000; + + // 2. Try to set pending state atomically + // We use a safe default TTL here, but will override it below if the payment option has a specific TTL + if (!authorizationStore.trySetPending(identity, paymentTtlMs)) { + logger.debug('payment already pending, returning -32043', { + requestEventId, + }); + const errorResponse: JSONRPCErrorResponse = { + jsonrpc: '2.0', + id: message.id, + error: { + code: PAYMENT_PENDING_ERROR_CODE, + message: 'Payment Pending', + data: { + instructions: 'A payment is already pending for this invocation. Wait and retry.', + retry_after: 5, + }, + }, + }; + await sendResponse(ctx.clientPubkey, errorResponse, requestEventId); + return; + } + + // 3. Resolve price and initiate new payment + try { + const clientPmis = ctx.clientPmis; + const chosenPmi = clientPmis + ? clientPmis.find((pmi) => processorsByPmi.has(pmi)) + : undefined; + + const chosenProcessor = chosenPmi + ? processorsByPmi.get(chosenPmi) + : options.processors[0]; + + if (!chosenProcessor) { + throw new Error('No payment processors configured'); + } + + const processor = chosenProcessor; + + const quote = options.resolvePrice + ? await options.resolvePrice({ + capability: priced, + request: message, + clientPubkey: ctx.clientPubkey, + requestEventId, + }) + : { amount: priced.amount, description: priced.description }; + + if (isResolvePriceRejection(quote)) { + logger.info('payment rejected', { + requestEventId, + pmi: processor.pmi, + amount: priced.amount, + reason: quote.message, + }); + + authorizationStore.clearPending(identity); + + // Spec: When a capability is rejected by policy, return a standard error. + // We'll use -32000 (Internal error or application-defined error) since CEP-8 doesn't specify a special rejection code. + const errorResponse: JSONRPCErrorResponse = { + jsonrpc: '2.0', + id: message.id, + error: { + code: -32000, + message: quote.message || 'Payment rejected by policy', + }, + }; + await sendResponse(ctx.clientPubkey, errorResponse, requestEventId); + return; + } + + if (isResolvePriceWaiver(quote)) { + logger.debug('payment waived, forwarding priced request', { + requestEventId, + method: message.method, + }); + + authorizationStore.clearPending(identity); + await forward(message); + return; + } + + const resolvedQuote = quote; + const paymentRequired = await processor.createPaymentRequired({ + amount: resolvedQuote.amount, + description: resolvedQuote.description, + requestEventId, + clientPubkey: ctx.clientPubkey, + }); + + const mergedMeta = + resolvedQuote.meta === undefined && + paymentRequired._meta === undefined + ? undefined + : { + ...(paymentRequired._meta ?? {}), + ...(resolvedQuote.meta ?? {}), + }; + + // Ensure pending TTL matches the payment request TTL + const verifyTimeoutMs = getVerificationTimeoutMs({ + ttlSeconds: paymentRequired.ttl, + }); + const effectiveTimeoutMs = Math.min(verifyTimeoutMs, paymentTtlMs); + + // Update pending with the precise TTL + authorizationStore.trySetPending(identity, effectiveTimeoutMs); + + const errorResponse: JSONRPCErrorResponse = { + jsonrpc: '2.0', + id: message.id, + error: { + code: PAYMENT_REQUIRED_ERROR_CODE, + message: 'Payment Required', + data: { + payment_options: [ + { + amount: paymentRequired.amount, + pmi: paymentRequired.pmi, + pay_req: paymentRequired.pay_req, + description: paymentRequired.description, + ttl: paymentRequired.ttl, + _meta: mergedMeta, + }, + ], + }, + }, + }; + + logger.info('payment required error sent', { + requestEventId, + pmi: paymentRequired.pmi, + amount: paymentRequired.amount, + ttl: paymentRequired.ttl, + }); + + await sendResponse(ctx.clientPubkey, errorResponse, requestEventId); + + // Start async verification + // Do not await this, we must let the middleware chain return the error response. + (async () => { + const controller = new AbortController(); + try { + logger.debug('verifying explicit payment', { + requestEventId, + pmi: paymentRequired.pmi, + timeoutMs: effectiveTimeoutMs, + }); + + await withTimeout( + processor.verifyPayment({ + pay_req: paymentRequired.pay_req, + requestEventId, + clientPubkey: ctx.clientPubkey, + abortSignal: controller.signal, + }), + effectiveTimeoutMs, + 'verifyPayment timed out', + ); + + logger.info('explicit payment accepted, granting authorization', { + requestEventId, + pmi: paymentRequired.pmi, + amount: paymentRequired.amount, + }); + + authorizationStore.grant(identity, effectiveTimeoutMs); + } catch (err) { + logger.info('explicit payment verification failed or timed out', { + requestEventId, + error: err instanceof Error ? err.message : String(err), + }); + authorizationStore.clearPending(identity); + } finally { + controller.abort(); + } + })(); + } catch (err) { + authorizationStore.clearPending(identity); + throw err; + } + }; +} diff --git a/src/payments/server-payments-utils.ts b/src/payments/server-payments-utils.ts new file mode 100644 index 0000000..2928ea4 --- /dev/null +++ b/src/payments/server-payments-utils.ts @@ -0,0 +1,69 @@ +import type { JSONRPCRequest } from '@modelcontextprotocol/sdk/types.js'; +import type { + PricedCapability, + ResolvePriceRejection, + ResolvePriceWaiver, + ResolvePriceResult, +} from './types.js'; + +export function getVerificationTimeoutMs(params: { + ttlSeconds: number | undefined; +}): number { + // CEP-8 TTL is in seconds. If TTL is absent, default is 5 minutes. + const ttlSeconds = params.ttlSeconds; + if (ttlSeconds === undefined) { + return 5 * 60 * 1000; + } + if (!Number.isFinite(ttlSeconds) || ttlSeconds <= 0) { + return 5 * 60 * 1000; + } + return Math.floor(ttlSeconds * 1000); +} + +export function matchPricedCapability( + message: JSONRPCRequest, + priced: readonly PricedCapability[], +): PricedCapability | undefined { + const capabilityName = getCapabilityNameForPricing(message); + + return priced.find((p) => { + if (p.method !== message.method) return false; + if (p.name === undefined) return true; + return p.name === capabilityName; + }); +} + +export function getCapabilityNameForPricing( + message: JSONRPCRequest, +): string | undefined { + const params = message.params as Record | undefined; + + switch (message.method) { + case 'tools/call': { + const name = params?.name; + return typeof name === 'string' ? name : undefined; + } + case 'prompts/get': { + const name = params?.name; + return typeof name === 'string' ? name : undefined; + } + case 'resources/read': { + const uri = params?.uri; + return typeof uri === 'string' ? uri : undefined; + } + default: + return undefined; + } +} + +export function isResolvePriceRejection( + quote: ResolvePriceResult, +): quote is ResolvePriceRejection { + return 'reject' in quote && quote.reject; +} + +export function isResolvePriceWaiver( + quote: ResolvePriceResult, +): quote is ResolvePriceWaiver { + return 'waive' in quote && quote.waive; +} diff --git a/src/payments/server-payments.ts b/src/payments/server-payments.ts index 878ec74..83f8e17 100644 --- a/src/payments/server-payments.ts +++ b/src/payments/server-payments.ts @@ -1,17 +1,14 @@ -import { type JSONRPCRequest } from '@modelcontextprotocol/sdk/types.js'; -import { +import { isJsonRpcRequest } from './types.js'; +import type { CorrelatedNotificationSender, PaymentAcceptedNotification, PaymentProcessor, PaymentRejectedNotification, PaymentRequiredNotification, PricedCapability, - ResolvePriceRejection, - ResolvePriceWaiver, - ResolvePriceResult, ResolvePriceFn, ServerMiddlewareFn, - isJsonRpcRequest, + PaymentInteractionMode, } from './types.js'; import { LruCache } from '../core/utils/lru-cache.js'; import { withTimeout } from '../core/utils/utils.js'; @@ -22,6 +19,13 @@ import { PAYMENT_REJECTED_METHOD, PAYMENT_REQUIRED_METHOD, } from './constants.js'; +import { + getVerificationTimeoutMs, + matchPricedCapability, + isResolvePriceRejection, + isResolvePriceWaiver, +} from './server-payments-utils.js'; + export interface ServerPaymentsOptions { processors: readonly PaymentProcessor[]; @@ -47,6 +51,9 @@ export interface ServerPaymentsOptions { * @default 1000 */ maxPendingPayments?: number; + + /** Effective payment interaction mode for this server instance. @default 'transparent' */ + paymentInteraction?: PaymentInteractionMode; } function purgeExpiredPending(params: { @@ -71,55 +78,7 @@ type PendingPaymentState = { inFlight: Promise; }; -function getVerificationTimeoutMs(params: { - ttlSeconds: number | undefined; -}): number { - // CEP-8 TTL is in seconds. If TTL is absent, default is 5 minutes. - const ttlSeconds = params.ttlSeconds; - if (ttlSeconds === undefined) { - return 5 * 60 * 1000; - } - if (!Number.isFinite(ttlSeconds) || ttlSeconds <= 0) { - return 5 * 60 * 1000; - } - return Math.floor(ttlSeconds * 1000); -} - -function matchPricedCapability( - message: JSONRPCRequest, - priced: readonly PricedCapability[], -): PricedCapability | undefined { - const capabilityName = getCapabilityNameForPricing(message); - - return priced.find((p) => { - if (p.method !== message.method) return false; - if (p.name === undefined) return true; - return p.name === capabilityName; - }); -} -function getCapabilityNameForPricing( - message: JSONRPCRequest, -): string | undefined { - const params = message.params as Record | undefined; - - switch (message.method) { - case 'tools/call': { - const name = params?.name; - return typeof name === 'string' ? name : undefined; - } - case 'prompts/get': { - const name = params?.name; - return typeof name === 'string' ? name : undefined; - } - case 'resources/read': { - const uri = params?.uri; - return typeof uri === 'string' ? uri : undefined; - } - default: - return undefined; - } -} function createPaymentRequiredNotification(params: { amount: number; @@ -160,17 +119,7 @@ function createPaymentRejectedNotification(params: { }; } -function isResolvePriceRejection( - quote: ResolvePriceResult, -): quote is ResolvePriceRejection { - return 'reject' in quote && quote.reject; -} -function isResolvePriceWaiver( - quote: ResolvePriceResult, -): quote is ResolvePriceWaiver { - return 'waive' in quote && quote.waive; -} /** * Creates a server-side middleware that gates priced requests until payment is verified. diff --git a/src/payments/server-transport-payments.ts b/src/payments/server-transport-payments.ts index 66ae160..6aef7df 100644 --- a/src/payments/server-transport-payments.ts +++ b/src/payments/server-transport-payments.ts @@ -3,6 +3,8 @@ import type { ServerPaymentsOptions } from './server-payments.js'; import { createCapTagsFromPricedCapabilities } from './cap-tags.js'; import { createPmiTagsFromProcessors } from './pmi-tags.js'; import { createServerPaymentsMiddleware } from './server-payments.js'; +import { createExplicitGatingMiddleware } from './server-explicit-gating.js'; +import { AuthorizationStore } from './authorization-store.js'; /** * Attaches CEP-8 payments gating to a NostrServerTransport. @@ -12,15 +14,35 @@ export function withServerPayments( options: ServerPaymentsOptions, ): NostrServerTransport { // CEP-8 discovery tags: advertise supported PMIs + reference pricing on announcement/list events. - transport.setAnnouncementExtraTags( - createPmiTagsFromProcessors(options.processors), - ); + const extraTags = createPmiTagsFromProcessors(options.processors); + + if (options.paymentInteraction === 'explicit_gating') { + extraTags.push(['payment_interaction', 'explicit_gating']); + } + + transport.setAnnouncementExtraTags(extraTags); transport.setAnnouncementPricingTags( createCapTagsFromPricedCapabilities(options.pricedCapabilities), ); - transport.addInboundMiddleware( - createServerPaymentsMiddleware({ sender: transport, options }), - ); + // Expose the configured payment interaction mode to the transport coordinator. + transport.setSupportedPaymentInteraction(options.paymentInteraction); + + if (options.paymentInteraction === 'explicit_gating') { + const authorizationStore = new AuthorizationStore({}); + transport.addInboundMiddleware( + createExplicitGatingMiddleware({ + options, + authorizationStore, + sendResponse: async (clientPubkey, response, requestEventId) => { + await transport.send(response); + }, + }), + ); + } else { + transport.addInboundMiddleware( + createServerPaymentsMiddleware({ sender: transport, options }), + ); + } return transport; } diff --git a/src/payments/types.ts b/src/payments/types.ts index be25a12..2728ba0 100644 --- a/src/payments/types.ts +++ b/src/payments/types.ts @@ -62,6 +62,48 @@ export type PaymentRequiredNotification = JSONRPCNotification & { }; }; +/** CEP-8 payment interaction modes. */ +export type PaymentInteractionMode = 'transparent' | 'explicit_gating'; + +/** A single payment option inside a -32042 error.data.payment_options entry. */ +export interface PaymentOption { + amount: number; + pmi: string; + pay_req: string; + description?: string; + ttl?: number; + _meta?: Record; +} + +/** Shape of error.data for -32042 Payment Required. */ +export interface PaymentRequiredErrorData { + instructions?: string; + payment_options: PaymentOption[]; +} + +/** Shape of error.data for -32043 Payment Pending. */ +export interface PaymentPendingErrorData { + instructions?: string; + retry_after?: number; +} + +/** Nostr `payment_interaction` tag as defined by CEP-8. */ +export type PaymentInteractionTag = ['payment_interaction', PaymentInteractionMode]; + +/** + * Canonical invocation identity for explicit-gating authorization matching. + * + * `invocationHash` is SHA-256 over JCS({method, params}). This means `params` MUST be + * deterministic — no timestamps, UUIDs, or ephemeral IDs that change across retries. + * Clients MUST preserve the exact original `params` object when retrying after payment + * so the retry computes the same `invocationHash` and matches the paid authorization. + */ +export interface CanonicalInvocationIdentity { + clientPubkey: string; + /** Hex-encoded SHA-256 of JCS({method, params}). */ + invocationHash: string; +} + /** A CEP-8 payment-accepted notification (JSON-RPC notification). */ export type PaymentAcceptedNotification = JSONRPCNotification & { method: 'notifications/payment_accepted'; diff --git a/src/transport/capability-negotiator.ts b/src/transport/capability-negotiator.ts index cae603b..ad118e9 100644 --- a/src/transport/capability-negotiator.ts +++ b/src/transport/capability-negotiator.ts @@ -180,6 +180,7 @@ export class ServerCapabilityNegotiator { export class ClientCapabilityNegotiator { private hasSentDiscoveryTags = false; private clientPmis?: readonly string[]; + private paymentInteraction?: import('../payments/types.js').PaymentInteractionMode; private serverSupportsEphemeralGiftWraps = false; private _serverInitializeEvent?: NostrEvent; @@ -204,6 +205,13 @@ export class ClientCapabilityNegotiator { this.clientPmis = pmis; } + /** + * Sets the requested payment interaction mode for negotiation. + */ + public setPaymentInteraction(mode: import('../payments/types.js').PaymentInteractionMode): void { + this.paymentInteraction = mode; + } + /** * Updates server capability flags from discovered peer tags. * Called by the transport when it learns new capabilities from inbound events. @@ -253,6 +261,9 @@ export class ClientCapabilityNegotiator { if (this.clientPmis) { tags.push(...this.clientPmis.map((pmi) => ['pmi', pmi])); } + if (this.paymentInteraction && this.paymentInteraction !== 'transparent') { + tags.push(['payment_interaction', this.paymentInteraction]); + } return tags; } diff --git a/src/transport/middleware.ts b/src/transport/middleware.ts index dc7c33f..293a0f8 100644 --- a/src/transport/middleware.ts +++ b/src/transport/middleware.ts @@ -1,10 +1,22 @@ import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'; +import type { PaymentInteractionMode } from '../payments/types.js'; + /** * Inbound middleware hook for server transports. + * + * @note Context relationship: `InboundMiddlewareFn`'s `ctx` is the authoritative source + * of per-request context, populated by the inbound coordinator from the session and + * inbound event tags. `ServerPaymentsContext` (used by `ServerMiddlewareFn`) is a subset + * of this context — it reads the same `paymentInteraction` field. The inbound coordinator + * constructs both from the same session state, so they stay synchronized automatically. */ export type InboundMiddlewareFn = ( message: JSONRPCMessage, - ctx: { clientPubkey: string; clientPmis?: readonly string[] }, + ctx: { + clientPubkey: string; + clientPmis?: readonly string[]; + paymentInteraction?: PaymentInteractionMode; + }, forward: (message: JSONRPCMessage) => Promise, ) => Promise; diff --git a/src/transport/nostr-client-transport.ts b/src/transport/nostr-client-transport.ts index da9c8b8..6dbdb32 100644 --- a/src/transport/nostr-client-transport.ts +++ b/src/transport/nostr-client-transport.ts @@ -584,6 +584,20 @@ export class NostrClientTransport return this.metadataStore.getServerInitializePicture(); } + /** + * Sets the requested payment interaction mode for negotiation. + */ + public setPaymentInteraction(mode: import('../payments/types.js').PaymentInteractionMode): void { + this.capabilityNegotiator.setPaymentInteraction(mode); + } + + /** + * Gets the effective payment interaction mode disclosed by the server. + */ + public getEffectivePaymentInteraction(): import('../payments/types.js').PaymentInteractionMode | undefined { + return this.metadataStore.getEffectivePaymentInteraction(); + } + /** Gets the server's most recently observed tools/list event envelope, if any. */ public getServerToolsListEvent(): NostrEvent | undefined { return this.metadataStore.getServerToolsListEvent(); @@ -628,6 +642,7 @@ export class NostrClientTransport private handleResponse( correlatedEventId: string, mcpMessage: JSONRPCMessage, + eventId?: string, ): void { try { const resolved = this.correlationStore.resolveResponse( @@ -637,6 +652,10 @@ export class NostrClientTransport if (resolved) { this.onmessage?.(mcpMessage); + this.onmessageWithContext?.(mcpMessage, { + eventId: eventId ?? correlatedEventId, + correlatedEventId, + }); } else { this.logger.warn('Response for unknown request', { eventId: correlatedEventId, diff --git a/src/transport/nostr-client/correlation-store.ts b/src/transport/nostr-client/correlation-store.ts index 2f93dc7..3313a07 100644 --- a/src/transport/nostr-client/correlation-store.ts +++ b/src/transport/nostr-client/correlation-store.ts @@ -15,6 +15,8 @@ export interface PendingRequest { progressToken?: string; /** Minimal context about the original request (safe to store; no arguments). */ originalRequestContext?: OriginalRequestContext; + /** The full raw original JSON-RPC request for explicit gating retries. */ + rawRequest?: import('@modelcontextprotocol/sdk/types.js').JSONRPCRequest; } /** @@ -74,6 +76,13 @@ export class ClientCorrelationStore { return this.pendingRequests.get(eventId); } + /** + * Gets the raw original JSON-RPC request for explicit gating retries. + */ + getRawRequest(eventId: string): import('@modelcontextprotocol/sdk/types.js').JSONRPCRequest | undefined { + return this.pendingRequests.get(eventId)?.rawRequest; + } + /** * Resolves a response by finding and removing the corresponding request. * Restores the original request ID in the response before resolving. diff --git a/src/transport/nostr-client/inbound-coordinator.ts b/src/transport/nostr-client/inbound-coordinator.ts index b476c74..d63e1a5 100644 --- a/src/transport/nostr-client/inbound-coordinator.ts +++ b/src/transport/nostr-client/inbound-coordinator.ts @@ -144,7 +144,7 @@ export class ClientInboundCoordinator { } } - this.deps.handleResponse(eTag, mcpMessage); + this.deps.handleResponse(eTag, mcpMessage, nostrEvent.id); return; } @@ -206,6 +206,15 @@ export class ClientInboundCoordinator { return; } + const paymentInteractionTag = event.tags.find( + (tag) => tag[0] === 'payment_interaction' && typeof tag[1] === 'string' + ); + if (paymentInteractionTag) { + this.deps.metadataStore.setEffectivePaymentInteraction( + paymentInteractionTag[1] as import('../../payments/types.js').PaymentInteractionMode + ); + } + const currentHasInitializeResult = InitializeResultSchema.safeParse( this.getInitializeResultCandidate(event), ).success; diff --git a/src/transport/nostr-client/outbound-sender.ts b/src/transport/nostr-client/outbound-sender.ts index 661fbef..67e9c07 100644 --- a/src/transport/nostr-client/outbound-sender.ts +++ b/src/transport/nostr-client/outbound-sender.ts @@ -129,6 +129,7 @@ export class ClientOutboundSender { progressToken: progressToken !== undefined ? String(progressToken) : undefined, originalRequestContext, + rawRequest: isRequest ? (message as import('@modelcontextprotocol/sdk/types.js').JSONRPCRequest) : undefined, }); if ( @@ -204,6 +205,7 @@ export class ClientOutboundSender { progressToken, originalRequestContext: this.deps.getOriginalRequestContext(originalMessage), + rawRequest: originalMessage as import('@modelcontextprotocol/sdk/types.js').JSONRPCRequest, }); } diff --git a/src/transport/nostr-client/server-metadata-store.ts b/src/transport/nostr-client/server-metadata-store.ts index ebe3b77..3c895e0 100644 --- a/src/transport/nostr-client/server-metadata-store.ts +++ b/src/transport/nostr-client/server-metadata-store.ts @@ -20,6 +20,15 @@ export class ServerMetadataStore { private serverResourceTemplatesListEvent: NostrEvent | undefined; private supportsOversizedTransfer = false; private supportsOpenStream = false; + private effectivePaymentInteraction?: import('../../payments/types.js').PaymentInteractionMode; + + public setEffectivePaymentInteraction(mode: import('../../payments/types.js').PaymentInteractionMode): void { + this.effectivePaymentInteraction = mode; + } + + public getEffectivePaymentInteraction(): import('../../payments/types.js').PaymentInteractionMode | undefined { + return this.effectivePaymentInteraction; + } public clear(): void { this.serverInitializeEvent = undefined; @@ -29,6 +38,7 @@ export class ServerMetadataStore { this.serverResourceTemplatesListEvent = undefined; this.supportsOversizedTransfer = false; this.supportsOpenStream = false; + this.effectivePaymentInteraction = undefined; } public setServerInitializeEvent(event: NostrEvent): void { diff --git a/src/transport/nostr-server-transport.ts b/src/transport/nostr-server-transport.ts index 3123205..d323662 100644 --- a/src/transport/nostr-server-transport.ts +++ b/src/transport/nostr-server-transport.ts @@ -487,6 +487,13 @@ export class NostrServerTransport this.listToolsResultTransformers.push(transformer); } + /** + * Sets the supported payment interaction mode for this server. + */ + public setSupportedPaymentInteraction(mode: import('../payments/types.js').PaymentInteractionMode | undefined): void { + this.inboundCoordinator.setSupportedPaymentInteraction(mode); + } + /** * Adds a provider for extra tags on public tools/list announcement events. */ diff --git a/src/transport/nostr-server/inbound-coordinator.ts b/src/transport/nostr-server/inbound-coordinator.ts index b08f053..a33684f 100644 --- a/src/transport/nostr-server/inbound-coordinator.ts +++ b/src/transport/nostr-server/inbound-coordinator.ts @@ -38,6 +38,7 @@ export interface ServerInboundCoordinatorDeps { oversizedEnabled: boolean; openStreamEnabled: boolean; giftWrapMode: GiftWrapMode; + supportedPaymentInteraction?: import('../../payments/types.js').PaymentInteractionMode; sendMcpMessage: ( msg: JSONRPCMessage, pubkey: string, @@ -75,6 +76,10 @@ export class ServerInboundCoordinator { this.inboundNotificationDispatcher = dispatcher; } + public setSupportedPaymentInteraction(mode: import('../../payments/types.js').PaymentInteractionMode | undefined): void { + this.deps.supportedPaymentInteraction = mode; + } + /** * Authorizes and processes an incoming Nostr event, handling message validation, * client authorization, session management, and optional client public key injection. @@ -164,9 +169,25 @@ export class ServerInboundCoordinator { const clientPmis = event.tags .filter((tag) => tag[0] === 'pmi' && typeof tag[1] === 'string') .map((tag) => tag[1] as string); + + const serverSupportsExplicitGating = + this.deps.supportedPaymentInteraction === 'explicit_gating'; + + const paymentInteractionTag = event.tags.find( + (tag) => tag[0] === 'payment_interaction' && typeof tag[1] === 'string' + ); + + if (paymentInteractionTag && !session.requestedPaymentInteraction) { + session.requestedPaymentInteraction = paymentInteractionTag[1] as import('../../payments/types.js').PaymentInteractionMode; + session.effectivePaymentInteraction = serverSupportsExplicitGating + ? session.requestedPaymentInteraction + : 'transparent'; + } + const ctx = { clientPubkey: event.pubkey, clientPmis: clientPmis.length > 0 ? clientPmis : undefined, + paymentInteraction: session.effectivePaymentInteraction, }; const middlewares = this.deps.inboundMiddlewares; diff --git a/src/transport/nostr-server/outbound-response-router.ts b/src/transport/nostr-server/outbound-response-router.ts index f525926..1ea9a2a 100644 --- a/src/transport/nostr-server/outbound-response-router.ts +++ b/src/transport/nostr-server/outbound-response-router.ts @@ -220,6 +220,17 @@ export class OutboundResponseRouter { baseTags: this.deps.createResponseTags(route.clientPubkey, nostrEventId), session, }); + + // CEP-8: Disclose effective mode on first response if client requested a non-default mode + if ( + session.requestedPaymentInteraction && + session.requestedPaymentInteraction !== 'transparent' && + !session.hasDisclosedPaymentInteraction && + session.effectivePaymentInteraction + ) { + tags.push(['payment_interaction', session.effectivePaymentInteraction]); + session.hasDisclosedPaymentInteraction = true; + } const giftWrapKind = this.deps.chooseGiftWrapKind({ session, diff --git a/src/transport/nostr-server/session-store.ts b/src/transport/nostr-server/session-store.ts index e911c1b..881f308 100644 --- a/src/transport/nostr-server/session-store.ts +++ b/src/transport/nostr-server/session-store.ts @@ -26,6 +26,12 @@ export interface ClientSession { supportsOversizedTransfer: boolean; /** Whether the client has advertised CEP-41 open stream support. */ supportsOpenStream: boolean; + /** Client-requested payment interaction mode (from first message). */ + requestedPaymentInteraction?: import('../../payments/types.js').PaymentInteractionMode; + /** Effective payment interaction mode for this session. */ + effectivePaymentInteraction?: import('../../payments/types.js').PaymentInteractionMode; + /** Whether the effective mode has been disclosed on the first response. */ + hasDisclosedPaymentInteraction?: boolean; } /** diff --git a/src/transport/payments-flow.test.ts b/src/transport/payments-flow.test.ts index 0ab3532..c7cbb4f 100644 --- a/src/transport/payments-flow.test.ts +++ b/src/transport/payments-flow.test.ts @@ -1009,4 +1009,91 @@ describe.serial('payments fake flow (transport-level)', () => { await client.close(); await mcpServer.close(); }, 20000); + + test('explicit gating: gates tools/call via -32042 error and auto-retries', async () => { + const serverSK = generateSecretKey(); + const serverPrivateKey = bytesToHex(serverSK); + const serverPublicKey = getPublicKey(serverSK); + + const mcpServer = new McpServer({ name: 'explicit-server', version: '1.0.0' }); + let toolCallCount = 0; + mcpServer.registerTool( + 'add', + { + title: 'Addition Tool', + description: 'Add two numbers', + inputSchema: { a: z.number(), b: z.number() }, + }, + async ({ a, b }: { a: number; b: number }) => { + toolCallCount++; + return { content: [{ type: 'text', text: String(a + b) }] }; + }, + ); + + const processor = new FakePaymentProcessor({ verifyDelayMs: 20 }); + const pricedCapabilities = [ + { + method: 'tools/call', + name: 'add', + amount: 1, + currencyUnit: 'test', + description: 'explicit test payment', + }, + ] as const; + + const serverTransport = withServerPayments( + new NostrServerTransport({ + signer: new PrivateKeySigner(serverPrivateKey), + relayHandler: new ApplesauceRelayPool([relayUrl]), + encryptionMode: EncryptionMode.DISABLED, + }), + { + processors: [processor], + pricedCapabilities: [...pricedCapabilities], + paymentInteraction: 'explicit_gating', + }, + ); + + await mcpServer.connect(serverTransport); + + const clientSK = generateSecretKey(); + const clientPrivateKey = bytesToHex(clientSK); + + // Track if onPaymentRequired was called + let explicitPaymentHandled = false; + + const clientTransport = new NostrClientTransport({ + signer: new PrivateKeySigner(clientPrivateKey), + relayHandler: new ApplesauceRelayPool([relayUrl]), + serverPubkey: serverPublicKey, + encryptionMode: EncryptionMode.DISABLED, + }); + const paidClientTransport = withClientPayments(clientTransport, { + handlers: [new FakePaymentHandler({ delayMs: 20 })], + paymentInteraction: 'explicit_gating', + onPaymentRequired: async () => { + explicitPaymentHandled = true; + return { paid: true }; + } + }); + + const client = new Client({ name: 'explicit-client', version: '1.0.0' }); + await client.connect(paidClientTransport); + + const result = await client.callTool({ + name: 'add', + arguments: { a: 10, b: 20 }, + }); + + const typedResult = result as { + content: Array<{ type: string; text?: string }>; + }; + expect(typedResult.content[0]).toMatchObject({ type: 'text', text: '30' }); + + expect(explicitPaymentHandled).toBe(true); + expect(toolCallCount).toBe(1); + + await client.close(); + await mcpServer.close(); + }, 20000); }); From 97f21e755d9160c477b296e03f0a05178d5af4b1 Mon Sep 17 00:00:00 2001 From: Khushvendra Date: Thu, 11 Jun 2026 16:57:22 +0530 Subject: [PATCH 2/5] fix: address code review findings for explicit gating --- src/payments/authorization-store.test.ts | 12 ++--- src/payments/authorization-store.ts | 17 ++++++ src/payments/client-payments.ts | 52 +++++++++++++------ src/payments/server-explicit-gating.ts | 6 +-- .../nostr-client/inbound-coordinator.ts | 11 ++-- .../nostr-server/inbound-coordinator.ts | 14 +++-- 6 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/payments/authorization-store.test.ts b/src/payments/authorization-store.test.ts index 782c56e..75ba365 100644 --- a/src/payments/authorization-store.test.ts +++ b/src/payments/authorization-store.test.ts @@ -32,9 +32,9 @@ describe('AuthorizationStore', () => { test('claim fails after TTL expires', async () => { const store = new AuthorizationStore(); - store.grant(identity, 10); + store.grant(identity, 50); - await new Promise((resolve) => setTimeout(resolve, 15)); + await new Promise((resolve) => setTimeout(resolve, 75)); expect(store.claim(identity)).toBe(false); }); @@ -66,12 +66,12 @@ describe('AuthorizationStore', () => { test('trySetPending allows setting again after pending state expires', async () => { const store = new AuthorizationStore(); - expect(store.trySetPending(identity, 10)).toBe(true); - expect(store.trySetPending(identity, 10)).toBe(false); + expect(store.trySetPending(identity, 50)).toBe(true); + expect(store.trySetPending(identity, 50)).toBe(false); - await new Promise((resolve) => setTimeout(resolve, 15)); + await new Promise((resolve) => setTimeout(resolve, 75)); - expect(store.trySetPending(identity, 10)).toBe(true); + expect(store.trySetPending(identity, 50)).toBe(true); }); test('grant clears pending state', () => { diff --git a/src/payments/authorization-store.ts b/src/payments/authorization-store.ts index e81e05c..e974953 100644 --- a/src/payments/authorization-store.ts +++ b/src/payments/authorization-store.ts @@ -14,6 +14,11 @@ export interface PaidAuthorization { * A bounded, TTL-aware store for explicit gating authorizations. * It manages both the pending state (waiting for payment verification) * and the granted state (paid and ready to consume). + * + * NOTE: The atomicity provided by `trySetPending` relies on in-memory maps, + * meaning it is strictly single-process. For multi-process horizontal scaling, + * implementers should use a distributed lock (e.g. Redis Redlock) keyed by + * the canonical invocation identity to prevent duplicate payments. */ export class AuthorizationStore { private readonly authorizations: LruCache; @@ -79,6 +84,8 @@ export class AuthorizationStore { if (auth.remaining === 0) { this.authorizations.delete(key); } else { + // Explicitly delete and set to guarantee LRU position is refreshed + this.authorizations.delete(key); this.authorizations.set(key, auth); } this.logger.debug('authorization claimed', { key, remaining: auth.remaining }); @@ -96,6 +103,7 @@ export class AuthorizationStore { * * This atomic check-and-set prevents concurrent requests from both receiving * -32042 and triggering duplicate payment flows. + * NOTE: This is single-process only. Distributed setups must use an external lock. */ public trySetPending(identity: CanonicalInvocationIdentity, ttlMs: number): boolean { const key = this.getKey(identity); @@ -134,6 +142,15 @@ export class AuthorizationStore { return true; } + /** Gets the remaining TTL in milliseconds for a pending authorization, or 0 if not pending. */ + public getPendingRemainingMs(identity: CanonicalInvocationIdentity): number { + const key = this.getKey(identity); + const expiry = this.pending.get(key); + if (expiry === undefined) return 0; + const remaining = expiry - Date.now(); + return remaining > 0 ? remaining : 0; + } + /** Clears pending state (e.g. on verification failure or expiry). */ public clearPending(identity: CanonicalInvocationIdentity): void { const key = this.getKey(identity); diff --git a/src/payments/client-payments.ts b/src/payments/client-payments.ts index df2507c..1d47e9e 100644 --- a/src/payments/client-payments.ts +++ b/src/payments/client-payments.ts @@ -215,12 +215,20 @@ export function withClientPayments( maybeStopScheduler(); }; + const pendingTimers = new Set>(); + const retryCounts = new Map(); + const MAX_RETRIES = 5; + const stopAllSyntheticProgress = (): void => { syntheticProgress.clear(); if (syntheticProgressScheduler) { clearInterval(syntheticProgressScheduler); syntheticProgressScheduler = undefined; } + for (const timer of pendingTimers) { + clearTimeout(timer); + } + pendingTimers.clear(); }; // Ensure CEP-8 discovery/negotiation: when using Nostr transports, always advertise @@ -335,11 +343,8 @@ export function withClientPayments( }); try { - await handler.handle(request); - logger.info('payment handler succeeded, retrying request', { - requestEventId, - pmi: option.pmi, - }); + // In explicit gating, we do NOT call handler.handle(request) directly. + // Instead, we delegate entirely to options.onPaymentRequired. // In explicit gating, the client MUST retry the exact same request // to trigger authorization consumption and get the result. @@ -362,7 +367,8 @@ export function withClientPayments( return; } - const rawRequest = transport.correlationStore.getRawRequest(requestEventId); + const nostrTransport = transport as NostrClientTransport; + const rawRequest = nostrTransport.correlationStore.getRawRequest(requestEventId); if (!rawRequest) { logger.warn('missing raw original request, cannot retry explicit payment', { requestEventId }); onmessage?.(message); @@ -375,14 +381,15 @@ export function withClientPayments( originalRequest: rawRequest, }); - if (result.paid) { - logger.info('explicit payment satisfied, retrying original request', { - requestEventId, - method: rawRequest.method, - }); - - // Re-send the exact request, updating the ID if necessary (or letting MCP SDK handle it) - // But actually we are the transport, we can just resend the raw request through the transport. + if (result.paid) { + // Only if they successfully paid via onPaymentRequired do we proceed to retry + logger.info('explicit payment satisfied, retrying original request', { + requestEventId, + method: rawRequest.method, + }); + + // Re-send the exact request, updating the ID if necessary (or letting MCP SDK handle it) + // But actually we are the transport, we can just resend the raw request through the transport. // Wait, we need to create a new ID so the proxy can track it properly. // Oh right, we can't easily resend and magically stitch it back to the original Promise in the MCP Client. // Actually, if we just send() it, the original promise in the MCP Client is already waiting @@ -470,23 +477,36 @@ export function withClientPayments( return; } - const rawRequest = transport.correlationStore.getRawRequest(requestEventId); + const nostrTransport = transport as NostrClientTransport; + const rawRequest = nostrTransport.correlationStore.getRawRequest(requestEventId); if (!rawRequest) { logger.warn('missing raw original request, cannot retry explicit payment pending', { requestEventId }); onmessage?.(message); return; } + const retries = retryCounts.get(requestEventId) ?? 0; + if (retries >= MAX_RETRIES) { + logger.error('max explicit payment retries exceeded', { requestEventId, maxRetries: MAX_RETRIES }); + onmessage?.(message); + return; + } + + retryCounts.set(requestEventId, retries + 1); + logger.info('payment pending, retrying after backoff', { requestEventId, retryAfterSeconds, + retryCount: retries + 1, }); - setTimeout(() => { + const timer = setTimeout(() => { + pendingTimers.delete(timer); transport.send(rawRequest).catch(err => { logger.error('failed to retry pending request', { requestEventId, error: err instanceof Error ? err.message : String(err) }); }); }, retryAfterSeconds * 1000); + pendingTimers.add(timer); return; // Intercept the error so the client waits } diff --git a/src/payments/server-explicit-gating.ts b/src/payments/server-explicit-gating.ts index 6186034..604554d 100644 --- a/src/payments/server-explicit-gating.ts +++ b/src/payments/server-explicit-gating.ts @@ -83,7 +83,7 @@ export function createExplicitGatingMiddleware( message: 'Payment Pending', data: { instructions: 'A payment is already pending for this invocation. Wait and retry.', - retry_after: 5, + retry_after: Math.ceil(authorizationStore.getPendingRemainingMs(identity) / 1000) || 5, }, }, }; @@ -175,8 +175,8 @@ export function createExplicitGatingMiddleware( }); const effectiveTimeoutMs = Math.min(verifyTimeoutMs, paymentTtlMs); - // Update pending with the precise TTL - authorizationStore.trySetPending(identity, effectiveTimeoutMs); + // Note: Pending TTL was set to paymentTtlMs at line 74, which is >= effectiveTimeoutMs + // This ensures pending state covers the entire verification period. const errorResponse: JSONRPCErrorResponse = { jsonrpc: '2.0', diff --git a/src/transport/nostr-client/inbound-coordinator.ts b/src/transport/nostr-client/inbound-coordinator.ts index d63e1a5..4af7239 100644 --- a/src/transport/nostr-client/inbound-coordinator.ts +++ b/src/transport/nostr-client/inbound-coordinator.ts @@ -28,7 +28,7 @@ export interface ClientInboundCoordinatorDeps { metadataStore: ServerMetadataStore; unwrapEvent: (event: NostrEvent) => Promise; convertNostrEventToMcpMessage: (event: NostrEvent) => JSONRPCMessage | null; - handleResponse: (correlatedEventId: string, msg: JSONRPCMessage) => void; + handleResponse: (correlatedEventId: string, msg: JSONRPCMessage, eventId?: string) => void; handleNotification: ( eventId: string, correlatedEventId: string | undefined, @@ -210,9 +210,12 @@ export class ClientInboundCoordinator { (tag) => tag[0] === 'payment_interaction' && typeof tag[1] === 'string' ); if (paymentInteractionTag) { - this.deps.metadataStore.setEffectivePaymentInteraction( - paymentInteractionTag[1] as import('../../payments/types.js').PaymentInteractionMode - ); + const mode = paymentInteractionTag[1]; + if (mode === 'transparent' || mode === 'explicit_gating') { + this.deps.metadataStore.setEffectivePaymentInteraction( + mode as import('../../payments/types.js').PaymentInteractionMode + ); + } } const currentHasInitializeResult = InitializeResultSchema.safeParse( diff --git a/src/transport/nostr-server/inbound-coordinator.ts b/src/transport/nostr-server/inbound-coordinator.ts index a33684f..e3b1d93 100644 --- a/src/transport/nostr-server/inbound-coordinator.ts +++ b/src/transport/nostr-server/inbound-coordinator.ts @@ -178,10 +178,16 @@ export class ServerInboundCoordinator { ); if (paymentInteractionTag && !session.requestedPaymentInteraction) { - session.requestedPaymentInteraction = paymentInteractionTag[1] as import('../../payments/types.js').PaymentInteractionMode; - session.effectivePaymentInteraction = serverSupportsExplicitGating - ? session.requestedPaymentInteraction - : 'transparent'; + const mode = paymentInteractionTag[1]; + if (mode === 'transparent' || mode === 'explicit_gating') { + session.requestedPaymentInteraction = mode as import('../../payments/types.js').PaymentInteractionMode; + session.effectivePaymentInteraction = serverSupportsExplicitGating + ? session.requestedPaymentInteraction + : 'transparent'; + } else { + session.requestedPaymentInteraction = 'transparent'; + session.effectivePaymentInteraction = 'transparent'; + } } const ctx = { From 8bc5b23025260b544926fe6294c7d1ccf658df6a Mon Sep 17 00:00:00 2001 From: Khushvendra Date: Thu, 11 Jun 2026 17:13:08 +0530 Subject: [PATCH 3/5] fix: address PR feedback for explicit gating --- package-lock.json | 5046 +++++++++++++++++ package.json | 1 - src/payments/authorization-store.ts | 10 + src/payments/canonical-identity.ts | 2 +- src/payments/client-payments.ts | 28 +- src/payments/server-explicit-gating.ts | 4 +- src/payments/server-transport-payments.ts | 2 +- src/transport/nostr-server-transport.ts | 17 + .../nostr-server/outbound-response-router.ts | 50 + 9 files changed, 5147 insertions(+), 13 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..00d0356 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5046 @@ +{ + "name": "@contextvm/sdk", + "version": "0.11.14", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@contextvm/sdk", + "version": "0.11.14", + "license": "LGPL-3.0-1", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "@noble/hashes": "^2.2.0", + "applesauce-relay": "^5.2.0", + "canonicalize": "^2.1.0", + "nostr-tools": "~2.18.2", + "pino": "^10.3.1", + "rxjs": "^7.8.2", + "ws": "^8.20.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@changesets/cli": "^2.31.0", + "@eslint/js": "^9.39.4", + "@types/bun": "^1.3.13", + "eslint": "^9.39.4", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-import": "^2.32.0", + "prettier": "^3.8.3", + "typescript-eslint": "^8.59.2" + }, + "engines": { + "bun": ">=1.2.0" + }, + "peerDependencies": { + "typescript": "^5.9.3" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@changesets/apply-release-plan": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/config": "^3.1.4", + "@changesets/get-version-range-type": "^0.4.0", + "@changesets/git": "^3.0.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/apply-release-plan/node_modules/prettier": { + "version": "2.8.8", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "6.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.31.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/apply-release-plan": "^7.1.1", + "@changesets/assemble-release-plan": "^6.0.10", + "@changesets/changelog-git": "^0.2.1", + "@changesets/config": "^3.1.4", + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.4", + "@changesets/get-release-plan": "^4.0.16", + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@changesets/write": "^0.4.0", + "@inquirer/external-editor": "^1.0.2", + "@manypkg/get-packages": "^1.1.3", + "ansi-colors": "^4.1.3", + "enquirer": "^2.4.1", + "fs-extra": "^7.0.1", + "mri": "^1.2.0", + "package-manager-detector": "^0.2.0", + "picocolors": "^1.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^3.0.1", + "term-size": "^2.1.0" + }, + "bin": { + "changeset": "bin.js" + } + }, + "node_modules/@changesets/config": { + "version": "3.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.4", + "@changesets/logger": "^0.1.1", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.8" + } + }, + "node_modules/@changesets/errors": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "picocolors": "^1.1.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "4.0.16", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/assemble-release-plan": "^6.0.10", + "@changesets/config": "^3.1.4", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/git": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.8", + "spawndamnit": "^3.0.1" + } + }, + "node_modules/@changesets/logger": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "js-yaml": "^4.1.1" + } + }, + "node_modules/@changesets/pre": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.6.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/parse": "^0.4.3", + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0", + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/should-skip-package": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/types": { + "version": "6.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/write": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "human-id": "^4.1.1", + "prettier": "^2.7.1" + } + }, + "node_modules/@changesets/write/node_modules/prettier": { + "version": "2.8.8", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@manypkg/find-root/node_modules/@types/node": { + "version": "12.20.55", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/find-root/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@manypkg/find-root/node_modules/find-up/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@manypkg/find-root/node_modules/find-up/node_modules/locate-path/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@manypkg/find-root/node_modules/find-up/node_modules/locate-path/node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@manypkg/find-root/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "8.20.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/zod": { + "version": "4.4.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@noble/ciphers": { + "version": "0.5.3", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@scure/base": { + "version": "1.1.1", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@scure/bip32": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.1", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.3.2", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.3.2", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@types/bun": { + "version": "1.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "bun-types": "1.3.13" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/type-utils": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.59.2", + "@typescript-eslint/types": "^8.59.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.59.2", + "@typescript-eslint/tsconfig-utils": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { + "version": "4.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/ajv/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/applesauce-core": { + "version": "5.2.0", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fast-deep-equal": "^3.1.3", + "hash-sum": "^2.0.0", + "nanoid": "^5.0.9", + "nostr-tools": "~2.19", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-core/node_modules/nostr-tools": { + "version": "2.19.4", + "license": "Unlicense", + "dependencies": { + "@noble/ciphers": "^0.5.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.1", + "@scure/base": "1.1.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1", + "nostr-wasm": "0.1.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/applesauce-core/node_modules/nostr-tools/node_modules/@noble/hashes": { + "version": "1.3.1", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay": { + "version": "5.2.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.7.1", + "applesauce-core": "^5.2.0", + "nanoid": "^5.0.9", + "nostr-tools": "~2.19", + "rxjs": "^7.8.1" + }, + "funding": { + "type": "lightning", + "url": "lightning:nostrudel@geyser.fund" + } + }, + "node_modules/applesauce-relay/node_modules/@noble/hashes": { + "version": "1.8.0", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/applesauce-relay/node_modules/nostr-tools": { + "version": "2.19.4", + "license": "Unlicense", + "dependencies": { + "@noble/ciphers": "^0.5.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.1", + "@scure/base": "1.1.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1", + "nostr-wasm": "0.1.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/applesauce-relay/node_modules/nostr-tools/node_modules/@noble/hashes": { + "version": "1.3.1", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bun-types": { + "version": "1.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/canonicalize": { + "version": "2.1.0", + "license": "Apache-2.0", + "bin": { + "canonicalize": "bin/canonicalize.js" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.8", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.4.1", + "license": "MIT", + "dependencies": { + "ip-address": "10.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.3", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.12.16", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/human-id": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "5.1.11", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/nostr-tools": { + "version": "2.18.2", + "license": "Unlicense", + "dependencies": { + "@noble/ciphers": "^0.5.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.1", + "@scure/base": "1.1.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1", + "nostr-wasm": "0.1.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/nostr-tools/node_modules/@noble/hashes": { + "version": "1.3.1", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/nostr-wasm": { + "version": "0.1.0", + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/own-keys": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "license": "MIT" + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-warning": { + "version": "5.0.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.1", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/read-yaml-file": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/read-yaml-file/node_modules/js-yaml": { + "version": "3.14.2", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/read-yaml-file/node_modules/js-yaml/node_modules/argparse": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.6", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/router": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/spawndamnit": { + "version": "3.0.1", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "cross-spawn": "^7.0.5", + "signal-exit": "^4.0.1" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/statuses": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/thread-stream": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.59.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.59.2", + "@typescript-eslint/parser": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/utils": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.20.0", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/package.json b/package.json index 9692c7c..d6721a0 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,6 @@ "@noble/hashes": "^2.2.0", "applesauce-relay": "^5.2.0", "canonicalize": "^2.1.0", - "json-canonicalize": "^2.0.0", "nostr-tools": "~2.18.2", "pino": "^10.3.1", "rxjs": "^7.8.2", diff --git a/src/payments/authorization-store.ts b/src/payments/authorization-store.ts index e974953..a8fa049 100644 --- a/src/payments/authorization-store.ts +++ b/src/payments/authorization-store.ts @@ -142,6 +142,16 @@ export class AuthorizationStore { return true; } + /** Updates the TTL of an already pending authorization. No-op if not pending. */ + public updatePendingTtl(identity: CanonicalInvocationIdentity, ttlMs: number): void { + const key = this.getKey(identity); + const existingExpiry = this.pending.get(key); + if (existingExpiry !== undefined && Date.now() <= existingExpiry) { + this.pending.set(key, Date.now() + ttlMs); + this.logger.debug('authorization pending TTL updated', { key, ttlMs }); + } + } + /** Gets the remaining TTL in milliseconds for a pending authorization, or 0 if not pending. */ public getPendingRemainingMs(identity: CanonicalInvocationIdentity): number { const key = this.getKey(identity); diff --git a/src/payments/canonical-identity.ts b/src/payments/canonical-identity.ts index 5bf29cb..3d98bdf 100644 --- a/src/payments/canonical-identity.ts +++ b/src/payments/canonical-identity.ts @@ -1,4 +1,4 @@ -import { canonicalize } from 'json-canonicalize'; +import canonicalize from 'canonicalize'; import { createHash } from 'crypto'; import type { CanonicalInvocationIdentity } from './types.js'; diff --git a/src/payments/client-payments.ts b/src/payments/client-payments.ts index 1d47e9e..e3b0e6f 100644 --- a/src/payments/client-payments.ts +++ b/src/payments/client-payments.ts @@ -216,7 +216,8 @@ export function withClientPayments( }; const pendingTimers = new Set>(); - const retryCounts = new Map(); + const retryCounts = new Map(); + const rawRequestCache = new Map(); const MAX_RETRIES = 5; const stopAllSyntheticProgress = (): void => { @@ -229,6 +230,8 @@ export function withClientPayments( clearTimeout(timer); } pendingTimers.clear(); + retryCounts.clear(); + rawRequestCache.clear(); }; // Ensure CEP-8 discovery/negotiation: when using Nostr transports, always advertise @@ -367,8 +370,8 @@ export function withClientPayments( return; } - const nostrTransport = transport as NostrClientTransport; - const rawRequest = nostrTransport.correlationStore.getRawRequest(requestEventId); + const requestId = message.id; + const rawRequest = requestId != null ? rawRequestCache.get(requestId) : undefined; if (!rawRequest) { logger.warn('missing raw original request, cannot retry explicit payment', { requestEventId }); onmessage?.(message); @@ -477,22 +480,23 @@ export function withClientPayments( return; } - const nostrTransport = transport as NostrClientTransport; - const rawRequest = nostrTransport.correlationStore.getRawRequest(requestEventId); + const requestId = message.id; + const rawRequest = requestId != null ? rawRequestCache.get(requestId) : undefined; if (!rawRequest) { logger.warn('missing raw original request, cannot retry explicit payment pending', { requestEventId }); onmessage?.(message); return; } - const retries = retryCounts.get(requestEventId) ?? 0; + const requestIdKey = message.id as string | number; + const retries = retryCounts.get(requestIdKey) ?? 0; if (retries >= MAX_RETRIES) { - logger.error('max explicit payment retries exceeded', { requestEventId, maxRetries: MAX_RETRIES }); + logger.error('max explicit payment retries exceeded', { requestEventId, id: requestIdKey, maxRetries: MAX_RETRIES }); onmessage?.(message); return; } - retryCounts.set(requestEventId, retries + 1); + retryCounts.set(requestIdKey, retries + 1); logger.info('payment pending, retrying after backoff', { requestEventId, @@ -736,6 +740,11 @@ export function withClientPayments( isJSONRPCErrorResponse(message) ) { stopSyntheticProgress(String(message.id)); + if (!isExplicitPaymentRequiredError(message) && !isExplicitPaymentPendingError(message)) { + const reqId = message.id as string | number; + rawRequestCache.delete(reqId); + retryCounts.delete(reqId); + } } // Best-effort: execute handler asynchronously, but never block delivery. @@ -823,6 +832,9 @@ export function withClientPayments( }, async send(message: JSONRPCMessage): Promise { + if ('method' in message && 'id' in message && message.id != null) { + rawRequestCache.set(message.id, message as JSONRPCRequest); + } await transport.send(message); }, diff --git a/src/payments/server-explicit-gating.ts b/src/payments/server-explicit-gating.ts index 604554d..46df622 100644 --- a/src/payments/server-explicit-gating.ts +++ b/src/payments/server-explicit-gating.ts @@ -175,8 +175,8 @@ export function createExplicitGatingMiddleware( }); const effectiveTimeoutMs = Math.min(verifyTimeoutMs, paymentTtlMs); - // Note: Pending TTL was set to paymentTtlMs at line 74, which is >= effectiveTimeoutMs - // This ensures pending state covers the entire verification period. + // Update pending with the precise TTL + authorizationStore.updatePendingTtl(identity, effectiveTimeoutMs); const errorResponse: JSONRPCErrorResponse = { jsonrpc: '2.0', diff --git a/src/payments/server-transport-payments.ts b/src/payments/server-transport-payments.ts index 6aef7df..695bc5d 100644 --- a/src/payments/server-transport-payments.ts +++ b/src/payments/server-transport-payments.ts @@ -35,7 +35,7 @@ export function withServerPayments( options, authorizationStore, sendResponse: async (clientPubkey, response, requestEventId) => { - await transport.send(response); + await transport.sendTargetedResponse(clientPubkey, response, requestEventId); }, }), ); diff --git a/src/transport/nostr-server-transport.ts b/src/transport/nostr-server-transport.ts index d323662..44ff670 100644 --- a/src/transport/nostr-server-transport.ts +++ b/src/transport/nostr-server-transport.ts @@ -693,6 +693,23 @@ export class NostrServerTransport await this.outboundResponseRouter.route(response); } + /** + * Sends a targeted response explicitly bypassing the correlation store lookup. + * Useful for middleware that needs to proactively reject requests without + * letting them reach the MCP application. + * + * @param clientPubkey The target client's public key. + * @param response The JSON-RPC response or error to send. + * @param requestEventId The original Nostr event ID of the request being responded to. + */ + public async sendTargetedResponse( + clientPubkey: string, + response: JSONRPCResponse | JSONRPCErrorResponse, + requestEventId: string, + ): Promise { + await this.outboundResponseRouter.routeTargeted(clientPubkey, response, requestEventId); + } + /** * Handles notification messages with routing. * @param notification The JSON-RPC notification to send. diff --git a/src/transport/nostr-server/outbound-response-router.ts b/src/transport/nostr-server/outbound-response-router.ts index 1ea9a2a..d5b0199 100644 --- a/src/transport/nostr-server/outbound-response-router.ts +++ b/src/transport/nostr-server/outbound-response-router.ts @@ -271,4 +271,54 @@ export class OutboundResponseRouter { throw error; } } + + /** + * Routes a response back to a specifically targeted client and request event. + * This bypasses the normal correlation lookup, which is useful when + * middleware needs to reject a request early (e.g. for explicit gating). + */ + public async routeTargeted( + clientPubkey: string, + response: JSONRPCResponse | JSONRPCErrorResponse, + requestEventId: string, + ): Promise { + const session = this.deps.getSession(clientPubkey); + if (!session) { + this.deps.logger.warn( + 'Cannot route targeted response: no active session found', + { clientPubkey, requestEventId }, + ); + return; + } + + const tags = this.deps.buildOutboundTags({ + baseTags: this.deps.createResponseTags(clientPubkey, requestEventId), + session, + }); + + // CEP-8: Disclose effective mode on first response if client requested a non-default mode + if ( + session.requestedPaymentInteraction && + session.requestedPaymentInteraction !== 'transparent' && + !session.hasDisclosedPaymentInteraction && + session.effectivePaymentInteraction + ) { + tags.push(['payment_interaction', session.effectivePaymentInteraction]); + session.hasDisclosedPaymentInteraction = true; + } + + const giftWrapKind = this.deps.chooseGiftWrapKind({ + session, + }); + + await this.deps.sendMcpMessage( + response, + clientPubkey, + CTXVM_MESSAGES_KIND, + tags, + session.isEncrypted, + undefined, + giftWrapKind, + ); + } } From 1023733de94a91bce46fea9cb19cdd15f6628a51 Mon Sep 17 00:00:00 2001 From: Khushvendra Date: Thu, 11 Jun 2026 20:18:59 +0530 Subject: [PATCH 4/5] fix(sdk): resolve explicit gating bugs and stabilize tests --- src/payments/authorization-store.test.ts | 46 +++++++++++++++++++ src/payments/authorization-store.ts | 12 ++++- src/payments/canonical-identity.ts | 7 ++- src/payments/client-payments.test.ts | 13 +++++- src/payments/client-payments.ts | 31 ++++++------- src/payments/server-explicit-gating.test.ts | 29 +++++++++++- src/payments/server-explicit-gating.ts | 11 ++++- src/payments/server-transport-payments.ts | 2 +- .../nostr-server/inbound-coordinator.ts | 2 +- .../nostr-server/outbound-response-router.ts | 2 +- src/transport/payments-flow.test.ts | 7 ++- 11 files changed, 136 insertions(+), 26 deletions(-) diff --git a/src/payments/authorization-store.test.ts b/src/payments/authorization-store.test.ts index 75ba365..d5aa150 100644 --- a/src/payments/authorization-store.test.ts +++ b/src/payments/authorization-store.test.ts @@ -101,4 +101,50 @@ describe('AuthorizationStore', () => { expect(store.claim(id2)).toBe(true); expect(store.claim(id3)).toBe(true); }); + + test('pending LRU eviction works when maxEntries is exceeded', () => { + const store = new AuthorizationStore({ maxEntries: 2 }); + + const id1 = { clientPubkey: 'client', invocationHash: 'p1' }; + const id2 = { clientPubkey: 'client', invocationHash: 'p2' }; + const id3 = { clientPubkey: 'client', invocationHash: 'p3' }; + + store.trySetPending(id1, 10000); + store.trySetPending(id2, 10000); + store.trySetPending(id3, 10000); // This should evict id1 + + expect(store.hasPending(id1)).toBe(false); + expect(store.hasPending(id2)).toBe(true); + expect(store.hasPending(id3)).toBe(true); + }); + + test('updatePendingTtl and getPendingRemainingMs behave correctly', async () => { + const store = new AuthorizationStore(); + + // (1) verify getPendingRemainingMs right after trySetPending + expect(store.trySetPending(identity, 100)).toBe(true); + const remainingAfterSet = store.getPendingRemainingMs(identity); + expect(remainingAfterSet).toBeGreaterThan(0); + expect(remainingAfterSet).toBeLessThanOrEqual(100); + + // (2) verify updatePendingTtl extends the pending TTL + store.updatePendingTtl(identity, 500); + const remainingAfterUpdate = store.getPendingRemainingMs(identity); + expect(remainingAfterUpdate).toBeGreaterThan(100); + expect(remainingAfterUpdate).toBeLessThanOrEqual(500); + + // (3) verify getPendingRemainingMs returns 0 after waiting past TTL + await new Promise((resolve) => setTimeout(resolve, 550)); + expect(store.getPendingRemainingMs(identity)).toBe(0); + + // (4) verify updatePendingTtl is a no-op when there is no active pending entry + store.updatePendingTtl(identity, 1000); + expect(store.getPendingRemainingMs(identity)).toBe(0); + + // And after clearPending + store.trySetPending(identity, 1000); + store.clearPending(identity); + store.updatePendingTtl(identity, 1000); + expect(store.getPendingRemainingMs(identity)).toBe(0); + }); }); diff --git a/src/payments/authorization-store.ts b/src/payments/authorization-store.ts index a8fa049..f739e6e 100644 --- a/src/payments/authorization-store.ts +++ b/src/payments/authorization-store.ts @@ -43,6 +43,10 @@ export class AuthorizationStore { ttlMs: number, count: number = 1, ): void { + if (count <= 0) { + throw new RangeError('Authorization count must be greater than 0'); + } + const key = this.getKey(identity); const expiresAtMs = Date.now() + ttlMs; @@ -142,7 +146,13 @@ export class AuthorizationStore { return true; } - /** Updates the TTL of an already pending authorization. No-op if not pending. */ + /** + * Updates the TTL of an already pending authorization. No-op if not pending. + * + * @param identity The canonical invocation identity. + * @param ttlMs The new TTL in milliseconds to apply from now. + * @returns void + */ public updatePendingTtl(identity: CanonicalInvocationIdentity, ttlMs: number): void { const key = this.getKey(identity); const existingExpiry = this.pending.get(key); diff --git a/src/payments/canonical-identity.ts b/src/payments/canonical-identity.ts index 3d98bdf..40fb7cd 100644 --- a/src/payments/canonical-identity.ts +++ b/src/payments/canonical-identity.ts @@ -1,4 +1,6 @@ -import canonicalize from 'canonicalize'; +import canonicalizePackage from 'canonicalize'; +type CanonicalizeFn = (input: unknown) => string | undefined; +const canonicalize = canonicalizePackage as unknown as CanonicalizeFn; import { createHash } from 'crypto'; import type { CanonicalInvocationIdentity } from './types.js'; @@ -17,6 +19,9 @@ export function computeCanonicalInvocationHash( ): string { const payload = { method, params }; const canonicalString = canonicalize(payload); + if (canonicalString === undefined) { + throw new Error('Failed to canonicalize invocation payload'); + } return createHash('sha256') .update(canonicalString) diff --git a/src/payments/client-payments.test.ts b/src/payments/client-payments.test.ts index cd56b29..98126b6 100644 --- a/src/payments/client-payments.test.ts +++ b/src/payments/client-payments.test.ts @@ -619,6 +619,10 @@ describe('withClientPayments()', () => { paid.onmessage = (msg) => observed.push(msg); await paid.start(); + // Populate the wrapper's cache with the original request + await paid.send({ jsonrpc: '2.0', id: 77, method: 'tools/call', params: { name: 'test' } }); + sentMessage = undefined; // Reset mock state so we can observe the retry + // Deliver -32042 Payment Required error transport.onmessageWithContext!( { @@ -668,6 +672,9 @@ describe('withClientPayments()', () => { paid.onmessage = (msg) => observed.push(msg); await paid.start(); + // Populate the wrapper's cache with the original request + await paid.send({ jsonrpc: '2.0', id: 88, method: 'tools/call', params: { name: 'test' } }); + // Deliver -32042 Payment Required error transport.onmessageWithContext!( { @@ -691,7 +698,7 @@ describe('withClientPayments()', () => { const errResp = observed[0] as JSONRPCMessage; expect(errResp.id).toBe(88); expect('error' in errResp && errResp.error?.code).toBe(-32042); - expect('error' in errResp && (errResp.error?.data as any)?.reason).toBe('user_cancelled'); + expect('error' in errResp && (errResp.error?.data as { reason?: string })?.reason).toBe('user_cancelled'); await paid.close(); }); @@ -720,6 +727,10 @@ describe('withClientPayments()', () => { paid.onmessage = (msg) => observed.push(msg); await paid.start(); + // Populate the wrapper's cache with the original request + await paid.send({ jsonrpc: '2.0', id: 99, method: 'tools/call', params: { name: 'test_pending' } }); + sentMessage = undefined; // Reset mock state so we can observe the retry + // Deliver -32043 Payment Pending error transport.onmessageWithContext!( { diff --git a/src/payments/client-payments.ts b/src/payments/client-payments.ts index e3b0e6f..007692c 100644 --- a/src/payments/client-payments.ts +++ b/src/payments/client-payments.ts @@ -5,6 +5,7 @@ import { isJSONRPCErrorResponse, JSONRPCNotification, type JSONRPCMessage, + type JSONRPCRequest, } from '@modelcontextprotocol/sdk/types.js'; import { NostrClientTransport } from '../transport/nostr-client-transport.js'; import { @@ -118,8 +119,8 @@ function isExplicitPaymentRequiredError( msg.error.code === PAYMENT_REQUIRED_ERROR_CODE && typeof msg.error.data === 'object' && msg.error.data !== null && - Array.isArray((msg.error.data as any).payment_options) && - (msg.error.data as any).payment_options.length > 0 + Array.isArray((msg.error.data as { payment_options?: unknown }).payment_options) && + ((msg.error.data as { payment_options: unknown[] }).payment_options).length > 0 ); } @@ -131,7 +132,7 @@ function isExplicitPaymentPendingError( msg.error.code === PAYMENT_PENDING_ERROR_CODE && typeof msg.error.data === 'object' && msg.error.data !== null && - typeof (msg.error.data as any).retry_after === 'number' + typeof (msg.error.data as { retry_after?: unknown }).retry_after === 'number' ); } @@ -281,7 +282,7 @@ export function withClientPayments( for (const option of data.payment_options) { const handler = handlersByPmi.get(option.pmi); - if (!handler) continue; + if (!handler && !options.onPaymentRequired) continue; const isNostrTransport = transport instanceof NostrClientTransport; const pending = isNostrTransport @@ -297,11 +298,11 @@ export function withClientPayments( return; } - const originalContext = pending + const originalContext = pending?.originalRequestContext ? { - method: pending.method, - capability: pending.capability, - id: pending.id, + method: pending.originalRequestContext.method, + capability: pending.originalRequestContext.capability, + id: pending.originalRequestId, } : undefined; @@ -327,7 +328,7 @@ export function withClientPayments( continue; // Try next option if rejected by policy } - const canHandle = handler.canHandle + const canHandle = handler?.canHandle ? await handler.canHandle(request) : true; @@ -364,12 +365,6 @@ export function withClientPayments( return; } - if (!pending?.originalRequestContext?.method) { - logger.warn('missing original request method, cannot retry explicit payment', { requestEventId }); - onmessage?.(message); - return; - } - const requestId = message.id; const rawRequest = requestId != null ? rawRequestCache.get(requestId) : undefined; if (!rawRequest) { @@ -509,7 +504,7 @@ export function withClientPayments( transport.send(rawRequest).catch(err => { logger.error('failed to retry pending request', { requestEventId, error: err instanceof Error ? err.message : String(err) }); }); - }, retryAfterSeconds * 1000); + }, (retryAfterSeconds ?? 1) * 1000); pendingTimers.add(timer); return; // Intercept the error so the client waits @@ -747,6 +742,10 @@ export function withClientPayments( } } + if (hasContextPath) { + return; + } + // Best-effort: execute handler asynchronously, but never block delivery. void maybeHandlePaymentRequired(message, 'unknown').catch( (err: unknown) => { diff --git a/src/payments/server-explicit-gating.test.ts b/src/payments/server-explicit-gating.test.ts index ecac39d..e26b0e1 100644 --- a/src/payments/server-explicit-gating.test.ts +++ b/src/payments/server-explicit-gating.test.ts @@ -74,7 +74,7 @@ describe('Explicit Gating Middleware', () => { const response = sentResponses[0]; expect(response.error.code).toBe(PAYMENT_REQUIRED_ERROR_CODE); - const data = response.error.data as any; + const data = response.error.data as { payment_options: { amount: number; pay_req: string }[] }; expect(data.payment_options.length).toBe(1); expect(data.payment_options[0].amount).toBe(10); expect(data.payment_options[0].pay_req).toBe('pay_req'); @@ -169,4 +169,31 @@ describe('Explicit Gating Middleware', () => { expect(sentResponses.length).toBe(0); expect(forwarded).toBe(true); }); + + test('rejects request immediately if resolvePrice rejects', async () => { + const store = new AuthorizationStore(); + const sentResponses: JSONRPCErrorResponse[] = []; + + const mw = createExplicitGatingMiddleware({ + options: { + processors: [processor], + pricedCapabilities: [...pricedCapabilities], + resolvePrice: async () => ({ reject: true, message: 'Rate limited' }), + }, + authorizationStore: store, + sendResponse: async (pubkey, response) => { + sentResponses.push(response as JSONRPCErrorResponse); + }, + }); + + let forwarded = false; + await mw(message, ctx, async () => { + forwarded = true; + }); + + expect(forwarded).toBe(false); + expect(sentResponses.length).toBe(1); + expect(sentResponses[0].error.code).toBe(-32000); + expect(sentResponses[0].error.message).toBe('Rate limited'); + }); }); diff --git a/src/payments/server-explicit-gating.ts b/src/payments/server-explicit-gating.ts index 46df622..abfe896 100644 --- a/src/payments/server-explicit-gating.ts +++ b/src/payments/server-explicit-gating.ts @@ -83,7 +83,8 @@ export function createExplicitGatingMiddleware( message: 'Payment Pending', data: { instructions: 'A payment is already pending for this invocation. Wait and retry.', - retry_after: Math.ceil(authorizationStore.getPendingRemainingMs(identity) / 1000) || 5, + // Suggest a short polling interval (e.g. 2 seconds) rather than the full TTL + retry_after: Math.min(2, Math.ceil(authorizationStore.getPendingRemainingMs(identity) / 1000)) || 2, }, }, }; @@ -246,7 +247,13 @@ export function createExplicitGatingMiddleware( } finally { controller.abort(); } - })(); + })().catch((err) => { + logger.error('unhandled exception in async payment verification', { + requestEventId, + pmi: paymentRequired.pmi, + error: err instanceof Error ? err.message : String(err), + }); + }); } catch (err) { authorizationStore.clearPending(identity); throw err; diff --git a/src/payments/server-transport-payments.ts b/src/payments/server-transport-payments.ts index 695bc5d..6d3a6cc 100644 --- a/src/payments/server-transport-payments.ts +++ b/src/payments/server-transport-payments.ts @@ -17,7 +17,7 @@ export function withServerPayments( const extraTags = createPmiTagsFromProcessors(options.processors); if (options.paymentInteraction === 'explicit_gating') { - extraTags.push(['payment_interaction', 'explicit_gating']); + extraTags.push(['payment_interaction', 'explicit_gating'] as any); } transport.setAnnouncementExtraTags(extraTags); diff --git a/src/transport/nostr-server/inbound-coordinator.ts b/src/transport/nostr-server/inbound-coordinator.ts index e3b1d93..3118436 100644 --- a/src/transport/nostr-server/inbound-coordinator.ts +++ b/src/transport/nostr-server/inbound-coordinator.ts @@ -193,7 +193,7 @@ export class ServerInboundCoordinator { const ctx = { clientPubkey: event.pubkey, clientPmis: clientPmis.length > 0 ? clientPmis : undefined, - paymentInteraction: session.effectivePaymentInteraction, + paymentInteraction: session.effectivePaymentInteraction ?? 'transparent', }; const middlewares = this.deps.inboundMiddlewares; diff --git a/src/transport/nostr-server/outbound-response-router.ts b/src/transport/nostr-server/outbound-response-router.ts index d5b0199..8b6a6b5 100644 --- a/src/transport/nostr-server/outbound-response-router.ts +++ b/src/transport/nostr-server/outbound-response-router.ts @@ -282,7 +282,7 @@ export class OutboundResponseRouter { response: JSONRPCResponse | JSONRPCErrorResponse, requestEventId: string, ): Promise { - const session = this.deps.getSession(clientPubkey); + const session = this.deps.sessionStore.getSession(clientPubkey); if (!session) { this.deps.logger.warn( 'Cannot route targeted response: no active session found', diff --git a/src/transport/payments-flow.test.ts b/src/transport/payments-flow.test.ts index c7cbb4f..db7dfc2 100644 --- a/src/transport/payments-flow.test.ts +++ b/src/transport/payments-flow.test.ts @@ -5,6 +5,7 @@ import { describe, expect, test, + spyOn, } from 'bun:test'; import { sleep } from 'bun'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; @@ -1031,6 +1032,8 @@ describe.serial('payments fake flow (transport-level)', () => { ); const processor = new FakePaymentProcessor({ verifyDelayMs: 20 }); + const createSpy = spyOn(processor, 'createPaymentRequired'); + const verifySpy = spyOn(processor, 'verifyPayment'); const pricedCapabilities = [ { method: 'tools/call', @@ -1069,7 +1072,7 @@ describe.serial('payments fake flow (transport-level)', () => { encryptionMode: EncryptionMode.DISABLED, }); const paidClientTransport = withClientPayments(clientTransport, { - handlers: [new FakePaymentHandler({ delayMs: 20 })], + handlers: [], paymentInteraction: 'explicit_gating', onPaymentRequired: async () => { explicitPaymentHandled = true; @@ -1092,6 +1095,8 @@ describe.serial('payments fake flow (transport-level)', () => { expect(explicitPaymentHandled).toBe(true); expect(toolCallCount).toBe(1); + expect(createSpy).toHaveBeenCalled(); + expect(verifySpy).toHaveBeenCalled(); await client.close(); await mcpServer.close(); From 887692913068da1ef246b41ef7cdd365153a06ce Mon Sep 17 00:00:00 2001 From: Khushvendra Date: Thu, 11 Jun 2026 20:39:57 +0530 Subject: [PATCH 5/5] Reseolve minor issue findings --- package-lock.json | 5046 ----------------- src/payments/server-transport-payments.ts | 4 +- .../nostr-server/inbound-coordinator.ts | 38 + 3 files changed, 40 insertions(+), 5048 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 00d0356..0000000 --- a/package-lock.json +++ /dev/null @@ -1,5046 +0,0 @@ -{ - "name": "@contextvm/sdk", - "version": "0.11.14", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@contextvm/sdk", - "version": "0.11.14", - "license": "LGPL-3.0-1", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.29.0", - "@noble/hashes": "^2.2.0", - "applesauce-relay": "^5.2.0", - "canonicalize": "^2.1.0", - "nostr-tools": "~2.18.2", - "pino": "^10.3.1", - "rxjs": "^7.8.2", - "ws": "^8.20.0", - "zod": "^4.4.3" - }, - "devDependencies": { - "@changesets/cli": "^2.31.0", - "@eslint/js": "^9.39.4", - "@types/bun": "^1.3.13", - "eslint": "^9.39.4", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-import": "^2.32.0", - "prettier": "^3.8.3", - "typescript-eslint": "^8.59.2" - }, - "engines": { - "bun": ">=1.2.0" - }, - "peerDependencies": { - "typescript": "^5.9.3" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@changesets/apply-release-plan": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/config": "^3.1.4", - "@changesets/get-version-range-type": "^0.4.0", - "@changesets/git": "^3.0.4", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "detect-indent": "^6.0.0", - "fs-extra": "^7.0.1", - "lodash.startcase": "^4.4.0", - "outdent": "^0.5.0", - "prettier": "^2.7.1", - "resolve-from": "^5.0.0", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/apply-release-plan/node_modules/prettier": { - "version": "2.8.8", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/@changesets/assemble-release-plan": { - "version": "6.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.4", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/changelog-git": { - "version": "0.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0" - } - }, - "node_modules/@changesets/cli": { - "version": "2.31.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/apply-release-plan": "^7.1.1", - "@changesets/assemble-release-plan": "^6.0.10", - "@changesets/changelog-git": "^0.2.1", - "@changesets/config": "^3.1.4", - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.4", - "@changesets/get-release-plan": "^4.0.16", - "@changesets/git": "^3.0.4", - "@changesets/logger": "^0.1.1", - "@changesets/pre": "^2.0.2", - "@changesets/read": "^0.6.7", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@changesets/write": "^0.4.0", - "@inquirer/external-editor": "^1.0.2", - "@manypkg/get-packages": "^1.1.3", - "ansi-colors": "^4.1.3", - "enquirer": "^2.4.1", - "fs-extra": "^7.0.1", - "mri": "^1.2.0", - "package-manager-detector": "^0.2.0", - "picocolors": "^1.1.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.3", - "spawndamnit": "^3.0.1", - "term-size": "^2.1.0" - }, - "bin": { - "changeset": "bin.js" - } - }, - "node_modules/@changesets/config": { - "version": "3.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/get-dependents-graph": "^2.1.4", - "@changesets/logger": "^0.1.1", - "@changesets/should-skip-package": "^0.1.2", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "fs-extra": "^7.0.1", - "micromatch": "^4.0.8" - } - }, - "node_modules/@changesets/errors": { - "version": "0.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "extendable-error": "^0.1.5" - } - }, - "node_modules/@changesets/get-dependents-graph": { - "version": "2.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "picocolors": "^1.1.0", - "semver": "^7.5.3" - } - }, - "node_modules/@changesets/get-release-plan": { - "version": "4.0.16", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/assemble-release-plan": "^6.0.10", - "@changesets/config": "^3.1.4", - "@changesets/pre": "^2.0.2", - "@changesets/read": "^0.6.7", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3" - } - }, - "node_modules/@changesets/get-version-range-type": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@changesets/git": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@manypkg/get-packages": "^1.1.3", - "is-subdir": "^1.1.1", - "micromatch": "^4.0.8", - "spawndamnit": "^3.0.1" - } - }, - "node_modules/@changesets/logger": { - "version": "0.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^1.1.0" - } - }, - "node_modules/@changesets/parse": { - "version": "0.4.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "js-yaml": "^4.1.1" - } - }, - "node_modules/@changesets/pre": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/errors": "^0.2.0", - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3", - "fs-extra": "^7.0.1" - } - }, - "node_modules/@changesets/read": { - "version": "0.6.7", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/git": "^3.0.4", - "@changesets/logger": "^0.1.1", - "@changesets/parse": "^0.4.3", - "@changesets/types": "^6.1.0", - "fs-extra": "^7.0.1", - "p-filter": "^2.1.0", - "picocolors": "^1.1.0" - } - }, - "node_modules/@changesets/should-skip-package": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "@manypkg/get-packages": "^1.1.3" - } - }, - "node_modules/@changesets/types": { - "version": "6.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@changesets/write": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@changesets/types": "^6.1.0", - "fs-extra": "^7.0.1", - "human-id": "^4.1.1", - "prettier": "^2.7.1" - } - }, - "node_modules/@changesets/write/node_modules/prettier": { - "version": "2.8.8", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.14", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@manypkg/find-root": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.5.5", - "@types/node": "^12.7.1", - "find-up": "^4.1.0", - "fs-extra": "^8.1.0" - } - }, - "node_modules/@manypkg/find-root/node_modules/@types/node": { - "version": "12.20.55", - "dev": true, - "license": "MIT" - }, - "node_modules/@manypkg/find-root/node_modules/find-up": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@manypkg/find-root/node_modules/find-up/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@manypkg/find-root/node_modules/find-up/node_modules/locate-path/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@manypkg/find-root/node_modules/find-up/node_modules/locate-path/node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@manypkg/find-root/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@manypkg/get-packages": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.5.5", - "@changesets/types": "^4.0.1", - "@manypkg/find-root": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "^11.0.0", - "read-yaml-file": "^1.1.0" - } - }, - "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { - "version": "4.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@manypkg/get-packages/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.29.0", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { - "version": "8.20.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/ajv/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/zod": { - "version": "4.4.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@noble/ciphers": { - "version": "0.5.3", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.3.2", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "license": "MIT" - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@scure/base": { - "version": "1.1.1", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@scure/bip32": { - "version": "1.3.1", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.1.0", - "@noble/hashes": "~1.3.1", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/curves": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.3.1", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.3.2", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.2.1", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.3.2", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@types/bun": { - "version": "1.3.13", - "dev": true, - "license": "MIT", - "dependencies": { - "bun-types": "1.3.13" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.19.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.59.2", - "@typescript-eslint/type-utils": "8.59.2", - "@typescript-eslint/utils": "8.59.2", - "@typescript-eslint/visitor-keys": "8.59.2", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.59.2", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.59.2", - "@typescript-eslint/types": "8.59.2", - "@typescript-eslint/typescript-estree": "8.59.2", - "@typescript-eslint/visitor-keys": "8.59.2", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.2", - "@typescript-eslint/types": "^8.59.2", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.2", - "@typescript-eslint/visitor-keys": "8.59.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.2", - "@typescript-eslint/typescript-estree": "8.59.2", - "@typescript-eslint/utils": "8.59.2", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.59.2", - "@typescript-eslint/tsconfig-utils": "8.59.2", - "@typescript-eslint/types": "8.59.2", - "@typescript-eslint/visitor-keys": "8.59.2", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { - "version": "4.0.4", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.2", - "@typescript-eslint/types": "8.59.2", - "@typescript-eslint/typescript-estree": "8.59.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.2", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.15.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.20.0", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/ajv/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/applesauce-core": { - "version": "5.2.0", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "fast-deep-equal": "^3.1.3", - "hash-sum": "^2.0.0", - "nanoid": "^5.0.9", - "nostr-tools": "~2.19", - "rxjs": "^7.8.1" - }, - "funding": { - "type": "lightning", - "url": "lightning:nostrudel@geyser.fund" - } - }, - "node_modules/applesauce-core/node_modules/nostr-tools": { - "version": "2.19.4", - "license": "Unlicense", - "dependencies": { - "@noble/ciphers": "^0.5.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.1", - "@scure/base": "1.1.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1", - "nostr-wasm": "0.1.0" - }, - "peerDependencies": { - "typescript": ">=5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/applesauce-core/node_modules/nostr-tools/node_modules/@noble/hashes": { - "version": "1.3.1", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/applesauce-relay": { - "version": "5.2.0", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.7.1", - "applesauce-core": "^5.2.0", - "nanoid": "^5.0.9", - "nostr-tools": "~2.19", - "rxjs": "^7.8.1" - }, - "funding": { - "type": "lightning", - "url": "lightning:nostrudel@geyser.fund" - } - }, - "node_modules/applesauce-relay/node_modules/@noble/hashes": { - "version": "1.8.0", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/applesauce-relay/node_modules/nostr-tools": { - "version": "2.19.4", - "license": "Unlicense", - "dependencies": { - "@noble/ciphers": "^0.5.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.1", - "@scure/base": "1.1.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1", - "nostr-wasm": "0.1.0" - }, - "peerDependencies": { - "typescript": ">=5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/applesauce-relay/node_modules/nostr-tools/node_modules/@noble/hashes": { - "version": "1.3.1", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/better-path-resolve": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-windows": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/body-parser": { - "version": "2.2.2", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.14", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bun-types": { - "version": "1.3.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "get-intrinsic": "^1.3.0", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/canonicalize": { - "version": "2.1.0", - "license": "Apache-2.0", - "bin": { - "canonicalize": "bin/canonicalize.js" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chardet": { - "version": "2.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enquirer": { - "version": "2.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/es-abstract": { - "version": "1.24.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.10", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.16.1", - "resolve": "^2.0.0-next.6" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.32.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.8", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.4.1", - "license": "MIT", - "dependencies": { - "ip-address": "10.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/extendable-error": { - "version": "0.1.7", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.20.1", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "dev": true, - "license": "ISC" - }, - "node_modules/for-each": { - "version": "0.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash-sum": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/hasown": { - "version": "2.0.3", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.12.16", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/human-id": { - "version": "4.1.3", - "dev": true, - "license": "MIT", - "bin": { - "human-id": "dist/cli.js" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip-address": { - "version": "10.1.0", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-subdir": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "better-path-resolve": "1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.2.3", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "license": "BSD-2-Clause" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.startcase": { - "version": "4.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mri": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "5.1.11", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-exports-info": { - "version": "1.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array.prototype.flatmap": "^1.3.3", - "es-errors": "^1.3.0", - "object.entries": "^1.1.9", - "semver": "^6.3.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/node-exports-info/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/nostr-tools": { - "version": "2.18.2", - "license": "Unlicense", - "dependencies": { - "@noble/ciphers": "^0.5.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.1", - "@scure/base": "1.1.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1", - "nostr-wasm": "0.1.0" - }, - "peerDependencies": { - "typescript": ">=5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/nostr-tools/node_modules/@noble/hashes": { - "version": "1.3.1", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/nostr-wasm": { - "version": "0.1.0", - "license": "MIT" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/outdent": { - "version": "0.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/own-keys": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-filter": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-map": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/package-manager-detector": { - "version": "0.2.11", - "dev": true, - "license": "MIT", - "dependencies": { - "quansync": "^0.2.7" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pino": { - "version": "10.3.1", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "3.0.0", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "license": "MIT" - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.8.3", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/process-warning": { - "version": "5.0.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.15.1", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/quansync": { - "version": "0.2.11", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/antfu" - }, - { - "type": "individual", - "url": "https://github.com/sponsors/sxzz" - } - ], - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/read-yaml-file": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.5", - "js-yaml": "^3.6.1", - "pify": "^4.0.1", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-yaml-file/node_modules/js-yaml": { - "version": "3.14.2", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/read-yaml-file/node_modules/js-yaml/node_modules/argparse": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/real-require": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "2.0.0-next.6", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/router": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "get-intrinsic": "^1.3.0", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.1", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sonic-boom": { - "version": "4.2.1", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/spawndamnit": { - "version": "3.0.1", - "dev": true, - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "cross-spawn": "^7.0.5", - "signal-exit": "^4.0.1" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/statuses": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/term-size": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/thread-stream": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "license": "0BSD" - }, - "node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.59.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.59.2", - "@typescript-eslint/parser": "8.59.2", - "@typescript-eslint/typescript-estree": "8.59.2", - "@typescript-eslint/utils": "8.59.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "7.19.2", - "dev": true, - "license": "MIT" - }, - "node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.20", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.20.0", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } - } - } -} diff --git a/src/payments/server-transport-payments.ts b/src/payments/server-transport-payments.ts index 6d3a6cc..ca0b1c1 100644 --- a/src/payments/server-transport-payments.ts +++ b/src/payments/server-transport-payments.ts @@ -14,10 +14,10 @@ export function withServerPayments( options: ServerPaymentsOptions, ): NostrServerTransport { // CEP-8 discovery tags: advertise supported PMIs + reference pricing on announcement/list events. - const extraTags = createPmiTagsFromProcessors(options.processors); + const extraTags: string[][] = createPmiTagsFromProcessors(options.processors); if (options.paymentInteraction === 'explicit_gating') { - extraTags.push(['payment_interaction', 'explicit_gating'] as any); + extraTags.push(['payment_interaction', 'explicit_gating']); } transport.setAnnouncementExtraTags(extraTags); diff --git a/src/transport/nostr-server/inbound-coordinator.ts b/src/transport/nostr-server/inbound-coordinator.ts index 3118436..b14f6fb 100644 --- a/src/transport/nostr-server/inbound-coordinator.ts +++ b/src/transport/nostr-server/inbound-coordinator.ts @@ -26,6 +26,7 @@ import { } from '../../core/index.js'; import { GiftWrapMode } from '../../core/interfaces.js'; import { type OpenStreamWriter } from '../open-stream/index.js'; +import { UNSUPPORTED_PAYMENT_INTERACTION_ERROR_CODE } from '../../payments/constants.js'; export interface ServerInboundCoordinatorDeps { sessionStore: SessionStore; @@ -181,6 +182,43 @@ export class ServerInboundCoordinator { const mode = paymentInteractionTag[1]; if (mode === 'transparent' || mode === 'explicit_gating') { session.requestedPaymentInteraction = mode as import('../../payments/types.js').PaymentInteractionMode; + + if (mode === 'explicit_gating' && !serverSupportsExplicitGating) { + if (isJSONRPCRequest(inboundMessage)) { + const errorResponse: JSONRPCErrorResponse = { + jsonrpc: '2.0', + id: inboundMessage.id, + error: { + code: UNSUPPORTED_PAYMENT_INTERACTION_ERROR_CODE, + message: 'Unsupported payment_interaction mode: explicit_gating', + }, + }; + const tags = this.deps.createResponseTags(event.pubkey, event.id); + this.deps + .sendMcpMessage( + errorResponse, + event.pubkey, + CTXVM_MESSAGES_KIND, + tags, + isEncrypted, + undefined, + isEncrypted + ? this.deps.giftWrapMode === GiftWrapMode.EPHEMERAL + ? EPHEMERAL_GIFT_WRAP_KIND + : this.deps.giftWrapMode === GiftWrapMode.PERSISTENT + ? GIFT_WRAP_KIND + : wrapKind + : undefined, + ) + .catch((err) => { + this.deps.logger.error('Failed to send negotiation error response', { + error: err instanceof Error ? err.message : String(err), + }); + }); + return; + } + } + session.effectivePaymentInteraction = serverSupportsExplicitGating ? session.requestedPaymentInteraction : 'transparent';